1 /* 2 * Copyright (c) 2011-2015 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); 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 66 int 67 hammer2_ioctl(hammer2_inode_t *ip, u_long com, void *data, int fflag, 68 struct ucred *cred) 69 { 70 int error; 71 72 /* 73 * Standard root cred checks, will be selectively ignored below 74 * for ioctls that do not require root creds. 75 */ 76 error = priv_check_cred(cred, PRIV_HAMMER_IOCTL, 0); 77 78 switch(com) { 79 case HAMMER2IOC_VERSION_GET: 80 error = hammer2_ioctl_version_get(ip, data); 81 break; 82 case HAMMER2IOC_RECLUSTER: 83 if (error == 0) 84 error = hammer2_ioctl_recluster(ip, data); 85 break; 86 case HAMMER2IOC_REMOTE_SCAN: 87 if (error == 0) 88 error = hammer2_ioctl_remote_scan(ip, data); 89 break; 90 case HAMMER2IOC_REMOTE_ADD: 91 if (error == 0) 92 error = hammer2_ioctl_remote_add(ip, data); 93 break; 94 case HAMMER2IOC_REMOTE_DEL: 95 if (error == 0) 96 error = hammer2_ioctl_remote_del(ip, data); 97 break; 98 case HAMMER2IOC_REMOTE_REP: 99 if (error == 0) 100 error = hammer2_ioctl_remote_rep(ip, data); 101 break; 102 case HAMMER2IOC_SOCKET_GET: 103 if (error == 0) 104 error = hammer2_ioctl_socket_get(ip, data); 105 break; 106 case HAMMER2IOC_SOCKET_SET: 107 if (error == 0) 108 error = hammer2_ioctl_socket_set(ip, data); 109 break; 110 case HAMMER2IOC_PFS_GET: 111 if (error == 0) 112 error = hammer2_ioctl_pfs_get(ip, data); 113 break; 114 case HAMMER2IOC_PFS_LOOKUP: 115 if (error == 0) 116 error = hammer2_ioctl_pfs_lookup(ip, data); 117 break; 118 case HAMMER2IOC_PFS_CREATE: 119 if (error == 0) 120 error = hammer2_ioctl_pfs_create(ip, data); 121 break; 122 case HAMMER2IOC_PFS_DELETE: 123 if (error == 0) 124 error = hammer2_ioctl_pfs_delete(ip, data); 125 break; 126 case HAMMER2IOC_PFS_SNAPSHOT: 127 if (error == 0) 128 error = hammer2_ioctl_pfs_snapshot(ip, data); 129 break; 130 case HAMMER2IOC_INODE_GET: 131 error = hammer2_ioctl_inode_get(ip, data); 132 break; 133 case HAMMER2IOC_INODE_SET: 134 if (error == 0) 135 error = hammer2_ioctl_inode_set(ip, data); 136 break; 137 case HAMMER2IOC_BULKFREE_SCAN: 138 error = hammer2_ioctl_bulkfree_scan(ip, data); 139 break; 140 /*case HAMMER2IOC_INODE_COMP_SET: 141 error = hammer2_ioctl_inode_comp_set(ip, data); 142 break; 143 case HAMMER2IOC_INODE_COMP_REC_SET: 144 error = hammer2_ioctl_inode_comp_rec_set(ip, data); 145 break; 146 case HAMMER2IOC_INODE_COMP_REC_SET2: 147 error = hammer2_ioctl_inode_comp_rec_set2(ip, data); 148 break;*/ 149 case HAMMER2IOC_DEBUG_DUMP: 150 error = hammer2_ioctl_debug_dump(ip); 151 break; 152 default: 153 error = EOPNOTSUPP; 154 break; 155 } 156 return (error); 157 } 158 159 /* 160 * Retrieve version and basic info 161 */ 162 static int 163 hammer2_ioctl_version_get(hammer2_inode_t *ip, void *data) 164 { 165 hammer2_ioc_version_t *version = data; 166 hammer2_dev_t *hmp; 167 168 hmp = ip->pmp->pfs_hmps[0]; 169 if (hmp) 170 version->version = hmp->voldata.version; 171 else 172 version->version = -1; 173 return 0; 174 } 175 176 static int 177 hammer2_ioctl_recluster(hammer2_inode_t *ip, void *data) 178 { 179 hammer2_ioc_recluster_t *recl = data; 180 struct file *fp; 181 hammer2_cluster_t *cluster; 182 int error; 183 184 fp = holdfp(curproc->p_fd, recl->fd, -1); 185 if (fp) { 186 kprintf("reconnect to cluster: XXX "); 187 cluster = &ip->pmp->iroot->cluster; 188 if (cluster->nchains != 1 || cluster->focus == NULL) { 189 kprintf("not a local device mount\n"); 190 error = EINVAL; 191 } else { 192 hammer2_cluster_reconnect(cluster->focus->hmp, fp); 193 kprintf("ok\n"); 194 error = 0; 195 } 196 } else { 197 error = EINVAL; 198 } 199 return error; 200 } 201 202 /* 203 * Retrieve information about a remote 204 */ 205 static int 206 hammer2_ioctl_remote_scan(hammer2_inode_t *ip, void *data) 207 { 208 hammer2_dev_t *hmp; 209 hammer2_ioc_remote_t *remote = data; 210 int copyid = remote->copyid; 211 212 hmp = ip->pmp->pfs_hmps[0]; 213 if (hmp == NULL) 214 return (EINVAL); 215 216 if (copyid < 0 || copyid >= HAMMER2_COPYID_COUNT) 217 return (EINVAL); 218 219 hammer2_voldata_lock(hmp); 220 remote->copy1 = hmp->voldata.copyinfo[copyid]; 221 hammer2_voldata_unlock(hmp); 222 223 /* 224 * Adjust nextid (GET only) 225 */ 226 while (++copyid < HAMMER2_COPYID_COUNT && 227 hmp->voldata.copyinfo[copyid].copyid == 0) { 228 ; 229 } 230 if (copyid == HAMMER2_COPYID_COUNT) 231 remote->nextid = -1; 232 else 233 remote->nextid = copyid; 234 235 return(0); 236 } 237 238 /* 239 * Add new remote entry 240 */ 241 static int 242 hammer2_ioctl_remote_add(hammer2_inode_t *ip, void *data) 243 { 244 hammer2_ioc_remote_t *remote = data; 245 hammer2_pfs_t *pmp = ip->pmp; 246 hammer2_dev_t *hmp; 247 int copyid = remote->copyid; 248 int error = 0; 249 250 hmp = pmp->pfs_hmps[0]; 251 if (hmp == NULL) 252 return (EINVAL); 253 if (copyid >= HAMMER2_COPYID_COUNT) 254 return (EINVAL); 255 256 hammer2_voldata_lock(hmp); 257 if (copyid < 0) { 258 for (copyid = 1; copyid < HAMMER2_COPYID_COUNT; ++copyid) { 259 if (hmp->voldata.copyinfo[copyid].copyid == 0) 260 break; 261 } 262 if (copyid == HAMMER2_COPYID_COUNT) { 263 error = ENOSPC; 264 goto failed; 265 } 266 } 267 hammer2_voldata_modify(hmp); 268 remote->copy1.copyid = copyid; 269 hmp->voldata.copyinfo[copyid] = remote->copy1; 270 hammer2_volconf_update(hmp, copyid); 271 failed: 272 hammer2_voldata_unlock(hmp); 273 return (error); 274 } 275 276 /* 277 * Delete existing remote entry 278 */ 279 static int 280 hammer2_ioctl_remote_del(hammer2_inode_t *ip, void *data) 281 { 282 hammer2_ioc_remote_t *remote = data; 283 hammer2_pfs_t *pmp = ip->pmp; 284 hammer2_dev_t *hmp; 285 int copyid = remote->copyid; 286 int error = 0; 287 288 hmp = pmp->pfs_hmps[0]; 289 if (hmp == NULL) 290 return (EINVAL); 291 if (copyid >= HAMMER2_COPYID_COUNT) 292 return (EINVAL); 293 remote->copy1.path[sizeof(remote->copy1.path) - 1] = 0; 294 hammer2_voldata_lock(hmp); 295 if (copyid < 0) { 296 for (copyid = 1; copyid < HAMMER2_COPYID_COUNT; ++copyid) { 297 if (hmp->voldata.copyinfo[copyid].copyid == 0) 298 continue; 299 if (strcmp(remote->copy1.path, 300 hmp->voldata.copyinfo[copyid].path) == 0) { 301 break; 302 } 303 } 304 if (copyid == HAMMER2_COPYID_COUNT) { 305 error = ENOENT; 306 goto failed; 307 } 308 } 309 hammer2_voldata_modify(hmp); 310 hmp->voldata.copyinfo[copyid].copyid = 0; 311 hammer2_volconf_update(hmp, copyid); 312 failed: 313 hammer2_voldata_unlock(hmp); 314 return (error); 315 } 316 317 /* 318 * Replace existing remote entry 319 */ 320 static int 321 hammer2_ioctl_remote_rep(hammer2_inode_t *ip, void *data) 322 { 323 hammer2_ioc_remote_t *remote = data; 324 hammer2_dev_t *hmp; 325 int copyid = remote->copyid; 326 327 hmp = ip->pmp->pfs_hmps[0]; 328 if (hmp == NULL) 329 return (EINVAL); 330 if (copyid < 0 || copyid >= HAMMER2_COPYID_COUNT) 331 return (EINVAL); 332 333 hammer2_voldata_lock(hmp); 334 hammer2_voldata_modify(hmp); 335 /*hammer2_volconf_update(hmp, copyid);*/ 336 hammer2_voldata_unlock(hmp); 337 338 return(0); 339 } 340 341 /* 342 * Retrieve communications socket 343 */ 344 static int 345 hammer2_ioctl_socket_get(hammer2_inode_t *ip, void *data) 346 { 347 return (EOPNOTSUPP); 348 } 349 350 /* 351 * Set communications socket for connection 352 */ 353 static int 354 hammer2_ioctl_socket_set(hammer2_inode_t *ip, void *data) 355 { 356 hammer2_ioc_remote_t *remote = data; 357 hammer2_dev_t *hmp; 358 int copyid = remote->copyid; 359 360 hmp = ip->pmp->pfs_hmps[0]; 361 if (hmp == NULL) 362 return (EINVAL); 363 if (copyid < 0 || copyid >= HAMMER2_COPYID_COUNT) 364 return (EINVAL); 365 366 hammer2_voldata_lock(hmp); 367 hammer2_voldata_unlock(hmp); 368 369 return(0); 370 } 371 372 /* 373 * Used to scan and retrieve PFS information. PFS's are directories under 374 * the super-root. 375 * 376 * To scan PFSs pass name_key=0. The function will scan for the next 377 * PFS and set all fields, as well as set name_next to the next key. 378 * When no PFSs remain, name_next is set to (hammer2_key_t)-1. 379 * 380 * To retrieve a particular PFS by key, specify the key but note that 381 * the ioctl will return the lowest key >= specified_key, so the caller 382 * must verify the key. 383 * 384 * To retrieve the PFS associated with the file descriptor, pass 385 * name_key set to (hammer2_key_t)-1. 386 */ 387 static int 388 hammer2_ioctl_pfs_get(hammer2_inode_t *ip, void *data) 389 { 390 const hammer2_inode_data_t *ripdata; 391 hammer2_dev_t *hmp; 392 hammer2_ioc_pfs_t *pfs; 393 hammer2_chain_t *parent; 394 hammer2_chain_t *chain; 395 hammer2_key_t key_next; 396 hammer2_key_t save_key; 397 int cache_index = -1; 398 int error; 399 400 hmp = ip->pmp->pfs_hmps[0]; 401 if (hmp == NULL) 402 return (EINVAL); 403 404 pfs = data; 405 save_key = pfs->name_key; 406 error = 0; 407 408 /* 409 * Setup 410 */ 411 if (save_key == (hammer2_key_t)-1) { 412 hammer2_inode_lock(ip->pmp->iroot, 0); 413 parent = NULL; 414 chain = hammer2_inode_chain(hmp->spmp->iroot, 0, 415 HAMMER2_RESOLVE_ALWAYS | 416 HAMMER2_RESOLVE_SHARED); 417 } else { 418 hammer2_inode_lock(hmp->spmp->iroot, 0); 419 parent = hammer2_inode_chain(hmp->spmp->iroot, 0, 420 HAMMER2_RESOLVE_ALWAYS | 421 HAMMER2_RESOLVE_SHARED); 422 chain = hammer2_chain_lookup(&parent, &key_next, 423 pfs->name_key, HAMMER2_KEY_MAX, 424 &cache_index, 425 HAMMER2_LOOKUP_SHARED); 426 } 427 428 /* 429 * Locate next PFS 430 */ 431 while (chain) { 432 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE) 433 break; 434 if (parent == NULL) { 435 hammer2_chain_unlock(chain); 436 hammer2_chain_drop(chain); 437 chain = NULL; 438 break; 439 } 440 chain = hammer2_chain_next(&parent, chain, &key_next, 441 key_next, HAMMER2_KEY_MAX, 442 &cache_index, 443 HAMMER2_LOOKUP_SHARED); 444 } 445 446 /* 447 * Load the data being returned by the ioctl. 448 */ 449 if (chain) { 450 ripdata = &chain->data->ipdata; 451 pfs->name_key = ripdata->meta.name_key; 452 pfs->pfs_type = ripdata->meta.pfs_type; 453 pfs->pfs_subtype = ripdata->meta.pfs_subtype; 454 pfs->pfs_clid = ripdata->meta.pfs_clid; 455 pfs->pfs_fsid = ripdata->meta.pfs_fsid; 456 KKASSERT(ripdata->meta.name_len < sizeof(pfs->name)); 457 bcopy(ripdata->filename, pfs->name, ripdata->meta.name_len); 458 pfs->name[ripdata->meta.name_len] = 0; 459 ripdata = NULL; /* safety */ 460 461 /* 462 * Calculate name_next, if any. 463 */ 464 if (parent == NULL) { 465 pfs->name_next = (hammer2_key_t)-1; 466 } else { 467 chain = hammer2_chain_next(&parent, chain, &key_next, 468 key_next, HAMMER2_KEY_MAX, 469 &cache_index, 470 HAMMER2_LOOKUP_SHARED); 471 if (chain) 472 pfs->name_next = chain->bref.key; 473 else 474 pfs->name_next = (hammer2_key_t)-1; 475 } 476 } else { 477 pfs->name_next = (hammer2_key_t)-1; 478 error = ENOENT; 479 } 480 481 /* 482 * Cleanup 483 */ 484 if (chain) { 485 hammer2_chain_unlock(chain); 486 hammer2_chain_drop(chain); 487 } 488 if (parent) { 489 hammer2_chain_unlock(parent); 490 hammer2_chain_drop(parent); 491 } 492 if (save_key == (hammer2_key_t)-1) { 493 hammer2_inode_unlock(ip->pmp->iroot); 494 } else { 495 hammer2_inode_unlock(hmp->spmp->iroot); 496 } 497 498 return (error); 499 } 500 501 /* 502 * Find a specific PFS by name 503 */ 504 static int 505 hammer2_ioctl_pfs_lookup(hammer2_inode_t *ip, void *data) 506 { 507 const hammer2_inode_data_t *ripdata; 508 hammer2_dev_t *hmp; 509 hammer2_ioc_pfs_t *pfs; 510 hammer2_chain_t *parent; 511 hammer2_chain_t *chain; 512 hammer2_key_t key_next; 513 hammer2_key_t lhc; 514 int cache_index = -1; 515 int error; 516 size_t len; 517 518 hmp = ip->pmp->pfs_hmps[0]; 519 if (hmp == NULL) 520 return (EINVAL); 521 522 pfs = data; 523 error = 0; 524 525 hammer2_inode_lock(hmp->spmp->iroot, HAMMER2_RESOLVE_SHARED); 526 parent = hammer2_inode_chain(hmp->spmp->iroot, 0, 527 HAMMER2_RESOLVE_ALWAYS | 528 HAMMER2_RESOLVE_SHARED); 529 530 pfs->name[sizeof(pfs->name) - 1] = 0; 531 len = strlen(pfs->name); 532 lhc = hammer2_dirhash(pfs->name, len); 533 534 chain = hammer2_chain_lookup(&parent, &key_next, 535 lhc, lhc + HAMMER2_DIRHASH_LOMASK, 536 &cache_index, 537 HAMMER2_LOOKUP_SHARED); 538 while (chain) { 539 if (hammer2_chain_dirent_test(chain, pfs->name, len)) 540 break; 541 chain = hammer2_chain_next(&parent, chain, &key_next, 542 key_next, 543 lhc + HAMMER2_DIRHASH_LOMASK, 544 &cache_index, 545 HAMMER2_LOOKUP_SHARED); 546 } 547 548 /* 549 * Load the data being returned by the ioctl. 550 */ 551 if (chain) { 552 KKASSERT(chain->bref.type == HAMMER2_BREF_TYPE_INODE); 553 ripdata = &chain->data->ipdata; 554 pfs->name_key = ripdata->meta.name_key; 555 pfs->pfs_type = ripdata->meta.pfs_type; 556 pfs->pfs_subtype = ripdata->meta.pfs_subtype; 557 pfs->pfs_clid = ripdata->meta.pfs_clid; 558 pfs->pfs_fsid = ripdata->meta.pfs_fsid; 559 ripdata = NULL; 560 561 hammer2_chain_unlock(chain); 562 hammer2_chain_drop(chain); 563 } else { 564 error = ENOENT; 565 } 566 if (parent) { 567 hammer2_chain_unlock(parent); 568 hammer2_chain_drop(parent); 569 } 570 hammer2_inode_unlock(hmp->spmp->iroot); 571 572 return (error); 573 } 574 575 /* 576 * Create a new PFS under the super-root 577 */ 578 static int 579 hammer2_ioctl_pfs_create(hammer2_inode_t *ip, void *data) 580 { 581 hammer2_inode_data_t *nipdata; 582 hammer2_chain_t *nchain; 583 hammer2_dev_t *hmp; 584 hammer2_dev_t *force_local; 585 hammer2_ioc_pfs_t *pfs; 586 hammer2_inode_t *nip; 587 hammer2_tid_t mtid; 588 int error; 589 590 hmp = ip->pmp->pfs_hmps[0]; /* XXX */ 591 if (hmp == NULL) 592 return (EINVAL); 593 594 pfs = data; 595 nip = NULL; 596 597 if (pfs->name[0] == 0) 598 return(EINVAL); 599 pfs->name[sizeof(pfs->name) - 1] = 0; /* ensure 0-termination */ 600 601 if (hammer2_ioctl_pfs_lookup(ip, pfs) == 0) 602 return(EEXIST); 603 604 hammer2_trans_init(hmp->spmp, 0); 605 mtid = hammer2_trans_sub(hmp->spmp); 606 nip = hammer2_inode_create(hmp->spmp->iroot, hmp->spmp->iroot, 607 NULL, NULL, 608 pfs->name, strlen(pfs->name), 0, 609 1, HAMMER2_OBJTYPE_DIRECTORY, 0, 610 HAMMER2_INSERT_PFSROOT, &error); 611 if (error == 0) { 612 hammer2_inode_modify(nip); 613 nchain = hammer2_inode_chain(nip, 0, HAMMER2_RESOLVE_ALWAYS); 614 hammer2_chain_modify(nchain, mtid, 0, 0); 615 nipdata = &nchain->data->ipdata; 616 617 nip->meta.pfs_type = pfs->pfs_type; 618 nip->meta.pfs_subtype = pfs->pfs_subtype; 619 nip->meta.pfs_clid = pfs->pfs_clid; 620 nip->meta.pfs_fsid = pfs->pfs_fsid; 621 nip->meta.op_flags |= HAMMER2_OPFLAG_PFSROOT; 622 623 /* 624 * Set default compression and check algorithm. This 625 * can be changed later. 626 * 627 * Do not allow compression on PFS's with the special name 628 * "boot", the boot loader can't decompress (yet). 629 */ 630 nip->meta.comp_algo = 631 HAMMER2_ENC_ALGO(HAMMER2_COMP_NEWFS_DEFAULT); 632 nip->meta.check_algo = 633 HAMMER2_ENC_ALGO( HAMMER2_CHECK_XXHASH64); 634 635 if (strcasecmp(pfs->name, "boot") == 0) { 636 nip->meta.comp_algo = 637 HAMMER2_ENC_ALGO(HAMMER2_COMP_AUTOZERO); 638 } 639 640 /* 641 * Super-root isn't mounted, fsync it 642 */ 643 hammer2_chain_unlock(nchain); 644 hammer2_inode_ref(nip); 645 hammer2_inode_unlock(nip); 646 hammer2_inode_chain_sync(nip); 647 hammer2_inode_drop(nip); 648 649 /* 650 * We still have a ref on the chain, relock and associate 651 * with an appropriate PFS. 652 */ 653 force_local = (hmp->hflags & HMNT2_LOCAL) ? hmp : NULL; 654 655 hammer2_chain_lock(nchain, HAMMER2_RESOLVE_ALWAYS); 656 nipdata = &nchain->data->ipdata; 657 kprintf("ADD LOCAL PFS (IOCTL): %s\n", nipdata->filename); 658 hammer2_pfsalloc(nchain, nipdata, 659 nchain->bref.modify_tid, force_local); 660 661 hammer2_chain_unlock(nchain); 662 hammer2_chain_drop(nchain); 663 664 } 665 hammer2_trans_done(hmp->spmp); 666 667 return (error); 668 } 669 670 /* 671 * Destroy an existing PFS under the super-root 672 */ 673 static int 674 hammer2_ioctl_pfs_delete(hammer2_inode_t *ip, void *data) 675 { 676 hammer2_ioc_pfs_t *pfs = data; 677 hammer2_dev_t *hmp; 678 hammer2_pfs_t *spmp; 679 hammer2_pfs_t *pmp; 680 hammer2_xop_unlink_t *xop; 681 hammer2_inode_t *dip; 682 hammer2_inode_t *iroot; 683 int error; 684 int i; 685 686 /* 687 * The PFS should be probed, so we should be able to 688 * locate it. We only delete the PFS from the 689 * specific H2 block device (hmp), not all of 690 * them. We must remove the PFS from the cluster 691 * before we can destroy it. 692 */ 693 hmp = ip->pmp->pfs_hmps[0]; 694 if (hmp == NULL) 695 return (EINVAL); 696 697 pfs->name[sizeof(pfs->name) - 1] = 0; /* ensure termination */ 698 699 lockmgr(&hammer2_mntlk, LK_EXCLUSIVE); 700 701 TAILQ_FOREACH(pmp, &hammer2_pfslist, mntentry) { 702 for (i = 0; i < HAMMER2_MAXCLUSTER; ++i) { 703 if (pmp->pfs_hmps[i] != hmp) 704 continue; 705 if (pmp->pfs_names[i] && 706 strcmp(pmp->pfs_names[i], pfs->name) == 0) { 707 break; 708 } 709 } 710 if (i != HAMMER2_MAXCLUSTER) 711 break; 712 } 713 714 if (pmp == NULL) { 715 lockmgr(&hammer2_mntlk, LK_RELEASE); 716 return ENOENT; 717 } 718 719 /* 720 * Ok, we found the pmp and we have the index. Permanently remove 721 * the PFS from the cluster 722 */ 723 iroot = pmp->iroot; 724 kprintf("FOUND PFS %s CLINDEX %d\n", pfs->name, i); 725 hammer2_pfsdealloc(pmp, i, 1); 726 727 lockmgr(&hammer2_mntlk, LK_RELEASE); 728 729 /* 730 * Now destroy the PFS under its device using the per-device 731 * super-root. 732 */ 733 spmp = hmp->spmp; 734 dip = spmp->iroot; 735 hammer2_trans_init(spmp, 0); 736 hammer2_inode_lock(dip, 0); 737 738 xop = hammer2_xop_alloc(dip, HAMMER2_XOP_MODIFYING); 739 hammer2_xop_setname(&xop->head, pfs->name, strlen(pfs->name)); 740 xop->isdir = 2; 741 xop->dopermanent = 2 | 1; /* FORCE | PERMANENT */ 742 hammer2_xop_start(&xop->head, hammer2_xop_unlink); 743 744 error = hammer2_xop_collect(&xop->head, 0); 745 746 hammer2_inode_unlock(dip); 747 748 #if 0 749 if (error == 0) { 750 ip = hammer2_inode_get(dip->pmp, dip, &xop->head.cluster, -1); 751 hammer2_xop_retire(&xop->head, HAMMER2_XOPMASK_VOP); 752 if (ip) { 753 hammer2_inode_unlink_finisher(ip, 0); 754 hammer2_inode_unlock(ip); 755 } 756 } else { 757 hammer2_xop_retire(&xop->head, HAMMER2_XOPMASK_VOP); 758 } 759 #endif 760 hammer2_xop_retire(&xop->head, HAMMER2_XOPMASK_VOP); 761 762 hammer2_trans_done(spmp); 763 764 return (error); 765 } 766 767 static int 768 hammer2_ioctl_pfs_snapshot(hammer2_inode_t *ip, void *data) 769 { 770 hammer2_ioc_pfs_t *pfs = data; 771 hammer2_dev_t *hmp; 772 hammer2_pfs_t *pmp; 773 hammer2_chain_t *chain; 774 hammer2_tid_t mtid; 775 int error; 776 777 if (pfs->name[0] == 0) 778 return(EINVAL); 779 if (pfs->name[sizeof(pfs->name)-1] != 0) 780 return(EINVAL); 781 782 pmp = ip->pmp; 783 ip = pmp->iroot; 784 785 hmp = pmp->pfs_hmps[0]; 786 if (hmp == NULL) 787 return (EINVAL); 788 789 hammer2_vfs_sync(pmp->mp, MNT_WAIT); 790 791 hammer2_trans_init(pmp, HAMMER2_TRANS_ISFLUSH); 792 mtid = hammer2_trans_sub(pmp); 793 hammer2_inode_lock(ip, 0); 794 hammer2_inode_modify(ip); 795 ip->meta.pfs_lsnap_tid = mtid; 796 797 /* XXX cluster it! */ 798 chain = hammer2_inode_chain(ip, 0, HAMMER2_RESOLVE_ALWAYS); 799 error = hammer2_chain_snapshot(chain, pfs, mtid); 800 hammer2_chain_unlock(chain); 801 hammer2_chain_drop(chain); 802 803 hammer2_inode_unlock(ip); 804 hammer2_trans_done(pmp); 805 806 return (error); 807 } 808 809 /* 810 * Retrieve the raw inode structure, non-inclusive of node-specific data. 811 */ 812 static int 813 hammer2_ioctl_inode_get(hammer2_inode_t *ip, void *data) 814 { 815 hammer2_ioc_inode_t *ino; 816 hammer2_chain_t *chain; 817 int error; 818 int i; 819 820 ino = data; 821 error = 0; 822 823 hammer2_inode_lock(ip, HAMMER2_RESOLVE_SHARED); 824 ino->data_count = 0; 825 ino->inode_count = 0; 826 for (i = 0; i < ip->cluster.nchains; ++i) { 827 if ((chain = ip->cluster.array[i].chain) != NULL) { 828 if (ino->data_count < 829 chain->bref.embed.stats.data_count) { 830 ino->data_count = 831 chain->bref.embed.stats.data_count; 832 } 833 if (ino->inode_count < 834 chain->bref.embed.stats.inode_count) { 835 ino->inode_count = 836 chain->bref.embed.stats.inode_count; 837 } 838 } 839 } 840 bzero(&ino->ip_data, sizeof(ino->ip_data)); 841 ino->ip_data.meta = ip->meta; 842 ino->kdata = ip; 843 hammer2_inode_unlock(ip); 844 845 return error; 846 } 847 848 /* 849 * Set various parameters in an inode which cannot be set through 850 * normal filesystem VNOPS. 851 */ 852 static int 853 hammer2_ioctl_inode_set(hammer2_inode_t *ip, void *data) 854 { 855 hammer2_ioc_inode_t *ino = data; 856 int error = 0; 857 858 hammer2_trans_init(ip->pmp, 0); 859 hammer2_inode_lock(ip, 0); 860 861 if ((ino->flags & HAMMER2IOC_INODE_FLAG_CHECK) && 862 ip->meta.check_algo != ino->ip_data.meta.check_algo) { 863 hammer2_inode_modify(ip); 864 ip->meta.check_algo = ino->ip_data.meta.check_algo; 865 } 866 if ((ino->flags & HAMMER2IOC_INODE_FLAG_COMP) && 867 ip->meta.comp_algo != ino->ip_data.meta.comp_algo) { 868 hammer2_inode_modify(ip); 869 ip->meta.comp_algo = ino->ip_data.meta.comp_algo; 870 } 871 ino->kdata = ip; 872 873 /* Ignore these flags for now...*/ 874 if ((ino->flags & HAMMER2IOC_INODE_FLAG_IQUOTA) && 875 ip->meta.inode_quota != ino->ip_data.meta.inode_quota) { 876 hammer2_inode_modify(ip); 877 ip->meta.inode_quota = ino->ip_data.meta.inode_quota; 878 } 879 if ((ino->flags & HAMMER2IOC_INODE_FLAG_DQUOTA) && 880 ip->meta.data_quota != ino->ip_data.meta.data_quota) { 881 hammer2_inode_modify(ip); 882 ip->meta.data_quota = ino->ip_data.meta.data_quota; 883 } 884 if ((ino->flags & HAMMER2IOC_INODE_FLAG_COPIES) && 885 ip->meta.ncopies != ino->ip_data.meta.ncopies) { 886 hammer2_inode_modify(ip); 887 ip->meta.ncopies = ino->ip_data.meta.ncopies; 888 } 889 hammer2_inode_unlock(ip); 890 hammer2_trans_done(ip->pmp); 891 892 return (error); 893 } 894 895 static 896 int 897 hammer2_ioctl_debug_dump(hammer2_inode_t *ip) 898 { 899 hammer2_chain_t *chain; 900 int count = 1000; 901 int i; 902 903 for (i = 0; i < ip->cluster.nchains; ++i) { 904 chain = ip->cluster.array[i].chain; 905 if (chain == NULL) 906 continue; 907 hammer2_dump_chain(chain, 0, &count, 'i'); 908 } 909 return 0; 910 } 911 912 /* 913 * Executes one flush/free pass per call. If trying to recover 914 * data we just freed up a moment ago it can take up to six passes 915 * to fully free the blocks. Note that passes occur automatically based 916 * on free space as the storage fills up, but manual passes may be needed 917 * if storage becomes almost completely full. 918 */ 919 static 920 int 921 hammer2_ioctl_bulkfree_scan(hammer2_inode_t *ip, void *data) 922 { 923 hammer2_ioc_bulkfree_t *bfi = data; 924 hammer2_dev_t *hmp; 925 int error; 926 927 hmp = ip->pmp->pfs_hmps[0]; 928 if (hmp == NULL) 929 return (EINVAL); 930 931 error = hammer2_bulkfree_pass(hmp, bfi); 932 933 return error; 934 } 935