brintos

brintos / linux-shallow public Read only

0
0
Text · 23.3 KiB · 143ac03 Raw
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