1 /* $NetBSD: tmpfs_rename.c,v 1.12 2021/10/20 14:28:21 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 2012 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Taylor R Campbell. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * tmpfs rename 34 */ 35 36 #include <sys/cdefs.h> 37 __KERNEL_RCSID(0, "$NetBSD: tmpfs_rename.c,v 1.12 2021/10/20 14:28:21 thorpej Exp $"); 38 39 #include <sys/param.h> 40 #include <sys/errno.h> 41 #include <sys/kauth.h> 42 #include <sys/mount.h> 43 #include <sys/namei.h> 44 #include <sys/stat.h> 45 #include <sys/vnode.h> 46 #include <sys/vnode_if.h> 47 48 #include <miscfs/genfs/genfs.h> 49 50 #include <fs/tmpfs/tmpfs_vnops.h> 51 #include <fs/tmpfs/tmpfs.h> 52 53 /* 54 * Forward declarations 55 */ 56 57 static int tmpfs_sane_rename(struct vnode *, struct componentname *, 58 struct vnode *, struct componentname *, 59 kauth_cred_t, bool); 60 static bool tmpfs_rmdired_p(struct vnode *); 61 static int tmpfs_gro_lock_directory(struct mount *, struct vnode *); 62 63 static const struct genfs_rename_ops tmpfs_genfs_rename_ops; 64 65 /* 66 * tmpfs_sane_rename: The hairiest vop, with the saner API. 67 * 68 * Arguments: 69 * 70 * . fdvp (from directory vnode), 71 * . fcnp (from component name), 72 * . tdvp (to directory vnode), 73 * . tcnp (to component name), 74 * . cred (credentials structure), and 75 * . posixly_correct (flag for behaviour if target & source link same file). 76 * 77 * fdvp and tdvp may be the same, and must be referenced and unlocked. 78 */ 79 static int 80 tmpfs_sane_rename( 81 struct vnode *fdvp, struct componentname *fcnp, 82 struct vnode *tdvp, struct componentname *tcnp, 83 kauth_cred_t cred, bool posixly_correct) 84 { 85 struct tmpfs_dirent *fdirent, *tdirent; 86 87 return genfs_sane_rename(&tmpfs_genfs_rename_ops, 88 fdvp, fcnp, &fdirent, tdvp, tcnp, &tdirent, 89 cred, posixly_correct); 90 } 91 92 /* 93 * tmpfs_rename: The hairiest vop, with the insanest API. Defer to 94 * genfs_insane_rename immediately. 95 */ 96 int 97 tmpfs_rename(void *v) 98 { 99 100 return genfs_insane_rename(v, &tmpfs_sane_rename); 101 } 102 103 /* 104 * tmpfs_gro_directory_empty_p: Return true if the directory vp is 105 * empty. dvp is its parent. 106 * 107 * vp and dvp must be locked and referenced. 108 */ 109 static bool 110 tmpfs_gro_directory_empty_p(struct mount *mp, kauth_cred_t cred, 111 struct vnode *vp, struct vnode *dvp) 112 { 113 114 (void)mp; 115 (void)cred; 116 (void)dvp; 117 KASSERT(mp != NULL); 118 KASSERT(vp != NULL); 119 KASSERT(dvp != NULL); 120 KASSERT(vp != dvp); 121 KASSERT(vp->v_mount == mp); 122 KASSERT(dvp->v_mount == mp); 123 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 124 KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); 125 126 return (VP_TO_TMPFS_NODE(vp)->tn_size == 0); 127 } 128 129 /* 130 * tmpfs_gro_rename_check_possible: Check whether a rename is possible 131 * independent of credentials. 132 */ 133 static int 134 tmpfs_gro_rename_check_possible(struct mount *mp, 135 struct vnode *fdvp, struct vnode *fvp, 136 struct vnode *tdvp, struct vnode *tvp) 137 { 138 139 (void)mp; 140 KASSERT(mp != NULL); 141 KASSERT(fdvp != NULL); 142 KASSERT(fvp != NULL); 143 KASSERT(tdvp != NULL); 144 KASSERT(fdvp != fvp); 145 KASSERT(fdvp != tvp); 146 KASSERT(tdvp != fvp); 147 KASSERT(tdvp != tvp); 148 KASSERT(fvp != tvp); 149 KASSERT(fdvp->v_type == VDIR); 150 KASSERT(tdvp->v_type == VDIR); 151 KASSERT(fdvp->v_mount == mp); 152 KASSERT(fvp->v_mount == mp); 153 KASSERT(tdvp->v_mount == mp); 154 KASSERT((tvp == NULL) || (tvp->v_mount == mp)); 155 KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE); 156 KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE); 157 KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE); 158 KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE)); 159 160 return genfs_ufslike_rename_check_possible( 161 VP_TO_TMPFS_NODE(fdvp)->tn_flags, VP_TO_TMPFS_NODE(fvp)->tn_flags, 162 VP_TO_TMPFS_NODE(tdvp)->tn_flags, 163 (tvp? VP_TO_TMPFS_NODE(tvp)->tn_flags : 0), (tvp != NULL), 164 IMMUTABLE, APPEND); 165 } 166 167 /* 168 * tmpfs_gro_rename_check_permitted: Check whether a rename is 169 * permitted given our credentials. 170 */ 171 static int 172 tmpfs_gro_rename_check_permitted(struct mount *mp, kauth_cred_t cred, 173 struct vnode *fdvp, struct vnode *fvp, 174 struct vnode *tdvp, struct vnode *tvp) 175 { 176 177 (void)mp; 178 KASSERT(mp != NULL); 179 KASSERT(fdvp != NULL); 180 KASSERT(fvp != NULL); 181 KASSERT(tdvp != NULL); 182 KASSERT(fdvp != fvp); 183 KASSERT(fdvp != tvp); 184 KASSERT(tdvp != fvp); 185 KASSERT(tdvp != tvp); 186 KASSERT(fvp != tvp); 187 KASSERT(fdvp->v_type == VDIR); 188 KASSERT(tdvp->v_type == VDIR); 189 KASSERT(fdvp->v_mount == mp); 190 KASSERT(fvp->v_mount == mp); 191 KASSERT(tdvp->v_mount == mp); 192 KASSERT((tvp == NULL) || (tvp->v_mount == mp)); 193 KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE); 194 KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE); 195 KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE); 196 KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE)); 197 198 return genfs_ufslike_rename_check_permitted(cred, 199 fdvp, VP_TO_TMPFS_NODE(fdvp)->tn_mode, 200 VP_TO_TMPFS_NODE(fdvp)->tn_uid, 201 fvp, VP_TO_TMPFS_NODE(fvp)->tn_uid, 202 tdvp, VP_TO_TMPFS_NODE(tdvp)->tn_mode, 203 VP_TO_TMPFS_NODE(tdvp)->tn_uid, 204 tvp, (tvp? VP_TO_TMPFS_NODE(tvp)->tn_uid : 0)); 205 } 206 207 /* 208 * tmpfs_gro_remove_check_possible: Check whether a remove is possible 209 * independent of credentials. 210 */ 211 static int 212 tmpfs_gro_remove_check_possible(struct mount *mp, 213 struct vnode *dvp, struct vnode *vp) 214 { 215 216 (void)mp; 217 KASSERT(mp != NULL); 218 KASSERT(dvp != NULL); 219 KASSERT(vp != NULL); 220 KASSERT(dvp != vp); 221 KASSERT(dvp->v_type == VDIR); 222 KASSERT(vp->v_type != VDIR); 223 KASSERT(dvp->v_mount == mp); 224 KASSERT(vp->v_mount == mp); 225 KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); 226 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 227 228 return genfs_ufslike_remove_check_possible( 229 VP_TO_TMPFS_NODE(dvp)->tn_flags, VP_TO_TMPFS_NODE(vp)->tn_flags, 230 IMMUTABLE, APPEND); 231 } 232 233 /* 234 * tmpfs_gro_remove_check_permitted: Check whether a remove is 235 * permitted given our credentials. 236 */ 237 static int 238 tmpfs_gro_remove_check_permitted(struct mount *mp, kauth_cred_t cred, 239 struct vnode *dvp, struct vnode *vp) 240 { 241 242 (void)mp; 243 KASSERT(mp != NULL); 244 KASSERT(dvp != NULL); 245 KASSERT(vp != NULL); 246 KASSERT(dvp != vp); 247 KASSERT(dvp->v_type == VDIR); 248 KASSERT(vp->v_type != VDIR); 249 KASSERT(dvp->v_mount == mp); 250 KASSERT(vp->v_mount == mp); 251 KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); 252 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 253 254 return genfs_ufslike_remove_check_permitted(cred, 255 dvp, VP_TO_TMPFS_NODE(dvp)->tn_mode, VP_TO_TMPFS_NODE(dvp)->tn_uid, 256 vp, VP_TO_TMPFS_NODE(vp)->tn_uid); 257 } 258 259 /* 260 * tmpfs_gro_rename: Actually perform the rename operation. 261 */ 262 static int 263 tmpfs_gro_rename(struct mount *mp, kauth_cred_t cred, 264 struct vnode *fdvp, struct componentname *fcnp, 265 void *fde, struct vnode *fvp, 266 struct vnode *tdvp, struct componentname *tcnp, 267 void *tde, struct vnode *tvp, nlink_t *tvp_nlinkp) 268 { 269 tmpfs_node_t *fdnode = VP_TO_TMPFS_DIR(fdvp); 270 tmpfs_node_t *tdnode = VP_TO_TMPFS_DIR(tdvp); 271 struct tmpfs_dirent **fdep = fde; 272 struct tmpfs_dirent **tdep = tde; 273 char *newname; 274 275 (void)cred; 276 KASSERT(mp != NULL); 277 KASSERT(fdvp != NULL); 278 KASSERT(fcnp != NULL); 279 KASSERT(fdep != NULL); 280 KASSERT(fvp != NULL); 281 KASSERT(tdvp != NULL); 282 KASSERT(tcnp != NULL); 283 KASSERT(tdep != NULL); 284 KASSERT(fdep != tdep); 285 KASSERT((tvp == NULL) || (*fdep) != (*tdep)); 286 KASSERT((*fdep) != NULL); 287 KASSERT((*fdep)->td_node == VP_TO_TMPFS_NODE(fvp)); 288 KASSERT((tvp == NULL) || ((*tdep) != NULL)); 289 KASSERT((tvp == NULL) || ((*tdep)->td_node == VP_TO_TMPFS_NODE(tvp))); 290 KASSERT(fdvp != fvp); 291 KASSERT(fdvp != tvp); 292 KASSERT(tdvp != fvp); 293 KASSERT(tdvp != tvp); 294 KASSERT(fvp != tvp); 295 KASSERT(fdvp->v_mount == mp); 296 KASSERT(fvp->v_mount == mp); 297 KASSERT(tdvp->v_mount == mp); 298 KASSERT((tvp == NULL) || (tvp->v_mount == mp)); 299 KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE); 300 KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE); 301 KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE); 302 KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE)); 303 304 if (tmpfs_strname_neqlen(fcnp, tcnp)) { 305 newname = tmpfs_strname_alloc(VFS_TO_TMPFS(mp), 306 tcnp->cn_namelen); 307 if (newname == NULL) 308 return ENOSPC; 309 } else { 310 newname = NULL; 311 } 312 313 /* 314 * If we are moving from one directory to another, detach the 315 * source entry and reattach it to the target directory. 316 */ 317 if (fdvp != tdvp) { 318 tmpfs_dir_detach(fdnode, *fdep); 319 tmpfs_dir_attach(tdnode, *fdep, VP_TO_TMPFS_NODE(fvp)); 320 } 321 322 /* 323 * If we are replacing an existing target entry, delete it. 324 * 325 * XXX What if the target is a directory with whiteout entries? 326 */ 327 if (tvp != NULL) { 328 tdnode = VP_TO_TMPFS_DIR(tdvp); 329 330 KASSERT((*tdep) != NULL); 331 KASSERT((*tdep)->td_node == VP_TO_TMPFS_NODE(tvp)); 332 KASSERT((fvp->v_type == VDIR) == (tvp->v_type == VDIR)); 333 if (tvp->v_type == VDIR) { 334 KASSERT(VP_TO_TMPFS_NODE(tvp)->tn_size == 0); 335 KASSERT(VP_TO_TMPFS_NODE(tvp)->tn_links == 2); 336 337 /* 338 * Decrement the extra link count for `.' so 339 * the vnode will be recycled when released. 340 */ 341 VP_TO_TMPFS_NODE(tvp)->tn_links--; 342 } 343 tmpfs_dir_detach(tdnode, *tdep); 344 tmpfs_free_dirent(VFS_TO_TMPFS(mp), *tdep); 345 346 *tvp_nlinkp = VP_TO_TMPFS_NODE(tvp)->tn_links; 347 } 348 349 /* 350 * Update the directory entry's name if necessary, and flag 351 * metadata updates. A memory allocation failure here is not 352 * OK because we've already committed some changes that we 353 * can't back out at this point, hence the early allocation 354 * above. 355 */ 356 if (newname != NULL) { 357 KASSERT(tcnp->cn_namelen <= TMPFS_MAXNAMLEN); 358 359 tmpfs_strname_free(VFS_TO_TMPFS(mp), (*fdep)->td_name, 360 (*fdep)->td_namelen); 361 (*fdep)->td_namelen = (uint16_t)tcnp->cn_namelen; 362 (void)memcpy(newname, tcnp->cn_nameptr, tcnp->cn_namelen); 363 (*fdep)->td_name = newname; 364 } 365 366 /* 367 * Update the timestamps of both parent directories and 368 * the renamed file itself. 369 */ 370 tmpfs_update(fdvp, TMPFS_UPDATE_MTIME | TMPFS_UPDATE_CTIME); 371 tmpfs_update(tdvp, TMPFS_UPDATE_MTIME | TMPFS_UPDATE_CTIME); 372 tmpfs_update(fvp, TMPFS_UPDATE_CTIME); 373 374 genfs_rename_cache_purge(fdvp, fvp, tdvp, tvp); 375 376 return 0; 377 } 378 379 /* 380 * tmpfs_gro_remove: Rename an object over another link to itself, 381 * effectively removing just the original link. 382 */ 383 static int 384 tmpfs_gro_remove(struct mount *mp, kauth_cred_t cred, 385 struct vnode *dvp, struct componentname *cnp, void *de, struct vnode *vp, 386 nlink_t *tvp_nlinkp) 387 { 388 tmpfs_node_t *dnode = VP_TO_TMPFS_DIR(dvp); 389 struct tmpfs_dirent **dep = de; 390 391 (void)vp; 392 KASSERT(mp != NULL); 393 KASSERT(dvp != NULL); 394 KASSERT(cnp != NULL); 395 KASSERT(dep != NULL); 396 KASSERT(vp != NULL); 397 KASSERT(dvp != vp); 398 KASSERT(dvp->v_mount == mp); 399 KASSERT(vp->v_mount == mp); 400 KASSERT(dvp->v_type == VDIR); 401 KASSERT(vp->v_type != VDIR); 402 KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); 403 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 404 405 KASSERT((*dep)->td_node == VP_TO_TMPFS_NODE(vp)); 406 407 tmpfs_dir_detach(dnode, *dep); 408 tmpfs_free_dirent(VFS_TO_TMPFS(mp), *dep); 409 tmpfs_update(dvp, TMPFS_UPDATE_MTIME | TMPFS_UPDATE_CTIME); 410 411 *tvp_nlinkp = VP_TO_TMPFS_NODE(vp)->tn_links; 412 413 return 0; 414 } 415 416 /* 417 * tmpfs_gro_lookup: Look up and save the lookup results. 418 */ 419 static int 420 tmpfs_gro_lookup(struct mount *mp, struct vnode *dvp, 421 struct componentname *cnp, void *de_ret, struct vnode **vp_ret) 422 { 423 struct tmpfs_dirent *dirent, **dep_ret = de_ret; 424 struct vnode *vp; 425 int error; 426 427 (void)mp; 428 KASSERT(mp != NULL); 429 KASSERT(dvp != NULL); 430 KASSERT(cnp != NULL); 431 KASSERT(dep_ret != NULL); 432 KASSERT(vp_ret != NULL); 433 KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); 434 435 dirent = tmpfs_dir_lookup(VP_TO_TMPFS_NODE(dvp), cnp); 436 if (dirent == NULL) 437 return ENOENT; 438 439 error = vcache_get(mp, &dirent->td_node, sizeof(dirent->td_node), &vp); 440 if (error) 441 return error; 442 KASSERT(vp != NULL); 443 444 *dep_ret = dirent; 445 *vp_ret = vp; 446 return 0; 447 } 448 449 /* 450 * tmpfs_rmdired_p: Check whether the directory vp has been rmdired. 451 * 452 * vp must be locked and referenced. 453 */ 454 static bool 455 tmpfs_rmdired_p(struct vnode *vp) 456 { 457 458 KASSERT(vp != NULL); 459 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 460 KASSERT(vp->v_type == VDIR); 461 462 return (VP_TO_TMPFS_NODE(vp)->tn_spec.tn_dir.tn_parent == NULL); 463 } 464 465 /* 466 * tmpfs_gro_genealogy: Analyze the genealogy of the source and target 467 * directories. 468 */ 469 static int 470 tmpfs_gro_genealogy(struct mount *mp, kauth_cred_t cred, 471 struct vnode *fdvp, struct vnode *tdvp, 472 struct vnode **intermediate_node_ret) 473 { 474 struct vnode *vp, *ovp; 475 struct tmpfs_node *dnode; 476 int error; 477 478 (void)cred; 479 KASSERT(mp != NULL); 480 KASSERT(fdvp != NULL); 481 KASSERT(tdvp != NULL); 482 KASSERT(fdvp != tdvp); 483 KASSERT(intermediate_node_ret != NULL); 484 KASSERT(fdvp->v_mount == mp); 485 KASSERT(tdvp->v_mount == mp); 486 KASSERT(fdvp->v_type == VDIR); 487 KASSERT(tdvp->v_type == VDIR); 488 489 /* 490 * We need to provisionally lock tdvp to keep rmdir from 491 * deleting it -- or any ancestor -- at an inopportune moment. 492 */ 493 error = tmpfs_gro_lock_directory(mp, tdvp); 494 if (error) 495 return error; 496 497 vp = tdvp; 498 vref(vp); 499 500 for (;;) { 501 KASSERT(vp != NULL); 502 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 503 KASSERT(vp->v_mount == mp); 504 KASSERT(vp->v_type == VDIR); 505 KASSERT(!tmpfs_rmdired_p(vp)); 506 507 dnode = VP_TO_TMPFS_NODE(vp)->tn_spec.tn_dir.tn_parent; 508 509 /* 510 * If dnode is null then vp has been rmdir'd, which is 511 * not supposed to happen because we have it locked. 512 */ 513 KASSERT(dnode != NULL); 514 515 /* Did we hit the root without finding fdvp? */ 516 if (dnode == VP_TO_TMPFS_NODE(vp)) { 517 vput(vp); 518 *intermediate_node_ret = NULL; 519 return 0; 520 } 521 522 /* Did we find that fdvp is an ancestor of tdvp? */ 523 if (dnode == VP_TO_TMPFS_NODE(fdvp)) { 524 KASSERT(dnode->tn_vnode == fdvp); 525 /* Unlock vp, but keep it referenced. */ 526 VOP_UNLOCK(vp); 527 *intermediate_node_ret = vp; 528 return 0; 529 } 530 531 /* Neither -- keep ascending the family tree. */ 532 ovp = vp; 533 vp = NULL; 534 error = vcache_get(mp, &dnode, sizeof(dnode), &vp); 535 vput(ovp); 536 if (error) 537 return error; 538 error = vn_lock(vp, LK_EXCLUSIVE); 539 if (error) { 540 vrele(vp); 541 return error; 542 } 543 544 /* 545 * vcache_get only guarantees that dnode will not 546 * be freed while we get a vnode for it. It does not 547 * preserve any other invariants, so we must check 548 * whether the parent has been removed in the meantime. 549 */ 550 if (tmpfs_rmdired_p(vp)) { 551 vput(vp); 552 return ENOENT; 553 } 554 } 555 } 556 557 /* 558 * tmpfs_gro_lock_directory: Lock the directory vp, but fail if it has 559 * been rmdir'd. 560 */ 561 static int 562 tmpfs_gro_lock_directory(struct mount *mp, struct vnode *vp) 563 { 564 565 (void)mp; 566 KASSERT(mp != NULL); 567 KASSERT(vp != NULL); 568 KASSERT(vp->v_mount == mp); 569 570 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 571 572 if (tmpfs_rmdired_p(vp)) { 573 VOP_UNLOCK(vp); 574 return ENOENT; 575 } 576 577 return 0; 578 } 579 580 static const struct genfs_rename_ops tmpfs_genfs_rename_ops = { 581 .gro_directory_empty_p = tmpfs_gro_directory_empty_p, 582 .gro_rename_check_possible = tmpfs_gro_rename_check_possible, 583 .gro_rename_check_permitted = tmpfs_gro_rename_check_permitted, 584 .gro_remove_check_possible = tmpfs_gro_remove_check_possible, 585 .gro_remove_check_permitted = tmpfs_gro_remove_check_permitted, 586 .gro_rename = tmpfs_gro_rename, 587 .gro_remove = tmpfs_gro_remove, 588 .gro_lookup = tmpfs_gro_lookup, 589 .gro_genealogy = tmpfs_gro_genealogy, 590 .gro_lock_directory = tmpfs_gro_lock_directory, 591 }; 592