1 /* 2 * Copyright (c) 2007-2008 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Matthew Dillon <dillon@backplane.com> 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * 3. Neither the name of The DragonFly Project nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific, prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, 27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include <sys/param.h> 36 #include <sys/systm.h> 37 #include <sys/kernel.h> 38 #include <sys/vnode.h> 39 #include <sys/mount.h> 40 #include <sys/malloc.h> 41 #include <sys/nlookup.h> 42 #include <sys/fcntl.h> 43 #include <sys/sysctl.h> 44 #include <sys/buf.h> 45 #include <sys/buf2.h> 46 #include "hammer.h" 47 48 /* 49 * NOTE! Global statistics may not be MPSAFE so HAMMER never uses them 50 * in conditionals. 51 */ 52 int hammer_supported_version = HAMMER_VOL_VERSION_DEFAULT; 53 int hammer_debug_io; 54 int hammer_debug_general; 55 int hammer_debug_debug = 1; /* medium-error panics */ 56 int hammer_debug_inode; 57 int hammer_debug_locks; 58 int hammer_debug_btree; 59 int hammer_debug_tid; 60 int hammer_debug_recover; /* -1 will disable, +1 will force */ 61 int hammer_debug_recover_faults; 62 int hammer_debug_critical; /* non-zero enter debugger on error */ 63 int hammer_cluster_enable = 1; /* enable read clustering by default */ 64 int hammer_live_dedup = 0; 65 int hammer_tdmux_ticks; 66 int hammer_count_fsyncs; 67 int hammer_count_inodes; 68 int hammer_count_iqueued; 69 int hammer_count_reclaims; 70 int hammer_count_records; 71 int hammer_count_record_datas; 72 int hammer_count_volumes; 73 int hammer_count_buffers; 74 int hammer_count_nodes; 75 int64_t hammer_count_extra_space_used; 76 int64_t hammer_stats_btree_lookups; 77 int64_t hammer_stats_btree_searches; 78 int64_t hammer_stats_btree_inserts; 79 int64_t hammer_stats_btree_deletes; 80 int64_t hammer_stats_btree_elements; 81 int64_t hammer_stats_btree_splits; 82 int64_t hammer_stats_btree_iterations; 83 int64_t hammer_stats_btree_root_iterations; 84 int64_t hammer_stats_record_iterations; 85 86 int64_t hammer_stats_file_read; 87 int64_t hammer_stats_file_write; 88 int64_t hammer_stats_file_iopsr; 89 int64_t hammer_stats_file_iopsw; 90 int64_t hammer_stats_disk_read; 91 int64_t hammer_stats_disk_write; 92 int64_t hammer_stats_inode_flushes; 93 int64_t hammer_stats_commits; 94 int64_t hammer_stats_undo; 95 int64_t hammer_stats_redo; 96 97 int hammer_count_dirtybufspace; /* global */ 98 int hammer_count_refedbufs; /* global */ 99 int hammer_count_reservations; 100 int hammer_count_io_running_read; 101 int hammer_count_io_running_write; 102 int hammer_count_io_locked; 103 int hammer_limit_dirtybufspace; /* per-mount */ 104 int hammer_limit_running_io; /* per-mount */ 105 int hammer_limit_recs; /* as a whole XXX */ 106 int hammer_limit_inode_recs = 2048; /* per inode */ 107 int hammer_limit_reclaims; 108 int hammer_live_dedup_cache_size = DEDUP_CACHE_SIZE; 109 int hammer_limit_redo = 4096 * 1024; /* per inode */ 110 int hammer_autoflush = 500; /* auto flush (typ on reclaim) */ 111 int hammer_bio_count; 112 int hammer_verify_zone; 113 int hammer_verify_data = 1; 114 int hammer_write_mode; 115 int hammer_double_buffer; 116 int hammer_yield_check = 16; 117 int hammer_fsync_mode = 3; 118 int64_t hammer_contention_count; 119 int64_t hammer_zone_limit; 120 121 /* 122 * Live dedup debug counters (sysctls are writable so that counters 123 * can be reset from userspace). 124 */ 125 int64_t hammer_live_dedup_vnode_bcmps = 0; 126 int64_t hammer_live_dedup_device_bcmps = 0; 127 int64_t hammer_live_dedup_findblk_failures = 0; 128 int64_t hammer_live_dedup_bmap_saves = 0; 129 130 131 SYSCTL_NODE(_vfs, OID_AUTO, hammer, CTLFLAG_RW, 0, "HAMMER filesystem"); 132 133 SYSCTL_INT(_vfs_hammer, OID_AUTO, supported_version, CTLFLAG_RD, 134 &hammer_supported_version, 0, ""); 135 SYSCTL_INT(_vfs_hammer, OID_AUTO, debug_general, CTLFLAG_RW, 136 &hammer_debug_general, 0, ""); 137 SYSCTL_INT(_vfs_hammer, OID_AUTO, debug_io, CTLFLAG_RW, 138 &hammer_debug_io, 0, ""); 139 SYSCTL_INT(_vfs_hammer, OID_AUTO, debug_debug, CTLFLAG_RW, 140 &hammer_debug_debug, 0, ""); 141 SYSCTL_INT(_vfs_hammer, OID_AUTO, debug_inode, CTLFLAG_RW, 142 &hammer_debug_inode, 0, ""); 143 SYSCTL_INT(_vfs_hammer, OID_AUTO, debug_locks, CTLFLAG_RW, 144 &hammer_debug_locks, 0, ""); 145 SYSCTL_INT(_vfs_hammer, OID_AUTO, debug_btree, CTLFLAG_RW, 146 &hammer_debug_btree, 0, ""); 147 SYSCTL_INT(_vfs_hammer, OID_AUTO, debug_tid, CTLFLAG_RW, 148 &hammer_debug_tid, 0, ""); 149 SYSCTL_INT(_vfs_hammer, OID_AUTO, debug_recover, CTLFLAG_RW, 150 &hammer_debug_recover, 0, ""); 151 SYSCTL_INT(_vfs_hammer, OID_AUTO, debug_recover_faults, CTLFLAG_RW, 152 &hammer_debug_recover_faults, 0, ""); 153 SYSCTL_INT(_vfs_hammer, OID_AUTO, debug_critical, CTLFLAG_RW, 154 &hammer_debug_critical, 0, ""); 155 SYSCTL_INT(_vfs_hammer, OID_AUTO, cluster_enable, CTLFLAG_RW, 156 &hammer_cluster_enable, 0, ""); 157 /* 158 * 0 - live dedup is disabled 159 * 1 - dedup cache is populated on reads only 160 * 2 - dedup cache is populated on both reads and writes 161 */ 162 SYSCTL_INT(_vfs_hammer, OID_AUTO, live_dedup, CTLFLAG_RW, 163 &hammer_live_dedup, 0, "Enable live dedup"); 164 SYSCTL_INT(_vfs_hammer, OID_AUTO, tdmux_ticks, CTLFLAG_RW, 165 &hammer_tdmux_ticks, 0, "Hammer tdmux ticks"); 166 167 SYSCTL_INT(_vfs_hammer, OID_AUTO, limit_dirtybufspace, CTLFLAG_RW, 168 &hammer_limit_dirtybufspace, 0, ""); 169 SYSCTL_INT(_vfs_hammer, OID_AUTO, limit_running_io, CTLFLAG_RW, 170 &hammer_limit_running_io, 0, ""); 171 SYSCTL_INT(_vfs_hammer, OID_AUTO, limit_recs, CTLFLAG_RW, 172 &hammer_limit_recs, 0, ""); 173 SYSCTL_INT(_vfs_hammer, OID_AUTO, limit_inode_recs, CTLFLAG_RW, 174 &hammer_limit_inode_recs, 0, ""); 175 SYSCTL_INT(_vfs_hammer, OID_AUTO, limit_reclaims, CTLFLAG_RW, 176 &hammer_limit_reclaims, 0, ""); 177 SYSCTL_INT(_vfs_hammer, OID_AUTO, live_dedup_cache_size, CTLFLAG_RW, 178 &hammer_live_dedup_cache_size, 0, 179 "Number of cache entries"); 180 SYSCTL_INT(_vfs_hammer, OID_AUTO, limit_redo, CTLFLAG_RW, 181 &hammer_limit_redo, 0, ""); 182 183 SYSCTL_INT(_vfs_hammer, OID_AUTO, count_fsyncs, CTLFLAG_RD, 184 &hammer_count_fsyncs, 0, ""); 185 SYSCTL_INT(_vfs_hammer, OID_AUTO, count_inodes, CTLFLAG_RD, 186 &hammer_count_inodes, 0, ""); 187 SYSCTL_INT(_vfs_hammer, OID_AUTO, count_iqueued, CTLFLAG_RD, 188 &hammer_count_iqueued, 0, ""); 189 SYSCTL_INT(_vfs_hammer, OID_AUTO, count_reclaims, CTLFLAG_RD, 190 &hammer_count_reclaims, 0, ""); 191 SYSCTL_INT(_vfs_hammer, OID_AUTO, count_records, CTLFLAG_RD, 192 &hammer_count_records, 0, ""); 193 SYSCTL_INT(_vfs_hammer, OID_AUTO, count_record_datas, CTLFLAG_RD, 194 &hammer_count_record_datas, 0, ""); 195 SYSCTL_INT(_vfs_hammer, OID_AUTO, count_volumes, CTLFLAG_RD, 196 &hammer_count_volumes, 0, ""); 197 SYSCTL_INT(_vfs_hammer, OID_AUTO, count_buffers, CTLFLAG_RD, 198 &hammer_count_buffers, 0, ""); 199 SYSCTL_INT(_vfs_hammer, OID_AUTO, count_nodes, CTLFLAG_RD, 200 &hammer_count_nodes, 0, ""); 201 SYSCTL_QUAD(_vfs_hammer, OID_AUTO, count_extra_space_used, CTLFLAG_RD, 202 &hammer_count_extra_space_used, 0, ""); 203 204 SYSCTL_QUAD(_vfs_hammer, OID_AUTO, stats_btree_searches, CTLFLAG_RD, 205 &hammer_stats_btree_searches, 0, ""); 206 SYSCTL_QUAD(_vfs_hammer, OID_AUTO, stats_btree_lookups, CTLFLAG_RD, 207 &hammer_stats_btree_lookups, 0, ""); 208 SYSCTL_QUAD(_vfs_hammer, OID_AUTO, stats_btree_inserts, CTLFLAG_RD, 209 &hammer_stats_btree_inserts, 0, ""); 210 SYSCTL_QUAD(_vfs_hammer, OID_AUTO, stats_btree_deletes, CTLFLAG_RD, 211 &hammer_stats_btree_deletes, 0, ""); 212 SYSCTL_QUAD(_vfs_hammer, OID_AUTO, stats_btree_elements, CTLFLAG_RD, 213 &hammer_stats_btree_elements, 0, ""); 214 SYSCTL_QUAD(_vfs_hammer, OID_AUTO, stats_btree_splits, CTLFLAG_RD, 215 &hammer_stats_btree_splits, 0, ""); 216 SYSCTL_QUAD(_vfs_hammer, OID_AUTO, stats_btree_iterations, CTLFLAG_RD, 217 &hammer_stats_btree_iterations, 0, ""); 218 SYSCTL_QUAD(_vfs_hammer, OID_AUTO, stats_btree_root_iterations, CTLFLAG_RD, 219 &hammer_stats_btree_root_iterations, 0, ""); 220 SYSCTL_QUAD(_vfs_hammer, OID_AUTO, stats_record_iterations, CTLFLAG_RD, 221 &hammer_stats_record_iterations, 0, ""); 222 223 SYSCTL_QUAD(_vfs_hammer, OID_AUTO, stats_file_read, CTLFLAG_RD, 224 &hammer_stats_file_read, 0, ""); 225 SYSCTL_QUAD(_vfs_hammer, OID_AUTO, stats_file_write, CTLFLAG_RD, 226 &hammer_stats_file_write, 0, ""); 227 SYSCTL_QUAD(_vfs_hammer, OID_AUTO, stats_file_iopsr, CTLFLAG_RD, 228 &hammer_stats_file_iopsr, 0, ""); 229 SYSCTL_QUAD(_vfs_hammer, OID_AUTO, stats_file_iopsw, CTLFLAG_RD, 230 &hammer_stats_file_iopsw, 0, ""); 231 SYSCTL_QUAD(_vfs_hammer, OID_AUTO, stats_disk_read, CTLFLAG_RD, 232 &hammer_stats_disk_read, 0, ""); 233 SYSCTL_QUAD(_vfs_hammer, OID_AUTO, stats_disk_write, CTLFLAG_RD, 234 &hammer_stats_disk_write, 0, ""); 235 SYSCTL_QUAD(_vfs_hammer, OID_AUTO, stats_inode_flushes, CTLFLAG_RD, 236 &hammer_stats_inode_flushes, 0, ""); 237 SYSCTL_QUAD(_vfs_hammer, OID_AUTO, stats_commits, CTLFLAG_RD, 238 &hammer_stats_commits, 0, ""); 239 SYSCTL_QUAD(_vfs_hammer, OID_AUTO, stats_undo, CTLFLAG_RD, 240 &hammer_stats_undo, 0, ""); 241 SYSCTL_QUAD(_vfs_hammer, OID_AUTO, stats_redo, CTLFLAG_RD, 242 &hammer_stats_redo, 0, ""); 243 244 SYSCTL_QUAD(_vfs_hammer, OID_AUTO, live_dedup_vnode_bcmps, CTLFLAG_RW, 245 &hammer_live_dedup_vnode_bcmps, 0, 246 "successful vnode buffer comparisons"); 247 SYSCTL_QUAD(_vfs_hammer, OID_AUTO, live_dedup_device_bcmps, CTLFLAG_RW, 248 &hammer_live_dedup_device_bcmps, 0, 249 "successful device buffer comparisons"); 250 SYSCTL_QUAD(_vfs_hammer, OID_AUTO, live_dedup_findblk_failures, CTLFLAG_RW, 251 &hammer_live_dedup_findblk_failures, 0, 252 "block lookup failures for comparison"); 253 SYSCTL_QUAD(_vfs_hammer, OID_AUTO, live_dedup_bmap_saves, CTLFLAG_RW, 254 &hammer_live_dedup_bmap_saves, 0, 255 "useful physical block lookups"); 256 257 SYSCTL_INT(_vfs_hammer, OID_AUTO, count_dirtybufspace, CTLFLAG_RD, 258 &hammer_count_dirtybufspace, 0, ""); 259 SYSCTL_INT(_vfs_hammer, OID_AUTO, count_refedbufs, CTLFLAG_RD, 260 &hammer_count_refedbufs, 0, ""); 261 SYSCTL_INT(_vfs_hammer, OID_AUTO, count_reservations, CTLFLAG_RD, 262 &hammer_count_reservations, 0, ""); 263 SYSCTL_INT(_vfs_hammer, OID_AUTO, count_io_running_read, CTLFLAG_RD, 264 &hammer_count_io_running_read, 0, ""); 265 SYSCTL_INT(_vfs_hammer, OID_AUTO, count_io_locked, CTLFLAG_RD, 266 &hammer_count_io_locked, 0, ""); 267 SYSCTL_INT(_vfs_hammer, OID_AUTO, count_io_running_write, CTLFLAG_RD, 268 &hammer_count_io_running_write, 0, ""); 269 SYSCTL_QUAD(_vfs_hammer, OID_AUTO, zone_limit, CTLFLAG_RW, 270 &hammer_zone_limit, 0, ""); 271 SYSCTL_QUAD(_vfs_hammer, OID_AUTO, contention_count, CTLFLAG_RW, 272 &hammer_contention_count, 0, ""); 273 SYSCTL_INT(_vfs_hammer, OID_AUTO, autoflush, CTLFLAG_RW, 274 &hammer_autoflush, 0, ""); 275 SYSCTL_INT(_vfs_hammer, OID_AUTO, verify_zone, CTLFLAG_RW, 276 &hammer_verify_zone, 0, ""); 277 SYSCTL_INT(_vfs_hammer, OID_AUTO, verify_data, CTLFLAG_RW, 278 &hammer_verify_data, 0, ""); 279 SYSCTL_INT(_vfs_hammer, OID_AUTO, write_mode, CTLFLAG_RW, 280 &hammer_write_mode, 0, ""); 281 SYSCTL_INT(_vfs_hammer, OID_AUTO, double_buffer, CTLFLAG_RW, 282 &hammer_double_buffer, 0, ""); 283 SYSCTL_INT(_vfs_hammer, OID_AUTO, yield_check, CTLFLAG_RW, 284 &hammer_yield_check, 0, ""); 285 SYSCTL_INT(_vfs_hammer, OID_AUTO, fsync_mode, CTLFLAG_RW, 286 &hammer_fsync_mode, 0, ""); 287 288 /* KTR_INFO_MASTER(hammer); */ 289 290 /* 291 * VFS ABI 292 */ 293 static void hammer_free_hmp(struct mount *mp); 294 295 static int hammer_vfs_mount(struct mount *mp, char *path, caddr_t data, 296 struct ucred *cred); 297 static int hammer_vfs_unmount(struct mount *mp, int mntflags); 298 static int hammer_vfs_root(struct mount *mp, struct vnode **vpp); 299 static int hammer_vfs_statfs(struct mount *mp, struct statfs *sbp, 300 struct ucred *cred); 301 static int hammer_vfs_statvfs(struct mount *mp, struct statvfs *sbp, 302 struct ucred *cred); 303 static int hammer_vfs_sync(struct mount *mp, int waitfor); 304 static int hammer_vfs_vget(struct mount *mp, struct vnode *dvp, 305 ino_t ino, struct vnode **vpp); 306 static int hammer_vfs_init(struct vfsconf *conf); 307 static int hammer_vfs_fhtovp(struct mount *mp, struct vnode *rootvp, 308 struct fid *fhp, struct vnode **vpp); 309 static int hammer_vfs_vptofh(struct vnode *vp, struct fid *fhp); 310 static int hammer_vfs_checkexp(struct mount *mp, struct sockaddr *nam, 311 int *exflagsp, struct ucred **credanonp); 312 313 314 static struct vfsops hammer_vfsops = { 315 .vfs_mount = hammer_vfs_mount, 316 .vfs_unmount = hammer_vfs_unmount, 317 .vfs_root = hammer_vfs_root, 318 .vfs_statfs = hammer_vfs_statfs, 319 .vfs_statvfs = hammer_vfs_statvfs, 320 .vfs_sync = hammer_vfs_sync, 321 .vfs_vget = hammer_vfs_vget, 322 .vfs_init = hammer_vfs_init, 323 .vfs_vptofh = hammer_vfs_vptofh, 324 .vfs_fhtovp = hammer_vfs_fhtovp, 325 .vfs_checkexp = hammer_vfs_checkexp 326 }; 327 328 MALLOC_DEFINE(M_HAMMER, "HAMMER-mount", ""); 329 330 VFS_SET(hammer_vfsops, hammer, 0); 331 MODULE_VERSION(hammer, 1); 332 333 static int 334 hammer_vfs_init(struct vfsconf *conf) 335 { 336 int n; 337 338 /* 339 * Wait up to this long for an exclusive deadlock to clear 340 * before acquiring a new shared lock on the ip. The deadlock 341 * may have occured on a b-tree node related to the ip. 342 */ 343 if (hammer_tdmux_ticks == 0) 344 hammer_tdmux_ticks = hz / 5; 345 346 /* 347 * Autosize 348 */ 349 if (hammer_limit_recs == 0) { 350 hammer_limit_recs = nbuf * 25; 351 n = kmalloc_limit(M_HAMMER) / 512; 352 if (hammer_limit_recs > n) 353 hammer_limit_recs = n; 354 } 355 if (hammer_limit_dirtybufspace == 0) { 356 hammer_limit_dirtybufspace = hidirtybufspace / 2; 357 if (hammer_limit_dirtybufspace < 100) 358 hammer_limit_dirtybufspace = 100; 359 } 360 361 /* 362 * Set reasonable limits to maintain an I/O pipeline. This is 363 * used by the flush code which explicitly initiates I/O, and 364 * is per-mount. 365 * 366 * The system-driven buffer cache uses vfs.lorunningspace and 367 * vfs.hirunningspace globally. 368 */ 369 if (hammer_limit_running_io == 0) 370 hammer_limit_running_io = hammer_limit_dirtybufspace; 371 372 if (hammer_limit_running_io > 10 * 1024 * 1024) 373 hammer_limit_running_io = 10 * 1024 * 1024; 374 375 /* 376 * The hammer_inode structure detaches from the vnode on reclaim. 377 * This limits the number of inodes in this state to prevent a 378 * memory pool blowout. 379 */ 380 if (hammer_limit_reclaims == 0) 381 hammer_limit_reclaims = desiredvnodes / 10; 382 383 return(0); 384 } 385 386 static int 387 hammer_vfs_mount(struct mount *mp, char *mntpt, caddr_t data, 388 struct ucred *cred) 389 { 390 struct hammer_mount_info info; 391 hammer_mount_t hmp; 392 hammer_volume_t rootvol; 393 struct vnode *rootvp; 394 struct vnode *devvp = NULL; 395 const char *upath; /* volume name in userspace */ 396 char *path; /* volume name in system space */ 397 int error; 398 int i; 399 int master_id; 400 char *next_volume_ptr = NULL; 401 402 /* 403 * Accept hammer_mount_info. mntpt is NULL for root mounts at boot. 404 */ 405 if (mntpt == NULL) { 406 bzero(&info, sizeof(info)); 407 info.asof = 0; 408 info.hflags = 0; 409 info.nvolumes = 1; 410 411 next_volume_ptr = mp->mnt_stat.f_mntfromname; 412 413 /* Count number of volumes separated by ':' */ 414 for (char *p = next_volume_ptr; *p != '\0'; ++p) { 415 if (*p == ':') { 416 ++info.nvolumes; 417 } 418 } 419 420 mp->mnt_flag &= ~MNT_RDONLY; /* mount R/W */ 421 } else { 422 if ((error = copyin(data, &info, sizeof(info))) != 0) 423 return (error); 424 } 425 426 /* 427 * updating or new mount 428 */ 429 if (mp->mnt_flag & MNT_UPDATE) { 430 hmp = (void *)mp->mnt_data; 431 KKASSERT(hmp != NULL); 432 } else { 433 if (info.nvolumes <= 0 || info.nvolumes >= 32768) 434 return (EINVAL); 435 hmp = NULL; 436 } 437 438 /* 439 * master-id validation. The master id may not be changed by a 440 * mount update. 441 */ 442 if (info.hflags & HMNT_MASTERID) { 443 if (hmp && hmp->master_id != info.master_id) { 444 kprintf("hammer: cannot change master id " 445 "with mount update\n"); 446 return(EINVAL); 447 } 448 master_id = info.master_id; 449 if (master_id < -1 || master_id >= HAMMER_MAX_MASTERS) 450 return (EINVAL); 451 } else { 452 if (hmp) 453 master_id = hmp->master_id; 454 else 455 master_id = 0; 456 } 457 458 /* 459 * Internal mount data structure 460 */ 461 if (hmp == NULL) { 462 hmp = kmalloc(sizeof(*hmp), M_HAMMER, M_WAITOK | M_ZERO); 463 mp->mnt_data = (qaddr_t)hmp; 464 hmp->mp = mp; 465 /*TAILQ_INIT(&hmp->recycle_list);*/ 466 467 /* 468 * Make sure kmalloc type limits are set appropriately. 469 * 470 * Our inode kmalloc group is sized based on maxvnodes 471 * (controlled by the system, not us). 472 */ 473 kmalloc_create(&hmp->m_misc, "HAMMER-others"); 474 kmalloc_create(&hmp->m_inodes, "HAMMER-inodes"); 475 476 kmalloc_raise_limit(hmp->m_inodes, 0); /* unlimited */ 477 478 hmp->root_btree_beg.localization = 0x00000000U; 479 hmp->root_btree_beg.obj_id = -0x8000000000000000LL; 480 hmp->root_btree_beg.key = -0x8000000000000000LL; 481 hmp->root_btree_beg.create_tid = 1; 482 hmp->root_btree_beg.delete_tid = 1; 483 hmp->root_btree_beg.rec_type = 0; 484 hmp->root_btree_beg.obj_type = 0; 485 486 hmp->root_btree_end.localization = 0xFFFFFFFFU; 487 hmp->root_btree_end.obj_id = 0x7FFFFFFFFFFFFFFFLL; 488 hmp->root_btree_end.key = 0x7FFFFFFFFFFFFFFFLL; 489 hmp->root_btree_end.create_tid = 0xFFFFFFFFFFFFFFFFULL; 490 hmp->root_btree_end.delete_tid = 0; /* special case */ 491 hmp->root_btree_end.rec_type = 0xFFFFU; 492 hmp->root_btree_end.obj_type = 0; 493 494 hmp->krate.freq = 1; /* maximum reporting rate (hz) */ 495 hmp->krate.count = -16; /* initial burst */ 496 497 hmp->sync_lock.refs = 1; 498 hmp->free_lock.refs = 1; 499 hmp->undo_lock.refs = 1; 500 hmp->blkmap_lock.refs = 1; 501 hmp->snapshot_lock.refs = 1; 502 hmp->volume_lock.refs = 1; 503 504 TAILQ_INIT(&hmp->delay_list); 505 TAILQ_INIT(&hmp->flush_group_list); 506 TAILQ_INIT(&hmp->objid_cache_list); 507 TAILQ_INIT(&hmp->undo_lru_list); 508 TAILQ_INIT(&hmp->reclaim_list); 509 510 RB_INIT(&hmp->rb_dedup_crc_root); 511 RB_INIT(&hmp->rb_dedup_off_root); 512 TAILQ_INIT(&hmp->dedup_lru_list); 513 } 514 hmp->hflags &= ~HMNT_USERFLAGS; 515 hmp->hflags |= info.hflags & HMNT_USERFLAGS; 516 517 hmp->master_id = master_id; 518 519 if (info.asof) { 520 mp->mnt_flag |= MNT_RDONLY; 521 hmp->asof = info.asof; 522 } else { 523 hmp->asof = HAMMER_MAX_TID; 524 } 525 526 hmp->volume_to_remove = -1; 527 528 /* 529 * Re-open read-write if originally read-only, or vise-versa. 530 * 531 * When going from read-only to read-write execute the stage2 532 * recovery if it has not already been run. 533 */ 534 if (mp->mnt_flag & MNT_UPDATE) { 535 lwkt_gettoken(&hmp->fs_token); 536 error = 0; 537 if (hmp->ronly && (mp->mnt_kern_flag & MNTK_WANTRDWR)) { 538 kprintf("HAMMER read-only -> read-write\n"); 539 hmp->ronly = 0; 540 RB_SCAN(hammer_vol_rb_tree, &hmp->rb_vols_root, NULL, 541 hammer_adjust_volume_mode, NULL); 542 rootvol = hammer_get_root_volume(hmp, &error); 543 if (rootvol) { 544 hammer_recover_flush_buffers(hmp, rootvol, 1); 545 error = hammer_recover_stage2(hmp, rootvol); 546 bcopy(rootvol->ondisk->vol0_blockmap, 547 hmp->blockmap, 548 sizeof(hmp->blockmap)); 549 hammer_rel_volume(rootvol, 0); 550 } 551 RB_SCAN(hammer_ino_rb_tree, &hmp->rb_inos_root, NULL, 552 hammer_reload_inode, NULL); 553 /* kernel clears MNT_RDONLY */ 554 } else if (hmp->ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { 555 kprintf("HAMMER read-write -> read-only\n"); 556 hmp->ronly = 1; /* messy */ 557 RB_SCAN(hammer_ino_rb_tree, &hmp->rb_inos_root, NULL, 558 hammer_reload_inode, NULL); 559 hmp->ronly = 0; 560 hammer_flusher_sync(hmp); 561 hammer_flusher_sync(hmp); 562 hammer_flusher_sync(hmp); 563 hmp->ronly = 1; 564 RB_SCAN(hammer_vol_rb_tree, &hmp->rb_vols_root, NULL, 565 hammer_adjust_volume_mode, NULL); 566 } 567 lwkt_reltoken(&hmp->fs_token); 568 return(error); 569 } 570 571 RB_INIT(&hmp->rb_vols_root); 572 RB_INIT(&hmp->rb_inos_root); 573 RB_INIT(&hmp->rb_redo_root); 574 RB_INIT(&hmp->rb_nods_root); 575 RB_INIT(&hmp->rb_undo_root); 576 RB_INIT(&hmp->rb_resv_root); 577 RB_INIT(&hmp->rb_bufs_root); 578 RB_INIT(&hmp->rb_pfsm_root); 579 580 hmp->ronly = ((mp->mnt_flag & MNT_RDONLY) != 0); 581 582 RB_INIT(&hmp->volu_root); 583 RB_INIT(&hmp->undo_root); 584 RB_INIT(&hmp->data_root); 585 RB_INIT(&hmp->meta_root); 586 RB_INIT(&hmp->lose_root); 587 TAILQ_INIT(&hmp->iorun_list); 588 589 lwkt_token_init(&hmp->fs_token, "hammerfs"); 590 lwkt_token_init(&hmp->io_token, "hammerio"); 591 592 lwkt_gettoken(&hmp->fs_token); 593 594 /* 595 * Load volumes 596 */ 597 path = objcache_get(namei_oc, M_WAITOK); 598 hmp->nvolumes = -1; 599 for (i = 0; i < info.nvolumes; ++i) { 600 if (mntpt == NULL) { 601 /* 602 * Root mount. 603 */ 604 KKASSERT(next_volume_ptr != NULL); 605 strcpy(path, ""); 606 if (*next_volume_ptr != '/') { 607 /* relative path */ 608 strcpy(path, "/dev/"); 609 } 610 int k; 611 for (k = strlen(path); k < MAXPATHLEN-1; ++k) { 612 if (*next_volume_ptr == '\0') { 613 break; 614 } else if (*next_volume_ptr == ':') { 615 ++next_volume_ptr; 616 break; 617 } else { 618 path[k] = *next_volume_ptr; 619 ++next_volume_ptr; 620 } 621 } 622 path[k] = '\0'; 623 624 error = 0; 625 cdev_t dev = kgetdiskbyname(path); 626 error = bdevvp(dev, &devvp); 627 if (error) { 628 kprintf("hammer_mountroot: can't find devvp\n"); 629 } 630 } else { 631 error = copyin(&info.volumes[i], &upath, 632 sizeof(char *)); 633 if (error == 0) 634 error = copyinstr(upath, path, 635 MAXPATHLEN, NULL); 636 } 637 if (error == 0) 638 error = hammer_install_volume(hmp, path, devvp); 639 if (error) 640 break; 641 } 642 objcache_put(namei_oc, path); 643 644 /* 645 * Make sure we found a root volume 646 */ 647 if (error == 0 && hmp->rootvol == NULL) { 648 kprintf("hammer_mount: No root volume found!\n"); 649 error = EINVAL; 650 } 651 652 /* 653 * Check that all required volumes are available 654 */ 655 if (error == 0 && hammer_mountcheck_volumes(hmp)) { 656 kprintf("hammer_mount: Missing volumes, cannot mount!\n"); 657 error = EINVAL; 658 } 659 660 if (error) { 661 /* called with fs_token held */ 662 hammer_free_hmp(mp); 663 return (error); 664 } 665 666 /* 667 * No errors, setup enough of the mount point so we can lookup the 668 * root vnode. 669 */ 670 mp->mnt_iosize_max = MAXPHYS; 671 mp->mnt_kern_flag |= MNTK_FSMID; 672 673 /* 674 * MPSAFE code. Note that VOPs and VFSops which are not MPSAFE 675 * will acquire a per-mount token prior to entry and release it 676 * on return, so even if we do not specify it we no longer get 677 * the BGL regardlless of how we are flagged. 678 */ 679 mp->mnt_kern_flag |= MNTK_ALL_MPSAFE; 680 /*MNTK_RD_MPSAFE | MNTK_GA_MPSAFE | MNTK_IN_MPSAFE;*/ 681 682 /* 683 * note: f_iosize is used by vnode_pager_haspage() when constructing 684 * its VOP_BMAP call. 685 */ 686 mp->mnt_stat.f_iosize = HAMMER_BUFSIZE; 687 mp->mnt_stat.f_bsize = HAMMER_BUFSIZE; 688 689 mp->mnt_vstat.f_frsize = HAMMER_BUFSIZE; 690 mp->mnt_vstat.f_bsize = HAMMER_BUFSIZE; 691 692 mp->mnt_maxsymlinklen = 255; 693 mp->mnt_flag |= MNT_LOCAL; 694 695 vfs_add_vnodeops(mp, &hammer_vnode_vops, &mp->mnt_vn_norm_ops); 696 vfs_add_vnodeops(mp, &hammer_spec_vops, &mp->mnt_vn_spec_ops); 697 vfs_add_vnodeops(mp, &hammer_fifo_vops, &mp->mnt_vn_fifo_ops); 698 699 /* 700 * The root volume's ondisk pointer is only valid if we hold a 701 * reference to it. 702 */ 703 rootvol = hammer_get_root_volume(hmp, &error); 704 if (error) 705 goto failed; 706 707 /* 708 * Perform any necessary UNDO operations. The recovery code does 709 * call hammer_undo_lookup() so we have to pre-cache the blockmap, 710 * and then re-copy it again after recovery is complete. 711 * 712 * If this is a read-only mount the UNDO information is retained 713 * in memory in the form of dirty buffer cache buffers, and not 714 * written back to the media. 715 */ 716 bcopy(rootvol->ondisk->vol0_blockmap, hmp->blockmap, 717 sizeof(hmp->blockmap)); 718 719 /* 720 * Check filesystem version 721 */ 722 hmp->version = rootvol->ondisk->vol_version; 723 if (hmp->version < HAMMER_VOL_VERSION_MIN || 724 hmp->version > HAMMER_VOL_VERSION_MAX) { 725 kprintf("HAMMER: mount unsupported fs version %d\n", 726 hmp->version); 727 error = ERANGE; 728 goto done; 729 } 730 731 /* 732 * The undo_rec_limit limits the size of flush groups to avoid 733 * blowing out the UNDO FIFO. This calculation is typically in 734 * the tens of thousands and is designed primarily when small 735 * HAMMER filesystems are created. 736 */ 737 hmp->undo_rec_limit = hammer_undo_max(hmp) / 8192 + 100; 738 if (hammer_debug_general & 0x0001) 739 kprintf("HAMMER: undo_rec_limit %d\n", hmp->undo_rec_limit); 740 741 /* 742 * NOTE: Recover stage1 not only handles meta-data recovery, it 743 * also sets hmp->undo_seqno for HAMMER VERSION 4+ filesystems. 744 */ 745 error = hammer_recover_stage1(hmp, rootvol); 746 if (error) { 747 kprintf("Failed to recover HAMMER filesystem on mount\n"); 748 goto done; 749 } 750 751 /* 752 * Finish setup now that we have a good root volume. 753 * 754 * The top 16 bits of fsid.val[1] is a pfs id. 755 */ 756 ksnprintf(mp->mnt_stat.f_mntfromname, 757 sizeof(mp->mnt_stat.f_mntfromname), "%s", 758 rootvol->ondisk->vol_name); 759 mp->mnt_stat.f_fsid.val[0] = 760 crc32((char *)&rootvol->ondisk->vol_fsid + 0, 8); 761 mp->mnt_stat.f_fsid.val[1] = 762 crc32((char *)&rootvol->ondisk->vol_fsid + 8, 8); 763 mp->mnt_stat.f_fsid.val[1] &= 0x0000FFFF; 764 765 mp->mnt_vstat.f_fsid_uuid = rootvol->ondisk->vol_fsid; 766 mp->mnt_vstat.f_fsid = crc32(&mp->mnt_vstat.f_fsid_uuid, 767 sizeof(mp->mnt_vstat.f_fsid_uuid)); 768 769 /* 770 * Certain often-modified fields in the root volume are cached in 771 * the hammer_mount structure so we do not have to generate lots 772 * of little UNDO structures for them. 773 * 774 * Recopy after recovery. This also has the side effect of 775 * setting our cached undo FIFO's first_offset, which serves to 776 * placemark the FIFO start for the NEXT flush cycle while the 777 * on-disk first_offset represents the LAST flush cycle. 778 */ 779 hmp->next_tid = rootvol->ondisk->vol0_next_tid; 780 hmp->flush_tid1 = hmp->next_tid; 781 hmp->flush_tid2 = hmp->next_tid; 782 bcopy(rootvol->ondisk->vol0_blockmap, hmp->blockmap, 783 sizeof(hmp->blockmap)); 784 hmp->copy_stat_freebigblocks = rootvol->ondisk->vol0_stat_freebigblocks; 785 786 hammer_flusher_create(hmp); 787 788 /* 789 * Locate the root directory using the root cluster's B-Tree as a 790 * starting point. The root directory uses an obj_id of 1. 791 * 792 * FUTURE: Leave the root directory cached referenced but unlocked 793 * in hmp->rootvp (need to flush it on unmount). 794 */ 795 error = hammer_vfs_vget(mp, NULL, 1, &rootvp); 796 if (error) 797 goto done; 798 vput(rootvp); 799 /*vn_unlock(hmp->rootvp);*/ 800 if (hmp->ronly == 0) 801 error = hammer_recover_stage2(hmp, rootvol); 802 803 /* 804 * If the stage2 recovery fails be sure to clean out all cached 805 * vnodes before throwing away the mount structure or bad things 806 * will happen. 807 */ 808 if (error) 809 vflush(mp, 0, 0); 810 811 done: 812 hammer_rel_volume(rootvol, 0); 813 failed: 814 /* 815 * Cleanup and return. 816 */ 817 if (error) { 818 /* called with fs_token held */ 819 hammer_free_hmp(mp); 820 } else { 821 lwkt_reltoken(&hmp->fs_token); 822 } 823 return (error); 824 } 825 826 static int 827 hammer_vfs_unmount(struct mount *mp, int mntflags) 828 { 829 hammer_mount_t hmp = (void *)mp->mnt_data; 830 int flags; 831 int error; 832 833 /* 834 * Clean out the vnodes 835 */ 836 lwkt_gettoken(&hmp->fs_token); 837 flags = 0; 838 if (mntflags & MNT_FORCE) 839 flags |= FORCECLOSE; 840 error = vflush(mp, 0, flags); 841 842 /* 843 * Clean up the internal mount structure and related entities. This 844 * may issue I/O. 845 */ 846 if (error == 0) { 847 /* called with fs_token held */ 848 hammer_free_hmp(mp); 849 } else { 850 lwkt_reltoken(&hmp->fs_token); 851 } 852 return(error); 853 } 854 855 /* 856 * Clean up the internal mount structure and disassociate it from the mount. 857 * This may issue I/O. 858 * 859 * Called with fs_token held. 860 */ 861 static void 862 hammer_free_hmp(struct mount *mp) 863 { 864 hammer_mount_t hmp = (void *)mp->mnt_data; 865 hammer_flush_group_t flg; 866 int count; 867 int dummy; 868 869 /* 870 * Flush anything dirty. This won't even run if the 871 * filesystem errored-out. 872 */ 873 count = 0; 874 while (hammer_flusher_haswork(hmp)) { 875 hammer_flusher_sync(hmp); 876 ++count; 877 if (count >= 5) { 878 if (count == 5) 879 kprintf("HAMMER: umount flushing."); 880 else 881 kprintf("."); 882 tsleep(&dummy, 0, "hmrufl", hz); 883 } 884 if (count == 30) { 885 kprintf("giving up\n"); 886 break; 887 } 888 } 889 if (count >= 5 && count < 30) 890 kprintf("\n"); 891 892 /* 893 * If the mount had a critical error we have to destroy any 894 * remaining inodes before we can finish cleaning up the flusher. 895 */ 896 if (hmp->flags & HAMMER_MOUNT_CRITICAL_ERROR) { 897 RB_SCAN(hammer_ino_rb_tree, &hmp->rb_inos_root, NULL, 898 hammer_destroy_inode_callback, NULL); 899 } 900 901 /* 902 * There shouldn't be any inodes left now and any left over 903 * flush groups should now be empty. 904 */ 905 KKASSERT(RB_EMPTY(&hmp->rb_inos_root)); 906 while ((flg = TAILQ_FIRST(&hmp->flush_group_list)) != NULL) { 907 TAILQ_REMOVE(&hmp->flush_group_list, flg, flush_entry); 908 KKASSERT(RB_EMPTY(&flg->flush_tree)); 909 if (flg->refs) { 910 kprintf("HAMMER: Warning, flush_group %p was " 911 "not empty on umount!\n", flg); 912 } 913 kfree(flg, hmp->m_misc); 914 } 915 916 /* 917 * We can finally destroy the flusher 918 */ 919 hammer_flusher_destroy(hmp); 920 921 /* 922 * We may have held recovered buffers due to a read-only mount. 923 * These must be discarded. 924 */ 925 if (hmp->ronly) 926 hammer_recover_flush_buffers(hmp, NULL, -1); 927 928 /* 929 * Unload buffers and then volumes 930 */ 931 RB_SCAN(hammer_buf_rb_tree, &hmp->rb_bufs_root, NULL, 932 hammer_unload_buffer, NULL); 933 RB_SCAN(hammer_vol_rb_tree, &hmp->rb_vols_root, NULL, 934 hammer_unload_volume, NULL); 935 936 mp->mnt_data = NULL; 937 mp->mnt_flag &= ~MNT_LOCAL; 938 hmp->mp = NULL; 939 hammer_destroy_objid_cache(hmp); 940 hammer_destroy_dedup_cache(hmp); 941 if (hmp->dedup_free_cache != NULL) { 942 kfree(hmp->dedup_free_cache, hmp->m_misc); 943 hmp->dedup_free_cache = NULL; 944 } 945 kmalloc_destroy(&hmp->m_misc); 946 kmalloc_destroy(&hmp->m_inodes); 947 lwkt_reltoken(&hmp->fs_token); 948 kfree(hmp, M_HAMMER); 949 } 950 951 /* 952 * Report critical errors. ip may be NULL. 953 */ 954 void 955 hammer_critical_error(hammer_mount_t hmp, hammer_inode_t ip, 956 int error, const char *msg) 957 { 958 hmp->flags |= HAMMER_MOUNT_CRITICAL_ERROR; 959 960 krateprintf(&hmp->krate, 961 "HAMMER(%s): Critical error inode=%jd error=%d %s\n", 962 hmp->mp->mnt_stat.f_mntfromname, 963 (intmax_t)(ip ? ip->obj_id : -1), 964 error, msg); 965 966 if (hmp->ronly == 0) { 967 hmp->ronly = 2; /* special errored read-only mode */ 968 hmp->mp->mnt_flag |= MNT_RDONLY; 969 RB_SCAN(hammer_vol_rb_tree, &hmp->rb_vols_root, NULL, 970 hammer_adjust_volume_mode, NULL); 971 kprintf("HAMMER(%s): Forcing read-only mode\n", 972 hmp->mp->mnt_stat.f_mntfromname); 973 } 974 hmp->error = error; 975 if (hammer_debug_critical) 976 Debugger("Entering debugger"); 977 } 978 979 980 /* 981 * Obtain a vnode for the specified inode number. An exclusively locked 982 * vnode is returned. 983 */ 984 int 985 hammer_vfs_vget(struct mount *mp, struct vnode *dvp, 986 ino_t ino, struct vnode **vpp) 987 { 988 struct hammer_transaction trans; 989 struct hammer_mount *hmp = (void *)mp->mnt_data; 990 struct hammer_inode *ip; 991 int error; 992 u_int32_t localization; 993 994 lwkt_gettoken(&hmp->fs_token); 995 hammer_simple_transaction(&trans, hmp); 996 997 /* 998 * If a directory vnode is supplied (mainly NFS) then we can acquire 999 * the PFS domain from it. Otherwise we would only be able to vget 1000 * inodes in the root PFS. 1001 */ 1002 if (dvp) { 1003 localization = HAMMER_DEF_LOCALIZATION + 1004 VTOI(dvp)->obj_localization; 1005 } else { 1006 localization = HAMMER_DEF_LOCALIZATION; 1007 } 1008 1009 /* 1010 * Lookup the requested HAMMER inode. The structure must be 1011 * left unlocked while we manipulate the related vnode to avoid 1012 * a deadlock. 1013 */ 1014 ip = hammer_get_inode(&trans, NULL, ino, 1015 hmp->asof, localization, 1016 0, &error); 1017 if (ip == NULL) { 1018 *vpp = NULL; 1019 } else { 1020 error = hammer_get_vnode(ip, vpp); 1021 hammer_rel_inode(ip, 0); 1022 } 1023 hammer_done_transaction(&trans); 1024 lwkt_reltoken(&hmp->fs_token); 1025 return (error); 1026 } 1027 1028 /* 1029 * Return the root vnode for the filesystem. 1030 * 1031 * HAMMER stores the root vnode in the hammer_mount structure so 1032 * getting it is easy. 1033 */ 1034 static int 1035 hammer_vfs_root(struct mount *mp, struct vnode **vpp) 1036 { 1037 int error; 1038 1039 error = hammer_vfs_vget(mp, NULL, 1, vpp); 1040 return (error); 1041 } 1042 1043 static int 1044 hammer_vfs_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred) 1045 { 1046 struct hammer_mount *hmp = (void *)mp->mnt_data; 1047 hammer_volume_t volume; 1048 hammer_volume_ondisk_t ondisk; 1049 int error; 1050 int64_t bfree; 1051 int64_t breserved; 1052 1053 lwkt_gettoken(&hmp->fs_token); 1054 volume = hammer_get_root_volume(hmp, &error); 1055 if (error) { 1056 lwkt_reltoken(&hmp->fs_token); 1057 return(error); 1058 } 1059 ondisk = volume->ondisk; 1060 1061 /* 1062 * Basic stats 1063 */ 1064 _hammer_checkspace(hmp, HAMMER_CHKSPC_WRITE, &breserved); 1065 mp->mnt_stat.f_files = ondisk->vol0_stat_inodes; 1066 bfree = ondisk->vol0_stat_freebigblocks * HAMMER_LARGEBLOCK_SIZE; 1067 hammer_rel_volume(volume, 0); 1068 1069 mp->mnt_stat.f_bfree = (bfree - breserved) / HAMMER_BUFSIZE; 1070 mp->mnt_stat.f_bavail = mp->mnt_stat.f_bfree; 1071 if (mp->mnt_stat.f_files < 0) 1072 mp->mnt_stat.f_files = 0; 1073 1074 *sbp = mp->mnt_stat; 1075 lwkt_reltoken(&hmp->fs_token); 1076 return(0); 1077 } 1078 1079 static int 1080 hammer_vfs_statvfs(struct mount *mp, struct statvfs *sbp, struct ucred *cred) 1081 { 1082 struct hammer_mount *hmp = (void *)mp->mnt_data; 1083 hammer_volume_t volume; 1084 hammer_volume_ondisk_t ondisk; 1085 int error; 1086 int64_t bfree; 1087 int64_t breserved; 1088 1089 lwkt_gettoken(&hmp->fs_token); 1090 volume = hammer_get_root_volume(hmp, &error); 1091 if (error) { 1092 lwkt_reltoken(&hmp->fs_token); 1093 return(error); 1094 } 1095 ondisk = volume->ondisk; 1096 1097 /* 1098 * Basic stats 1099 */ 1100 _hammer_checkspace(hmp, HAMMER_CHKSPC_WRITE, &breserved); 1101 mp->mnt_vstat.f_files = ondisk->vol0_stat_inodes; 1102 bfree = ondisk->vol0_stat_freebigblocks * HAMMER_LARGEBLOCK_SIZE; 1103 hammer_rel_volume(volume, 0); 1104 1105 mp->mnt_vstat.f_bfree = (bfree - breserved) / HAMMER_BUFSIZE; 1106 mp->mnt_vstat.f_bavail = mp->mnt_vstat.f_bfree; 1107 if (mp->mnt_vstat.f_files < 0) 1108 mp->mnt_vstat.f_files = 0; 1109 *sbp = mp->mnt_vstat; 1110 lwkt_reltoken(&hmp->fs_token); 1111 return(0); 1112 } 1113 1114 /* 1115 * Sync the filesystem. Currently we have to run it twice, the second 1116 * one will advance the undo start index to the end index, so if a crash 1117 * occurs no undos will be run on mount. 1118 * 1119 * We do not sync the filesystem if we are called from a panic. If we did 1120 * we might end up blowing up a sync that was already in progress. 1121 */ 1122 static int 1123 hammer_vfs_sync(struct mount *mp, int waitfor) 1124 { 1125 struct hammer_mount *hmp = (void *)mp->mnt_data; 1126 int error; 1127 1128 lwkt_gettoken(&hmp->fs_token); 1129 if (panicstr == NULL) { 1130 error = hammer_sync_hmp(hmp, waitfor); 1131 } else { 1132 error = EIO; 1133 } 1134 lwkt_reltoken(&hmp->fs_token); 1135 return (error); 1136 } 1137 1138 /* 1139 * Convert a vnode to a file handle. 1140 * 1141 * Accesses read-only fields on already-referenced structures so 1142 * no token is needed. 1143 */ 1144 static int 1145 hammer_vfs_vptofh(struct vnode *vp, struct fid *fhp) 1146 { 1147 hammer_inode_t ip; 1148 1149 KKASSERT(MAXFIDSZ >= 16); 1150 ip = VTOI(vp); 1151 fhp->fid_len = offsetof(struct fid, fid_data[16]); 1152 fhp->fid_ext = ip->obj_localization >> 16; 1153 bcopy(&ip->obj_id, fhp->fid_data + 0, sizeof(ip->obj_id)); 1154 bcopy(&ip->obj_asof, fhp->fid_data + 8, sizeof(ip->obj_asof)); 1155 return(0); 1156 } 1157 1158 1159 /* 1160 * Convert a file handle back to a vnode. 1161 * 1162 * Use rootvp to enforce PFS isolation when a PFS is exported via a 1163 * null mount. 1164 */ 1165 static int 1166 hammer_vfs_fhtovp(struct mount *mp, struct vnode *rootvp, 1167 struct fid *fhp, struct vnode **vpp) 1168 { 1169 hammer_mount_t hmp = (void *)mp->mnt_data; 1170 struct hammer_transaction trans; 1171 struct hammer_inode *ip; 1172 struct hammer_inode_info info; 1173 int error; 1174 u_int32_t localization; 1175 1176 bcopy(fhp->fid_data + 0, &info.obj_id, sizeof(info.obj_id)); 1177 bcopy(fhp->fid_data + 8, &info.obj_asof, sizeof(info.obj_asof)); 1178 if (rootvp) 1179 localization = VTOI(rootvp)->obj_localization; 1180 else 1181 localization = (u_int32_t)fhp->fid_ext << 16; 1182 1183 lwkt_gettoken(&hmp->fs_token); 1184 hammer_simple_transaction(&trans, hmp); 1185 1186 /* 1187 * Get/allocate the hammer_inode structure. The structure must be 1188 * unlocked while we manipulate the related vnode to avoid a 1189 * deadlock. 1190 */ 1191 ip = hammer_get_inode(&trans, NULL, info.obj_id, 1192 info.obj_asof, localization, 0, &error); 1193 if (ip) { 1194 error = hammer_get_vnode(ip, vpp); 1195 hammer_rel_inode(ip, 0); 1196 } else { 1197 *vpp = NULL; 1198 } 1199 hammer_done_transaction(&trans); 1200 lwkt_reltoken(&hmp->fs_token); 1201 return (error); 1202 } 1203 1204 static int 1205 hammer_vfs_checkexp(struct mount *mp, struct sockaddr *nam, 1206 int *exflagsp, struct ucred **credanonp) 1207 { 1208 hammer_mount_t hmp = (void *)mp->mnt_data; 1209 struct netcred *np; 1210 int error; 1211 1212 lwkt_gettoken(&hmp->fs_token); 1213 np = vfs_export_lookup(mp, &hmp->export, nam); 1214 if (np) { 1215 *exflagsp = np->netc_exflags; 1216 *credanonp = &np->netc_anon; 1217 error = 0; 1218 } else { 1219 error = EACCES; 1220 } 1221 lwkt_reltoken(&hmp->fs_token); 1222 return (error); 1223 1224 } 1225 1226 int 1227 hammer_vfs_export(struct mount *mp, int op, const struct export_args *export) 1228 { 1229 hammer_mount_t hmp = (void *)mp->mnt_data; 1230 int error; 1231 1232 lwkt_gettoken(&hmp->fs_token); 1233 1234 switch(op) { 1235 case MOUNTCTL_SET_EXPORT: 1236 error = vfs_export(mp, &hmp->export, export); 1237 break; 1238 default: 1239 error = EOPNOTSUPP; 1240 break; 1241 } 1242 lwkt_reltoken(&hmp->fs_token); 1243 1244 return(error); 1245 } 1246 1247