aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-11-02 15:23:21 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2009-11-02 15:23:21 -0500
commit1836d95928a0f41ada0cbb2a6c4e46b027db9491 (patch)
tree24ebf7cfd598dfef82247044fb3b65110fe22fc8 /fs
parent333a07437c31ea8c16a2b82071629a540ae1e50f (diff)
parent3e2796a90cf349527e50b3bc4d0b2f4019b1ce7a (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs: 9p: fix readdir corner cases 9p: fix readlink 9p: fix a small bug in readdir for long directories
Diffstat (limited to 'fs')
-rw-r--r--fs/9p/vfs_dir.c93
-rw-r--r--fs/9p/vfs_inode.c5
2 files changed, 69 insertions, 29 deletions
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c
index 873cd31baa47..15cce53bf61e 100644
--- a/fs/9p/vfs_dir.c
+++ b/fs/9p/vfs_dir.c
@@ -40,6 +40,24 @@
40#include "fid.h" 40#include "fid.h"
41 41
42/** 42/**
43 * struct p9_rdir - readdir accounting
44 * @mutex: mutex protecting readdir
45 * @head: start offset of current dirread buffer
46 * @tail: end offset of current dirread buffer
47 * @buf: dirread buffer
48 *
49 * private structure for keeping track of readdir
50 * allocated on demand
51 */
52
53struct p9_rdir {
54 struct mutex mutex;
55 int head;
56 int tail;
57 uint8_t *buf;
58};
59
60/**
43 * dt_type - return file type 61 * dt_type - return file type
44 * @mistat: mistat structure 62 * @mistat: mistat structure
45 * 63 *
@@ -70,56 +88,79 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
70{ 88{
71 int over; 89 int over;
72 struct p9_wstat st; 90 struct p9_wstat st;
73 int err; 91 int err = 0;
74 struct p9_fid *fid; 92 struct p9_fid *fid;
75 int buflen; 93 int buflen;
76 char *statbuf; 94 int reclen = 0;
77 int n, i = 0; 95 struct p9_rdir *rdir;
78 96
79 P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name); 97 P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name);
80 fid = filp->private_data; 98 fid = filp->private_data;
81 99
82 buflen = fid->clnt->msize - P9_IOHDRSZ; 100 buflen = fid->clnt->msize - P9_IOHDRSZ;
83 statbuf = kmalloc(buflen, GFP_KERNEL); 101
84 if (!statbuf) 102 /* allocate rdir on demand */
85 return -ENOMEM; 103 if (!fid->rdir) {
86 104 rdir = kmalloc(sizeof(struct p9_rdir) + buflen, GFP_KERNEL);
87 while (1) { 105
88 err = v9fs_file_readn(filp, statbuf, NULL, buflen, 106 if (rdir == NULL) {
89 fid->rdir_fpos); 107 err = -ENOMEM;
90 if (err <= 0) 108 goto exit;
91 break; 109 }
92 110 spin_lock(&filp->f_dentry->d_lock);
93 n = err; 111 if (!fid->rdir) {
94 while (i < n) { 112 rdir->buf = (uint8_t *)rdir + sizeof(struct p9_rdir);
95 err = p9stat_read(statbuf + i, buflen-i, &st, 113 mutex_init(&rdir->mutex);
96 fid->clnt->dotu); 114 rdir->head = rdir->tail = 0;
115 fid->rdir = (void *) rdir;
116 rdir = NULL;
117 }
118 spin_unlock(&filp->f_dentry->d_lock);
119 kfree(rdir);
120 }
121 rdir = (struct p9_rdir *) fid->rdir;
122
123 err = mutex_lock_interruptible(&rdir->mutex);
124 while (err == 0) {
125 if (rdir->tail == rdir->head) {
126 err = v9fs_file_readn(filp, rdir->buf, NULL,
127 buflen, filp->f_pos);
128 if (err <= 0)
129 goto unlock_and_exit;
130
131 rdir->head = 0;
132 rdir->tail = err;
133 }
134
135 while (rdir->head < rdir->tail) {
136 err = p9stat_read(rdir->buf + rdir->head,
137 buflen - rdir->head, &st,
138 fid->clnt->dotu);
97 if (err) { 139 if (err) {
98 P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err); 140 P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err);
99 err = -EIO; 141 err = -EIO;
100 p9stat_free(&st); 142 p9stat_free(&st);
101 goto free_and_exit; 143 goto unlock_and_exit;
102 } 144 }
103 145 reclen = st.size+2;
104 i += st.size+2;
105 fid->rdir_fpos += st.size+2;
106 146
107 over = filldir(dirent, st.name, strlen(st.name), 147 over = filldir(dirent, st.name, strlen(st.name),
108 filp->f_pos, v9fs_qid2ino(&st.qid), dt_type(&st)); 148 filp->f_pos, v9fs_qid2ino(&st.qid), dt_type(&st));
109 149
110 filp->f_pos += st.size+2;
111
112 p9stat_free(&st); 150 p9stat_free(&st);
113 151
114 if (over) { 152 if (over) {
115 err = 0; 153 err = 0;
116 goto free_and_exit; 154 goto unlock_and_exit;
117 } 155 }
156 rdir->head += reclen;
157 filp->f_pos += reclen;
118 } 158 }
119 } 159 }
120 160
121free_and_exit: 161unlock_and_exit:
122 kfree(statbuf); 162 mutex_unlock(&rdir->mutex);
163exit:
123 return err; 164 return err;
124} 165}
125 166
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 5947628aefef..18f74ec4dce9 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -994,8 +994,7 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
994 P9_DPRINTK(P9_DEBUG_VFS, 994 P9_DPRINTK(P9_DEBUG_VFS,
995 "%s -> %s (%s)\n", dentry->d_name.name, st->extension, buffer); 995 "%s -> %s (%s)\n", dentry->d_name.name, st->extension, buffer);
996 996
997 retval = buflen; 997 retval = strnlen(buffer, buflen);
998
999done: 998done:
1000 kfree(st); 999 kfree(st);
1001 return retval; 1000 return retval;
@@ -1062,7 +1061,7 @@ static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd)
1062 __putname(link); 1061 __putname(link);
1063 link = ERR_PTR(len); 1062 link = ERR_PTR(len);
1064 } else 1063 } else
1065 link[len] = 0; 1064 link[min(len, PATH_MAX-1)] = 0;
1066 } 1065 }
1067 nd_set_link(nd, link); 1066 nd_set_link(nd, link);
1068 1067