| 1 | // SPDX-License-Identifier: GPL-2.0-only | 
|---|
| 2 | /* | 
|---|
| 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 |  | 
|---|
| 31 | static int | 
|---|
| 32 | v9fs_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 object | 
|---|
| 37 | * @dir_inode: The directory inode | 
|---|
| 38 | * | 
|---|
| 39 | * Helper function to get the gid for creating a | 
|---|
| 40 | * new file system object. This checks the S_ISGID to determine the owning | 
|---|
| 41 | * group of the new file system object. | 
|---|
| 42 | */ | 
|---|
| 43 |  | 
|---|
| 44 | static 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 |  | 
|---|
| 55 | static 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, mode: 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 */ | 
|---|
| 81 | static int v9fs_test_new_inode_dotl(struct inode *inode, void *data) | 
|---|
| 82 | { | 
|---|
| 83 | return 0; | 
|---|
| 84 | } | 
|---|
| 85 |  | 
|---|
| 86 | static 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(to: &v9inode->qid, from: &st->qid, len: sizeof(st->qid)); | 
|---|
| 92 | inode->i_generation = st->st_gen; | 
|---|
| 93 | return 0; | 
|---|
| 94 | } | 
|---|
| 95 |  | 
|---|
| 96 | static 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 | else | 
|---|
| 110 | test = v9fs_test_inode_dotl; | 
|---|
| 111 |  | 
|---|
| 112 | inode = iget5_locked(sb, QID2INO(qid), test, set: v9fs_set_inode_dotl, st); | 
|---|
| 113 | if (!inode) | 
|---|
| 114 | return ERR_PTR(error: -ENOMEM); | 
|---|
| 115 | if (!(inode->i_state & I_NEW)) | 
|---|
| 116 | return inode; | 
|---|
| 117 | /* | 
|---|
| 118 | * initialize the inode with the stat info | 
|---|
| 119 | * FIXME!! we may need support for stale inodes | 
|---|
| 120 | * later. | 
|---|
| 121 | */ | 
|---|
| 122 | inode->i_ino = QID2INO(qid); | 
|---|
| 123 | retval = v9fs_init_inode(v9ses, inode, | 
|---|
| 124 | mode: st->st_mode, rdev: new_decode_dev(dev: st->st_rdev)); | 
|---|
| 125 | if (retval) | 
|---|
| 126 | goto error; | 
|---|
| 127 |  | 
|---|
| 128 | v9fs_stat2inode_dotl(stat: st, inode, flags: 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; | 
|---|
| 137 | error: | 
|---|
| 138 | iget_failed(inode); | 
|---|
| 139 | return ERR_PTR(error: retval); | 
|---|
| 140 |  | 
|---|
| 141 | } | 
|---|
| 142 |  | 
|---|
| 143 | struct inode * | 
|---|
| 144 | v9fs_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(ptr: st)) | 
|---|
| 152 | return ERR_CAST(ptr: st); | 
|---|
| 153 |  | 
|---|
| 154 | inode = v9fs_qid_iget_dotl(sb, qid: &st->qid, fid, st, new); | 
|---|
| 155 | kfree(objp: st); | 
|---|
| 156 | return inode; | 
|---|
| 157 | } | 
|---|
| 158 |  | 
|---|
| 159 | struct dotl_openflag_map { | 
|---|
| 160 | int open_flag; | 
|---|
| 161 | int dotl_flag; | 
|---|
| 162 | }; | 
|---|
| 163 |  | 
|---|
| 164 | static 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 to | 
|---|
| 193 | * plan 9 open flag. | 
|---|
| 194 | * @flags: flags to convert | 
|---|
| 195 | */ | 
|---|
| 196 | int 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_WRONLY | 
|---|
| 202 | * and P9_DOTL_NOACCESS | 
|---|
| 203 | */ | 
|---|
| 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 mount | 
|---|
| 213 | * @dir: directory inode that is being created | 
|---|
| 214 | * @dentry:  dentry that is being deleted | 
|---|
| 215 | * @omode: create permissions | 
|---|
| 216 | * @excl: True if the file must not yet exist | 
|---|
| 217 | * | 
|---|
| 218 | */ | 
|---|
| 219 | static int | 
|---|
| 220 | v9fs_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, rdev: 0); | 
|---|
| 224 | } | 
|---|
| 225 |  | 
|---|
| 226 | static int | 
|---|
| 227 | v9fs_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 |  | 
|---|
| 242 | if (d_in_lookup(dentry)) { | 
|---|
| 243 | struct dentry *res = v9fs_vfs_lookup(dir, dentry, flags: 0); | 
|---|
| 244 | if (res || d_really_is_positive(dentry)) | 
|---|
| 245 | return	finish_no_open(file, dentry: res); | 
|---|
| 246 | } | 
|---|
| 247 |  | 
|---|
| 248 | /* Only creates */ | 
|---|
| 249 | if (!(flags & O_CREAT)) | 
|---|
| 250 | return	finish_no_open(file, NULL); | 
|---|
| 251 |  | 
|---|
| 252 | v9ses = v9fs_inode2v9ses(inode: dir); | 
|---|
| 253 |  | 
|---|
| 254 | name = dentry->d_name.name; | 
|---|
| 255 | p9_debug(P9_DEBUG_VFS, "name:%s flags:0x%x mode:0x%x\n", | 
|---|
| 256 | name, flags, omode); | 
|---|
| 257 |  | 
|---|
| 258 | dfid = v9fs_parent_fid(dentry); | 
|---|
| 259 | if (IS_ERR(ptr: dfid)) { | 
|---|
| 260 | err = PTR_ERR(ptr: dfid); | 
|---|
| 261 | p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err); | 
|---|
| 262 | goto out; | 
|---|
| 263 | } | 
|---|
| 264 |  | 
|---|
| 265 | /* clone a fid to use for creation */ | 
|---|
| 266 | ofid = clone_fid(fid: dfid); | 
|---|
| 267 | if (IS_ERR(ptr: ofid)) { | 
|---|
| 268 | err = PTR_ERR(ptr: ofid); | 
|---|
| 269 | p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err); | 
|---|
| 270 | goto out; | 
|---|
| 271 | } | 
|---|
| 272 |  | 
|---|
| 273 | gid = v9fs_get_fsgid_for_create(dir_inode: dir); | 
|---|
| 274 |  | 
|---|
| 275 | mode = omode; | 
|---|
| 276 | /* Update mode based on ACL value */ | 
|---|
| 277 | err = v9fs_acl_mode(dir, modep: &mode, dpacl: &dacl, pacl: &pacl); | 
|---|
| 278 | if (err) { | 
|---|
| 279 | p9_debug(P9_DEBUG_VFS, "Failed to get acl values in create %d\n", | 
|---|
| 280 | err); | 
|---|
| 281 | goto out; | 
|---|
| 282 | } | 
|---|
| 283 |  | 
|---|
| 284 | if ((v9ses->cache & CACHE_WRITEBACK) && (p9_omode & P9_OWRITE)) { | 
|---|
| 285 | p9_omode = (p9_omode & ~P9_OWRITE) | P9_ORDWR; | 
|---|
| 286 | p9_debug(P9_DEBUG_CACHE, | 
|---|
| 287 | "write-only file with writeback enabled, creating w/ O_RDWR\n"); | 
|---|
| 288 | } | 
|---|
| 289 | err = p9_client_create_dotl(ofid, name, flags: p9_omode, mode, gid, qid: &qid); | 
|---|
| 290 | if (err < 0) { | 
|---|
| 291 | p9_debug(P9_DEBUG_VFS, "p9_client_open_dotl failed in create %d\n", | 
|---|
| 292 | err); | 
|---|
| 293 | goto out; | 
|---|
| 294 | } | 
|---|
| 295 | v9fs_invalidate_inode_attr(inode: dir); | 
|---|
| 296 |  | 
|---|
| 297 | /* instantiate inode and assign the unopened fid to the dentry */ | 
|---|
| 298 | fid = p9_client_walk(oldfid: dfid, nwname: 1, wnames: &name, clone: 1); | 
|---|
| 299 | if (IS_ERR(ptr: fid)) { | 
|---|
| 300 | err = PTR_ERR(ptr: fid); | 
|---|
| 301 | p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err); | 
|---|
| 302 | goto out; | 
|---|
| 303 | } | 
|---|
| 304 | inode = v9fs_get_new_inode_from_fid(v9ses, fid, sb: dir->i_sb); | 
|---|
| 305 | if (IS_ERR(ptr: inode)) { | 
|---|
| 306 | err = PTR_ERR(ptr: inode); | 
|---|
| 307 | p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n", err); | 
|---|
| 308 | goto out; | 
|---|
| 309 | } | 
|---|
| 310 | /* Now set the ACL based on the default value */ | 
|---|
| 311 | v9fs_set_create_acl(inode, fid, dacl, acl: pacl); | 
|---|
| 312 |  | 
|---|
| 313 | v9fs_fid_add(dentry, fid: &fid); | 
|---|
| 314 | d_instantiate(dentry, inode); | 
|---|
| 315 |  | 
|---|
| 316 | /* Since we are opening a file, assign the open fid to the file */ | 
|---|
| 317 | err = finish_open(file, dentry, open: generic_file_open); | 
|---|
| 318 | if (err) | 
|---|
| 319 | goto out; | 
|---|
| 320 | file->private_data = ofid; | 
|---|
| 321 | #ifdef CONFIG_9P_FSCACHE | 
|---|
| 322 | if (v9ses->cache & CACHE_FSCACHE) { | 
|---|
| 323 | struct v9fs_inode *v9inode = V9FS_I(inode); | 
|---|
| 324 | fscache_use_cookie(v9fs_inode_cookie(v9inode), | 
|---|
| 325 | file->f_mode & FMODE_WRITE); | 
|---|
| 326 | } | 
|---|
| 327 | #endif | 
|---|
| 328 | v9fs_fid_add_modes(fid: ofid, s_flags: v9ses->flags, s_cache: v9ses->cache, f_flags: flags); | 
|---|
| 329 | v9fs_open_fid_add(inode, fid: &ofid); | 
|---|
| 330 | file->f_mode |= FMODE_CREATED; | 
|---|
| 331 | out: | 
|---|
| 332 | p9_fid_put(fid: dfid); | 
|---|
| 333 | p9_fid_put(fid: ofid); | 
|---|
| 334 | p9_fid_put(fid); | 
|---|
| 335 | v9fs_put_acl(dacl, acl: pacl); | 
|---|
| 336 | return err; | 
|---|
| 337 | } | 
|---|
| 338 |  | 
|---|
| 339 | /** | 
|---|
| 340 | * v9fs_vfs_mkdir_dotl - VFS mkdir hook to create a directory | 
|---|
| 341 | * @idmap: The idmap of the mount | 
|---|
| 342 | * @dir:  inode that is being unlinked | 
|---|
| 343 | * @dentry: dentry that is being unlinked | 
|---|
| 344 | * @omode: mode for new directory | 
|---|
| 345 | * | 
|---|
| 346 | */ | 
|---|
| 347 |  | 
|---|
| 348 | static struct dentry *v9fs_vfs_mkdir_dotl(struct mnt_idmap *idmap, | 
|---|
| 349 | struct inode *dir, struct dentry *dentry, | 
|---|
| 350 | umode_t omode) | 
|---|
| 351 | { | 
|---|
| 352 | int err; | 
|---|
| 353 | struct v9fs_session_info *v9ses; | 
|---|
| 354 | struct p9_fid *fid = NULL, *dfid = NULL; | 
|---|
| 355 | kgid_t gid; | 
|---|
| 356 | const unsigned char *name; | 
|---|
| 357 | umode_t mode; | 
|---|
| 358 | struct inode *inode; | 
|---|
| 359 | struct p9_qid qid; | 
|---|
| 360 | struct posix_acl *dacl = NULL, *pacl = NULL; | 
|---|
| 361 |  | 
|---|
| 362 | p9_debug(P9_DEBUG_VFS, "name %pd\n", dentry); | 
|---|
| 363 | v9ses = v9fs_inode2v9ses(inode: dir); | 
|---|
| 364 |  | 
|---|
| 365 | omode |= S_IFDIR; | 
|---|
| 366 | if (dir->i_mode & S_ISGID) | 
|---|
| 367 | omode |= S_ISGID; | 
|---|
| 368 |  | 
|---|
| 369 | dfid = v9fs_parent_fid(dentry); | 
|---|
| 370 | if (IS_ERR(ptr: dfid)) { | 
|---|
| 371 | err = PTR_ERR(ptr: dfid); | 
|---|
| 372 | p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err); | 
|---|
| 373 | goto error; | 
|---|
| 374 | } | 
|---|
| 375 |  | 
|---|
| 376 | gid = v9fs_get_fsgid_for_create(dir_inode: dir); | 
|---|
| 377 | mode = omode; | 
|---|
| 378 | /* Update mode based on ACL value */ | 
|---|
| 379 | err = v9fs_acl_mode(dir, modep: &mode, dpacl: &dacl, pacl: &pacl); | 
|---|
| 380 | if (err) { | 
|---|
| 381 | p9_debug(P9_DEBUG_VFS, "Failed to get acl values in mkdir %d\n", | 
|---|
| 382 | err); | 
|---|
| 383 | goto error; | 
|---|
| 384 | } | 
|---|
| 385 | name = dentry->d_name.name; | 
|---|
| 386 | err = p9_client_mkdir_dotl(fid: dfid, name, mode, gid, qid: &qid); | 
|---|
| 387 | if (err < 0) | 
|---|
| 388 | goto error; | 
|---|
| 389 | fid = p9_client_walk(oldfid: dfid, nwname: 1, wnames: &name, clone: 1); | 
|---|
| 390 | if (IS_ERR(ptr: fid)) { | 
|---|
| 391 | err = PTR_ERR(ptr: fid); | 
|---|
| 392 | p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", | 
|---|
| 393 | err); | 
|---|
| 394 | goto error; | 
|---|
| 395 | } | 
|---|
| 396 |  | 
|---|
| 397 | /* instantiate inode and assign the unopened fid to the dentry */ | 
|---|
| 398 | inode = v9fs_get_new_inode_from_fid(v9ses, fid, sb: dir->i_sb); | 
|---|
| 399 | if (IS_ERR(ptr: inode)) { | 
|---|
| 400 | err = PTR_ERR(ptr: inode); | 
|---|
| 401 | p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n", | 
|---|
| 402 | err); | 
|---|
| 403 | goto error; | 
|---|
| 404 | } | 
|---|
| 405 | v9fs_set_create_acl(inode, fid, dacl, acl: pacl); | 
|---|
| 406 | v9fs_fid_add(dentry, fid: &fid); | 
|---|
| 407 | d_instantiate(dentry, inode); | 
|---|
| 408 | err = 0; | 
|---|
| 409 | inc_nlink(inode: dir); | 
|---|
| 410 | v9fs_invalidate_inode_attr(inode: dir); | 
|---|
| 411 | error: | 
|---|
| 412 | p9_fid_put(fid); | 
|---|
| 413 | v9fs_put_acl(dacl, acl: pacl); | 
|---|
| 414 | p9_fid_put(fid: dfid); | 
|---|
| 415 | return ERR_PTR(error: err); | 
|---|
| 416 | } | 
|---|
| 417 |  | 
|---|
| 418 | static int | 
|---|
| 419 | v9fs_vfs_getattr_dotl(struct mnt_idmap *idmap, | 
|---|
| 420 | const struct path *path, struct kstat *stat, | 
|---|
| 421 | u32 request_mask, unsigned int flags) | 
|---|
| 422 | { | 
|---|
| 423 | struct dentry *dentry = path->dentry; | 
|---|
| 424 | struct v9fs_session_info *v9ses; | 
|---|
| 425 | struct p9_fid *fid; | 
|---|
| 426 | struct inode *inode = d_inode(dentry); | 
|---|
| 427 | struct p9_stat_dotl *st; | 
|---|
| 428 |  | 
|---|
| 429 | p9_debug(P9_DEBUG_VFS, "dentry: %p\n", dentry); | 
|---|
| 430 | v9ses = v9fs_dentry2v9ses(dentry); | 
|---|
| 431 | if (v9ses->cache & (CACHE_META|CACHE_LOOSE)) { | 
|---|
| 432 | generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat); | 
|---|
| 433 | return 0; | 
|---|
| 434 | } else if (v9ses->cache) { | 
|---|
| 435 | if (S_ISREG(inode->i_mode)) { | 
|---|
| 436 | int retval = filemap_fdatawrite(inode->i_mapping); | 
|---|
| 437 |  | 
|---|
| 438 | if (retval) | 
|---|
| 439 | p9_debug(P9_DEBUG_ERROR, | 
|---|
| 440 | "flushing writeback during getattr returned %d\n", retval); | 
|---|
| 441 | } | 
|---|
| 442 | } | 
|---|
| 443 | fid = v9fs_fid_lookup(dentry); | 
|---|
| 444 | if (IS_ERR(ptr: fid)) | 
|---|
| 445 | return PTR_ERR(ptr: fid); | 
|---|
| 446 |  | 
|---|
| 447 | /* Ask for all the fields in stat structure. Server will return | 
|---|
| 448 | * whatever it supports | 
|---|
| 449 | */ | 
|---|
| 450 |  | 
|---|
| 451 | st = p9_client_getattr_dotl(fid, P9_STATS_ALL); | 
|---|
| 452 | p9_fid_put(fid); | 
|---|
| 453 | if (IS_ERR(ptr: st)) | 
|---|
| 454 | return PTR_ERR(ptr: st); | 
|---|
| 455 |  | 
|---|
| 456 | v9fs_stat2inode_dotl(stat: st, inode: d_inode(dentry), flags: 0); | 
|---|
| 457 | generic_fillattr(&nop_mnt_idmap, request_mask, d_inode(dentry), stat); | 
|---|
| 458 | /* Change block size to what the server returned */ | 
|---|
| 459 | stat->blksize = st->st_blksize; | 
|---|
| 460 |  | 
|---|
| 461 | kfree(objp: st); | 
|---|
| 462 | return 0; | 
|---|
| 463 | } | 
|---|
| 464 |  | 
|---|
| 465 | /* | 
|---|
| 466 | * Attribute flags. | 
|---|
| 467 | */ | 
|---|
| 468 | #define P9_ATTR_MODE		(1 << 0) | 
|---|
| 469 | #define P9_ATTR_UID		(1 << 1) | 
|---|
| 470 | #define P9_ATTR_GID		(1 << 2) | 
|---|
| 471 | #define P9_ATTR_SIZE		(1 << 3) | 
|---|
| 472 | #define P9_ATTR_ATIME		(1 << 4) | 
|---|
| 473 | #define P9_ATTR_MTIME		(1 << 5) | 
|---|
| 474 | #define P9_ATTR_CTIME		(1 << 6) | 
|---|
| 475 | #define P9_ATTR_ATIME_SET	(1 << 7) | 
|---|
| 476 | #define P9_ATTR_MTIME_SET	(1 << 8) | 
|---|
| 477 |  | 
|---|
| 478 | struct dotl_iattr_map { | 
|---|
| 479 | int iattr_valid; | 
|---|
| 480 | int p9_iattr_valid; | 
|---|
| 481 | }; | 
|---|
| 482 |  | 
|---|
| 483 | static int v9fs_mapped_iattr_valid(int iattr_valid) | 
|---|
| 484 | { | 
|---|
| 485 | int i; | 
|---|
| 486 | int p9_iattr_valid = 0; | 
|---|
| 487 | struct dotl_iattr_map dotl_iattr_map[] = { | 
|---|
| 488 | { ATTR_MODE,		P9_ATTR_MODE }, | 
|---|
| 489 | { ATTR_UID,		P9_ATTR_UID }, | 
|---|
| 490 | { ATTR_GID,		P9_ATTR_GID }, | 
|---|
| 491 | { ATTR_SIZE,		P9_ATTR_SIZE }, | 
|---|
| 492 | { ATTR_ATIME,		P9_ATTR_ATIME }, | 
|---|
| 493 | { ATTR_MTIME,		P9_ATTR_MTIME }, | 
|---|
| 494 | { ATTR_CTIME,		P9_ATTR_CTIME }, | 
|---|
| 495 | { ATTR_ATIME_SET,	P9_ATTR_ATIME_SET }, | 
|---|
| 496 | { ATTR_MTIME_SET,	P9_ATTR_MTIME_SET }, | 
|---|
| 497 | }; | 
|---|
| 498 | for (i = 0; i < ARRAY_SIZE(dotl_iattr_map); i++) { | 
|---|
| 499 | if (iattr_valid & dotl_iattr_map[i].iattr_valid) | 
|---|
| 500 | p9_iattr_valid |= dotl_iattr_map[i].p9_iattr_valid; | 
|---|
| 501 | } | 
|---|
| 502 | return p9_iattr_valid; | 
|---|
| 503 | } | 
|---|
| 504 |  | 
|---|
| 505 | /** | 
|---|
| 506 | * v9fs_vfs_setattr_dotl - set file metadata | 
|---|
| 507 | * @idmap: idmap of the mount | 
|---|
| 508 | * @dentry: file whose metadata to set | 
|---|
| 509 | * @iattr: metadata assignment structure | 
|---|
| 510 | * | 
|---|
| 511 | */ | 
|---|
| 512 |  | 
|---|
| 513 | int v9fs_vfs_setattr_dotl(struct mnt_idmap *idmap, | 
|---|
| 514 | struct dentry *dentry, struct iattr *iattr) | 
|---|
| 515 | { | 
|---|
| 516 | int retval, use_dentry = 0; | 
|---|
| 517 | struct inode *inode = d_inode(dentry); | 
|---|
| 518 | struct v9fs_session_info __maybe_unused *v9ses; | 
|---|
| 519 | struct p9_fid *fid = NULL; | 
|---|
| 520 | struct p9_iattr_dotl p9attr = { | 
|---|
| 521 | .uid = INVALID_UID, | 
|---|
| 522 | .gid = INVALID_GID, | 
|---|
| 523 | }; | 
|---|
| 524 |  | 
|---|
| 525 | p9_debug(P9_DEBUG_VFS, "\n"); | 
|---|
| 526 |  | 
|---|
| 527 | retval = setattr_prepare(&nop_mnt_idmap, dentry, iattr); | 
|---|
| 528 | if (retval) | 
|---|
| 529 | return retval; | 
|---|
| 530 |  | 
|---|
| 531 | v9ses = v9fs_dentry2v9ses(dentry); | 
|---|
| 532 |  | 
|---|
| 533 | p9attr.valid = v9fs_mapped_iattr_valid(iattr_valid: iattr->ia_valid); | 
|---|
| 534 | if (iattr->ia_valid & ATTR_MODE) | 
|---|
| 535 | p9attr.mode = iattr->ia_mode; | 
|---|
| 536 | if (iattr->ia_valid & ATTR_UID) | 
|---|
| 537 | p9attr.uid = iattr->ia_uid; | 
|---|
| 538 | if (iattr->ia_valid & ATTR_GID) | 
|---|
| 539 | p9attr.gid = iattr->ia_gid; | 
|---|
| 540 | if (iattr->ia_valid & ATTR_SIZE) | 
|---|
| 541 | p9attr.size = iattr->ia_size; | 
|---|
| 542 | if (iattr->ia_valid & ATTR_ATIME_SET) { | 
|---|
| 543 | p9attr.atime_sec = iattr->ia_atime.tv_sec; | 
|---|
| 544 | p9attr.atime_nsec = iattr->ia_atime.tv_nsec; | 
|---|
| 545 | } | 
|---|
| 546 | if (iattr->ia_valid & ATTR_MTIME_SET) { | 
|---|
| 547 | p9attr.mtime_sec = iattr->ia_mtime.tv_sec; | 
|---|
| 548 | p9attr.mtime_nsec = iattr->ia_mtime.tv_nsec; | 
|---|
| 549 | } | 
|---|
| 550 |  | 
|---|
| 551 | if (iattr->ia_valid & ATTR_FILE) { | 
|---|
| 552 | fid = iattr->ia_file->private_data; | 
|---|
| 553 | WARN_ON(!fid); | 
|---|
| 554 | } | 
|---|
| 555 | if (!fid) { | 
|---|
| 556 | fid = v9fs_fid_lookup(dentry); | 
|---|
| 557 | use_dentry = 1; | 
|---|
| 558 | } | 
|---|
| 559 | if (IS_ERR(ptr: fid)) | 
|---|
| 560 | return PTR_ERR(ptr: fid); | 
|---|
| 561 |  | 
|---|
| 562 | /* Write all dirty data */ | 
|---|
| 563 | if (S_ISREG(inode->i_mode)) { | 
|---|
| 564 | retval = filemap_fdatawrite(inode->i_mapping); | 
|---|
| 565 | if (retval < 0) | 
|---|
| 566 | p9_debug(P9_DEBUG_ERROR, | 
|---|
| 567 | "Flushing file prior to setattr failed: %d\n", retval); | 
|---|
| 568 | } | 
|---|
| 569 |  | 
|---|
| 570 | retval = p9_client_setattr(fid, attr: &p9attr); | 
|---|
| 571 | if (retval < 0) { | 
|---|
| 572 | if (use_dentry) | 
|---|
| 573 | p9_fid_put(fid); | 
|---|
| 574 | return retval; | 
|---|
| 575 | } | 
|---|
| 576 |  | 
|---|
| 577 | if ((iattr->ia_valid & ATTR_SIZE) && iattr->ia_size != | 
|---|
| 578 | i_size_read(inode)) { | 
|---|
| 579 | truncate_setsize(inode, newsize: iattr->ia_size); | 
|---|
| 580 | netfs_resize_file(ctx: netfs_inode(inode), new_i_size: iattr->ia_size, changed_on_server: true); | 
|---|
| 581 |  | 
|---|
| 582 | #ifdef CONFIG_9P_FSCACHE | 
|---|
| 583 | if (v9ses->cache & CACHE_FSCACHE) | 
|---|
| 584 | fscache_resize_cookie(v9fs_inode_cookie(V9FS_I(inode)), | 
|---|
| 585 | iattr->ia_size); | 
|---|
| 586 | #endif | 
|---|
| 587 | } | 
|---|
| 588 |  | 
|---|
| 589 | v9fs_invalidate_inode_attr(inode); | 
|---|
| 590 | setattr_copy(&nop_mnt_idmap, inode, attr: iattr); | 
|---|
| 591 | mark_inode_dirty(inode); | 
|---|
| 592 | if (iattr->ia_valid & ATTR_MODE) { | 
|---|
| 593 | /* We also want to update ACL when we update mode bits */ | 
|---|
| 594 | retval = v9fs_acl_chmod(inode, fid); | 
|---|
| 595 | if (retval < 0) { | 
|---|
| 596 | if (use_dentry) | 
|---|
| 597 | p9_fid_put(fid); | 
|---|
| 598 | return retval; | 
|---|
| 599 | } | 
|---|
| 600 | } | 
|---|
| 601 | if (use_dentry) | 
|---|
| 602 | p9_fid_put(fid); | 
|---|
| 603 |  | 
|---|
| 604 | return 0; | 
|---|
| 605 | } | 
|---|
| 606 |  | 
|---|
| 607 | /** | 
|---|
| 608 | * v9fs_stat2inode_dotl - populate an inode structure with stat info | 
|---|
| 609 | * @stat: stat structure | 
|---|
| 610 | * @inode: inode to populate | 
|---|
| 611 | * @flags: ctrl flags (e.g. V9FS_STAT2INODE_KEEP_ISIZE) | 
|---|
| 612 | * | 
|---|
| 613 | */ | 
|---|
| 614 |  | 
|---|
| 615 | void | 
|---|
| 616 | v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode, | 
|---|
| 617 | unsigned int flags) | 
|---|
| 618 | { | 
|---|
| 619 | umode_t mode; | 
|---|
| 620 | struct v9fs_inode *v9inode = V9FS_I(inode); | 
|---|
| 621 |  | 
|---|
| 622 | if ((stat->st_result_mask & P9_STATS_BASIC) == P9_STATS_BASIC) { | 
|---|
| 623 | inode_set_atime(inode, sec: stat->st_atime_sec, | 
|---|
| 624 | nsec: stat->st_atime_nsec); | 
|---|
| 625 | inode_set_mtime(inode, sec: stat->st_mtime_sec, | 
|---|
| 626 | nsec: stat->st_mtime_nsec); | 
|---|
| 627 | inode_set_ctime(inode, sec: stat->st_ctime_sec, | 
|---|
| 628 | nsec: stat->st_ctime_nsec); | 
|---|
| 629 | inode->i_uid = stat->st_uid; | 
|---|
| 630 | inode->i_gid = stat->st_gid; | 
|---|
| 631 | set_nlink(inode, nlink: stat->st_nlink); | 
|---|
| 632 |  | 
|---|
| 633 | mode = stat->st_mode & S_IALLUGO; | 
|---|
| 634 | mode |= inode->i_mode & ~S_IALLUGO; | 
|---|
| 635 | inode->i_mode = mode; | 
|---|
| 636 |  | 
|---|
| 637 | v9inode->netfs.remote_i_size = stat->st_size; | 
|---|
| 638 | if (!(flags & V9FS_STAT2INODE_KEEP_ISIZE)) | 
|---|
| 639 | v9fs_i_size_write(inode, i_size: stat->st_size); | 
|---|
| 640 | inode->i_blocks = stat->st_blocks; | 
|---|
| 641 | } else { | 
|---|
| 642 | if (stat->st_result_mask & P9_STATS_ATIME) { | 
|---|
| 643 | inode_set_atime(inode, sec: stat->st_atime_sec, | 
|---|
| 644 | nsec: stat->st_atime_nsec); | 
|---|
| 645 | } | 
|---|
| 646 | if (stat->st_result_mask & P9_STATS_MTIME) { | 
|---|
| 647 | inode_set_mtime(inode, sec: stat->st_mtime_sec, | 
|---|
| 648 | nsec: stat->st_mtime_nsec); | 
|---|
| 649 | } | 
|---|
| 650 | if (stat->st_result_mask & P9_STATS_CTIME) { | 
|---|
| 651 | inode_set_ctime(inode, sec: stat->st_ctime_sec, | 
|---|
| 652 | nsec: stat->st_ctime_nsec); | 
|---|
| 653 | } | 
|---|
| 654 | if (stat->st_result_mask & P9_STATS_UID) | 
|---|
| 655 | inode->i_uid = stat->st_uid; | 
|---|
| 656 | if (stat->st_result_mask & P9_STATS_GID) | 
|---|
| 657 | inode->i_gid = stat->st_gid; | 
|---|
| 658 | if (stat->st_result_mask & P9_STATS_NLINK) | 
|---|
| 659 | set_nlink(inode, nlink: stat->st_nlink); | 
|---|
| 660 | if (stat->st_result_mask & P9_STATS_MODE) { | 
|---|
| 661 | mode = stat->st_mode & S_IALLUGO; | 
|---|
| 662 | mode |= inode->i_mode & ~S_IALLUGO; | 
|---|
| 663 | inode->i_mode = mode; | 
|---|
| 664 | } | 
|---|
| 665 | if (!(flags & V9FS_STAT2INODE_KEEP_ISIZE) && | 
|---|
| 666 | stat->st_result_mask & P9_STATS_SIZE) { | 
|---|
| 667 | v9inode->netfs.remote_i_size = stat->st_size; | 
|---|
| 668 | v9fs_i_size_write(inode, i_size: stat->st_size); | 
|---|
| 669 | } | 
|---|
| 670 | if (stat->st_result_mask & P9_STATS_BLOCKS) | 
|---|
| 671 | inode->i_blocks = stat->st_blocks; | 
|---|
| 672 | } | 
|---|
| 673 | if (stat->st_result_mask & P9_STATS_GEN) | 
|---|
| 674 | inode->i_generation = stat->st_gen; | 
|---|
| 675 |  | 
|---|
| 676 | /* Currently we don't support P9_STATS_BTIME and P9_STATS_DATA_VERSION | 
|---|
| 677 | * because the inode structure does not have fields for them. | 
|---|
| 678 | */ | 
|---|
| 679 | v9inode->cache_validity &= ~V9FS_INO_INVALID_ATTR; | 
|---|
| 680 | } | 
|---|
| 681 |  | 
|---|
| 682 | static int | 
|---|
| 683 | v9fs_vfs_symlink_dotl(struct mnt_idmap *idmap, struct inode *dir, | 
|---|
| 684 | struct dentry *dentry, const char *symname) | 
|---|
| 685 | { | 
|---|
| 686 | int err; | 
|---|
| 687 | kgid_t gid; | 
|---|
| 688 | const unsigned char *name; | 
|---|
| 689 | struct p9_qid qid; | 
|---|
| 690 | struct p9_fid *dfid; | 
|---|
| 691 | struct p9_fid *fid = NULL; | 
|---|
| 692 |  | 
|---|
| 693 | name = dentry->d_name.name; | 
|---|
| 694 | p9_debug(P9_DEBUG_VFS, "%lu,%s,%s\n", dir->i_ino, name, symname); | 
|---|
| 695 |  | 
|---|
| 696 | dfid = v9fs_parent_fid(dentry); | 
|---|
| 697 | if (IS_ERR(ptr: dfid)) { | 
|---|
| 698 | err = PTR_ERR(ptr: dfid); | 
|---|
| 699 | p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err); | 
|---|
| 700 | return err; | 
|---|
| 701 | } | 
|---|
| 702 |  | 
|---|
| 703 | gid = v9fs_get_fsgid_for_create(dir_inode: dir); | 
|---|
| 704 |  | 
|---|
| 705 | /* Server doesn't alter fid on TSYMLINK. Hence no need to clone it. */ | 
|---|
| 706 | err = p9_client_symlink(fid: dfid, name, symname, gid, qid: &qid); | 
|---|
| 707 |  | 
|---|
| 708 | if (err < 0) { | 
|---|
| 709 | p9_debug(P9_DEBUG_VFS, "p9_client_symlink failed %d\n", err); | 
|---|
| 710 | goto error; | 
|---|
| 711 | } | 
|---|
| 712 |  | 
|---|
| 713 | v9fs_invalidate_inode_attr(inode: dir); | 
|---|
| 714 |  | 
|---|
| 715 | error: | 
|---|
| 716 | p9_fid_put(fid); | 
|---|
| 717 | p9_fid_put(fid: dfid); | 
|---|
| 718 | return err; | 
|---|
| 719 | } | 
|---|
| 720 |  | 
|---|
| 721 | /** | 
|---|
| 722 | * v9fs_vfs_link_dotl - create a hardlink for dotl | 
|---|
| 723 | * @old_dentry: dentry for file to link to | 
|---|
| 724 | * @dir: inode destination for new link | 
|---|
| 725 | * @dentry: dentry for link | 
|---|
| 726 | * | 
|---|
| 727 | */ | 
|---|
| 728 |  | 
|---|
| 729 | static int | 
|---|
| 730 | v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir, | 
|---|
| 731 | struct dentry *dentry) | 
|---|
| 732 | { | 
|---|
| 733 | int err; | 
|---|
| 734 | struct p9_fid *dfid, *oldfid; | 
|---|
| 735 | struct v9fs_session_info *v9ses; | 
|---|
| 736 |  | 
|---|
| 737 | p9_debug(P9_DEBUG_VFS, "dir ino: %lu, old_name: %pd, new_name: %pd\n", | 
|---|
| 738 | dir->i_ino, old_dentry, dentry); | 
|---|
| 739 |  | 
|---|
| 740 | v9ses = v9fs_inode2v9ses(inode: dir); | 
|---|
| 741 | dfid = v9fs_parent_fid(dentry); | 
|---|
| 742 | if (IS_ERR(ptr: dfid)) | 
|---|
| 743 | return PTR_ERR(ptr: dfid); | 
|---|
| 744 |  | 
|---|
| 745 | oldfid = v9fs_fid_lookup(dentry: old_dentry); | 
|---|
| 746 | if (IS_ERR(ptr: oldfid)) { | 
|---|
| 747 | p9_fid_put(fid: dfid); | 
|---|
| 748 | return PTR_ERR(ptr: oldfid); | 
|---|
| 749 | } | 
|---|
| 750 |  | 
|---|
| 751 | err = p9_client_link(fid: dfid, oldfid, newname: dentry->d_name.name); | 
|---|
| 752 |  | 
|---|
| 753 | p9_fid_put(fid: dfid); | 
|---|
| 754 | p9_fid_put(fid: oldfid); | 
|---|
| 755 | if (err < 0) { | 
|---|
| 756 | p9_debug(P9_DEBUG_VFS, "p9_client_link failed %d\n", err); | 
|---|
| 757 | return err; | 
|---|
| 758 | } | 
|---|
| 759 |  | 
|---|
| 760 | v9fs_invalidate_inode_attr(inode: dir); | 
|---|
| 761 | if (v9ses->cache & (CACHE_META|CACHE_LOOSE)) { | 
|---|
| 762 | /* Get the latest stat info from server. */ | 
|---|
| 763 | struct p9_fid *fid; | 
|---|
| 764 |  | 
|---|
| 765 | fid = v9fs_fid_lookup(dentry: old_dentry); | 
|---|
| 766 | if (IS_ERR(ptr: fid)) | 
|---|
| 767 | return PTR_ERR(ptr: fid); | 
|---|
| 768 |  | 
|---|
| 769 | v9fs_refresh_inode_dotl(fid, inode: d_inode(dentry: old_dentry)); | 
|---|
| 770 | p9_fid_put(fid); | 
|---|
| 771 | } | 
|---|
| 772 | ihold(inode: d_inode(dentry: old_dentry)); | 
|---|
| 773 | d_instantiate(dentry, d_inode(dentry: old_dentry)); | 
|---|
| 774 |  | 
|---|
| 775 | return err; | 
|---|
| 776 | } | 
|---|
| 777 |  | 
|---|
| 778 | /** | 
|---|
| 779 | * v9fs_vfs_mknod_dotl - create a special file | 
|---|
| 780 | * @idmap: The idmap of the mount | 
|---|
| 781 | * @dir: inode destination for new link | 
|---|
| 782 | * @dentry: dentry for file | 
|---|
| 783 | * @omode: mode for creation | 
|---|
| 784 | * @rdev: device associated with special file | 
|---|
| 785 | * | 
|---|
| 786 | */ | 
|---|
| 787 | static int | 
|---|
| 788 | v9fs_vfs_mknod_dotl(struct mnt_idmap *idmap, struct inode *dir, | 
|---|
| 789 | struct dentry *dentry, umode_t omode, dev_t rdev) | 
|---|
| 790 | { | 
|---|
| 791 | int err; | 
|---|
| 792 | kgid_t gid; | 
|---|
| 793 | const unsigned char *name; | 
|---|
| 794 | umode_t mode; | 
|---|
| 795 | struct v9fs_session_info *v9ses; | 
|---|
| 796 | struct p9_fid *fid = NULL, *dfid = NULL; | 
|---|
| 797 | struct inode *inode; | 
|---|
| 798 | struct p9_qid qid; | 
|---|
| 799 | struct posix_acl *dacl = NULL, *pacl = NULL; | 
|---|
| 800 |  | 
|---|
| 801 | p9_debug(P9_DEBUG_VFS, " %lu,%pd mode: %x MAJOR: %u MINOR: %u\n", | 
|---|
| 802 | dir->i_ino, dentry, omode, | 
|---|
| 803 | MAJOR(rdev), MINOR(rdev)); | 
|---|
| 804 |  | 
|---|
| 805 | v9ses = v9fs_inode2v9ses(inode: dir); | 
|---|
| 806 | dfid = v9fs_parent_fid(dentry); | 
|---|
| 807 | if (IS_ERR(ptr: dfid)) { | 
|---|
| 808 | err = PTR_ERR(ptr: dfid); | 
|---|
| 809 | p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err); | 
|---|
| 810 | goto error; | 
|---|
| 811 | } | 
|---|
| 812 |  | 
|---|
| 813 | gid = v9fs_get_fsgid_for_create(dir_inode: dir); | 
|---|
| 814 | mode = omode; | 
|---|
| 815 | /* Update mode based on ACL value */ | 
|---|
| 816 | err = v9fs_acl_mode(dir, modep: &mode, dpacl: &dacl, pacl: &pacl); | 
|---|
| 817 | if (err) { | 
|---|
| 818 | p9_debug(P9_DEBUG_VFS, "Failed to get acl values in mknod %d\n", | 
|---|
| 819 | err); | 
|---|
| 820 | goto error; | 
|---|
| 821 | } | 
|---|
| 822 | name = dentry->d_name.name; | 
|---|
| 823 |  | 
|---|
| 824 | err = p9_client_mknod_dotl(oldfid: dfid, name, mode, rdev, gid, qid: &qid); | 
|---|
| 825 | if (err < 0) | 
|---|
| 826 | goto error; | 
|---|
| 827 |  | 
|---|
| 828 | v9fs_invalidate_inode_attr(inode: dir); | 
|---|
| 829 | fid = p9_client_walk(oldfid: dfid, nwname: 1, wnames: &name, clone: 1); | 
|---|
| 830 | if (IS_ERR(ptr: fid)) { | 
|---|
| 831 | err = PTR_ERR(ptr: fid); | 
|---|
| 832 | p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", | 
|---|
| 833 | err); | 
|---|
| 834 | goto error; | 
|---|
| 835 | } | 
|---|
| 836 | inode = v9fs_get_new_inode_from_fid(v9ses, fid, sb: dir->i_sb); | 
|---|
| 837 | if (IS_ERR(ptr: inode)) { | 
|---|
| 838 | err = PTR_ERR(ptr: inode); | 
|---|
| 839 | p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n", | 
|---|
| 840 | err); | 
|---|
| 841 | goto error; | 
|---|
| 842 | } | 
|---|
| 843 | v9fs_set_create_acl(inode, fid, dacl, acl: pacl); | 
|---|
| 844 | v9fs_fid_add(dentry, fid: &fid); | 
|---|
| 845 | d_instantiate(dentry, inode); | 
|---|
| 846 | err = 0; | 
|---|
| 847 | error: | 
|---|
| 848 | p9_fid_put(fid); | 
|---|
| 849 | v9fs_put_acl(dacl, acl: pacl); | 
|---|
| 850 | p9_fid_put(fid: dfid); | 
|---|
| 851 |  | 
|---|
| 852 | return err; | 
|---|
| 853 | } | 
|---|
| 854 |  | 
|---|
| 855 | /** | 
|---|
| 856 | * v9fs_vfs_get_link_dotl - follow a symlink path | 
|---|
| 857 | * @dentry: dentry for symlink | 
|---|
| 858 | * @inode: inode for symlink | 
|---|
| 859 | * @done: destructor for return value | 
|---|
| 860 | */ | 
|---|
| 861 |  | 
|---|
| 862 | static const char * | 
|---|
| 863 | v9fs_vfs_get_link_dotl(struct dentry *dentry, | 
|---|
| 864 | struct inode *inode, | 
|---|
| 865 | struct delayed_call *done) | 
|---|
| 866 | { | 
|---|
| 867 | struct p9_fid *fid; | 
|---|
| 868 | char *target; | 
|---|
| 869 | int retval; | 
|---|
| 870 |  | 
|---|
| 871 | if (!dentry) | 
|---|
| 872 | return ERR_PTR(error: -ECHILD); | 
|---|
| 873 |  | 
|---|
| 874 | p9_debug(P9_DEBUG_VFS, "%pd\n", dentry); | 
|---|
| 875 |  | 
|---|
| 876 | fid = v9fs_fid_lookup(dentry); | 
|---|
| 877 | if (IS_ERR(ptr: fid)) | 
|---|
| 878 | return ERR_CAST(ptr: fid); | 
|---|
| 879 | retval = p9_client_readlink(fid, target: &target); | 
|---|
| 880 | p9_fid_put(fid); | 
|---|
| 881 | if (retval) | 
|---|
| 882 | return ERR_PTR(error: retval); | 
|---|
| 883 | set_delayed_call(call: done, fn: kfree_link, arg: target); | 
|---|
| 884 | return target; | 
|---|
| 885 | } | 
|---|
| 886 |  | 
|---|
| 887 | int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode) | 
|---|
| 888 | { | 
|---|
| 889 | struct p9_stat_dotl *st; | 
|---|
| 890 | struct v9fs_session_info *v9ses; | 
|---|
| 891 | unsigned int flags; | 
|---|
| 892 |  | 
|---|
| 893 | v9ses = v9fs_inode2v9ses(inode); | 
|---|
| 894 | st = p9_client_getattr_dotl(fid, P9_STATS_ALL); | 
|---|
| 895 | if (IS_ERR(ptr: st)) | 
|---|
| 896 | return PTR_ERR(ptr: st); | 
|---|
| 897 | /* | 
|---|
| 898 | * Don't update inode if the file type is different | 
|---|
| 899 | */ | 
|---|
| 900 | if (inode_wrong_type(inode, mode: st->st_mode)) { | 
|---|
| 901 | /* | 
|---|
| 902 | * Do this as a way of letting the caller know the inode should not | 
|---|
| 903 | * be reused | 
|---|
| 904 | */ | 
|---|
| 905 | v9fs_invalidate_inode_attr(inode); | 
|---|
| 906 | goto out; | 
|---|
| 907 | } | 
|---|
| 908 |  | 
|---|
| 909 | /* | 
|---|
| 910 | * We don't want to refresh inode->i_size, | 
|---|
| 911 | * because we may have cached data | 
|---|
| 912 | */ | 
|---|
| 913 | flags = (v9ses->cache & CACHE_LOOSE) ? | 
|---|
| 914 | V9FS_STAT2INODE_KEEP_ISIZE : 0; | 
|---|
| 915 | v9fs_stat2inode_dotl(stat: st, inode, flags); | 
|---|
| 916 | out: | 
|---|
| 917 | kfree(objp: st); | 
|---|
| 918 | return 0; | 
|---|
| 919 | } | 
|---|
| 920 |  | 
|---|
| 921 | const struct inode_operations v9fs_dir_inode_operations_dotl = { | 
|---|
| 922 | .create = v9fs_vfs_create_dotl, | 
|---|
| 923 | .atomic_open = v9fs_vfs_atomic_open_dotl, | 
|---|
| 924 | .lookup = v9fs_vfs_lookup, | 
|---|
| 925 | .link = v9fs_vfs_link_dotl, | 
|---|
| 926 | .symlink = v9fs_vfs_symlink_dotl, | 
|---|
| 927 | .unlink = v9fs_vfs_unlink, | 
|---|
| 928 | .mkdir = v9fs_vfs_mkdir_dotl, | 
|---|
| 929 | .rmdir = v9fs_vfs_rmdir, | 
|---|
| 930 | .mknod = v9fs_vfs_mknod_dotl, | 
|---|
| 931 | .rename = v9fs_vfs_rename, | 
|---|
| 932 | .getattr = v9fs_vfs_getattr_dotl, | 
|---|
| 933 | .setattr = v9fs_vfs_setattr_dotl, | 
|---|
| 934 | .listxattr = v9fs_listxattr, | 
|---|
| 935 | .get_inode_acl = v9fs_iop_get_inode_acl, | 
|---|
| 936 | .get_acl = v9fs_iop_get_acl, | 
|---|
| 937 | .set_acl = v9fs_iop_set_acl, | 
|---|
| 938 | }; | 
|---|
| 939 |  | 
|---|
| 940 | const struct inode_operations v9fs_file_inode_operations_dotl = { | 
|---|
| 941 | .getattr = v9fs_vfs_getattr_dotl, | 
|---|
| 942 | .setattr = v9fs_vfs_setattr_dotl, | 
|---|
| 943 | .listxattr = v9fs_listxattr, | 
|---|
| 944 | .get_inode_acl = v9fs_iop_get_inode_acl, | 
|---|
| 945 | .get_acl = v9fs_iop_get_acl, | 
|---|
| 946 | .set_acl = v9fs_iop_set_acl, | 
|---|
| 947 | }; | 
|---|
| 948 |  | 
|---|
| 949 | const struct inode_operations v9fs_symlink_inode_operations_dotl = { | 
|---|
| 950 | .get_link = v9fs_vfs_get_link_dotl, | 
|---|
| 951 | .getattr = v9fs_vfs_getattr_dotl, | 
|---|
| 952 | .setattr = v9fs_vfs_setattr_dotl, | 
|---|
| 953 | .listxattr = v9fs_listxattr, | 
|---|
| 954 | }; | 
|---|
| 955 |  | 
|---|