0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/module.h>
0010 #include <linux/errno.h>
0011 #include <linux/fs.h>
0012 #include <linux/file.h>
0013 #include <linux/stat.h>
0014 #include <linux/string.h>
0015 #include <linux/sched.h>
0016 #include <linux/inet.h>
0017 #include <linux/idr.h>
0018 #include <linux/slab.h>
0019 #include <linux/uio.h>
0020 #include <linux/fscache.h>
0021 #include <net/9p/9p.h>
0022 #include <net/9p/client.h>
0023
0024 #include "v9fs.h"
0025 #include "v9fs_vfs.h"
0026 #include "fid.h"
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038 struct p9_rdir {
0039 int head;
0040 int tail;
0041 uint8_t buf[];
0042 };
0043
0044
0045
0046
0047
0048
0049
0050 static inline int dt_type(struct p9_wstat *mistat)
0051 {
0052 unsigned long perm = mistat->mode;
0053 int rettype = DT_REG;
0054
0055 if (perm & P9_DMDIR)
0056 rettype = DT_DIR;
0057 if (perm & P9_DMSYMLINK)
0058 rettype = DT_LNK;
0059
0060 return rettype;
0061 }
0062
0063
0064
0065
0066
0067
0068
0069
0070 static struct p9_rdir *v9fs_alloc_rdir_buf(struct file *filp, int buflen)
0071 {
0072 struct p9_fid *fid = filp->private_data;
0073
0074 if (!fid->rdir)
0075 fid->rdir = kzalloc(sizeof(struct p9_rdir) + buflen, GFP_KERNEL);
0076 return fid->rdir;
0077 }
0078
0079
0080
0081
0082
0083
0084
0085
0086 static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx)
0087 {
0088 bool over;
0089 struct p9_wstat st;
0090 int err = 0;
0091 struct p9_fid *fid;
0092 int buflen;
0093 struct p9_rdir *rdir;
0094 struct kvec kvec;
0095
0096 p9_debug(P9_DEBUG_VFS, "name %pD\n", file);
0097 fid = file->private_data;
0098
0099 buflen = fid->clnt->msize - P9_IOHDRSZ;
0100
0101 rdir = v9fs_alloc_rdir_buf(file, buflen);
0102 if (!rdir)
0103 return -ENOMEM;
0104 kvec.iov_base = rdir->buf;
0105 kvec.iov_len = buflen;
0106
0107 while (1) {
0108 if (rdir->tail == rdir->head) {
0109 struct iov_iter to;
0110 int n;
0111
0112 iov_iter_kvec(&to, READ, &kvec, 1, buflen);
0113 n = p9_client_read(file->private_data, ctx->pos, &to,
0114 &err);
0115 if (err)
0116 return err;
0117 if (n == 0)
0118 return 0;
0119
0120 rdir->head = 0;
0121 rdir->tail = n;
0122 }
0123 while (rdir->head < rdir->tail) {
0124 err = p9stat_read(fid->clnt, rdir->buf + rdir->head,
0125 rdir->tail - rdir->head, &st);
0126 if (err <= 0) {
0127 p9_debug(P9_DEBUG_VFS, "returned %d\n", err);
0128 return -EIO;
0129 }
0130
0131 over = !dir_emit(ctx, st.name, strlen(st.name),
0132 v9fs_qid2ino(&st.qid), dt_type(&st));
0133 p9stat_free(&st);
0134 if (over)
0135 return 0;
0136
0137 rdir->head += err;
0138 ctx->pos += err;
0139 }
0140 }
0141 }
0142
0143
0144
0145
0146
0147
0148
0149 static int v9fs_dir_readdir_dotl(struct file *file, struct dir_context *ctx)
0150 {
0151 int err = 0;
0152 struct p9_fid *fid;
0153 int buflen;
0154 struct p9_rdir *rdir;
0155 struct p9_dirent curdirent;
0156
0157 p9_debug(P9_DEBUG_VFS, "name %pD\n", file);
0158 fid = file->private_data;
0159
0160 buflen = fid->clnt->msize - P9_READDIRHDRSZ;
0161
0162 rdir = v9fs_alloc_rdir_buf(file, buflen);
0163 if (!rdir)
0164 return -ENOMEM;
0165
0166 while (1) {
0167 if (rdir->tail == rdir->head) {
0168 err = p9_client_readdir(fid, rdir->buf, buflen,
0169 ctx->pos);
0170 if (err <= 0)
0171 return err;
0172
0173 rdir->head = 0;
0174 rdir->tail = err;
0175 }
0176
0177 while (rdir->head < rdir->tail) {
0178
0179 err = p9dirent_read(fid->clnt, rdir->buf + rdir->head,
0180 rdir->tail - rdir->head,
0181 &curdirent);
0182 if (err < 0) {
0183 p9_debug(P9_DEBUG_VFS, "returned %d\n", err);
0184 return -EIO;
0185 }
0186
0187 if (!dir_emit(ctx, curdirent.d_name,
0188 strlen(curdirent.d_name),
0189 v9fs_qid2ino(&curdirent.qid),
0190 curdirent.d_type))
0191 return 0;
0192
0193 ctx->pos = curdirent.d_off;
0194 rdir->head += err;
0195 }
0196 }
0197 }
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207 int v9fs_dir_release(struct inode *inode, struct file *filp)
0208 {
0209 struct v9fs_inode *v9inode = V9FS_I(inode);
0210 struct p9_fid *fid;
0211 __le32 version;
0212 loff_t i_size;
0213
0214 fid = filp->private_data;
0215 p9_debug(P9_DEBUG_VFS, "inode: %p filp: %p fid: %d\n",
0216 inode, filp, fid ? fid->fid : -1);
0217 if (fid) {
0218 spin_lock(&inode->i_lock);
0219 hlist_del(&fid->ilist);
0220 spin_unlock(&inode->i_lock);
0221 p9_fid_put(fid);
0222 }
0223
0224 if ((filp->f_mode & FMODE_WRITE)) {
0225 version = cpu_to_le32(v9inode->qid.version);
0226 i_size = i_size_read(inode);
0227 fscache_unuse_cookie(v9fs_inode_cookie(v9inode),
0228 &version, &i_size);
0229 } else {
0230 fscache_unuse_cookie(v9fs_inode_cookie(v9inode), NULL, NULL);
0231 }
0232 return 0;
0233 }
0234
0235 const struct file_operations v9fs_dir_operations = {
0236 .read = generic_read_dir,
0237 .llseek = generic_file_llseek,
0238 .iterate_shared = v9fs_dir_readdir,
0239 .open = v9fs_file_open,
0240 .release = v9fs_dir_release,
0241 };
0242
0243 const struct file_operations v9fs_dir_operations_dotl = {
0244 .read = generic_read_dir,
0245 .llseek = generic_file_llseek,
0246 .iterate_shared = v9fs_dir_readdir_dotl,
0247 .open = v9fs_file_open,
0248 .release = v9fs_dir_release,
0249 .fsync = v9fs_file_fsync_dotl,
0250 };