]> git.ipfire.org Git - people/ms/linux.git/blame - fs/9p/vfs_dir.c
Merge tag 'soc-fixes-6.0-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
[people/ms/linux.git] / fs / 9p / vfs_dir.c
CommitLineData
1f327613 1// SPDX-License-Identifier: GPL-2.0-only
e69e7fe5 2/*
e69e7fe5
EVH
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>
e69e7fe5
EVH
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>
914e2637 15#include <linux/sched.h>
e69e7fe5
EVH
16#include <linux/inet.h>
17#include <linux/idr.h>
5a0e3ad6 18#include <linux/slab.h>
e1200fe6 19#include <linux/uio.h>
24e42e32 20#include <linux/fscache.h>
bd238fb4
LI
21#include <net/9p/9p.h>
22#include <net/9p/client.h>
e69e7fe5 23
e69e7fe5 24#include "v9fs.h"
531b1094 25#include "v9fs_vfs.h"
e69e7fe5
EVH
26#include "fid.h"
27
3e2796a9
EVH
28/**
29 * struct p9_rdir - readdir accounting
3e2796a9
EVH
30 * @head: start offset of current dirread buffer
31 * @tail: end offset of current dirread buffer
32 * @buf: dirread buffer
33 *
34 * private structure for keeping track of readdir
35 * allocated on demand
36 */
37
38struct p9_rdir {
3e2796a9
EVH
39 int head;
40 int tail;
7ffdea7e 41 uint8_t buf[];
3e2796a9
EVH
42};
43
e69e7fe5
EVH
44/**
45 * dt_type - return file type
46 * @mistat: mistat structure
47 *
48 */
49
02da398b 50static inline int dt_type(struct p9_wstat *mistat)
e69e7fe5
EVH
51{
52 unsigned long perm = mistat->mode;
53 int rettype = DT_REG;
54
bd238fb4 55 if (perm & P9_DMDIR)
e69e7fe5 56 rettype = DT_DIR;
bd238fb4 57 if (perm & P9_DMSYMLINK)
e69e7fe5
EVH
58 rettype = DT_LNK;
59
60 return rettype;
61}
62
63/**
7751bdb3 64 * v9fs_alloc_rdir_buf - Allocate buffer used for read and readdir
ee443996 65 * @filp: opened file structure
7751bdb3 66 * @buflen: Length in bytes of buffer to allocate
e69e7fe5
EVH
67 *
68 */
69
7ffdea7e 70static struct p9_rdir *v9fs_alloc_rdir_buf(struct file *filp, int buflen)
e69e7fe5 71{
7ffdea7e 72 struct p9_fid *fid = filp->private_data;
6d66ffc1 73
7ffdea7e
AV
74 if (!fid->rdir)
75 fid->rdir = kzalloc(sizeof(struct p9_rdir) + buflen, GFP_KERNEL);
76 return fid->rdir;
7751bdb3
SK
77}
78
79/**
8f29843a
AV
80 * v9fs_dir_readdir - iterate through a directory
81 * @file: opened file structure
82 * @ctx: actor we feed the entries to
7751bdb3
SK
83 *
84 */
85
8f29843a 86static int v9fs_dir_readdir(struct file *file, struct dir_context *ctx)
7751bdb3 87{
8f29843a 88 bool over;
7751bdb3
SK
89 struct p9_wstat st;
90 int err = 0;
91 struct p9_fid *fid;
92 int buflen;
7751bdb3 93 struct p9_rdir *rdir;
e1200fe6 94 struct kvec kvec;
7751bdb3 95
4b8e9923 96 p9_debug(P9_DEBUG_VFS, "name %pD\n", file);
8f29843a 97 fid = file->private_data;
7751bdb3
SK
98
99 buflen = fid->clnt->msize - P9_IOHDRSZ;
100
8f29843a 101 rdir = v9fs_alloc_rdir_buf(file, buflen);
7ffdea7e
AV
102 if (!rdir)
103 return -ENOMEM;
e1200fe6
AV
104 kvec.iov_base = rdir->buf;
105 kvec.iov_len = buflen;
3e2796a9 106
7ffdea7e 107 while (1) {
3e2796a9 108 if (rdir->tail == rdir->head) {
e1200fe6
AV
109 struct iov_iter to;
110 int n;
6d66ffc1 111
aa563d7b 112 iov_iter_kvec(&to, READ, &kvec, 1, buflen);
e1200fe6
AV
113 n = p9_client_read(file->private_data, ctx->pos, &to,
114 &err);
115 if (err)
7ffdea7e 116 return err;
8e3c5005
JB
117 if (n == 0)
118 return 0;
3e2796a9
EVH
119
120 rdir->head = 0;
e1200fe6 121 rdir->tail = n;
3e2796a9 122 }
3e2796a9 123 while (rdir->head < rdir->tail) {
348b5901
AK
124 err = p9stat_read(fid->clnt, rdir->buf + rdir->head,
125 rdir->tail - rdir->head, &st);
2803cf43 126 if (err <= 0) {
5d385153 127 p9_debug(P9_DEBUG_VFS, "returned %d\n", err);
7ffdea7e 128 return -EIO;
06b55b46 129 }
06b55b46 130
8f29843a
AV
131 over = !dir_emit(ctx, st.name, strlen(st.name),
132 v9fs_qid2ino(&st.qid), dt_type(&st));
02da398b 133 p9stat_free(&st);
7ffdea7e
AV
134 if (over)
135 return 0;
136
2803cf43
GH
137 rdir->head += err;
138 ctx->pos += err;
06b55b46 139 }
e69e7fe5 140 }
e69e7fe5
EVH
141}
142
7751bdb3 143/**
8f29843a
AV
144 * v9fs_dir_readdir_dotl - iterate through a directory
145 * @file: opened file structure
146 * @ctx: actor we feed the entries to
7751bdb3
SK
147 *
148 */
8f29843a 149static int v9fs_dir_readdir_dotl(struct file *file, struct dir_context *ctx)
7751bdb3 150{
7751bdb3
SK
151 int err = 0;
152 struct p9_fid *fid;
153 int buflen;
154 struct p9_rdir *rdir;
155 struct p9_dirent curdirent;
7751bdb3 156
4b8e9923 157 p9_debug(P9_DEBUG_VFS, "name %pD\n", file);
8f29843a 158 fid = file->private_data;
7751bdb3
SK
159
160 buflen = fid->clnt->msize - P9_READDIRHDRSZ;
161
8f29843a 162 rdir = v9fs_alloc_rdir_buf(file, buflen);
7ffdea7e
AV
163 if (!rdir)
164 return -ENOMEM;
7751bdb3 165
7ffdea7e 166 while (1) {
7751bdb3
SK
167 if (rdir->tail == rdir->head) {
168 err = p9_client_readdir(fid, rdir->buf, buflen,
8f29843a 169 ctx->pos);
7751bdb3 170 if (err <= 0)
7ffdea7e 171 return err;
7751bdb3
SK
172
173 rdir->head = 0;
174 rdir->tail = err;
175 }
176
177 while (rdir->head < rdir->tail) {
178
348b5901
AK
179 err = p9dirent_read(fid->clnt, rdir->buf + rdir->head,
180 rdir->tail - rdir->head,
181 &curdirent);
7751bdb3 182 if (err < 0) {
5d385153 183 p9_debug(P9_DEBUG_VFS, "returned %d\n", err);
7ffdea7e 184 return -EIO;
7751bdb3
SK
185 }
186
8f29843a
AV
187 if (!dir_emit(ctx, curdirent.d_name,
188 strlen(curdirent.d_name),
189 v9fs_qid2ino(&curdirent.qid),
190 curdirent.d_type))
7ffdea7e 191 return 0;
7751bdb3 192
8f29843a 193 ctx->pos = curdirent.d_off;
7751bdb3
SK
194 rdir->head += err;
195 }
196 }
7751bdb3
SK
197}
198
bd238fb4 199
e69e7fe5
EVH
200/**
201 * v9fs_dir_release - close a directory
202 * @inode: inode of the directory
203 * @filp: file pointer to a directory
204 *
205 */
206
207int v9fs_dir_release(struct inode *inode, struct file *filp)
208{
24e42e32 209 struct v9fs_inode *v9inode = V9FS_I(inode);
bd238fb4 210 struct p9_fid *fid;
24e42e32
DH
211 __le32 version;
212 loff_t i_size;
e69e7fe5 213
bd238fb4 214 fid = filp->private_data;
5d385153
JP
215 p9_debug(P9_DEBUG_VFS, "inode: %p filp: %p fid: %d\n",
216 inode, filp, fid ? fid->fid : -1);
6636b6dc
JW
217 if (fid) {
218 spin_lock(&inode->i_lock);
219 hlist_del(&fid->ilist);
220 spin_unlock(&inode->i_lock);
b48dbb99 221 p9_fid_put(fid);
6636b6dc 222 }
24e42e32
DH
223
224 if ((filp->f_mode & FMODE_WRITE)) {
225 version = cpu_to_le32(v9inode->qid.version);
226 i_size = i_size_read(inode);
227 fscache_unuse_cookie(v9fs_inode_cookie(v9inode),
228 &version, &i_size);
229 } else {
230 fscache_unuse_cookie(v9fs_inode_cookie(v9inode), NULL, NULL);
231 }
e69e7fe5
EVH
232 return 0;
233}
234
4b6f5d20 235const struct file_operations v9fs_dir_operations = {
e69e7fe5 236 .read = generic_read_dir,
59af1584 237 .llseek = generic_file_llseek,
5963ded8 238 .iterate_shared = v9fs_dir_readdir,
e69e7fe5
EVH
239 .open = v9fs_file_open,
240 .release = v9fs_dir_release,
241};
9b6533c9
SK
242
243const struct file_operations v9fs_dir_operations_dotl = {
244 .read = generic_read_dir,
245 .llseek = generic_file_llseek,
5963ded8 246 .iterate_shared = v9fs_dir_readdir_dotl,
9b6533c9
SK
247 .open = v9fs_file_open,
248 .release = v9fs_dir_release,
6d66ffc1 249 .fsync = v9fs_file_fsync_dotl,
9b6533c9 250};