~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/9p/vfs_dir.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * This file contains vfs directory ops for the 9P2000 protocol.
  4  *
  5  *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
  6  *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
  7  */
  8 
  9 #include <linux/module.h>
 10 #include <linux/errno.h>
 11 #include <linux/fs.h>
 12 #include <linux/file.h>
 13 #include <linux/stat.h>
 14 #include <linux/string.h>
 15 #include <linux/sched.h>
 16 #include <linux/slab.h>
 17 #include <linux/uio.h>
 18 #include <linux/fscache.h>
 19 #include <net/9p/9p.h>
 20 #include <net/9p/client.h>
 21 
 22 #include "v9fs.h"
 23 #include "v9fs_vfs.h"
 24 #include "fid.h"
 25 
 26 /**
 27  * struct p9_rdir - readdir accounting
 28  * @head: start offset of current dirread buffer
 29  * @tail: end offset of current dirread buffer
 30  * @buf: dirread buffer
 31  *
 32  * private structure for keeping track of readdir
 33  * allocated on demand
 34  */
 35 
 36 struct p9_rdir {
 37         int head;
 38         int tail;
 39         uint8_t buf[];
 40 };
 41 
 42 /**
 43  * dt_type - return file type
 44  * @mistat: mistat structure
 45  *
 46  */
 47 
 48 static inline int dt_type(struct p9_wstat *mistat)
 49 {
 50         unsigned long perm = mistat->mode;
 51         int rettype = DT_REG;
 52 
 53         if (perm & P9_DMDIR)
 54                 rettype = DT_DIR;
 55         if (perm & P9_DMSYMLINK)
 56                 rettype = DT_LNK;
 57 
 58         return rettype;
 59 }
 60 
 61 /**
 62  * v9fs_alloc_rdir_buf - Allocate buffer used for read and readdir
 63  * @filp: opened file structure
 64  * @buflen: Length in bytes of buffer to allocate
 65  *
 66  */
 67 
 68 static struct p9_rdir *v9fs_alloc_rdir_buf(struct file *filp, int buflen)
 69 {
 70         struct p9_fid *fid = filp->private_data;
 71 
 72         if (!fid->rdir)
 73                 fid->rdir = kzalloc(sizeof(struct p9_rdir) + buflen, GFP_KERNEL);
 74         return fid->rdir;
 75 }
 76 
 77 /**
 78  * v9fs_dir_readdir - iterate through a directory
 79  * @file: opened file structure
 80  * @ctx: actor we feed the entries to
 81  *
 82  */
 83 
 84 static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx)
 85 {
 86         bool over;
 87         struct p9_wstat st;
 88         int err = 0;
 89         struct p9_fid *fid;
 90         int buflen;
 91         struct p9_rdir *rdir;
 92         struct kvec kvec;
 93 
 94         p9_debug(P9_DEBUG_VFS, "name %pD\n", file);
 95         fid = file->private_data;
 96 
 97         buflen = fid->clnt->msize - P9_IOHDRSZ;
 98 
 99         rdir = v9fs_alloc_rdir_buf(file, buflen);
100         if (!rdir)
101                 return -ENOMEM;
102         kvec.iov_base = rdir->buf;
103         kvec.iov_len = buflen;
104 
105         while (1) {
106                 if (rdir->tail == rdir->head) {
107                         struct iov_iter to;
108                         int n;
109 
110                         iov_iter_kvec(&to, ITER_DEST, &kvec, 1, buflen);
111                         n = p9_client_read(file->private_data, ctx->pos, &to,
112                                            &err);
113                         if (err)
114                                 return err;
115                         if (n == 0)
116                                 return 0;
117 
118                         rdir->head = 0;
119                         rdir->tail = n;
120                 }
121                 while (rdir->head < rdir->tail) {
122                         err = p9stat_read(fid->clnt, rdir->buf + rdir->head,
123                                           rdir->tail - rdir->head, &st);
124                         if (err <= 0) {
125                                 p9_debug(P9_DEBUG_VFS, "returned %d\n", err);
126                                 return -EIO;
127                         }
128 
129                         over = !dir_emit(ctx, st.name, strlen(st.name),
130                                         QID2INO(&st.qid), dt_type(&st));
131                         p9stat_free(&st);
132                         if (over)
133                                 return 0;
134 
135                         rdir->head += err;
136                         ctx->pos += err;
137                 }
138         }
139 }
140 
141 /**
142  * v9fs_dir_readdir_dotl - iterate through a directory
143  * @file: opened file structure
144  * @ctx: actor we feed the entries to
145  *
146  */
147 static int v9fs_dir_readdir_dotl(struct file *file, struct dir_context *ctx)
148 {
149         int err = 0;
150         struct p9_fid *fid;
151         int buflen;
152         struct p9_rdir *rdir;
153         struct p9_dirent curdirent;
154 
155         p9_debug(P9_DEBUG_VFS, "name %pD\n", file);
156         fid = file->private_data;
157 
158         buflen = fid->clnt->msize - P9_READDIRHDRSZ;
159 
160         rdir = v9fs_alloc_rdir_buf(file, buflen);
161         if (!rdir)
162                 return -ENOMEM;
163 
164         while (1) {
165                 if (rdir->tail == rdir->head) {
166                         err = p9_client_readdir(fid, rdir->buf, buflen,
167                                                 ctx->pos);
168                         if (err <= 0)
169                                 return err;
170 
171                         rdir->head = 0;
172                         rdir->tail = err;
173                 }
174 
175                 while (rdir->head < rdir->tail) {
176 
177                         err = p9dirent_read(fid->clnt, rdir->buf + rdir->head,
178                                             rdir->tail - rdir->head,
179                                             &curdirent);
180                         if (err < 0) {
181                                 p9_debug(P9_DEBUG_VFS, "returned %d\n", err);
182                                 return -EIO;
183                         }
184 
185                         if (!dir_emit(ctx, curdirent.d_name,
186                                       strlen(curdirent.d_name),
187                                       QID2INO(&curdirent.qid),
188                                       curdirent.d_type))
189                                 return 0;
190 
191                         ctx->pos = curdirent.d_off;
192                         rdir->head += err;
193                 }
194         }
195 }
196 
197 
198 /**
199  * v9fs_dir_release - close a directory or a file
200  * @inode: inode of the directory or file
201  * @filp: file pointer to a directory or file
202  *
203  */
204 
205 int v9fs_dir_release(struct inode *inode, struct file *filp)
206 {
207         struct v9fs_inode *v9inode = V9FS_I(inode);
208         struct p9_fid *fid;
209         __le32 version;
210         loff_t i_size;
211         int retval = 0, put_err;
212 
213         fid = filp->private_data;
214         p9_debug(P9_DEBUG_VFS, "inode: %p filp: %p fid: %d\n",
215                  inode, filp, fid ? fid->fid : -1);
216 
217         if (fid) {
218                 if ((S_ISREG(inode->i_mode)) && (filp->f_mode & FMODE_WRITE))
219                         retval = filemap_fdatawrite(inode->i_mapping);
220 
221                 spin_lock(&inode->i_lock);
222                 hlist_del(&fid->ilist);
223                 spin_unlock(&inode->i_lock);
224                 put_err = p9_fid_put(fid);
225                 retval = retval < 0 ? retval : put_err;
226         }
227 
228         if ((filp->f_mode & FMODE_WRITE)) {
229                 version = cpu_to_le32(v9inode->qid.version);
230                 i_size = i_size_read(inode);
231                 fscache_unuse_cookie(v9fs_inode_cookie(v9inode),
232                                      &version, &i_size);
233         } else {
234                 fscache_unuse_cookie(v9fs_inode_cookie(v9inode), NULL, NULL);
235         }
236         return retval;
237 }
238 
239 const struct file_operations v9fs_dir_operations = {
240         .read = generic_read_dir,
241         .llseek = generic_file_llseek,
242         .iterate_shared = v9fs_dir_readdir,
243         .open = v9fs_file_open,
244         .release = v9fs_dir_release,
245 };
246 
247 const struct file_operations v9fs_dir_operations_dotl = {
248         .read = generic_read_dir,
249         .llseek = generic_file_llseek,
250         .iterate_shared = v9fs_dir_readdir_dotl,
251         .open = v9fs_file_open,
252         .release = v9fs_dir_release,
253         .fsync = v9fs_file_fsync_dotl,
254 };
255 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php