brintos

brintos / linux-shallow public Read only

0
0
Text · 32.6 KiB · 3e68521 Raw
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