aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/9p/vfs_dir.c92
1 files changed, 23 insertions, 69 deletions
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c
index ff911e779651..be1e34adc3c6 100644
--- a/fs/9p/vfs_dir.c
+++ b/fs/9p/vfs_dir.c
@@ -52,10 +52,9 @@
52 */ 52 */
53 53
54struct p9_rdir { 54struct p9_rdir {
55 struct mutex mutex;
56 int head; 55 int head;
57 int tail; 56 int tail;
58 uint8_t *buf; 57 uint8_t buf[];
59}; 58};
60 59
61/** 60/**
@@ -93,33 +92,12 @@ static void p9stat_init(struct p9_wstat *stbuf)
93 * 92 *
94 */ 93 */
95 94
96static int v9fs_alloc_rdir_buf(struct file *filp, int buflen) 95static struct p9_rdir *v9fs_alloc_rdir_buf(struct file *filp, int buflen)
97{ 96{
98 struct p9_rdir *rdir; 97 struct p9_fid *fid = filp->private_data;
99 struct p9_fid *fid; 98 if (!fid->rdir)
100 int err = 0; 99 fid->rdir = kzalloc(sizeof(struct p9_rdir) + buflen, GFP_KERNEL);
101 100 return fid->rdir;
102 fid = filp->private_data;
103 if (!fid->rdir) {
104 rdir = kmalloc(sizeof(struct p9_rdir) + buflen, GFP_KERNEL);
105
106 if (rdir == NULL) {
107 err = -ENOMEM;
108 goto exit;
109 }
110 spin_lock(&filp->f_dentry->d_lock);
111 if (!fid->rdir) {
112 rdir->buf = (uint8_t *)rdir + sizeof(struct p9_rdir);
113 mutex_init(&rdir->mutex);
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 }
121exit:
122 return err;
123} 101}
124 102
125/** 103/**
@@ -145,20 +123,16 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
145 123
146 buflen = fid->clnt->msize - P9_IOHDRSZ; 124 buflen = fid->clnt->msize - P9_IOHDRSZ;
147 125
148 err = v9fs_alloc_rdir_buf(filp, buflen); 126 rdir = v9fs_alloc_rdir_buf(filp, buflen);
149 if (err) 127 if (!rdir)
150 goto exit; 128 return -ENOMEM;
151 rdir = (struct p9_rdir *) fid->rdir;
152 129
153 err = mutex_lock_interruptible(&rdir->mutex); 130 while (1) {
154 if (err)
155 return err;
156 while (err == 0) {
157 if (rdir->tail == rdir->head) { 131 if (rdir->tail == rdir->head) {
158 err = v9fs_file_readn(filp, rdir->buf, NULL, 132 err = v9fs_file_readn(filp, rdir->buf, NULL,
159 buflen, filp->f_pos); 133 buflen, filp->f_pos);
160 if (err <= 0) 134 if (err <= 0)
161 goto unlock_and_exit; 135 return err;
162 136
163 rdir->head = 0; 137 rdir->head = 0;
164 rdir->tail = err; 138 rdir->tail = err;
@@ -169,9 +143,8 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
169 rdir->tail - rdir->head, &st); 143 rdir->tail - rdir->head, &st);
170 if (err) { 144 if (err) {
171 p9_debug(P9_DEBUG_VFS, "returned %d\n", err); 145 p9_debug(P9_DEBUG_VFS, "returned %d\n", err);
172 err = -EIO;
173 p9stat_free(&st); 146 p9stat_free(&st);
174 goto unlock_and_exit; 147 return -EIO;
175 } 148 }
176 reclen = st.size+2; 149 reclen = st.size+2;
177 150
@@ -180,19 +153,13 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir)
180 153
181 p9stat_free(&st); 154 p9stat_free(&st);
182 155
183 if (over) { 156 if (over)
184 err = 0; 157 return 0;
185 goto unlock_and_exit; 158
186 }
187 rdir->head += reclen; 159 rdir->head += reclen;
188 filp->f_pos += reclen; 160 filp->f_pos += reclen;
189 } 161 }
190 } 162 }
191
192unlock_and_exit:
193 mutex_unlock(&rdir->mutex);
194exit:
195 return err;
196} 163}
197 164
198/** 165/**
@@ -218,21 +185,16 @@ static int v9fs_dir_readdir_dotl(struct file *filp, void *dirent,
218 185
219 buflen = fid->clnt->msize - P9_READDIRHDRSZ; 186 buflen = fid->clnt->msize - P9_READDIRHDRSZ;
220 187
221 err = v9fs_alloc_rdir_buf(filp, buflen); 188 rdir = v9fs_alloc_rdir_buf(filp, buflen);
222 if (err) 189 if (!rdir)
223 goto exit; 190 return -ENOMEM;
224 rdir = (struct p9_rdir *) fid->rdir;
225 191
226 err = mutex_lock_interruptible(&rdir->mutex); 192 while (1) {
227 if (err)
228 return err;
229
230 while (err == 0) {
231 if (rdir->tail == rdir->head) { 193 if (rdir->tail == rdir->head) {
232 err = p9_client_readdir(fid, rdir->buf, buflen, 194 err = p9_client_readdir(fid, rdir->buf, buflen,
233 filp->f_pos); 195 filp->f_pos);
234 if (err <= 0) 196 if (err <= 0)
235 goto unlock_and_exit; 197 return err;
236 198
237 rdir->head = 0; 199 rdir->head = 0;
238 rdir->tail = err; 200 rdir->tail = err;
@@ -245,8 +207,7 @@ static int v9fs_dir_readdir_dotl(struct file *filp, void *dirent,
245 &curdirent); 207 &curdirent);
246 if (err < 0) { 208 if (err < 0) {
247 p9_debug(P9_DEBUG_VFS, "returned %d\n", err); 209 p9_debug(P9_DEBUG_VFS, "returned %d\n", err);
248 err = -EIO; 210 return -EIO;
249 goto unlock_and_exit;
250 } 211 }
251 212
252 /* d_off in dirent structure tracks the offset into 213 /* d_off in dirent structure tracks the offset into
@@ -261,20 +222,13 @@ static int v9fs_dir_readdir_dotl(struct file *filp, void *dirent,
261 curdirent.d_type); 222 curdirent.d_type);
262 oldoffset = curdirent.d_off; 223 oldoffset = curdirent.d_off;
263 224
264 if (over) { 225 if (over)
265 err = 0; 226 return 0;
266 goto unlock_and_exit;
267 }
268 227
269 filp->f_pos = curdirent.d_off; 228 filp->f_pos = curdirent.d_off;
270 rdir->head += err; 229 rdir->head += err;
271 } 230 }
272 } 231 }
273
274unlock_and_exit:
275 mutex_unlock(&rdir->mutex);
276exit:
277 return err;
278} 232}
279 233
280 234