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