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_dev_t *hmp = ip->pmp->iroot->cluster.focus->hmp; 166 hammer2_ioc_version_t *version = data; 167 168 version->version = hmp->voldata.version; 169 return 0; 170 } 171 172 static int 173 hammer2_ioctl_recluster(hammer2_inode_t *ip, void *data) 174 { 175 hammer2_ioc_recluster_t *recl = data; 176 struct file *fp; 177 hammer2_cluster_t *cluster; 178 int error; 179 180 fp = holdfp(curproc->p_fd, recl->fd, -1); 181 if (fp) { 182 kprintf("reconnect to cluster: XXX "); 183 cluster = &ip->pmp->iroot->cluster; 184 if (cluster->nchains != 1 || cluster->focus == NULL) { 185 kprintf("not a local device mount\n"); 186 error = EINVAL; 187 } else { 188 hammer2_cluster_reconnect(cluster->focus->hmp, fp); 189 kprintf("ok\n"); 190 error = 0; 191 } 192 } else { 193 error = EINVAL; 194 } 195 return error; 196 } 197 198 /* 199 * Retrieve information about a remote 200 */ 201 static int 202 hammer2_ioctl_remote_scan(hammer2_inode_t *ip, void *data) 203 { 204 hammer2_dev_t *hmp = ip->pmp->iroot->cluster.focus->hmp; 205 hammer2_ioc_remote_t *remote = data; 206 int copyid = remote->copyid; 207 208 if (copyid < 0 || copyid >= HAMMER2_COPYID_COUNT) 209 return (EINVAL); 210 211 hammer2_voldata_lock(hmp); 212 remote->copy1 = hmp->voldata.copyinfo[copyid]; 213 hammer2_voldata_unlock(hmp); 214 215 /* 216 * Adjust nextid (GET only) 217 */ 218 while (++copyid < HAMMER2_COPYID_COUNT && 219 hmp->voldata.copyinfo[copyid].copyid == 0) { 220 ; 221 } 222 if (copyid == HAMMER2_COPYID_COUNT) 223 remote->nextid = -1; 224 else 225 remote->nextid = copyid; 226 227 return(0); 228 } 229 230 /* 231 * Add new remote entry 232 */ 233 static int 234 hammer2_ioctl_remote_add(hammer2_inode_t *ip, void *data) 235 { 236 hammer2_ioc_remote_t *remote = data; 237 hammer2_pfs_t *pmp = ip->pmp; 238 hammer2_dev_t *hmp; 239 int copyid = remote->copyid; 240 int error = 0; 241 242 if (copyid >= HAMMER2_COPYID_COUNT) 243 return (EINVAL); 244 245 hmp = pmp->iroot->cluster.focus->hmp; /* XXX */ 246 hammer2_voldata_lock(hmp); 247 if (copyid < 0) { 248 for (copyid = 1; copyid < HAMMER2_COPYID_COUNT; ++copyid) { 249 if (hmp->voldata.copyinfo[copyid].copyid == 0) 250 break; 251 } 252 if (copyid == HAMMER2_COPYID_COUNT) { 253 error = ENOSPC; 254 goto failed; 255 } 256 } 257 hammer2_voldata_modify(hmp); 258 remote->copy1.copyid = copyid; 259 hmp->voldata.copyinfo[copyid] = remote->copy1; 260 hammer2_volconf_update(hmp, copyid); 261 failed: 262 hammer2_voldata_unlock(hmp); 263 return (error); 264 } 265 266 /* 267 * Delete existing remote entry 268 */ 269 static int 270 hammer2_ioctl_remote_del(hammer2_inode_t *ip, void *data) 271 { 272 hammer2_ioc_remote_t *remote = data; 273 hammer2_pfs_t *pmp = ip->pmp; 274 hammer2_dev_t *hmp; 275 int copyid = remote->copyid; 276 int error = 0; 277 278 hmp = pmp->iroot->cluster.focus->hmp; /* XXX */ 279 if (copyid >= HAMMER2_COPYID_COUNT) 280 return (EINVAL); 281 remote->copy1.path[sizeof(remote->copy1.path) - 1] = 0; 282 hammer2_voldata_lock(hmp); 283 if (copyid < 0) { 284 for (copyid = 1; copyid < HAMMER2_COPYID_COUNT; ++copyid) { 285 if (hmp->voldata.copyinfo[copyid].copyid == 0) 286 continue; 287 if (strcmp(remote->copy1.path, 288 hmp->voldata.copyinfo[copyid].path) == 0) { 289 break; 290 } 291 } 292 if (copyid == HAMMER2_COPYID_COUNT) { 293 error = ENOENT; 294 goto failed; 295 } 296 } 297 hammer2_voldata_modify(hmp); 298 hmp->voldata.copyinfo[copyid].copyid = 0; 299 hammer2_volconf_update(hmp, copyid); 300 failed: 301 hammer2_voldata_unlock(hmp); 302 return (error); 303 } 304 305 /* 306 * Replace existing remote entry 307 */ 308 static int 309 hammer2_ioctl_remote_rep(hammer2_inode_t *ip, void *data) 310 { 311 hammer2_ioc_remote_t *remote = data; 312 hammer2_dev_t *hmp; 313 int copyid = remote->copyid; 314 315 hmp = ip->pmp->iroot->cluster.focus->hmp; /* XXX */ 316 317 if (copyid < 0 || copyid >= HAMMER2_COPYID_COUNT) 318 return (EINVAL); 319 320 hammer2_voldata_lock(hmp); 321 hammer2_voldata_modify(hmp); 322 /*hammer2_volconf_update(hmp, copyid);*/ 323 hammer2_voldata_unlock(hmp); 324 325 return(0); 326 } 327 328 /* 329 * Retrieve communications socket 330 */ 331 static int 332 hammer2_ioctl_socket_get(hammer2_inode_t *ip, void *data) 333 { 334 return (EOPNOTSUPP); 335 } 336 337 /* 338 * Set communications socket for connection 339 */ 340 static int 341 hammer2_ioctl_socket_set(hammer2_inode_t *ip, void *data) 342 { 343 hammer2_ioc_remote_t *remote = data; 344 hammer2_dev_t *hmp; 345 int copyid = remote->copyid; 346 347 hmp = ip->pmp->iroot->cluster.focus->hmp; /* XXX */ 348 if (copyid < 0 || copyid >= HAMMER2_COPYID_COUNT) 349 return (EINVAL); 350 351 hammer2_voldata_lock(hmp); 352 hammer2_voldata_unlock(hmp); 353 354 return(0); 355 } 356 357 /* 358 * Used to scan and retrieve PFS information. PFS's are directories under 359 * the super-root. 360 * 361 * To scan PFSs pass name_key=0. The function will scan for the next 362 * PFS and set all fields, as well as set name_next to the next key. 363 * When no PFSs remain, name_next is set to (hammer2_key_t)-1. 364 * 365 * To retrieve a particular PFS by key, specify the key but note that 366 * the ioctl will return the lowest key >= specified_key, so the caller 367 * must verify the key. 368 * 369 * To retrieve the PFS associated with the file descriptor, pass 370 * name_key set to (hammer2_key_t)-1. 371 */ 372 static int 373 hammer2_ioctl_pfs_get(hammer2_inode_t *ip, void *data) 374 { 375 const hammer2_inode_data_t *ripdata; 376 hammer2_dev_t *hmp; 377 hammer2_ioc_pfs_t *pfs; 378 hammer2_chain_t *parent; 379 hammer2_chain_t *chain; 380 hammer2_key_t key_next; 381 hammer2_key_t save_key; 382 int cache_index = -1; 383 int error; 384 385 error = 0; 386 hmp = ip->pmp->iroot->cluster.focus->hmp; /* XXX */ 387 pfs = data; 388 389 save_key = pfs->name_key; 390 391 /* 392 * Setup 393 */ 394 if (save_key == (hammer2_key_t)-1) { 395 hammer2_inode_lock(ip->pmp->iroot, 0); 396 parent = NULL; 397 chain = hammer2_inode_chain(hmp->spmp->iroot, 0, 398 HAMMER2_RESOLVE_ALWAYS | 399 HAMMER2_RESOLVE_SHARED); 400 } else { 401 hammer2_inode_lock(hmp->spmp->iroot, 0); 402 parent = hammer2_inode_chain(hmp->spmp->iroot, 0, 403 HAMMER2_RESOLVE_ALWAYS | 404 HAMMER2_RESOLVE_SHARED); 405 chain = hammer2_chain_lookup(&parent, &key_next, 406 pfs->name_key, HAMMER2_KEY_MAX, 407 &cache_index, 408 HAMMER2_LOOKUP_SHARED); 409 } 410 411 /* 412 * Locate next PFS 413 */ 414 while (chain) { 415 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE) 416 break; 417 if (parent == NULL) { 418 hammer2_chain_unlock(chain); 419 hammer2_chain_drop(chain); 420 break; 421 } 422 chain = hammer2_chain_next(&parent, chain, &key_next, 423 key_next, HAMMER2_KEY_MAX, 424 &cache_index, 425 HAMMER2_LOOKUP_SHARED); 426 } 427 428 /* 429 * Load the data being returned by the ioctl. 430 */ 431 if (chain) { 432 ripdata = &chain->data->ipdata; 433 pfs->name_key = ripdata->meta.name_key; 434 pfs->pfs_type = ripdata->meta.pfs_type; 435 pfs->pfs_subtype = ripdata->meta.pfs_subtype; 436 pfs->pfs_clid = ripdata->meta.pfs_clid; 437 pfs->pfs_fsid = ripdata->meta.pfs_fsid; 438 KKASSERT(ripdata->meta.name_len < sizeof(pfs->name)); 439 bcopy(ripdata->filename, pfs->name, ripdata->meta.name_len); 440 pfs->name[ripdata->meta.name_len] = 0; 441 ripdata = NULL; /* safety */ 442 443 /* 444 * Calculate name_next. 445 */ 446 chain = hammer2_chain_next(&parent, chain, &key_next, 447 key_next, HAMMER2_KEY_MAX, 448 &cache_index, 449 HAMMER2_LOOKUP_SHARED); 450 if (chain) 451 pfs->name_next = chain->bref.key; 452 else 453 pfs->name_next = (hammer2_key_t)-1; 454 } else { 455 pfs->name_next = (hammer2_key_t)-1; 456 error = ENOENT; 457 } 458 459 /* 460 * Cleanup 461 */ 462 if (chain) { 463 hammer2_chain_unlock(chain); 464 hammer2_chain_drop(chain); 465 } 466 if (parent) { 467 hammer2_chain_unlock(parent); 468 hammer2_chain_drop(parent); 469 } 470 if (save_key == (hammer2_key_t)-1) { 471 hammer2_inode_unlock(ip->pmp->iroot); 472 } else { 473 hammer2_inode_unlock(hmp->spmp->iroot); 474 } 475 476 return (error); 477 } 478 479 /* 480 * Find a specific PFS by name 481 */ 482 static int 483 hammer2_ioctl_pfs_lookup(hammer2_inode_t *ip, void *data) 484 { 485 const hammer2_inode_data_t *ripdata; 486 hammer2_dev_t *hmp; 487 hammer2_ioc_pfs_t *pfs; 488 hammer2_chain_t *parent; 489 hammer2_chain_t *chain; 490 hammer2_key_t key_next; 491 hammer2_key_t lhc; 492 int cache_index = -1; 493 int error; 494 size_t len; 495 496 error = 0; 497 hmp = ip->pmp->iroot->cluster.focus->hmp; /* XXX */ 498 pfs = data; 499 hammer2_inode_lock(hmp->spmp->iroot, HAMMER2_RESOLVE_SHARED); 500 parent = hammer2_inode_chain(hmp->spmp->iroot, 0, 501 HAMMER2_RESOLVE_ALWAYS | 502 HAMMER2_RESOLVE_SHARED); 503 504 pfs->name[sizeof(pfs->name) - 1] = 0; 505 len = strlen(pfs->name); 506 lhc = hammer2_dirhash(pfs->name, len); 507 508 chain = hammer2_chain_lookup(&parent, &key_next, 509 lhc, lhc + HAMMER2_DIRHASH_LOMASK, 510 &cache_index, 511 HAMMER2_LOOKUP_SHARED); 512 while (chain) { 513 if (chain->bref.type == HAMMER2_BREF_TYPE_INODE) { 514 ripdata = &chain->data->ipdata; 515 if (ripdata->meta.name_len == len && 516 bcmp(ripdata->filename, pfs->name, len) == 0) { 517 break; 518 } 519 ripdata = NULL; /* safety */ 520 } 521 chain = hammer2_chain_next(&parent, chain, &key_next, 522 key_next, 523 lhc + HAMMER2_DIRHASH_LOMASK, 524 &cache_index, 525 HAMMER2_LOOKUP_SHARED); 526 } 527 528 /* 529 * Load the data being returned by the ioctl. 530 */ 531 if (chain) { 532 ripdata = &chain->data->ipdata; 533 pfs->name_key = ripdata->meta.name_key; 534 pfs->pfs_type = ripdata->meta.pfs_type; 535 pfs->pfs_subtype = ripdata->meta.pfs_subtype; 536 pfs->pfs_clid = ripdata->meta.pfs_clid; 537 pfs->pfs_fsid = ripdata->meta.pfs_fsid; 538 ripdata = NULL; 539 540 hammer2_chain_unlock(chain); 541 hammer2_chain_drop(chain); 542 } else { 543 error = ENOENT; 544 } 545 if (parent) { 546 hammer2_chain_unlock(parent); 547 hammer2_chain_drop(parent); 548 } 549 hammer2_inode_unlock(hmp->spmp->iroot); 550 551 return (error); 552 } 553 554 /* 555 * Create a new PFS under the super-root 556 */ 557 static int 558 hammer2_ioctl_pfs_create(hammer2_inode_t *ip, void *data) 559 { 560 hammer2_inode_data_t *nipdata; 561 hammer2_chain_t *nchain; 562 hammer2_dev_t *hmp; 563 hammer2_ioc_pfs_t *pfs; 564 hammer2_inode_t *nip; 565 int error; 566 567 hmp = ip->pmp->iroot->cluster.focus->hmp; /* XXX */ 568 pfs = data; 569 nip = NULL; 570 571 if (pfs->name[0] == 0) 572 return(EINVAL); 573 pfs->name[sizeof(pfs->name) - 1] = 0; /* ensure 0-termination */ 574 575 if (hammer2_ioctl_pfs_lookup(ip, pfs) == 0) 576 return(EEXIST); 577 578 hammer2_trans_init(hmp->spmp, 0); 579 nip = hammer2_inode_create(hmp->spmp->iroot, NULL, NULL, 580 pfs->name, strlen(pfs->name), 0, 581 1, HAMMER2_OBJTYPE_DIRECTORY, 0, 582 HAMMER2_INSERT_PFSROOT, &error); 583 if (error == 0) { 584 hammer2_inode_modify(nip); 585 nchain = hammer2_inode_chain(nip, 0, HAMMER2_RESOLVE_ALWAYS); 586 hammer2_chain_modify(nchain, 0); 587 nipdata = &nchain->data->ipdata; 588 589 nip->meta.pfs_type = pfs->pfs_type; 590 nip->meta.pfs_subtype = pfs->pfs_subtype; 591 nip->meta.pfs_clid = pfs->pfs_clid; 592 nip->meta.pfs_fsid = pfs->pfs_fsid; 593 nip->meta.op_flags |= HAMMER2_OPFLAG_PFSROOT; 594 595 /* 596 * Set default compression and check algorithm. This 597 * can be changed later. 598 * 599 * Do not allow compression on PFS's with the special name 600 * "boot", the boot loader can't decompress (yet). 601 */ 602 nip->meta.comp_algo = 603 HAMMER2_ENC_ALGO(HAMMER2_COMP_NEWFS_DEFAULT); 604 nip->meta.check_algo = 605 HAMMER2_ENC_ALGO( HAMMER2_CHECK_ISCSI32); 606 607 if (strcasecmp(pfs->name, "boot") == 0) { 608 nip->meta.comp_algo = 609 HAMMER2_ENC_ALGO(HAMMER2_COMP_AUTOZERO); 610 } 611 #if 0 612 hammer2_blockref_t bref; 613 /* XXX new PFS needs to be rescanned / added */ 614 bref = nchain->bref; 615 kprintf("ADD LOCAL PFS (IOCTL): %s\n", nipdata->filename); 616 hammer2_pfsalloc(nchain, nipdata, bref.modify_tid); 617 #endif 618 /* XXX rescan */ 619 hammer2_chain_unlock(nchain); 620 hammer2_chain_drop(nchain); 621 622 hammer2_inode_unlock(nip); 623 } 624 hammer2_trans_done(hmp->spmp); 625 626 return (error); 627 } 628 629 /* 630 * Destroy an existing PFS under the super-root 631 */ 632 static int 633 hammer2_ioctl_pfs_delete(hammer2_inode_t *ip, void *data) 634 { 635 hammer2_ioc_pfs_t *pfs = data; 636 hammer2_pfs_t *spmp; 637 hammer2_xop_unlink_t *xop; 638 hammer2_inode_t *dip; 639 int error; 640 641 pfs->name[sizeof(pfs->name) - 1] = 0; /* ensure termination */ 642 643 /* XXX */ 644 spmp = ip->pmp->iroot->cluster.focus->hmp->spmp; 645 dip = spmp->iroot; 646 hammer2_trans_init(spmp, 0); 647 hammer2_inode_lock(dip, 0); 648 649 xop = &hammer2_xop_alloc(dip)->xop_unlink; 650 hammer2_xop_setname(&xop->head, pfs->name, strlen(pfs->name)); 651 xop->isdir = 2; 652 xop->dopermanent = 1; 653 hammer2_xop_start(&xop->head, hammer2_xop_unlink); 654 655 error = hammer2_xop_collect(&xop->head, 0); 656 657 hammer2_inode_unlock(dip); 658 hammer2_trans_done(spmp); 659 660 return (error); 661 } 662 663 static int 664 hammer2_ioctl_pfs_snapshot(hammer2_inode_t *ip, void *data) 665 { 666 hammer2_ioc_pfs_t *pfs = data; 667 hammer2_cluster_t *cparent; 668 int error; 669 670 if (pfs->name[0] == 0) 671 return(EINVAL); 672 if (pfs->name[sizeof(pfs->name)-1] != 0) 673 return(EINVAL); 674 675 hammer2_vfs_sync(ip->pmp->mp, MNT_WAIT); 676 677 hammer2_trans_init(ip->pmp, HAMMER2_TRANS_ISFLUSH); 678 hammer2_inode_lock(ip, 0); 679 cparent = hammer2_inode_cluster(ip, HAMMER2_RESOLVE_ALWAYS); 680 error = hammer2_cluster_snapshot(cparent, pfs); 681 hammer2_inode_unlock(ip); 682 hammer2_cluster_unlock(cparent); 683 hammer2_cluster_drop(cparent); 684 hammer2_trans_done(ip->pmp); 685 686 return (error); 687 } 688 689 /* 690 * Retrieve the raw inode structure, non-inclusive of node-specific data. 691 */ 692 static int 693 hammer2_ioctl_inode_get(hammer2_inode_t *ip, void *data) 694 { 695 hammer2_ioc_inode_t *ino; 696 int error; 697 698 ino = data; 699 700 hammer2_inode_lock(ip, HAMMER2_RESOLVE_SHARED); 701 if (ip->cluster.focus) { 702 /* XXX */ 703 ino->data_count = ip->cluster.focus->bref.data_count; 704 ino->inode_count = ip->cluster.focus->bref.inode_count; 705 error = 0; 706 } else { 707 ino->data_count = -1; 708 ino->inode_count = -1; 709 error = EIO; 710 } 711 bzero(&ino->ip_data, sizeof(ino->ip_data)); 712 ino->ip_data.meta = ip->meta; 713 ino->kdata = ip; 714 hammer2_inode_unlock(ip); 715 716 return error; 717 } 718 719 /* 720 * Set various parameters in an inode which cannot be set through 721 * normal filesystem VNOPS. 722 */ 723 static int 724 hammer2_ioctl_inode_set(hammer2_inode_t *ip, void *data) 725 { 726 hammer2_ioc_inode_t *ino = data; 727 int error = 0; 728 729 hammer2_trans_init(ip->pmp, 0); 730 hammer2_inode_lock(ip, 0); 731 732 if ((ino->flags & HAMMER2IOC_INODE_FLAG_CHECK) && 733 ip->meta.check_algo != ino->ip_data.meta.check_algo) { 734 hammer2_inode_modify(ip); 735 ip->meta.check_algo = ino->ip_data.meta.check_algo; 736 } 737 if ((ino->flags & HAMMER2IOC_INODE_FLAG_COMP) && 738 ip->meta.comp_algo != ino->ip_data.meta.comp_algo) { 739 hammer2_inode_modify(ip); 740 ip->meta.comp_algo = ino->ip_data.meta.comp_algo; 741 } 742 ino->kdata = ip; 743 744 /* Ignore these flags for now...*/ 745 if ((ino->flags & HAMMER2IOC_INODE_FLAG_IQUOTA) && 746 ip->meta.inode_quota != ino->ip_data.meta.inode_quota) { 747 hammer2_inode_modify(ip); 748 ip->meta.inode_quota = ino->ip_data.meta.inode_quota; 749 } 750 if ((ino->flags & HAMMER2IOC_INODE_FLAG_DQUOTA) && 751 ip->meta.data_quota != ino->ip_data.meta.data_quota) { 752 hammer2_inode_modify(ip); 753 ip->meta.data_quota = ino->ip_data.meta.data_quota; 754 } 755 if ((ino->flags & HAMMER2IOC_INODE_FLAG_COPIES) && 756 ip->meta.ncopies != ino->ip_data.meta.ncopies) { 757 hammer2_inode_modify(ip); 758 ip->meta.ncopies = ino->ip_data.meta.ncopies; 759 } 760 hammer2_inode_unlock(ip); 761 hammer2_trans_done(ip->pmp); 762 763 return (error); 764 } 765 766 static 767 int 768 hammer2_ioctl_debug_dump(hammer2_inode_t *ip) 769 { 770 hammer2_chain_t *chain; 771 int count = 1000; 772 int i; 773 774 for (i = 0; i < ip->cluster.nchains; ++i) { 775 chain = ip->cluster.array[i].chain; 776 if (chain == NULL) 777 continue; 778 hammer2_dump_chain(chain, 0, &count, 'i'); 779 } 780 return 0; 781 } 782 783 static 784 int 785 hammer2_ioctl_bulkfree_scan(hammer2_inode_t *ip, void *data) 786 { 787 hammer2_ioc_bulkfree_t *bfi = data; 788 hammer2_dev_t *hmp = ip->pmp->iroot->cluster.focus->hmp; 789 int error; 790 791 /* XXX run local cluster targets only */ 792 error = hammer2_bulkfree_pass(hmp, bfi); 793 794 return error; 795 } 796