aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/9p/vfs_dir.c134
-rw-r--r--include/net/9p/9p.h17
-rw-r--r--include/net/9p/client.h18
-rw-r--r--net/9p/client.c47
-rw-r--r--net/9p/protocol.c27
5 files changed, 227 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
97static int v9fs_dir_readdir(struct file *filp, void *dirent, filldir_t filldir) 96static 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 }
121exit:
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
133static 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 */
206static 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
275unlock_and_exit:
276 mutex_unlock(&rdir->mutex);
277exit:
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 = {
207const struct file_operations v9fs_dir_operations_dotl = { 309const 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};
diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h
index 156c26bb8bd7..f1b0b310265d 100644
--- a/include/net/9p/9p.h
+++ b/include/net/9p/9p.h
@@ -133,6 +133,8 @@ enum p9_msg_t {
133 P9_RSTATFS, 133 P9_RSTATFS,
134 P9_TRENAME = 20, 134 P9_TRENAME = 20,
135 P9_RRENAME, 135 P9_RRENAME,
136 P9_TREADDIR = 40,
137 P9_RREADDIR,
136 P9_TVERSION = 100, 138 P9_TVERSION = 100,
137 P9_RVERSION, 139 P9_RVERSION,
138 P9_TAUTH = 102, 140 P9_TAUTH = 102,
@@ -275,6 +277,9 @@ enum p9_qid_t {
275/* ample room for Twrite/Rread header */ 277/* ample room for Twrite/Rread header */
276#define P9_IOHDRSZ 24 278#define P9_IOHDRSZ 24
277 279
280/* Room for readdir header */
281#define P9_READDIRHDRSZ 24
282
278/** 283/**
279 * struct p9_str - length prefixed string type 284 * struct p9_str - length prefixed string type
280 * @len: length of the string 285 * @len: length of the string
@@ -485,6 +490,18 @@ struct p9_rwrite {
485 u32 count; 490 u32 count;
486}; 491};
487 492
493struct p9_treaddir {
494 u32 fid;
495 u64 offset;
496 u32 count;
497};
498
499struct p9_rreaddir {
500 u32 count;
501 u8 *data;
502};
503
504
488struct p9_tclunk { 505struct p9_tclunk {
489 u32 fid; 506 u32 fid;
490}; 507};
diff --git a/include/net/9p/client.h b/include/net/9p/client.h
index 7dd3ed85c782..2ec93685e6db 100644
--- a/include/net/9p/client.h
+++ b/include/net/9p/client.h
@@ -195,6 +195,21 @@ struct p9_fid {
195 struct list_head dlist; /* list of all fids attached to a dentry */ 195 struct list_head dlist; /* list of all fids attached to a dentry */
196}; 196};
197 197
198/**
199 * struct p9_dirent - directory entry structure
200 * @qid: The p9 server qid for this dirent
201 * @d_off: offset to the next dirent
202 * @d_type: type of file
203 * @d_name: file name
204 */
205
206struct p9_dirent {
207 struct p9_qid qid;
208 u64 d_off;
209 unsigned char d_type;
210 char d_name[256];
211};
212
198int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb); 213int p9_client_statfs(struct p9_fid *fid, struct p9_rstatfs *sb);
199int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid, char *name); 214int p9_client_rename(struct p9_fid *fid, struct p9_fid *newdirfid, char *name);
200int p9_client_version(struct p9_client *); 215int p9_client_version(struct p9_client *);
@@ -217,6 +232,9 @@ int p9_client_read(struct p9_fid *fid, char *data, char __user *udata,
217 u64 offset, u32 count); 232 u64 offset, u32 count);
218int p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, 233int p9_client_write(struct p9_fid *fid, char *data, const char __user *udata,
219 u64 offset, u32 count); 234 u64 offset, u32 count);
235int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset);
236int p9dirent_read(char *buf, int len, struct p9_dirent *dirent,
237 int proto_version);
220struct p9_wstat *p9_client_stat(struct p9_fid *fid); 238struct p9_wstat *p9_client_stat(struct p9_fid *fid);
221int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst); 239int p9_client_wstat(struct p9_fid *fid, struct p9_wstat *wst);
222 240
diff --git a/net/9p/client.c b/net/9p/client.c
index 37c8da07a80b..a80357483a47 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -1432,3 +1432,50 @@ error:
1432} 1432}
1433EXPORT_SYMBOL(p9_client_rename); 1433EXPORT_SYMBOL(p9_client_rename);
1434 1434
1435int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset)
1436{
1437 int err, rsize, total;
1438 struct p9_client *clnt;
1439 struct p9_req_t *req;
1440 char *dataptr;
1441
1442 P9_DPRINTK(P9_DEBUG_9P, ">>> TREADDIR fid %d offset %llu count %d\n",
1443 fid->fid, (long long unsigned) offset, count);
1444
1445 err = 0;
1446 clnt = fid->clnt;
1447 total = 0;
1448
1449 rsize = fid->iounit;
1450 if (!rsize || rsize > clnt->msize-P9_READDIRHDRSZ)
1451 rsize = clnt->msize - P9_READDIRHDRSZ;
1452
1453 if (count < rsize)
1454 rsize = count;
1455
1456 req = p9_client_rpc(clnt, P9_TREADDIR, "dqd", fid->fid, offset, rsize);
1457 if (IS_ERR(req)) {
1458 err = PTR_ERR(req);
1459 goto error;
1460 }
1461
1462 err = p9pdu_readf(req->rc, clnt->proto_version, "D", &count, &dataptr);
1463 if (err) {
1464 p9pdu_dump(1, req->rc);
1465 goto free_and_error;
1466 }
1467
1468 P9_DPRINTK(P9_DEBUG_9P, "<<< RREADDIR count %d\n", count);
1469
1470 if (data)
1471 memmove(data, dataptr, count);
1472
1473 p9_free_req(clnt, req);
1474 return count;
1475
1476free_and_error:
1477 p9_free_req(clnt, req);
1478error:
1479 return err;
1480}
1481EXPORT_SYMBOL(p9_client_readdir);
diff --git a/net/9p/protocol.c b/net/9p/protocol.c
index 149f82160130..b645c8263538 100644
--- a/net/9p/protocol.c
+++ b/net/9p/protocol.c
@@ -580,3 +580,30 @@ void p9pdu_reset(struct p9_fcall *pdu)
580 pdu->offset = 0; 580 pdu->offset = 0;
581 pdu->size = 0; 581 pdu->size = 0;
582} 582}
583
584int p9dirent_read(char *buf, int len, struct p9_dirent *dirent,
585 int proto_version)
586{
587 struct p9_fcall fake_pdu;
588 int ret;
589 char *nameptr;
590
591 fake_pdu.size = len;
592 fake_pdu.capacity = len;
593 fake_pdu.sdata = buf;
594 fake_pdu.offset = 0;
595
596 ret = p9pdu_readf(&fake_pdu, proto_version, "Qqbs", &dirent->qid,
597 &dirent->d_off, &dirent->d_type, &nameptr);
598 if (ret) {
599 P9_DPRINTK(P9_DEBUG_9P, "<<< p9dirent_read failed: %d\n", ret);
600 p9pdu_dump(1, &fake_pdu);
601 goto out;
602 }
603
604 strcpy(dirent->d_name, nameptr);
605
606out:
607 return fake_pdu.offset;
608}
609EXPORT_SYMBOL(p9dirent_read);