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 (chain->bref.type == HAMMER2_BREF_TYPE_INODE) { 540 ripdata = &chain->data->ipdata; 541 if (ripdata->meta.name_len == len && 542 bcmp(ripdata->filename, pfs->name, len) == 0) { 543 break; 544 } 545 ripdata = NULL; /* safety */ 546 } 547 chain = hammer2_chain_next(&parent, chain, &key_next, 548 key_next, 549 lhc + HAMMER2_DIRHASH_LOMASK, 550 &cache_index, 551 HAMMER2_LOOKUP_SHARED); 552 } 553 554 /* 555 * Load the data being returned by the ioctl. 556 */ 557 if (chain) { 558 ripdata = &chain->data->ipdata; 559 pfs->name_key = ripdata->meta.name_key; 560 pfs->pfs_type = ripdata->meta.pfs_type; 561 pfs->pfs_subtype = ripdata->meta.pfs_subtype; 562 pfs->pfs_clid = ripdata->meta.pfs_clid; 563 pfs->pfs_fsid = ripdata->meta.pfs_fsid; 564 ripdata = NULL; 565 566 hammer2_chain_unlock(chain); 567 hammer2_chain_drop(chain); 568 } else { 569 error = ENOENT; 570 } 571 if (parent) { 572 hammer2_chain_unlock(parent); 573 hammer2_chain_drop(parent); 574 } 575 hammer2_inode_unlock(hmp->spmp->iroot); 576 577 return (error); 578 } 579 580 /* 581 * Create a new PFS under the super-root 582 */ 583 static int 584 hammer2_ioctl_pfs_create(hammer2_inode_t *ip, void *data) 585 { 586 hammer2_inode_data_t *nipdata; 587 hammer2_chain_t *nchain; 588 hammer2_dev_t *hmp; 589 hammer2_dev_t *force_local; 590 hammer2_ioc_pfs_t *pfs; 591 hammer2_inode_t *nip; 592 hammer2_tid_t mtid; 593 int error; 594 595 hmp = ip->pmp->pfs_hmps[0]; /* XXX */ 596 if (hmp == NULL) 597 return (EINVAL); 598 599 pfs = data; 600 nip = NULL; 601 602 if (pfs->name[0] == 0) 603 return(EINVAL); 604 pfs->name[sizeof(pfs->name) - 1] = 0; /* ensure 0-termination */ 605 606 if (hammer2_ioctl_pfs_lookup(ip, pfs) == 0) 607 return(EEXIST); 608 609 hammer2_trans_init(hmp->spmp, 0); 610 mtid = hammer2_trans_sub(hmp->spmp); 611 nip = hammer2_inode_create(hmp->spmp->iroot, hmp->spmp->iroot, 612 NULL, NULL, 613 pfs->name, strlen(pfs->name), 0, 614 1, HAMMER2_OBJTYPE_DIRECTORY, 0, 615 HAMMER2_INSERT_PFSROOT, &error); 616 if (error == 0) { 617 hammer2_inode_modify(nip); 618 nchain = hammer2_inode_chain(nip, 0, HAMMER2_RESOLVE_ALWAYS); 619 hammer2_chain_modify(nchain, mtid, 0, 0); 620 nipdata = &nchain->data->ipdata; 621 622 nip->meta.pfs_type = pfs->pfs_type; 623 nip->meta.pfs_subtype = pfs->pfs_subtype; 624 nip->meta.pfs_clid = pfs->pfs_clid; 625 nip->meta.pfs_fsid = pfs->pfs_fsid; 626 nip->meta.op_flags |= HAMMER2_OPFLAG_PFSROOT; 627 628 /* 629 * Set default compression and check algorithm. This 630 * can be changed later. 631 * 632 * Do not allow compression on PFS's with the special name 633 * "boot", the boot loader can't decompress (yet). 634 */ 635 nip->meta.comp_algo = 636 HAMMER2_ENC_ALGO(HAMMER2_COMP_NEWFS_DEFAULT); 637 nip->meta.check_algo = 638 HAMMER2_ENC_ALGO( HAMMER2_CHECK_XXHASH64); 639 640 if (strcasecmp(pfs->name, "boot") == 0) { 641 nip->meta.comp_algo = 642 HAMMER2_ENC_ALGO(HAMMER2_COMP_AUTOZERO); 643 } 644 645 /* 646 * Super-root isn't mounted, fsync it 647 */ 648 hammer2_chain_unlock(nchain); 649 hammer2_inode_ref(nip); 650 hammer2_inode_unlock(nip); 651 hammer2_inode_chain_sync(nip); 652 hammer2_inode_drop(nip); 653 654 /* 655 * We still have a ref on the chain, relock and associate 656 * with an appropriate PFS. 657 */ 658 force_local = (hmp->hflags & HMNT2_LOCAL) ? hmp : NULL; 659 660 hammer2_chain_lock(nchain, HAMMER2_RESOLVE_ALWAYS); 661 nipdata = &nchain->data->ipdata; 662 kprintf("ADD LOCAL PFS (IOCTL): %s\n", nipdata->filename); 663 hammer2_pfsalloc(nchain, nipdata, 664 nchain->bref.modify_tid, force_local); 665 666 hammer2_chain_unlock(nchain); 667 hammer2_chain_drop(nchain); 668 669 } 670 hammer2_trans_done(hmp->spmp); 671 672 return (error); 673 } 674 675 /* 676 * Destroy an existing PFS under the super-root 677 */ 678 static int 679 hammer2_ioctl_pfs_delete(hammer2_inode_t *ip, void *data) 680 { 681 hammer2_ioc_pfs_t *pfs = data; 682 hammer2_dev_t *hmp; 683 hammer2_pfs_t *spmp; 684 hammer2_xop_unlink_t *xop; 685 hammer2_inode_t *dip; 686 int error; 687 688 pfs->name[sizeof(pfs->name) - 1] = 0; /* ensure termination */ 689 690 hmp = ip->pmp->pfs_hmps[0]; 691 if (hmp == NULL) 692 return (EINVAL); 693 694 spmp = hmp->spmp; 695 dip = spmp->iroot; 696 hammer2_trans_init(spmp, 0); 697 hammer2_inode_lock(dip, 0); 698 699 xop = hammer2_xop_alloc(dip, HAMMER2_XOP_MODIFYING); 700 hammer2_xop_setname(&xop->head, pfs->name, strlen(pfs->name)); 701 xop->isdir = 2; 702 xop->dopermanent = 1; 703 hammer2_xop_start(&xop->head, hammer2_xop_unlink); 704 705 error = hammer2_xop_collect(&xop->head, 0); 706 707 hammer2_inode_unlock(dip); 708 hammer2_trans_done(spmp); 709 710 return (error); 711 } 712 713 static int 714 hammer2_ioctl_pfs_snapshot(hammer2_inode_t *ip, void *data) 715 { 716 hammer2_ioc_pfs_t *pfs = data; 717 hammer2_dev_t *hmp; 718 hammer2_pfs_t *pmp; 719 hammer2_chain_t *chain; 720 hammer2_tid_t mtid; 721 int error; 722 723 if (pfs->name[0] == 0) 724 return(EINVAL); 725 if (pfs->name[sizeof(pfs->name)-1] != 0) 726 return(EINVAL); 727 728 pmp = ip->pmp; 729 ip = pmp->iroot; 730 731 hmp = pmp->pfs_hmps[0]; 732 if (hmp == NULL) 733 return (EINVAL); 734 735 hammer2_vfs_sync(pmp->mp, MNT_WAIT); 736 737 hammer2_trans_init(pmp, HAMMER2_TRANS_ISFLUSH); 738 mtid = hammer2_trans_sub(pmp); 739 hammer2_inode_lock(ip, 0); 740 hammer2_inode_modify(ip); 741 ip->meta.pfs_lsnap_tid = mtid; 742 743 /* XXX cluster it! */ 744 chain = hammer2_inode_chain(ip, 0, HAMMER2_RESOLVE_ALWAYS); 745 error = hammer2_chain_snapshot(chain, pfs, mtid); 746 hammer2_chain_unlock(chain); 747 hammer2_chain_drop(chain); 748 749 hammer2_inode_unlock(ip); 750 hammer2_trans_done(pmp); 751 752 return (error); 753 } 754 755 /* 756 * Retrieve the raw inode structure, non-inclusive of node-specific data. 757 */ 758 static int 759 hammer2_ioctl_inode_get(hammer2_inode_t *ip, void *data) 760 { 761 hammer2_ioc_inode_t *ino; 762 hammer2_chain_t *chain; 763 int error; 764 int i; 765 766 ino = data; 767 error = 0; 768 769 hammer2_inode_lock(ip, HAMMER2_RESOLVE_SHARED); 770 ino->data_count = 0; 771 ino->inode_count = 0; 772 for (i = 0; i < ip->cluster.nchains; ++i) { 773 if ((chain = ip->cluster.array[i].chain) != NULL) { 774 if (ino->data_count < chain->bref.data_count) 775 ino->data_count = chain->bref.data_count; 776 if (ino->inode_count < chain->bref.inode_count) 777 ino->inode_count = chain->bref.inode_count; 778 } 779 } 780 bzero(&ino->ip_data, sizeof(ino->ip_data)); 781 ino->ip_data.meta = ip->meta; 782 ino->kdata = ip; 783 hammer2_inode_unlock(ip); 784 785 return error; 786 } 787 788 /* 789 * Set various parameters in an inode which cannot be set through 790 * normal filesystem VNOPS. 791 */ 792 static int 793 hammer2_ioctl_inode_set(hammer2_inode_t *ip, void *data) 794 { 795 hammer2_ioc_inode_t *ino = data; 796 int error = 0; 797 798 hammer2_trans_init(ip->pmp, 0); 799 hammer2_inode_lock(ip, 0); 800 801 if ((ino->flags & HAMMER2IOC_INODE_FLAG_CHECK) && 802 ip->meta.check_algo != ino->ip_data.meta.check_algo) { 803 hammer2_inode_modify(ip); 804 ip->meta.check_algo = ino->ip_data.meta.check_algo; 805 } 806 if ((ino->flags & HAMMER2IOC_INODE_FLAG_COMP) && 807 ip->meta.comp_algo != ino->ip_data.meta.comp_algo) { 808 hammer2_inode_modify(ip); 809 ip->meta.comp_algo = ino->ip_data.meta.comp_algo; 810 } 811 ino->kdata = ip; 812 813 /* Ignore these flags for now...*/ 814 if ((ino->flags & HAMMER2IOC_INODE_FLAG_IQUOTA) && 815 ip->meta.inode_quota != ino->ip_data.meta.inode_quota) { 816 hammer2_inode_modify(ip); 817 ip->meta.inode_quota = ino->ip_data.meta.inode_quota; 818 } 819 if ((ino->flags & HAMMER2IOC_INODE_FLAG_DQUOTA) && 820 ip->meta.data_quota != ino->ip_data.meta.data_quota) { 821 hammer2_inode_modify(ip); 822 ip->meta.data_quota = ino->ip_data.meta.data_quota; 823 } 824 if ((ino->flags & HAMMER2IOC_INODE_FLAG_COPIES) && 825 ip->meta.ncopies != ino->ip_data.meta.ncopies) { 826 hammer2_inode_modify(ip); 827 ip->meta.ncopies = ino->ip_data.meta.ncopies; 828 } 829 hammer2_inode_unlock(ip); 830 hammer2_trans_done(ip->pmp); 831 832 return (error); 833 } 834 835 static 836 int 837 hammer2_ioctl_debug_dump(hammer2_inode_t *ip) 838 { 839 hammer2_chain_t *chain; 840 int count = 1000; 841 int i; 842 843 for (i = 0; i < ip->cluster.nchains; ++i) { 844 chain = ip->cluster.array[i].chain; 845 if (chain == NULL) 846 continue; 847 hammer2_dump_chain(chain, 0, &count, 'i'); 848 } 849 return 0; 850 } 851 852 /* 853 * Executes one flush/free pass per call. If trying to recover 854 * data we just freed up a moment ago it can take up to six passes 855 * to fully free the blocks. Note that passes occur automatically based 856 * on free space as the storage fills up, but manual passes may be needed 857 * if storage becomes almost completely full. 858 */ 859 static 860 int 861 hammer2_ioctl_bulkfree_scan(hammer2_inode_t *ip, void *data) 862 { 863 hammer2_ioc_bulkfree_t *bfi = data; 864 hammer2_dev_t *hmp; 865 int error; 866 867 hmp = ip->pmp->pfs_hmps[0]; 868 if (hmp == NULL) 869 return (EINVAL); 870 871 error = hammer2_bulkfree_pass(hmp, bfi); 872 873 return error; 874 } 875