1 /* 2 * Copyright (c) 2011-2018 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@dragonflybsd.org> 6 * by Venkatesh Srinivas <vsrinivas@dragonflybsd.org> 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in 16 * the documentation and/or other materials provided with the 17 * distribution. 18 * 3. Neither the name of The DragonFly Project nor the names of its 19 * contributors may be used to endorse or promote products derived 20 * from this software without specific, prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 26 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 30 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 31 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 32 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 /* 36 * Ioctl Functions. 37 * 38 * WARNING! The ioctl functions which manipulate the connection state need 39 * to be able to run without deadlock on the volume's chain lock. 40 * Most of these functions use a separate lock. 41 */ 42 43 #include "hammer2.h" 44 45 static int hammer2_ioctl_version_get(hammer2_inode_t *ip, void *data); 46 static int hammer2_ioctl_recluster(hammer2_inode_t *ip, void *data); 47 static int hammer2_ioctl_remote_scan(hammer2_inode_t *ip, void *data); 48 static int hammer2_ioctl_remote_add(hammer2_inode_t *ip, void *data); 49 static int hammer2_ioctl_remote_del(hammer2_inode_t *ip, void *data); 50 static int hammer2_ioctl_remote_rep(hammer2_inode_t *ip, void *data); 51 static int hammer2_ioctl_socket_get(hammer2_inode_t *ip, void *data); 52 static int hammer2_ioctl_socket_set(hammer2_inode_t *ip, void *data); 53 static int hammer2_ioctl_pfs_get(hammer2_inode_t *ip, void *data); 54 static int hammer2_ioctl_pfs_lookup(hammer2_inode_t *ip, void *data); 55 static int hammer2_ioctl_pfs_create(hammer2_inode_t *ip, void *data); 56 static int hammer2_ioctl_pfs_snapshot(hammer2_inode_t *ip, void *data); 57 static int hammer2_ioctl_pfs_delete(hammer2_inode_t *ip, void *data); 58 static int hammer2_ioctl_inode_get(hammer2_inode_t *ip, void *data); 59 static int hammer2_ioctl_inode_set(hammer2_inode_t *ip, void *data); 60 static int hammer2_ioctl_debug_dump(hammer2_inode_t *ip, u_int flags); 61 //static int hammer2_ioctl_inode_comp_set(hammer2_inode_t *ip, void *data); 62 //static int hammer2_ioctl_inode_comp_rec_set(hammer2_inode_t *ip, void *data); 63 //static int hammer2_ioctl_inode_comp_rec_set2(hammer2_inode_t *ip, void *data); 64 static int hammer2_ioctl_bulkfree_scan(hammer2_inode_t *ip, void *data); 65 static int hammer2_ioctl_destroy(hammer2_inode_t *ip, void *data); 66 67 int 68 hammer2_ioctl(hammer2_inode_t *ip, u_long com, void *data, int fflag, 69 struct ucred *cred) 70 { 71 int error; 72 73 /* 74 * Standard root cred checks, will be selectively ignored below 75 * for ioctls that do not require root creds. 76 */ 77 error = priv_check_cred(cred, PRIV_HAMMER_IOCTL, 0); 78 79 switch(com) { 80 case HAMMER2IOC_VERSION_GET: 81 error = hammer2_ioctl_version_get(ip, data); 82 break; 83 case HAMMER2IOC_RECLUSTER: 84 if (error == 0) 85 error = hammer2_ioctl_recluster(ip, data); 86 break; 87 case HAMMER2IOC_REMOTE_SCAN: 88 if (error == 0) 89 error = hammer2_ioctl_remote_scan(ip, data); 90 break; 91 case HAMMER2IOC_REMOTE_ADD: 92 if (error == 0) 93 error = hammer2_ioctl_remote_add(ip, data); 94 break; 95 case HAMMER2IOC_REMOTE_DEL: 96 if (error == 0) 97 error = hammer2_ioctl_remote_del(ip, data); 98 break; 99 case HAMMER2IOC_REMOTE_REP: 100 if (error == 0) 101 error = hammer2_ioctl_remote_rep(ip, data); 102 break; 103 case HAMMER2IOC_SOCKET_GET: 104 if (error == 0) 105 error = hammer2_ioctl_socket_get(ip, data); 106 break; 107 case HAMMER2IOC_SOCKET_SET: 108 if (error == 0) 109 error = hammer2_ioctl_socket_set(ip, data); 110 break; 111 case HAMMER2IOC_PFS_GET: 112 if (error == 0) 113 error = hammer2_ioctl_pfs_get(ip, data); 114 break; 115 case HAMMER2IOC_PFS_LOOKUP: 116 if (error == 0) 117 error = hammer2_ioctl_pfs_lookup(ip, data); 118 break; 119 case HAMMER2IOC_PFS_CREATE: 120 if (error == 0) 121 error = hammer2_ioctl_pfs_create(ip, data); 122 break; 123 case HAMMER2IOC_PFS_DELETE: 124 if (error == 0) 125 error = hammer2_ioctl_pfs_delete(ip, data); 126 break; 127 case HAMMER2IOC_PFS_SNAPSHOT: 128 if (error == 0) 129 error = hammer2_ioctl_pfs_snapshot(ip, data); 130 break; 131 case HAMMER2IOC_INODE_GET: 132 error = hammer2_ioctl_inode_get(ip, data); 133 break; 134 case HAMMER2IOC_INODE_SET: 135 if (error == 0) 136 error = hammer2_ioctl_inode_set(ip, data); 137 break; 138 case HAMMER2IOC_BULKFREE_SCAN: 139 error = hammer2_ioctl_bulkfree_scan(ip, data); 140 break; 141 case HAMMER2IOC_BULKFREE_ASYNC: 142 error = hammer2_ioctl_bulkfree_scan(ip, NULL); 143 break; 144 /*case HAMMER2IOC_INODE_COMP_SET: 145 error = hammer2_ioctl_inode_comp_set(ip, data); 146 break; 147 case HAMMER2IOC_INODE_COMP_REC_SET: 148 error = hammer2_ioctl_inode_comp_rec_set(ip, data); 149 break; 150 case HAMMER2IOC_INODE_COMP_REC_SET2: 151 error = hammer2_ioctl_inode_comp_rec_set2(ip, data); 152 break;*/ 153 case HAMMER2IOC_DESTROY: 154 if (error == 0) 155 error = hammer2_ioctl_destroy(ip, data); 156 break; 157 case HAMMER2IOC_DEBUG_DUMP: 158 error = hammer2_ioctl_debug_dump(ip, *(u_int *)data); 159 break; 160 default: 161 error = EOPNOTSUPP; 162 break; 163 } 164 return (error); 165 } 166 167 /* 168 * Retrieve version and basic info 169 */ 170 static int 171 hammer2_ioctl_version_get(hammer2_inode_t *ip, void *data) 172 { 173 hammer2_ioc_version_t *version = data; 174 hammer2_dev_t *hmp; 175 176 hmp = ip->pmp->pfs_hmps[0]; 177 if (hmp) 178 version->version = hmp->voldata.version; 179 else 180 version->version = -1; 181 return 0; 182 } 183 184 static int 185 hammer2_ioctl_recluster(hammer2_inode_t *ip, void *data) 186 { 187 hammer2_ioc_recluster_t *recl = data; 188 struct vnode *vproot; 189 struct file *fp; 190 hammer2_cluster_t *cluster; 191 int error; 192 193 fp = holdfp(curthread, recl->fd, -1); 194 if (fp) { 195 error = VFS_ROOT(ip->pmp->mp, &vproot); 196 if (error == 0) { 197 cluster = &ip->pmp->iroot->cluster; 198 kprintf("reconnect to cluster: nc=%d focus=%p\n", 199 cluster->nchains, cluster->focus); 200 if (cluster->nchains != 1 || cluster->focus == NULL) { 201 kprintf("not a local device mount\n"); 202 error = EINVAL; 203 } else { 204 hammer2_cluster_reconnect(cluster->focus->hmp, 205 fp); 206 kprintf("ok\n"); 207 error = 0; 208 } 209 vput(vproot); 210 } 211 } else { 212 error = EINVAL; 213 } 214 return error; 215 } 216 217 /* 218 * Retrieve information about a remote 219 */ 220 static int 221 hammer2_ioctl_remote_scan(hammer2_inode_t *ip, void *data) 222 { 223 hammer2_dev_t *hmp; 224 hammer2_ioc_remote_t *remote = data; 225 int copyid = remote->copyid; 226 227 hmp = ip->pmp->pfs_hmps[0]; 228 if (hmp == NULL) 229 return (EINVAL); 230 231 if (copyid < 0 || copyid >= HAMMER2_COPYID_COUNT) 232 return (EINVAL); 233 234 hammer2_voldata_lock(hmp); 235 remote->copy1 = hmp->voldata.copyinfo[copyid]; 236 hammer2_voldata_unlock(hmp); 237 238 /* 239 * Adjust nextid (GET only) 240 */ 241 while (++copyid < HAMMER2_COPYID_COUNT && 242 hmp->voldata.copyinfo[copyid].copyid == 0) { 243 ; 244 } 245 if (copyid == HAMMER2_COPYID_COUNT) 246 remote->nextid = -1; 247 else 248 remote->nextid = copyid; 249 250 return(0); 251 } 252 253 /* 254 * Add new remote entry 255 */ 256 static int 257 hammer2_ioctl_remote_add(hammer2_inode_t *ip, void *data) 258 { 259 hammer2_ioc_remote_t *remote = data; 260 hammer2_pfs_t *pmp = ip->pmp; 261 hammer2_dev_t *hmp; 262 int copyid = remote->copyid; 263 int error = 0; 264 265 hmp = pmp->pfs_hmps[0]; 266 if (hmp == NULL) 267 return (EINVAL); 268 if (copyid >= HAMMER2_COPYID_COUNT) 269 return (EINVAL); 270 271 hammer2_voldata_lock(hmp); 272 if (copyid < 0) { 273 for (copyid = 1; copyid < HAMMER2_COPYID_COUNT; ++copyid) { 274 if (hmp->voldata.copyinfo[copyid].copyid == 0) 275 break; 276 } 277 if (copyid == HAMMER2_COPYID_COUNT) { 278 error = ENOSPC; 279 goto failed; 280 } 281 } 282 hammer2_voldata_modify(hmp); 283 remote->copy1.copyid = copyid; 284 hmp->voldata.copyinfo[copyid] = remote->copy1; 285 hammer2_volconf_update(hmp, copyid); 286 failed: 287 hammer2_voldata_unlock(hmp); 288 return (error); 289 } 290 291 /* 292 * Delete existing remote entry 293 */ 294 static int 295 hammer2_ioctl_remote_del(hammer2_inode_t *ip, void *data) 296 { 297 hammer2_ioc_remote_t *remote = data; 298 hammer2_pfs_t *pmp = ip->pmp; 299 hammer2_dev_t *hmp; 300 int copyid = remote->copyid; 301 int error = 0; 302 303 hmp = pmp->pfs_hmps[0]; 304 if (hmp == NULL) 305 return (EINVAL); 306 if (copyid >= HAMMER2_COPYID_COUNT) 307 return (EINVAL); 308 remote->copy1.path[sizeof(remote->copy1.path) - 1] = 0; 309 hammer2_voldata_lock(hmp); 310 if (copyid < 0) { 311 for (copyid = 1; copyid < HAMMER2_COPYID_COUNT; ++copyid) { 312 if (hmp->voldata.copyinfo[copyid].copyid == 0) 313 continue; 314 if (strcmp(remote->copy1.path, 315 hmp->voldata.copyinfo[copyid].path) == 0) { 316 break; 317 } 318 } 319 if (copyid == HAMMER2_COPYID_COUNT) { 320 error = ENOENT; 321 goto failed; 322 } 323 } 324 hammer2_voldata_modify(hmp); 325 hmp->voldata.copyinfo[copyid].copyid = 0; 326 hammer2_volconf_update(hmp, copyid); 327 failed: 328 hammer2_voldata_unlock(hmp); 329 return (error); 330 } 331 332 /* 333 * Replace existing remote entry 334 */ 335 static int 336 hammer2_ioctl_remote_rep(hammer2_inode_t *ip, void *data) 337 { 338 hammer2_ioc_remote_t *remote = data; 339 hammer2_dev_t *hmp; 340 int copyid = remote->copyid; 341 342 hmp = ip->pmp->pfs_hmps[0]; 343 if (hmp == NULL) 344 return (EINVAL); 345 if (copyid < 0 || copyid >= HAMMER2_COPYID_COUNT) 346 return (EINVAL); 347 348 hammer2_voldata_lock(hmp); 349 hammer2_voldata_modify(hmp); 350 /*hammer2_volconf_update(hmp, copyid);*/ 351 hammer2_voldata_unlock(hmp); 352 353 return(0); 354 } 355 356 /* 357 * Retrieve communications socket 358 */ 359 static int 360 hammer2_ioctl_socket_get(hammer2_inode_t *ip, void *data) 361 { 362 return (EOPNOTSUPP); 363 } 364 365 /* 366 * Set communications socket for connection 367 */ 368 static int 369 hammer2_ioctl_socket_set(hammer2_inode_t *ip, void *data) 370 { 371 hammer2_ioc_remote_t *remote = data; 372 hammer2_dev_t *hmp; 373 int copyid = remote->copyid; 374 375 hmp = ip->pmp->pfs_hmps[0]; 376 if (hmp == NULL) 377 return (EINVAL); 378 if (copyid < 0 || copyid >= HAMMER2_COPYID_COUNT) 379 return (EINVAL); 380 381 hammer2_voldata_lock(hmp); 382 hammer2_voldata_unlock(hmp); 383 384 return(0); 385 } 386 387 /* 388 * Used to scan and retrieve PFS information. PFS's are directories under 389 * the super-root. 390 * 391 * To scan PFSs pass name_key=0. The function will scan for the next 392 * PFS and set all fields, as well as set name_next to the next key. 393 * When no PFSs remain, name_next is set to (hammer2_key_t)-1. 394 * 395 * To retrieve a particular PFS by key, specify the key but note that 396 * the ioctl will return the lowest key >= specified_key, so the caller 397 * must verify the key. 398 * 399 * To retrieve the PFS associated with the file descriptor, pass 400 * name_key set to (hammer2_key_t)-1. 401 */ 402 static int 403 hammer2_ioctl_pfs_get(hammer2_inode_t *ip, void *data) 404 { 405 const hammer2_inode_data_t *ripdata; 406 hammer2_dev_t *hmp; 407 hammer2_ioc_pfs_t *pfs; 408 hammer2_chain_t *parent; 409 hammer2_chain_t *chain; 410 hammer2_key_t key_next; 411 hammer2_key_t save_key; 412 int error; 413 414 hmp = ip->pmp->pfs_hmps[0]; 415 if (hmp == NULL) 416 return (EINVAL); 417 418 pfs = data; 419 save_key = pfs->name_key; 420 error = 0; 421 422 /* 423 * Setup 424 */ 425 if (save_key == (hammer2_key_t)-1) { 426 hammer2_inode_lock(ip->pmp->iroot, 0); 427 parent = NULL; 428 chain = hammer2_inode_chain(ip->pmp->iroot, 0, 429 HAMMER2_RESOLVE_ALWAYS | 430 HAMMER2_RESOLVE_SHARED); 431 } else { 432 hammer2_inode_lock(hmp->spmp->iroot, 0); 433 parent = hammer2_inode_chain(hmp->spmp->iroot, 0, 434 HAMMER2_RESOLVE_ALWAYS | 435 HAMMER2_RESOLVE_SHARED); 436 chain = hammer2_chain_lookup(&parent, &key_next, 437 pfs->name_key, HAMMER2_KEY_MAX, 438 &error, 439 HAMMER2_LOOKUP_SHARED); 440 } 441 442 /* 443 * Locate next PFS 444 */ 445 while (chain) { 446 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE) 447 break; 448 if (parent == NULL) { 449 hammer2_chain_unlock(chain); 450 hammer2_chain_drop(chain); 451 chain = NULL; 452 break; 453 } 454 chain = hammer2_chain_next(&parent, chain, &key_next, 455 key_next, HAMMER2_KEY_MAX, 456 &error, 457 HAMMER2_LOOKUP_SHARED); 458 } 459 error = hammer2_error_to_errno(error); 460 461 /* 462 * Load the data being returned by the ioctl. 463 */ 464 if (chain && chain->error == 0) { 465 ripdata = &chain->data->ipdata; 466 pfs->name_key = ripdata->meta.name_key; 467 pfs->pfs_type = ripdata->meta.pfs_type; 468 pfs->pfs_subtype = ripdata->meta.pfs_subtype; 469 pfs->pfs_clid = ripdata->meta.pfs_clid; 470 pfs->pfs_fsid = ripdata->meta.pfs_fsid; 471 KKASSERT(ripdata->meta.name_len < sizeof(pfs->name)); 472 bcopy(ripdata->filename, pfs->name, ripdata->meta.name_len); 473 pfs->name[ripdata->meta.name_len] = 0; 474 ripdata = NULL; /* safety */ 475 476 /* 477 * Calculate name_next, if any. We are only accessing 478 * chain->bref so we can ignore chain->error (if the key 479 * is used later it will error then). 480 */ 481 if (parent == NULL) { 482 pfs->name_next = (hammer2_key_t)-1; 483 } else { 484 chain = hammer2_chain_next(&parent, chain, &key_next, 485 key_next, HAMMER2_KEY_MAX, 486 &error, 487 HAMMER2_LOOKUP_SHARED); 488 if (chain) 489 pfs->name_next = chain->bref.key; 490 else 491 pfs->name_next = (hammer2_key_t)-1; 492 } 493 } else { 494 pfs->name_next = (hammer2_key_t)-1; 495 error = ENOENT; 496 } 497 498 /* 499 * Cleanup 500 */ 501 if (chain) { 502 hammer2_chain_unlock(chain); 503 hammer2_chain_drop(chain); 504 } 505 if (parent) { 506 hammer2_chain_unlock(parent); 507 hammer2_chain_drop(parent); 508 } 509 if (save_key == (hammer2_key_t)-1) { 510 hammer2_inode_unlock(ip->pmp->iroot); 511 } else { 512 hammer2_inode_unlock(hmp->spmp->iroot); 513 } 514 515 return (error); 516 } 517 518 /* 519 * Find a specific PFS by name 520 */ 521 static int 522 hammer2_ioctl_pfs_lookup(hammer2_inode_t *ip, void *data) 523 { 524 const hammer2_inode_data_t *ripdata; 525 hammer2_dev_t *hmp; 526 hammer2_ioc_pfs_t *pfs; 527 hammer2_chain_t *parent; 528 hammer2_chain_t *chain; 529 hammer2_key_t key_next; 530 hammer2_key_t lhc; 531 int error; 532 size_t len; 533 534 hmp = ip->pmp->pfs_hmps[0]; 535 if (hmp == NULL) 536 return (EINVAL); 537 538 pfs = data; 539 error = 0; 540 541 hammer2_inode_lock(hmp->spmp->iroot, HAMMER2_RESOLVE_SHARED); 542 parent = hammer2_inode_chain(hmp->spmp->iroot, 0, 543 HAMMER2_RESOLVE_ALWAYS | 544 HAMMER2_RESOLVE_SHARED); 545 546 pfs->name[sizeof(pfs->name) - 1] = 0; 547 len = strlen(pfs->name); 548 lhc = hammer2_dirhash(pfs->name, len); 549 550 chain = hammer2_chain_lookup(&parent, &key_next, 551 lhc, lhc + HAMMER2_DIRHASH_LOMASK, 552 &error, HAMMER2_LOOKUP_SHARED); 553 while (chain) { 554 if (hammer2_chain_dirent_test(chain, pfs->name, len)) 555 break; 556 chain = hammer2_chain_next(&parent, chain, &key_next, 557 key_next, 558 lhc + HAMMER2_DIRHASH_LOMASK, 559 &error, HAMMER2_LOOKUP_SHARED); 560 } 561 error = hammer2_error_to_errno(error); 562 563 /* 564 * Load the data being returned by the ioctl. 565 */ 566 if (chain && chain->error == 0) { 567 KKASSERT(chain->bref.type == HAMMER2_BREF_TYPE_INODE); 568 ripdata = &chain->data->ipdata; 569 pfs->name_key = ripdata->meta.name_key; 570 pfs->pfs_type = ripdata->meta.pfs_type; 571 pfs->pfs_subtype = ripdata->meta.pfs_subtype; 572 pfs->pfs_clid = ripdata->meta.pfs_clid; 573 pfs->pfs_fsid = ripdata->meta.pfs_fsid; 574 ripdata = NULL; 575 576 hammer2_chain_unlock(chain); 577 hammer2_chain_drop(chain); 578 } else if (error == 0) { 579 error = ENOENT; 580 } 581 if (parent) { 582 hammer2_chain_unlock(parent); 583 hammer2_chain_drop(parent); 584 } 585 hammer2_inode_unlock(hmp->spmp->iroot); 586 587 return (error); 588 } 589 590 /* 591 * Create a new PFS under the super-root 592 */ 593 static int 594 hammer2_ioctl_pfs_create(hammer2_inode_t *ip, void *data) 595 { 596 hammer2_inode_data_t *nipdata; 597 hammer2_chain_t *nchain; 598 hammer2_dev_t *hmp; 599 hammer2_dev_t *force_local; 600 hammer2_ioc_pfs_t *pfs; 601 hammer2_inode_t *nip; 602 hammer2_tid_t mtid; 603 int error; 604 605 hmp = ip->pmp->pfs_hmps[0]; /* XXX */ 606 if (hmp == NULL) 607 return (EINVAL); 608 609 pfs = data; 610 nip = NULL; 611 612 if (pfs->name[0] == 0) 613 return(EINVAL); 614 pfs->name[sizeof(pfs->name) - 1] = 0; /* ensure 0-termination */ 615 616 if (hammer2_ioctl_pfs_lookup(ip, pfs) == 0) 617 return(EEXIST); 618 619 hammer2_trans_init(hmp->spmp, HAMMER2_TRANS_ISFLUSH); 620 mtid = hammer2_trans_sub(hmp->spmp); 621 nip = hammer2_inode_create_pfs(hmp->spmp, pfs->name, strlen(pfs->name), 622 &error); 623 if (error == 0) { 624 atomic_set_int(&nip->flags, HAMMER2_INODE_NOSIDEQ); 625 hammer2_inode_modify(nip); 626 nchain = hammer2_inode_chain(nip, 0, HAMMER2_RESOLVE_ALWAYS); 627 error = hammer2_chain_modify(nchain, mtid, 0, 0); 628 KKASSERT(error == 0); 629 nipdata = &nchain->data->ipdata; 630 631 nip->meta.pfs_type = pfs->pfs_type; 632 nip->meta.pfs_subtype = pfs->pfs_subtype; 633 nip->meta.pfs_clid = pfs->pfs_clid; 634 nip->meta.pfs_fsid = pfs->pfs_fsid; 635 nip->meta.op_flags |= HAMMER2_OPFLAG_PFSROOT; 636 637 /* 638 * Set default compression and check algorithm. This 639 * can be changed later. 640 * 641 * Do not allow compression on PFS's with the special name 642 * "boot", the boot loader can't decompress (yet). 643 */ 644 nip->meta.comp_algo = 645 HAMMER2_ENC_ALGO(HAMMER2_COMP_NEWFS_DEFAULT); 646 nip->meta.check_algo = 647 HAMMER2_ENC_ALGO( HAMMER2_CHECK_XXHASH64); 648 649 if (strcasecmp(pfs->name, "boot") == 0) { 650 nip->meta.comp_algo = 651 HAMMER2_ENC_ALGO(HAMMER2_COMP_AUTOZERO); 652 } 653 654 /* 655 * Super-root isn't mounted, fsync it 656 */ 657 hammer2_chain_unlock(nchain); 658 hammer2_inode_ref(nip); 659 hammer2_inode_unlock(nip); 660 hammer2_inode_chain_sync(nip); 661 hammer2_inode_chain_flush(nip, HAMMER2_XOP_INODE_STOP | 662 HAMMER2_XOP_FSSYNC); 663 hammer2_inode_drop(nip); 664 /* nip is dead */ 665 666 /* 667 * We still have a ref on the chain, relock and associate 668 * with an appropriate PFS. 669 */ 670 force_local = (hmp->hflags & HMNT2_LOCAL) ? hmp : NULL; 671 672 hammer2_chain_lock(nchain, HAMMER2_RESOLVE_ALWAYS); 673 nipdata = &nchain->data->ipdata; 674 kprintf("ADD LOCAL PFS (IOCTL): %s\n", nipdata->filename); 675 hammer2_pfsalloc(nchain, nipdata, 676 nchain->bref.modify_tid, force_local); 677 678 hammer2_chain_unlock(nchain); 679 hammer2_chain_drop(nchain); 680 } 681 hammer2_trans_done(hmp->spmp, HAMMER2_TRANS_ISFLUSH | 682 HAMMER2_TRANS_SIDEQ); 683 684 return (error); 685 } 686 687 /* 688 * Destroy an existing PFS under the super-root 689 */ 690 static int 691 hammer2_ioctl_pfs_delete(hammer2_inode_t *ip, void *data) 692 { 693 hammer2_ioc_pfs_t *pfs = data; 694 hammer2_dev_t *hmp; 695 hammer2_pfs_t *spmp; 696 hammer2_pfs_t *pmp; 697 hammer2_xop_unlink_t *xop; 698 hammer2_inode_t *dip; 699 hammer2_inode_t *iroot; 700 int error; 701 int i; 702 703 /* 704 * The PFS should be probed, so we should be able to 705 * locate it. We only delete the PFS from the 706 * specific H2 block device (hmp), not all of 707 * them. We must remove the PFS from the cluster 708 * before we can destroy it. 709 */ 710 hmp = ip->pmp->pfs_hmps[0]; 711 if (hmp == NULL) 712 return (EINVAL); 713 714 pfs->name[sizeof(pfs->name) - 1] = 0; /* ensure termination */ 715 716 lockmgr(&hammer2_mntlk, LK_EXCLUSIVE); 717 718 TAILQ_FOREACH(pmp, &hammer2_pfslist, mntentry) { 719 for (i = 0; i < HAMMER2_MAXCLUSTER; ++i) { 720 if (pmp->pfs_hmps[i] != hmp) 721 continue; 722 if (pmp->pfs_names[i] && 723 strcmp(pmp->pfs_names[i], pfs->name) == 0) { 724 break; 725 } 726 } 727 if (i != HAMMER2_MAXCLUSTER) 728 break; 729 } 730 731 if (pmp == NULL) { 732 lockmgr(&hammer2_mntlk, LK_RELEASE); 733 return ENOENT; 734 } 735 736 /* 737 * Ok, we found the pmp and we have the index. Permanently remove 738 * the PFS from the cluster 739 */ 740 iroot = pmp->iroot; 741 kprintf("FOUND PFS %s CLINDEX %d\n", pfs->name, i); 742 hammer2_pfsdealloc(pmp, i, 1); 743 744 lockmgr(&hammer2_mntlk, LK_RELEASE); 745 746 /* 747 * Now destroy the PFS under its device using the per-device 748 * super-root. 749 */ 750 spmp = hmp->spmp; 751 dip = spmp->iroot; 752 hammer2_trans_init(spmp, 0); 753 hammer2_inode_lock(dip, 0); 754 755 xop = hammer2_xop_alloc(dip, HAMMER2_XOP_MODIFYING); 756 hammer2_xop_setname(&xop->head, pfs->name, strlen(pfs->name)); 757 xop->isdir = 2; 758 xop->dopermanent = H2DOPERM_PERMANENT | H2DOPERM_FORCE; 759 hammer2_xop_start(&xop->head, &hammer2_unlink_desc); 760 761 error = hammer2_xop_collect(&xop->head, 0); 762 763 hammer2_inode_unlock(dip); 764 765 #if 0 766 if (error == 0) { 767 ip = hammer2_inode_get(dip->pmp, &xop->head, -1, -1); 768 hammer2_xop_retire(&xop->head, HAMMER2_XOPMASK_VOP); 769 if (ip) { 770 hammer2_inode_unlink_finisher(ip, 0); 771 hammer2_inode_unlock(ip); 772 } 773 } else { 774 hammer2_xop_retire(&xop->head, HAMMER2_XOPMASK_VOP); 775 } 776 #endif 777 hammer2_xop_retire(&xop->head, HAMMER2_XOPMASK_VOP); 778 779 hammer2_trans_done(spmp, HAMMER2_TRANS_SIDEQ); 780 781 return (hammer2_error_to_errno(error)); 782 } 783 784 static int 785 hammer2_ioctl_pfs_snapshot(hammer2_inode_t *ip, void *data) 786 { 787 hammer2_ioc_pfs_t *pfs = data; 788 hammer2_dev_t *hmp; 789 hammer2_pfs_t *pmp; 790 hammer2_chain_t *chain; 791 hammer2_inode_t *nip; 792 hammer2_tid_t mtid; 793 size_t name_len; 794 hammer2_key_t lhc; 795 int error; 796 #if 0 797 uuid_t opfs_clid; 798 #endif 799 800 if (pfs->name[0] == 0) 801 return(EINVAL); 802 if (pfs->name[sizeof(pfs->name)-1] != 0) 803 return(EINVAL); 804 805 pmp = ip->pmp; 806 ip = pmp->iroot; 807 808 hmp = pmp->pfs_hmps[0]; 809 if (hmp == NULL) 810 return (EINVAL); 811 812 lockmgr(&hmp->bulklk, LK_EXCLUSIVE); 813 814 /* 815 * NOSYNC is for debugging. We skip the filesystem sync and use 816 * a normal transaction (which is less likely to stall). used for 817 * testing filesystem consistency. 818 * 819 * In normal mode we sync the filesystem and use a flush transaction. 820 */ 821 if (pfs->pfs_flags & HAMMER2_PFSFLAGS_NOSYNC) { 822 hammer2_trans_init(pmp, 0); 823 } else { 824 hammer2_vfs_sync(pmp->mp, MNT_WAIT); 825 hammer2_trans_init(pmp, HAMMER2_TRANS_ISFLUSH); 826 } 827 mtid = hammer2_trans_sub(pmp); 828 hammer2_inode_lock(ip, 0); 829 hammer2_inode_modify(ip); 830 ip->meta.pfs_lsnap_tid = mtid; 831 832 /* XXX cluster it! */ 833 chain = hammer2_inode_chain(ip, 0, HAMMER2_RESOLVE_ALWAYS); 834 835 name_len = strlen(pfs->name); 836 lhc = hammer2_dirhash(pfs->name, name_len); 837 838 /* 839 * Get the clid 840 */ 841 hmp = chain->hmp; 842 843 /* 844 * Create the snapshot directory under the super-root 845 * 846 * Set PFS type, generate a unique filesystem id, and generate 847 * a cluster id. Use the same clid when snapshotting a PFS root, 848 * which theoretically allows the snapshot to be used as part of 849 * the same cluster (perhaps as a cache). 850 * 851 * Copy the (flushed) blockref array. Theoretically we could use 852 * chain_duplicate() but it becomes difficult to disentangle 853 * the shared core so for now just brute-force it. 854 */ 855 hammer2_chain_unlock(chain); 856 nip = hammer2_inode_create_pfs(hmp->spmp, pfs->name, name_len, &error); 857 hammer2_chain_lock(chain, HAMMER2_RESOLVE_ALWAYS); 858 859 if (nip) { 860 hammer2_dev_t *force_local; 861 hammer2_chain_t *nchain; 862 hammer2_inode_data_t *wipdata; 863 hammer2_key_t starting_inum; 864 865 atomic_set_int(&nip->flags, HAMMER2_INODE_NOSIDEQ); 866 hammer2_inode_modify(nip); 867 nchain = hammer2_inode_chain(nip, 0, HAMMER2_RESOLVE_ALWAYS); 868 error = hammer2_chain_modify(nchain, mtid, 0, 0); 869 KKASSERT(error == 0); 870 wipdata = &nchain->data->ipdata; 871 872 starting_inum = ip->pmp->inode_tid + 1; 873 nip->meta.pfs_inum = starting_inum; 874 nip->meta.pfs_type = HAMMER2_PFSTYPE_MASTER; 875 nip->meta.pfs_subtype = HAMMER2_PFSSUBTYPE_SNAPSHOT; 876 nip->meta.op_flags |= HAMMER2_OPFLAG_PFSROOT; 877 nchain->bref.embed.stats = chain->bref.embed.stats; 878 879 kern_uuidgen(&nip->meta.pfs_fsid, 1); 880 881 #if 0 882 /* 883 * Give the snapshot its own private cluster id. As a 884 * snapshot no further synchronization with the original 885 * cluster will be done. 886 */ 887 if (chain->flags & HAMMER2_CHAIN_PFSBOUNDARY) 888 nip->meta.pfs_clid = opfs_clid; 889 else 890 kern_uuidgen(&nip->meta.pfs_clid, 1); 891 #endif 892 kern_uuidgen(&nip->meta.pfs_clid, 1); 893 nchain->bref.flags |= HAMMER2_BREF_FLAG_PFSROOT; 894 895 /* XXX hack blockset copy */ 896 /* XXX doesn't work with real cluster */ 897 wipdata->meta = nip->meta; 898 hammer2_spin_ex(&pmp->inum_spin); 899 wipdata->u.blockset = pmp->pfs_iroot_blocksets[0]; 900 hammer2_spin_unex(&pmp->inum_spin); 901 902 KKASSERT(wipdata == &nchain->data->ipdata); 903 904 hammer2_chain_unlock(nchain); 905 hammer2_inode_ref(nip); 906 hammer2_inode_unlock(nip); 907 hammer2_inode_chain_sync(nip); 908 hammer2_inode_chain_flush(nip, HAMMER2_XOP_INODE_STOP | 909 HAMMER2_XOP_FSSYNC); 910 /* XXX | HAMMER2_XOP_VOLHDR */ 911 hammer2_inode_drop(nip); 912 /* nip is dead */ 913 914 force_local = (hmp->hflags & HMNT2_LOCAL) ? hmp : NULL; 915 916 hammer2_chain_lock(nchain, HAMMER2_RESOLVE_ALWAYS); 917 wipdata = &nchain->data->ipdata; 918 kprintf("SNAPSHOT LOCAL PFS (IOCTL): %s\n", wipdata->filename); 919 hammer2_pfsalloc(nchain, wipdata, nchain->bref.modify_tid, 920 force_local); 921 nchain->pmp->inode_tid = starting_inum; 922 923 hammer2_chain_unlock(nchain); 924 hammer2_chain_drop(nchain); 925 } 926 927 hammer2_chain_unlock(chain); 928 hammer2_chain_drop(chain); 929 930 hammer2_inode_unlock(ip); 931 if (pfs->pfs_flags & HAMMER2_PFSFLAGS_NOSYNC) { 932 hammer2_trans_done(pmp, 0); 933 } else { 934 hammer2_trans_done(pmp, HAMMER2_TRANS_ISFLUSH | 935 HAMMER2_TRANS_SIDEQ); 936 } 937 938 lockmgr(&hmp->bulklk, LK_RELEASE); 939 940 return (hammer2_error_to_errno(error)); 941 } 942 943 /* 944 * Retrieve the raw inode structure, non-inclusive of node-specific data. 945 */ 946 static int 947 hammer2_ioctl_inode_get(hammer2_inode_t *ip, void *data) 948 { 949 hammer2_ioc_inode_t *ino; 950 hammer2_chain_t *chain; 951 int error; 952 int i; 953 954 ino = data; 955 error = 0; 956 957 hammer2_inode_lock(ip, HAMMER2_RESOLVE_SHARED); 958 ino->data_count = 0; 959 ino->inode_count = 0; 960 for (i = 0; i < ip->cluster.nchains; ++i) { 961 if ((chain = ip->cluster.array[i].chain) != NULL) { 962 if (ino->data_count < 963 chain->bref.embed.stats.data_count) { 964 ino->data_count = 965 chain->bref.embed.stats.data_count; 966 } 967 if (ino->inode_count < 968 chain->bref.embed.stats.inode_count) { 969 ino->inode_count = 970 chain->bref.embed.stats.inode_count; 971 } 972 } 973 } 974 bzero(&ino->ip_data, sizeof(ino->ip_data)); 975 ino->ip_data.meta = ip->meta; 976 ino->kdata = ip; 977 hammer2_inode_unlock(ip); 978 979 return hammer2_error_to_errno(error); 980 } 981 982 /* 983 * Set various parameters in an inode which cannot be set through 984 * normal filesystem VNOPS. 985 */ 986 static int 987 hammer2_ioctl_inode_set(hammer2_inode_t *ip, void *data) 988 { 989 hammer2_ioc_inode_t *ino = data; 990 int error = 0; 991 992 hammer2_trans_init(ip->pmp, 0); 993 hammer2_inode_lock(ip, 0); 994 995 if ((ino->flags & HAMMER2IOC_INODE_FLAG_CHECK) && 996 ip->meta.check_algo != ino->ip_data.meta.check_algo) { 997 hammer2_inode_modify(ip); 998 ip->meta.check_algo = ino->ip_data.meta.check_algo; 999 } 1000 if ((ino->flags & HAMMER2IOC_INODE_FLAG_COMP) && 1001 ip->meta.comp_algo != ino->ip_data.meta.comp_algo) { 1002 hammer2_inode_modify(ip); 1003 ip->meta.comp_algo = ino->ip_data.meta.comp_algo; 1004 } 1005 ino->kdata = ip; 1006 1007 /* Ignore these flags for now...*/ 1008 if ((ino->flags & HAMMER2IOC_INODE_FLAG_IQUOTA) && 1009 ip->meta.inode_quota != ino->ip_data.meta.inode_quota) { 1010 hammer2_inode_modify(ip); 1011 ip->meta.inode_quota = ino->ip_data.meta.inode_quota; 1012 } 1013 if ((ino->flags & HAMMER2IOC_INODE_FLAG_DQUOTA) && 1014 ip->meta.data_quota != ino->ip_data.meta.data_quota) { 1015 hammer2_inode_modify(ip); 1016 ip->meta.data_quota = ino->ip_data.meta.data_quota; 1017 } 1018 if ((ino->flags & HAMMER2IOC_INODE_FLAG_COPIES) && 1019 ip->meta.ncopies != ino->ip_data.meta.ncopies) { 1020 hammer2_inode_modify(ip); 1021 ip->meta.ncopies = ino->ip_data.meta.ncopies; 1022 } 1023 hammer2_inode_unlock(ip); 1024 hammer2_trans_done(ip->pmp, HAMMER2_TRANS_SIDEQ); 1025 1026 return (hammer2_error_to_errno(error)); 1027 } 1028 1029 static 1030 int 1031 hammer2_ioctl_debug_dump(hammer2_inode_t *ip, u_int flags) 1032 { 1033 hammer2_chain_t *chain; 1034 int count = 100000; 1035 int i; 1036 1037 for (i = 0; i < ip->cluster.nchains; ++i) { 1038 chain = ip->cluster.array[i].chain; 1039 if (chain == NULL) 1040 continue; 1041 hammer2_dump_chain(chain, 0, &count, 'i', flags); 1042 } 1043 return 0; 1044 } 1045 1046 /* 1047 * Executes one flush/free pass per call. If trying to recover 1048 * data we just freed up a moment ago it can take up to six passes 1049 * to fully free the blocks. Note that passes occur automatically based 1050 * on free space as the storage fills up, but manual passes may be needed 1051 * if storage becomes almost completely full. 1052 */ 1053 static 1054 int 1055 hammer2_ioctl_bulkfree_scan(hammer2_inode_t *ip, void *data) 1056 { 1057 hammer2_ioc_bulkfree_t *bfi = data; 1058 hammer2_dev_t *hmp; 1059 hammer2_pfs_t *pmp; 1060 hammer2_chain_t *vchain; 1061 int error; 1062 int didsnap; 1063 1064 pmp = ip->pmp; 1065 ip = pmp->iroot; 1066 1067 hmp = pmp->pfs_hmps[0]; 1068 if (hmp == NULL) 1069 return (EINVAL); 1070 if (bfi == NULL) 1071 return (EINVAL); 1072 1073 /* 1074 * Bulkfree has to be serialized to guarantee at least one sync 1075 * inbetween bulkfrees. 1076 */ 1077 error = lockmgr(&hmp->bflock, LK_EXCLUSIVE | LK_PCATCH); 1078 if (error) 1079 return error; 1080 1081 /* 1082 * sync the filesystem and obtain a snapshot of the synchronized 1083 * hmp volume header. We treat the snapshot as an independent 1084 * entity. 1085 * 1086 * If ENOSPC occurs we should continue, because bulkfree is the only 1087 * way to fix that. The flush will have flushed everything it could 1088 * and not left any modified chains. Otherwise an error is fatal. 1089 */ 1090 error = hammer2_vfs_sync(pmp->mp, MNT_WAIT); 1091 if (error && error != ENOSPC) 1092 goto failed; 1093 1094 /* 1095 * If we have an ENOSPC error we have to bulkfree on the live 1096 * topology. Otherwise we can bulkfree on a snapshot. 1097 */ 1098 if (error) { 1099 kprintf("hammer2: WARNING! Bulkfree forced to use live " 1100 "topology\n"); 1101 vchain = &hmp->vchain; 1102 hammer2_chain_ref(vchain); 1103 didsnap = 0; 1104 } else { 1105 vchain = hammer2_chain_bulksnap(hmp); 1106 didsnap = 1; 1107 } 1108 1109 /* 1110 * Bulkfree on a snapshot does not need a transaction, which allows 1111 * it to run concurrently with any operation other than another 1112 * bulkfree. 1113 * 1114 * If we are running bulkfree on the live topology we have to be 1115 * in a FLUSH transaction. 1116 */ 1117 if (didsnap == 0) 1118 hammer2_trans_init(pmp, HAMMER2_TRANS_ISFLUSH); 1119 1120 if (bfi) { 1121 hammer2_thr_freeze(&hmp->bfthr); 1122 error = hammer2_bulkfree_pass(hmp, vchain, bfi); 1123 hammer2_thr_unfreeze(&hmp->bfthr); 1124 } 1125 if (didsnap) { 1126 hammer2_chain_bulkdrop(vchain); 1127 } else { 1128 hammer2_chain_drop(vchain); 1129 hammer2_trans_done(pmp, HAMMER2_TRANS_ISFLUSH | 1130 HAMMER2_TRANS_SIDEQ); 1131 } 1132 error = hammer2_error_to_errno(error); 1133 1134 failed: 1135 lockmgr(&hmp->bflock, LK_RELEASE); 1136 return error; 1137 } 1138 1139 /* 1140 * Unconditionally delete meta-data in a hammer2 filesystem 1141 */ 1142 static 1143 int 1144 hammer2_ioctl_destroy(hammer2_inode_t *ip, void *data) 1145 { 1146 hammer2_ioc_destroy_t *iocd = data; 1147 hammer2_pfs_t *pmp = ip->pmp; 1148 int error; 1149 1150 if (pmp->ronly) { 1151 error = EROFS; 1152 return error; 1153 } 1154 1155 switch(iocd->cmd) { 1156 case HAMMER2_DELETE_FILE: 1157 /* 1158 * Destroy a bad directory entry by name. Caller must 1159 * pass the directory as fd. 1160 */ 1161 { 1162 hammer2_xop_unlink_t *xop; 1163 1164 if (iocd->path[sizeof(iocd->path)-1]) { 1165 error = EINVAL; 1166 break; 1167 } 1168 if (ip->meta.type != HAMMER2_OBJTYPE_DIRECTORY) { 1169 error = EINVAL; 1170 break; 1171 } 1172 hammer2_pfs_memory_wait(pmp); 1173 hammer2_trans_init(pmp, 0); 1174 hammer2_inode_lock(ip, 0); 1175 1176 xop = hammer2_xop_alloc(ip, HAMMER2_XOP_MODIFYING); 1177 hammer2_xop_setname(&xop->head, iocd->path, strlen(iocd->path)); 1178 xop->isdir = -1; 1179 xop->dopermanent = H2DOPERM_PERMANENT | 1180 H2DOPERM_FORCE | 1181 H2DOPERM_IGNINO; 1182 hammer2_xop_start(&xop->head, &hammer2_unlink_desc); 1183 1184 error = hammer2_xop_collect(&xop->head, 0); 1185 error = hammer2_error_to_errno(error); 1186 hammer2_inode_unlock(ip); 1187 hammer2_xop_retire(&xop->head, HAMMER2_XOPMASK_VOP); 1188 hammer2_trans_done(pmp, HAMMER2_TRANS_SIDEQ); 1189 } 1190 break; 1191 case HAMMER2_DELETE_INUM: 1192 /* 1193 * Destroy a bad inode by inode number. 1194 */ 1195 { 1196 hammer2_xop_lookup_t *xop; 1197 1198 if (iocd->inum < 1) { 1199 error = EINVAL; 1200 break; 1201 } 1202 hammer2_pfs_memory_wait(pmp); 1203 hammer2_trans_init(pmp, 0); 1204 1205 xop = hammer2_xop_alloc(pmp->iroot, HAMMER2_XOP_MODIFYING); 1206 xop->lhc = iocd->inum; 1207 hammer2_xop_start(&xop->head, &hammer2_delete_desc); 1208 error = hammer2_xop_collect(&xop->head, 0); 1209 error = hammer2_error_to_errno(error); 1210 hammer2_xop_retire(&xop->head, HAMMER2_XOPMASK_VOP); 1211 hammer2_trans_done(pmp, HAMMER2_TRANS_SIDEQ); 1212 } 1213 break; 1214 default: 1215 error = EINVAL; 1216 break; 1217 } 1218 return error; 1219 } 1220