From 307a11e5dd9cd5f7bfb84ad804ea5bcdd81c9ae7 Mon Sep 17 00:00:00 2001 From: Sage Weil Date: Tue, 21 Jul 2009 16:02:53 -0700 Subject: [PATCH] kclient: fix dcache readdir -> sync readdir transition We need to keep maintain the same state variables (namely, fi->next_offset and fi->dentry) in a consistent fashion. Use a helper to keep track of the last name we _did_ see. --- src/kernel/dir.c | 76 +++++++++++++++++++++++++++++------------------- 1 file changed, 46 insertions(+), 30 deletions(-) diff --git a/src/kernel/dir.c b/src/kernel/dir.c index fd07112b6173c..c58309006e0b8 100644 --- a/src/kernel/dir.c +++ b/src/kernel/dir.c @@ -80,7 +80,7 @@ static int __dcache_readdir(struct file *filp, p = parent->d_subdirs.prev; dout(" initial p %p/%p\n", p->prev, p->next); } else { - p = &last->d_u.d_child; + p = last->d_u.d_child.prev; } more: @@ -109,11 +109,6 @@ more: spin_unlock(&dcache_lock); spin_unlock(&inode->i_lock); - if (last) { - dput(last); - last = NULL; - } - dout(" %llu (%llu) dentry %p %.*s %p\n", di->offset, filp->f_pos, dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode); filp->f_pos = di->offset; @@ -122,13 +117,22 @@ more: dentry->d_inode->i_ino, dentry->d_inode->i_mode >> 12); + if (last) { + if (err < 0) { + /* remember our position */ + fi->dentry = last; + fi->next_offset = di->offset; + } else { + dput(last); + } + last = NULL; + } + spin_lock(&inode->i_lock); spin_lock(&dcache_lock); - if (err < 0) { - fi->dentry = dentry; /* remember our position */ + if (err < 0) goto out_unlock; - } last = dentry; @@ -153,6 +157,25 @@ out_unlock: return err; } +/* + * make note of the last dentry we read, so we can + * continue at the same lexicographical point, + * regardless of what dir changes take place on the + * server. + */ +static int note_last_dentry(struct ceph_file_info *fi, const char *name, + int len) +{ + kfree(fi->last_name); + fi->last_name = kmalloc(len+1, GFP_NOFS); + if (!fi->last_name) + return -ENOMEM; + memcpy(fi->last_name, name, len); + fi->last_name[len] = 0; + dout("note_last_dentry '%s'\n", fi->last_name); + return 0; +} + static int ceph_readdir(struct file *filp, void *dirent, filldir_t filldir) { struct ceph_file_info *fi = filp->private_data; @@ -165,7 +188,6 @@ static int ceph_readdir(struct file *filp, void *dirent, filldir_t filldir) int err; u32 ftype; struct ceph_mds_reply_info_parsed *rinfo; - int len; const int max_entries = client->mount_args.max_readdir; dout("readdir %p filp %p frag %u off %u\n", inode, filp, frag, off); @@ -209,6 +231,10 @@ static int ceph_readdir(struct file *filp, void *dirent, filldir_t filldir) } spin_unlock(&inode->i_lock); if (fi->dentry) { + err = note_last_dentry(fi, fi->dentry->d_name.name, + fi->dentry->d_name.len); + if (err) + return err; dput(fi->dentry); fi->dentry = NULL; } @@ -260,33 +286,23 @@ more: fi->dir_release_count--; /* preclude I_COMPLETE */ } - /* - * make note of the last dentry we read, so we can - * continue at the same lexicographical point, - * regardless of what dir changes take place on the - * server. and choose the next offset to - * readdir from. - */ + /* note next offset and last dentry name */ fi->offset = fi->next_offset; - kfree(fi->last_name); - fi->last_name = NULL; + fi->last_readdir = req; + if (req->r_reply_info.dir_end) { + kfree(fi->last_name); + fi->last_name = NULL; fi->next_offset = 0; } else { rinfo = &req->r_reply_info; - len = rinfo->dir_dname_len[rinfo->dir_nr-1]; - fi->last_name = kmalloc(len+1, GFP_NOFS); - if (!fi->last_name) { - ceph_mdsc_put_request(req); - return -ENOMEM; - } - memcpy(fi->last_name, rinfo->dir_dname[rinfo->dir_nr-1], - len); - fi->last_name[len] = 0; + err = note_last_dentry(fi, + rinfo->dir_dname[rinfo->dir_nr-1], + rinfo->dir_dname_len[rinfo->dir_nr-1]); + if (err) + return err; fi->next_offset += rinfo->dir_nr; - dout("readdir last item is '%s'\n", fi->last_name); } - fi->last_readdir = req; } rinfo = &fi->last_readdir->r_reply_info; -- 2.39.5