nandfs_vfsops.c revision 262211
1/*- 2 * Copyright (c) 2010-2012 Semihalf 3 * Copyright (c) 2008, 2009 Reinoud Zandijk 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 * From: NetBSD: nilfs_vfsops.c,v 1.1 2009/07/18 16:31:42 reinoud Exp 27 */ 28 29#include <sys/cdefs.h> 30__FBSDID("$FreeBSD: stable/10/sys/fs/nandfs/nandfs_vfsops.c 262211 2014-02-19 07:55:28Z dim $"); 31 32#include <sys/param.h> 33#include <sys/systm.h> 34#include <sys/fcntl.h> 35#include <sys/kernel.h> 36#include <sys/lock.h> 37#include <sys/malloc.h> 38#include <sys/mount.h> 39#include <sys/namei.h> 40#include <sys/proc.h> 41#include <sys/priv.h> 42#include <sys/vnode.h> 43#include <sys/buf.h> 44#include <sys/sysctl.h> 45#include <sys/libkern.h> 46 47#include <geom/geom.h> 48#include <geom/geom_vfs.h> 49 50#include <machine/_inttypes.h> 51 52#include <fs/nandfs/nandfs_mount.h> 53#include <fs/nandfs/nandfs.h> 54#include <fs/nandfs/nandfs_subr.h> 55 56static MALLOC_DEFINE(M_NANDFSMNT, "nandfs_mount", "NANDFS mount structure"); 57 58#define NANDFS_SET_SYSTEMFILE(vp) { \ 59 (vp)->v_vflag |= VV_SYSTEM; \ 60 vref(vp); \ 61 vput(vp); } 62 63#define NANDFS_UNSET_SYSTEMFILE(vp) { \ 64 VOP_LOCK(vp, LK_EXCLUSIVE); \ 65 MPASS(vp->v_bufobj.bo_dirty.bv_cnt == 0); \ 66 (vp)->v_vflag &= ~VV_SYSTEM; \ 67 vgone(vp); \ 68 vput(vp); } 69 70/* Globals */ 71struct _nandfs_devices nandfs_devices; 72 73/* Parameters */ 74int nandfs_verbose = 0; 75 76static void 77nandfs_tunable_init(void *arg) 78{ 79 80 TUNABLE_INT_FETCH("vfs.nandfs.verbose", &nandfs_verbose); 81} 82SYSINIT(nandfs_tunables, SI_SUB_VFS, SI_ORDER_ANY, nandfs_tunable_init, NULL); 83 84static SYSCTL_NODE(_vfs, OID_AUTO, nandfs, CTLFLAG_RD, 0, "NAND filesystem"); 85static SYSCTL_NODE(_vfs_nandfs, OID_AUTO, mount, CTLFLAG_RD, 0, 86 "NANDFS mountpoints"); 87SYSCTL_INT(_vfs_nandfs, OID_AUTO, verbose, CTLFLAG_RW, &nandfs_verbose, 0, ""); 88 89#define NANDFS_CONSTR_INTERVAL 5 90int nandfs_sync_interval = NANDFS_CONSTR_INTERVAL; /* sync every 5 seconds */ 91SYSCTL_UINT(_vfs_nandfs, OID_AUTO, sync_interval, CTLFLAG_RW, 92 &nandfs_sync_interval, 0, ""); 93 94#define NANDFS_MAX_DIRTY_SEGS 5 95int nandfs_max_dirty_segs = NANDFS_MAX_DIRTY_SEGS; /* sync when 5 dirty seg */ 96SYSCTL_UINT(_vfs_nandfs, OID_AUTO, max_dirty_segs, CTLFLAG_RW, 97 &nandfs_max_dirty_segs, 0, ""); 98 99#define NANDFS_CPS_BETWEEN_SBLOCKS 5 100int nandfs_cps_between_sblocks = NANDFS_CPS_BETWEEN_SBLOCKS; /* write superblock every 5 checkpoints */ 101SYSCTL_UINT(_vfs_nandfs, OID_AUTO, cps_between_sblocks, CTLFLAG_RW, 102 &nandfs_cps_between_sblocks, 0, ""); 103 104#define NANDFS_CLEANER_ENABLE 1 105int nandfs_cleaner_enable = NANDFS_CLEANER_ENABLE; 106SYSCTL_UINT(_vfs_nandfs, OID_AUTO, cleaner_enable, CTLFLAG_RW, 107 &nandfs_cleaner_enable, 0, ""); 108 109#define NANDFS_CLEANER_INTERVAL 5 110int nandfs_cleaner_interval = NANDFS_CLEANER_INTERVAL; 111SYSCTL_UINT(_vfs_nandfs, OID_AUTO, cleaner_interval, CTLFLAG_RW, 112 &nandfs_cleaner_interval, 0, ""); 113 114#define NANDFS_CLEANER_SEGMENTS 5 115int nandfs_cleaner_segments = NANDFS_CLEANER_SEGMENTS; 116SYSCTL_UINT(_vfs_nandfs, OID_AUTO, cleaner_segments, CTLFLAG_RW, 117 &nandfs_cleaner_segments, 0, ""); 118 119static int nandfs_mountfs(struct vnode *devvp, struct mount *mp); 120static vfs_mount_t nandfs_mount; 121static vfs_root_t nandfs_root; 122static vfs_statfs_t nandfs_statfs; 123static vfs_unmount_t nandfs_unmount; 124static vfs_vget_t nandfs_vget; 125static vfs_sync_t nandfs_sync; 126static const char *nandfs_opts[] = { 127 "snap", "from", "noatime", NULL 128}; 129 130/* System nodes */ 131static int 132nandfs_create_system_nodes(struct nandfs_device *nandfsdev) 133{ 134 int error; 135 136 error = nandfs_get_node_raw(nandfsdev, NULL, NANDFS_DAT_INO, 137 &nandfsdev->nd_super_root.sr_dat, &nandfsdev->nd_dat_node); 138 if (error) 139 goto errorout; 140 141 error = nandfs_get_node_raw(nandfsdev, NULL, NANDFS_CPFILE_INO, 142 &nandfsdev->nd_super_root.sr_cpfile, &nandfsdev->nd_cp_node); 143 if (error) 144 goto errorout; 145 146 error = nandfs_get_node_raw(nandfsdev, NULL, NANDFS_SUFILE_INO, 147 &nandfsdev->nd_super_root.sr_sufile, &nandfsdev->nd_su_node); 148 if (error) 149 goto errorout; 150 151 error = nandfs_get_node_raw(nandfsdev, NULL, NANDFS_GC_INO, 152 NULL, &nandfsdev->nd_gc_node); 153 if (error) 154 goto errorout; 155 156 NANDFS_SET_SYSTEMFILE(NTOV(nandfsdev->nd_dat_node)); 157 NANDFS_SET_SYSTEMFILE(NTOV(nandfsdev->nd_cp_node)); 158 NANDFS_SET_SYSTEMFILE(NTOV(nandfsdev->nd_su_node)); 159 NANDFS_SET_SYSTEMFILE(NTOV(nandfsdev->nd_gc_node)); 160 161 DPRINTF(VOLUMES, ("System vnodes: dat: %p cp: %p su: %p\n", 162 NTOV(nandfsdev->nd_dat_node), NTOV(nandfsdev->nd_cp_node), 163 NTOV(nandfsdev->nd_su_node))); 164 return (0); 165 166errorout: 167 nandfs_dispose_node(&nandfsdev->nd_gc_node); 168 nandfs_dispose_node(&nandfsdev->nd_dat_node); 169 nandfs_dispose_node(&nandfsdev->nd_cp_node); 170 nandfs_dispose_node(&nandfsdev->nd_su_node); 171 172 return (error); 173} 174 175static void 176nandfs_release_system_nodes(struct nandfs_device *nandfsdev) 177{ 178 179 if (!nandfsdev) 180 return; 181 if (nandfsdev->nd_refcnt > 0) 182 return; 183 184 if (nandfsdev->nd_gc_node) 185 NANDFS_UNSET_SYSTEMFILE(NTOV(nandfsdev->nd_gc_node)); 186 if (nandfsdev->nd_dat_node) 187 NANDFS_UNSET_SYSTEMFILE(NTOV(nandfsdev->nd_dat_node)); 188 if (nandfsdev->nd_cp_node) 189 NANDFS_UNSET_SYSTEMFILE(NTOV(nandfsdev->nd_cp_node)); 190 if (nandfsdev->nd_su_node) 191 NANDFS_UNSET_SYSTEMFILE(NTOV(nandfsdev->nd_su_node)); 192} 193 194static int 195nandfs_check_fsdata_crc(struct nandfs_fsdata *fsdata) 196{ 197 uint32_t fsdata_crc, comp_crc; 198 199 if (fsdata->f_magic != NANDFS_FSDATA_MAGIC) 200 return (0); 201 202 /* Preserve CRC */ 203 fsdata_crc = fsdata->f_sum; 204 205 /* Calculate */ 206 fsdata->f_sum = (0); 207 comp_crc = crc32((uint8_t *)fsdata, fsdata->f_bytes); 208 209 /* Restore */ 210 fsdata->f_sum = fsdata_crc; 211 212 /* Check CRC */ 213 return (fsdata_crc == comp_crc); 214} 215 216static int 217nandfs_check_superblock_crc(struct nandfs_fsdata *fsdata, 218 struct nandfs_super_block *super) 219{ 220 uint32_t super_crc, comp_crc; 221 222 /* Check super block magic */ 223 if (super->s_magic != NANDFS_SUPER_MAGIC) 224 return (0); 225 226 /* Preserve CRC */ 227 super_crc = super->s_sum; 228 229 /* Calculate */ 230 super->s_sum = (0); 231 comp_crc = crc32((uint8_t *)super, fsdata->f_sbbytes); 232 233 /* Restore */ 234 super->s_sum = super_crc; 235 236 /* Check CRC */ 237 return (super_crc == comp_crc); 238} 239 240static void 241nandfs_calc_superblock_crc(struct nandfs_fsdata *fsdata, 242 struct nandfs_super_block *super) 243{ 244 uint32_t comp_crc; 245 246 /* Calculate */ 247 super->s_sum = 0; 248 comp_crc = crc32((uint8_t *)super, fsdata->f_sbbytes); 249 250 /* Restore */ 251 super->s_sum = comp_crc; 252} 253 254static int 255nandfs_is_empty(u_char *area, int size) 256{ 257 int i; 258 259 for (i = 0; i < size; i++) 260 if (area[i] != 0xff) 261 return (0); 262 263 return (1); 264} 265 266static __inline int 267nandfs_sblocks_in_esize(struct nandfs_device *fsdev) 268{ 269 270 return ((fsdev->nd_erasesize - NANDFS_SBLOCK_OFFSET_BYTES) / 271 sizeof(struct nandfs_super_block)); 272} 273 274static __inline int 275nandfs_max_sblocks(struct nandfs_device *fsdev) 276{ 277 278 return (NANDFS_NFSAREAS * nandfs_sblocks_in_esize(fsdev)); 279} 280 281static __inline int 282nandfs_sblocks_in_block(struct nandfs_device *fsdev) 283{ 284 285 return (fsdev->nd_devblocksize / sizeof(struct nandfs_super_block)); 286} 287 288#if 0 289static __inline int 290nandfs_sblocks_in_first_block(struct nandfs_device *fsdev) 291{ 292 int n; 293 294 n = nandfs_sblocks_in_block(fsdev) - 295 NANDFS_SBLOCK_OFFSET_BYTES / sizeof(struct nandfs_super_block); 296 if (n < 0) 297 n = 0; 298 299 return (n); 300} 301#endif 302 303static int 304nandfs_write_superblock_at(struct nandfs_device *fsdev, 305 struct nandfs_fsarea *fstp) 306{ 307 struct nandfs_super_block *super, *supert; 308 struct buf *bp; 309 int sb_per_sector, sbs_in_fsd, read_block; 310 int index, pos, error; 311 off_t offset; 312 313 DPRINTF(SYNC, ("%s: last_used %d nandfs_sblocks_in_esize %d\n", 314 __func__, fstp->last_used, nandfs_sblocks_in_esize(fsdev))); 315 if (fstp->last_used == nandfs_sblocks_in_esize(fsdev) - 1) 316 index = 0; 317 else 318 index = fstp->last_used + 1; 319 320 super = &fsdev->nd_super; 321 supert = NULL; 322 323 sb_per_sector = nandfs_sblocks_in_block(fsdev); 324 sbs_in_fsd = sizeof(struct nandfs_fsdata) / 325 sizeof(struct nandfs_super_block); 326 index += sbs_in_fsd; 327 offset = fstp->offset; 328 329 DPRINTF(SYNC, ("%s: offset %#jx s_last_pseg %#jx s_last_cno %#jx " 330 "s_last_seq %#jx wtime %jd index %d\n", __func__, offset, 331 super->s_last_pseg, super->s_last_cno, super->s_last_seq, 332 super->s_wtime, index)); 333 334 read_block = btodb(offset + ((index / sb_per_sector) * sb_per_sector) 335 * sizeof(struct nandfs_super_block)); 336 337 DPRINTF(SYNC, ("%s: read_block %#x\n", __func__, read_block)); 338 339 if (index == sbs_in_fsd) { 340 error = nandfs_erase(fsdev, offset, fsdev->nd_erasesize); 341 if (error) 342 return (error); 343 344 error = bread(fsdev->nd_devvp, btodb(offset), 345 fsdev->nd_devblocksize, NOCRED, &bp); 346 if (error) { 347 printf("NANDFS: couldn't read initial data: %d\n", 348 error); 349 brelse(bp); 350 return (error); 351 } 352 memcpy(bp->b_data, &fsdev->nd_fsdata, sizeof(fsdev->nd_fsdata)); 353 /* 354 * 0xff-out the rest. This bp could be cached, so potentially 355 * b_data contains stale super blocks. 356 * 357 * We don't mind cached bp since most of the time we just add 358 * super blocks to already 0xff-out b_data and don't need to 359 * perform actual read. 360 */ 361 if (fsdev->nd_devblocksize > sizeof(fsdev->nd_fsdata)) 362 memset(bp->b_data + sizeof(fsdev->nd_fsdata), 0xff, 363 fsdev->nd_devblocksize - sizeof(fsdev->nd_fsdata)); 364 error = bwrite(bp); 365 if (error) { 366 printf("NANDFS: cannot rewrite initial data at %jx\n", 367 offset); 368 return (error); 369 } 370 } 371 372 error = bread(fsdev->nd_devvp, read_block, fsdev->nd_devblocksize, 373 NOCRED, &bp); 374 if (error) { 375 brelse(bp); 376 return (error); 377 } 378 379 supert = (struct nandfs_super_block *)(bp->b_data); 380 pos = index % sb_per_sector; 381 382 DPRINTF(SYNC, ("%s: storing at %d\n", __func__, pos)); 383 memcpy(&supert[pos], super, sizeof(struct nandfs_super_block)); 384 385 /* 386 * See comment above in code that performs erase. 387 */ 388 if (pos == 0) 389 memset(&supert[1], 0xff, 390 (sb_per_sector - 1) * sizeof(struct nandfs_super_block)); 391 392 error = bwrite(bp); 393 if (error) { 394 printf("NANDFS: cannot update superblock at %jx\n", offset); 395 return (error); 396 } 397 398 DPRINTF(SYNC, ("%s: fstp->last_used %d -> %d\n", __func__, 399 fstp->last_used, index - sbs_in_fsd)); 400 fstp->last_used = index - sbs_in_fsd; 401 402 return (0); 403} 404 405int 406nandfs_write_superblock(struct nandfs_device *fsdev) 407{ 408 struct nandfs_super_block *super; 409 struct timespec ts; 410 int error; 411 int i, j; 412 413 vfs_timestamp(&ts); 414 415 super = &fsdev->nd_super; 416 417 super->s_last_pseg = fsdev->nd_last_pseg; 418 super->s_last_cno = fsdev->nd_last_cno; 419 super->s_last_seq = fsdev->nd_seg_sequence; 420 super->s_wtime = ts.tv_sec; 421 422 nandfs_calc_superblock_crc(&fsdev->nd_fsdata, super); 423 424 error = 0; 425 for (i = 0, j = fsdev->nd_last_fsarea; i < NANDFS_NFSAREAS; 426 i++, j = (j + 1 % NANDFS_NFSAREAS)) { 427 if (fsdev->nd_fsarea[j].flags & NANDFS_FSSTOR_FAILED) { 428 DPRINTF(SYNC, ("%s: skipping %d\n", __func__, j)); 429 continue; 430 } 431 error = nandfs_write_superblock_at(fsdev, &fsdev->nd_fsarea[j]); 432 if (error) { 433 printf("NANDFS: writing superblock at offset %d failed:" 434 "%d\n", j * fsdev->nd_erasesize, error); 435 fsdev->nd_fsarea[j].flags |= NANDFS_FSSTOR_FAILED; 436 } else 437 break; 438 } 439 440 if (i == NANDFS_NFSAREAS) { 441 printf("NANDFS: superblock was not written\n"); 442 /* 443 * TODO: switch to read-only? 444 */ 445 return (error); 446 } else 447 fsdev->nd_last_fsarea = (j + 1) % NANDFS_NFSAREAS; 448 449 return (0); 450} 451 452static int 453nandfs_select_fsdata(struct nandfs_device *fsdev, 454 struct nandfs_fsdata *fsdatat, struct nandfs_fsdata **fsdata, int nfsds) 455{ 456 int i; 457 458 *fsdata = NULL; 459 for (i = 0; i < nfsds; i++) { 460 DPRINTF(VOLUMES, ("%s: i %d f_magic %x f_crc %x\n", __func__, 461 i, fsdatat[i].f_magic, fsdatat[i].f_sum)); 462 if (!nandfs_check_fsdata_crc(&fsdatat[i])) 463 continue; 464 *fsdata = &fsdatat[i]; 465 break; 466 } 467 468 return (*fsdata != NULL ? 0 : EINVAL); 469} 470 471static int 472nandfs_select_sb(struct nandfs_device *fsdev, 473 struct nandfs_super_block *supert, struct nandfs_super_block **super, 474 int nsbs) 475{ 476 int i; 477 478 *super = NULL; 479 for (i = 0; i < nsbs; i++) { 480 if (!nandfs_check_superblock_crc(&fsdev->nd_fsdata, &supert[i])) 481 continue; 482 DPRINTF(SYNC, ("%s: i %d s_last_cno %jx s_magic %x " 483 "s_wtime %jd\n", __func__, i, supert[i].s_last_cno, 484 supert[i].s_magic, supert[i].s_wtime)); 485 if (*super == NULL || supert[i].s_last_cno > 486 (*super)->s_last_cno) 487 *super = &supert[i]; 488 } 489 490 return (*super != NULL ? 0 : EINVAL); 491} 492 493static int 494nandfs_read_structures_at(struct nandfs_device *fsdev, 495 struct nandfs_fsarea *fstp, struct nandfs_fsdata *fsdata, 496 struct nandfs_super_block *super) 497{ 498 struct nandfs_super_block *tsuper, *tsuperd; 499 struct buf *bp; 500 int error, read_size; 501 int i; 502 int offset; 503 504 offset = fstp->offset; 505 506 if (fsdev->nd_erasesize > MAXBSIZE) 507 read_size = MAXBSIZE; 508 else 509 read_size = fsdev->nd_erasesize; 510 511 error = bread(fsdev->nd_devvp, btodb(offset), read_size, NOCRED, &bp); 512 if (error) { 513 printf("couldn't read: %d\n", error); 514 brelse(bp); 515 fstp->flags |= NANDFS_FSSTOR_FAILED; 516 return (error); 517 } 518 519 tsuper = super; 520 521 memcpy(fsdata, bp->b_data, sizeof(struct nandfs_fsdata)); 522 memcpy(tsuper, (bp->b_data + sizeof(struct nandfs_fsdata)), 523 read_size - sizeof(struct nandfs_fsdata)); 524 brelse(bp); 525 526 tsuper += (read_size - sizeof(struct nandfs_fsdata)) / 527 sizeof(struct nandfs_super_block); 528 529 for (i = 1; i < fsdev->nd_erasesize / read_size; i++) { 530 error = bread(fsdev->nd_devvp, btodb(offset + i * read_size), 531 read_size, NOCRED, &bp); 532 if (error) { 533 printf("couldn't read: %d\n", error); 534 brelse(bp); 535 fstp->flags |= NANDFS_FSSTOR_FAILED; 536 return (error); 537 } 538 memcpy(tsuper, bp->b_data, read_size); 539 tsuper += read_size / sizeof(struct nandfs_super_block); 540 brelse(bp); 541 } 542 543 tsuper -= 1; 544 fstp->last_used = nandfs_sblocks_in_esize(fsdev) - 1; 545 for (tsuperd = super - 1; (tsuper != tsuperd); tsuper -= 1) { 546 if (nandfs_is_empty((u_char *)tsuper, sizeof(*tsuper))) 547 fstp->last_used--; 548 else 549 break; 550 } 551 552 DPRINTF(VOLUMES, ("%s: last_used %d\n", __func__, fstp->last_used)); 553 554 return (0); 555} 556 557static int 558nandfs_read_structures(struct nandfs_device *fsdev) 559{ 560 struct nandfs_fsdata *fsdata, *fsdatat; 561 struct nandfs_super_block *sblocks, *ssblock; 562 int nsbs, nfsds, i; 563 int error = 0; 564 int nrsbs; 565 566 nfsds = NANDFS_NFSAREAS; 567 nsbs = nandfs_max_sblocks(fsdev); 568 569 fsdatat = malloc(sizeof(struct nandfs_fsdata) * nfsds, M_NANDFSTEMP, 570 M_WAITOK | M_ZERO); 571 sblocks = malloc(sizeof(struct nandfs_super_block) * nsbs, M_NANDFSTEMP, 572 M_WAITOK | M_ZERO); 573 574 nrsbs = 0; 575 for (i = 0; i < NANDFS_NFSAREAS; i++) { 576 fsdev->nd_fsarea[i].offset = i * fsdev->nd_erasesize; 577 error = nandfs_read_structures_at(fsdev, &fsdev->nd_fsarea[i], 578 &fsdatat[i], sblocks + nrsbs); 579 if (error) 580 continue; 581 nrsbs += (fsdev->nd_fsarea[i].last_used + 1); 582 if (fsdev->nd_fsarea[fsdev->nd_last_fsarea].last_used > 583 fsdev->nd_fsarea[i].last_used) 584 fsdev->nd_last_fsarea = i; 585 } 586 587 if (nrsbs == 0) { 588 printf("nandfs: no valid superblocks found\n"); 589 error = EINVAL; 590 goto out; 591 } 592 593 error = nandfs_select_fsdata(fsdev, fsdatat, &fsdata, nfsds); 594 if (error) 595 goto out; 596 memcpy(&fsdev->nd_fsdata, fsdata, sizeof(struct nandfs_fsdata)); 597 598 error = nandfs_select_sb(fsdev, sblocks, &ssblock, nsbs); 599 if (error) 600 goto out; 601 602 memcpy(&fsdev->nd_super, ssblock, sizeof(struct nandfs_super_block)); 603out: 604 free(fsdatat, M_NANDFSTEMP); 605 free(sblocks, M_NANDFSTEMP); 606 607 if (error == 0) 608 DPRINTF(VOLUMES, ("%s: selected sb with w_time %jd " 609 "last_pseg %#jx\n", __func__, fsdev->nd_super.s_wtime, 610 fsdev->nd_super.s_last_pseg)); 611 612 return (error); 613} 614 615static void 616nandfs_unmount_base(struct nandfs_device *nandfsdev) 617{ 618 int error; 619 620 if (!nandfsdev) 621 return; 622 623 /* Remove all our information */ 624 error = vinvalbuf(nandfsdev->nd_devvp, V_SAVE, 0, 0); 625 if (error) { 626 /* 627 * Flushing buffers failed when fs was umounting, can't do 628 * much now, just printf error and continue with umount. 629 */ 630 nandfs_error("%s(): error:%d when umounting FS\n", 631 __func__, error); 632 } 633 634 /* Release the device's system nodes */ 635 nandfs_release_system_nodes(nandfsdev); 636} 637 638static void 639nandfs_get_ncleanseg(struct nandfs_device *nandfsdev) 640{ 641 struct nandfs_seg_stat nss; 642 643 nandfs_get_seg_stat(nandfsdev, &nss); 644 nandfsdev->nd_clean_segs = nss.nss_ncleansegs; 645 DPRINTF(VOLUMES, ("nandfs_mount: clean segs: %jx\n", 646 (uintmax_t)nandfsdev->nd_clean_segs)); 647} 648 649 650static int 651nandfs_mount_base(struct nandfs_device *nandfsdev, struct mount *mp, 652 struct nandfs_args *args) 653{ 654 uint32_t log_blocksize; 655 int error; 656 657 /* Flush out any old buffers remaining from a previous use. */ 658 if ((error = vinvalbuf(nandfsdev->nd_devvp, V_SAVE, 0, 0))) 659 return (error); 660 661 error = nandfs_read_structures(nandfsdev); 662 if (error) { 663 printf("nandfs: could not get valid filesystem structures\n"); 664 return (error); 665 } 666 667 if (nandfsdev->nd_fsdata.f_rev_level != NANDFS_CURRENT_REV) { 668 printf("nandfs: unsupported file system revision: %d " 669 "(supported is %d).\n", nandfsdev->nd_fsdata.f_rev_level, 670 NANDFS_CURRENT_REV); 671 return (EINVAL); 672 } 673 674 if (nandfsdev->nd_fsdata.f_erasesize != nandfsdev->nd_erasesize) { 675 printf("nandfs: erasesize mismatch (device %#x, fs %#x)\n", 676 nandfsdev->nd_erasesize, nandfsdev->nd_fsdata.f_erasesize); 677 return (EINVAL); 678 } 679 680 /* Get our blocksize */ 681 log_blocksize = nandfsdev->nd_fsdata.f_log_block_size; 682 nandfsdev->nd_blocksize = (uint64_t) 1 << (log_blocksize + 10); 683 DPRINTF(VOLUMES, ("%s: blocksize:%x\n", __func__, 684 nandfsdev->nd_blocksize)); 685 686 DPRINTF(VOLUMES, ("%s: accepted super block with cp %#jx\n", __func__, 687 (uintmax_t)nandfsdev->nd_super.s_last_cno)); 688 689 /* Calculate dat structure parameters */ 690 nandfs_calc_mdt_consts(nandfsdev, &nandfsdev->nd_dat_mdt, 691 nandfsdev->nd_fsdata.f_dat_entry_size); 692 nandfs_calc_mdt_consts(nandfsdev, &nandfsdev->nd_ifile_mdt, 693 nandfsdev->nd_fsdata.f_inode_size); 694 695 /* Search for the super root and roll forward when needed */ 696 if (nandfs_search_super_root(nandfsdev)) { 697 printf("Cannot find valid SuperRoot\n"); 698 return (EINVAL); 699 } 700 701 nandfsdev->nd_mount_state = nandfsdev->nd_super.s_state; 702 if (nandfsdev->nd_mount_state != NANDFS_VALID_FS) { 703 printf("FS is seriously damaged, needs repairing\n"); 704 printf("aborting mount\n"); 705 return (EINVAL); 706 } 707 708 /* 709 * FS should be ok now. The superblock and the last segsum could be 710 * updated from the repair so extract running values again. 711 */ 712 nandfsdev->nd_last_pseg = nandfsdev->nd_super.s_last_pseg; 713 nandfsdev->nd_seg_sequence = nandfsdev->nd_super.s_last_seq; 714 nandfsdev->nd_seg_num = nandfs_get_segnum_of_block(nandfsdev, 715 nandfsdev->nd_last_pseg); 716 nandfsdev->nd_next_seg_num = nandfs_get_segnum_of_block(nandfsdev, 717 nandfsdev->nd_last_segsum.ss_next); 718 nandfsdev->nd_ts.tv_sec = nandfsdev->nd_last_segsum.ss_create; 719 nandfsdev->nd_last_cno = nandfsdev->nd_super.s_last_cno; 720 nandfsdev->nd_fakevblk = 1; 721 nandfsdev->nd_last_ino = NANDFS_USER_INO; 722 DPRINTF(VOLUMES, ("%s: last_pseg %#jx last_cno %#jx last_seq %#jx\n" 723 "fsdev: last_seg: seq %#jx num %#jx, next_seg_num %#jx\n", 724 __func__, (uintmax_t)nandfsdev->nd_last_pseg, 725 (uintmax_t)nandfsdev->nd_last_cno, 726 (uintmax_t)nandfsdev->nd_seg_sequence, 727 (uintmax_t)nandfsdev->nd_seg_sequence, 728 (uintmax_t)nandfsdev->nd_seg_num, 729 (uintmax_t)nandfsdev->nd_next_seg_num)); 730 731 DPRINTF(VOLUMES, ("nandfs_mount: accepted super root\n")); 732 733 /* Create system vnodes for DAT, CP and SEGSUM */ 734 error = nandfs_create_system_nodes(nandfsdev); 735 if (error) 736 nandfs_unmount_base(nandfsdev); 737 738 nandfs_get_ncleanseg(nandfsdev); 739 740 return (error); 741} 742 743static void 744nandfs_unmount_device(struct nandfs_device *nandfsdev) 745{ 746 747 /* Is there anything? */ 748 if (nandfsdev == NULL) 749 return; 750 751 /* Remove the device only if we're the last reference */ 752 nandfsdev->nd_refcnt--; 753 if (nandfsdev->nd_refcnt >= 1) 754 return; 755 756 MPASS(nandfsdev->nd_syncer == NULL); 757 MPASS(nandfsdev->nd_cleaner == NULL); 758 MPASS(nandfsdev->nd_free_base == NULL); 759 760 /* Unmount our base */ 761 nandfs_unmount_base(nandfsdev); 762 763 /* Remove from our device list */ 764 SLIST_REMOVE(&nandfs_devices, nandfsdev, nandfs_device, nd_next_device); 765 766 DROP_GIANT(); 767 g_topology_lock(); 768 g_vfs_close(nandfsdev->nd_gconsumer); 769 g_topology_unlock(); 770 PICKUP_GIANT(); 771 772 DPRINTF(VOLUMES, ("closing device\n")); 773 774 /* Clear our mount reference and release device node */ 775 vrele(nandfsdev->nd_devvp); 776 777 dev_rel(nandfsdev->nd_devvp->v_rdev); 778 779 /* Free our device info */ 780 cv_destroy(&nandfsdev->nd_sync_cv); 781 mtx_destroy(&nandfsdev->nd_sync_mtx); 782 cv_destroy(&nandfsdev->nd_clean_cv); 783 mtx_destroy(&nandfsdev->nd_clean_mtx); 784 mtx_destroy(&nandfsdev->nd_mutex); 785 lockdestroy(&nandfsdev->nd_seg_const); 786 free(nandfsdev, M_NANDFSMNT); 787} 788 789static int 790nandfs_check_mounts(struct nandfs_device *nandfsdev, struct mount *mp, 791 struct nandfs_args *args) 792{ 793 struct nandfsmount *nmp; 794 uint64_t last_cno; 795 796 /* no double-mounting of the same checkpoint */ 797 STAILQ_FOREACH(nmp, &nandfsdev->nd_mounts, nm_next_mount) { 798 if (nmp->nm_mount_args.cpno == args->cpno) 799 return (EBUSY); 800 } 801 802 /* Allow readonly mounts without questioning here */ 803 if (mp->mnt_flag & MNT_RDONLY) 804 return (0); 805 806 /* Read/write mount */ 807 STAILQ_FOREACH(nmp, &nandfsdev->nd_mounts, nm_next_mount) { 808 /* Only one RW mount on this device! */ 809 if ((nmp->nm_vfs_mountp->mnt_flag & MNT_RDONLY)==0) 810 return (EROFS); 811 /* RDONLY on last mountpoint is device busy */ 812 last_cno = nmp->nm_nandfsdev->nd_super.s_last_cno; 813 if (nmp->nm_mount_args.cpno == last_cno) 814 return (EBUSY); 815 } 816 817 /* OK for now */ 818 return (0); 819} 820 821static int 822nandfs_mount_device(struct vnode *devvp, struct mount *mp, 823 struct nandfs_args *args, struct nandfs_device **nandfsdev_p) 824{ 825 struct nandfs_device *nandfsdev; 826 struct g_provider *pp; 827 struct g_consumer *cp; 828 struct cdev *dev; 829 uint32_t erasesize; 830 int error, size; 831 int ronly; 832 833 DPRINTF(VOLUMES, ("Mounting NANDFS device\n")); 834 835 ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 836 837 /* Look up device in our nandfs_mountpoints */ 838 *nandfsdev_p = NULL; 839 SLIST_FOREACH(nandfsdev, &nandfs_devices, nd_next_device) 840 if (nandfsdev->nd_devvp == devvp) 841 break; 842 843 if (nandfsdev) { 844 DPRINTF(VOLUMES, ("device already mounted\n")); 845 error = nandfs_check_mounts(nandfsdev, mp, args); 846 if (error) 847 return error; 848 nandfsdev->nd_refcnt++; 849 *nandfsdev_p = nandfsdev; 850 851 if (!ronly) { 852 DROP_GIANT(); 853 g_topology_lock(); 854 error = g_access(nandfsdev->nd_gconsumer, 0, 1, 0); 855 g_topology_unlock(); 856 PICKUP_GIANT(); 857 } 858 return (error); 859 } 860 861 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 862 dev = devvp->v_rdev; 863 dev_ref(dev); 864 DROP_GIANT(); 865 g_topology_lock(); 866 error = g_vfs_open(devvp, &cp, "nandfs", ronly ? 0 : 1); 867 pp = g_dev_getprovider(dev); 868 g_topology_unlock(); 869 PICKUP_GIANT(); 870 VOP_UNLOCK(devvp, 0); 871 if (error) { 872 dev_rel(dev); 873 return (error); 874 } 875 876 nandfsdev = malloc(sizeof(struct nandfs_device), M_NANDFSMNT, M_WAITOK | M_ZERO); 877 878 /* Initialise */ 879 nandfsdev->nd_refcnt = 1; 880 nandfsdev->nd_devvp = devvp; 881 nandfsdev->nd_syncing = 0; 882 nandfsdev->nd_cleaning = 0; 883 nandfsdev->nd_gconsumer = cp; 884 cv_init(&nandfsdev->nd_sync_cv, "nandfssync"); 885 mtx_init(&nandfsdev->nd_sync_mtx, "nffssyncmtx", NULL, MTX_DEF); 886 cv_init(&nandfsdev->nd_clean_cv, "nandfsclean"); 887 mtx_init(&nandfsdev->nd_clean_mtx, "nffscleanmtx", NULL, MTX_DEF); 888 mtx_init(&nandfsdev->nd_mutex, "nandfsdev lock", NULL, MTX_DEF); 889 lockinit(&nandfsdev->nd_seg_const, PVFS, "nffssegcon", VLKTIMEOUT, 890 LK_CANRECURSE); 891 STAILQ_INIT(&nandfsdev->nd_mounts); 892 893 nandfsdev->nd_devsize = pp->mediasize; 894 nandfsdev->nd_devblocksize = pp->sectorsize; 895 896 size = sizeof(erasesize); 897 error = g_io_getattr("NAND::blocksize", nandfsdev->nd_gconsumer, &size, 898 &erasesize); 899 if (error) { 900 DPRINTF(VOLUMES, ("couldn't get erasesize: %d\n", error)); 901 902 if (error == ENOIOCTL || error == EOPNOTSUPP) { 903 /* 904 * We conclude that this is not NAND storage 905 */ 906 nandfsdev->nd_erasesize = NANDFS_DEF_ERASESIZE; 907 nandfsdev->nd_is_nand = 0; 908 } else { 909 DROP_GIANT(); 910 g_topology_lock(); 911 g_vfs_close(nandfsdev->nd_gconsumer); 912 g_topology_unlock(); 913 PICKUP_GIANT(); 914 dev_rel(dev); 915 free(nandfsdev, M_NANDFSMNT); 916 return (error); 917 } 918 } else { 919 nandfsdev->nd_erasesize = erasesize; 920 nandfsdev->nd_is_nand = 1; 921 } 922 923 DPRINTF(VOLUMES, ("%s: erasesize %x\n", __func__, 924 nandfsdev->nd_erasesize)); 925 926 /* Register nandfs_device in list */ 927 SLIST_INSERT_HEAD(&nandfs_devices, nandfsdev, nd_next_device); 928 929 error = nandfs_mount_base(nandfsdev, mp, args); 930 if (error) { 931 /* Remove all our information */ 932 nandfs_unmount_device(nandfsdev); 933 return (EINVAL); 934 } 935 936 nandfsdev->nd_maxfilesize = nandfs_get_maxfilesize(nandfsdev); 937 938 *nandfsdev_p = nandfsdev; 939 DPRINTF(VOLUMES, ("NANDFS device mounted ok\n")); 940 941 return (0); 942} 943 944static int 945nandfs_mount_checkpoint(struct nandfsmount *nmp) 946{ 947 struct nandfs_cpfile_header *cphdr; 948 struct nandfs_checkpoint *cp; 949 struct nandfs_inode ifile_inode; 950 struct nandfs_node *cp_node; 951 struct buf *bp; 952 uint64_t ncp, nsn, cpno, fcpno, blocknr, last_cno; 953 uint32_t off, dlen; 954 int cp_per_block, error; 955 956 cpno = nmp->nm_mount_args.cpno; 957 if (cpno == 0) 958 cpno = nmp->nm_nandfsdev->nd_super.s_last_cno; 959 960 DPRINTF(VOLUMES, ("%s: trying to mount checkpoint number %"PRIu64"\n", 961 __func__, cpno)); 962 963 cp_node = nmp->nm_nandfsdev->nd_cp_node; 964 965 VOP_LOCK(NTOV(cp_node), LK_SHARED); 966 /* Get cpfile header from 1st block of cp file */ 967 error = nandfs_bread(cp_node, 0, NOCRED, 0, &bp); 968 if (error) { 969 brelse(bp); 970 VOP_UNLOCK(NTOV(cp_node), 0); 971 return (error); 972 } 973 974 cphdr = (struct nandfs_cpfile_header *) bp->b_data; 975 ncp = cphdr->ch_ncheckpoints; 976 nsn = cphdr->ch_nsnapshots; 977 978 brelse(bp); 979 980 DPRINTF(VOLUMES, ("mount_nandfs: checkpoint header read in\n")); 981 DPRINTF(VOLUMES, ("\tNumber of checkpoints %"PRIu64"\n", ncp)); 982 DPRINTF(VOLUMES, ("\tNumber of snapshots %"PRIu64"\n", nsn)); 983 984 /* Read in our specified checkpoint */ 985 dlen = nmp->nm_nandfsdev->nd_fsdata.f_checkpoint_size; 986 cp_per_block = nmp->nm_nandfsdev->nd_blocksize / dlen; 987 988 fcpno = cpno + NANDFS_CPFILE_FIRST_CHECKPOINT_OFFSET - 1; 989 blocknr = fcpno / cp_per_block; 990 off = (fcpno % cp_per_block) * dlen; 991 error = nandfs_bread(cp_node, blocknr, NOCRED, 0, &bp); 992 if (error) { 993 brelse(bp); 994 VOP_UNLOCK(NTOV(cp_node), 0); 995 printf("mount_nandfs: couldn't read cp block %"PRIu64"\n", 996 fcpno); 997 return (EINVAL); 998 } 999 1000 /* Needs to be a valid checkpoint */ 1001 cp = (struct nandfs_checkpoint *) ((uint8_t *) bp->b_data + off); 1002 if (cp->cp_flags & NANDFS_CHECKPOINT_INVALID) { 1003 printf("mount_nandfs: checkpoint marked invalid\n"); 1004 brelse(bp); 1005 VOP_UNLOCK(NTOV(cp_node), 0); 1006 return (EINVAL); 1007 } 1008 1009 /* Is this really the checkpoint we want? */ 1010 if (cp->cp_cno != cpno) { 1011 printf("mount_nandfs: checkpoint file corrupt? " 1012 "expected cpno %"PRIu64", found cpno %"PRIu64"\n", 1013 cpno, cp->cp_cno); 1014 brelse(bp); 1015 VOP_UNLOCK(NTOV(cp_node), 0); 1016 return (EINVAL); 1017 } 1018 1019 /* Check if it's a snapshot ! */ 1020 last_cno = nmp->nm_nandfsdev->nd_super.s_last_cno; 1021 if (cpno != last_cno) { 1022 /* Only allow snapshots if not mounting on the last cp */ 1023 if ((cp->cp_flags & NANDFS_CHECKPOINT_SNAPSHOT) == 0) { 1024 printf( "mount_nandfs: checkpoint %"PRIu64" is not a " 1025 "snapshot\n", cpno); 1026 brelse(bp); 1027 VOP_UNLOCK(NTOV(cp_node), 0); 1028 return (EINVAL); 1029 } 1030 } 1031 1032 ifile_inode = cp->cp_ifile_inode; 1033 brelse(bp); 1034 1035 /* Get ifile inode */ 1036 error = nandfs_get_node_raw(nmp->nm_nandfsdev, NULL, NANDFS_IFILE_INO, 1037 &ifile_inode, &nmp->nm_ifile_node); 1038 if (error) { 1039 printf("mount_nandfs: can't read ifile node\n"); 1040 VOP_UNLOCK(NTOV(cp_node), 0); 1041 return (EINVAL); 1042 } 1043 1044 NANDFS_SET_SYSTEMFILE(NTOV(nmp->nm_ifile_node)); 1045 VOP_UNLOCK(NTOV(cp_node), 0); 1046 /* Get root node? */ 1047 1048 return (0); 1049} 1050 1051static void 1052free_nandfs_mountinfo(struct mount *mp) 1053{ 1054 struct nandfsmount *nmp = VFSTONANDFS(mp); 1055 1056 if (nmp == NULL) 1057 return; 1058 1059 free(nmp, M_NANDFSMNT); 1060} 1061 1062void 1063nandfs_wakeup_wait_sync(struct nandfs_device *nffsdev, int reason) 1064{ 1065 char *reasons[] = { 1066 "umount", 1067 "vfssync", 1068 "bdflush", 1069 "fforce", 1070 "fsync", 1071 "ro_upd" 1072 }; 1073 1074 DPRINTF(SYNC, ("%s: %s\n", __func__, reasons[reason])); 1075 mtx_lock(&nffsdev->nd_sync_mtx); 1076 if (nffsdev->nd_syncing) 1077 cv_wait(&nffsdev->nd_sync_cv, &nffsdev->nd_sync_mtx); 1078 if (reason == SYNCER_UMOUNT) 1079 nffsdev->nd_syncer_exit = 1; 1080 nffsdev->nd_syncing = 1; 1081 wakeup(&nffsdev->nd_syncing); 1082 cv_wait(&nffsdev->nd_sync_cv, &nffsdev->nd_sync_mtx); 1083 1084 mtx_unlock(&nffsdev->nd_sync_mtx); 1085} 1086 1087static void 1088nandfs_gc_finished(struct nandfs_device *nffsdev, int exit) 1089{ 1090 int error; 1091 1092 mtx_lock(&nffsdev->nd_sync_mtx); 1093 nffsdev->nd_syncing = 0; 1094 DPRINTF(SYNC, ("%s: cleaner finish\n", __func__)); 1095 cv_broadcast(&nffsdev->nd_sync_cv); 1096 mtx_unlock(&nffsdev->nd_sync_mtx); 1097 if (!exit) { 1098 error = tsleep(&nffsdev->nd_syncing, PRIBIO, "-", 1099 hz * nandfs_sync_interval); 1100 DPRINTF(SYNC, ("%s: cleaner waked up: %d\n", 1101 __func__, error)); 1102 } 1103} 1104 1105static void 1106nandfs_syncer(struct nandfsmount *nmp) 1107{ 1108 struct nandfs_device *nffsdev; 1109 struct mount *mp; 1110 int flags, error; 1111 1112 mp = nmp->nm_vfs_mountp; 1113 nffsdev = nmp->nm_nandfsdev; 1114 tsleep(&nffsdev->nd_syncing, PRIBIO, "-", hz * nandfs_sync_interval); 1115 1116 while (!nffsdev->nd_syncer_exit) { 1117 DPRINTF(SYNC, ("%s: syncer run\n", __func__)); 1118 nffsdev->nd_syncing = 1; 1119 1120 flags = (nmp->nm_flags & (NANDFS_FORCE_SYNCER | NANDFS_UMOUNT)); 1121 1122 error = nandfs_segment_constructor(nmp, flags); 1123 if (error) 1124 nandfs_error("%s: error:%d when creating segments\n", 1125 __func__, error); 1126 1127 nmp->nm_flags &= ~flags; 1128 1129 nandfs_gc_finished(nffsdev, 0); 1130 } 1131 1132 MPASS(nffsdev->nd_cleaner == NULL); 1133 error = nandfs_segment_constructor(nmp, 1134 NANDFS_FORCE_SYNCER | NANDFS_UMOUNT); 1135 if (error) 1136 nandfs_error("%s: error:%d when creating segments\n", 1137 __func__, error); 1138 nandfs_gc_finished(nffsdev, 1); 1139 nffsdev->nd_syncer = NULL; 1140 MPASS(nffsdev->nd_free_base == NULL); 1141 1142 DPRINTF(SYNC, ("%s: exiting\n", __func__)); 1143 kthread_exit(); 1144} 1145 1146static int 1147start_syncer(struct nandfsmount *nmp) 1148{ 1149 int error; 1150 1151 MPASS(nmp->nm_nandfsdev->nd_syncer == NULL); 1152 1153 DPRINTF(SYNC, ("%s: start syncer\n", __func__)); 1154 1155 nmp->nm_nandfsdev->nd_syncer_exit = 0; 1156 1157 error = kthread_add((void(*)(void *))nandfs_syncer, nmp, NULL, 1158 &nmp->nm_nandfsdev->nd_syncer, 0, 0, "nandfs_syncer"); 1159 1160 if (error) 1161 printf("nandfs: could not start syncer: %d\n", error); 1162 1163 return (error); 1164} 1165 1166static int 1167stop_syncer(struct nandfsmount *nmp) 1168{ 1169 1170 MPASS(nmp->nm_nandfsdev->nd_syncer != NULL); 1171 1172 nandfs_wakeup_wait_sync(nmp->nm_nandfsdev, SYNCER_UMOUNT); 1173 1174 DPRINTF(SYNC, ("%s: stop syncer\n", __func__)); 1175 return (0); 1176} 1177 1178/* 1179 * Mount null layer 1180 */ 1181static int 1182nandfs_mount(struct mount *mp) 1183{ 1184 struct nandfsmount *nmp; 1185 struct vnode *devvp; 1186 struct nameidata nd; 1187 struct vfsoptlist *opts; 1188 struct thread *td; 1189 char *from; 1190 int error = 0, flags; 1191 1192 DPRINTF(VOLUMES, ("%s: mp = %p\n", __func__, (void *)mp)); 1193 1194 td = curthread; 1195 opts = mp->mnt_optnew; 1196 1197 if (vfs_filteropt(opts, nandfs_opts)) 1198 return (EINVAL); 1199 1200 /* 1201 * Update is a no-op 1202 */ 1203 if (mp->mnt_flag & MNT_UPDATE) { 1204 nmp = VFSTONANDFS(mp); 1205 if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0)) { 1206 return (error); 1207 } 1208 if (!(nmp->nm_ronly) && vfs_flagopt(opts, "ro", NULL, 0)) { 1209 vn_start_write(NULL, &mp, V_WAIT); 1210 error = VFS_SYNC(mp, MNT_WAIT); 1211 if (error) 1212 return (error); 1213 vn_finished_write(mp); 1214 1215 flags = WRITECLOSE; 1216 if (mp->mnt_flag & MNT_FORCE) 1217 flags |= FORCECLOSE; 1218 1219 nandfs_wakeup_wait_sync(nmp->nm_nandfsdev, 1220 SYNCER_ROUPD); 1221 error = vflush(mp, 0, flags, td); 1222 if (error) 1223 return (error); 1224 1225 nandfs_stop_cleaner(nmp->nm_nandfsdev); 1226 stop_syncer(nmp); 1227 DROP_GIANT(); 1228 g_topology_lock(); 1229 g_access(nmp->nm_nandfsdev->nd_gconsumer, 0, -1, 0); 1230 g_topology_unlock(); 1231 PICKUP_GIANT(); 1232 MNT_ILOCK(mp); 1233 mp->mnt_flag |= MNT_RDONLY; 1234 MNT_IUNLOCK(mp); 1235 nmp->nm_ronly = 1; 1236 1237 } else if ((nmp->nm_ronly) && 1238 !vfs_flagopt(opts, "ro", NULL, 0)) { 1239 /* 1240 * Don't allow read-write snapshots. 1241 */ 1242 if (nmp->nm_mount_args.cpno != 0) 1243 return (EROFS); 1244 /* 1245 * If upgrade to read-write by non-root, then verify 1246 * that user has necessary permissions on the device. 1247 */ 1248 devvp = nmp->nm_nandfsdev->nd_devvp; 1249 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 1250 error = VOP_ACCESS(devvp, VREAD | VWRITE, 1251 td->td_ucred, td); 1252 if (error) { 1253 error = priv_check(td, PRIV_VFS_MOUNT_PERM); 1254 if (error) { 1255 VOP_UNLOCK(devvp, 0); 1256 return (error); 1257 } 1258 } 1259 1260 VOP_UNLOCK(devvp, 0); 1261 DROP_GIANT(); 1262 g_topology_lock(); 1263 error = g_access(nmp->nm_nandfsdev->nd_gconsumer, 0, 1, 1264 0); 1265 g_topology_unlock(); 1266 PICKUP_GIANT(); 1267 if (error) 1268 return (error); 1269 1270 MNT_ILOCK(mp); 1271 mp->mnt_flag &= ~MNT_RDONLY; 1272 MNT_IUNLOCK(mp); 1273 error = start_syncer(nmp); 1274 if (error == 0) 1275 error = nandfs_start_cleaner(nmp->nm_nandfsdev); 1276 if (error) { 1277 DROP_GIANT(); 1278 g_topology_lock(); 1279 g_access(nmp->nm_nandfsdev->nd_gconsumer, 0, -1, 1280 0); 1281 g_topology_unlock(); 1282 PICKUP_GIANT(); 1283 return (error); 1284 } 1285 1286 nmp->nm_ronly = 0; 1287 } 1288 return (0); 1289 } 1290 1291 from = vfs_getopts(opts, "from", &error); 1292 if (error) 1293 return (error); 1294 1295 /* 1296 * Find device node 1297 */ 1298 NDINIT(&nd, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, from, curthread); 1299 error = namei(&nd); 1300 if (error) 1301 return (error); 1302 NDFREE(&nd, NDF_ONLY_PNBUF); 1303 1304 devvp = nd.ni_vp; 1305 1306 if (!vn_isdisk(devvp, &error)) { 1307 vput(devvp); 1308 return (error); 1309 } 1310 1311 /* Check the access rights on the mount device */ 1312 error = VOP_ACCESS(devvp, VREAD, curthread->td_ucred, curthread); 1313 if (error) 1314 error = priv_check(curthread, PRIV_VFS_MOUNT_PERM); 1315 if (error) { 1316 vput(devvp); 1317 return (error); 1318 } 1319 1320 vfs_getnewfsid(mp); 1321 1322 error = nandfs_mountfs(devvp, mp); 1323 if (error) 1324 return (error); 1325 vfs_mountedfrom(mp, from); 1326 1327 return (0); 1328} 1329 1330static int 1331nandfs_mountfs(struct vnode *devvp, struct mount *mp) 1332{ 1333 struct nandfsmount *nmp = NULL; 1334 struct nandfs_args *args = NULL; 1335 struct nandfs_device *nandfsdev; 1336 char *from; 1337 int error, ronly; 1338 char *cpno; 1339 1340 ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 1341 1342 if (devvp->v_rdev->si_iosize_max != 0) 1343 mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max; 1344 VOP_UNLOCK(devvp, 0); 1345 1346 if (mp->mnt_iosize_max > MAXPHYS) 1347 mp->mnt_iosize_max = MAXPHYS; 1348 1349 from = vfs_getopts(mp->mnt_optnew, "from", &error); 1350 if (error) 1351 goto error; 1352 1353 error = vfs_getopt(mp->mnt_optnew, "snap", (void **)&cpno, NULL); 1354 if (error == ENOENT) 1355 cpno = NULL; 1356 else if (error) 1357 goto error; 1358 1359 args = (struct nandfs_args *)malloc(sizeof(struct nandfs_args), 1360 M_NANDFSMNT, M_WAITOK | M_ZERO); 1361 1362 if (cpno != NULL) 1363 args->cpno = strtoul(cpno, (char **)NULL, 10); 1364 else 1365 args->cpno = 0; 1366 args->fspec = from; 1367 1368 if (args->cpno != 0 && !ronly) { 1369 error = EROFS; 1370 goto error; 1371 } 1372 1373 printf("WARNING: NANDFS is considered to be a highly experimental " 1374 "feature in FreeBSD.\n"); 1375 1376 error = nandfs_mount_device(devvp, mp, args, &nandfsdev); 1377 if (error) 1378 goto error; 1379 1380 nmp = (struct nandfsmount *) malloc(sizeof(struct nandfsmount), 1381 M_NANDFSMNT, M_WAITOK | M_ZERO); 1382 1383 mp->mnt_data = nmp; 1384 nmp->nm_vfs_mountp = mp; 1385 nmp->nm_ronly = ronly; 1386 MNT_ILOCK(mp); 1387 mp->mnt_flag |= MNT_LOCAL; 1388 MNT_IUNLOCK(mp); 1389 nmp->nm_nandfsdev = nandfsdev; 1390 /* Add our mountpoint */ 1391 STAILQ_INSERT_TAIL(&nandfsdev->nd_mounts, nmp, nm_next_mount); 1392 1393 if (args->cpno > nandfsdev->nd_last_cno) { 1394 printf("WARNING: supplied checkpoint number (%jd) is greater " 1395 "than last known checkpoint on filesystem (%jd). Mounting" 1396 " checkpoint %jd\n", (uintmax_t)args->cpno, 1397 (uintmax_t)nandfsdev->nd_last_cno, 1398 (uintmax_t)nandfsdev->nd_last_cno); 1399 args->cpno = nandfsdev->nd_last_cno; 1400 } 1401 1402 /* Setting up other parameters */ 1403 nmp->nm_mount_args = *args; 1404 free(args, M_NANDFSMNT); 1405 error = nandfs_mount_checkpoint(nmp); 1406 if (error) { 1407 nandfs_unmount(mp, MNT_FORCE); 1408 goto unmounted; 1409 } 1410 1411 if (!ronly) { 1412 error = start_syncer(nmp); 1413 if (error == 0) 1414 error = nandfs_start_cleaner(nmp->nm_nandfsdev); 1415 if (error) 1416 nandfs_unmount(mp, MNT_FORCE); 1417 } 1418 1419 return (0); 1420 1421error: 1422 if (args != NULL) 1423 free(args, M_NANDFSMNT); 1424 1425 if (nmp != NULL) { 1426 free(nmp, M_NANDFSMNT); 1427 mp->mnt_data = NULL; 1428 } 1429unmounted: 1430 return (error); 1431} 1432 1433static int 1434nandfs_unmount(struct mount *mp, int mntflags) 1435{ 1436 struct nandfs_device *nandfsdev; 1437 struct nandfsmount *nmp; 1438 int error; 1439 int flags = 0; 1440 1441 DPRINTF(VOLUMES, ("%s: mp = %p\n", __func__, (void *)mp)); 1442 1443 if (mntflags & MNT_FORCE) 1444 flags |= FORCECLOSE; 1445 1446 nmp = mp->mnt_data; 1447 nandfsdev = nmp->nm_nandfsdev; 1448 1449 error = vflush(mp, 0, flags | SKIPSYSTEM, curthread); 1450 if (error) 1451 return (error); 1452 1453 if (!(nmp->nm_ronly)) { 1454 nandfs_stop_cleaner(nandfsdev); 1455 stop_syncer(nmp); 1456 } 1457 1458 if (nmp->nm_ifile_node) 1459 NANDFS_UNSET_SYSTEMFILE(NTOV(nmp->nm_ifile_node)); 1460 1461 /* Remove our mount point */ 1462 STAILQ_REMOVE(&nandfsdev->nd_mounts, nmp, nandfsmount, nm_next_mount); 1463 1464 /* Unmount the device itself when we're the last one */ 1465 nandfs_unmount_device(nandfsdev); 1466 1467 free_nandfs_mountinfo(mp); 1468 1469 /* 1470 * Finally, throw away the null_mount structure 1471 */ 1472 mp->mnt_data = 0; 1473 MNT_ILOCK(mp); 1474 mp->mnt_flag &= ~MNT_LOCAL; 1475 MNT_IUNLOCK(mp); 1476 1477 return (0); 1478} 1479 1480static int 1481nandfs_statfs(struct mount *mp, struct statfs *sbp) 1482{ 1483 struct nandfsmount *nmp; 1484 struct nandfs_device *nandfsdev; 1485 struct nandfs_fsdata *fsdata; 1486 struct nandfs_super_block *sb; 1487 struct nandfs_block_group_desc *groups; 1488 struct nandfs_node *ifile; 1489 struct nandfs_mdt *mdt; 1490 struct buf *bp; 1491 int i, error; 1492 uint32_t entries_per_group; 1493 uint64_t files = 0; 1494 1495 nmp = mp->mnt_data; 1496 nandfsdev = nmp->nm_nandfsdev; 1497 fsdata = &nandfsdev->nd_fsdata; 1498 sb = &nandfsdev->nd_super; 1499 ifile = nmp->nm_ifile_node; 1500 mdt = &nandfsdev->nd_ifile_mdt; 1501 entries_per_group = mdt->entries_per_group; 1502 1503 VOP_LOCK(NTOV(ifile), LK_SHARED); 1504 error = nandfs_bread(ifile, 0, NOCRED, 0, &bp); 1505 if (error) { 1506 brelse(bp); 1507 VOP_UNLOCK(NTOV(ifile), 0); 1508 return (error); 1509 } 1510 1511 groups = (struct nandfs_block_group_desc *)bp->b_data; 1512 1513 for (i = 0; i < mdt->groups_per_desc_block; i++) 1514 files += (entries_per_group - groups[i].bg_nfrees); 1515 1516 brelse(bp); 1517 VOP_UNLOCK(NTOV(ifile), 0); 1518 1519 sbp->f_bsize = nandfsdev->nd_blocksize; 1520 sbp->f_iosize = sbp->f_bsize; 1521 sbp->f_blocks = fsdata->f_blocks_per_segment * fsdata->f_nsegments; 1522 sbp->f_bfree = sb->s_free_blocks_count; 1523 sbp->f_bavail = sbp->f_bfree; 1524 sbp->f_files = files; 1525 sbp->f_ffree = 0; 1526 return (0); 1527} 1528 1529static int 1530nandfs_root(struct mount *mp, int flags, struct vnode **vpp) 1531{ 1532 struct nandfsmount *nmp = VFSTONANDFS(mp); 1533 struct nandfs_node *node; 1534 int error; 1535 1536 error = nandfs_get_node(nmp, NANDFS_ROOT_INO, &node); 1537 if (error) 1538 return (error); 1539 1540 KASSERT(NTOV(node)->v_vflag & VV_ROOT, 1541 ("root_vp->v_vflag & VV_ROOT")); 1542 1543 *vpp = NTOV(node); 1544 1545 return (error); 1546} 1547 1548static int 1549nandfs_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) 1550{ 1551 struct nandfsmount *nmp = VFSTONANDFS(mp); 1552 struct nandfs_node *node; 1553 int error; 1554 1555 error = nandfs_get_node(nmp, ino, &node); 1556 if (node) 1557 *vpp = NTOV(node); 1558 1559 return (error); 1560} 1561 1562static int 1563nandfs_sync(struct mount *mp, int waitfor) 1564{ 1565 struct nandfsmount *nmp = VFSTONANDFS(mp); 1566 1567 DPRINTF(SYNC, ("%s: mp %p waitfor %d\n", __func__, mp, waitfor)); 1568 1569 /* 1570 * XXX: A hack to be removed soon 1571 */ 1572 if (waitfor == MNT_LAZY) 1573 return (0); 1574 if (waitfor == MNT_SUSPEND) 1575 return (0); 1576 nandfs_wakeup_wait_sync(nmp->nm_nandfsdev, SYNCER_VFS_SYNC); 1577 return (0); 1578} 1579 1580static struct vfsops nandfs_vfsops = { 1581 .vfs_init = nandfs_init, 1582 .vfs_mount = nandfs_mount, 1583 .vfs_root = nandfs_root, 1584 .vfs_statfs = nandfs_statfs, 1585 .vfs_uninit = nandfs_uninit, 1586 .vfs_unmount = nandfs_unmount, 1587 .vfs_vget = nandfs_vget, 1588 .vfs_sync = nandfs_sync, 1589}; 1590 1591VFS_SET(nandfs_vfsops, nandfs, VFCF_LOOPBACK); 1592