/* $NetBSD$ */ /*- * Copyright (c) 2014 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation * by Taylor R Campbell. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /* * XXX NOTE NOTE NOTE XXX * * This code does not actually work. It is a draft of an idea. It * probably won't even compile, even if you make it include the right * header files. */ /* * Example use of vinotab. */ int ffs_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l) { ... ump->um_vinotab = vinotab_create(); ... } int ffs_unmount(struct mount *mp, int mntflags) { ... vinotab_destroy(ump->um_vinotab); ... } int ffs_vget(struct mount *mp, ino_t ino, struct vnode *vpp) { struct ufsmount *const ump = VFSTOUFS(mp); struct vnode *vp = NULL, *vp0 = NULL; static const struct inode zero_inode; struct inode *ip; int error; /* * Try to get an existing vnode for this inode number. */ error = vinotab_get(ump->um_vinotab, &ino, sizeof(ino_t), VWAIT_INTR, &vp); KASSERT((error == 0) == (vp != NULL)); if (error != ENOENT) goto out; /* * Create a new vnode for it instead. */ error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, NULL, &vp); KASSERT((error == 0) == (vp != NULL)); if (error) goto out; /* * Create an inode structure for it and fill it in just enough * for a lookup. */ ip = pool_cache_get(ffs_inode_cache, PR_WAITOK); KASSERT(ip != NULL); *ip = zero_inode; ip->i_number = ino; /* * Try to put this vnode in the table for the inode number. If * someone else beat us to it, release ours and use theirs * instead. */ error = vinotab_intern(ump->um_vinotab, &ip->i_vinoent, &ip->i_number, sizeof(ino_t), vp, VWAIT_INTR, &vp0); KASSERT((error == 0) == (vp0 != NULL)); if (vp0 != vp) { ungetnewvnode(vp); pool_cache_put(ffs_inode_cache, ip); vp = vp0; goto out; } /* * Set up the vnode and inode data structures. */ ufs_vcreate(mp, vp, ip, &ffs_genfsops); /* * Load the inode from disk. */ error = bread(ump->um_devvp, FFS_FSBTODB(ump->um_fs, ino_to_fsba(ump->um_fs, ino)), (int)ump->um_fs->fs_bsize, NOCRED, 0, &bp); if (error) { ufs_vdestroy(vp); ungetnewvnode(vp); pool_cache_put(ffs_inode_cache, ip); vp = NULL; goto out; } if (ip->i_ump->um_fstype == UFS1) ip->i_din.ffs1_din = pool_cache_get(ffs_dinode1_cache, PR_WAITOK); else ip->i_din.ffs2_din = pool_cache_get(ffs_dinode2_cache, PR_WAITOK); ffs_load_inode(bp, ip, ump->um_fs, ino); brelse(bp, 0); /* * Initialize the vnode type &c. from the loaded inode. */ ufs_vinit(mp, ffs_specop_p, ffs_fifoop_p, vp); /* * Ensure that uid and gid are correct. This is a temporary * fix until fsck has been changed to do the update. * * XXX That comment has been there since 1994. `Temporary' * indeed. */ if (fs->fs_old_inodefmt < FS_44INODEFMT) { /* XXX */ ip->i_uid = ip->i_ffs1_ouid; /* XXX */ ip->i_gid = ip->i_ffs1_ogid; /* XXX */ } /* * Set the uvm size from the inode size. */ uvm_vnp_setsize(vp, ip->i_size); /* * All set. Mark it ready to go and wake anyone waiting. */ vready(vp); error = 0; out: *vpp = vp; return error; } /* * ufs_vcreate: Set up a new vnode vp on ufs mount mp with inode ip. * * Caller must have set ip->i_vnode to vp and initialized ip->i_number. */ void ufs_vcreate(struct mount *mp, struct vnode *vp, struct inode *ip, struct genfs_ops *gops) { KASSERT(ip->i_vnode == vp); vp->v_data = ip; genfs_node_init(vp, gops); ip->i_ump = ump; ip->i_fs = ump->um_fs; ip->i_dev = dev; ip->i_devvp = ump->um_devvp; vref(ip->i_devvp); #if defined(QUOTA) || defined(QUOTA2) ufsquota_init(ip); #endif } /* * ufs_vdestroy: Reverse of ufs_vcreate. */ void ufs_vdestroy(struct vnode *vp) { struct inode *ip = VTOI(vp); #if defined(QUOTA) || defined(QUOTA2) ufsquota_free(ip); #endif vrele(ip->i_devvp); ip->i_devvp = NULL; genfs_node_destroy(vp); vp->v_data = NULL; } int ffs_reclaim(void *v) { struct vop_reclaim_args /* { struct vnode *a_vp; } */ *ap = v; struct vnode *vp = ap->a_vp; struct inode *ip = VTOI(vp); struct mount *mp = vp->v_mount; struct ufsmount *ump = VFSTOUFS(mp); int error; fstrans_start(mp, FSTRANS_LAZY); error = UFS_WAPBL_BEGIN(mp); if (error) goto destroy; if ((ip->i_nlink <= 0) && (ip->i_omode != 0) && !ISSET(mp->mnt_flag, MNT_RDONLY)) ffs_vfree(vp, ip->i_number, ip->i_omode); UFS_WAPBL_END(mp); /* * The double call to UFS_UPDATE here is cargo-culted from the * old ffs_reclaim. Ask simonb. */ error = UFS_WAPBL_BEGIN(mp); UFS_UPDATE(vp, NULL, NULL, UPDATE_CLOSE); if (error) goto destroy; UFS_WAPBL_END(mp); UFS_UPDATE(vp, NULL, NULL, UPDATE_CLOSE); destroy: fstrans_done(mp); if (error) { printf("ffs: unable to clean inode %"PRIuMAX"\n", (uintmax_t)ip->i_number); vprint(NULL, vp); } vinotab_remove(ump->um_vinotab, &ip->i_vinoent); if (ump->um_fstype == UFS1) pool_cache_put(ffs_dinode1_cache, ip->i_din.ffs1_din); else pool_cache_put(ffs_dinode2_cache, ip->i_din.ffs2_din); ufs_vdestroy(vp); pool_cache_put(ffs_inode_cache, ip); return 0; }