1 /* $NetBSD: tmpfs_rename.c,v 1.10 2019/12/03 04:59:05 riastradh 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.10 2019/12/03 04:59:05 riastradh 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) 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 } else if (tvp == NULL) { 321 /* 322 * We are changing the directory. tmpfs_dir_attach and 323 * tmpfs_dir_detach note the events for us, but for 324 * this case we don't call them, so we must note the 325 * event explicitly. 326 */ 327 VN_KNOTE(fdvp, NOTE_WRITE); 328 } 329 330 /* 331 * If we are replacing an existing target entry, delete it. 332 * 333 * XXX What if the target is a directory with whiteout entries? 334 */ 335 if (tvp != NULL) { 336 tdnode = VP_TO_TMPFS_DIR(tdvp); 337 338 KASSERT((*tdep) != NULL); 339 KASSERT((*tdep)->td_node == VP_TO_TMPFS_NODE(tvp)); 340 KASSERT((fvp->v_type == VDIR) == (tvp->v_type == VDIR)); 341 if (tvp->v_type == VDIR) { 342 KASSERT(VP_TO_TMPFS_NODE(tvp)->tn_size == 0); 343 KASSERT(VP_TO_TMPFS_NODE(tvp)->tn_links == 2); 344 345 /* 346 * Decrement the extra link count for `.' so 347 * the vnode will be recycled when released. 348 */ 349 VP_TO_TMPFS_NODE(tvp)->tn_links--; 350 } 351 tmpfs_dir_detach(tdnode, *tdep); 352 tmpfs_free_dirent(VFS_TO_TMPFS(mp), *tdep); 353 } 354 355 /* 356 * Update the directory entry's name if necessary, and flag 357 * metadata updates. A memory allocation failure here is not 358 * OK because we've already committed some changes that we 359 * can't back out at this point, hence the early allocation 360 * above. 361 */ 362 if (newname != NULL) { 363 KASSERT(tcnp->cn_namelen <= TMPFS_MAXNAMLEN); 364 365 tmpfs_strname_free(VFS_TO_TMPFS(mp), (*fdep)->td_name, 366 (*fdep)->td_namelen); 367 (*fdep)->td_namelen = (uint16_t)tcnp->cn_namelen; 368 (void)memcpy(newname, tcnp->cn_nameptr, tcnp->cn_namelen); 369 (*fdep)->td_name = newname; 370 } 371 372 /* 373 * Update the timestamps of both parent directories and 374 * the renamed file itself. 375 */ 376 tmpfs_update(fdvp, TMPFS_UPDATE_MTIME | TMPFS_UPDATE_CTIME); 377 tmpfs_update(tdvp, TMPFS_UPDATE_MTIME | TMPFS_UPDATE_CTIME); 378 tmpfs_update(fvp, TMPFS_UPDATE_CTIME); 379 380 VN_KNOTE(fvp, NOTE_RENAME); 381 382 genfs_rename_cache_purge(fdvp, fvp, tdvp, tvp); 383 384 return 0; 385 } 386 387 /* 388 * tmpfs_gro_remove: Rename an object over another link to itself, 389 * effectively removing just the original link. 390 */ 391 static int 392 tmpfs_gro_remove(struct mount *mp, kauth_cred_t cred, 393 struct vnode *dvp, struct componentname *cnp, void *de, struct vnode *vp) 394 { 395 tmpfs_node_t *dnode = VP_TO_TMPFS_DIR(dvp); 396 struct tmpfs_dirent **dep = de; 397 398 (void)vp; 399 KASSERT(mp != NULL); 400 KASSERT(dvp != NULL); 401 KASSERT(cnp != NULL); 402 KASSERT(dep != NULL); 403 KASSERT(vp != NULL); 404 KASSERT(dvp != vp); 405 KASSERT(dvp->v_mount == mp); 406 KASSERT(vp->v_mount == mp); 407 KASSERT(dvp->v_type == VDIR); 408 KASSERT(vp->v_type != VDIR); 409 KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); 410 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 411 412 tmpfs_dir_detach(dnode, *dep); 413 tmpfs_free_dirent(VFS_TO_TMPFS(mp), *dep); 414 tmpfs_update(dvp, TMPFS_UPDATE_MTIME | TMPFS_UPDATE_CTIME); 415 416 return 0; 417 } 418 419 /* 420 * tmpfs_gro_lookup: Look up and save the lookup results. 421 */ 422 static int 423 tmpfs_gro_lookup(struct mount *mp, struct vnode *dvp, 424 struct componentname *cnp, void *de_ret, struct vnode **vp_ret) 425 { 426 struct tmpfs_dirent *dirent, **dep_ret = de_ret; 427 struct vnode *vp; 428 int error; 429 430 (void)mp; 431 KASSERT(mp != NULL); 432 KASSERT(dvp != NULL); 433 KASSERT(cnp != NULL); 434 KASSERT(dep_ret != NULL); 435 KASSERT(vp_ret != NULL); 436 KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE); 437 438 dirent = tmpfs_dir_lookup(VP_TO_TMPFS_NODE(dvp), cnp); 439 if (dirent == NULL) 440 return ENOENT; 441 442 error = vcache_get(mp, &dirent->td_node, sizeof(dirent->td_node), &vp); 443 if (error) 444 return error; 445 KASSERT(vp != NULL); 446 447 *dep_ret = dirent; 448 *vp_ret = vp; 449 return 0; 450 } 451 452 /* 453 * tmpfs_rmdired_p: Check whether the directory vp has been rmdired. 454 * 455 * vp must be locked and referenced. 456 */ 457 static bool 458 tmpfs_rmdired_p(struct vnode *vp) 459 { 460 461 KASSERT(vp != NULL); 462 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 463 KASSERT(vp->v_type == VDIR); 464 465 return (VP_TO_TMPFS_NODE(vp)->tn_spec.tn_dir.tn_parent == NULL); 466 } 467 468 /* 469 * tmpfs_gro_genealogy: Analyze the genealogy of the source and target 470 * directories. 471 */ 472 static int 473 tmpfs_gro_genealogy(struct mount *mp, kauth_cred_t cred, 474 struct vnode *fdvp, struct vnode *tdvp, 475 struct vnode **intermediate_node_ret) 476 { 477 struct vnode *vp, *ovp; 478 struct tmpfs_node *dnode; 479 int error; 480 481 (void)cred; 482 KASSERT(mp != NULL); 483 KASSERT(fdvp != NULL); 484 KASSERT(tdvp != NULL); 485 KASSERT(fdvp != tdvp); 486 KASSERT(intermediate_node_ret != NULL); 487 KASSERT(fdvp->v_mount == mp); 488 KASSERT(tdvp->v_mount == mp); 489 KASSERT(fdvp->v_type == VDIR); 490 KASSERT(tdvp->v_type == VDIR); 491 492 /* 493 * We need to provisionally lock tdvp to keep rmdir from 494 * deleting it -- or any ancestor -- at an inopportune moment. 495 */ 496 error = tmpfs_gro_lock_directory(mp, tdvp); 497 if (error) 498 return error; 499 500 vp = tdvp; 501 vref(vp); 502 503 for (;;) { 504 KASSERT(vp != NULL); 505 KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE); 506 KASSERT(vp->v_mount == mp); 507 KASSERT(vp->v_type == VDIR); 508 KASSERT(!tmpfs_rmdired_p(vp)); 509 510 dnode = VP_TO_TMPFS_NODE(vp)->tn_spec.tn_dir.tn_parent; 511 512 /* 513 * If dnode is null then vp has been rmdir'd, which is 514 * not supposed to happen because we have it locked. 515 */ 516 KASSERT(dnode != NULL); 517 518 /* Did we hit the root without finding fdvp? */ 519 if (dnode == VP_TO_TMPFS_NODE(vp)) { 520 vput(vp); 521 *intermediate_node_ret = NULL; 522 return 0; 523 } 524 525 /* Did we find that fdvp is an ancestor of tdvp? */ 526 if (dnode == VP_TO_TMPFS_NODE(fdvp)) { 527 KASSERT(dnode->tn_vnode == fdvp); 528 /* Unlock vp, but keep it referenced. */ 529 VOP_UNLOCK(vp); 530 *intermediate_node_ret = vp; 531 return 0; 532 } 533 534 /* Neither -- keep ascending the family tree. */ 535 ovp = vp; 536 vp = NULL; 537 error = vcache_get(mp, &dnode, sizeof(dnode), &vp); 538 vput(ovp); 539 if (error) 540 return error; 541 error = vn_lock(vp, LK_EXCLUSIVE); 542 if (error) { 543 vrele(vp); 544 return error; 545 } 546 547 /* 548 * vcache_get only guarantees that dnode will not 549 * be freed while we get a vnode for it. It does not 550 * preserve any other invariants, so we must check 551 * whether the parent has been removed in the meantime. 552 */ 553 if (tmpfs_rmdired_p(vp)) { 554 vput(vp); 555 return ENOENT; 556 } 557 } 558 } 559 560 /* 561 * tmpfs_gro_lock_directory: Lock the directory vp, but fail if it has 562 * been rmdir'd. 563 */ 564 static int 565 tmpfs_gro_lock_directory(struct mount *mp, struct vnode *vp) 566 { 567 568 (void)mp; 569 KASSERT(mp != NULL); 570 KASSERT(vp != NULL); 571 KASSERT(vp->v_mount == mp); 572 573 vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); 574 575 if (tmpfs_rmdired_p(vp)) { 576 VOP_UNLOCK(vp); 577 return ENOENT; 578 } 579 580 return 0; 581 } 582 583 static const struct genfs_rename_ops tmpfs_genfs_rename_ops = { 584 .gro_directory_empty_p = tmpfs_gro_directory_empty_p, 585 .gro_rename_check_possible = tmpfs_gro_rename_check_possible, 586 .gro_rename_check_permitted = tmpfs_gro_rename_check_permitted, 587 .gro_remove_check_possible = tmpfs_gro_remove_check_possible, 588 .gro_remove_check_permitted = tmpfs_gro_remove_check_permitted, 589 .gro_rename = tmpfs_gro_rename, 590 .gro_remove = tmpfs_gro_remove, 591 .gro_lookup = tmpfs_gro_lookup, 592 .gro_genealogy = tmpfs_gro_genealogy, 593 .gro_lock_directory = tmpfs_gro_lock_directory, 594 }; 595