diff options
Diffstat (limited to 'fs/9p')
-rw-r--r-- | fs/9p/vfs_dir.c | 134 |
1 files changed, 118 insertions, 16 deletions
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c index 36d961f342af..16c8a2a98c1b 100644 --- a/fs/9p/vfs_dir.c +++ b/fs/9p/vfs_dir.c | |||
@@ -87,29 +87,19 @@ static void p9stat_init(struct p9_wstat *stbuf) | |||
87 | } | 87 | } |
88 | 88 | ||
89 | /** | 89 | /** |
90 | * v9fs_dir_readdir - read a directory | 90 | * v9fs_alloc_rdir_buf - Allocate buffer used for read and readdir |
91 | * @filp: opened file structure | 91 | * @filp: opened file structure |
92 | * @dirent: directory structure ??? | 92 | * @buflen: Length in bytes of buffer to allocate |
93 | * @filldir: function to populate directory structure ??? | ||
94 | * | 93 | * |
95 | */ | 94 | */ |
96 | 95 | ||
97 | static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) | 96 | static int v9fs_alloc_rdir_buf(struct file *filp, int buflen) |
98 | { | 97 | { |
99 | int over; | ||
100 | struct p9_wstat st; | ||
101 | int err = 0; | ||
102 | struct p9_fid *fid; | ||
103 | int buflen; | ||
104 | int reclen = 0; | ||
105 | struct p9_rdir *rdir; | 98 | struct p9_rdir *rdir; |
99 | struct p9_fid *fid; | ||
100 | int err = 0; | ||
106 | 101 | ||
107 | P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name); | ||
108 | fid = filp->private_data; | 102 | fid = filp->private_data; |
109 | |||
110 | buflen = fid->clnt->msize - P9_IOHDRSZ; | ||
111 | |||
112 | /* allocate rdir on demand */ | ||
113 | if (!fid->rdir) { | 103 | if (!fid->rdir) { |
114 | rdir = kmalloc(sizeof(struct p9_rdir) + buflen, GFP_KERNEL); | 104 | rdir = kmalloc(sizeof(struct p9_rdir) + buflen, GFP_KERNEL); |
115 | 105 | ||
@@ -128,6 +118,36 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
128 | spin_unlock(&filp->f_dentry->d_lock); | 118 | spin_unlock(&filp->f_dentry->d_lock); |
129 | kfree(rdir); | 119 | kfree(rdir); |
130 | } | 120 | } |
121 | exit: | ||
122 | return err; | ||
123 | } | ||
124 | |||
125 | /** | ||
126 | * v9fs_dir_readdir - read a directory | ||
127 | * @filp: opened file structure | ||
128 | * @dirent: directory structure ??? | ||
129 | * @filldir: function to populate directory structure ??? | ||
130 | * | ||
131 | */ | ||
132 | |||
133 | static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) | ||
134 | { | ||
135 | int over; | ||
136 | struct p9_wstat st; | ||
137 | int err = 0; | ||
138 | struct p9_fid *fid; | ||
139 | int buflen; | ||
140 | int reclen = 0; | ||
141 | struct p9_rdir *rdir; | ||
142 | |||
143 | P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name); | ||
144 | fid = filp->private_data; | ||
145 | |||
146 | buflen = fid->clnt->msize - P9_IOHDRSZ; | ||
147 | |||
148 | err = v9fs_alloc_rdir_buf(filp, buflen); | ||
149 | if (err) | ||
150 | goto exit; | ||
131 | rdir = (struct p9_rdir *) fid->rdir; | 151 | rdir = (struct p9_rdir *) fid->rdir; |
132 | 152 | ||
133 | err = mutex_lock_interruptible(&rdir->mutex); | 153 | err = mutex_lock_interruptible(&rdir->mutex); |
@@ -176,6 +196,88 @@ exit: | |||
176 | return err; | 196 | return err; |
177 | } | 197 | } |
178 | 198 | ||
199 | /** | ||
200 | * v9fs_dir_readdir_dotl - read a directory | ||
201 | * @filp: opened file structure | ||
202 | * @dirent: buffer to fill dirent structures | ||
203 | * @filldir: function to populate dirent structures | ||
204 | * | ||
205 | */ | ||
206 | static int v9fs_dir_readdir_dotl(struct file *filp, void *dirent, | ||
207 | filldir_t filldir) | ||
208 | { | ||
209 | int over; | ||
210 | int err = 0; | ||
211 | struct p9_fid *fid; | ||
212 | int buflen; | ||
213 | struct p9_rdir *rdir; | ||
214 | struct p9_dirent curdirent; | ||
215 | u64 oldoffset = 0; | ||
216 | |||
217 | P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name); | ||
218 | fid = filp->private_data; | ||
219 | |||
220 | buflen = fid->clnt->msize - P9_READDIRHDRSZ; | ||
221 | |||
222 | err = v9fs_alloc_rdir_buf(filp, buflen); | ||
223 | if (err) | ||
224 | goto exit; | ||
225 | rdir = (struct p9_rdir *) fid->rdir; | ||
226 | |||
227 | err = mutex_lock_interruptible(&rdir->mutex); | ||
228 | if (err) | ||
229 | return err; | ||
230 | |||
231 | while (err == 0) { | ||
232 | if (rdir->tail == rdir->head) { | ||
233 | err = p9_client_readdir(fid, rdir->buf, buflen, | ||
234 | filp->f_pos); | ||
235 | if (err <= 0) | ||
236 | goto unlock_and_exit; | ||
237 | |||
238 | rdir->head = 0; | ||
239 | rdir->tail = err; | ||
240 | } | ||
241 | |||
242 | while (rdir->head < rdir->tail) { | ||
243 | |||
244 | err = p9dirent_read(rdir->buf + rdir->head, | ||
245 | buflen - rdir->head, &curdirent, | ||
246 | fid->clnt->proto_version); | ||
247 | if (err < 0) { | ||
248 | P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err); | ||
249 | err = -EIO; | ||
250 | goto unlock_and_exit; | ||
251 | } | ||
252 | |||
253 | /* d_off in dirent structure tracks the offset into | ||
254 | * the next dirent in the dir. However, filldir() | ||
255 | * expects offset into the current dirent. Hence | ||
256 | * while calling filldir send the offset from the | ||
257 | * previous dirent structure. | ||
258 | */ | ||
259 | over = filldir(dirent, curdirent.d_name, | ||
260 | strlen(curdirent.d_name), | ||
261 | oldoffset, v9fs_qid2ino(&curdirent.qid), | ||
262 | curdirent.d_type); | ||
263 | oldoffset = curdirent.d_off; | ||
264 | |||
265 | if (over) { | ||
266 | err = 0; | ||
267 | goto unlock_and_exit; | ||
268 | } | ||
269 | |||
270 | filp->f_pos = curdirent.d_off; | ||
271 | rdir->head += err; | ||
272 | } | ||
273 | } | ||
274 | |||
275 | unlock_and_exit: | ||
276 | mutex_unlock(&rdir->mutex); | ||
277 | exit: | ||
278 | return err; | ||
279 | } | ||
280 | |||
179 | 281 | ||
180 | /** | 282 | /** |
181 | * v9fs_dir_release - close a directory | 283 | * v9fs_dir_release - close a directory |
@@ -207,7 +309,7 @@ const struct file_operations v9fs_dir_operations = { | |||
207 | const struct file_operations v9fs_dir_operations_dotl = { | 309 | const struct file_operations v9fs_dir_operations_dotl = { |
208 | .read = generic_read_dir, | 310 | .read = generic_read_dir, |
209 | .llseek = generic_file_llseek, | 311 | .llseek = generic_file_llseek, |
210 | .readdir = v9fs_dir_readdir, | 312 | .readdir = v9fs_dir_readdir_dotl, |
211 | .open = v9fs_file_open, | 313 | .open = v9fs_file_open, |
212 | .release = v9fs_dir_release, | 314 | .release = v9fs_dir_release, |
213 | }; | 315 | }; |