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 the PFS associated with the file descriptor, pass 366 * name_key set to (hammer2_key_t)-1. 367 */ 368 static int 369 hammer2_ioctl_pfs_get(hammer2_inode_t *ip, void *data) 370 { 371 const hammer2_inode_data_t *ripdata; 372 hammer2_dev_t *hmp; 373 hammer2_ioc_pfs_t *pfs; 374 hammer2_cluster_t *cparent; 375 hammer2_cluster_t *rcluster; 376 hammer2_cluster_t *cluster; 377 hammer2_key_t key_next; 378 int error; 379 380 error = 0; 381 hmp = ip->pmp->iroot->cluster.focus->hmp; /* XXX */ 382 pfs = data; 383 hammer2_inode_lock(hmp->spmp->iroot, HAMMER2_RESOLVE_ALWAYS); 384 cparent = hammer2_inode_cluster(hmp->spmp->iroot, 385 HAMMER2_RESOLVE_ALWAYS); 386 hammer2_inode_lock(ip->pmp->iroot, HAMMER2_RESOLVE_ALWAYS); 387 rcluster = hammer2_inode_cluster(ip->pmp->iroot, 388 HAMMER2_RESOLVE_ALWAYS); 389 390 /* 391 * Search for the first key or specific key. Remember that keys 392 * can be returned in any order. 393 */ 394 if (pfs->name_key == 0) { 395 cluster = hammer2_cluster_lookup(cparent, &key_next, 396 0, (hammer2_key_t)-1, 397 0); 398 } else if (pfs->name_key == (hammer2_key_t)-1) { 399 ripdata = &hammer2_cluster_rdata(rcluster)->ipdata; 400 cluster = hammer2_cluster_lookup(cparent, &key_next, 401 ripdata->meta.name_key, 402 ripdata->meta.name_key, 403 0); 404 ripdata = NULL; /* safety */ 405 } else { 406 cluster = hammer2_cluster_lookup(cparent, &key_next, 407 pfs->name_key, pfs->name_key, 408 0); 409 } 410 hammer2_inode_unlock(ip->pmp->iroot, rcluster); 411 412 while (cluster && 413 hammer2_cluster_type(cluster) != HAMMER2_BREF_TYPE_INODE) { 414 cluster = hammer2_cluster_next(cparent, cluster, &key_next, 415 key_next, (hammer2_key_t)-1, 416 0); 417 } 418 if (cluster) { 419 /* 420 * Load the data being returned by the ioctl. 421 */ 422 ripdata = &hammer2_cluster_rdata(cluster)->ipdata; 423 pfs->name_key = ripdata->meta.name_key; 424 pfs->pfs_type = ripdata->meta.pfs_type; 425 pfs->pfs_subtype = ripdata->meta.pfs_subtype; 426 pfs->pfs_clid = ripdata->meta.pfs_clid; 427 pfs->pfs_fsid = ripdata->meta.pfs_fsid; 428 KKASSERT(ripdata->meta.name_len < sizeof(pfs->name)); 429 bcopy(ripdata->filename, pfs->name, ripdata->meta.name_len); 430 pfs->name[ripdata->meta.name_len] = 0; 431 ripdata = NULL; /* safety */ 432 433 /* 434 * Calculate the next field 435 */ 436 do { 437 cluster = hammer2_cluster_next(cparent, cluster, 438 &key_next, 439 0, (hammer2_key_t)-1, 440 0); 441 } while (cluster && 442 hammer2_cluster_type(cluster) != 443 HAMMER2_BREF_TYPE_INODE); 444 if (cluster) { 445 ripdata = &hammer2_cluster_rdata(cluster)->ipdata; 446 pfs->name_next = ripdata->meta.name_key; 447 hammer2_cluster_unlock(cluster); 448 hammer2_cluster_drop(cluster); 449 } else { 450 pfs->name_next = (hammer2_key_t)-1; 451 } 452 } else { 453 pfs->name_next = (hammer2_key_t)-1; 454 error = ENOENT; 455 } 456 hammer2_inode_unlock(hmp->spmp->iroot, cparent); 457 458 return (error); 459 } 460 461 /* 462 * Find a specific PFS by name 463 */ 464 static int 465 hammer2_ioctl_pfs_lookup(hammer2_inode_t *ip, void *data) 466 { 467 const hammer2_inode_data_t *ripdata; 468 hammer2_dev_t *hmp; 469 hammer2_ioc_pfs_t *pfs; 470 hammer2_cluster_t *cparent; 471 hammer2_cluster_t *cluster; 472 hammer2_key_t key_next; 473 hammer2_key_t lhc; 474 int error; 475 size_t len; 476 477 error = 0; 478 hmp = ip->pmp->iroot->cluster.focus->hmp; /* XXX */ 479 pfs = data; 480 hammer2_inode_lock(hmp->spmp->iroot, HAMMER2_RESOLVE_ALWAYS | 481 HAMMER2_RESOLVE_SHARED); 482 cparent = hammer2_inode_cluster(hmp->spmp->iroot, 483 HAMMER2_RESOLVE_ALWAYS | 484 HAMMER2_RESOLVE_SHARED); 485 486 pfs->name[sizeof(pfs->name) - 1] = 0; 487 len = strlen(pfs->name); 488 lhc = hammer2_dirhash(pfs->name, len); 489 490 cluster = hammer2_cluster_lookup(cparent, &key_next, 491 lhc, lhc + HAMMER2_DIRHASH_LOMASK, 492 HAMMER2_LOOKUP_SHARED); 493 while (cluster) { 494 if (hammer2_cluster_type(cluster) == HAMMER2_BREF_TYPE_INODE) { 495 ripdata = &hammer2_cluster_rdata(cluster)->ipdata; 496 if (ripdata->meta.name_len == len && 497 bcmp(ripdata->filename, pfs->name, len) == 0) { 498 break; 499 } 500 ripdata = NULL; /* safety */ 501 } 502 cluster = hammer2_cluster_next(cparent, cluster, &key_next, 503 key_next, 504 lhc + HAMMER2_DIRHASH_LOMASK, 505 HAMMER2_LOOKUP_SHARED); 506 } 507 508 /* 509 * Load the data being returned by the ioctl. 510 */ 511 if (cluster) { 512 ripdata = &hammer2_cluster_rdata(cluster)->ipdata; 513 pfs->name_key = ripdata->meta.name_key; 514 pfs->pfs_type = ripdata->meta.pfs_type; 515 pfs->pfs_subtype = ripdata->meta.pfs_subtype; 516 pfs->pfs_clid = ripdata->meta.pfs_clid; 517 pfs->pfs_fsid = ripdata->meta.pfs_fsid; 518 ripdata = NULL; 519 520 hammer2_cluster_unlock(cluster); 521 hammer2_cluster_drop(cluster); 522 } else { 523 error = ENOENT; 524 } 525 hammer2_inode_unlock(hmp->spmp->iroot, cparent); 526 527 return (error); 528 } 529 530 /* 531 * Create a new PFS under the super-root 532 */ 533 static int 534 hammer2_ioctl_pfs_create(hammer2_inode_t *ip, void *data) 535 { 536 hammer2_inode_data_t *nipdata; 537 hammer2_dev_t *hmp; 538 hammer2_ioc_pfs_t *pfs; 539 hammer2_inode_t *nip; 540 hammer2_cluster_t *ncluster; 541 hammer2_trans_t trans; 542 hammer2_blockref_t bref; 543 int error; 544 545 hmp = ip->pmp->iroot->cluster.focus->hmp; /* XXX */ 546 pfs = data; 547 nip = NULL; 548 549 if (pfs->name[0] == 0) 550 return(EINVAL); 551 pfs->name[sizeof(pfs->name) - 1] = 0; /* ensure 0-termination */ 552 553 if (hammer2_ioctl_pfs_lookup(ip, pfs) == 0) 554 return(EEXIST); 555 556 hammer2_trans_init(&trans, hmp->spmp, HAMMER2_TRANS_NEWINODE); 557 nip = hammer2_inode_create(&trans, hmp->spmp->iroot, NULL, NULL, 558 pfs->name, strlen(pfs->name), 559 &ncluster, 560 HAMMER2_INSERT_PFSROOT, &error); 561 if (error == 0) { 562 nipdata = hammer2_cluster_modify_ip(&trans, nip, ncluster, 0); 563 nipdata->meta.pfs_type = pfs->pfs_type; 564 nipdata->meta.pfs_subtype = pfs->pfs_subtype; 565 nipdata->meta.pfs_clid = pfs->pfs_clid; 566 nipdata->meta.pfs_fsid = pfs->pfs_fsid; 567 nipdata->meta.op_flags |= HAMMER2_OPFLAG_PFSROOT; 568 569 /* 570 * Set default compression and check algorithm. This 571 * can be changed later. 572 * 573 * Do not allow compression on PFS's with the special name 574 * "boot", the boot loader can't decompress (yet). 575 */ 576 nipdata->meta.comp_algo = 577 HAMMER2_ENC_ALGO(HAMMER2_COMP_NEWFS_DEFAULT); 578 nipdata->meta.check_algo = 579 HAMMER2_ENC_ALGO( HAMMER2_CHECK_ISCSI32); 580 581 if (strcasecmp(pfs->name, "boot") == 0) { 582 nipdata->meta.comp_algo = 583 HAMMER2_ENC_ALGO(HAMMER2_COMP_AUTOZERO); 584 } 585 hammer2_cluster_modsync(ncluster); 586 hammer2_cluster_bref(ncluster, &bref); 587 #if 1 588 kprintf("ADD LOCAL PFS (IOCTL): %s\n", nipdata->filename); 589 hammer2_pfsalloc(ncluster, nipdata, bref.modify_tid); 590 /* XXX rescan */ 591 #endif 592 hammer2_inode_unlock(nip, ncluster); 593 } 594 hammer2_trans_done(&trans); 595 596 return (error); 597 } 598 599 /* 600 * Destroy an existing PFS under the super-root 601 */ 602 static int 603 hammer2_ioctl_pfs_delete(hammer2_inode_t *ip, void *data) 604 { 605 hammer2_dev_t *hmp; 606 hammer2_ioc_pfs_t *pfs = data; 607 hammer2_trans_t trans; 608 int error; 609 610 hmp = ip->pmp->iroot->cluster.focus->hmp; /* XXX */ 611 hammer2_trans_init(&trans, hmp->spmp, 0); 612 error = hammer2_unlink_file(&trans, hmp->spmp->iroot, NULL, 613 pfs->name, strlen(pfs->name), 614 2, NULL, NULL, -1); 615 hammer2_trans_done(&trans); 616 617 return (error); 618 } 619 620 static int 621 hammer2_ioctl_pfs_snapshot(hammer2_inode_t *ip, void *data) 622 { 623 hammer2_ioc_pfs_t *pfs = data; 624 hammer2_trans_t trans; 625 hammer2_cluster_t *cparent; 626 int error; 627 628 if (pfs->name[0] == 0) 629 return(EINVAL); 630 if (pfs->name[sizeof(pfs->name)-1] != 0) 631 return(EINVAL); 632 633 hammer2_vfs_sync(ip->pmp->mp, MNT_WAIT); 634 635 hammer2_trans_init(&trans, ip->pmp, 636 HAMMER2_TRANS_ISFLUSH | HAMMER2_TRANS_NEWINODE); 637 hammer2_inode_lock(ip, HAMMER2_RESOLVE_ALWAYS); 638 cparent = hammer2_inode_cluster(ip, HAMMER2_RESOLVE_ALWAYS); 639 error = hammer2_cluster_snapshot(&trans, cparent, pfs); 640 hammer2_inode_unlock(ip, cparent); 641 hammer2_trans_done(&trans); 642 643 return (error); 644 } 645 646 /* 647 * Retrieve the raw inode structure 648 */ 649 static int 650 hammer2_ioctl_inode_get(hammer2_inode_t *ip, void *data) 651 { 652 const hammer2_inode_data_t *ripdata; 653 hammer2_ioc_inode_t *ino; 654 hammer2_cluster_t *cluster; 655 int error; 656 657 ino = data; 658 659 hammer2_inode_lock(ip, HAMMER2_RESOLVE_ALWAYS | 660 HAMMER2_RESOLVE_SHARED); 661 cluster = hammer2_inode_cluster(ip, HAMMER2_RESOLVE_ALWAYS | 662 HAMMER2_RESOLVE_SHARED); 663 if (cluster->error) { 664 error = EIO; 665 } else { 666 ripdata = &hammer2_cluster_rdata(cluster)->ipdata; 667 ino->ip_data = *ripdata; 668 ino->kdata = ip; 669 ino->data_count = cluster->focus->bref.data_count; 670 ino->inode_count = cluster->focus->bref.inode_count; 671 error = 0; 672 } 673 hammer2_inode_unlock(ip, cluster); 674 675 return error; 676 } 677 678 /* 679 * Set various parameters in an inode which cannot be set through 680 * normal filesystem VNOPS. 681 */ 682 static int 683 hammer2_ioctl_inode_set(hammer2_inode_t *ip, void *data) 684 { 685 const hammer2_inode_data_t *ripdata; 686 hammer2_inode_data_t *wipdata; 687 hammer2_ioc_inode_t *ino = data; 688 hammer2_cluster_t *cparent; 689 hammer2_trans_t trans; 690 int error = 0; 691 int dosync = 0; 692 693 hammer2_trans_init(&trans, ip->pmp, 0); 694 hammer2_inode_lock(ip, HAMMER2_RESOLVE_ALWAYS); 695 cparent = hammer2_inode_cluster(ip, HAMMER2_RESOLVE_ALWAYS); 696 ripdata = &hammer2_cluster_rdata(cparent)->ipdata; 697 698 if (ino->ip_data.meta.check_algo != ripdata->meta.check_algo) { 699 wipdata = hammer2_cluster_modify_ip(&trans, ip, cparent, 0); 700 wipdata->meta.check_algo = ino->ip_data.meta.check_algo; 701 ripdata = wipdata; /* safety */ 702 hammer2_cluster_setmethod_check(&trans, cparent, 703 wipdata->meta.check_algo); 704 dosync = 1; 705 } 706 if (ino->ip_data.meta.comp_algo != ripdata->meta.comp_algo) { 707 wipdata = hammer2_cluster_modify_ip(&trans, ip, cparent, 0); 708 wipdata->meta.comp_algo = ino->ip_data.meta.comp_algo; 709 ripdata = wipdata; /* safety */ 710 dosync = 1; 711 } 712 ino->kdata = ip; 713 714 /* Ignore these flags for now...*/ 715 if (ino->flags & HAMMER2IOC_INODE_FLAG_IQUOTA) { 716 } 717 if (ino->flags & HAMMER2IOC_INODE_FLAG_DQUOTA) { 718 } 719 if (ino->flags & HAMMER2IOC_INODE_FLAG_COPIES) { 720 } 721 if (dosync) 722 hammer2_cluster_modsync(cparent); 723 hammer2_trans_done(&trans); 724 hammer2_inode_unlock(ip, cparent); 725 726 return (error); 727 } 728 729 static 730 int 731 hammer2_ioctl_debug_dump(hammer2_inode_t *ip) 732 { 733 hammer2_chain_t *chain; 734 int count = 1000; 735 int i; 736 737 for (i = 0; i < ip->cluster.nchains; ++i) { 738 chain = ip->cluster.array[i].chain; 739 if (chain == NULL) 740 continue; 741 hammer2_dump_chain(chain, 0, &count, 'i'); 742 } 743 return 0; 744 } 745 746 static 747 int 748 hammer2_ioctl_bulkfree_scan(hammer2_inode_t *ip, void *data) 749 { 750 hammer2_ioc_bulkfree_t *bfi = data; 751 hammer2_dev_t *hmp = ip->pmp->iroot->cluster.focus->hmp; 752 int error; 753 754 /* XXX run local cluster targets only */ 755 error = hammer2_bulkfree_pass(hmp, bfi); 756 757 return error; 758 } 759