diff options
author | Mark Fasheh <mark.fasheh@oracle.com> | 2007-09-12 11:19:00 -0700 |
---|---|---|
committer | Mark Fasheh <mark.fasheh@oracle.com> | 2007-10-12 11:54:37 -0700 |
commit | 0bfbbf62a8b5a129ba2c689283bfece80a601aba (patch) | |
tree | af010d9f03acf04f81aef04eb07e2962fe502543 /fs/ocfs2/dir.c | |
parent | 5eae5b96fc86e6c85f5f90e90fe9e6966f1fec63 (diff) |
ocfs2: Implement ocfs2_empty_dir() as a caller of ocfs2_dir_foreach()
We can preserve the behavior of ocfs2_empty_dir(), while getting rid of the
open coded directory walk by just providing a smart filldir callback. This
also automatically gets to use the dir readahead code, though in this case
any advantage is minor at best.
Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>
Reviewed-by: Joel Becker <joel.becker@oracle.com>
Diffstat (limited to 'fs/ocfs2/dir.c')
-rw-r--r-- | fs/ocfs2/dir.c | 96 |
1 files changed, 45 insertions, 51 deletions
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index a75c340fc689..4bb54406354b 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c @@ -660,67 +660,61 @@ bail: return ret; } +struct ocfs2_empty_dir_priv { + unsigned seen_dot; + unsigned seen_dot_dot; + unsigned seen_other; +}; +static int ocfs2_empty_dir_filldir(void *priv, const char *name, int name_len, + loff_t pos, u64 ino, unsigned type) +{ + struct ocfs2_empty_dir_priv *p = priv; + + /* + * Check the positions of "." and ".." records to be sure + * they're in the correct place. + */ + if (name_len == 1 && !strncmp(".", name, 1) && pos == 0) { + p->seen_dot = 1; + return 0; + } + + if (name_len == 2 && !strncmp("..", name, 2) && + pos == OCFS2_DIR_REC_LEN(1)) { + p->seen_dot_dot = 1; + return 0; + } + + p->seen_other = 1; + return 1; +} /* * routine to check that the specified directory is empty (for rmdir) + * + * Returns 1 if dir is empty, zero otherwise. */ int ocfs2_empty_dir(struct inode *inode) { - unsigned long offset; - struct buffer_head * bh; - struct ocfs2_dir_entry * de, * de1; - struct super_block * sb; - int err; + int ret; + loff_t start = 0; + struct ocfs2_empty_dir_priv priv; - sb = inode->i_sb; - if ((i_size_read(inode) < - (OCFS2_DIR_REC_LEN(1) + OCFS2_DIR_REC_LEN(2))) || - !(bh = ocfs2_bread(inode, 0, &err, 0))) { - mlog(ML_ERROR, "bad directory (dir #%llu) - no data block\n", - (unsigned long long)OCFS2_I(inode)->ip_blkno); - return 1; - } + memset(&priv, 0, sizeof(priv)); - de = (struct ocfs2_dir_entry *) bh->b_data; - de1 = (struct ocfs2_dir_entry *) - ((char *)de + le16_to_cpu(de->rec_len)); - if ((le64_to_cpu(de->inode) != OCFS2_I(inode)->ip_blkno) || - !le64_to_cpu(de1->inode) || - strcmp(".", de->name) || - strcmp("..", de1->name)) { - mlog(ML_ERROR, "bad directory (dir #%llu) - no `.' or `..'\n", + ret = ocfs2_dir_foreach(inode, &start, &priv, ocfs2_empty_dir_filldir); + if (ret) + mlog_errno(ret); + + if (!priv.seen_dot || !priv.seen_dot_dot) { + mlog(ML_ERROR, "bad directory (dir #%llu) - no `.' or `..'\n", (unsigned long long)OCFS2_I(inode)->ip_blkno); - brelse(bh); + /* + * XXX: Is it really safe to allow an unlink to continue? + */ return 1; } - offset = le16_to_cpu(de->rec_len) + le16_to_cpu(de1->rec_len); - de = (struct ocfs2_dir_entry *)((char *)de1 + le16_to_cpu(de1->rec_len)); - while (offset < i_size_read(inode) ) { - if (!bh || (void *)de >= (void *)(bh->b_data + sb->s_blocksize)) { - brelse(bh); - bh = ocfs2_bread(inode, - offset >> sb->s_blocksize_bits, &err, 0); - if (!bh) { - mlog(ML_ERROR, "dir %llu has a hole at %lu\n", - (unsigned long long)OCFS2_I(inode)->ip_blkno, offset); - offset += sb->s_blocksize; - continue; - } - de = (struct ocfs2_dir_entry *) bh->b_data; - } - if (!ocfs2_check_dir_entry(inode, de, bh, offset)) { - brelse(bh); - return 1; - } - if (le64_to_cpu(de->inode)) { - brelse(bh); - return 0; - } - offset += le16_to_cpu(de->rec_len); - de = (struct ocfs2_dir_entry *) - ((char *)de + le16_to_cpu(de->rec_len)); - } - brelse(bh); - return 1; + + return !priv.seen_other; } int ocfs2_fill_new_dir(struct ocfs2_super *osb, |