summaryrefslogtreecommitdiff
path: root/fs/ocfs2/dir.c
diff options
context:
space:
mode:
authorMark Fasheh <mark.fasheh@oracle.com>2007-09-12 11:19:00 -0700
committerMark Fasheh <mark.fasheh@oracle.com>2007-10-12 11:54:37 -0700
commit0bfbbf62a8b5a129ba2c689283bfece80a601aba (patch)
treeaf010d9f03acf04f81aef04eb07e2962fe502543 /fs/ocfs2/dir.c
parent5eae5b96fc86e6c85f5f90e90fe9e6966f1fec63 (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.c96
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,