162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * This file contains vfs inode ops for the 9P2000.L protocol. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> 662306a36Sopenharmony_ci * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/errno.h> 1162306a36Sopenharmony_ci#include <linux/fs.h> 1262306a36Sopenharmony_ci#include <linux/file.h> 1362306a36Sopenharmony_ci#include <linux/pagemap.h> 1462306a36Sopenharmony_ci#include <linux/stat.h> 1562306a36Sopenharmony_ci#include <linux/string.h> 1662306a36Sopenharmony_ci#include <linux/namei.h> 1762306a36Sopenharmony_ci#include <linux/sched.h> 1862306a36Sopenharmony_ci#include <linux/slab.h> 1962306a36Sopenharmony_ci#include <linux/xattr.h> 2062306a36Sopenharmony_ci#include <linux/posix_acl.h> 2162306a36Sopenharmony_ci#include <net/9p/9p.h> 2262306a36Sopenharmony_ci#include <net/9p/client.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include "v9fs.h" 2562306a36Sopenharmony_ci#include "v9fs_vfs.h" 2662306a36Sopenharmony_ci#include "fid.h" 2762306a36Sopenharmony_ci#include "cache.h" 2862306a36Sopenharmony_ci#include "xattr.h" 2962306a36Sopenharmony_ci#include "acl.h" 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic int 3262306a36Sopenharmony_civ9fs_vfs_mknod_dotl(struct mnt_idmap *idmap, struct inode *dir, 3362306a36Sopenharmony_ci struct dentry *dentry, umode_t omode, dev_t rdev); 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci/** 3662306a36Sopenharmony_ci * v9fs_get_fsgid_for_create - Helper function to get the gid for a new object 3762306a36Sopenharmony_ci * @dir_inode: The directory inode 3862306a36Sopenharmony_ci * 3962306a36Sopenharmony_ci * Helper function to get the gid for creating a 4062306a36Sopenharmony_ci * new file system object. This checks the S_ISGID to determine the owning 4162306a36Sopenharmony_ci * group of the new file system object. 4262306a36Sopenharmony_ci */ 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic kgid_t v9fs_get_fsgid_for_create(struct inode *dir_inode) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci BUG_ON(dir_inode == NULL); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci if (dir_inode->i_mode & S_ISGID) { 4962306a36Sopenharmony_ci /* set_gid bit is set.*/ 5062306a36Sopenharmony_ci return dir_inode->i_gid; 5162306a36Sopenharmony_ci } 5262306a36Sopenharmony_ci return current_fsgid(); 5362306a36Sopenharmony_ci} 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic int v9fs_test_inode_dotl(struct inode *inode, void *data) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci struct v9fs_inode *v9inode = V9FS_I(inode); 5862306a36Sopenharmony_ci struct p9_stat_dotl *st = (struct p9_stat_dotl *)data; 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci /* don't match inode of different type */ 6162306a36Sopenharmony_ci if (inode_wrong_type(inode, st->st_mode)) 6262306a36Sopenharmony_ci return 0; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci if (inode->i_generation != st->st_gen) 6562306a36Sopenharmony_ci return 0; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci /* compare qid details */ 6862306a36Sopenharmony_ci if (memcmp(&v9inode->qid.version, 6962306a36Sopenharmony_ci &st->qid.version, sizeof(v9inode->qid.version))) 7062306a36Sopenharmony_ci return 0; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci if (v9inode->qid.type != st->qid.type) 7362306a36Sopenharmony_ci return 0; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci if (v9inode->qid.path != st->qid.path) 7662306a36Sopenharmony_ci return 0; 7762306a36Sopenharmony_ci return 1; 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci/* Always get a new inode */ 8162306a36Sopenharmony_cistatic int v9fs_test_new_inode_dotl(struct inode *inode, void *data) 8262306a36Sopenharmony_ci{ 8362306a36Sopenharmony_ci return 0; 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic int v9fs_set_inode_dotl(struct inode *inode, void *data) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci struct v9fs_inode *v9inode = V9FS_I(inode); 8962306a36Sopenharmony_ci struct p9_stat_dotl *st = (struct p9_stat_dotl *)data; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci memcpy(&v9inode->qid, &st->qid, sizeof(st->qid)); 9262306a36Sopenharmony_ci inode->i_generation = st->st_gen; 9362306a36Sopenharmony_ci return 0; 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistatic struct inode *v9fs_qid_iget_dotl(struct super_block *sb, 9762306a36Sopenharmony_ci struct p9_qid *qid, 9862306a36Sopenharmony_ci struct p9_fid *fid, 9962306a36Sopenharmony_ci struct p9_stat_dotl *st, 10062306a36Sopenharmony_ci int new) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci int retval; 10362306a36Sopenharmony_ci unsigned long i_ino; 10462306a36Sopenharmony_ci struct inode *inode; 10562306a36Sopenharmony_ci struct v9fs_session_info *v9ses = sb->s_fs_info; 10662306a36Sopenharmony_ci int (*test)(struct inode *inode, void *data); 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci if (new) 10962306a36Sopenharmony_ci test = v9fs_test_new_inode_dotl; 11062306a36Sopenharmony_ci else 11162306a36Sopenharmony_ci test = v9fs_test_inode_dotl; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci i_ino = v9fs_qid2ino(qid); 11462306a36Sopenharmony_ci inode = iget5_locked(sb, i_ino, test, v9fs_set_inode_dotl, st); 11562306a36Sopenharmony_ci if (!inode) 11662306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 11762306a36Sopenharmony_ci if (!(inode->i_state & I_NEW)) 11862306a36Sopenharmony_ci return inode; 11962306a36Sopenharmony_ci /* 12062306a36Sopenharmony_ci * initialize the inode with the stat info 12162306a36Sopenharmony_ci * FIXME!! we may need support for stale inodes 12262306a36Sopenharmony_ci * later. 12362306a36Sopenharmony_ci */ 12462306a36Sopenharmony_ci inode->i_ino = i_ino; 12562306a36Sopenharmony_ci retval = v9fs_init_inode(v9ses, inode, 12662306a36Sopenharmony_ci st->st_mode, new_decode_dev(st->st_rdev)); 12762306a36Sopenharmony_ci if (retval) 12862306a36Sopenharmony_ci goto error; 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci v9fs_stat2inode_dotl(st, inode, 0); 13162306a36Sopenharmony_ci v9fs_set_netfs_context(inode); 13262306a36Sopenharmony_ci v9fs_cache_inode_get_cookie(inode); 13362306a36Sopenharmony_ci retval = v9fs_get_acl(inode, fid); 13462306a36Sopenharmony_ci if (retval) 13562306a36Sopenharmony_ci goto error; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci unlock_new_inode(inode); 13862306a36Sopenharmony_ci return inode; 13962306a36Sopenharmony_cierror: 14062306a36Sopenharmony_ci iget_failed(inode); 14162306a36Sopenharmony_ci return ERR_PTR(retval); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistruct inode * 14662306a36Sopenharmony_civ9fs_inode_from_fid_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid, 14762306a36Sopenharmony_ci struct super_block *sb, int new) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci struct p9_stat_dotl *st; 15062306a36Sopenharmony_ci struct inode *inode = NULL; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci st = p9_client_getattr_dotl(fid, P9_STATS_BASIC | P9_STATS_GEN); 15362306a36Sopenharmony_ci if (IS_ERR(st)) 15462306a36Sopenharmony_ci return ERR_CAST(st); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci inode = v9fs_qid_iget_dotl(sb, &st->qid, fid, st, new); 15762306a36Sopenharmony_ci kfree(st); 15862306a36Sopenharmony_ci return inode; 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistruct dotl_openflag_map { 16262306a36Sopenharmony_ci int open_flag; 16362306a36Sopenharmony_ci int dotl_flag; 16462306a36Sopenharmony_ci}; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_cistatic int v9fs_mapped_dotl_flags(int flags) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci int i; 16962306a36Sopenharmony_ci int rflags = 0; 17062306a36Sopenharmony_ci struct dotl_openflag_map dotl_oflag_map[] = { 17162306a36Sopenharmony_ci { O_CREAT, P9_DOTL_CREATE }, 17262306a36Sopenharmony_ci { O_EXCL, P9_DOTL_EXCL }, 17362306a36Sopenharmony_ci { O_NOCTTY, P9_DOTL_NOCTTY }, 17462306a36Sopenharmony_ci { O_APPEND, P9_DOTL_APPEND }, 17562306a36Sopenharmony_ci { O_NONBLOCK, P9_DOTL_NONBLOCK }, 17662306a36Sopenharmony_ci { O_DSYNC, P9_DOTL_DSYNC }, 17762306a36Sopenharmony_ci { FASYNC, P9_DOTL_FASYNC }, 17862306a36Sopenharmony_ci { O_DIRECT, P9_DOTL_DIRECT }, 17962306a36Sopenharmony_ci { O_LARGEFILE, P9_DOTL_LARGEFILE }, 18062306a36Sopenharmony_ci { O_DIRECTORY, P9_DOTL_DIRECTORY }, 18162306a36Sopenharmony_ci { O_NOFOLLOW, P9_DOTL_NOFOLLOW }, 18262306a36Sopenharmony_ci { O_NOATIME, P9_DOTL_NOATIME }, 18362306a36Sopenharmony_ci { O_CLOEXEC, P9_DOTL_CLOEXEC }, 18462306a36Sopenharmony_ci { O_SYNC, P9_DOTL_SYNC}, 18562306a36Sopenharmony_ci }; 18662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(dotl_oflag_map); i++) { 18762306a36Sopenharmony_ci if (flags & dotl_oflag_map[i].open_flag) 18862306a36Sopenharmony_ci rflags |= dotl_oflag_map[i].dotl_flag; 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci return rflags; 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci/** 19462306a36Sopenharmony_ci * v9fs_open_to_dotl_flags- convert Linux specific open flags to 19562306a36Sopenharmony_ci * plan 9 open flag. 19662306a36Sopenharmony_ci * @flags: flags to convert 19762306a36Sopenharmony_ci */ 19862306a36Sopenharmony_ciint v9fs_open_to_dotl_flags(int flags) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci int rflags = 0; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci /* 20362306a36Sopenharmony_ci * We have same bits for P9_DOTL_READONLY, P9_DOTL_WRONLY 20462306a36Sopenharmony_ci * and P9_DOTL_NOACCESS 20562306a36Sopenharmony_ci */ 20662306a36Sopenharmony_ci rflags |= flags & O_ACCMODE; 20762306a36Sopenharmony_ci rflags |= v9fs_mapped_dotl_flags(flags); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci return rflags; 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci/** 21362306a36Sopenharmony_ci * v9fs_vfs_create_dotl - VFS hook to create files for 9P2000.L protocol. 21462306a36Sopenharmony_ci * @idmap: The user namespace of the mount 21562306a36Sopenharmony_ci * @dir: directory inode that is being created 21662306a36Sopenharmony_ci * @dentry: dentry that is being deleted 21762306a36Sopenharmony_ci * @omode: create permissions 21862306a36Sopenharmony_ci * @excl: True if the file must not yet exist 21962306a36Sopenharmony_ci * 22062306a36Sopenharmony_ci */ 22162306a36Sopenharmony_cistatic int 22262306a36Sopenharmony_civ9fs_vfs_create_dotl(struct mnt_idmap *idmap, struct inode *dir, 22362306a36Sopenharmony_ci struct dentry *dentry, umode_t omode, bool excl) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci return v9fs_vfs_mknod_dotl(idmap, dir, dentry, omode, 0); 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic int 22962306a36Sopenharmony_civ9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry, 23062306a36Sopenharmony_ci struct file *file, unsigned int flags, umode_t omode) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci int err = 0; 23362306a36Sopenharmony_ci kgid_t gid; 23462306a36Sopenharmony_ci umode_t mode; 23562306a36Sopenharmony_ci int p9_omode = v9fs_open_to_dotl_flags(flags); 23662306a36Sopenharmony_ci const unsigned char *name = NULL; 23762306a36Sopenharmony_ci struct p9_qid qid; 23862306a36Sopenharmony_ci struct inode *inode; 23962306a36Sopenharmony_ci struct p9_fid *fid = NULL; 24062306a36Sopenharmony_ci struct p9_fid *dfid = NULL, *ofid = NULL; 24162306a36Sopenharmony_ci struct v9fs_session_info *v9ses; 24262306a36Sopenharmony_ci struct posix_acl *pacl = NULL, *dacl = NULL; 24362306a36Sopenharmony_ci struct dentry *res = NULL; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci if (d_in_lookup(dentry)) { 24662306a36Sopenharmony_ci res = v9fs_vfs_lookup(dir, dentry, 0); 24762306a36Sopenharmony_ci if (IS_ERR(res)) 24862306a36Sopenharmony_ci return PTR_ERR(res); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci if (res) 25162306a36Sopenharmony_ci dentry = res; 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci /* Only creates */ 25562306a36Sopenharmony_ci if (!(flags & O_CREAT) || d_really_is_positive(dentry)) 25662306a36Sopenharmony_ci return finish_no_open(file, res); 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci v9ses = v9fs_inode2v9ses(dir); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci name = dentry->d_name.name; 26162306a36Sopenharmony_ci p9_debug(P9_DEBUG_VFS, "name:%s flags:0x%x mode:0x%x\n", 26262306a36Sopenharmony_ci name, flags, omode); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci dfid = v9fs_parent_fid(dentry); 26562306a36Sopenharmony_ci if (IS_ERR(dfid)) { 26662306a36Sopenharmony_ci err = PTR_ERR(dfid); 26762306a36Sopenharmony_ci p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err); 26862306a36Sopenharmony_ci goto out; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci /* clone a fid to use for creation */ 27262306a36Sopenharmony_ci ofid = clone_fid(dfid); 27362306a36Sopenharmony_ci if (IS_ERR(ofid)) { 27462306a36Sopenharmony_ci err = PTR_ERR(ofid); 27562306a36Sopenharmony_ci p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err); 27662306a36Sopenharmony_ci goto out; 27762306a36Sopenharmony_ci } 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci gid = v9fs_get_fsgid_for_create(dir); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci mode = omode; 28262306a36Sopenharmony_ci /* Update mode based on ACL value */ 28362306a36Sopenharmony_ci err = v9fs_acl_mode(dir, &mode, &dacl, &pacl); 28462306a36Sopenharmony_ci if (err) { 28562306a36Sopenharmony_ci p9_debug(P9_DEBUG_VFS, "Failed to get acl values in create %d\n", 28662306a36Sopenharmony_ci err); 28762306a36Sopenharmony_ci goto out; 28862306a36Sopenharmony_ci } 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci if ((v9ses->cache & CACHE_WRITEBACK) && (p9_omode & P9_OWRITE)) { 29162306a36Sopenharmony_ci p9_omode = (p9_omode & ~P9_OWRITE) | P9_ORDWR; 29262306a36Sopenharmony_ci p9_debug(P9_DEBUG_CACHE, 29362306a36Sopenharmony_ci "write-only file with writeback enabled, creating w/ O_RDWR\n"); 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci err = p9_client_create_dotl(ofid, name, p9_omode, mode, gid, &qid); 29662306a36Sopenharmony_ci if (err < 0) { 29762306a36Sopenharmony_ci p9_debug(P9_DEBUG_VFS, "p9_client_open_dotl failed in create %d\n", 29862306a36Sopenharmony_ci err); 29962306a36Sopenharmony_ci goto out; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci v9fs_invalidate_inode_attr(dir); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci /* instantiate inode and assign the unopened fid to the dentry */ 30462306a36Sopenharmony_ci fid = p9_client_walk(dfid, 1, &name, 1); 30562306a36Sopenharmony_ci if (IS_ERR(fid)) { 30662306a36Sopenharmony_ci err = PTR_ERR(fid); 30762306a36Sopenharmony_ci p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err); 30862306a36Sopenharmony_ci goto out; 30962306a36Sopenharmony_ci } 31062306a36Sopenharmony_ci inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb); 31162306a36Sopenharmony_ci if (IS_ERR(inode)) { 31262306a36Sopenharmony_ci err = PTR_ERR(inode); 31362306a36Sopenharmony_ci p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n", err); 31462306a36Sopenharmony_ci goto out; 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci /* Now set the ACL based on the default value */ 31762306a36Sopenharmony_ci v9fs_set_create_acl(inode, fid, dacl, pacl); 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci v9fs_fid_add(dentry, &fid); 32062306a36Sopenharmony_ci d_instantiate(dentry, inode); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci /* Since we are opening a file, assign the open fid to the file */ 32362306a36Sopenharmony_ci err = finish_open(file, dentry, generic_file_open); 32462306a36Sopenharmony_ci if (err) 32562306a36Sopenharmony_ci goto out; 32662306a36Sopenharmony_ci file->private_data = ofid; 32762306a36Sopenharmony_ci#ifdef CONFIG_9P_FSCACHE 32862306a36Sopenharmony_ci if (v9ses->cache & CACHE_FSCACHE) { 32962306a36Sopenharmony_ci struct v9fs_inode *v9inode = V9FS_I(inode); 33062306a36Sopenharmony_ci fscache_use_cookie(v9fs_inode_cookie(v9inode), 33162306a36Sopenharmony_ci file->f_mode & FMODE_WRITE); 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci#endif 33462306a36Sopenharmony_ci v9fs_fid_add_modes(ofid, v9ses->flags, v9ses->cache, flags); 33562306a36Sopenharmony_ci v9fs_open_fid_add(inode, &ofid); 33662306a36Sopenharmony_ci file->f_mode |= FMODE_CREATED; 33762306a36Sopenharmony_ciout: 33862306a36Sopenharmony_ci p9_fid_put(dfid); 33962306a36Sopenharmony_ci p9_fid_put(ofid); 34062306a36Sopenharmony_ci p9_fid_put(fid); 34162306a36Sopenharmony_ci v9fs_put_acl(dacl, pacl); 34262306a36Sopenharmony_ci dput(res); 34362306a36Sopenharmony_ci return err; 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci/** 34762306a36Sopenharmony_ci * v9fs_vfs_mkdir_dotl - VFS mkdir hook to create a directory 34862306a36Sopenharmony_ci * @idmap: The idmap of the mount 34962306a36Sopenharmony_ci * @dir: inode that is being unlinked 35062306a36Sopenharmony_ci * @dentry: dentry that is being unlinked 35162306a36Sopenharmony_ci * @omode: mode for new directory 35262306a36Sopenharmony_ci * 35362306a36Sopenharmony_ci */ 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic int v9fs_vfs_mkdir_dotl(struct mnt_idmap *idmap, 35662306a36Sopenharmony_ci struct inode *dir, struct dentry *dentry, 35762306a36Sopenharmony_ci umode_t omode) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci int err; 36062306a36Sopenharmony_ci struct v9fs_session_info *v9ses; 36162306a36Sopenharmony_ci struct p9_fid *fid = NULL, *dfid = NULL; 36262306a36Sopenharmony_ci kgid_t gid; 36362306a36Sopenharmony_ci const unsigned char *name; 36462306a36Sopenharmony_ci umode_t mode; 36562306a36Sopenharmony_ci struct inode *inode; 36662306a36Sopenharmony_ci struct p9_qid qid; 36762306a36Sopenharmony_ci struct posix_acl *dacl = NULL, *pacl = NULL; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci p9_debug(P9_DEBUG_VFS, "name %pd\n", dentry); 37062306a36Sopenharmony_ci v9ses = v9fs_inode2v9ses(dir); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci omode |= S_IFDIR; 37362306a36Sopenharmony_ci if (dir->i_mode & S_ISGID) 37462306a36Sopenharmony_ci omode |= S_ISGID; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci dfid = v9fs_parent_fid(dentry); 37762306a36Sopenharmony_ci if (IS_ERR(dfid)) { 37862306a36Sopenharmony_ci err = PTR_ERR(dfid); 37962306a36Sopenharmony_ci p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err); 38062306a36Sopenharmony_ci goto error; 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci gid = v9fs_get_fsgid_for_create(dir); 38462306a36Sopenharmony_ci mode = omode; 38562306a36Sopenharmony_ci /* Update mode based on ACL value */ 38662306a36Sopenharmony_ci err = v9fs_acl_mode(dir, &mode, &dacl, &pacl); 38762306a36Sopenharmony_ci if (err) { 38862306a36Sopenharmony_ci p9_debug(P9_DEBUG_VFS, "Failed to get acl values in mkdir %d\n", 38962306a36Sopenharmony_ci err); 39062306a36Sopenharmony_ci goto error; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci name = dentry->d_name.name; 39362306a36Sopenharmony_ci err = p9_client_mkdir_dotl(dfid, name, mode, gid, &qid); 39462306a36Sopenharmony_ci if (err < 0) 39562306a36Sopenharmony_ci goto error; 39662306a36Sopenharmony_ci fid = p9_client_walk(dfid, 1, &name, 1); 39762306a36Sopenharmony_ci if (IS_ERR(fid)) { 39862306a36Sopenharmony_ci err = PTR_ERR(fid); 39962306a36Sopenharmony_ci p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", 40062306a36Sopenharmony_ci err); 40162306a36Sopenharmony_ci goto error; 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci /* instantiate inode and assign the unopened fid to the dentry */ 40562306a36Sopenharmony_ci if (v9ses->cache & (CACHE_META|CACHE_LOOSE)) { 40662306a36Sopenharmony_ci inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb); 40762306a36Sopenharmony_ci if (IS_ERR(inode)) { 40862306a36Sopenharmony_ci err = PTR_ERR(inode); 40962306a36Sopenharmony_ci p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n", 41062306a36Sopenharmony_ci err); 41162306a36Sopenharmony_ci goto error; 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci v9fs_fid_add(dentry, &fid); 41462306a36Sopenharmony_ci v9fs_set_create_acl(inode, fid, dacl, pacl); 41562306a36Sopenharmony_ci d_instantiate(dentry, inode); 41662306a36Sopenharmony_ci err = 0; 41762306a36Sopenharmony_ci } else { 41862306a36Sopenharmony_ci /* 41962306a36Sopenharmony_ci * Not in cached mode. No need to populate 42062306a36Sopenharmony_ci * inode with stat. We need to get an inode 42162306a36Sopenharmony_ci * so that we can set the acl with dentry 42262306a36Sopenharmony_ci */ 42362306a36Sopenharmony_ci inode = v9fs_get_inode(dir->i_sb, mode, 0); 42462306a36Sopenharmony_ci if (IS_ERR(inode)) { 42562306a36Sopenharmony_ci err = PTR_ERR(inode); 42662306a36Sopenharmony_ci goto error; 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci v9fs_set_create_acl(inode, fid, dacl, pacl); 42962306a36Sopenharmony_ci d_instantiate(dentry, inode); 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci inc_nlink(dir); 43262306a36Sopenharmony_ci v9fs_invalidate_inode_attr(dir); 43362306a36Sopenharmony_cierror: 43462306a36Sopenharmony_ci p9_fid_put(fid); 43562306a36Sopenharmony_ci v9fs_put_acl(dacl, pacl); 43662306a36Sopenharmony_ci p9_fid_put(dfid); 43762306a36Sopenharmony_ci return err; 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_cistatic int 44162306a36Sopenharmony_civ9fs_vfs_getattr_dotl(struct mnt_idmap *idmap, 44262306a36Sopenharmony_ci const struct path *path, struct kstat *stat, 44362306a36Sopenharmony_ci u32 request_mask, unsigned int flags) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci struct dentry *dentry = path->dentry; 44662306a36Sopenharmony_ci struct v9fs_session_info *v9ses; 44762306a36Sopenharmony_ci struct p9_fid *fid; 44862306a36Sopenharmony_ci struct inode *inode = d_inode(dentry); 44962306a36Sopenharmony_ci struct p9_stat_dotl *st; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci p9_debug(P9_DEBUG_VFS, "dentry: %p\n", dentry); 45262306a36Sopenharmony_ci v9ses = v9fs_dentry2v9ses(dentry); 45362306a36Sopenharmony_ci if (v9ses->cache & (CACHE_META|CACHE_LOOSE)) { 45462306a36Sopenharmony_ci generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat); 45562306a36Sopenharmony_ci return 0; 45662306a36Sopenharmony_ci } else if (v9ses->cache) { 45762306a36Sopenharmony_ci if (S_ISREG(inode->i_mode)) { 45862306a36Sopenharmony_ci int retval = filemap_fdatawrite(inode->i_mapping); 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci if (retval) 46162306a36Sopenharmony_ci p9_debug(P9_DEBUG_ERROR, 46262306a36Sopenharmony_ci "flushing writeback during getattr returned %d\n", retval); 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci fid = v9fs_fid_lookup(dentry); 46662306a36Sopenharmony_ci if (IS_ERR(fid)) 46762306a36Sopenharmony_ci return PTR_ERR(fid); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci /* Ask for all the fields in stat structure. Server will return 47062306a36Sopenharmony_ci * whatever it supports 47162306a36Sopenharmony_ci */ 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci st = p9_client_getattr_dotl(fid, P9_STATS_ALL); 47462306a36Sopenharmony_ci p9_fid_put(fid); 47562306a36Sopenharmony_ci if (IS_ERR(st)) 47662306a36Sopenharmony_ci return PTR_ERR(st); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci v9fs_stat2inode_dotl(st, d_inode(dentry), 0); 47962306a36Sopenharmony_ci generic_fillattr(&nop_mnt_idmap, request_mask, d_inode(dentry), stat); 48062306a36Sopenharmony_ci /* Change block size to what the server returned */ 48162306a36Sopenharmony_ci stat->blksize = st->st_blksize; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci kfree(st); 48462306a36Sopenharmony_ci return 0; 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci/* 48862306a36Sopenharmony_ci * Attribute flags. 48962306a36Sopenharmony_ci */ 49062306a36Sopenharmony_ci#define P9_ATTR_MODE (1 << 0) 49162306a36Sopenharmony_ci#define P9_ATTR_UID (1 << 1) 49262306a36Sopenharmony_ci#define P9_ATTR_GID (1 << 2) 49362306a36Sopenharmony_ci#define P9_ATTR_SIZE (1 << 3) 49462306a36Sopenharmony_ci#define P9_ATTR_ATIME (1 << 4) 49562306a36Sopenharmony_ci#define P9_ATTR_MTIME (1 << 5) 49662306a36Sopenharmony_ci#define P9_ATTR_CTIME (1 << 6) 49762306a36Sopenharmony_ci#define P9_ATTR_ATIME_SET (1 << 7) 49862306a36Sopenharmony_ci#define P9_ATTR_MTIME_SET (1 << 8) 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cistruct dotl_iattr_map { 50162306a36Sopenharmony_ci int iattr_valid; 50262306a36Sopenharmony_ci int p9_iattr_valid; 50362306a36Sopenharmony_ci}; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_cistatic int v9fs_mapped_iattr_valid(int iattr_valid) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci int i; 50862306a36Sopenharmony_ci int p9_iattr_valid = 0; 50962306a36Sopenharmony_ci struct dotl_iattr_map dotl_iattr_map[] = { 51062306a36Sopenharmony_ci { ATTR_MODE, P9_ATTR_MODE }, 51162306a36Sopenharmony_ci { ATTR_UID, P9_ATTR_UID }, 51262306a36Sopenharmony_ci { ATTR_GID, P9_ATTR_GID }, 51362306a36Sopenharmony_ci { ATTR_SIZE, P9_ATTR_SIZE }, 51462306a36Sopenharmony_ci { ATTR_ATIME, P9_ATTR_ATIME }, 51562306a36Sopenharmony_ci { ATTR_MTIME, P9_ATTR_MTIME }, 51662306a36Sopenharmony_ci { ATTR_CTIME, P9_ATTR_CTIME }, 51762306a36Sopenharmony_ci { ATTR_ATIME_SET, P9_ATTR_ATIME_SET }, 51862306a36Sopenharmony_ci { ATTR_MTIME_SET, P9_ATTR_MTIME_SET }, 51962306a36Sopenharmony_ci }; 52062306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(dotl_iattr_map); i++) { 52162306a36Sopenharmony_ci if (iattr_valid & dotl_iattr_map[i].iattr_valid) 52262306a36Sopenharmony_ci p9_iattr_valid |= dotl_iattr_map[i].p9_iattr_valid; 52362306a36Sopenharmony_ci } 52462306a36Sopenharmony_ci return p9_iattr_valid; 52562306a36Sopenharmony_ci} 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci/** 52862306a36Sopenharmony_ci * v9fs_vfs_setattr_dotl - set file metadata 52962306a36Sopenharmony_ci * @idmap: idmap of the mount 53062306a36Sopenharmony_ci * @dentry: file whose metadata to set 53162306a36Sopenharmony_ci * @iattr: metadata assignment structure 53262306a36Sopenharmony_ci * 53362306a36Sopenharmony_ci */ 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ciint v9fs_vfs_setattr_dotl(struct mnt_idmap *idmap, 53662306a36Sopenharmony_ci struct dentry *dentry, struct iattr *iattr) 53762306a36Sopenharmony_ci{ 53862306a36Sopenharmony_ci int retval, use_dentry = 0; 53962306a36Sopenharmony_ci struct inode *inode = d_inode(dentry); 54062306a36Sopenharmony_ci struct v9fs_session_info __maybe_unused *v9ses; 54162306a36Sopenharmony_ci struct p9_fid *fid = NULL; 54262306a36Sopenharmony_ci struct p9_iattr_dotl p9attr = { 54362306a36Sopenharmony_ci .uid = INVALID_UID, 54462306a36Sopenharmony_ci .gid = INVALID_GID, 54562306a36Sopenharmony_ci }; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci p9_debug(P9_DEBUG_VFS, "\n"); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci retval = setattr_prepare(&nop_mnt_idmap, dentry, iattr); 55062306a36Sopenharmony_ci if (retval) 55162306a36Sopenharmony_ci return retval; 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci v9ses = v9fs_dentry2v9ses(dentry); 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci p9attr.valid = v9fs_mapped_iattr_valid(iattr->ia_valid); 55662306a36Sopenharmony_ci if (iattr->ia_valid & ATTR_MODE) 55762306a36Sopenharmony_ci p9attr.mode = iattr->ia_mode; 55862306a36Sopenharmony_ci if (iattr->ia_valid & ATTR_UID) 55962306a36Sopenharmony_ci p9attr.uid = iattr->ia_uid; 56062306a36Sopenharmony_ci if (iattr->ia_valid & ATTR_GID) 56162306a36Sopenharmony_ci p9attr.gid = iattr->ia_gid; 56262306a36Sopenharmony_ci if (iattr->ia_valid & ATTR_SIZE) 56362306a36Sopenharmony_ci p9attr.size = iattr->ia_size; 56462306a36Sopenharmony_ci if (iattr->ia_valid & ATTR_ATIME_SET) { 56562306a36Sopenharmony_ci p9attr.atime_sec = iattr->ia_atime.tv_sec; 56662306a36Sopenharmony_ci p9attr.atime_nsec = iattr->ia_atime.tv_nsec; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci if (iattr->ia_valid & ATTR_MTIME_SET) { 56962306a36Sopenharmony_ci p9attr.mtime_sec = iattr->ia_mtime.tv_sec; 57062306a36Sopenharmony_ci p9attr.mtime_nsec = iattr->ia_mtime.tv_nsec; 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if (iattr->ia_valid & ATTR_FILE) { 57462306a36Sopenharmony_ci fid = iattr->ia_file->private_data; 57562306a36Sopenharmony_ci WARN_ON(!fid); 57662306a36Sopenharmony_ci } 57762306a36Sopenharmony_ci if (!fid) { 57862306a36Sopenharmony_ci fid = v9fs_fid_lookup(dentry); 57962306a36Sopenharmony_ci use_dentry = 1; 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci if (IS_ERR(fid)) 58262306a36Sopenharmony_ci return PTR_ERR(fid); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci /* Write all dirty data */ 58562306a36Sopenharmony_ci if (S_ISREG(inode->i_mode)) { 58662306a36Sopenharmony_ci retval = filemap_fdatawrite(inode->i_mapping); 58762306a36Sopenharmony_ci if (retval < 0) 58862306a36Sopenharmony_ci p9_debug(P9_DEBUG_ERROR, 58962306a36Sopenharmony_ci "Flushing file prior to setattr failed: %d\n", retval); 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci retval = p9_client_setattr(fid, &p9attr); 59362306a36Sopenharmony_ci if (retval < 0) { 59462306a36Sopenharmony_ci if (use_dentry) 59562306a36Sopenharmony_ci p9_fid_put(fid); 59662306a36Sopenharmony_ci return retval; 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci if ((iattr->ia_valid & ATTR_SIZE) && iattr->ia_size != 60062306a36Sopenharmony_ci i_size_read(inode)) { 60162306a36Sopenharmony_ci truncate_setsize(inode, iattr->ia_size); 60262306a36Sopenharmony_ci truncate_pagecache(inode, iattr->ia_size); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci#ifdef CONFIG_9P_FSCACHE 60562306a36Sopenharmony_ci if (v9ses->cache & CACHE_FSCACHE) 60662306a36Sopenharmony_ci fscache_resize_cookie(v9fs_inode_cookie(V9FS_I(inode)), 60762306a36Sopenharmony_ci iattr->ia_size); 60862306a36Sopenharmony_ci#endif 60962306a36Sopenharmony_ci } 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci v9fs_invalidate_inode_attr(inode); 61262306a36Sopenharmony_ci setattr_copy(&nop_mnt_idmap, inode, iattr); 61362306a36Sopenharmony_ci mark_inode_dirty(inode); 61462306a36Sopenharmony_ci if (iattr->ia_valid & ATTR_MODE) { 61562306a36Sopenharmony_ci /* We also want to update ACL when we update mode bits */ 61662306a36Sopenharmony_ci retval = v9fs_acl_chmod(inode, fid); 61762306a36Sopenharmony_ci if (retval < 0) { 61862306a36Sopenharmony_ci if (use_dentry) 61962306a36Sopenharmony_ci p9_fid_put(fid); 62062306a36Sopenharmony_ci return retval; 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci } 62362306a36Sopenharmony_ci if (use_dentry) 62462306a36Sopenharmony_ci p9_fid_put(fid); 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci return 0; 62762306a36Sopenharmony_ci} 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci/** 63062306a36Sopenharmony_ci * v9fs_stat2inode_dotl - populate an inode structure with stat info 63162306a36Sopenharmony_ci * @stat: stat structure 63262306a36Sopenharmony_ci * @inode: inode to populate 63362306a36Sopenharmony_ci * @flags: ctrl flags (e.g. V9FS_STAT2INODE_KEEP_ISIZE) 63462306a36Sopenharmony_ci * 63562306a36Sopenharmony_ci */ 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_civoid 63862306a36Sopenharmony_civ9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode, 63962306a36Sopenharmony_ci unsigned int flags) 64062306a36Sopenharmony_ci{ 64162306a36Sopenharmony_ci umode_t mode; 64262306a36Sopenharmony_ci struct v9fs_inode *v9inode = V9FS_I(inode); 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci if ((stat->st_result_mask & P9_STATS_BASIC) == P9_STATS_BASIC) { 64562306a36Sopenharmony_ci inode->i_atime.tv_sec = stat->st_atime_sec; 64662306a36Sopenharmony_ci inode->i_atime.tv_nsec = stat->st_atime_nsec; 64762306a36Sopenharmony_ci inode->i_mtime.tv_sec = stat->st_mtime_sec; 64862306a36Sopenharmony_ci inode->i_mtime.tv_nsec = stat->st_mtime_nsec; 64962306a36Sopenharmony_ci inode_set_ctime(inode, stat->st_ctime_sec, 65062306a36Sopenharmony_ci stat->st_ctime_nsec); 65162306a36Sopenharmony_ci inode->i_uid = stat->st_uid; 65262306a36Sopenharmony_ci inode->i_gid = stat->st_gid; 65362306a36Sopenharmony_ci set_nlink(inode, stat->st_nlink); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci mode = stat->st_mode & S_IALLUGO; 65662306a36Sopenharmony_ci mode |= inode->i_mode & ~S_IALLUGO; 65762306a36Sopenharmony_ci inode->i_mode = mode; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci if (!(flags & V9FS_STAT2INODE_KEEP_ISIZE)) 66062306a36Sopenharmony_ci v9fs_i_size_write(inode, stat->st_size); 66162306a36Sopenharmony_ci inode->i_blocks = stat->st_blocks; 66262306a36Sopenharmony_ci } else { 66362306a36Sopenharmony_ci if (stat->st_result_mask & P9_STATS_ATIME) { 66462306a36Sopenharmony_ci inode->i_atime.tv_sec = stat->st_atime_sec; 66562306a36Sopenharmony_ci inode->i_atime.tv_nsec = stat->st_atime_nsec; 66662306a36Sopenharmony_ci } 66762306a36Sopenharmony_ci if (stat->st_result_mask & P9_STATS_MTIME) { 66862306a36Sopenharmony_ci inode->i_mtime.tv_sec = stat->st_mtime_sec; 66962306a36Sopenharmony_ci inode->i_mtime.tv_nsec = stat->st_mtime_nsec; 67062306a36Sopenharmony_ci } 67162306a36Sopenharmony_ci if (stat->st_result_mask & P9_STATS_CTIME) { 67262306a36Sopenharmony_ci inode_set_ctime(inode, stat->st_ctime_sec, 67362306a36Sopenharmony_ci stat->st_ctime_nsec); 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci if (stat->st_result_mask & P9_STATS_UID) 67662306a36Sopenharmony_ci inode->i_uid = stat->st_uid; 67762306a36Sopenharmony_ci if (stat->st_result_mask & P9_STATS_GID) 67862306a36Sopenharmony_ci inode->i_gid = stat->st_gid; 67962306a36Sopenharmony_ci if (stat->st_result_mask & P9_STATS_NLINK) 68062306a36Sopenharmony_ci set_nlink(inode, stat->st_nlink); 68162306a36Sopenharmony_ci if (stat->st_result_mask & P9_STATS_MODE) { 68262306a36Sopenharmony_ci mode = stat->st_mode & S_IALLUGO; 68362306a36Sopenharmony_ci mode |= inode->i_mode & ~S_IALLUGO; 68462306a36Sopenharmony_ci inode->i_mode = mode; 68562306a36Sopenharmony_ci } 68662306a36Sopenharmony_ci if (!(flags & V9FS_STAT2INODE_KEEP_ISIZE) && 68762306a36Sopenharmony_ci stat->st_result_mask & P9_STATS_SIZE) 68862306a36Sopenharmony_ci v9fs_i_size_write(inode, stat->st_size); 68962306a36Sopenharmony_ci if (stat->st_result_mask & P9_STATS_BLOCKS) 69062306a36Sopenharmony_ci inode->i_blocks = stat->st_blocks; 69162306a36Sopenharmony_ci } 69262306a36Sopenharmony_ci if (stat->st_result_mask & P9_STATS_GEN) 69362306a36Sopenharmony_ci inode->i_generation = stat->st_gen; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci /* Currently we don't support P9_STATS_BTIME and P9_STATS_DATA_VERSION 69662306a36Sopenharmony_ci * because the inode structure does not have fields for them. 69762306a36Sopenharmony_ci */ 69862306a36Sopenharmony_ci v9inode->cache_validity &= ~V9FS_INO_INVALID_ATTR; 69962306a36Sopenharmony_ci} 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_cistatic int 70262306a36Sopenharmony_civ9fs_vfs_symlink_dotl(struct mnt_idmap *idmap, struct inode *dir, 70362306a36Sopenharmony_ci struct dentry *dentry, const char *symname) 70462306a36Sopenharmony_ci{ 70562306a36Sopenharmony_ci int err; 70662306a36Sopenharmony_ci kgid_t gid; 70762306a36Sopenharmony_ci const unsigned char *name; 70862306a36Sopenharmony_ci struct p9_qid qid; 70962306a36Sopenharmony_ci struct inode *inode; 71062306a36Sopenharmony_ci struct p9_fid *dfid; 71162306a36Sopenharmony_ci struct p9_fid *fid = NULL; 71262306a36Sopenharmony_ci struct v9fs_session_info *v9ses; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci name = dentry->d_name.name; 71562306a36Sopenharmony_ci p9_debug(P9_DEBUG_VFS, "%lu,%s,%s\n", dir->i_ino, name, symname); 71662306a36Sopenharmony_ci v9ses = v9fs_inode2v9ses(dir); 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci dfid = v9fs_parent_fid(dentry); 71962306a36Sopenharmony_ci if (IS_ERR(dfid)) { 72062306a36Sopenharmony_ci err = PTR_ERR(dfid); 72162306a36Sopenharmony_ci p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err); 72262306a36Sopenharmony_ci return err; 72362306a36Sopenharmony_ci } 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci gid = v9fs_get_fsgid_for_create(dir); 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci /* Server doesn't alter fid on TSYMLINK. Hence no need to clone it. */ 72862306a36Sopenharmony_ci err = p9_client_symlink(dfid, name, symname, gid, &qid); 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci if (err < 0) { 73162306a36Sopenharmony_ci p9_debug(P9_DEBUG_VFS, "p9_client_symlink failed %d\n", err); 73262306a36Sopenharmony_ci goto error; 73362306a36Sopenharmony_ci } 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci v9fs_invalidate_inode_attr(dir); 73662306a36Sopenharmony_ci if (v9ses->cache & (CACHE_META|CACHE_LOOSE)) { 73762306a36Sopenharmony_ci /* Now walk from the parent so we can get an unopened fid. */ 73862306a36Sopenharmony_ci fid = p9_client_walk(dfid, 1, &name, 1); 73962306a36Sopenharmony_ci if (IS_ERR(fid)) { 74062306a36Sopenharmony_ci err = PTR_ERR(fid); 74162306a36Sopenharmony_ci p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", 74262306a36Sopenharmony_ci err); 74362306a36Sopenharmony_ci goto error; 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci /* instantiate inode and assign the unopened fid to dentry */ 74762306a36Sopenharmony_ci inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb); 74862306a36Sopenharmony_ci if (IS_ERR(inode)) { 74962306a36Sopenharmony_ci err = PTR_ERR(inode); 75062306a36Sopenharmony_ci p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n", 75162306a36Sopenharmony_ci err); 75262306a36Sopenharmony_ci goto error; 75362306a36Sopenharmony_ci } 75462306a36Sopenharmony_ci v9fs_fid_add(dentry, &fid); 75562306a36Sopenharmony_ci d_instantiate(dentry, inode); 75662306a36Sopenharmony_ci err = 0; 75762306a36Sopenharmony_ci } else { 75862306a36Sopenharmony_ci /* Not in cached mode. No need to populate inode with stat */ 75962306a36Sopenharmony_ci inode = v9fs_get_inode(dir->i_sb, S_IFLNK, 0); 76062306a36Sopenharmony_ci if (IS_ERR(inode)) { 76162306a36Sopenharmony_ci err = PTR_ERR(inode); 76262306a36Sopenharmony_ci goto error; 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci d_instantiate(dentry, inode); 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_cierror: 76862306a36Sopenharmony_ci p9_fid_put(fid); 76962306a36Sopenharmony_ci p9_fid_put(dfid); 77062306a36Sopenharmony_ci return err; 77162306a36Sopenharmony_ci} 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci/** 77462306a36Sopenharmony_ci * v9fs_vfs_link_dotl - create a hardlink for dotl 77562306a36Sopenharmony_ci * @old_dentry: dentry for file to link to 77662306a36Sopenharmony_ci * @dir: inode destination for new link 77762306a36Sopenharmony_ci * @dentry: dentry for link 77862306a36Sopenharmony_ci * 77962306a36Sopenharmony_ci */ 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_cistatic int 78262306a36Sopenharmony_civ9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir, 78362306a36Sopenharmony_ci struct dentry *dentry) 78462306a36Sopenharmony_ci{ 78562306a36Sopenharmony_ci int err; 78662306a36Sopenharmony_ci struct p9_fid *dfid, *oldfid; 78762306a36Sopenharmony_ci struct v9fs_session_info *v9ses; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci p9_debug(P9_DEBUG_VFS, "dir ino: %lu, old_name: %pd, new_name: %pd\n", 79062306a36Sopenharmony_ci dir->i_ino, old_dentry, dentry); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci v9ses = v9fs_inode2v9ses(dir); 79362306a36Sopenharmony_ci dfid = v9fs_parent_fid(dentry); 79462306a36Sopenharmony_ci if (IS_ERR(dfid)) 79562306a36Sopenharmony_ci return PTR_ERR(dfid); 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci oldfid = v9fs_fid_lookup(old_dentry); 79862306a36Sopenharmony_ci if (IS_ERR(oldfid)) { 79962306a36Sopenharmony_ci p9_fid_put(dfid); 80062306a36Sopenharmony_ci return PTR_ERR(oldfid); 80162306a36Sopenharmony_ci } 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci err = p9_client_link(dfid, oldfid, dentry->d_name.name); 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci p9_fid_put(dfid); 80662306a36Sopenharmony_ci p9_fid_put(oldfid); 80762306a36Sopenharmony_ci if (err < 0) { 80862306a36Sopenharmony_ci p9_debug(P9_DEBUG_VFS, "p9_client_link failed %d\n", err); 80962306a36Sopenharmony_ci return err; 81062306a36Sopenharmony_ci } 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci v9fs_invalidate_inode_attr(dir); 81362306a36Sopenharmony_ci if (v9ses->cache & (CACHE_META|CACHE_LOOSE)) { 81462306a36Sopenharmony_ci /* Get the latest stat info from server. */ 81562306a36Sopenharmony_ci struct p9_fid *fid; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci fid = v9fs_fid_lookup(old_dentry); 81862306a36Sopenharmony_ci if (IS_ERR(fid)) 81962306a36Sopenharmony_ci return PTR_ERR(fid); 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci v9fs_refresh_inode_dotl(fid, d_inode(old_dentry)); 82262306a36Sopenharmony_ci p9_fid_put(fid); 82362306a36Sopenharmony_ci } 82462306a36Sopenharmony_ci ihold(d_inode(old_dentry)); 82562306a36Sopenharmony_ci d_instantiate(dentry, d_inode(old_dentry)); 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci return err; 82862306a36Sopenharmony_ci} 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci/** 83162306a36Sopenharmony_ci * v9fs_vfs_mknod_dotl - create a special file 83262306a36Sopenharmony_ci * @idmap: The idmap of the mount 83362306a36Sopenharmony_ci * @dir: inode destination for new link 83462306a36Sopenharmony_ci * @dentry: dentry for file 83562306a36Sopenharmony_ci * @omode: mode for creation 83662306a36Sopenharmony_ci * @rdev: device associated with special file 83762306a36Sopenharmony_ci * 83862306a36Sopenharmony_ci */ 83962306a36Sopenharmony_cistatic int 84062306a36Sopenharmony_civ9fs_vfs_mknod_dotl(struct mnt_idmap *idmap, struct inode *dir, 84162306a36Sopenharmony_ci struct dentry *dentry, umode_t omode, dev_t rdev) 84262306a36Sopenharmony_ci{ 84362306a36Sopenharmony_ci int err; 84462306a36Sopenharmony_ci kgid_t gid; 84562306a36Sopenharmony_ci const unsigned char *name; 84662306a36Sopenharmony_ci umode_t mode; 84762306a36Sopenharmony_ci struct v9fs_session_info *v9ses; 84862306a36Sopenharmony_ci struct p9_fid *fid = NULL, *dfid = NULL; 84962306a36Sopenharmony_ci struct inode *inode; 85062306a36Sopenharmony_ci struct p9_qid qid; 85162306a36Sopenharmony_ci struct posix_acl *dacl = NULL, *pacl = NULL; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci p9_debug(P9_DEBUG_VFS, " %lu,%pd mode: %x MAJOR: %u MINOR: %u\n", 85462306a36Sopenharmony_ci dir->i_ino, dentry, omode, 85562306a36Sopenharmony_ci MAJOR(rdev), MINOR(rdev)); 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci v9ses = v9fs_inode2v9ses(dir); 85862306a36Sopenharmony_ci dfid = v9fs_parent_fid(dentry); 85962306a36Sopenharmony_ci if (IS_ERR(dfid)) { 86062306a36Sopenharmony_ci err = PTR_ERR(dfid); 86162306a36Sopenharmony_ci p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err); 86262306a36Sopenharmony_ci goto error; 86362306a36Sopenharmony_ci } 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci gid = v9fs_get_fsgid_for_create(dir); 86662306a36Sopenharmony_ci mode = omode; 86762306a36Sopenharmony_ci /* Update mode based on ACL value */ 86862306a36Sopenharmony_ci err = v9fs_acl_mode(dir, &mode, &dacl, &pacl); 86962306a36Sopenharmony_ci if (err) { 87062306a36Sopenharmony_ci p9_debug(P9_DEBUG_VFS, "Failed to get acl values in mknod %d\n", 87162306a36Sopenharmony_ci err); 87262306a36Sopenharmony_ci goto error; 87362306a36Sopenharmony_ci } 87462306a36Sopenharmony_ci name = dentry->d_name.name; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci err = p9_client_mknod_dotl(dfid, name, mode, rdev, gid, &qid); 87762306a36Sopenharmony_ci if (err < 0) 87862306a36Sopenharmony_ci goto error; 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci v9fs_invalidate_inode_attr(dir); 88162306a36Sopenharmony_ci fid = p9_client_walk(dfid, 1, &name, 1); 88262306a36Sopenharmony_ci if (IS_ERR(fid)) { 88362306a36Sopenharmony_ci err = PTR_ERR(fid); 88462306a36Sopenharmony_ci p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", 88562306a36Sopenharmony_ci err); 88662306a36Sopenharmony_ci goto error; 88762306a36Sopenharmony_ci } 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci /* instantiate inode and assign the unopened fid to the dentry */ 89062306a36Sopenharmony_ci if (v9ses->cache & (CACHE_META|CACHE_LOOSE)) { 89162306a36Sopenharmony_ci inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb); 89262306a36Sopenharmony_ci if (IS_ERR(inode)) { 89362306a36Sopenharmony_ci err = PTR_ERR(inode); 89462306a36Sopenharmony_ci p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n", 89562306a36Sopenharmony_ci err); 89662306a36Sopenharmony_ci goto error; 89762306a36Sopenharmony_ci } 89862306a36Sopenharmony_ci v9fs_set_create_acl(inode, fid, dacl, pacl); 89962306a36Sopenharmony_ci v9fs_fid_add(dentry, &fid); 90062306a36Sopenharmony_ci d_instantiate(dentry, inode); 90162306a36Sopenharmony_ci err = 0; 90262306a36Sopenharmony_ci } else { 90362306a36Sopenharmony_ci /* 90462306a36Sopenharmony_ci * Not in cached mode. No need to populate inode with stat. 90562306a36Sopenharmony_ci * socket syscall returns a fd, so we need instantiate 90662306a36Sopenharmony_ci */ 90762306a36Sopenharmony_ci inode = v9fs_get_inode(dir->i_sb, mode, rdev); 90862306a36Sopenharmony_ci if (IS_ERR(inode)) { 90962306a36Sopenharmony_ci err = PTR_ERR(inode); 91062306a36Sopenharmony_ci goto error; 91162306a36Sopenharmony_ci } 91262306a36Sopenharmony_ci v9fs_set_create_acl(inode, fid, dacl, pacl); 91362306a36Sopenharmony_ci d_instantiate(dentry, inode); 91462306a36Sopenharmony_ci } 91562306a36Sopenharmony_cierror: 91662306a36Sopenharmony_ci p9_fid_put(fid); 91762306a36Sopenharmony_ci v9fs_put_acl(dacl, pacl); 91862306a36Sopenharmony_ci p9_fid_put(dfid); 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci return err; 92162306a36Sopenharmony_ci} 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci/** 92462306a36Sopenharmony_ci * v9fs_vfs_get_link_dotl - follow a symlink path 92562306a36Sopenharmony_ci * @dentry: dentry for symlink 92662306a36Sopenharmony_ci * @inode: inode for symlink 92762306a36Sopenharmony_ci * @done: destructor for return value 92862306a36Sopenharmony_ci */ 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_cistatic const char * 93162306a36Sopenharmony_civ9fs_vfs_get_link_dotl(struct dentry *dentry, 93262306a36Sopenharmony_ci struct inode *inode, 93362306a36Sopenharmony_ci struct delayed_call *done) 93462306a36Sopenharmony_ci{ 93562306a36Sopenharmony_ci struct p9_fid *fid; 93662306a36Sopenharmony_ci char *target; 93762306a36Sopenharmony_ci int retval; 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci if (!dentry) 94062306a36Sopenharmony_ci return ERR_PTR(-ECHILD); 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci p9_debug(P9_DEBUG_VFS, "%pd\n", dentry); 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci fid = v9fs_fid_lookup(dentry); 94562306a36Sopenharmony_ci if (IS_ERR(fid)) 94662306a36Sopenharmony_ci return ERR_CAST(fid); 94762306a36Sopenharmony_ci retval = p9_client_readlink(fid, &target); 94862306a36Sopenharmony_ci p9_fid_put(fid); 94962306a36Sopenharmony_ci if (retval) 95062306a36Sopenharmony_ci return ERR_PTR(retval); 95162306a36Sopenharmony_ci set_delayed_call(done, kfree_link, target); 95262306a36Sopenharmony_ci return target; 95362306a36Sopenharmony_ci} 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ciint v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode) 95662306a36Sopenharmony_ci{ 95762306a36Sopenharmony_ci struct p9_stat_dotl *st; 95862306a36Sopenharmony_ci struct v9fs_session_info *v9ses; 95962306a36Sopenharmony_ci unsigned int flags; 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci v9ses = v9fs_inode2v9ses(inode); 96262306a36Sopenharmony_ci st = p9_client_getattr_dotl(fid, P9_STATS_ALL); 96362306a36Sopenharmony_ci if (IS_ERR(st)) 96462306a36Sopenharmony_ci return PTR_ERR(st); 96562306a36Sopenharmony_ci /* 96662306a36Sopenharmony_ci * Don't update inode if the file type is different 96762306a36Sopenharmony_ci */ 96862306a36Sopenharmony_ci if (inode_wrong_type(inode, st->st_mode)) 96962306a36Sopenharmony_ci goto out; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci /* 97262306a36Sopenharmony_ci * We don't want to refresh inode->i_size, 97362306a36Sopenharmony_ci * because we may have cached data 97462306a36Sopenharmony_ci */ 97562306a36Sopenharmony_ci flags = (v9ses->cache & CACHE_LOOSE) ? 97662306a36Sopenharmony_ci V9FS_STAT2INODE_KEEP_ISIZE : 0; 97762306a36Sopenharmony_ci v9fs_stat2inode_dotl(st, inode, flags); 97862306a36Sopenharmony_ciout: 97962306a36Sopenharmony_ci kfree(st); 98062306a36Sopenharmony_ci return 0; 98162306a36Sopenharmony_ci} 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ciconst struct inode_operations v9fs_dir_inode_operations_dotl = { 98462306a36Sopenharmony_ci .create = v9fs_vfs_create_dotl, 98562306a36Sopenharmony_ci .atomic_open = v9fs_vfs_atomic_open_dotl, 98662306a36Sopenharmony_ci .lookup = v9fs_vfs_lookup, 98762306a36Sopenharmony_ci .link = v9fs_vfs_link_dotl, 98862306a36Sopenharmony_ci .symlink = v9fs_vfs_symlink_dotl, 98962306a36Sopenharmony_ci .unlink = v9fs_vfs_unlink, 99062306a36Sopenharmony_ci .mkdir = v9fs_vfs_mkdir_dotl, 99162306a36Sopenharmony_ci .rmdir = v9fs_vfs_rmdir, 99262306a36Sopenharmony_ci .mknod = v9fs_vfs_mknod_dotl, 99362306a36Sopenharmony_ci .rename = v9fs_vfs_rename, 99462306a36Sopenharmony_ci .getattr = v9fs_vfs_getattr_dotl, 99562306a36Sopenharmony_ci .setattr = v9fs_vfs_setattr_dotl, 99662306a36Sopenharmony_ci .listxattr = v9fs_listxattr, 99762306a36Sopenharmony_ci .get_inode_acl = v9fs_iop_get_inode_acl, 99862306a36Sopenharmony_ci .get_acl = v9fs_iop_get_acl, 99962306a36Sopenharmony_ci .set_acl = v9fs_iop_set_acl, 100062306a36Sopenharmony_ci}; 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ciconst struct inode_operations v9fs_file_inode_operations_dotl = { 100362306a36Sopenharmony_ci .getattr = v9fs_vfs_getattr_dotl, 100462306a36Sopenharmony_ci .setattr = v9fs_vfs_setattr_dotl, 100562306a36Sopenharmony_ci .listxattr = v9fs_listxattr, 100662306a36Sopenharmony_ci .get_inode_acl = v9fs_iop_get_inode_acl, 100762306a36Sopenharmony_ci .get_acl = v9fs_iop_get_acl, 100862306a36Sopenharmony_ci .set_acl = v9fs_iop_set_acl, 100962306a36Sopenharmony_ci}; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ciconst struct inode_operations v9fs_symlink_inode_operations_dotl = { 101262306a36Sopenharmony_ci .get_link = v9fs_vfs_get_link_dotl, 101362306a36Sopenharmony_ci .getattr = v9fs_vfs_getattr_dotl, 101462306a36Sopenharmony_ci .setattr = v9fs_vfs_setattr_dotl, 101562306a36Sopenharmony_ci .listxattr = v9fs_listxattr, 101662306a36Sopenharmony_ci}; 1017