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

+72 -34
+65 -24
fs/9p/vfs_dir.c
··· 40 #include "fid.h" 41 42 /** 43 * dt_type - return file type 44 * @mistat: mistat structure 45 * ··· 88 { 89 int over; 90 struct p9_wstat st; 91 - int err; 92 struct p9_fid *fid; 93 int buflen; 94 - char *statbuf; 95 - int n, i = 0; 96 97 P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name); 98 fid = filp->private_data; 99 100 buflen = fid->clnt->msize - P9_IOHDRSZ; 101 - statbuf = kmalloc(buflen, GFP_KERNEL); 102 - if (!statbuf) 103 - return -ENOMEM; 104 105 - while (1) { 106 - err = v9fs_file_readn(filp, statbuf, NULL, buflen, 107 - fid->rdir_fpos); 108 - if (err <= 0) 109 - break; 110 111 - n = err; 112 - while (i < n) { 113 - err = p9stat_read(statbuf + i, buflen-i, &st, 114 - fid->clnt->dotu); 115 if (err) { 116 P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err); 117 err = -EIO; 118 p9stat_free(&st); 119 - goto free_and_exit; 120 } 121 - 122 - i += st.size+2; 123 - fid->rdir_fpos += st.size+2; 124 125 over = filldir(dirent, st.name, strlen(st.name), 126 filp->f_pos, v9fs_qid2ino(&st.qid), dt_type(&st)); 127 - 128 - filp->f_pos += st.size+2; 129 130 p9stat_free(&st); 131 132 if (over) { 133 err = 0; 134 - goto free_and_exit; 135 } 136 } 137 } 138 139 - free_and_exit: 140 - kfree(statbuf); 141 return err; 142 } 143
··· 40 #include "fid.h" 41 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 + 53 + struct p9_rdir { 54 + struct mutex mutex; 55 + int head; 56 + int tail; 57 + uint8_t *buf; 58 + }; 59 + 60 + /** 61 * dt_type - return file type 62 * @mistat: mistat structure 63 * ··· 70 { 71 int over; 72 struct p9_wstat st; 73 + int err = 0; 74 struct p9_fid *fid; 75 int buflen; 76 + int reclen = 0; 77 + struct p9_rdir *rdir; 78 79 P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", filp->f_path.dentry->d_name.name); 80 fid = filp->private_data; 81 82 buflen = fid->clnt->msize - P9_IOHDRSZ; 83 84 + /* allocate rdir on demand */ 85 + if (!fid->rdir) { 86 + rdir = kmalloc(sizeof(struct p9_rdir) + buflen, GFP_KERNEL); 87 88 + if (rdir == NULL) { 89 + err = -ENOMEM; 90 + goto exit; 91 + } 92 + spin_lock(&filp->f_dentry->d_lock); 93 + if (!fid->rdir) { 94 + rdir->buf = (uint8_t *)rdir + sizeof(struct p9_rdir); 95 + mutex_init(&rdir->mutex); 96 + rdir->head = rdir->tail = 0; 97 + fid->rdir = (void *) rdir; 98 + rdir = NULL; 99 + } 100 + spin_unlock(&filp->f_dentry->d_lock); 101 + kfree(rdir); 102 + } 103 + rdir = (struct p9_rdir *) fid->rdir; 104 + 105 + err = mutex_lock_interruptible(&rdir->mutex); 106 + while (err == 0) { 107 + if (rdir->tail == rdir->head) { 108 + err = v9fs_file_readn(filp, rdir->buf, NULL, 109 + buflen, filp->f_pos); 110 + if (err <= 0) 111 + goto unlock_and_exit; 112 + 113 + rdir->head = 0; 114 + rdir->tail = err; 115 + } 116 + 117 + while (rdir->head < rdir->tail) { 118 + err = p9stat_read(rdir->buf + rdir->head, 119 + buflen - rdir->head, &st, 120 + fid->clnt->dotu); 121 if (err) { 122 P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err); 123 err = -EIO; 124 p9stat_free(&st); 125 + goto unlock_and_exit; 126 } 127 + reclen = st.size+2; 128 129 over = filldir(dirent, st.name, strlen(st.name), 130 filp->f_pos, v9fs_qid2ino(&st.qid), dt_type(&st)); 131 132 p9stat_free(&st); 133 134 if (over) { 135 err = 0; 136 + goto unlock_and_exit; 137 } 138 + rdir->head += reclen; 139 + filp->f_pos += reclen; 140 } 141 } 142 143 + unlock_and_exit: 144 + mutex_unlock(&rdir->mutex); 145 + exit: 146 return err; 147 } 148
+2 -3
fs/9p/vfs_inode.c
··· 994 P9_DPRINTK(P9_DEBUG_VFS, 995 "%s -> %s (%s)\n", dentry->d_name.name, st->extension, buffer); 996 997 - retval = buflen; 998 - 999 done: 1000 kfree(st); 1001 return retval; ··· 1061 __putname(link); 1062 link = ERR_PTR(len); 1063 } else 1064 - link[len] = 0; 1065 } 1066 nd_set_link(nd, link); 1067
··· 994 P9_DPRINTK(P9_DEBUG_VFS, 995 "%s -> %s (%s)\n", dentry->d_name.name, st->extension, buffer); 996 997 + retval = strnlen(buffer, buflen); 998 done: 999 kfree(st); 1000 return retval; ··· 1062 __putname(link); 1063 link = ERR_PTR(len); 1064 } else 1065 + link[min(len, PATH_MAX-1)] = 0; 1066 } 1067 nd_set_link(nd, link); 1068
+3 -4
include/net/9p/client.h
··· 159 * @qid: the &p9_qid server identifier this handle points to 160 * @iounit: the server reported maximum transaction size for this file 161 * @uid: the numeric uid of the local user who owns this handle 162 - * @aux: transport specific information (unused?) 163 - * @rdir_fpos: tracks offset of file position when reading directory contents 164 * @flist: per-client-instance fid tracking 165 * @dlist: per-dentry fid tracking 166 * ··· 173 struct p9_qid qid; 174 u32 iounit; 175 uid_t uid; 176 - void *aux; 177 178 - int rdir_fpos; 179 struct list_head flist; 180 struct list_head dlist; /* list of all fids attached to a dentry */ 181 };
··· 159 * @qid: the &p9_qid server identifier this handle points to 160 * @iounit: the server reported maximum transaction size for this file 161 * @uid: the numeric uid of the local user who owns this handle 162 + * @rdir: readdir accounting structure (allocated on demand) 163 * @flist: per-client-instance fid tracking 164 * @dlist: per-dentry fid tracking 165 * ··· 174 struct p9_qid qid; 175 u32 iounit; 176 uid_t uid; 177 178 + void *rdir; 179 + 180 struct list_head flist; 181 struct list_head dlist; /* list of all fids attached to a dentry */ 182 };
+2 -3
net/9p/client.c
··· 582 583 memset(&fid->qid, 0, sizeof(struct p9_qid)); 584 fid->mode = -1; 585 - fid->rdir_fpos = 0; 586 fid->uid = current_fsuid(); 587 fid->clnt = clnt; 588 - fid->aux = NULL; 589 - 590 spin_lock_irqsave(&clnt->lock, flags); 591 list_add(&fid->flist, &clnt->fidlist); 592 spin_unlock_irqrestore(&clnt->lock, flags); ··· 607 spin_lock_irqsave(&clnt->lock, flags); 608 list_del(&fid->flist); 609 spin_unlock_irqrestore(&clnt->lock, flags); 610 kfree(fid); 611 } 612
··· 582 583 memset(&fid->qid, 0, sizeof(struct p9_qid)); 584 fid->mode = -1; 585 fid->uid = current_fsuid(); 586 fid->clnt = clnt; 587 + fid->rdir = NULL; 588 spin_lock_irqsave(&clnt->lock, flags); 589 list_add(&fid->flist, &clnt->fidlist); 590 spin_unlock_irqrestore(&clnt->lock, flags); ··· 609 spin_lock_irqsave(&clnt->lock, flags); 610 list_del(&fid->flist); 611 spin_unlock_irqrestore(&clnt->lock, flags); 612 + kfree(fid->rdir); 613 kfree(fid); 614 } 615