1408 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * This file contains vfs inode 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#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt10 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/namei.h>19#include <linux/sched.h>20#include <linux/slab.h>21#include <linux/xattr.h>22#include <linux/posix_acl.h>23#include <net/9p/9p.h>24#include <net/9p/client.h>25 26#include "v9fs.h"27#include "v9fs_vfs.h"28#include "fid.h"29#include "cache.h"30#include "xattr.h"31#include "acl.h"32 33static const struct inode_operations v9fs_dir_inode_operations;34static const struct inode_operations v9fs_dir_inode_operations_dotu;35static const struct inode_operations v9fs_file_inode_operations;36static const struct inode_operations v9fs_symlink_inode_operations;37 38/**39 * unixmode2p9mode - convert unix mode bits to plan 940 * @v9ses: v9fs session information41 * @mode: mode to convert42 *43 */44 45static u32 unixmode2p9mode(struct v9fs_session_info *v9ses, umode_t mode)46{47 int res;48 49 res = mode & 0777;50 if (S_ISDIR(mode))51 res |= P9_DMDIR;52 if (v9fs_proto_dotu(v9ses)) {53 if (v9ses->nodev == 0) {54 if (S_ISSOCK(mode))55 res |= P9_DMSOCKET;56 if (S_ISFIFO(mode))57 res |= P9_DMNAMEDPIPE;58 if (S_ISBLK(mode))59 res |= P9_DMDEVICE;60 if (S_ISCHR(mode))61 res |= P9_DMDEVICE;62 }63 64 if ((mode & S_ISUID) == S_ISUID)65 res |= P9_DMSETUID;66 if ((mode & S_ISGID) == S_ISGID)67 res |= P9_DMSETGID;68 if ((mode & S_ISVTX) == S_ISVTX)69 res |= P9_DMSETVTX;70 }71 return res;72}73 74/**75 * p9mode2perm- convert plan9 mode bits to unix permission bits76 * @v9ses: v9fs session information77 * @stat: p9_wstat from which mode need to be derived78 *79 */80static int p9mode2perm(struct v9fs_session_info *v9ses,81 struct p9_wstat *stat)82{83 int res;84 int mode = stat->mode;85 86 res = mode & 0777; /* S_IRWXUGO */87 if (v9fs_proto_dotu(v9ses)) {88 if ((mode & P9_DMSETUID) == P9_DMSETUID)89 res |= S_ISUID;90 91 if ((mode & P9_DMSETGID) == P9_DMSETGID)92 res |= S_ISGID;93 94 if ((mode & P9_DMSETVTX) == P9_DMSETVTX)95 res |= S_ISVTX;96 }97 return res;98}99 100/**101 * p9mode2unixmode- convert plan9 mode bits to unix mode bits102 * @v9ses: v9fs session information103 * @stat: p9_wstat from which mode need to be derived104 * @rdev: major number, minor number in case of device files.105 *106 */107static umode_t p9mode2unixmode(struct v9fs_session_info *v9ses,108 struct p9_wstat *stat, dev_t *rdev)109{110 int res, r;111 u32 mode = stat->mode;112 113 *rdev = 0;114 res = p9mode2perm(v9ses, stat);115 116 if ((mode & P9_DMDIR) == P9_DMDIR)117 res |= S_IFDIR;118 else if ((mode & P9_DMSYMLINK) && (v9fs_proto_dotu(v9ses)))119 res |= S_IFLNK;120 else if ((mode & P9_DMSOCKET) && (v9fs_proto_dotu(v9ses))121 && (v9ses->nodev == 0))122 res |= S_IFSOCK;123 else if ((mode & P9_DMNAMEDPIPE) && (v9fs_proto_dotu(v9ses))124 && (v9ses->nodev == 0))125 res |= S_IFIFO;126 else if ((mode & P9_DMDEVICE) && (v9fs_proto_dotu(v9ses))127 && (v9ses->nodev == 0)) {128 char type = 0;129 int major = -1, minor = -1;130 131 r = sscanf(stat->extension, "%c %i %i", &type, &major, &minor);132 if (r != 3) {133 p9_debug(P9_DEBUG_ERROR,134 "invalid device string, umode will be bogus: %s\n",135 stat->extension);136 return res;137 }138 switch (type) {139 case 'c':140 res |= S_IFCHR;141 break;142 case 'b':143 res |= S_IFBLK;144 break;145 default:146 p9_debug(P9_DEBUG_ERROR, "Unknown special type %c %s\n",147 type, stat->extension);148 }149 *rdev = MKDEV(major, minor);150 } else151 res |= S_IFREG;152 153 return res;154}155 156/**157 * v9fs_uflags2omode- convert posix open flags to plan 9 mode bits158 * @uflags: flags to convert159 * @extended: if .u extensions are active160 */161 162int v9fs_uflags2omode(int uflags, int extended)163{164 int ret;165 166 switch (uflags&3) {167 default:168 case O_RDONLY:169 ret = P9_OREAD;170 break;171 172 case O_WRONLY:173 ret = P9_OWRITE;174 break;175 176 case O_RDWR:177 ret = P9_ORDWR;178 break;179 }180 181 if (uflags & O_TRUNC)182 ret |= P9_OTRUNC;183 184 if (extended) {185 if (uflags & O_EXCL)186 ret |= P9_OEXCL;187 188 if (uflags & O_APPEND)189 ret |= P9_OAPPEND;190 }191 192 return ret;193}194 195/**196 * v9fs_blank_wstat - helper function to setup a 9P stat structure197 * @wstat: structure to initialize198 *199 */200 201void202v9fs_blank_wstat(struct p9_wstat *wstat)203{204 wstat->type = ~0;205 wstat->dev = ~0;206 wstat->qid.type = ~0;207 wstat->qid.version = ~0;208 *((long long *)&wstat->qid.path) = ~0;209 wstat->mode = ~0;210 wstat->atime = ~0;211 wstat->mtime = ~0;212 wstat->length = ~0;213 wstat->name = NULL;214 wstat->uid = NULL;215 wstat->gid = NULL;216 wstat->muid = NULL;217 wstat->n_uid = INVALID_UID;218 wstat->n_gid = INVALID_GID;219 wstat->n_muid = INVALID_UID;220 wstat->extension = NULL;221}222 223/**224 * v9fs_alloc_inode - helper function to allocate an inode225 * @sb: The superblock to allocate the inode from226 */227struct inode *v9fs_alloc_inode(struct super_block *sb)228{229 struct v9fs_inode *v9inode;230 231 v9inode = alloc_inode_sb(sb, v9fs_inode_cache, GFP_KERNEL);232 if (!v9inode)233 return NULL;234 v9inode->cache_validity = 0;235 mutex_init(&v9inode->v_mutex);236 return &v9inode->netfs.inode;237}238 239/**240 * v9fs_free_inode - destroy an inode241 * @inode: The inode to be freed242 */243 244void v9fs_free_inode(struct inode *inode)245{246 kmem_cache_free(v9fs_inode_cache, V9FS_I(inode));247}248 249/*250 * Set parameters for the netfs library251 */252void v9fs_set_netfs_context(struct inode *inode)253{254 struct v9fs_inode *v9inode = V9FS_I(inode);255 netfs_inode_init(&v9inode->netfs, &v9fs_req_ops, true);256}257 258int v9fs_init_inode(struct v9fs_session_info *v9ses,259 struct inode *inode, umode_t mode, dev_t rdev)260{261 int err = 0;262 263 inode_init_owner(&nop_mnt_idmap, inode, NULL, mode);264 inode->i_blocks = 0;265 inode->i_rdev = rdev;266 simple_inode_init_ts(inode);267 inode->i_mapping->a_ops = &v9fs_addr_operations;268 inode->i_private = NULL;269 270 switch (mode & S_IFMT) {271 case S_IFIFO:272 case S_IFBLK:273 case S_IFCHR:274 case S_IFSOCK:275 if (v9fs_proto_dotl(v9ses)) {276 inode->i_op = &v9fs_file_inode_operations_dotl;277 } else if (v9fs_proto_dotu(v9ses)) {278 inode->i_op = &v9fs_file_inode_operations;279 } else {280 p9_debug(P9_DEBUG_ERROR,281 "special files without extended mode\n");282 err = -EINVAL;283 goto error;284 }285 init_special_inode(inode, inode->i_mode, inode->i_rdev);286 break;287 case S_IFREG:288 if (v9fs_proto_dotl(v9ses)) {289 inode->i_op = &v9fs_file_inode_operations_dotl;290 inode->i_fop = &v9fs_file_operations_dotl;291 } else {292 inode->i_op = &v9fs_file_inode_operations;293 inode->i_fop = &v9fs_file_operations;294 }295 296 break;297 case S_IFLNK:298 if (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses)) {299 p9_debug(P9_DEBUG_ERROR,300 "extended modes used with legacy protocol\n");301 err = -EINVAL;302 goto error;303 }304 305 if (v9fs_proto_dotl(v9ses))306 inode->i_op = &v9fs_symlink_inode_operations_dotl;307 else308 inode->i_op = &v9fs_symlink_inode_operations;309 310 break;311 case S_IFDIR:312 inc_nlink(inode);313 if (v9fs_proto_dotl(v9ses))314 inode->i_op = &v9fs_dir_inode_operations_dotl;315 else if (v9fs_proto_dotu(v9ses))316 inode->i_op = &v9fs_dir_inode_operations_dotu;317 else318 inode->i_op = &v9fs_dir_inode_operations;319 320 if (v9fs_proto_dotl(v9ses))321 inode->i_fop = &v9fs_dir_operations_dotl;322 else323 inode->i_fop = &v9fs_dir_operations;324 325 break;326 default:327 p9_debug(P9_DEBUG_ERROR, "BAD mode 0x%hx S_IFMT 0x%x\n",328 mode, mode & S_IFMT);329 err = -EINVAL;330 goto error;331 }332error:333 return err;334 335}336 337/**338 * v9fs_evict_inode - Remove an inode from the inode cache339 * @inode: inode to release340 *341 */342void v9fs_evict_inode(struct inode *inode)343{344 struct v9fs_inode __maybe_unused *v9inode = V9FS_I(inode);345 __le32 __maybe_unused version;346 347 if (!is_bad_inode(inode)) {348 netfs_wait_for_outstanding_io(inode);349 truncate_inode_pages_final(&inode->i_data);350 351 version = cpu_to_le32(v9inode->qid.version);352 netfs_clear_inode_writeback(inode, &version);353 354 clear_inode(inode);355 filemap_fdatawrite(&inode->i_data);356 357#ifdef CONFIG_9P_FSCACHE358 if (v9fs_inode_cookie(v9inode))359 fscache_relinquish_cookie(v9fs_inode_cookie(v9inode), false);360#endif361 } else362 clear_inode(inode);363}364 365static int v9fs_test_inode(struct inode *inode, void *data)366{367 int umode;368 dev_t rdev;369 struct v9fs_inode *v9inode = V9FS_I(inode);370 struct p9_wstat *st = (struct p9_wstat *)data;371 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);372 373 umode = p9mode2unixmode(v9ses, st, &rdev);374 /* don't match inode of different type */375 if (inode_wrong_type(inode, umode))376 return 0;377 378 /* compare qid details */379 if (memcmp(&v9inode->qid.version,380 &st->qid.version, sizeof(v9inode->qid.version)))381 return 0;382 383 if (v9inode->qid.type != st->qid.type)384 return 0;385 386 if (v9inode->qid.path != st->qid.path)387 return 0;388 return 1;389}390 391static int v9fs_test_new_inode(struct inode *inode, void *data)392{393 return 0;394}395 396static int v9fs_set_inode(struct inode *inode, void *data)397{398 struct v9fs_inode *v9inode = V9FS_I(inode);399 struct p9_wstat *st = (struct p9_wstat *)data;400 401 memcpy(&v9inode->qid, &st->qid, sizeof(st->qid));402 return 0;403}404 405static struct inode *v9fs_qid_iget(struct super_block *sb,406 struct p9_qid *qid,407 struct p9_wstat *st,408 int new)409{410 dev_t rdev;411 int retval;412 umode_t umode;413 struct inode *inode;414 struct v9fs_session_info *v9ses = sb->s_fs_info;415 int (*test)(struct inode *inode, void *data);416 417 if (new)418 test = v9fs_test_new_inode;419 else420 test = v9fs_test_inode;421 422 inode = iget5_locked(sb, QID2INO(qid), test, v9fs_set_inode, st);423 if (!inode)424 return ERR_PTR(-ENOMEM);425 if (!(inode->i_state & I_NEW))426 return inode;427 /*428 * initialize the inode with the stat info429 * FIXME!! we may need support for stale inodes430 * later.431 */432 inode->i_ino = QID2INO(qid);433 umode = p9mode2unixmode(v9ses, st, &rdev);434 retval = v9fs_init_inode(v9ses, inode, umode, rdev);435 if (retval)436 goto error;437 438 v9fs_stat2inode(st, inode, sb, 0);439 v9fs_set_netfs_context(inode);440 v9fs_cache_inode_get_cookie(inode);441 unlock_new_inode(inode);442 return inode;443error:444 iget_failed(inode);445 return ERR_PTR(retval);446 447}448 449struct inode *450v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,451 struct super_block *sb, int new)452{453 struct p9_wstat *st;454 struct inode *inode = NULL;455 456 st = p9_client_stat(fid);457 if (IS_ERR(st))458 return ERR_CAST(st);459 460 inode = v9fs_qid_iget(sb, &st->qid, st, new);461 p9stat_free(st);462 kfree(st);463 return inode;464}465 466/**467 * v9fs_at_to_dotl_flags- convert Linux specific AT flags to468 * plan 9 AT flag.469 * @flags: flags to convert470 */471static int v9fs_at_to_dotl_flags(int flags)472{473 int rflags = 0;474 475 if (flags & AT_REMOVEDIR)476 rflags |= P9_DOTL_AT_REMOVEDIR;477 478 return rflags;479}480 481/**482 * v9fs_dec_count - helper functon to drop i_nlink.483 *484 * If a directory had nlink <= 2 (including . and ..), then we should not drop485 * the link count, which indicates the underlying exported fs doesn't maintain486 * nlink accurately. e.g.487 * - overlayfs sets nlink to 1 for merged dir488 * - ext4 (with dir_nlink feature enabled) sets nlink to 1 if a dir has more489 * than EXT4_LINK_MAX (65000) links.490 *491 * @inode: inode whose nlink is being dropped492 */493static void v9fs_dec_count(struct inode *inode)494{495 if (!S_ISDIR(inode->i_mode) || inode->i_nlink > 2)496 drop_nlink(inode);497}498 499/**500 * v9fs_remove - helper function to remove files and directories501 * @dir: directory inode that is being deleted502 * @dentry: dentry that is being deleted503 * @flags: removing a directory504 *505 */506 507static int v9fs_remove(struct inode *dir, struct dentry *dentry, int flags)508{509 struct inode *inode;510 int retval = -EOPNOTSUPP;511 struct p9_fid *v9fid, *dfid;512 struct v9fs_session_info *v9ses;513 514 p9_debug(P9_DEBUG_VFS, "inode: %p dentry: %p rmdir: %x\n",515 dir, dentry, flags);516 517 v9ses = v9fs_inode2v9ses(dir);518 inode = d_inode(dentry);519 dfid = v9fs_parent_fid(dentry);520 if (IS_ERR(dfid)) {521 retval = PTR_ERR(dfid);522 p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", retval);523 return retval;524 }525 if (v9fs_proto_dotl(v9ses))526 retval = p9_client_unlinkat(dfid, dentry->d_name.name,527 v9fs_at_to_dotl_flags(flags));528 p9_fid_put(dfid);529 if (retval == -EOPNOTSUPP) {530 /* Try the one based on path */531 v9fid = v9fs_fid_clone(dentry);532 if (IS_ERR(v9fid))533 return PTR_ERR(v9fid);534 retval = p9_client_remove(v9fid);535 }536 if (!retval) {537 /*538 * directories on unlink should have zero539 * link count540 */541 if (flags & AT_REMOVEDIR) {542 clear_nlink(inode);543 v9fs_dec_count(dir);544 } else545 v9fs_dec_count(inode);546 547 v9fs_invalidate_inode_attr(inode);548 v9fs_invalidate_inode_attr(dir);549 550 /* invalidate all fids associated with dentry */551 /* NOTE: This will not include open fids */552 dentry->d_op->d_release(dentry);553 }554 return retval;555}556 557/**558 * v9fs_create - Create a file559 * @v9ses: session information560 * @dir: directory that dentry is being created in561 * @dentry: dentry that is being created562 * @extension: 9p2000.u extension string to support devices, etc.563 * @perm: create permissions564 * @mode: open mode565 *566 */567static struct p9_fid *568v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,569 struct dentry *dentry, char *extension, u32 perm, u8 mode)570{571 int err;572 const unsigned char *name;573 struct p9_fid *dfid, *ofid = NULL, *fid = NULL;574 struct inode *inode;575 576 p9_debug(P9_DEBUG_VFS, "name %pd\n", dentry);577 578 name = dentry->d_name.name;579 dfid = v9fs_parent_fid(dentry);580 if (IS_ERR(dfid)) {581 err = PTR_ERR(dfid);582 p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);583 return ERR_PTR(err);584 }585 586 /* clone a fid to use for creation */587 ofid = clone_fid(dfid);588 if (IS_ERR(ofid)) {589 err = PTR_ERR(ofid);590 p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);591 goto error;592 }593 594 err = p9_client_fcreate(ofid, name, perm, mode, extension);595 if (err < 0) {596 p9_debug(P9_DEBUG_VFS, "p9_client_fcreate failed %d\n", err);597 goto error;598 }599 600 if (!(perm & P9_DMLINK)) {601 /* now walk from the parent so we can get unopened fid */602 fid = p9_client_walk(dfid, 1, &name, 1);603 if (IS_ERR(fid)) {604 err = PTR_ERR(fid);605 p9_debug(P9_DEBUG_VFS,606 "p9_client_walk failed %d\n", err);607 goto error;608 }609 /*610 * instantiate inode and assign the unopened fid to the dentry611 */612 inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);613 if (IS_ERR(inode)) {614 err = PTR_ERR(inode);615 p9_debug(P9_DEBUG_VFS,616 "inode creation failed %d\n", err);617 goto error;618 }619 v9fs_fid_add(dentry, &fid);620 d_instantiate(dentry, inode);621 }622 p9_fid_put(dfid);623 return ofid;624error:625 p9_fid_put(dfid);626 p9_fid_put(ofid);627 p9_fid_put(fid);628 return ERR_PTR(err);629}630 631/**632 * v9fs_vfs_create - VFS hook to create a regular file633 * @idmap: idmap of the mount634 * @dir: The parent directory635 * @dentry: The name of file to be created636 * @mode: The UNIX file mode to set637 * @excl: True if the file must not yet exist638 *639 * open(.., O_CREAT) is handled in v9fs_vfs_atomic_open(). This is only called640 * for mknod(2).641 *642 */643 644static int645v9fs_vfs_create(struct mnt_idmap *idmap, struct inode *dir,646 struct dentry *dentry, umode_t mode, bool excl)647{648 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir);649 u32 perm = unixmode2p9mode(v9ses, mode);650 struct p9_fid *fid;651 652 /* P9_OEXCL? */653 fid = v9fs_create(v9ses, dir, dentry, NULL, perm, P9_ORDWR);654 if (IS_ERR(fid))655 return PTR_ERR(fid);656 657 v9fs_invalidate_inode_attr(dir);658 p9_fid_put(fid);659 660 return 0;661}662 663/**664 * v9fs_vfs_mkdir - VFS mkdir hook to create a directory665 * @idmap: idmap of the mount666 * @dir: inode that is being unlinked667 * @dentry: dentry that is being unlinked668 * @mode: mode for new directory669 *670 */671 672static int v9fs_vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir,673 struct dentry *dentry, umode_t mode)674{675 int err;676 u32 perm;677 struct p9_fid *fid;678 struct v9fs_session_info *v9ses;679 680 p9_debug(P9_DEBUG_VFS, "name %pd\n", dentry);681 err = 0;682 v9ses = v9fs_inode2v9ses(dir);683 perm = unixmode2p9mode(v9ses, mode | S_IFDIR);684 fid = v9fs_create(v9ses, dir, dentry, NULL, perm, P9_OREAD);685 if (IS_ERR(fid)) {686 err = PTR_ERR(fid);687 fid = NULL;688 } else {689 inc_nlink(dir);690 v9fs_invalidate_inode_attr(dir);691 }692 693 if (fid)694 p9_fid_put(fid);695 696 return err;697}698 699/**700 * v9fs_vfs_lookup - VFS lookup hook to "walk" to a new inode701 * @dir: inode that is being walked from702 * @dentry: dentry that is being walked to?703 * @flags: lookup flags (unused)704 *705 */706 707struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,708 unsigned int flags)709{710 struct dentry *res;711 struct v9fs_session_info *v9ses;712 struct p9_fid *dfid, *fid;713 struct inode *inode;714 const unsigned char *name;715 716 p9_debug(P9_DEBUG_VFS, "dir: %p dentry: (%pd) %p flags: %x\n",717 dir, dentry, dentry, flags);718 719 if (dentry->d_name.len > NAME_MAX)720 return ERR_PTR(-ENAMETOOLONG);721 722 v9ses = v9fs_inode2v9ses(dir);723 /* We can walk d_parent because we hold the dir->i_mutex */724 dfid = v9fs_parent_fid(dentry);725 if (IS_ERR(dfid))726 return ERR_CAST(dfid);727 728 /*729 * Make sure we don't use a wrong inode due to parallel730 * unlink. For cached mode create calls request for new731 * inode. But with cache disabled, lookup should do this.732 */733 name = dentry->d_name.name;734 fid = p9_client_walk(dfid, 1, &name, 1);735 p9_fid_put(dfid);736 if (fid == ERR_PTR(-ENOENT))737 inode = NULL;738 else if (IS_ERR(fid))739 inode = ERR_CAST(fid);740 else if (v9ses->cache & (CACHE_META|CACHE_LOOSE))741 inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb);742 else743 inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);744 /*745 * If we had a rename on the server and a parallel lookup746 * for the new name, then make sure we instantiate with747 * the new name. ie look up for a/b, while on server somebody748 * moved b under k and client parallely did a lookup for749 * k/b.750 */751 res = d_splice_alias(inode, dentry);752 if (!IS_ERR(fid)) {753 if (!res)754 v9fs_fid_add(dentry, &fid);755 else if (!IS_ERR(res))756 v9fs_fid_add(res, &fid);757 else758 p9_fid_put(fid);759 }760 return res;761}762 763static int764v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry,765 struct file *file, unsigned int flags, umode_t mode)766{767 int err;768 u32 perm;769 struct v9fs_inode __maybe_unused *v9inode;770 struct v9fs_session_info *v9ses;771 struct p9_fid *fid;772 struct dentry *res = NULL;773 struct inode *inode;774 int p9_omode;775 776 if (d_in_lookup(dentry)) {777 res = v9fs_vfs_lookup(dir, dentry, 0);778 if (IS_ERR(res))779 return PTR_ERR(res);780 781 if (res)782 dentry = res;783 }784 785 /* Only creates */786 if (!(flags & O_CREAT) || d_really_is_positive(dentry))787 return finish_no_open(file, res);788 789 v9ses = v9fs_inode2v9ses(dir);790 perm = unixmode2p9mode(v9ses, mode);791 p9_omode = v9fs_uflags2omode(flags, v9fs_proto_dotu(v9ses));792 793 if ((v9ses->cache & CACHE_WRITEBACK) && (p9_omode & P9_OWRITE)) {794 p9_omode = (p9_omode & ~P9_OWRITE) | P9_ORDWR;795 p9_debug(P9_DEBUG_CACHE,796 "write-only file with writeback enabled, creating w/ O_RDWR\n");797 }798 fid = v9fs_create(v9ses, dir, dentry, NULL, perm, p9_omode);799 if (IS_ERR(fid)) {800 err = PTR_ERR(fid);801 goto error;802 }803 804 v9fs_invalidate_inode_attr(dir);805 inode = d_inode(dentry);806 v9inode = V9FS_I(inode);807 err = finish_open(file, dentry, generic_file_open);808 if (err)809 goto error;810 811 file->private_data = fid;812#ifdef CONFIG_9P_FSCACHE813 if (v9ses->cache & CACHE_FSCACHE)814 fscache_use_cookie(v9fs_inode_cookie(v9inode),815 file->f_mode & FMODE_WRITE);816#endif817 818 v9fs_fid_add_modes(fid, v9ses->flags, v9ses->cache, file->f_flags);819 v9fs_open_fid_add(inode, &fid);820 821 file->f_mode |= FMODE_CREATED;822out:823 dput(res);824 return err;825 826error:827 p9_fid_put(fid);828 goto out;829}830 831/**832 * v9fs_vfs_unlink - VFS unlink hook to delete an inode833 * @i: inode that is being unlinked834 * @d: dentry that is being unlinked835 *836 */837 838int v9fs_vfs_unlink(struct inode *i, struct dentry *d)839{840 return v9fs_remove(i, d, 0);841}842 843/**844 * v9fs_vfs_rmdir - VFS unlink hook to delete a directory845 * @i: inode that is being unlinked846 * @d: dentry that is being unlinked847 *848 */849 850int v9fs_vfs_rmdir(struct inode *i, struct dentry *d)851{852 return v9fs_remove(i, d, AT_REMOVEDIR);853}854 855/**856 * v9fs_vfs_rename - VFS hook to rename an inode857 * @idmap: The idmap of the mount858 * @old_dir: old dir inode859 * @old_dentry: old dentry860 * @new_dir: new dir inode861 * @new_dentry: new dentry862 * @flags: RENAME_* flags863 *864 */865 866int867v9fs_vfs_rename(struct mnt_idmap *idmap, struct inode *old_dir,868 struct dentry *old_dentry, struct inode *new_dir,869 struct dentry *new_dentry, unsigned int flags)870{871 int retval;872 struct inode *old_inode;873 struct inode *new_inode;874 struct v9fs_session_info *v9ses;875 struct p9_fid *oldfid = NULL, *dfid = NULL;876 struct p9_fid *olddirfid = NULL;877 struct p9_fid *newdirfid = NULL;878 struct p9_wstat wstat;879 880 if (flags)881 return -EINVAL;882 883 p9_debug(P9_DEBUG_VFS, "\n");884 old_inode = d_inode(old_dentry);885 new_inode = d_inode(new_dentry);886 v9ses = v9fs_inode2v9ses(old_inode);887 oldfid = v9fs_fid_lookup(old_dentry);888 if (IS_ERR(oldfid))889 return PTR_ERR(oldfid);890 891 dfid = v9fs_parent_fid(old_dentry);892 olddirfid = clone_fid(dfid);893 p9_fid_put(dfid);894 dfid = NULL;895 896 if (IS_ERR(olddirfid)) {897 retval = PTR_ERR(olddirfid);898 goto error;899 }900 901 dfid = v9fs_parent_fid(new_dentry);902 newdirfid = clone_fid(dfid);903 p9_fid_put(dfid);904 dfid = NULL;905 906 if (IS_ERR(newdirfid)) {907 retval = PTR_ERR(newdirfid);908 goto error;909 }910 911 down_write(&v9ses->rename_sem);912 if (v9fs_proto_dotl(v9ses)) {913 retval = p9_client_renameat(olddirfid, old_dentry->d_name.name,914 newdirfid, new_dentry->d_name.name);915 if (retval == -EOPNOTSUPP)916 retval = p9_client_rename(oldfid, newdirfid,917 new_dentry->d_name.name);918 if (retval != -EOPNOTSUPP)919 goto error_locked;920 }921 if (old_dentry->d_parent != new_dentry->d_parent) {922 /*923 * 9P .u can only handle file rename in the same directory924 */925 926 p9_debug(P9_DEBUG_ERROR, "old dir and new dir are different\n");927 retval = -EXDEV;928 goto error_locked;929 }930 v9fs_blank_wstat(&wstat);931 wstat.muid = v9ses->uname;932 wstat.name = new_dentry->d_name.name;933 retval = p9_client_wstat(oldfid, &wstat);934 935error_locked:936 if (!retval) {937 if (new_inode) {938 if (S_ISDIR(new_inode->i_mode))939 clear_nlink(new_inode);940 else941 v9fs_dec_count(new_inode);942 }943 if (S_ISDIR(old_inode->i_mode)) {944 if (!new_inode)945 inc_nlink(new_dir);946 v9fs_dec_count(old_dir);947 }948 v9fs_invalidate_inode_attr(old_inode);949 v9fs_invalidate_inode_attr(old_dir);950 v9fs_invalidate_inode_attr(new_dir);951 952 /* successful rename */953 d_move(old_dentry, new_dentry);954 }955 up_write(&v9ses->rename_sem);956 957error:958 p9_fid_put(newdirfid);959 p9_fid_put(olddirfid);960 p9_fid_put(oldfid);961 return retval;962}963 964/**965 * v9fs_vfs_getattr - retrieve file metadata966 * @idmap: idmap of the mount967 * @path: Object to query968 * @stat: metadata structure to populate969 * @request_mask: Mask of STATX_xxx flags indicating the caller's interests970 * @flags: AT_STATX_xxx setting971 *972 */973 974static int975v9fs_vfs_getattr(struct mnt_idmap *idmap, const struct path *path,976 struct kstat *stat, u32 request_mask, unsigned int flags)977{978 struct dentry *dentry = path->dentry;979 struct inode *inode = d_inode(dentry);980 struct v9fs_session_info *v9ses;981 struct p9_fid *fid;982 struct p9_wstat *st;983 984 p9_debug(P9_DEBUG_VFS, "dentry: %p\n", dentry);985 v9ses = v9fs_dentry2v9ses(dentry);986 if (v9ses->cache & (CACHE_META|CACHE_LOOSE)) {987 generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);988 return 0;989 } else if (v9ses->cache & CACHE_WRITEBACK) {990 if (S_ISREG(inode->i_mode)) {991 int retval = filemap_fdatawrite(inode->i_mapping);992 993 if (retval)994 p9_debug(P9_DEBUG_ERROR,995 "flushing writeback during getattr returned %d\n", retval);996 }997 }998 fid = v9fs_fid_lookup(dentry);999 if (IS_ERR(fid))1000 return PTR_ERR(fid);1001 1002 st = p9_client_stat(fid);1003 p9_fid_put(fid);1004 if (IS_ERR(st))1005 return PTR_ERR(st);1006 1007 v9fs_stat2inode(st, d_inode(dentry), dentry->d_sb, 0);1008 generic_fillattr(&nop_mnt_idmap, request_mask, d_inode(dentry), stat);1009 1010 p9stat_free(st);1011 kfree(st);1012 return 0;1013}1014 1015/**1016 * v9fs_vfs_setattr - set file metadata1017 * @idmap: idmap of the mount1018 * @dentry: file whose metadata to set1019 * @iattr: metadata assignment structure1020 *1021 */1022 1023static int v9fs_vfs_setattr(struct mnt_idmap *idmap,1024 struct dentry *dentry, struct iattr *iattr)1025{1026 int retval, use_dentry = 0;1027 struct inode *inode = d_inode(dentry);1028 struct v9fs_session_info *v9ses;1029 struct p9_fid *fid = NULL;1030 struct p9_wstat wstat;1031 1032 p9_debug(P9_DEBUG_VFS, "\n");1033 retval = setattr_prepare(&nop_mnt_idmap, dentry, iattr);1034 if (retval)1035 return retval;1036 1037 v9ses = v9fs_dentry2v9ses(dentry);1038 if (iattr->ia_valid & ATTR_FILE) {1039 fid = iattr->ia_file->private_data;1040 WARN_ON(!fid);1041 }1042 if (!fid) {1043 fid = v9fs_fid_lookup(dentry);1044 use_dentry = 1;1045 }1046 if (IS_ERR(fid))1047 return PTR_ERR(fid);1048 1049 v9fs_blank_wstat(&wstat);1050 if (iattr->ia_valid & ATTR_MODE)1051 wstat.mode = unixmode2p9mode(v9ses, iattr->ia_mode);1052 1053 if (iattr->ia_valid & ATTR_MTIME)1054 wstat.mtime = iattr->ia_mtime.tv_sec;1055 1056 if (iattr->ia_valid & ATTR_ATIME)1057 wstat.atime = iattr->ia_atime.tv_sec;1058 1059 if (iattr->ia_valid & ATTR_SIZE)1060 wstat.length = iattr->ia_size;1061 1062 if (v9fs_proto_dotu(v9ses)) {1063 if (iattr->ia_valid & ATTR_UID)1064 wstat.n_uid = iattr->ia_uid;1065 1066 if (iattr->ia_valid & ATTR_GID)1067 wstat.n_gid = iattr->ia_gid;1068 }1069 1070 /* Write all dirty data */1071 if (d_is_reg(dentry)) {1072 retval = filemap_fdatawrite(inode->i_mapping);1073 if (retval)1074 p9_debug(P9_DEBUG_ERROR,1075 "flushing writeback during setattr returned %d\n", retval);1076 }1077 1078 retval = p9_client_wstat(fid, &wstat);1079 1080 if (use_dentry)1081 p9_fid_put(fid);1082 1083 if (retval < 0)1084 return retval;1085 1086 if ((iattr->ia_valid & ATTR_SIZE) &&1087 iattr->ia_size != i_size_read(inode)) {1088 truncate_setsize(inode, iattr->ia_size);1089 netfs_resize_file(netfs_inode(inode), iattr->ia_size, true);1090 1091#ifdef CONFIG_9P_FSCACHE1092 if (v9ses->cache & CACHE_FSCACHE) {1093 struct v9fs_inode *v9inode = V9FS_I(inode);1094 1095 fscache_resize_cookie(v9fs_inode_cookie(v9inode), iattr->ia_size);1096 }1097#endif1098 }1099 1100 v9fs_invalidate_inode_attr(inode);1101 1102 setattr_copy(&nop_mnt_idmap, inode, iattr);1103 mark_inode_dirty(inode);1104 return 0;1105}1106 1107/**1108 * v9fs_stat2inode - populate an inode structure with mistat info1109 * @stat: Plan 9 metadata (mistat) structure1110 * @inode: inode to populate1111 * @sb: superblock of filesystem1112 * @flags: control flags (e.g. V9FS_STAT2INODE_KEEP_ISIZE)1113 *1114 */1115 1116void1117v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,1118 struct super_block *sb, unsigned int flags)1119{1120 umode_t mode;1121 struct v9fs_session_info *v9ses = sb->s_fs_info;1122 struct v9fs_inode *v9inode = V9FS_I(inode);1123 1124 inode_set_atime(inode, stat->atime, 0);1125 inode_set_mtime(inode, stat->mtime, 0);1126 inode_set_ctime(inode, stat->mtime, 0);1127 1128 inode->i_uid = v9ses->dfltuid;1129 inode->i_gid = v9ses->dfltgid;1130 1131 if (v9fs_proto_dotu(v9ses)) {1132 inode->i_uid = stat->n_uid;1133 inode->i_gid = stat->n_gid;1134 }1135 if ((S_ISREG(inode->i_mode)) || (S_ISDIR(inode->i_mode))) {1136 if (v9fs_proto_dotu(v9ses)) {1137 unsigned int i_nlink;1138 /*1139 * Hadlink support got added later to the .u extension.1140 * So there can be a server out there that doesn't1141 * support this even with .u extension. That would1142 * just leave us with stat->extension being an empty1143 * string, though.1144 */1145 /* HARDLINKCOUNT %u */1146 if (sscanf(stat->extension,1147 " HARDLINKCOUNT %u", &i_nlink) == 1)1148 set_nlink(inode, i_nlink);1149 }1150 }1151 mode = p9mode2perm(v9ses, stat);1152 mode |= inode->i_mode & ~S_IALLUGO;1153 inode->i_mode = mode;1154 1155 v9inode->netfs.remote_i_size = stat->length;1156 if (!(flags & V9FS_STAT2INODE_KEEP_ISIZE))1157 v9fs_i_size_write(inode, stat->length);1158 /* not real number of blocks, but 512 byte ones ... */1159 inode->i_blocks = (stat->length + 512 - 1) >> 9;1160 v9inode->cache_validity &= ~V9FS_INO_INVALID_ATTR;1161}1162 1163/**1164 * v9fs_vfs_get_link - follow a symlink path1165 * @dentry: dentry for symlink1166 * @inode: inode for symlink1167 * @done: delayed call for when we are done with the return value1168 */1169 1170static const char *v9fs_vfs_get_link(struct dentry *dentry,1171 struct inode *inode,1172 struct delayed_call *done)1173{1174 struct v9fs_session_info *v9ses;1175 struct p9_fid *fid;1176 struct p9_wstat *st;1177 char *res;1178 1179 if (!dentry)1180 return ERR_PTR(-ECHILD);1181 1182 v9ses = v9fs_dentry2v9ses(dentry);1183 if (!v9fs_proto_dotu(v9ses))1184 return ERR_PTR(-EBADF);1185 1186 p9_debug(P9_DEBUG_VFS, "%pd\n", dentry);1187 fid = v9fs_fid_lookup(dentry);1188 1189 if (IS_ERR(fid))1190 return ERR_CAST(fid);1191 1192 st = p9_client_stat(fid);1193 p9_fid_put(fid);1194 if (IS_ERR(st))1195 return ERR_CAST(st);1196 1197 if (!(st->mode & P9_DMSYMLINK)) {1198 p9stat_free(st);1199 kfree(st);1200 return ERR_PTR(-EINVAL);1201 }1202 res = st->extension;1203 st->extension = NULL;1204 if (strlen(res) >= PATH_MAX)1205 res[PATH_MAX - 1] = '\0';1206 1207 p9stat_free(st);1208 kfree(st);1209 set_delayed_call(done, kfree_link, res);1210 return res;1211}1212 1213/**1214 * v9fs_vfs_mkspecial - create a special file1215 * @dir: inode to create special file in1216 * @dentry: dentry to create1217 * @perm: mode to create special file1218 * @extension: 9p2000.u format extension string representing special file1219 *1220 */1221 1222static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,1223 u32 perm, const char *extension)1224{1225 struct p9_fid *fid;1226 struct v9fs_session_info *v9ses;1227 1228 v9ses = v9fs_inode2v9ses(dir);1229 if (!v9fs_proto_dotu(v9ses)) {1230 p9_debug(P9_DEBUG_ERROR, "not extended\n");1231 return -EPERM;1232 }1233 1234 fid = v9fs_create(v9ses, dir, dentry, (char *) extension, perm,1235 P9_OREAD);1236 if (IS_ERR(fid))1237 return PTR_ERR(fid);1238 1239 v9fs_invalidate_inode_attr(dir);1240 p9_fid_put(fid);1241 return 0;1242}1243 1244/**1245 * v9fs_vfs_symlink - helper function to create symlinks1246 * @idmap: idmap of the mount1247 * @dir: directory inode containing symlink1248 * @dentry: dentry for symlink1249 * @symname: symlink data1250 *1251 * See Also: 9P2000.u RFC for more information1252 *1253 */1254 1255static int1256v9fs_vfs_symlink(struct mnt_idmap *idmap, struct inode *dir,1257 struct dentry *dentry, const char *symname)1258{1259 p9_debug(P9_DEBUG_VFS, " %lu,%pd,%s\n",1260 dir->i_ino, dentry, symname);1261 1262 return v9fs_vfs_mkspecial(dir, dentry, P9_DMSYMLINK, symname);1263}1264 1265#define U32_MAX_DIGITS 101266 1267/**1268 * v9fs_vfs_link - create a hardlink1269 * @old_dentry: dentry for file to link to1270 * @dir: inode destination for new link1271 * @dentry: dentry for link1272 *1273 */1274 1275static int1276v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,1277 struct dentry *dentry)1278{1279 int retval;1280 char name[1 + U32_MAX_DIGITS + 2]; /* sign + number + \n + \0 */1281 struct p9_fid *oldfid;1282 1283 p9_debug(P9_DEBUG_VFS, " %lu,%pd,%pd\n",1284 dir->i_ino, dentry, old_dentry);1285 1286 oldfid = v9fs_fid_clone(old_dentry);1287 if (IS_ERR(oldfid))1288 return PTR_ERR(oldfid);1289 1290 sprintf(name, "%d\n", oldfid->fid);1291 retval = v9fs_vfs_mkspecial(dir, dentry, P9_DMLINK, name);1292 if (!retval) {1293 v9fs_refresh_inode(oldfid, d_inode(old_dentry));1294 v9fs_invalidate_inode_attr(dir);1295 }1296 p9_fid_put(oldfid);1297 return retval;1298}1299 1300/**1301 * v9fs_vfs_mknod - create a special file1302 * @idmap: idmap of the mount1303 * @dir: inode destination for new link1304 * @dentry: dentry for file1305 * @mode: mode for creation1306 * @rdev: device associated with special file1307 *1308 */1309 1310static int1311v9fs_vfs_mknod(struct mnt_idmap *idmap, struct inode *dir,1312 struct dentry *dentry, umode_t mode, dev_t rdev)1313{1314 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir);1315 int retval;1316 char name[2 + U32_MAX_DIGITS + 1 + U32_MAX_DIGITS + 1];1317 u32 perm;1318 1319 p9_debug(P9_DEBUG_VFS, " %lu,%pd mode: %x MAJOR: %u MINOR: %u\n",1320 dir->i_ino, dentry, mode,1321 MAJOR(rdev), MINOR(rdev));1322 1323 /* build extension */1324 if (S_ISBLK(mode))1325 sprintf(name, "b %u %u", MAJOR(rdev), MINOR(rdev));1326 else if (S_ISCHR(mode))1327 sprintf(name, "c %u %u", MAJOR(rdev), MINOR(rdev));1328 else1329 *name = 0;1330 1331 perm = unixmode2p9mode(v9ses, mode);1332 retval = v9fs_vfs_mkspecial(dir, dentry, perm, name);1333 1334 return retval;1335}1336 1337int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode)1338{1339 int umode;1340 dev_t rdev;1341 struct p9_wstat *st;1342 struct v9fs_session_info *v9ses;1343 unsigned int flags;1344 1345 v9ses = v9fs_inode2v9ses(inode);1346 st = p9_client_stat(fid);1347 if (IS_ERR(st))1348 return PTR_ERR(st);1349 /*1350 * Don't update inode if the file type is different1351 */1352 umode = p9mode2unixmode(v9ses, st, &rdev);1353 if (inode_wrong_type(inode, umode))1354 goto out;1355 1356 /*1357 * We don't want to refresh inode->i_size,1358 * because we may have cached data1359 */1360 flags = (v9ses->cache & CACHE_LOOSE) ?1361 V9FS_STAT2INODE_KEEP_ISIZE : 0;1362 v9fs_stat2inode(st, inode, inode->i_sb, flags);1363out:1364 p9stat_free(st);1365 kfree(st);1366 return 0;1367}1368 1369static const struct inode_operations v9fs_dir_inode_operations_dotu = {1370 .create = v9fs_vfs_create,1371 .lookup = v9fs_vfs_lookup,1372 .atomic_open = v9fs_vfs_atomic_open,1373 .symlink = v9fs_vfs_symlink,1374 .link = v9fs_vfs_link,1375 .unlink = v9fs_vfs_unlink,1376 .mkdir = v9fs_vfs_mkdir,1377 .rmdir = v9fs_vfs_rmdir,1378 .mknod = v9fs_vfs_mknod,1379 .rename = v9fs_vfs_rename,1380 .getattr = v9fs_vfs_getattr,1381 .setattr = v9fs_vfs_setattr,1382};1383 1384static const struct inode_operations v9fs_dir_inode_operations = {1385 .create = v9fs_vfs_create,1386 .lookup = v9fs_vfs_lookup,1387 .atomic_open = v9fs_vfs_atomic_open,1388 .unlink = v9fs_vfs_unlink,1389 .mkdir = v9fs_vfs_mkdir,1390 .rmdir = v9fs_vfs_rmdir,1391 .mknod = v9fs_vfs_mknod,1392 .rename = v9fs_vfs_rename,1393 .getattr = v9fs_vfs_getattr,1394 .setattr = v9fs_vfs_setattr,1395};1396 1397static const struct inode_operations v9fs_file_inode_operations = {1398 .getattr = v9fs_vfs_getattr,1399 .setattr = v9fs_vfs_setattr,1400};1401 1402static const struct inode_operations v9fs_symlink_inode_operations = {1403 .get_link = v9fs_vfs_get_link,1404 .getattr = v9fs_vfs_getattr,1405 .setattr = v9fs_vfs_setattr,1406};1407 1408