lk: teach crfs_readdir about dirents with multiple items

Alex Chiang achiang at hp.com
Mon May 12 21:29:00 PDT 2008


* Zach Brown <zach.brown at oracle.com>:
> Alex Chiang wrote:
> 		
> > +				done = filldir(dirent, ditem->name,
> > +				          le16_to_cpu(ditem->name_len),
> > +				          filp->f_pos,
> > +				          le64_to_cpu(ditem->location.objectid),
> > +				          crfs_filldir_type[ditem->type]);
> > +
> > +				if (!done)
> > +					filp->f_pos++;
> 
> Hmm, do we want to be incrementing f_pos at each dirent in the item?  If
> the user doesn't have enough room for all the dirents in the item then
> we'll return from the syscall after having given them some of the items.
>  Then they'll call back in with an f_pos that is roughly (objectid +
> dirents).  That f_pos will be used as the objectid that they'll start
> from, so they'll miss the rest of the dirents in the item they were in
> and they'll miss dirents in the items of the objectids that they skipped.

Hrm, yeah, that makes sense.

> So we need a reasonably clever way to encode objectid+direntoffset in
> stupid old f_pos.  We should see how Chris is doing this in btrfs.

btrfs_readdir is a lot scarier than crfs_readdir, but I think
this version of the patch should do it.

The differences are:

	- do not bump f_pos for every dirent *within* an item,
	  but do bump it after we've successfully filldir()'ed
	  *every* dirent in the item.

This works because...

	- if filldir() returns with an error, then we don't bump
	  f_pos. User later calls back in with prior value of
	  f_pos, which we use as a key search value.

Hm?

/ac

From: Alex Chiang <achiang at hp.com>
Subject: lk: teach crfs_readdir about items with multiple dirents

Teach crfs_readdir about items with multiple dirents.

Only increment f_pos after successfully calling filldir() for
each dirent within an item. That way, we won't lose track of
cases where an item has multiple dirents, but ran out of room
before returning them all.

The most immediate, obvious change is that we now see both the
dot and dotdot entries during 'ls -alF'.

	[root at canola crfs]# pwd
	/mnt/crfs
	[root at canola crfs]# ls -alF
	total 5
	drwxr-xr-x 1 root root   42 2008-05-12 11:14 ./
	drwxr-xr-x 6 root root 4096 2008-05-01 17:23 ../

All tests in crfs test suite pass successfully.

Signed-off-by: Alex Chiang <achiang at hp.com>
---
diff -r 77848719c4ba lk/dir.c
--- a/lk/dir.c	Tue Apr 22 14:03:17 2008 -0700
+++ b/lk/dir.c	Mon May 12 22:17:24 2008 -0600
@@ -90,6 +90,7 @@ static int crfs_readdir(struct file *fil
 	struct crfs_key key;
 	struct crfs_key last;
 	struct crfs_meta_ref mref;
+	void *dent;
 	int done = 0;
 	int ret;
 
@@ -106,25 +107,39 @@ static int crfs_readdir(struct file *fil
 			break;
 
 		if (crfs_key_compare(mref.r_key, &last) <= 0) {
-			ditem = mref.r_data;
+			dent = mref.r_data;
 			filp->f_pos = le64_to_cpu(mref.r_key->offset);
 
-			crfs_log("ent %.*s", le16_to_cpu(ditem->name_len),
-				ditem->name);
+			while (dent < (mref.r_data + mref.r_bytes)) {
+				ditem = dent;
 
-			done = filldir(dirent, ditem->name,
-				       le16_to_cpu(ditem->name_len),
-				       filp->f_pos,
-				       le64_to_cpu(ditem->location.objectid),
-				       crfs_filldir_type[ditem->type]);
-			if (!done)
-				filp->f_pos++;
+				crfs_log("ent %.*s",
+						le16_to_cpu(ditem->name_len),
+						ditem->name);
+			
+				done = filldir(dirent, ditem->name,
+				          le16_to_cpu(ditem->name_len),
+				          filp->f_pos,
+				          le64_to_cpu(ditem->location.objectid),
+				          crfs_filldir_type[ditem->type]);
+
+				if (done) {
+					crfs_meta_ref_put(&mref);
+					goto out;
+				}
+
+				dent += sizeof(*ditem);
+				dent += le16_to_cpu(ditem->name_len);
+			}
+
+			filp->f_pos++;
 		} else
 			done = 1;
 
 		crfs_meta_ref_put(&mref);
 	}
 
+out:
 	return ret;
 }
 




More information about the crfs-devel mailing list