@@ -75,6 +75,7 @@ static int v9fs_dir_readdir(struct file *filp, void *dirent,
int buflen;
char *statbuf;
int n, i = 0;
+ int reclen = 0;
P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name
fid = filp->private_data;
@@ -85,13 +86,35 @@ static int v9fs_dir_readdir(struct file *filp, void *diren
return -ENOMEM;
while (1) {
- err = v9fs_file_readn(filp, statbuf, NULL, buflen,
+ if (fid->rdir_fpos > filp->f_pos) {
+ n = fid->rdir_fpos - filp->f_pos;
+ if (n > buflen) {
+ printk(KERN_ERR
+ "9p: readdir: n=%d buflen=%d\n",
+ n, buflen);
+ err = -EIO;
+ goto free_and_exit;
+ }
+ if (!fid->aux) {
+ printk(KERN_ERR
+ "9p: readdir: null aux rd=%d fp=%d\n",
+ fid->rdir_fpos, filp->f_pos);
+ err = -EIO;
+ goto free_and_exit;
+ }
+ memcpy(statbuf, fid->aux, n);
+ /* TODO: would it make more sense to leave buffer? */
+ kfree(fid->aux);
+ fid->aux = NULL;
+ } else {
+ err = v9fs_file_readn(filp, statbuf, NULL, buflen,
fid->rdir_fpos
- if (err <= 0)
- break;
-
+ if (err <= 0)
+ break;
+ n = err;
+ fid->rdir_fpos += n;
+ }
i = 0;
- n = err;
while (i < n) {
err = p9stat_read(statbuf + i, buflen-i, &st,
fid->clnt->dotu);
@@ -101,21 +124,32 @@ static int v9fs_dir_readdir(struct file *filp, void *dir
p9stat_free(&st);
goto free_and_exit;
}
-
- i += st.size+2;
- fid->rdir_fpos += st.size+2;
+ reclen = st.size+2;
over = filldir(dirent, st.name, strlen(st.name),
filp->f_pos, v9fs_qid2ino(&st.qid), dt_type(&st));
- filp->f_pos += st.size+2;
-
p9stat_free(&st);
if (over) {
+ /* TODO: alloc msize buffer instead? */
+ if (fid->aux) {
+ printk(KERN_ERR "9p: readdir: aux\n");
+ err = -EIO;
+ goto free_and_exit;
+ }
+ fid->aux = kmalloc(n - i, GFP_KERNEL);
+ if (!fid->aux) {
+ err = -ENOMEM;
+ goto free_and_exit;
+ }
+ memcpy(fid->aux, statbuf + i, n - i);
+
err = 0;
goto free_and_exit;
}
+ filp->f_pos += reclen;
+ i += reclen;
}
}
@@ -609,6 +609,8 @@ static void p9_fid_destroy(struct p9_fid *fid)
spin_lock_irqsave(&clnt->lock, flags);
list_del(&fid->flist);
spin_unlock_irqrestore(&clnt->lock, flags);
+ if (fid->aux)
+ kfree(fid->aux);
kfree(fid);
}