Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0-only
2 : : /*
3 : : * linux/fs/9p/vfs_inode_dotl.c
4 : : *
5 : : * This file contains vfs inode ops for the 9P2000.L protocol.
6 : : *
7 : : * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
8 : : * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
9 : : */
10 : :
11 : : #include <linux/module.h>
12 : : #include <linux/errno.h>
13 : : #include <linux/fs.h>
14 : : #include <linux/file.h>
15 : : #include <linux/pagemap.h>
16 : : #include <linux/stat.h>
17 : : #include <linux/string.h>
18 : : #include <linux/inet.h>
19 : : #include <linux/namei.h>
20 : : #include <linux/idr.h>
21 : : #include <linux/sched.h>
22 : : #include <linux/slab.h>
23 : : #include <linux/xattr.h>
24 : : #include <linux/posix_acl.h>
25 : : #include <net/9p/9p.h>
26 : : #include <net/9p/client.h>
27 : :
28 : : #include "v9fs.h"
29 : : #include "v9fs_vfs.h"
30 : : #include "fid.h"
31 : : #include "cache.h"
32 : : #include "xattr.h"
33 : : #include "acl.h"
34 : :
35 : : static int
36 : : v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
37 : : dev_t rdev);
38 : :
39 : : /**
40 : : * v9fs_get_fsgid_for_create - Helper function to get the gid for creating a
41 : : * new file system object. This checks the S_ISGID to determine the owning
42 : : * group of the new file system object.
43 : : */
44 : :
45 : 0 : static kgid_t v9fs_get_fsgid_for_create(struct inode *dir_inode)
46 : : {
47 [ # # ]: 0 : BUG_ON(dir_inode == NULL);
48 : :
49 [ # # ]: 0 : if (dir_inode->i_mode & S_ISGID) {
50 : : /* set_gid bit is set.*/
51 : 0 : return dir_inode->i_gid;
52 : : }
53 : 0 : return current_fsgid();
54 : : }
55 : :
56 : 0 : static int v9fs_test_inode_dotl(struct inode *inode, void *data)
57 : : {
58 [ # # ]: 0 : struct v9fs_inode *v9inode = V9FS_I(inode);
59 : 0 : struct p9_stat_dotl *st = (struct p9_stat_dotl *)data;
60 : :
61 : : /* don't match inode of different type */
62 [ # # ]: 0 : if ((inode->i_mode & S_IFMT) != (st->st_mode & S_IFMT))
63 : : return 0;
64 : :
65 [ # # ]: 0 : if (inode->i_generation != st->st_gen)
66 : : return 0;
67 : :
68 : : /* compare qid details */
69 : 0 : if (memcmp(&v9inode->qid.version,
70 [ # # ]: 0 : &st->qid.version, sizeof(v9inode->qid.version)))
71 : : return 0;
72 : :
73 [ # # ]: 0 : if (v9inode->qid.type != st->qid.type)
74 : : return 0;
75 : :
76 [ # # ]: 0 : if (v9inode->qid.path != st->qid.path)
77 : 0 : return 0;
78 : : return 1;
79 : : }
80 : :
81 : : /* Always get a new inode */
82 : 0 : static int v9fs_test_new_inode_dotl(struct inode *inode, void *data)
83 : : {
84 : 0 : return 0;
85 : : }
86 : :
87 : 0 : static int v9fs_set_inode_dotl(struct inode *inode, void *data)
88 : : {
89 : 0 : struct v9fs_inode *v9inode = V9FS_I(inode);
90 : 0 : struct p9_stat_dotl *st = (struct p9_stat_dotl *)data;
91 : :
92 : 0 : memcpy(&v9inode->qid, &st->qid, sizeof(st->qid));
93 : 0 : inode->i_generation = st->st_gen;
94 : 0 : return 0;
95 : : }
96 : :
97 : : static struct inode *v9fs_qid_iget_dotl(struct super_block *sb,
98 : : struct p9_qid *qid,
99 : : struct p9_fid *fid,
100 : : struct p9_stat_dotl *st,
101 : : int new)
102 : : {
103 : : int retval;
104 : : unsigned long i_ino;
105 : : struct inode *inode;
106 : : struct v9fs_session_info *v9ses = sb->s_fs_info;
107 : : int (*test)(struct inode *, void *);
108 : :
109 : : if (new)
110 : : test = v9fs_test_new_inode_dotl;
111 : : else
112 : : test = v9fs_test_inode_dotl;
113 : :
114 : : i_ino = v9fs_qid2ino(qid);
115 : : inode = iget5_locked(sb, i_ino, test, v9fs_set_inode_dotl, st);
116 : : if (!inode)
117 : : return ERR_PTR(-ENOMEM);
118 : : if (!(inode->i_state & I_NEW))
119 : : return inode;
120 : : /*
121 : : * initialize the inode with the stat info
122 : : * FIXME!! we may need support for stale inodes
123 : : * later.
124 : : */
125 : : inode->i_ino = i_ino;
126 : : retval = v9fs_init_inode(v9ses, inode,
127 : : st->st_mode, new_decode_dev(st->st_rdev));
128 : : if (retval)
129 : : goto error;
130 : :
131 : : v9fs_stat2inode_dotl(st, inode, 0);
132 : : v9fs_cache_inode_get_cookie(inode);
133 : : retval = v9fs_get_acl(inode, fid);
134 : : if (retval)
135 : : goto error;
136 : :
137 : : unlock_new_inode(inode);
138 : : return inode;
139 : : error:
140 : : iget_failed(inode);
141 : : return ERR_PTR(retval);
142 : :
143 : : }
144 : :
145 : : struct inode *
146 : 0 : v9fs_inode_from_fid_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid,
147 : : struct super_block *sb, int new)
148 : : {
149 : 0 : struct p9_stat_dotl *st;
150 : 0 : struct inode *inode = NULL;
151 : :
152 : 0 : st = p9_client_getattr_dotl(fid, P9_STATS_BASIC | P9_STATS_GEN);
153 [ # # ]: 0 : if (IS_ERR(st))
154 : : return ERR_CAST(st);
155 : :
156 : 0 : inode = v9fs_qid_iget_dotl(sb, &st->qid, fid, st, new);
157 : 0 : kfree(st);
158 : 0 : return inode;
159 : : }
160 : :
161 : : struct dotl_openflag_map {
162 : : int open_flag;
163 : : int dotl_flag;
164 : : };
165 : :
166 : 0 : static int v9fs_mapped_dotl_flags(int flags)
167 : : {
168 : 0 : int i;
169 : 0 : int rflags = 0;
170 : 0 : struct dotl_openflag_map dotl_oflag_map[] = {
171 : : { O_CREAT, P9_DOTL_CREATE },
172 : : { O_EXCL, P9_DOTL_EXCL },
173 : : { O_NOCTTY, P9_DOTL_NOCTTY },
174 : : { O_APPEND, P9_DOTL_APPEND },
175 : : { O_NONBLOCK, P9_DOTL_NONBLOCK },
176 : : { O_DSYNC, P9_DOTL_DSYNC },
177 : : { FASYNC, P9_DOTL_FASYNC },
178 : : { O_DIRECT, P9_DOTL_DIRECT },
179 : : { O_LARGEFILE, P9_DOTL_LARGEFILE },
180 : : { O_DIRECTORY, P9_DOTL_DIRECTORY },
181 : : { O_NOFOLLOW, P9_DOTL_NOFOLLOW },
182 : : { O_NOATIME, P9_DOTL_NOATIME },
183 : : { O_CLOEXEC, P9_DOTL_CLOEXEC },
184 : : { O_SYNC, P9_DOTL_SYNC},
185 : : };
186 [ # # ]: 0 : for (i = 0; i < ARRAY_SIZE(dotl_oflag_map); i++) {
187 [ # # ]: 0 : if (flags & dotl_oflag_map[i].open_flag)
188 : 0 : rflags |= dotl_oflag_map[i].dotl_flag;
189 : : }
190 : 0 : return rflags;
191 : : }
192 : :
193 : : /**
194 : : * v9fs_open_to_dotl_flags- convert Linux specific open flags to
195 : : * plan 9 open flag.
196 : : * @flags: flags to convert
197 : : */
198 : 0 : int v9fs_open_to_dotl_flags(int flags)
199 : : {
200 : 0 : int rflags = 0;
201 : :
202 : : /*
203 : : * We have same bits for P9_DOTL_READONLY, P9_DOTL_WRONLY
204 : : * and P9_DOTL_NOACCESS
205 : : */
206 : 0 : rflags |= flags & O_ACCMODE;
207 : 0 : rflags |= v9fs_mapped_dotl_flags(flags);
208 : :
209 : 0 : return rflags;
210 : : }
211 : :
212 : : /**
213 : : * v9fs_vfs_create_dotl - VFS hook to create files for 9P2000.L protocol.
214 : : * @dir: directory inode that is being created
215 : : * @dentry: dentry that is being deleted
216 : : * @omode: create permissions
217 : : *
218 : : */
219 : :
220 : : static int
221 : 0 : v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
222 : : bool excl)
223 : : {
224 : 0 : return v9fs_vfs_mknod_dotl(dir, dentry, omode, 0);
225 : : }
226 : :
227 : : static int
228 : 0 : v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry,
229 : : struct file *file, unsigned flags, umode_t omode)
230 : : {
231 : 0 : int err = 0;
232 : 0 : kgid_t gid;
233 : 0 : umode_t mode;
234 : 0 : const unsigned char *name = NULL;
235 : 0 : struct p9_qid qid;
236 : 0 : struct inode *inode;
237 : 0 : struct p9_fid *fid = NULL;
238 : 0 : struct v9fs_inode *v9inode;
239 : 0 : struct p9_fid *dfid, *ofid, *inode_fid;
240 : 0 : struct v9fs_session_info *v9ses;
241 : 0 : struct posix_acl *pacl = NULL, *dacl = NULL;
242 : 0 : struct dentry *res = NULL;
243 : :
244 [ # # ]: 0 : if (d_in_lookup(dentry)) {
245 : 0 : res = v9fs_vfs_lookup(dir, dentry, 0);
246 [ # # ]: 0 : if (IS_ERR(res))
247 : 0 : return PTR_ERR(res);
248 : :
249 [ # # ]: 0 : if (res)
250 : 0 : dentry = res;
251 : : }
252 : :
253 : : /* Only creates */
254 [ # # # # ]: 0 : if (!(flags & O_CREAT) || d_really_is_positive(dentry))
255 : 0 : return finish_no_open(file, res);
256 : :
257 : 0 : v9ses = v9fs_inode2v9ses(dir);
258 : :
259 : 0 : name = dentry->d_name.name;
260 : 0 : p9_debug(P9_DEBUG_VFS, "name:%s flags:0x%x mode:0x%hx\n",
261 : : name, flags, omode);
262 : :
263 : 0 : dfid = v9fs_parent_fid(dentry);
264 [ # # ]: 0 : if (IS_ERR(dfid)) {
265 : 0 : err = PTR_ERR(dfid);
266 : 0 : p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
267 : 0 : goto out;
268 : : }
269 : :
270 : : /* clone a fid to use for creation */
271 : 0 : ofid = clone_fid(dfid);
272 [ # # ]: 0 : if (IS_ERR(ofid)) {
273 : 0 : err = PTR_ERR(ofid);
274 : 0 : p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
275 : 0 : goto out;
276 : : }
277 : :
278 : 0 : gid = v9fs_get_fsgid_for_create(dir);
279 : :
280 : 0 : mode = omode;
281 : : /* Update mode based on ACL value */
282 : 0 : err = v9fs_acl_mode(dir, &mode, &dacl, &pacl);
283 : 0 : if (err) {
284 : : p9_debug(P9_DEBUG_VFS, "Failed to get acl values in creat %d\n",
285 : : err);
286 : : goto error;
287 : : }
288 : 0 : err = p9_client_create_dotl(ofid, name, v9fs_open_to_dotl_flags(flags),
289 : : mode, gid, &qid);
290 [ # # ]: 0 : if (err < 0) {
291 : 0 : p9_debug(P9_DEBUG_VFS, "p9_client_open_dotl failed in creat %d\n",
292 : : err);
293 : 0 : goto error;
294 : : }
295 : 0 : v9fs_invalidate_inode_attr(dir);
296 : :
297 : : /* instantiate inode and assign the unopened fid to the dentry */
298 : 0 : fid = p9_client_walk(dfid, 1, &name, 1);
299 [ # # ]: 0 : if (IS_ERR(fid)) {
300 : 0 : err = PTR_ERR(fid);
301 : 0 : p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
302 : 0 : fid = NULL;
303 : 0 : goto error;
304 : : }
305 : 0 : inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
306 [ # # ]: 0 : if (IS_ERR(inode)) {
307 [ # # ]: 0 : err = PTR_ERR(inode);
308 : 0 : p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n", err);
309 : 0 : goto error;
310 : : }
311 : : /* Now set the ACL based on the default value */
312 : 0 : v9fs_set_create_acl(inode, fid, dacl, pacl);
313 : :
314 : 0 : v9fs_fid_add(dentry, fid);
315 : 0 : d_instantiate(dentry, inode);
316 : :
317 : 0 : v9inode = V9FS_I(inode);
318 : 0 : mutex_lock(&v9inode->v_mutex);
319 [ # # ]: 0 : if ((v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) &&
320 [ # # ]: 0 : !v9inode->writeback_fid &&
321 [ # # ]: 0 : ((flags & O_ACCMODE) != O_RDONLY)) {
322 : : /*
323 : : * clone a fid and add it to writeback_fid
324 : : * we do it during open time instead of
325 : : * page dirty time via write_begin/page_mkwrite
326 : : * because we want write after unlink usecase
327 : : * to work.
328 : : */
329 : 0 : inode_fid = v9fs_writeback_fid(dentry);
330 [ # # ]: 0 : if (IS_ERR(inode_fid)) {
331 : 0 : err = PTR_ERR(inode_fid);
332 : 0 : mutex_unlock(&v9inode->v_mutex);
333 : 0 : goto err_clunk_old_fid;
334 : : }
335 : 0 : v9inode->writeback_fid = (void *) inode_fid;
336 : : }
337 : 0 : mutex_unlock(&v9inode->v_mutex);
338 : : /* Since we are opening a file, assign the open fid to the file */
339 : 0 : err = finish_open(file, dentry, generic_file_open);
340 [ # # ]: 0 : if (err)
341 : 0 : goto err_clunk_old_fid;
342 : 0 : file->private_data = ofid;
343 : 0 : if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
344 : : v9fs_cache_inode_set_cookie(inode, file);
345 : 0 : file->f_mode |= FMODE_CREATED;
346 : 0 : out:
347 : 0 : v9fs_put_acl(dacl, pacl);
348 : 0 : dput(res);
349 : 0 : return err;
350 : :
351 : : error:
352 [ # # ]: 0 : if (fid)
353 : 0 : p9_client_clunk(fid);
354 : 0 : err_clunk_old_fid:
355 [ # # ]: 0 : if (ofid)
356 : 0 : p9_client_clunk(ofid);
357 : 0 : goto out;
358 : : }
359 : :
360 : : /**
361 : : * v9fs_vfs_mkdir_dotl - VFS mkdir hook to create a directory
362 : : * @dir: inode that is being unlinked
363 : : * @dentry: dentry that is being unlinked
364 : : * @omode: mode for new directory
365 : : *
366 : : */
367 : :
368 : 0 : static int v9fs_vfs_mkdir_dotl(struct inode *dir,
369 : : struct dentry *dentry, umode_t omode)
370 : : {
371 : 0 : int err;
372 : 0 : struct v9fs_session_info *v9ses;
373 : 0 : struct p9_fid *fid = NULL, *dfid = NULL;
374 : 0 : kgid_t gid;
375 : 0 : const unsigned char *name;
376 : 0 : umode_t mode;
377 : 0 : struct inode *inode;
378 : 0 : struct p9_qid qid;
379 : 0 : struct posix_acl *dacl = NULL, *pacl = NULL;
380 : :
381 : 0 : p9_debug(P9_DEBUG_VFS, "name %pd\n", dentry);
382 : 0 : err = 0;
383 [ # # ]: 0 : v9ses = v9fs_inode2v9ses(dir);
384 : :
385 : 0 : omode |= S_IFDIR;
386 [ # # ]: 0 : if (dir->i_mode & S_ISGID)
387 : 0 : omode |= S_ISGID;
388 : :
389 : 0 : dfid = v9fs_parent_fid(dentry);
390 [ # # ]: 0 : if (IS_ERR(dfid)) {
391 : 0 : err = PTR_ERR(dfid);
392 : 0 : p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
393 : 0 : dfid = NULL;
394 : 0 : goto error;
395 : : }
396 : :
397 : 0 : gid = v9fs_get_fsgid_for_create(dir);
398 : 0 : mode = omode;
399 : : /* Update mode based on ACL value */
400 : 0 : err = v9fs_acl_mode(dir, &mode, &dacl, &pacl);
401 : 0 : if (err) {
402 : : p9_debug(P9_DEBUG_VFS, "Failed to get acl values in mkdir %d\n",
403 : : err);
404 : : goto error;
405 : : }
406 : 0 : name = dentry->d_name.name;
407 : 0 : err = p9_client_mkdir_dotl(dfid, name, mode, gid, &qid);
408 [ # # ]: 0 : if (err < 0)
409 : 0 : goto error;
410 : :
411 : 0 : fid = p9_client_walk(dfid, 1, &name, 1);
412 [ # # ]: 0 : if (IS_ERR(fid)) {
413 : 0 : err = PTR_ERR(fid);
414 : 0 : p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n",
415 : : err);
416 : 0 : fid = NULL;
417 : 0 : goto error;
418 : : }
419 : :
420 : : /* instantiate inode and assign the unopened fid to the dentry */
421 [ # # ]: 0 : if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
422 : 0 : inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
423 [ # # ]: 0 : if (IS_ERR(inode)) {
424 : 0 : err = PTR_ERR(inode);
425 : 0 : p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n",
426 : : err);
427 : 0 : goto error;
428 : : }
429 : 0 : v9fs_fid_add(dentry, fid);
430 : 0 : v9fs_set_create_acl(inode, fid, dacl, pacl);
431 : 0 : d_instantiate(dentry, inode);
432 : 0 : fid = NULL;
433 : 0 : err = 0;
434 : : } else {
435 : : /*
436 : : * Not in cached mode. No need to populate
437 : : * inode with stat. We need to get an inode
438 : : * so that we can set the acl with dentry
439 : : */
440 : 0 : inode = v9fs_get_inode(dir->i_sb, mode, 0);
441 [ # # ]: 0 : if (IS_ERR(inode)) {
442 : 0 : err = PTR_ERR(inode);
443 : 0 : goto error;
444 : : }
445 : 0 : v9fs_set_create_acl(inode, fid, dacl, pacl);
446 : 0 : d_instantiate(dentry, inode);
447 : : }
448 : 0 : inc_nlink(dir);
449 : 0 : v9fs_invalidate_inode_attr(dir);
450 : 0 : error:
451 [ # # ]: 0 : if (fid)
452 : 0 : p9_client_clunk(fid);
453 : 0 : v9fs_put_acl(dacl, pacl);
454 : 0 : return err;
455 : : }
456 : :
457 : : static int
458 : 0 : v9fs_vfs_getattr_dotl(const struct path *path, struct kstat *stat,
459 : : u32 request_mask, unsigned int flags)
460 : : {
461 : 0 : struct dentry *dentry = path->dentry;
462 : 0 : struct v9fs_session_info *v9ses;
463 : 0 : struct p9_fid *fid;
464 : 0 : struct p9_stat_dotl *st;
465 : :
466 : 0 : p9_debug(P9_DEBUG_VFS, "dentry: %p\n", dentry);
467 [ # # ]: 0 : v9ses = v9fs_dentry2v9ses(dentry);
468 [ # # ]: 0 : if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
469 : 0 : generic_fillattr(d_inode(dentry), stat);
470 : 0 : return 0;
471 : : }
472 : 0 : fid = v9fs_fid_lookup(dentry);
473 [ # # ]: 0 : if (IS_ERR(fid))
474 : 0 : return PTR_ERR(fid);
475 : :
476 : : /* Ask for all the fields in stat structure. Server will return
477 : : * whatever it supports
478 : : */
479 : :
480 : 0 : st = p9_client_getattr_dotl(fid, P9_STATS_ALL);
481 [ # # ]: 0 : if (IS_ERR(st))
482 : 0 : return PTR_ERR(st);
483 : :
484 : 0 : v9fs_stat2inode_dotl(st, d_inode(dentry), 0);
485 : 0 : generic_fillattr(d_inode(dentry), stat);
486 : : /* Change block size to what the server returned */
487 : 0 : stat->blksize = st->st_blksize;
488 : :
489 : 0 : kfree(st);
490 : 0 : return 0;
491 : : }
492 : :
493 : : /*
494 : : * Attribute flags.
495 : : */
496 : : #define P9_ATTR_MODE (1 << 0)
497 : : #define P9_ATTR_UID (1 << 1)
498 : : #define P9_ATTR_GID (1 << 2)
499 : : #define P9_ATTR_SIZE (1 << 3)
500 : : #define P9_ATTR_ATIME (1 << 4)
501 : : #define P9_ATTR_MTIME (1 << 5)
502 : : #define P9_ATTR_CTIME (1 << 6)
503 : : #define P9_ATTR_ATIME_SET (1 << 7)
504 : : #define P9_ATTR_MTIME_SET (1 << 8)
505 : :
506 : : struct dotl_iattr_map {
507 : : int iattr_valid;
508 : : int p9_iattr_valid;
509 : : };
510 : :
511 : 0 : static int v9fs_mapped_iattr_valid(int iattr_valid)
512 : : {
513 : 0 : int i;
514 : 0 : int p9_iattr_valid = 0;
515 : 0 : struct dotl_iattr_map dotl_iattr_map[] = {
516 : : { ATTR_MODE, P9_ATTR_MODE },
517 : : { ATTR_UID, P9_ATTR_UID },
518 : : { ATTR_GID, P9_ATTR_GID },
519 : : { ATTR_SIZE, P9_ATTR_SIZE },
520 : : { ATTR_ATIME, P9_ATTR_ATIME },
521 : : { ATTR_MTIME, P9_ATTR_MTIME },
522 : : { ATTR_CTIME, P9_ATTR_CTIME },
523 : : { ATTR_ATIME_SET, P9_ATTR_ATIME_SET },
524 : : { ATTR_MTIME_SET, P9_ATTR_MTIME_SET },
525 : : };
526 [ # # ]: 0 : for (i = 0; i < ARRAY_SIZE(dotl_iattr_map); i++) {
527 [ # # ]: 0 : if (iattr_valid & dotl_iattr_map[i].iattr_valid)
528 : 0 : p9_iattr_valid |= dotl_iattr_map[i].p9_iattr_valid;
529 : : }
530 : 0 : return p9_iattr_valid;
531 : : }
532 : :
533 : : /**
534 : : * v9fs_vfs_setattr_dotl - set file metadata
535 : : * @dentry: file whose metadata to set
536 : : * @iattr: metadata assignment structure
537 : : *
538 : : */
539 : :
540 : 0 : int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
541 : : {
542 : 0 : int retval;
543 : 0 : struct p9_fid *fid;
544 : 0 : struct p9_iattr_dotl p9attr;
545 : 0 : struct inode *inode = d_inode(dentry);
546 : :
547 : 0 : p9_debug(P9_DEBUG_VFS, "\n");
548 : :
549 : 0 : retval = setattr_prepare(dentry, iattr);
550 [ # # ]: 0 : if (retval)
551 : : return retval;
552 : :
553 : 0 : p9attr.valid = v9fs_mapped_iattr_valid(iattr->ia_valid);
554 : 0 : p9attr.mode = iattr->ia_mode;
555 : 0 : p9attr.uid = iattr->ia_uid;
556 : 0 : p9attr.gid = iattr->ia_gid;
557 : 0 : p9attr.size = iattr->ia_size;
558 : 0 : p9attr.atime_sec = iattr->ia_atime.tv_sec;
559 : 0 : p9attr.atime_nsec = iattr->ia_atime.tv_nsec;
560 : 0 : p9attr.mtime_sec = iattr->ia_mtime.tv_sec;
561 : 0 : p9attr.mtime_nsec = iattr->ia_mtime.tv_nsec;
562 : :
563 : 0 : fid = v9fs_fid_lookup(dentry);
564 [ # # ]: 0 : if (IS_ERR(fid))
565 : 0 : return PTR_ERR(fid);
566 : :
567 : : /* Write all dirty data */
568 [ # # ]: 0 : if (S_ISREG(inode->i_mode))
569 : 0 : filemap_write_and_wait(inode->i_mapping);
570 : :
571 : 0 : retval = p9_client_setattr(fid, &p9attr);
572 [ # # ]: 0 : if (retval < 0)
573 : : return retval;
574 : :
575 [ # # # # ]: 0 : if ((iattr->ia_valid & ATTR_SIZE) &&
576 [ # # ]: 0 : iattr->ia_size != i_size_read(inode))
577 : 0 : truncate_setsize(inode, iattr->ia_size);
578 : :
579 : 0 : v9fs_invalidate_inode_attr(inode);
580 : 0 : setattr_copy(inode, iattr);
581 : 0 : mark_inode_dirty(inode);
582 : 0 : if (iattr->ia_valid & ATTR_MODE) {
583 : : /* We also want to update ACL when we update mode bits */
584 : : retval = v9fs_acl_chmod(inode, fid);
585 : : if (retval < 0)
586 : : return retval;
587 : : }
588 : 0 : return 0;
589 : : }
590 : :
591 : : /**
592 : : * v9fs_stat2inode_dotl - populate an inode structure with stat info
593 : : * @stat: stat structure
594 : : * @inode: inode to populate
595 : : * @flags: ctrl flags (e.g. V9FS_STAT2INODE_KEEP_ISIZE)
596 : : *
597 : : */
598 : :
599 : : void
600 : 0 : v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode,
601 : : unsigned int flags)
602 : : {
603 : 0 : umode_t mode;
604 [ # # ]: 0 : struct v9fs_inode *v9inode = V9FS_I(inode);
605 : :
606 [ # # ]: 0 : if ((stat->st_result_mask & P9_STATS_BASIC) == P9_STATS_BASIC) {
607 : 0 : inode->i_atime.tv_sec = stat->st_atime_sec;
608 : 0 : inode->i_atime.tv_nsec = stat->st_atime_nsec;
609 : 0 : inode->i_mtime.tv_sec = stat->st_mtime_sec;
610 : 0 : inode->i_mtime.tv_nsec = stat->st_mtime_nsec;
611 : 0 : inode->i_ctime.tv_sec = stat->st_ctime_sec;
612 : 0 : inode->i_ctime.tv_nsec = stat->st_ctime_nsec;
613 : 0 : inode->i_uid = stat->st_uid;
614 : 0 : inode->i_gid = stat->st_gid;
615 : 0 : set_nlink(inode, stat->st_nlink);
616 : :
617 : 0 : mode = stat->st_mode & S_IALLUGO;
618 : 0 : mode |= inode->i_mode & ~S_IALLUGO;
619 : 0 : inode->i_mode = mode;
620 : :
621 [ # # ]: 0 : if (!(flags & V9FS_STAT2INODE_KEEP_ISIZE))
622 : 0 : v9fs_i_size_write(inode, stat->st_size);
623 : 0 : inode->i_blocks = stat->st_blocks;
624 : : } else {
625 [ # # ]: 0 : if (stat->st_result_mask & P9_STATS_ATIME) {
626 : 0 : inode->i_atime.tv_sec = stat->st_atime_sec;
627 : 0 : inode->i_atime.tv_nsec = stat->st_atime_nsec;
628 : : }
629 [ # # ]: 0 : if (stat->st_result_mask & P9_STATS_MTIME) {
630 : 0 : inode->i_mtime.tv_sec = stat->st_mtime_sec;
631 : 0 : inode->i_mtime.tv_nsec = stat->st_mtime_nsec;
632 : : }
633 [ # # ]: 0 : if (stat->st_result_mask & P9_STATS_CTIME) {
634 : 0 : inode->i_ctime.tv_sec = stat->st_ctime_sec;
635 : 0 : inode->i_ctime.tv_nsec = stat->st_ctime_nsec;
636 : : }
637 [ # # ]: 0 : if (stat->st_result_mask & P9_STATS_UID)
638 : 0 : inode->i_uid = stat->st_uid;
639 [ # # ]: 0 : if (stat->st_result_mask & P9_STATS_GID)
640 : 0 : inode->i_gid = stat->st_gid;
641 [ # # ]: 0 : if (stat->st_result_mask & P9_STATS_NLINK)
642 : 0 : set_nlink(inode, stat->st_nlink);
643 [ # # ]: 0 : if (stat->st_result_mask & P9_STATS_MODE) {
644 : 0 : inode->i_mode = stat->st_mode;
645 [ # # ]: 0 : if ((S_ISBLK(inode->i_mode)) ||
646 : : (S_ISCHR(inode->i_mode)))
647 : 0 : init_special_inode(inode, inode->i_mode,
648 : : inode->i_rdev);
649 : : }
650 [ # # ]: 0 : if (stat->st_result_mask & P9_STATS_RDEV)
651 : 0 : inode->i_rdev = new_decode_dev(stat->st_rdev);
652 [ # # ]: 0 : if (!(flags & V9FS_STAT2INODE_KEEP_ISIZE) &&
653 [ # # ]: 0 : stat->st_result_mask & P9_STATS_SIZE)
654 : 0 : v9fs_i_size_write(inode, stat->st_size);
655 [ # # ]: 0 : if (stat->st_result_mask & P9_STATS_BLOCKS)
656 : 0 : inode->i_blocks = stat->st_blocks;
657 : : }
658 [ # # ]: 0 : if (stat->st_result_mask & P9_STATS_GEN)
659 : 0 : inode->i_generation = stat->st_gen;
660 : :
661 : : /* Currently we don't support P9_STATS_BTIME and P9_STATS_DATA_VERSION
662 : : * because the inode structure does not have fields for them.
663 : : */
664 : 0 : v9inode->cache_validity &= ~V9FS_INO_INVALID_ATTR;
665 : 0 : }
666 : :
667 : : static int
668 : 0 : v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry,
669 : : const char *symname)
670 : : {
671 : 0 : int err;
672 : 0 : kgid_t gid;
673 : 0 : const unsigned char *name;
674 : 0 : struct p9_qid qid;
675 : 0 : struct inode *inode;
676 : 0 : struct p9_fid *dfid;
677 : 0 : struct p9_fid *fid = NULL;
678 : 0 : struct v9fs_session_info *v9ses;
679 : :
680 : 0 : name = dentry->d_name.name;
681 : 0 : p9_debug(P9_DEBUG_VFS, "%lu,%s,%s\n", dir->i_ino, name, symname);
682 : 0 : v9ses = v9fs_inode2v9ses(dir);
683 : :
684 : 0 : dfid = v9fs_parent_fid(dentry);
685 [ # # ]: 0 : if (IS_ERR(dfid)) {
686 : 0 : err = PTR_ERR(dfid);
687 : 0 : p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
688 : 0 : return err;
689 : : }
690 : :
691 : 0 : gid = v9fs_get_fsgid_for_create(dir);
692 : :
693 : : /* Server doesn't alter fid on TSYMLINK. Hence no need to clone it. */
694 : 0 : err = p9_client_symlink(dfid, name, symname, gid, &qid);
695 : :
696 [ # # ]: 0 : if (err < 0) {
697 : 0 : p9_debug(P9_DEBUG_VFS, "p9_client_symlink failed %d\n", err);
698 : 0 : goto error;
699 : : }
700 : :
701 [ # # ]: 0 : v9fs_invalidate_inode_attr(dir);
702 [ # # ]: 0 : if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
703 : : /* Now walk from the parent so we can get an unopened fid. */
704 : 0 : fid = p9_client_walk(dfid, 1, &name, 1);
705 [ # # ]: 0 : if (IS_ERR(fid)) {
706 : 0 : err = PTR_ERR(fid);
707 : 0 : p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n",
708 : : err);
709 : 0 : fid = NULL;
710 : 0 : goto error;
711 : : }
712 : :
713 : : /* instantiate inode and assign the unopened fid to dentry */
714 : 0 : inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
715 [ # # ]: 0 : if (IS_ERR(inode)) {
716 [ # # ]: 0 : err = PTR_ERR(inode);
717 : 0 : p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n",
718 : : err);
719 : 0 : goto error;
720 : : }
721 : 0 : v9fs_fid_add(dentry, fid);
722 : 0 : d_instantiate(dentry, inode);
723 : 0 : fid = NULL;
724 : 0 : err = 0;
725 : : } else {
726 : : /* Not in cached mode. No need to populate inode with stat */
727 : 0 : inode = v9fs_get_inode(dir->i_sb, S_IFLNK, 0);
728 [ # # ]: 0 : if (IS_ERR(inode)) {
729 : 0 : err = PTR_ERR(inode);
730 : 0 : goto error;
731 : : }
732 : 0 : d_instantiate(dentry, inode);
733 : : }
734 : :
735 : : error:
736 [ # # ]: 0 : if (fid)
737 : 0 : p9_client_clunk(fid);
738 : :
739 : : return err;
740 : : }
741 : :
742 : : /**
743 : : * v9fs_vfs_link_dotl - create a hardlink for dotl
744 : : * @old_dentry: dentry for file to link to
745 : : * @dir: inode destination for new link
746 : : * @dentry: dentry for link
747 : : *
748 : : */
749 : :
750 : : static int
751 : 0 : v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir,
752 : : struct dentry *dentry)
753 : : {
754 : 0 : int err;
755 : 0 : struct p9_fid *dfid, *oldfid;
756 : 0 : struct v9fs_session_info *v9ses;
757 : :
758 : 0 : p9_debug(P9_DEBUG_VFS, "dir ino: %lu, old_name: %pd, new_name: %pd\n",
759 : : dir->i_ino, old_dentry, dentry);
760 : :
761 : 0 : v9ses = v9fs_inode2v9ses(dir);
762 : 0 : dfid = v9fs_parent_fid(dentry);
763 [ # # ]: 0 : if (IS_ERR(dfid))
764 : 0 : return PTR_ERR(dfid);
765 : :
766 : 0 : oldfid = v9fs_fid_lookup(old_dentry);
767 [ # # ]: 0 : if (IS_ERR(oldfid))
768 : 0 : return PTR_ERR(oldfid);
769 : :
770 : 0 : err = p9_client_link(dfid, oldfid, dentry->d_name.name);
771 : :
772 [ # # ]: 0 : if (err < 0) {
773 : : p9_debug(P9_DEBUG_VFS, "p9_client_link failed %d\n", err);
774 : : return err;
775 : : }
776 : :
777 [ # # ]: 0 : v9fs_invalidate_inode_attr(dir);
778 [ # # ]: 0 : if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
779 : : /* Get the latest stat info from server. */
780 : 0 : struct p9_fid *fid;
781 : 0 : fid = v9fs_fid_lookup(old_dentry);
782 [ # # ]: 0 : if (IS_ERR(fid))
783 : 0 : return PTR_ERR(fid);
784 : :
785 : 0 : v9fs_refresh_inode_dotl(fid, d_inode(old_dentry));
786 : : }
787 : 0 : ihold(d_inode(old_dentry));
788 : 0 : d_instantiate(dentry, d_inode(old_dentry));
789 : :
790 : 0 : return err;
791 : : }
792 : :
793 : : /**
794 : : * v9fs_vfs_mknod_dotl - create a special file
795 : : * @dir: inode destination for new link
796 : : * @dentry: dentry for file
797 : : * @omode: mode for creation
798 : : * @rdev: device associated with special file
799 : : *
800 : : */
801 : : static int
802 : 0 : v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
803 : : dev_t rdev)
804 : : {
805 : 0 : int err;
806 : 0 : kgid_t gid;
807 : 0 : const unsigned char *name;
808 : 0 : umode_t mode;
809 : 0 : struct v9fs_session_info *v9ses;
810 : 0 : struct p9_fid *fid = NULL, *dfid = NULL;
811 : 0 : struct inode *inode;
812 : 0 : struct p9_qid qid;
813 : 0 : struct posix_acl *dacl = NULL, *pacl = NULL;
814 : :
815 : 0 : p9_debug(P9_DEBUG_VFS, " %lu,%pd mode: %hx MAJOR: %u MINOR: %u\n",
816 : : dir->i_ino, dentry, omode,
817 : : MAJOR(rdev), MINOR(rdev));
818 : :
819 : 0 : v9ses = v9fs_inode2v9ses(dir);
820 : 0 : dfid = v9fs_parent_fid(dentry);
821 [ # # ]: 0 : if (IS_ERR(dfid)) {
822 : 0 : err = PTR_ERR(dfid);
823 : 0 : p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
824 : 0 : dfid = NULL;
825 : 0 : goto error;
826 : : }
827 : :
828 : 0 : gid = v9fs_get_fsgid_for_create(dir);
829 : 0 : mode = omode;
830 : : /* Update mode based on ACL value */
831 : 0 : err = v9fs_acl_mode(dir, &mode, &dacl, &pacl);
832 : 0 : if (err) {
833 : : p9_debug(P9_DEBUG_VFS, "Failed to get acl values in mknod %d\n",
834 : : err);
835 : : goto error;
836 : : }
837 : 0 : name = dentry->d_name.name;
838 : :
839 : 0 : err = p9_client_mknod_dotl(dfid, name, mode, rdev, gid, &qid);
840 [ # # ]: 0 : if (err < 0)
841 : 0 : goto error;
842 : :
843 : 0 : v9fs_invalidate_inode_attr(dir);
844 : 0 : fid = p9_client_walk(dfid, 1, &name, 1);
845 [ # # ]: 0 : if (IS_ERR(fid)) {
846 : 0 : err = PTR_ERR(fid);
847 : 0 : p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n",
848 : : err);
849 : 0 : fid = NULL;
850 : 0 : goto error;
851 : : }
852 : :
853 : : /* instantiate inode and assign the unopened fid to the dentry */
854 [ # # ]: 0 : if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
855 : 0 : inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
856 [ # # ]: 0 : if (IS_ERR(inode)) {
857 : 0 : err = PTR_ERR(inode);
858 : 0 : p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n",
859 : : err);
860 : 0 : goto error;
861 : : }
862 : 0 : v9fs_set_create_acl(inode, fid, dacl, pacl);
863 : 0 : v9fs_fid_add(dentry, fid);
864 : 0 : d_instantiate(dentry, inode);
865 : 0 : fid = NULL;
866 : 0 : err = 0;
867 : : } else {
868 : : /*
869 : : * Not in cached mode. No need to populate inode with stat.
870 : : * socket syscall returns a fd, so we need instantiate
871 : : */
872 : 0 : inode = v9fs_get_inode(dir->i_sb, mode, rdev);
873 [ # # ]: 0 : if (IS_ERR(inode)) {
874 : 0 : err = PTR_ERR(inode);
875 : 0 : goto error;
876 : : }
877 : 0 : v9fs_set_create_acl(inode, fid, dacl, pacl);
878 : 0 : d_instantiate(dentry, inode);
879 : : }
880 : 0 : error:
881 [ # # ]: 0 : if (fid)
882 : 0 : p9_client_clunk(fid);
883 : 0 : v9fs_put_acl(dacl, pacl);
884 : 0 : return err;
885 : : }
886 : :
887 : : /**
888 : : * v9fs_vfs_get_link_dotl - follow a symlink path
889 : : * @dentry: dentry for symlink
890 : : * @inode: inode for symlink
891 : : * @done: destructor for return value
892 : : */
893 : :
894 : : static const char *
895 : 0 : v9fs_vfs_get_link_dotl(struct dentry *dentry,
896 : : struct inode *inode,
897 : : struct delayed_call *done)
898 : : {
899 : 0 : struct p9_fid *fid;
900 : 0 : char *target;
901 : 0 : int retval;
902 : :
903 [ # # ]: 0 : if (!dentry)
904 : : return ERR_PTR(-ECHILD);
905 : :
906 : 0 : p9_debug(P9_DEBUG_VFS, "%pd\n", dentry);
907 : :
908 : 0 : fid = v9fs_fid_lookup(dentry);
909 [ # # ]: 0 : if (IS_ERR(fid))
910 : : return ERR_CAST(fid);
911 : 0 : retval = p9_client_readlink(fid, &target);
912 [ # # ]: 0 : if (retval)
913 : 0 : return ERR_PTR(retval);
914 : 0 : set_delayed_call(done, kfree_link, target);
915 : 0 : return target;
916 : : }
917 : :
918 : 0 : int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode)
919 : : {
920 : 0 : struct p9_stat_dotl *st;
921 : 0 : struct v9fs_session_info *v9ses;
922 : 0 : unsigned int flags;
923 : :
924 : 0 : v9ses = v9fs_inode2v9ses(inode);
925 : 0 : st = p9_client_getattr_dotl(fid, P9_STATS_ALL);
926 [ # # ]: 0 : if (IS_ERR(st))
927 : 0 : return PTR_ERR(st);
928 : : /*
929 : : * Don't update inode if the file type is different
930 : : */
931 [ # # ]: 0 : if ((inode->i_mode & S_IFMT) != (st->st_mode & S_IFMT))
932 : 0 : goto out;
933 : :
934 : : /*
935 : : * We don't want to refresh inode->i_size,
936 : : * because we may have cached data
937 : : */
938 : 0 : flags = (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) ?
939 : 0 : V9FS_STAT2INODE_KEEP_ISIZE : 0;
940 : 0 : v9fs_stat2inode_dotl(st, inode, flags);
941 : 0 : out:
942 : 0 : kfree(st);
943 : 0 : return 0;
944 : : }
945 : :
946 : : const struct inode_operations v9fs_dir_inode_operations_dotl = {
947 : : .create = v9fs_vfs_create_dotl,
948 : : .atomic_open = v9fs_vfs_atomic_open_dotl,
949 : : .lookup = v9fs_vfs_lookup,
950 : : .link = v9fs_vfs_link_dotl,
951 : : .symlink = v9fs_vfs_symlink_dotl,
952 : : .unlink = v9fs_vfs_unlink,
953 : : .mkdir = v9fs_vfs_mkdir_dotl,
954 : : .rmdir = v9fs_vfs_rmdir,
955 : : .mknod = v9fs_vfs_mknod_dotl,
956 : : .rename = v9fs_vfs_rename,
957 : : .getattr = v9fs_vfs_getattr_dotl,
958 : : .setattr = v9fs_vfs_setattr_dotl,
959 : : .listxattr = v9fs_listxattr,
960 : : .get_acl = v9fs_iop_get_acl,
961 : : };
962 : :
963 : : const struct inode_operations v9fs_file_inode_operations_dotl = {
964 : : .getattr = v9fs_vfs_getattr_dotl,
965 : : .setattr = v9fs_vfs_setattr_dotl,
966 : : .listxattr = v9fs_listxattr,
967 : : .get_acl = v9fs_iop_get_acl,
968 : : };
969 : :
970 : : const struct inode_operations v9fs_symlink_inode_operations_dotl = {
971 : : .get_link = v9fs_vfs_get_link_dotl,
972 : : .getattr = v9fs_vfs_getattr_dotl,
973 : : .setattr = v9fs_vfs_setattr_dotl,
974 : : .listxattr = v9fs_listxattr,
975 : : };
|