From owner-svn-src-projects@FreeBSD.ORG Fri Apr 20 03:02:08 2012 Return-Path: Delivered-To: svn-src-projects@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 478F4106566B; Fri, 20 Apr 2012 03:02:08 +0000 (UTC) (envelope-from gber@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 30FAE8FC12; Fri, 20 Apr 2012 03:02:08 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.4/8.14.4) with ESMTP id q3K328Ih019331; Fri, 20 Apr 2012 03:02:08 GMT (envelope-from gber@svn.freebsd.org) Received: (from gber@localhost) by svn.freebsd.org (8.14.4/8.14.4/Submit) id q3K327L5019317; Fri, 20 Apr 2012 03:02:07 GMT (envelope-from gber@svn.freebsd.org) Message-Id: <201204200302.q3K327L5019317@svn.freebsd.org> From: Grzegorz Bernacki Date: Fri, 20 Apr 2012 03:02:07 +0000 (UTC) To: src-committers@freebsd.org, svn-src-projects@freebsd.org X-SVN-Group: projects MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r234479 - in projects/nand: lib/libnandfs sbin/nandfs sbin/newfs_nandfs sys/fs/nandfs X-BeenThere: svn-src-projects@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: "SVN commit messages for the src " projects" tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 20 Apr 2012 03:02:08 -0000 Author: gber Date: Fri Apr 20 03:02:07 2012 New Revision: 234479 URL: http://svn.freebsd.org/changeset/base/234479 Log: nandfs: Fixes. - replace error numbers with proper macros - get rid of some unused fields in fsdata and super block - when erasing segment invalidate gc buffers that still point to it - flag segments that are going to be erased (this flag should never hit storage - it is only so that cleaner does not try to clear one segment twice) - place some asserts - add veryfing FS revision at mount time - rmdir without this operation left invalid data in inode - file created right after deleted directory appeared as directory - reduce inode size of removed directory to 0 (similar to ext2fs, msdosfs) - check if inode has any links during lookup (similar to ufs) - protect write entry points by very same lock used to protect segment construction - this servers as our own version of vfs_write_suspend - ignore MNT_LAZY syncs - this is a hack used to ignore periodic syncs from mnt_syncer Obtained from: Semihalf Supported by: FreeBSD Foundation, Juniper Networks Modified: projects/nand/lib/libnandfs/Makefile projects/nand/sbin/nandfs/nandfs.c projects/nand/sbin/newfs_nandfs/newfs_nandfs.c projects/nand/sys/fs/nandfs/nandfs.h projects/nand/sys/fs/nandfs/nandfs_alloc.c projects/nand/sys/fs/nandfs/nandfs_cleaner.c projects/nand/sys/fs/nandfs/nandfs_fs.h projects/nand/sys/fs/nandfs/nandfs_segment.c projects/nand/sys/fs/nandfs/nandfs_subr.c projects/nand/sys/fs/nandfs/nandfs_subr.h projects/nand/sys/fs/nandfs/nandfs_sufile.c projects/nand/sys/fs/nandfs/nandfs_vfsops.c projects/nand/sys/fs/nandfs/nandfs_vnops.c Modified: projects/nand/lib/libnandfs/Makefile ============================================================================== --- projects/nand/lib/libnandfs/Makefile Fri Apr 20 02:47:35 2012 (r234478) +++ projects/nand/lib/libnandfs/Makefile Fri Apr 20 03:02:07 2012 (r234479) @@ -1,3 +1,5 @@ +# $FreeBSD$ + LIB= nandfs SRCS+= nandfs.c INCS= libnandfs.h Modified: projects/nand/sbin/nandfs/nandfs.c ============================================================================== --- projects/nand/sbin/nandfs/nandfs.c Fri Apr 20 02:47:35 2012 (r234478) +++ projects/nand/sbin/nandfs/nandfs.c Fri Apr 20 03:02:07 2012 (r234479) @@ -45,7 +45,7 @@ usage(void) fprintf(stderr, "usage: nandfs [lssnap | mksnap | rmsnap] " "node\n"); - exit(EX_USAGE); + exit(1); } int Modified: projects/nand/sbin/newfs_nandfs/newfs_nandfs.c ============================================================================== --- projects/nand/sbin/newfs_nandfs/newfs_nandfs.c Fri Apr 20 02:47:35 2012 (r234478) +++ projects/nand/sbin/newfs_nandfs/newfs_nandfs.c Fri Apr 20 03:02:07 2012 (r234479) @@ -517,13 +517,9 @@ create_fsdata(void) fsdata.f_rev_level = NANDFS_CURRENT_REV; fsdata.f_sbbytes = NANDFS_SB_BYTES; fsdata.f_bytes = NANDFS_FSDATA_CRC_BYTES; - fsdata.f_dev_size = mediasize; fsdata.f_ctime = nandfs_time; fsdata.f_log_block_size = nandfs_log2(blocksize) - 10; fsdata.f_errors = 1; - fsdata.f_lastcheck = nandfs_time; - fsdata.f_checkinterval = 60*60*24*180; - fsdata.f_first_ino = NANDFS_USER_INO; fsdata.f_inode_size = sizeof(struct nandfs_inode); fsdata.f_dat_entry_size = sizeof(struct nandfs_dat_entry); fsdata.f_checkpoint_size = sizeof(struct nandfs_checkpoint); @@ -559,8 +555,6 @@ create_super_block(void) (nsegments - bad_segments_count) * blocks_per_segment; super_block.s_mtime = 0; super_block.s_wtime = nandfs_time; - super_block.s_mnt_count = 0; - super_block.s_max_mnt_count = NANDFS_DFL_MAX_MNT_COUNT; super_block.s_state = NANDFS_VALID_FS; super_block.s_sum = crc32_le(crc_seed, (const uint8_t *)&super_block, Modified: projects/nand/sys/fs/nandfs/nandfs.h ============================================================================== --- projects/nand/sys/fs/nandfs/nandfs.h Fri Apr 20 02:47:35 2012 (r234478) +++ projects/nand/sys/fs/nandfs/nandfs.h Fri Apr 20 03:02:07 2012 (r234479) @@ -233,6 +233,11 @@ extern SLIST_HEAD(_nandfs_devices, nandf #define SYNCER_FSYNC 0x4 #define SYNCER_ROUPD 0x5 +#define NANDFS_WRITELOCK(vp, fsdev) nandfs_writelock(vp, fsdev) +#define NANDFS_WRITEUNLOCK(fsdev) nandfs_writeunlock(fsdev) + +#define NANDFS_WRITEASSERT(fsdev) nandfs_writeassert(fsdev) + /* Specific mountpoint; head or a checkpoint/snapshot */ struct nandfsmount { STAILQ_ENTRY(nandfsmount) nm_next_mount; Modified: projects/nand/sys/fs/nandfs/nandfs_alloc.c ============================================================================== --- projects/nand/sys/fs/nandfs/nandfs_alloc.c Fri Apr 20 02:47:35 2012 (r234478) +++ projects/nand/sys/fs/nandfs/nandfs_alloc.c Fri Apr 20 03:02:07 2012 (r234479) @@ -260,6 +260,7 @@ nandfs_free_entry(struct nandfs_mdt* mdt /* Set bit to indicate that entry is taken */ mask = (uint32_t *)req->bp_bitmap->b_data; maskrw = mask[bitmap_idx]; + KASSERT(maskrw & (1 << bitmap_off), ("freeing unallocated vblock")); maskrw &= ~(1 << bitmap_off); mask[bitmap_idx] = maskrw; Modified: projects/nand/sys/fs/nandfs/nandfs_cleaner.c ============================================================================== --- projects/nand/sys/fs/nandfs/nandfs_cleaner.c Fri Apr 20 02:47:35 2012 (r234478) +++ projects/nand/sys/fs/nandfs/nandfs_cleaner.c Fri Apr 20 03:02:07 2012 (r234479) @@ -256,8 +256,8 @@ nandfs_cleaner_iterate_segment(struct na binfo = (union nandfs_binfo *)(bp->b_data + segsum->ss_bytes); if (!nandfs_segsum_valid(segsum)) { - nandfs_error("nandfs: invalid summary of segment %jx\n", segno); brelse(bp); + nandfs_error("nandfs: invalid summary of segment %jx\n", segno); return (error); } @@ -293,7 +293,8 @@ nandfs_cleaner_choose_segment(struct nan error = nandfs_get_segment_info_filter(fsdev, suinfo, nsegs, *rseg, &ssegs, NANDFS_SEGMENT_USAGE_DIRTY, - NANDFS_SEGMENT_USAGE_ACTIVE | NANDFS_SEGMENT_USAGE_ERROR); + NANDFS_SEGMENT_USAGE_ACTIVE | NANDFS_SEGMENT_USAGE_ERROR | + NANDFS_SEGMENT_USAGE_GC); if (error) { nandfs_error("%s:%d", __FILE__, __LINE__); goto out; @@ -306,7 +307,7 @@ nandfs_cleaner_choose_segment(struct nan (*segpp)++; } - *rseg = suinfo[i - 1].nsi_num; + *rseg = suinfo[i - 1].nsi_num + 1; out: free(suinfo, M_NANDFSTEMP); @@ -351,13 +352,21 @@ nandfs_cleaner_body(struct nandfs_device error = nandfs_cleaner_iterate_segment(fsdev, segnums[i], &vip, &bdp, &select); if (error) { - nandfs_error("%s:%d", __FILE__, __LINE__); + /* + * XXX deselect (see below)? + */ goto out; } if (!select) segnums[i] = NANDFS_NOSEGMENT; - else + else { + error = nandfs_markgc_segment(fsdev, segnums[i]); + if (error) { + nandfs_error("%s:%d\n", __FILE__, __LINE__); + goto out; + } selected++; + } } if (selected == 0) { @@ -379,14 +388,16 @@ nandfs_cleaner_body(struct nandfs_device cpinfo, cpstat.ncp_nss, NULL); if (error) { nandfs_error("%s:%d\n", __FILE__, __LINE__); - goto out; + goto out_locked; } } + lockmgr(&fsdev->nd_seg_const, LK_EXCLUSIVE, NULL); + error = nandfs_get_dat_vinfo(fsdev, vinfo, vip - vinfo); if (error) { nandfs_error("%s:%d\n", __FILE__, __LINE__); - goto out; + goto out_locked; } nandfs_cleaner_vinfo_mark_alive(fsdev, vinfo, vip - vinfo, cpinfo, @@ -395,7 +406,7 @@ nandfs_cleaner_body(struct nandfs_device error = nandfs_get_dat_bdescs(fsdev, bdesc, bdp - bdesc); if (error) { nandfs_error("%s:%d\n", __FILE__, __LINE__); - goto out; + goto out_locked; } nandfs_cleaner_bdesc_mark_alive(fsdev, bdesc, bdp - bdesc); @@ -407,8 +418,9 @@ nandfs_cleaner_body(struct nandfs_device vipi->nvi_start, vipi->nvi_end, vipi->nvi_alive)); } for (bdpi = bdesc; bdpi < bdp; bdpi++) { - DPRINTF(CLEAN, ("b oblocknr %jx blocknr %jx offset %jx\n", - bdpi->bd_oblocknr, bdpi->bd_blocknr, bdpi->bd_offset)); + DPRINTF(CLEAN, ("b oblocknr %jx blocknr %jx offset %jx " + "alive %d\n", bdpi->bd_oblocknr, bdpi->bd_blocknr, + bdpi->bd_offset, bdpi->bd_alive)); } DPRINTF(CLEAN, ("end list\n")); @@ -417,6 +429,8 @@ nandfs_cleaner_body(struct nandfs_device if (error) nandfs_error("%s:%d\n", __FILE__, __LINE__); +out_locked: + lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL); out: free(cpinfo, M_NANDFSTEMP); free(segnums, M_NANDFSTEMP); @@ -464,7 +478,6 @@ nandfs_cleaner_clean_segments(struct nan gc = nffsdev->nd_gc_node; - lockmgr(&nffsdev->nd_seg_const, LK_EXCLUSIVE, NULL); DPRINTF(CLEAN, ("%s: enter\n", __func__)); @@ -535,7 +548,6 @@ nandfs_cleaner_clean_segments(struct nan } out: - lockmgr(&nffsdev->nd_seg_const, LK_RELEASE, NULL); DPRINTF(CLEAN, ("%s: exit error %d\n", __func__, error)); Modified: projects/nand/sys/fs/nandfs/nandfs_fs.h ============================================================================== --- projects/nand/sys/fs/nandfs/nandfs_fs.h Fri Apr 20 02:47:35 2012 (r234478) +++ projects/nand/sys/fs/nandfs/nandfs_fs.h Fri Apr 20 03:02:07 2012 (r234479) @@ -146,7 +146,6 @@ struct nandfs_fsdata { uint32_t f_sum; /* checksum of fsdata */ uint32_t f_rev_level; /* major disk format revision */ - uint64_t f_dev_size; /* block device size in bytes */ uint64_t f_ctime; /* creation time (execution time of newfs) */ /* Block size represented as: blocksize = 1 << (f_log_block_size + 10) */ @@ -162,7 +161,6 @@ struct nandfs_fsdata { is excluded! */ uint16_t f_errors; /* behaviour on detecting errors */ - uint64_t f_lastcheck; /* time of last checked */ uint32_t f_erasesize; uint64_t f_nsegments; /* number of segm. in filesystem */ @@ -170,24 +168,17 @@ struct nandfs_fsdata { uint32_t f_blocks_per_segment; /* number of blocks per segment */ uint32_t f_r_segments_percentage; /* reserved segments percentage */ - uint32_t f_checkinterval; /* max. time between checks */ - uint16_t f_def_resuid; /* default uid for reserv. blocks */ - uint16_t f_def_resgid; /* default gid for reserv. blocks */ - uint32_t f_first_ino; /* first non-reserved inode */ - uint32_t f_crc_seed; /* seed value of CRC calculation */ struct uuid f_uuid; /* 128-bit uuid for volume */ char f_volume_name[16]; /* volume name */ - uint32_t f_pad[96]; + uint32_t f_pad[103]; } __packed; #ifdef _KERNEL CTASSERT(sizeof(struct nandfs_fsdata) == 512); #endif -#define NANDFS_DFL_MAX_MNT_COUNT 50 /* default 50 mounts before fsck */ - struct nandfs_super_block { uint16_t s_magic; /* magic value for identification */ @@ -200,8 +191,6 @@ struct nandfs_super_block { uint64_t s_mtime; /* mount time */ uint64_t s_wtime; /* write time */ - uint16_t s_mnt_count; /* mount count */ - uint16_t s_max_mnt_count; /* maximal mount count */ uint16_t s_state; /* file system state */ char s_last_mounted[64]; /* directory where last mounted */ @@ -209,7 +198,7 @@ struct nandfs_super_block { uint32_t s_c_interval; /* commit interval of segment */ uint32_t s_c_block_max; /* threshold of data amount for the segment construction */ - uint32_t s_reserved[31]; /* padding to end of the block */ + uint32_t s_reserved[32]; /* padding to end of the block */ } __packed; #ifdef _KERNEL @@ -442,6 +431,7 @@ struct nandfs_segment_usage { #define NANDFS_SEGMENT_USAGE_ACTIVE 1 #define NANDFS_SEGMENT_USAGE_DIRTY 2 #define NANDFS_SEGMENT_USAGE_ERROR 4 +#define NANDFS_SEGMENT_USAGE_GC 8 #define NANDFS_SEGMENT_USAGE_BITS "\20\1ACTIVE\2DIRTY\3ERROR" /* Header of the segment usage file */ Modified: projects/nand/sys/fs/nandfs/nandfs_segment.c ============================================================================== --- projects/nand/sys/fs/nandfs/nandfs_segment.c Fri Apr 20 02:47:35 2012 (r234478) +++ projects/nand/sys/fs/nandfs/nandfs_segment.c Fri Apr 20 03:02:07 2012 (r234479) @@ -110,7 +110,7 @@ create_segment(struct nandfs_seginfo *se } start_block = fsdev->nd_last_pseg + (uint64_t)nblocks; /* - * XXX hack + * XXX Hack */ if (blks_per_seg - (start_block % blks_per_seg) - 1 == 0) start_block++; @@ -123,6 +123,10 @@ create_segment(struct nandfs_seginfo *se __func__); return (error); } + /* + * XXX Hack + */ + nandfs_get_segment_range(fsdev, fsdev->nd_seg_num, &start_block, NULL); } } else { nandfs_get_segment_range(fsdev, fsdev->nd_next_seg_num, @@ -503,6 +507,12 @@ nandfs_iterate_dirty_vnodes(struct mount continue; } + if (vp->v_iflag & VI_DOOMED) { + vput(vp); + MNT_ILOCK(mp); + continue; + } + nandfs_node = VTON(vp); if (nandfs_node->nn_flags & IN_MODIFIED) { nandfs_node->nn_flags &= ~(IN_MODIFIED); @@ -921,6 +931,36 @@ out: return (error); } +static void +nandfs_invalidate_bufs(struct nandfs_device *fsdev, uint64_t segno) +{ + uint64_t start, end; + struct buf *bp, *tbd; + struct bufobj *bo; + + nandfs_get_segment_range(fsdev, segno, &start, &end); + + bo = &NTOV(fsdev->nd_gc_node)->v_bufobj; + + BO_LOCK(bo); +restart_locked_gc: + TAILQ_FOREACH_SAFE(bp, &bo->bo_clean.bv_hd, b_bobufs, tbd) { + if (!(bp->b_lblkno >= start || bp->b_lblkno <= end)) + continue; + + if (BUF_LOCK(bp, LK_EXCLUSIVE | LK_NOWAIT, NULL)) + goto restart_locked_gc; + + bremfree(bp); + bp->b_flags |= (B_INVAL | B_RELBUF); + bp->b_flags &= ~(B_ASYNC | B_MANAGED); + BO_UNLOCK(bo); + brelse(bp); + BO_LOCK(bo); + } + BO_UNLOCK(bo); +} + /* Process segments marks to free by cleaner */ static void nandfs_process_segments(struct nandfs_device *fsdev) @@ -940,6 +980,7 @@ nandfs_process_segments(struct nandfs_de saved_segment = nandfs_get_segnum_of_block( fsdev, fsdev->nd_super.s_last_pseg); } + nandfs_invalidate_bufs(fsdev, fsdev->nd_free_base[i]); nandfs_clear_segment(fsdev, fsdev->nd_free_base[i]); } Modified: projects/nand/sys/fs/nandfs/nandfs_subr.c ============================================================================== --- projects/nand/sys/fs/nandfs/nandfs_subr.c Fri Apr 20 02:47:35 2012 (r234478) +++ projects/nand/sys/fs/nandfs/nandfs_subr.c Fri Apr 20 03:02:07 2012 (r234479) @@ -274,6 +274,8 @@ nandfs_bdestroy(struct nandfs_node *node { int error; + NANDFS_WRITEASSERT(node->nn_nandfsdev); + error = nandfs_vblock_end(node->nn_nandfsdev, vblk); if (error) { nandfs_error("%s: ending vblk: %jx failed\n", @@ -292,6 +294,7 @@ nandfs_bcreate(struct nandfs_node *node, int error; ASSERT_VOP_LOCKED(NTOV(node), __func__); + NANDFS_WRITEASSERT(node->nn_nandfsdev); DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node), blocknr)); @@ -329,6 +332,7 @@ nandfs_bcreate_meta(struct nandfs_node * int error; ASSERT_VOP_LOCKED(NTOV(node), __func__); + NANDFS_WRITEASSERT(node->nn_nandfsdev); DPRINTF(BLOCK, ("%s: vp:%p lbn:%#jx\n", __func__, NTOV(node), blocknr)); @@ -431,7 +435,7 @@ nandfs_mdt_trans_blk(struct nandfs_mdt * static int nandfs_vtop(struct nandfs_device *nandfsdev, nandfs_daddr_t vblocknr, - uint64_t *pblocknr) + nandfs_daddr_t *pblocknr) { struct nandfs_node *dat_node; struct nandfs_dat_entry *entry; @@ -468,13 +472,16 @@ nandfs_vtop(struct nandfs_device *nandfs brelse(bp); if (!locked) VOP_UNLOCK(NTOV(dat_node), 0); + + MPASS(*pblocknr >= 0); + return (0); } int nandfs_nvtop(struct nandfs_node *node, uint64_t blks, nandfs_daddr_t *l2vmap, - uint64_t *v2pmap) + nandfs_daddr_t *v2pmap) { nandfs_daddr_t vblocknr; uint64_t *pblocknr; @@ -1200,3 +1207,34 @@ nandfs_block_to_dblock(struct nandfs_dev return (btodb(block * fsdev->nd_blocksize)); } + +void +nandfs_writelock(struct vnode *vp, struct nandfs_device *fsdev) +{ + int lock; + + if (lockmgr(&fsdev->nd_seg_const, LK_NOWAIT | LK_SHARED, NULL)) { + vref(vp); + lock = VOP_ISLOCKED(vp); + VOP_UNLOCK(vp, 0); + DPRINTF(WRITE, ("%s: waiting for write lock, vp %p\n", + __func__, vp)); + lockmgr(&fsdev->nd_seg_const, LK_SHARED, NULL); + VOP_LOCK(vp, lock | LK_RETRY); + vunref(vp); + } +} + +void +nandfs_writeunlock(struct nandfs_device *fsdev) +{ + + lockmgr(&fsdev->nd_seg_const, LK_RELEASE, NULL); +} + +void +nandfs_writeassert(struct nandfs_device *fsdev) +{ + + lockmgr_assert(&fsdev->nd_seg_const, KA_LOCKED); +} Modified: projects/nand/sys/fs/nandfs/nandfs_subr.h ============================================================================== --- projects/nand/sys/fs/nandfs/nandfs_subr.h Fri Apr 20 02:47:35 2012 (r234478) +++ projects/nand/sys/fs/nandfs/nandfs_subr.h Fri Apr 20 03:02:07 2012 (r234479) @@ -75,7 +75,7 @@ int nandfs_bmap_nlookup(struct nandfs_no uint64_t *); /* vtop operations */ -int nandfs_nvtop(struct nandfs_node *, uint64_t, nandfs_daddr_t *, uint64_t *); +int nandfs_nvtop(struct nandfs_node *, uint64_t, nandfs_daddr_t *, nandfs_daddr_t *); /* Node action implementators */ int nandfs_vinit(struct vnode *, uint64_t); @@ -147,6 +147,7 @@ int nandfs_update_segment(struct nandfs_ int nandfs_free_segment(struct nandfs_device *, uint64_t); int nandfs_clear_segment(struct nandfs_device *, uint64_t); int nandfs_touch_segment(struct nandfs_device *, uint64_t); +int nandfs_markgc_segment(struct nandfs_device *, uint64_t); int nandfs_bmap_insert_block(struct nandfs_node *, nandfs_lbn_t, struct buf *); int nandfs_bmap_update_block(struct nandfs_node *, struct buf *, nandfs_lbn_t); @@ -226,6 +227,10 @@ int nandfs_vop_islocked(struct vnode *vp nandfs_daddr_t nandfs_block_to_dblock(struct nandfs_device *, nandfs_lbn_t); +void nandfs_writelock(struct vnode *, struct nandfs_device *); +void nandfs_writeunlock(struct nandfs_device *); +void nandfs_writeassert(struct nandfs_device *); + #define DEBUG_MODE #if defined(DEBUG_MODE) #define nandfs_error panic Modified: projects/nand/sys/fs/nandfs/nandfs_sufile.c ============================================================================== --- projects/nand/sys/fs/nandfs/nandfs_sufile.c Fri Apr 20 02:47:35 2012 (r234478) +++ projects/nand/sys/fs/nandfs/nandfs_sufile.c Fri Apr 20 03:02:07 2012 (r234479) @@ -367,6 +367,40 @@ nandfs_bad_segment(struct nandfs_device } int +nandfs_markgc_segment(struct nandfs_device *fsdev, uint64_t seg) +{ + struct nandfs_node *su_node; + struct nandfs_segment_usage *su_usage; + struct buf *bp; + uint64_t blk, offset; + int error; + + su_node = fsdev->nd_su_node; + + VOP_LOCK(NTOV(su_node), LK_EXCLUSIVE); + + nandfs_seg_usage_blk_offset(fsdev, seg, &blk, &offset); + + error = nandfs_bread(su_node, blk, NOCRED, 0, &bp); + if (error) { + brelse(bp); + VOP_UNLOCK(NTOV(su_node), 0); + return (error); + } + + su_usage = SU_USAGE_OFF(bp, offset); + MPASS((su_usage->su_flags & NANDFS_SEGMENT_USAGE_GC) == 0); + su_usage->su_flags |= NANDFS_SEGMENT_USAGE_GC; + + brelse(bp); + VOP_UNLOCK(NTOV(su_node), 0); + + DPRINTF(SEG, ("%s: seg:%#jx\n", __func__, (uintmax_t)seg)); + + return (0); +} + +int nandfs_clear_segment(struct nandfs_device *fsdev, uint64_t seg) { uint64_t offset, segsize; Modified: projects/nand/sys/fs/nandfs/nandfs_vfsops.c ============================================================================== --- projects/nand/sys/fs/nandfs/nandfs_vfsops.c Fri Apr 20 02:47:35 2012 (r234478) +++ projects/nand/sys/fs/nandfs/nandfs_vfsops.c Fri Apr 20 03:02:07 2012 (r234479) @@ -664,6 +664,13 @@ nandfs_mount_base(struct nandfs_device * return (error); } + if (nandfsdev->nd_fsdata.f_rev_level != NANDFS_CURRENT_REV) { + printf("nandfs: unsupported file system revision: %d " + "(supported is %d).\n", nandfsdev->nd_fsdata.f_rev_level, + NANDFS_CURRENT_REV); + return (EINVAL); + } + if (nandfsdev->nd_fsdata.f_erasesize != nandfsdev->nd_erasesize) { printf("nandfs: erasesize mismatch (device %#x, fs %#x)\n", nandfsdev->nd_erasesize, nandfsdev->nd_fsdata.f_erasesize); @@ -892,11 +899,7 @@ nandfs_mount_device(struct vnode *devvp, if (error) { DPRINTF(VOLUMES, ("couldn't get erasesize: %d\n", error)); - /* - * FIXME translate this to some normal error codes, also make - * sure that we cannot get this error with NAND devices - */ - if (error == -3 || error == 45) { + if (error == ENOIOCTL || error == EOPNOTSUPP) { /* * We conclude that this is not NAND storage */ @@ -1116,12 +1119,10 @@ nandfs_procbody(struct nandfsmount *nmp) flags = (nmp->nm_flags & (NANDFS_FORCE_SYNCER|NANDFS_UMOUNT)); - vfs_write_suspend(mp); error = nandfs_segment_constructor(nmp, flags); if (error) nandfs_error("%s: error:%d when creating segments\n", __func__, error); - vfs_write_resume(mp); nmp->nm_flags &= ~flags; @@ -1173,9 +1174,7 @@ stop_syncer(struct nandfsmount *nmp) MPASS(nmp->nm_nandfsdev->nd_syncer != NULL); - vn_finished_write(nmp->nm_vfs_mountp); nandfs_wakeup_wait_sync(nmp->nm_nandfsdev, SYNCER_UMOUNT); - vn_start_write(NULL, &nmp->nm_vfs_mountp, V_WAIT); DPRINTF(SYNC, ("%s: stop syncer\n", __func__)); return (0); @@ -1453,12 +1452,7 @@ nandfs_unmount(struct mount *mp, int mnt /* Umount already stopped writing */ if (!(nmp->nm_ronly)) { nmp->nm_flags |= NANDFS_UMOUNT; - /* - * XXX This is a hack soon to be removed - */ - vn_finished_write(mp); nandfs_wakeup_wait_sync(nmp->nm_nandfsdev, SYNCER_VFS_SYNC); - vn_start_write(NULL, &mp, V_WAIT); } error = vflush(mp, 0, flags | SKIPSYSTEM, curthread); if (error) @@ -1578,11 +1572,16 @@ nandfs_sync(struct mount *mp, int waitfo { struct nandfsmount *nmp = VFSTONANDFS(mp); + DPRINTF(SYNC, ("%s: mp %p waitfor %d\n", __func__, mp, waitfor)); + + /* + * XXX: A hack to be removed soon + */ + if (waitfor == MNT_LAZY) + return (0); if (waitfor == MNT_SUSPEND) return (0); - vn_finished_write(mp); nandfs_wakeup_wait_sync(nmp->nm_nandfsdev, SYNCER_VFS_SYNC); - vn_start_write(NULL, &mp, V_WAIT); return (0); } Modified: projects/nand/sys/fs/nandfs/nandfs_vnops.c ============================================================================== --- projects/nand/sys/fs/nandfs/nandfs_vnops.c Fri Apr 20 02:47:35 2012 (r234478) +++ projects/nand/sys/fs/nandfs/nandfs_vnops.c Fri Apr 20 03:02:07 2012 (r234479) @@ -124,8 +124,8 @@ static int nandfs_read(struct vop_read_args *ap) { register struct vnode *vp = ap->a_vp; - register struct nandfs_node *nandfs_node = VTON(vp); - struct nandfs_device *nandfsdev = nandfs_node->nn_nandfsdev; + register struct nandfs_node *node = VTON(vp); + struct nandfs_device *nandfsdev = node->nn_nandfsdev; struct uio *uio = ap->a_uio; struct buf *bp; uint64_t size; @@ -139,10 +139,12 @@ nandfs_read(struct vop_read_args *ap) if (uio->uio_resid == 0) return (0); - size = nandfs_node->nn_inode.i_size; + size = node->nn_inode.i_size; if (uio->uio_offset >= size) return (0); + NANDFS_WRITELOCK(vp, node->nn_nandfsdev); + blocksize = nandfsdev->nd_blocksize; bytesinfile = size - uio->uio_offset; @@ -157,7 +159,7 @@ nandfs_read(struct vop_read_args *ap) DPRINTF(READ, ("nandfs_read bn: 0x%jx toread: 0x%zx (0x%x)\n", (uintmax_t)lbn, toread, blocksize)); - error = nandfs_bread(nandfs_node, lbn, NOCRED, 0, &bp); + error = nandfs_bread(node, lbn, NOCRED, 0, &bp); if (error) { brelse(bp); break; @@ -173,6 +175,8 @@ nandfs_read(struct vop_read_args *ap) resid -= toread; } + NANDFS_WRITEUNLOCK(node->nn_nandfsdev); + return (error); } @@ -208,6 +212,8 @@ nandfs_write(struct vop_write_args *ap) if (uio->uio_resid == 0) return (0); + NANDFS_WRITELOCK(vp, node->nn_nandfsdev); + blocksize = fsdev->nd_blocksize; file_size = node->nn_inode.i_size; @@ -217,6 +223,7 @@ nandfs_write(struct vop_write_args *ap) uio->uio_offset = file_size; break; case VDIR: + NANDFS_WRITEUNLOCK(node->nn_nandfsdev); return (EISDIR); case VLNK: break; @@ -288,6 +295,8 @@ nandfs_write(struct vop_write_args *ap) } } + NANDFS_WRITEUNLOCK(node->nn_nandfsdev); + DPRINTF(WRITE, ("%s: return:%d\n", __func__, error)); return (error); @@ -332,6 +341,9 @@ nandfs_lookup(struct vop_cachedlookup_ar if (islastcn && mounted_ro && (nameiop == DELETE || nameiop == RENAME)) return (EROFS); + if (dir_node->nn_inode.i_links_count == 0) + return (ENOENT); + /* * Obviously, the file is not (anymore) in the namecache, we have to * search for it. There are three basic cases: '.', '..' and others. @@ -579,9 +591,12 @@ nandfs_truncate(struct vnode *vp, uint64 /* Calculate end of file */ size = inode->i_size; + NANDFS_WRITELOCK(vp, node->nn_nandfsdev); + if (newsize == size) { node->nn_flags |= IN_CHANGE | IN_UPDATE; nandfs_itimes(vp); + NANDFS_WRITEUNLOCK(node->nn_nandfsdev); return (0); } @@ -590,6 +605,7 @@ nandfs_truncate(struct vnode *vp, uint64 vnode_pager_setsize(vp, newsize); node->nn_flags |= IN_CHANGE | IN_UPDATE; nandfs_itimes(vp); + NANDFS_WRITEUNLOCK(node->nn_nandfsdev); return (0); } @@ -599,8 +615,10 @@ nandfs_truncate(struct vnode *vp, uint64 if (rest) { error = nandfs_bmap_nlookup(node, nblks - 1, 1, &vblk); - if (error) + if (error) { + NANDFS_WRITEUNLOCK(node->nn_nandfsdev); return (error); + } if (vblk != 0) error = nandfs_bread(node, nblks - 1, NOCRED, 0, &bp); @@ -610,14 +628,17 @@ nandfs_truncate(struct vnode *vp, uint64 if (error) { if (bp) brelse(bp); + NANDFS_WRITEUNLOCK(node->nn_nandfsdev); return (error); } bzero((char *)bp->b_data + rest, (u_int)(nffsdev->nd_blocksize - rest)); error = nandfs_dirty_buf(bp, 0); - if (error) + if (error) { + NANDFS_WRITEUNLOCK(node->nn_nandfsdev); return (error); + } } DPRINTF(VNCALL, ("%s: vp %p oblks %jx nblks %jx\n", __func__, vp, oblks, @@ -627,6 +648,7 @@ nandfs_truncate(struct vnode *vp, uint64 if (error) { if (bp) nandfs_undirty_buf(bp); + NANDFS_WRITEUNLOCK(node->nn_nandfsdev); return (error); } @@ -634,6 +656,7 @@ nandfs_truncate(struct vnode *vp, uint64 if (error) { if (bp) nandfs_undirty_buf(bp); + NANDFS_WRITEUNLOCK(node->nn_nandfsdev); return (error); } @@ -642,6 +665,8 @@ nandfs_truncate(struct vnode *vp, uint64 node->nn_flags |= IN_CHANGE | IN_UPDATE; nandfs_itimes(vp); + NANDFS_WRITEUNLOCK(node->nn_nandfsdev); + return (error); } @@ -1068,7 +1093,7 @@ nandfs_read_filebuf(struct nandfs_node * struct nandfs_device *nandfsdev = node->nn_nandfsdev; struct buf *nbp; nandfs_daddr_t *l2vmap; - uint64_t *v2pmap; + nandfs_daddr_t *v2pmap; nandfs_lbn_t from; uint64_t blks; uint32_t blocksize; @@ -1375,6 +1400,8 @@ nandfs_link(struct vop_link_args *ap) /* Update link count */ inode->i_links_count++; + NANDFS_WRITELOCK(vp, node->nn_nandfsdev); + /* Add dir entry */ error = nandfs_add_dirent(tdvp, node->nn_ino, cnp->cn_nameptr, cnp->cn_namelen, IFTODT(inode->i_mode)); @@ -1387,6 +1414,8 @@ nandfs_link(struct vop_link_args *ap) DPRINTF(VNCALL, ("%s: tdvp %p vp %p cnp %p\n", __func__, tdvp, vp, cnp)); + NANDFS_WRITEUNLOCK(node->nn_nandfsdev); + return (0); } @@ -1407,6 +1436,8 @@ nandfs_create(struct vop_create_args *ap if (nandfs_fs_full(dir_node->nn_nandfsdev)) return (ENOSPC); + NANDFS_WRITELOCK(dvp, nmp->nm_nandfsdev); + /* Create new vnode/inode */ error = nandfs_node_create(nmp, &node, mode); if (error) @@ -1422,10 +1453,13 @@ nandfs_create(struct vop_create_args *ap nandfs_error("%s: error destroying node %p\n", __func__, node); } + NANDFS_WRITEUNLOCK(nmp->nm_nandfsdev); return (error); } *vpp = NTOV(node); + NANDFS_WRITEUNLOCK(nmp->nm_nandfsdev); + DPRINTF(VNCALL, ("created file vp %p nandnode %p ino %jx\n", *vpp, node, (uintmax_t)node->nn_ino)); return (0); @@ -1452,10 +1486,14 @@ nandfs_remove(struct vop_remove_args *ap (dnode->nn_inode.i_flags & APPEND)) return (EPERM); + NANDFS_WRITELOCK(vp, node->nn_nandfsdev); + nandfs_remove_dirent(dvp, node, cnp); node->nn_inode.i_links_count--; node->nn_flags |= IN_CHANGE; + NANDFS_WRITEUNLOCK(node->nn_nandfsdev); + return (0); } @@ -1543,6 +1581,9 @@ nandfs_rename(struct vop_rename_args *ap DPRINTF(VNCALL, ("%s: fdvp:%p fvp:%p tdvp:%p tdp:%p\n", __func__, fdvp, fvp, tdvp, tvp)); + + NANDFS_WRITELOCK(tdvp, tdnode->nn_nandfsdev); + /* * Check for cross-device rename. */ @@ -1558,6 +1599,7 @@ abortit: vput(tvp); vrele(fdvp); vrele(fvp); + NANDFS_WRITEUNLOCK(tdnode->nn_nandfsdev); return (error); } @@ -1763,6 +1805,7 @@ abortit: if (doingdirectory) panic("nandfs_rename: lost dir entry"); vrele(ap->a_fvp); + NANDFS_WRITEUNLOCK(tdnode->nn_nandfsdev); return (0); } @@ -1810,6 +1853,7 @@ abortit: if (fnode) vput(fvp); vrele(ap->a_fvp); + NANDFS_WRITEUNLOCK(tdnode->nn_nandfsdev); return (error); bad: @@ -1827,6 +1871,7 @@ out: vput(fvp); } else vrele(fvp); + NANDFS_WRITEUNLOCK(tdnode->nn_nandfsdev); return (error); } @@ -1851,9 +1896,14 @@ nandfs_mkdir(struct vop_mkdir_args *ap) if (dir_inode->i_links_count >= LINK_MAX) return (EMLINK); + NANDFS_WRITELOCK(dvp, nmp->nm_nandfsdev); + error = nandfs_node_create(nmp, &node, mode); - if (error) + if (error) { + NANDFS_WRITEUNLOCK(nmp->nm_nandfsdev); return (error); + } + node->nn_inode.i_gid = dir_node->nn_inode.i_gid; node->nn_inode.i_uid = cnp->cn_cred->cr_uid; @@ -1863,6 +1913,7 @@ nandfs_mkdir(struct vop_mkdir_args *ap) cnp->cn_namelen, IFTODT(mode)); if (error) { vput(*vpp); + NANDFS_WRITEUNLOCK(nmp->nm_nandfsdev); return (error); } @@ -1872,9 +1923,12 @@ nandfs_mkdir(struct vop_mkdir_args *ap) error = nandfs_init_dir(NTOV(node), node->nn_ino, dir_node->nn_ino); if (error) { vput(NTOV(node)); + NANDFS_WRITEUNLOCK(nmp->nm_nandfsdev); return (error); } + NANDFS_WRITEUNLOCK(nmp->nm_nandfsdev); + DPRINTF(VNCALL, ("created dir vp %p nandnode %p ino %jx\n", *vpp, node, (uintmax_t)node->nn_ino)); return (0); @@ -1896,9 +1950,13 @@ nandfs_mknod(struct vop_mknod_args *ap) if (nandfs_fs_full(dir_node->nn_nandfsdev)) return (ENOSPC); + NANDFS_WRITELOCK(dvp, nmp->nm_nandfsdev); + error = nandfs_node_create(nmp, &node, mode); - if (error) + if (error) { + NANDFS_WRITEUNLOCK(nmp->nm_nandfsdev); return (error); + } node->nn_inode.i_gid = dir_node->nn_inode.i_gid; node->nn_inode.i_uid = cnp->cn_cred->cr_uid; if (vap->va_rdev != VNOVAL) @@ -1909,11 +1967,14 @@ nandfs_mknod(struct vop_mknod_args *ap) if (nandfs_add_dirent(dvp, node->nn_ino, cnp->cn_nameptr, cnp->cn_namelen, IFTODT(mode))) { vput(*vpp); + NANDFS_WRITEUNLOCK(nmp->nm_nandfsdev); return (ENOTDIR); } node->nn_flags |= IN_ACCESS | IN_CHANGE | IN_UPDATE; + NANDFS_WRITEUNLOCK(nmp->nm_nandfsdev); + return (0); } @@ -1932,9 +1993,13 @@ nandfs_symlink(struct vop_symlink_args * if (nandfs_fs_full(dir_node->nn_nandfsdev)) return (ENOSPC); + NANDFS_WRITELOCK(dvp, nmp->nm_nandfsdev); + error = nandfs_node_create(nmp, &node, S_IFLNK | mode); - if (error) + if (error) { + NANDFS_WRITEUNLOCK(nmp->nm_nandfsdev); return (error); + } node->nn_inode.i_gid = dir_node->nn_inode.i_gid; node->nn_inode.i_uid = cnp->cn_cred->cr_uid; @@ -1943,6 +2008,7 @@ nandfs_symlink(struct vop_symlink_args * if (nandfs_add_dirent(dvp, node->nn_ino, cnp->cn_nameptr, cnp->cn_namelen, IFTODT(mode))) { vput(*vpp); + NANDFS_WRITEUNLOCK(nmp->nm_nandfsdev); return (ENOTDIR); } @@ -1954,6 +2020,8 @@ nandfs_symlink(struct vop_symlink_args * if (error) vput(*vpp); + NANDFS_WRITEUNLOCK(nmp->nm_nandfsdev); + return (error); } @@ -1973,6 +2041,7 @@ nandfs_rmdir(struct vop_rmdir_args *ap) struct componentname *cnp = ap->a_cnp; struct nandfs_node *node, *dnode; uint32_t dflag, flag; + int error = 0; node = VTON(vp); dnode = VTON(dvp); @@ -2002,16 +2071,26 @@ nandfs_rmdir(struct vop_rmdir_args *ap) if (vp->v_mountedhere != 0) return (EINVAL); + NANDFS_WRITELOCK(vp, node->nn_nandfsdev); + nandfs_remove_dirent(dvp, node, cnp); dnode->nn_inode.i_links_count -= 1; dnode->nn_flags |= IN_CHANGE; cache_purge(dvp); + error = nandfs_truncate(vp, (uint64_t)0); + if (error) + return (error); + node->nn_inode.i_links_count -= 2; node->nn_flags |= IN_CHANGE; - return (0); + NANDFS_WRITEUNLOCK(node->nn_nandfsdev); + + cache_purge(vp); + + return (error); } static int @@ -2032,9 +2111,7 @@ nandfs_fsync(struct vop_fsync_args *ap) vp->v_bufobj.bo_dirty.bv_cnt) { locked = VOP_ISLOCKED(vp); VOP_UNLOCK(vp, 0); - vn_finished_write(nmp->nm_vfs_mountp); nandfs_wakeup_wait_sync(nmp->nm_nandfsdev, SYNCER_FSYNC); - vn_start_write(NULL, &nmp->nm_vfs_mountp, V_WAIT); VOP_LOCK(vp, locked); } @@ -2047,7 +2124,7 @@ nandfs_bmap(struct vop_bmap_args *ap) struct vnode *vp = ap->a_vp; struct nandfs_node *nnode = VTON(vp); struct nandfs_device *nandfsdev = nnode->nn_nandfsdev; - uint64_t l2vmap, v2pmap; + nandfs_daddr_t l2vmap, v2pmap; *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***