diff --git a/sys/conf/files b/sys/conf/files index e7f520a6430c..2fb96e87e17f 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -732,6 +732,8 @@ geom/geom_sunlabel.c optional geom gnu/ext2fs/ext2_alloc.c optional ext2fs \ warning "kernel contains GPL contaminated ext2fs file system" gnu/ext2fs/ext2_balloc.c optional ext2fs +gnu/ext2fs/ext2_bmap.c optional ext2fs +gnu/ext2fs/ext2_ihash.c optional ext2fs gnu/ext2fs/ext2_inode.c optional ext2fs gnu/ext2fs/ext2_inode_cnv.c optional ext2fs gnu/ext2fs/ext2_linux_balloc.c optional ext2fs diff --git a/sys/gnu/ext2fs/ext2_alloc.c b/sys/gnu/ext2fs/ext2_alloc.c index b9c40d37b9e1..585c5cdb4632 100644 --- a/sys/gnu/ext2fs/ext2_alloc.c +++ b/sys/gnu/ext2fs/ext2_alloc.c @@ -40,8 +40,6 @@ * $FreeBSD$ */ -#include "opt_quota.h" - #include <sys/param.h> #include <sys/systm.h> #include <sys/conf.h> @@ -50,11 +48,8 @@ #include <sys/mount.h> #include <sys/syslog.h> -#include <ufs/ufs/extattr.h> -#include <ufs/ufs/quota.h> -#include <ufs/ufs/inode.h> -#include <ufs/ufs/ufsmount.h> - +#include <gnu/ext2fs/inode.h> +#include <gnu/ext2fs/ext2_mount.h> #include <gnu/ext2fs/ext2_fs.h> #include <gnu/ext2fs/ext2_fs_sb.h> #include <gnu/ext2fs/fs.h> @@ -108,9 +103,6 @@ ext2_alloc(ip, lbn, bpref, size, cred, bnp) { register struct ext2_sb_info *fs; daddr_t bno; -#if QUOTA - int error; -#endif *bnp = 0; fs = ip->i_e2fs; @@ -128,10 +120,6 @@ ext2_alloc(ip, lbn, bpref, size, cred, bnp) if (cred->cr_uid != 0 && fs->s_es->s_free_blocks_count < fs->s_es->s_r_blocks_count) goto nospace; -#if QUOTA - if ((error = chkdq(ip, (long)btodb(size), cred, 0)) != 0) - return (error); -#endif if (bpref >= fs->s_es->s_blocks_count) bpref = 0; /* call the Linux code */ @@ -179,12 +167,6 @@ ext2_alloc(ip, lbn, bpref, size, cred, bnp) *bnp = bno; return (0); } -#if QUOTA - /* - * Restore user's disk quota because allocation failed. - */ - (void) chkdq(ip, (long)-btodb(size), cred, FORCE); -#endif nospace: ext2_fserr(fs, cred->cr_uid, "file system full"); uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt); @@ -342,7 +324,7 @@ return ENOSPC; } else { ip->i_flag |= IN_CHANGE | IN_UPDATE; if (!doasyncfree) - UFS_UPDATE(vp, 1); + ext2_update(vp, 1); } if (ssize < len) if (doasyncfree) @@ -401,7 +383,7 @@ ext2_valloc(pvp, mode, cred, vpp) goto noinodes; error = VFS_VGET(pvp->v_mount, ino, LK_EXCLUSIVE, vpp); if (error) { - UFS_VFREE(pvp, ino, mode); + ext2_vfree(pvp, ino, mode); return (error); } ip = VTOI(*vpp); diff --git a/sys/gnu/ext2fs/ext2_balloc.c b/sys/gnu/ext2fs/ext2_balloc.c index 275849fcec52..252a29792527 100644 --- a/sys/gnu/ext2fs/ext2_balloc.c +++ b/sys/gnu/ext2fs/ext2_balloc.c @@ -48,10 +48,7 @@ #include <sys/ucred.h> #include <sys/vnode.h> -#include <ufs/ufs/quota.h> -#include <ufs/ufs/inode.h> -#include <ufs/ufs/ufs_extern.h> - +#include <gnu/ext2fs/inode.h> #include <gnu/ext2fs/ext2_fs.h> #include <gnu/ext2fs/ext2_fs_sb.h> #include <gnu/ext2fs/fs.h> @@ -164,11 +161,11 @@ ext2_debug("ext2_balloc called (%d, %d, %d)\n", * Determine the number of levels of indirection. */ pref = 0; - if ((error = ufs_getlbns(vp, bn, indirs, &num)) != 0) + if ((error = ext2_getlbns(vp, bn, indirs, &num)) != 0) return(error); #if DIAGNOSTIC if (num < 1) - panic ("ext2_balloc: ufs_getlbns returned indirect block"); + panic ("ext2_balloc: ext2_getlbns returned indirect block"); #endif /* * Fetch the first indirect block allocating if necessary. diff --git a/sys/gnu/ext2fs/ext2_extern.h b/sys/gnu/ext2fs/ext2_extern.h index 8df829b369a7..505fefd97c56 100644 --- a/sys/gnu/ext2fs/ext2_extern.h +++ b/sys/gnu/ext2fs/ext2_extern.h @@ -43,8 +43,8 @@ #ifndef _SYS_GNU_EXT2FS_EXT2_EXTERN_H_ #define _SYS_GNU_EXT2FS_EXT2_EXTERN_H_ -struct dinode; struct ext2_inode; +struct indir; struct inode; struct mount; struct vfsconf; @@ -58,7 +58,18 @@ int ext2_blkatoff(struct vnode *, off_t, char **, struct buf **); void ext2_blkfree(struct inode *, daddr_t, long); daddr_t ext2_blkpref(struct inode *, daddr_t, int, daddr_t *, daddr_t); int ext2_bmap(struct vop_bmap_args *); -int ext2_init(struct vfsconf *); +int ext2_bmaparray(struct vnode *, daddr_t, daddr_t *, int *, int *); +void ext2_dirbad(struct inode *ip, doff_t offset, char *how); +void ext2_ei2i(struct ext2_inode *, struct inode *); +int ext2_getlbns(struct vnode *, daddr_t, struct indir *, int *); +void ext2_i2ei(struct inode *, struct ext2_inode *); +int ext2_ihashget(dev_t, ino_t, int, struct vnode **); +void ext2_ihashinit(void); +void ext2_ihashins(struct inode *); +struct vnode * + ext2_ihashlookup(dev_t, ino_t); +void ext2_ihashrem(struct inode *); +void ext2_itimes(struct vnode *vp); int ext2_reallocblks(struct vop_reallocblks_args *); int ext2_reclaim(struct vop_reclaim_args *); void ext2_setblock(struct ext2_sb_info *, u_char *, daddr_t); @@ -66,9 +77,9 @@ int ext2_truncate(struct vnode *, off_t, int, struct ucred *, struct thread *); int ext2_update(struct vnode *, int); int ext2_valloc(struct vnode *, int, struct ucred *, struct vnode **); int ext2_vfree(struct vnode *, ino_t, int); +int ext2_vinit(struct mount *, vop_t **, vop_t **, struct vnode **vpp); int ext2_lookup(struct vop_cachedlookup_args *); int ext2_readdir(struct vop_readdir_args *); -void ext2_print_dinode(struct dinode *); void ext2_print_inode(struct inode *); int ext2_direnter(struct inode *, struct vnode *, struct componentname *); @@ -89,15 +100,13 @@ unsigned long ext2_count_free(struct buf *map, unsigned int numchars); void ext2_free_blocks(struct mount *mp, unsigned long block, unsigned long count); void ext2_free_inode(struct inode * inode); -void ext2_ei2di(struct ext2_inode *ei, struct dinode *di); -void ext2_di2ei(struct dinode *di, struct ext2_inode *ei); void mark_buffer_dirty(struct buf *bh); -/* - * This macro allows the ufs code to distinguish between an EXT2 and a - * non-ext2(FFS/LFS) vnode. - */ -#define IS_EXT2_VNODE(vp) (vp->v_mount->mnt_stat.f_type == MOUNT_EXT2FS) +/* Flags to low-level allocation routines. */ +#define B_CLRBUF 0x01 /* Request allocated buffer be cleared. */ +#define B_SYNC 0x02 /* Do all allocations synchronously. */ +#define B_METAONLY 0x04 /* Return indirect block buffer. */ +#define B_NOWAIT 0x08 /* do not sleep to await lock */ extern vop_t **ext2_vnodeop_p; extern vop_t **ext2_specop_p; diff --git a/sys/gnu/ext2fs/ext2_fs.h b/sys/gnu/ext2fs/ext2_fs.h index b5e9f4a92573..29435937181b 100644 --- a/sys/gnu/ext2fs/ext2_fs.h +++ b/sys/gnu/ext2fs/ext2_fs.h @@ -38,19 +38,6 @@ #define umode_t mode_t #define loff_t off_t -/* the Linux implementation of EXT2 stores some information about - * an inode in a ext2_inode_info structure which is part of the incore - * inode in Linux - * I decided to use the "spare" fields instead - we'll see how this - * works out - */ - -#define i_block_group i_spare[0] -#define i_next_alloc_block i_spare[1] -#define i_next_alloc_goal i_spare[2] -#define i_prealloc_block i_din.di_spare[0] -#define i_prealloc_count i_din.di_spare[1] - /* * The second extended filesystem constants/structures */ @@ -263,14 +250,6 @@ struct ext2_group_desc #define EXT2_IOC_GETVERSION _IOR('v', 1, long) #define EXT2_IOC_SETVERSION _IOW('v', 2, long) -/* - * Only declare `struct ext2_inode' if <ufs/ufs/inode.h> hasn't made things - * difficult by #defining i_mode and other struct members. The details of - * the struct are only needed in ext2_inode_cnv.c where the ext2fs on-disk - * inode is converted to a ufs in-core inode. - */ -#ifndef i_mode - /* * Structure of an inode on the disk */ @@ -351,8 +330,6 @@ struct ext2_inode { #define i_reserved2 osd2.masix2.m_i_reserved2 #endif -#endif /* i_mode */ - /* * File system states */ diff --git a/sys/gnu/ext2fs/ext2_inode.c b/sys/gnu/ext2fs/ext2_inode.c index 2f0aed472f09..207778c84f88 100644 --- a/sys/gnu/ext2fs/ext2_inode.c +++ b/sys/gnu/ext2fs/ext2_inode.c @@ -40,8 +40,6 @@ * $FreeBSD$ */ -#include "opt_quota.h" - #include <sys/param.h> #include <sys/systm.h> #include <sys/mount.h> @@ -53,12 +51,8 @@ #include <vm/vm.h> #include <vm/vm_extern.h> -#include <ufs/ufs/extattr.h> -#include <ufs/ufs/quota.h> -#include <ufs/ufs/inode.h> -#include <ufs/ufs/ufsmount.h> -#include <ufs/ufs/ufs_extern.h> - +#include <gnu/ext2fs/inode.h> +#include <gnu/ext2fs/ext2_mount.h> #include <gnu/ext2fs/ext2_fs.h> #include <gnu/ext2fs/ext2_fs_sb.h> #include <gnu/ext2fs/fs.h> @@ -67,12 +61,6 @@ static int ext2_indirtrunc(struct inode *, daddr_t, daddr_t, daddr_t, int, long *); -int -ext2_init(struct vfsconf *vfsp) -{ - return (ufs_init(vfsp)); -} - /* * Update the access, modified, and inode change times as specified by the * IN_ACCESS, IN_UPDATE, and IN_CHANGE flags respectively. Write the inode @@ -92,7 +80,7 @@ ext2_update(vp, waitfor) struct inode *ip; int error; - ufs_itimes(vp); + ext2_itimes(vp); ip = VTOI(vp); if ((ip->i_flag & IN_MODIFIED) == 0) return (0); @@ -106,8 +94,8 @@ ext2_update(vp, waitfor) brelse(bp); return (error); } - ext2_di2ei( &ip->i_din, (struct ext2_inode *) ((char *)bp->b_data + EXT2_INODE_SIZE * - ino_to_fsbo(fs, ip->i_number))); + ext2_i2ei(ip, (struct ext2_inode *)((char *)bp->b_data + + EXT2_INODE_SIZE * ino_to_fsbo(fs, ip->i_number))); /* if (waitfor && (vp->v_mount->mnt_flag & MNT_ASYNC) == 0) return (bwrite(bp)); @@ -166,16 +154,12 @@ printf("ext2_truncate called %d to %d\n", VTOI(ovp)->i_number, length); bzero((char *)&oip->i_shortlink, (u_int)oip->i_size); oip->i_size = 0; oip->i_flag |= IN_CHANGE | IN_UPDATE; - return (UFS_UPDATE(ovp, 1)); + return (ext2_update(ovp, 1)); } if (oip->i_size == length) { oip->i_flag |= IN_CHANGE | IN_UPDATE; - return (UFS_UPDATE(ovp, 0)); + return (ext2_update(ovp, 0)); } -#if QUOTA - if ((error = getinoquota(oip)) != 0) - return (error); -#endif fs = oip->i_e2fs; osize = oip->i_size; ext2_discard_prealloc(oip); @@ -200,7 +184,7 @@ printf("ext2_truncate called %d to %d\n", VTOI(ovp)->i_number, length); else bawrite(bp); oip->i_flag |= IN_CHANGE | IN_UPDATE; - return (UFS_UPDATE(ovp, 1)); + return (ext2_update(ovp, 1)); } /* * Shorten the size of the file. If the file is not being @@ -256,7 +240,7 @@ printf("ext2_truncate called %d to %d\n", VTOI(ovp)->i_number, length); for (i = NDADDR - 1; i > lastblock; i--) oip->i_db[i] = 0; oip->i_flag |= IN_CHANGE | IN_UPDATE; - allerror = UFS_UPDATE(ovp, 1); + allerror = ext2_update(ovp, 1); /* * Having written the new inode to disk, save its new configuration @@ -361,9 +345,6 @@ done: oip->i_blocks = 0; oip->i_flag |= IN_CHANGE; vnode_pager_setsize(ovp, length); -#if QUOTA - (void) chkdq(oip, -blocksreleased, NOCRED, 0); -#endif return (allerror); } @@ -488,9 +469,86 @@ int ext2_inactive(ap) struct vop_inactive_args /* { struct vnode *a_vp; + struct thread *a_td; } */ *ap; { - ext2_discard_prealloc(VTOI(ap->a_vp)); - return ufs_inactive(ap); + struct vnode *vp = ap->a_vp; + struct inode *ip = VTOI(vp); + struct thread *td = ap->a_td; + int mode, error = 0; + + ext2_discard_prealloc(ip); + if (prtactive && vp->v_usecount != 0) + vprint("ext2_inactive: pushing active", vp); + + /* + * Ignore inodes related to stale file handles. + */ + if (ip->i_mode == 0) + goto out; + if (ip->i_nlink <= 0) { + (void) vn_write_suspend_wait(vp, NULL, V_WAIT); + error = ext2_truncate(vp, (off_t)0, 0, NOCRED, td); + ip->i_rdev = 0; + mode = ip->i_mode; + ip->i_mode = 0; + ip->i_flag |= IN_CHANGE | IN_UPDATE; + ext2_vfree(vp, ip->i_number, mode); + } + if (ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) { + if ((ip->i_flag & (IN_CHANGE | IN_UPDATE | IN_MODIFIED)) == 0 && + vn_write_suspend_wait(vp, NULL, V_NOWAIT)) { + ip->i_flag &= ~IN_ACCESS; + } else { + (void) vn_write_suspend_wait(vp, NULL, V_WAIT); + ext2_update(vp, 0); + } + } +out: + VOP_UNLOCK(vp, 0, td); + /* + * If we are done with the inode, reclaim it + * so that it can be reused immediately. + */ + if (ip->i_mode == 0) + vrecycle(vp, NULL, td); + return (error); } +/* + * Reclaim an inode so that it can be used for other purposes. + */ +int +ext2_reclaim(ap) + struct vop_reclaim_args /* { + struct vnode *a_vp; + struct thread *a_td; + } */ *ap; +{ + struct inode *ip; + struct vnode *vp = ap->a_vp; + + if (prtactive && vp->v_usecount != 0) + vprint("ufs_reclaim: pushing active", vp); + ip = VTOI(vp); + if (ip->i_flag & IN_LAZYMOD) { + ip->i_flag |= IN_MODIFIED; + ext2_update(vp, 0); + } + /* + * Remove the inode from its hash chain. + */ + ext2_ihashrem(ip); + /* + * Purge old data structures associated with the inode. + */ + cache_purge(vp); + if (ip->i_devvp) { + vrele(ip->i_devvp); + ip->i_devvp = 0; + } + lockdestroy(&vp->v_lock); + FREE(vp->v_data, M_EXT2NODE); + vp->v_data = 0; + return (0); +} diff --git a/sys/gnu/ext2fs/ext2_inode_cnv.c b/sys/gnu/ext2fs/ext2_inode_cnv.c index 3e8e0ff73445..d64e5498776b 100644 --- a/sys/gnu/ext2fs/ext2_inode_cnv.c +++ b/sys/gnu/ext2fs/ext2_inode_cnv.c @@ -23,7 +23,7 @@ */ /* - * routines to convert on disk ext2 inodes in dinodes and back + * routines to convert on disk ext2 inodes into inodes and back */ #include <sys/param.h> #include <sys/systm.h> @@ -31,130 +31,101 @@ #include <sys/stat.h> #include <sys/vnode.h> -#include <ufs/ufs/quota.h> -#include <ufs/ufs/inode.h> - -/* - * Undo the definitions in <ufs/ufs/inode.h> that would destroy the include - * of <gnu/ext2fs/ext2_fs.h>. - */ -#undef i_atime -#undef i_blocks -#undef i_ctime -#undef i_db -#undef i_flags -#undef i_gen -#undef i_gid -#undef i_ib -#undef i_mode -#undef i_mtime -#undef i_nlink -#undef i_rdev -#undef i_shortlink -#undef i_size -#undef i_uid - +#include <gnu/ext2fs/inode.h> #include <gnu/ext2fs/ext2_fs.h> #include <gnu/ext2fs/ext2_extern.h> -void -ext2_print_dinode( di ) - struct dinode *di; -{ - int i; - printf( /* "Inode: %5d" */ - " Type: %10s Mode: 0x%o Flags: 0x%x Version: %d\n", - "n/a", di->di_mode, di->di_flags, di->di_gen); - printf( "User: %5lu Group: %5lu Size: %lu\n", - (unsigned long)di->di_uid, (unsigned long)di->di_gid, - (unsigned long)di->di_size); - printf( "Links: %3d Blockcount: %d\n", - di->di_nlink, di->di_blocks); - printf( "ctime: 0x%x", di->di_ctime); - printf( "atime: 0x%x", di->di_atime); - printf( "mtime: 0x%x", di->di_mtime); - printf( "BLOCKS: "); - for(i=0; i < (di->di_blocks <= 24 ? ((di->di_blocks+1)/2): 12); i++) - printf("%d ", di->di_db[i]); - printf("\n"); -} - void ext2_print_inode( in ) struct inode *in; { + int i; + printf( "Inode: %5d", in->i_number); - ext2_print_dinode(&in->i_din); + printf( /* "Inode: %5d" */ + " Type: %10s Mode: 0x%o Flags: 0x%x Version: %d\n", + "n/a", in->i_mode, in->i_flags, in->i_gen); + printf( "User: %5lu Group: %5lu Size: %lu\n", + (unsigned long)in->i_uid, (unsigned long)in->i_gid, + (unsigned long)in->i_size); + printf( "Links: %3d Blockcount: %d\n", + in->i_nlink, in->i_blocks); + printf( "ctime: 0x%x", in->i_ctime); + printf( "atime: 0x%x", in->i_atime); + printf( "mtime: 0x%x", in->i_mtime); + printf( "BLOCKS: "); + for(i=0; i < (in->i_blocks <= 24 ? ((in->i_blocks+1)/2): 12); i++) + printf("%d ", in->i_db[i]); + printf("\n"); } /* - * raw ext2 inode to dinode + * raw ext2 inode to inode */ void -ext2_ei2di(ei, di) - struct ext2_inode *ei; - struct dinode *di; +ext2_ei2i(ei, ip) + struct ext2_inode *ei; + struct inode *ip; { - int i; + int i; - di->di_nlink = ei->i_links_count; + ip->i_nlink = ei->i_links_count; /* Godmar thinks - if the link count is zero, then the inode is unused - according to ext2 standards. Ufs marks this fact by setting i_mode to zero - why ? I can see that this might lead to problems in an undelete. */ - di->di_mode = ei->i_links_count ? ei->i_mode : 0; - di->di_size = ei->i_size; - di->di_atime = ei->i_atime; - di->di_mtime = ei->i_mtime; - di->di_ctime = ei->i_ctime; - di->di_flags = 0; - di->di_flags |= (ei->i_flags & EXT2_APPEND_FL) ? APPEND : 0; - di->di_flags |= (ei->i_flags & EXT2_IMMUTABLE_FL) ? IMMUTABLE : 0; - di->di_blocks = ei->i_blocks; - di->di_gen = ei->i_generation; - di->di_uid = ei->i_uid; - di->di_gid = ei->i_gid; + ip->i_mode = ei->i_links_count ? ei->i_mode : 0; + ip->i_size = ei->i_size; + ip->i_atime = ei->i_atime; + ip->i_mtime = ei->i_mtime; + ip->i_ctime = ei->i_ctime; + ip->i_flags = 0; + ip->i_flags |= (ei->i_flags & EXT2_APPEND_FL) ? APPEND : 0; + ip->i_flags |= (ei->i_flags & EXT2_IMMUTABLE_FL) ? IMMUTABLE : 0; + ip->i_blocks = ei->i_blocks; + ip->i_gen = ei->i_generation; + ip->i_uid = ei->i_uid; + ip->i_gid = ei->i_gid; /* XXX use memcpy */ - for(i = 0; i < NDADDR; i++) - di->di_db[i] = ei->i_block[i]; - for(i = 0; i < NIADDR; i++) - di->di_ib[i] = ei->i_block[EXT2_NDIR_BLOCKS + i]; + for(i = 0; i < NDADDR; i++) + ip->i_db[i] = ei->i_block[i]; + for(i = 0; i < NIADDR; i++) + ip->i_ib[i] = ei->i_block[EXT2_NDIR_BLOCKS + i]; } /* - * dinode to raw ext2 inode + * inode to raw ext2 inode */ void -ext2_di2ei(di, ei) - struct dinode *di; - struct ext2_inode *ei; +ext2_i2ei(ip, ei) + struct inode *ip; + struct ext2_inode *ei; { - int i; + int i; - ei->i_mode = di->di_mode; - ei->i_links_count = di->di_nlink; + ei->i_mode = ip->i_mode; + ei->i_links_count = ip->i_nlink; /* Godmar thinks: if dtime is nonzero, ext2 says this inode has been deleted, this would correspond to a zero link count */ - ei->i_dtime = ei->i_links_count ? 0 : di->di_mtime; - ei->i_size = di->di_size; - ei->i_atime = di->di_atime; - ei->i_mtime = di->di_mtime; - ei->i_ctime = di->di_ctime; - ei->i_flags = di->di_flags; - ei->i_flags = 0; - ei->i_flags |= (di->di_flags & APPEND) ? EXT2_APPEND_FL: 0; - ei->i_flags |= (di->di_flags & IMMUTABLE) - ? EXT2_IMMUTABLE_FL: 0; - ei->i_blocks = di->di_blocks; - ei->i_generation = di->di_gen; - ei->i_uid = di->di_uid; - ei->i_gid = di->di_gid; + ei->i_dtime = ei->i_links_count ? 0 : ip->i_mtime; + ei->i_size = ip->i_size; + ei->i_atime = ip->i_atime; + ei->i_mtime = ip->i_mtime; + ei->i_ctime = ip->i_ctime; + ei->i_flags = ip->i_flags; + ei->i_flags = 0; + ei->i_flags |= (ip->i_flags & APPEND) ? EXT2_APPEND_FL: 0; + ei->i_flags |= (ip->i_flags & IMMUTABLE) ? EXT2_IMMUTABLE_FL: 0; + ei->i_blocks = ip->i_blocks; + ei->i_generation = ip->i_gen; + ei->i_uid = ip->i_uid; + ei->i_gid = ip->i_gid; /* XXX use memcpy */ - for(i = 0; i < NDADDR; i++) - ei->i_block[i] = di->di_db[i]; - for(i = 0; i < NIADDR; i++) - ei->i_block[EXT2_NDIR_BLOCKS + i] = di->di_ib[i]; + for(i = 0; i < NDADDR; i++) + ei->i_block[i] = ip->i_db[i]; + for(i = 0; i < NIADDR; i++) + ei->i_block[EXT2_NDIR_BLOCKS + i] = ip->i_ib[i]; } diff --git a/sys/gnu/ext2fs/ext2_linux_balloc.c b/sys/gnu/ext2fs/ext2_linux_balloc.c index fc723114dfa6..632044009643 100644 --- a/sys/gnu/ext2fs/ext2_linux_balloc.c +++ b/sys/gnu/ext2fs/ext2_linux_balloc.c @@ -35,9 +35,8 @@ #include <sys/mount.h> #include <sys/vnode.h> -#include <ufs/ufs/extattr.h> -#include <ufs/ufs/quota.h> -#include <ufs/ufs/ufsmount.h> +#include <gnu/ext2fs/inode.h> +#include <gnu/ext2fs/ext2_mount.h> #include <gnu/ext2fs/ext2_extern.h> #include <gnu/ext2fs/ext2_fs.h> #include <gnu/ext2fs/ext2_fs_sb.h> @@ -61,13 +60,13 @@ static void read_block_bitmap (struct mount * mp, unsigned int block_group, unsigned long bitmap_nr) { - struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs; + struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs; struct ext2_group_desc * gdp; struct buffer_head * bh; int error; gdp = get_group_desc (mp, block_group, NULL); - if ((error = bread (VFSTOUFS(mp)->um_devvp, + if ((error = bread (VFSTOEXT2(mp)->um_devvp, fsbtodb(sb, gdp->bg_block_bitmap),sb->s_blocksize, NOCRED, &bh)) != 0) panic ( "read_block_bitmap: " "Cannot read block bitmap - " @@ -93,7 +92,7 @@ static int load__block_bitmap (struct mount * mp, unsigned int block_group) { int i, j; - struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs; + struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs; unsigned long block_bitmap_number; struct buffer_head * block_bitmap; @@ -152,7 +151,7 @@ static int load__block_bitmap (struct mount * mp, static __inline int load_block_bitmap (struct mount * mp, unsigned int block_group) { - struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs; + struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs; if (sb->s_loaded_block_bitmaps > 0 && sb->s_block_bitmap_number[0] == block_group) return 0; @@ -168,7 +167,7 @@ static __inline int load_block_bitmap (struct mount * mp, void ext2_free_blocks (struct mount * mp, unsigned long block, unsigned long count) { - struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs; + struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs; struct buffer_head * bh; struct buffer_head * bh2; unsigned long block_group; @@ -182,13 +181,13 @@ void ext2_free_blocks (struct mount * mp, unsigned long block, printf ("ext2_free_blocks: nonexistent device"); return; } - lock_super (VFSTOUFS(mp)->um_devvp); + lock_super (VFSTOEXT2(mp)->um_devvp); if (block < es->s_first_data_block || (block + count) > es->s_blocks_count) { printf ( "ext2_free_blocks: " "Freeing blocks not in datazone - " "block = %lu, count = %lu", block, count); - unlock_super (VFSTOUFS(mp)->um_devvp); + unlock_super (VFSTOEXT2(mp)->um_devvp); return; } @@ -238,7 +237,7 @@ void ext2_free_blocks (struct mount * mp, unsigned long block, } ****/ sb->s_dirt = 1; - unlock_super (VFSTOUFS(mp)->um_devvp); + unlock_super (VFSTOEXT2(mp)->um_devvp); return; } @@ -253,7 +252,7 @@ int ext2_new_block (struct mount * mp, unsigned long goal, u_int32_t * prealloc_count, u_int32_t * prealloc_block) { - struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs; + struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs; struct buffer_head * bh; struct buffer_head * bh2; char * p, * r; @@ -269,7 +268,7 @@ int ext2_new_block (struct mount * mp, unsigned long goal, printf ("ext2_new_block: nonexistent device"); return 0; } - lock_super (VFSTOUFS(mp)->um_devvp); + lock_super (VFSTOEXT2(mp)->um_devvp); ext2_debug ("goal=%lu.\n", goal); @@ -356,7 +355,7 @@ repeat: break; } if (k >= sb->s_groups_count) { - unlock_super (VFSTOUFS(mp)->um_devvp); + unlock_super (VFSTOEXT2(mp)->um_devvp); return 0; } bitmap_nr = load_block_bitmap (mp, i); @@ -372,7 +371,7 @@ repeat: if (j >= EXT2_BLOCKS_PER_GROUP(sb)) { printf ( "ext2_new_block: " "Free blocks count corrupted for block group %d", i); - unlock_super (VFSTOUFS(mp)->um_devvp); + unlock_super (VFSTOEXT2(mp)->um_devvp); return 0; } @@ -439,7 +438,7 @@ got_block: printf ( "ext2_new_block: " "block >= blocks count - " "block_group = %d, block=%d", i, j); - unlock_super (VFSTOUFS(mp)->um_devvp); + unlock_super (VFSTOEXT2(mp)->um_devvp); return 0; } @@ -450,14 +449,14 @@ got_block: mark_buffer_dirty(bh2); es->s_free_blocks_count--; sb->s_dirt = 1; - unlock_super (VFSTOUFS(mp)->um_devvp); + unlock_super (VFSTOEXT2(mp)->um_devvp); return j; } #ifdef unused static unsigned long ext2_count_free_blocks (struct mount * mp) { - struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs; + struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs; #ifdef EXT2FS_DEBUG struct ext2_super_block * es; unsigned long desc_count, bitmap_count, x; @@ -465,7 +464,7 @@ static unsigned long ext2_count_free_blocks (struct mount * mp) struct ext2_group_desc * gdp; int i; - lock_super (VFSTOUFS(mp)->um_devvp); + lock_super (VFSTOEXT2(mp)->um_devvp); es = sb->s_es; desc_count = 0; bitmap_count = 0; @@ -482,7 +481,7 @@ static unsigned long ext2_count_free_blocks (struct mount * mp) } ext2_debug( "stored = %lu, computed = %lu, %lu\n", es->s_free_blocks_count, desc_count, bitmap_count); - unlock_super (VFSTOUFS(mp)->um_devvp); + unlock_super (VFSTOEXT2(mp)->um_devvp); return bitmap_count; #else return sb->s_es->s_free_blocks_count; @@ -520,7 +519,7 @@ int ext2_group_sparse(int group) #ifdef unused static void ext2_check_blocks_bitmap (struct mount * mp) { - struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs; + struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs; struct buffer_head * bh; struct ext2_super_block * es; unsigned long desc_count, bitmap_count, x; @@ -529,7 +528,7 @@ static void ext2_check_blocks_bitmap (struct mount * mp) struct ext2_group_desc * gdp; int i, j; - lock_super (VFSTOUFS(mp)->um_devvp); + lock_super (VFSTOEXT2(mp)->um_devvp); es = sb->s_es; desc_count = 0; bitmap_count = 0; @@ -586,7 +585,7 @@ static void ext2_check_blocks_bitmap (struct mount * mp) "Wrong free blocks count in super block, " "stored = %lu, counted = %lu", (unsigned long) es->s_free_blocks_count, bitmap_count); - unlock_super (VFSTOUFS(mp)->um_devvp); + unlock_super (VFSTOEXT2(mp)->um_devvp); } #endif /* unused */ diff --git a/sys/gnu/ext2fs/ext2_linux_ialloc.c b/sys/gnu/ext2fs/ext2_linux_ialloc.c index 01ae55b078dc..64d96b21104c 100644 --- a/sys/gnu/ext2fs/ext2_linux_ialloc.c +++ b/sys/gnu/ext2fs/ext2_linux_ialloc.c @@ -36,10 +36,8 @@ #include <sys/mount.h> #include <sys/vnode.h> -#include <ufs/ufs/extattr.h> -#include <ufs/ufs/quota.h> -#include <ufs/ufs/inode.h> -#include <ufs/ufs/ufsmount.h> +#include <gnu/ext2fs/inode.h> +#include <gnu/ext2fs/ext2_mount.h> #include <gnu/ext2fs/ext2_extern.h> #include <gnu/ext2fs/ext2_fs.h> #include <gnu/ext2fs/ext2_fs_sb.h> @@ -69,7 +67,7 @@ struct ext2_group_desc * get_group_desc (struct mount * mp, unsigned int block_group, struct buffer_head ** bh) { - struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs; + struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs; unsigned long group_desc; unsigned long desc; struct ext2_group_desc * gdp; @@ -98,13 +96,13 @@ static void read_inode_bitmap (struct mount * mp, unsigned long block_group, unsigned int bitmap_nr) { - struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs; + struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs; struct ext2_group_desc * gdp; struct buffer_head * bh; int error; gdp = get_group_desc (mp, block_group, NULL); - if ((error = bread (VFSTOUFS(mp)->um_devvp, + if ((error = bread (VFSTOEXT2(mp)->um_devvp, fsbtodb(sb, gdp->bg_inode_bitmap), sb->s_blocksize, NOCRED, &bh)) != 0) @@ -131,7 +129,7 @@ static void read_inode_bitmap (struct mount * mp, static int load_inode_bitmap (struct mount * mp, unsigned int block_group) { - struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs; + struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs; int i, j; unsigned long inode_bitmap_number; struct buffer_head * inode_bitmap; @@ -447,14 +445,14 @@ repeat: static unsigned long ext2_count_free_inodes (struct mount * mp) { #ifdef EXT2FS_DEBUG - struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs; + struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs; struct ext2_super_block * es; unsigned long desc_count, bitmap_count, x; int bitmap_nr; struct ext2_group_desc * gdp; int i; - lock_super (VFSTOUFS(mp)->um_devvp); + lock_super (VFSTOEXT2(mp)->um_devvp); es = sb->s_es; desc_count = 0; bitmap_count = 0; @@ -471,10 +469,10 @@ static unsigned long ext2_count_free_inodes (struct mount * mp) } ext2_debug("stored = %lu, computed = %lu, %lu\n", es->s_free_inodes_count, desc_count, bitmap_count); - unlock_super (VFSTOUFS(mp)->um_devvp); + unlock_super (VFSTOEXT2(mp)->um_devvp); return desc_count; #else - return VFSTOUFS(mp)->um_e2fsb->s_free_inodes_count; + return VFSTOEXT2(mp)->um_e2fsb->s_free_inodes_count; #endif } #endif /* unused */ diff --git a/sys/gnu/ext2fs/ext2_lookup.c b/sys/gnu/ext2fs/ext2_lookup.c index 2c1de41414f4..14b78b58a7cf 100644 --- a/sys/gnu/ext2fs/ext2_lookup.c +++ b/sys/gnu/ext2fs/ext2_lookup.c @@ -55,13 +55,10 @@ #include <sys/malloc.h> #include <sys/dirent.h> -#include <ufs/ufs/extattr.h> -#include <ufs/ufs/quota.h> -#include <ufs/ufs/inode.h> #include <ufs/ufs/dir.h> -#include <ufs/ufs/ufsmount.h> -#include <ufs/ufs/ufs_extern.h> +#include <gnu/ext2fs/inode.h> +#include <gnu/ext2fs/ext2_mount.h> #include <gnu/ext2fs/ext2_extern.h> #include <gnu/ext2fs/ext2_fs.h> #include <gnu/ext2fs/ext2_fs_sb.h> @@ -364,7 +361,7 @@ ext2_lookup(ap) * profiling time and hence has been removed in the interest * of simplicity. */ - bmask = VFSTOUFS(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1; + bmask = VFSTOEXT2(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1; if (nameiop != LOOKUP || dp->i_diroff == 0 || dp->i_diroff > dp->i_size) { entryoffsetinblock = 0; @@ -373,7 +370,8 @@ ext2_lookup(ap) } else { dp->i_offset = dp->i_diroff; if ((entryoffsetinblock = dp->i_offset & bmask) && - (error = UFS_BLKATOFF(vdp, (off_t)dp->i_offset, NULL, &bp))) + (error = ext2_blkatoff(vdp, (off_t)dp->i_offset, NULL, + &bp))) return (error); numdirpasses = 2; nchstats.ncs_2passes++; @@ -391,7 +389,8 @@ searchloop: if (bp != NULL) brelse(bp); if ((error = - UFS_BLKATOFF(vdp, (off_t)dp->i_offset, NULL, &bp)) != 0) + ext2_blkatoff(vdp, (off_t)dp->i_offset, NULL, + &bp)) != 0) return (error); entryoffsetinblock = 0; } @@ -416,7 +415,7 @@ searchloop: if (ep->rec_len == 0 || (dirchk && ext2_dirbadentry(vdp, ep, entryoffsetinblock))) { int i; - ufs_dirbad(dp, dp->i_offset, "mangled entry"); + ext2_dirbad(dp, dp->i_offset, "mangled entry"); i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)); dp->i_offset += i; entryoffsetinblock += i; @@ -558,7 +557,7 @@ found: */ if (entryoffsetinblock + EXT2_DIR_REC_LEN(ep->name_len) > dp->i_size) { - ufs_dirbad(dp, dp->i_offset, "i_size too small"); + ext2_dirbad(dp, dp->i_offset, "i_size too small"); dp->i_size = entryoffsetinblock+EXT2_DIR_REC_LEN(ep->name_len); dp->i_flag |= IN_CHANGE | IN_UPDATE; } @@ -700,6 +699,21 @@ found: return (0); } +void +ext2_dirbad(ip, offset, how) + struct inode *ip; + doff_t offset; + char *how; +{ + struct mount *mp; + + mp = ITOV(ip)->v_mount; + (void)printf("%s: bad dir ino %lu at offset %ld: %s\n", + mp->mnt_stat.f_mntonname, (u_long)ip->i_number, (long)offset, how); + if ((mp->mnt_flag & MNT_RDONLY) == 0) + panic("ext2_dirbad: bad dir"); +} + /* * Do consistency checking on a directory entry: * record length must be multiple of 4 @@ -804,7 +818,7 @@ ext2_direnter(ip, dvp, cnp) auio.uio_td = (struct thread *)0; error = VOP_WRITE(dvp, &auio, IO_SYNC, cnp->cn_cred); if (DIRBLKSIZ > - VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize) + VFSTOEXT2(dvp->v_mount)->um_mountp->mnt_stat.f_bsize) /* XXX should grow with balloc() */ panic("ext2_direnter: frag size"); else if (!error) { @@ -835,7 +849,8 @@ ext2_direnter(ip, dvp, cnp) /* * Get the block containing the space for the new directory entry. */ - if ((error = UFS_BLKATOFF(dvp, (off_t)dp->i_offset, &dirbuf, &bp)) != 0) + if ((error = ext2_blkatoff(dvp, (off_t)dp->i_offset, &dirbuf, + &bp)) != 0) return (error); /* * Find space for the new entry. In the simple case, the entry at @@ -881,7 +896,7 @@ ext2_direnter(ip, dvp, cnp) error = BUF_WRITE(bp); dp->i_flag |= IN_CHANGE | IN_UPDATE; if (!error && dp->i_endoff && dp->i_endoff < dp->i_size) - error = UFS_TRUNCATE(dvp, (off_t)dp->i_endoff, IO_SYNC, + error = ext2_truncate(dvp, (off_t)dp->i_endoff, IO_SYNC, cnp->cn_cred, cnp->cn_thread); return (error); } @@ -914,7 +929,8 @@ ext2_dirremove(dvp, cnp) * First entry in block: set d_ino to zero. */ if ((error = - UFS_BLKATOFF(dvp, (off_t)dp->i_offset, (char **)&ep, &bp)) != 0) + ext2_blkatoff(dvp, (off_t)dp->i_offset, (char **)&ep, + &bp)) != 0) return (error); ep->inode = 0; error = BUF_WRITE(bp); @@ -924,7 +940,7 @@ ext2_dirremove(dvp, cnp) /* * Collapse new free space into previous entry. */ - if ((error = UFS_BLKATOFF(dvp, (off_t)(dp->i_offset - dp->i_count), + if ((error = ext2_blkatoff(dvp, (off_t)(dp->i_offset - dp->i_count), (char **)&ep, &bp)) != 0) return (error); ep->rec_len += dp->i_reclen; @@ -948,7 +964,8 @@ ext2_dirrewrite(dp, ip, cnp) struct vnode *vdp = ITOV(dp); int error; - if ((error = UFS_BLKATOFF(vdp, (off_t)dp->i_offset, (char **)&ep, &bp)) != 0) + if ((error = ext2_blkatoff(vdp, (off_t)dp->i_offset, (char **)&ep, + &bp)) != 0) return (error); ep->inode = ip->i_number; if (EXT2_HAS_INCOMPAT_FEATURE(ip->i_e2fs->s_es, diff --git a/sys/gnu/ext2fs/ext2_readwrite.c b/sys/gnu/ext2fs/ext2_readwrite.c index 2772f7b2306e..73f900cd3230 100644 --- a/sys/gnu/ext2fs/ext2_readwrite.c +++ b/sys/gnu/ext2fs/ext2_readwrite.c @@ -301,12 +301,12 @@ WRITE(ap) ip->i_mode &= ~(ISUID | ISGID); if (error) { if (ioflag & IO_UNIT) { - (void)UFS_TRUNCATE(vp, osize, + (void)ext2_truncate(vp, osize, ioflag & IO_SYNC, ap->a_cred, uio->uio_td); uio->uio_offset -= resid - uio->uio_resid; uio->uio_resid = resid; } } else if (resid > uio->uio_resid && (ioflag & IO_SYNC)) - error = UFS_UPDATE(vp, 1); + error = ext2_update(vp, 1); return (error); } diff --git a/sys/gnu/ext2fs/ext2_subr.c b/sys/gnu/ext2fs/ext2_subr.c index 69eecf1e236b..587ed0520f6d 100644 --- a/sys/gnu/ext2fs/ext2_subr.c +++ b/sys/gnu/ext2fs/ext2_subr.c @@ -50,9 +50,7 @@ #include <sys/ucred.h> #include <sys/vnode.h> -#include <ufs/ufs/quota.h> -#include <ufs/ufs/inode.h> - +#include <gnu/ext2fs/inode.h> #include <gnu/ext2fs/ext2_extern.h> #include <gnu/ext2fs/ext2_fs_sb.h> #include <gnu/ext2fs/fs.h> @@ -121,7 +119,7 @@ ext2_checkoverlap(bp, ip) continue; vprint("Disk overlap", vp); (void)printf("\tstart %d, end %d overlap start %lld, end %ld\n", - start, last, ep->b_blkno, + start, last, (long long)ep->b_blkno, (long)(ep->b_blkno + btodb(ep->b_bcount) - 1)); panic("Disk buffer overlap"); } diff --git a/sys/gnu/ext2fs/ext2_vfsops.c b/sys/gnu/ext2fs/ext2_vfsops.c index 54c43058cb3d..b9afe91a1f7f 100644 --- a/sys/gnu/ext2fs/ext2_vfsops.c +++ b/sys/gnu/ext2fs/ext2_vfsops.c @@ -40,8 +40,6 @@ * $FreeBSD$ */ -#include "opt_quota.h" - #include <sys/param.h> #include <sys/systm.h> #include <sys/namei.h> @@ -57,12 +55,8 @@ #include <sys/stat.h> #include <sys/mutex.h> -#include <ufs/ufs/extattr.h> -#include <ufs/ufs/quota.h> -#include <ufs/ufs/ufsmount.h> -#include <ufs/ufs/inode.h> -#include <ufs/ufs/ufs_extern.h> - +#include <gnu/ext2fs/ext2_mount.h> +#include <gnu/ext2fs/inode.h> #include <gnu/ext2fs/fs.h> #include <gnu/ext2fs/ext2_extern.h> @@ -71,26 +65,29 @@ static int ext2_fhtovp(struct mount *, struct fid *, struct vnode **); static int ext2_flushfiles(struct mount *mp, int flags, struct thread *td); +static int ext2_init(struct vfsconf *); static int ext2_mount(struct mount *, char *, caddr_t, struct nameidata *, struct thread *); static int ext2_mountfs(struct vnode *, struct mount *, struct thread *); static int ext2_reload(struct mount *mountp, struct ucred *cred, struct thread *td); -static int ext2_sbupdate(struct ufsmount *, int); +static int ext2_root(struct mount *, struct vnode **vpp); +static int ext2_sbupdate(struct ext2mount *, int); static int ext2_statfs(struct mount *, struct statfs *, struct thread *); static int ext2_sync(struct mount *, int, struct ucred *, struct thread *); static int ext2_unmount(struct mount *, int, struct thread *); static int ext2_vget(struct mount *, ino_t, int, struct vnode **); static int ext2_vptofh(struct vnode *, struct fid *); -static MALLOC_DEFINE(M_EXT2NODE, "EXT2 node", "EXT2 vnode private part"); +MALLOC_DEFINE(M_EXT2NODE, "EXT2 node", "EXT2 vnode private part"); +static MALLOC_DEFINE(M_EXT2MNT, "EXT2 mount", "EXT2 mount structure"); static struct vfsops ext2fs_vfsops = { ext2_mount, - ufs_start, /* empty function */ + vfs_stdstart, ext2_unmount, - ufs_root, /* root inode via vget */ - ufs_quotactl, /* does operations associated with quotas */ + ext2_root, /* root inode via vget */ + vfs_stdquotactl, ext2_statfs, ext2_sync, ext2_vget, @@ -129,7 +126,7 @@ ext2_mountroot() register struct ext2_sb_info *fs; register struct mount *mp; struct thread *td = curthread; - struct ufsmount *ump; + struct ext2mount *ump; u_int size; int error; @@ -155,7 +152,7 @@ ext2_mountroot() TAILQ_INSERT_HEAD(&mountlist, mp, mnt_list); mp->mnt_flag |= MNT_ROOTFS; mp->mnt_vnodecovered = NULLVP; - ump = VFSTOUFS(mp); + ump = VFSTOEXT2(mp); fs = ump->um_e2fs; bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt)); fs->fs_fsmnt[0] = '/'; @@ -180,13 +177,13 @@ static int ext2_mount(mp, path, data, ndp, td) register struct mount *mp; char *path; - caddr_t data; /* this is actually a (struct ufs_args *) */ + caddr_t data; /* this is actually a (struct ext2_args *) */ struct nameidata *ndp; struct thread *td; { struct vnode *devvp; - struct ufs_args args; - struct ufsmount *ump = 0; + struct ext2_args args; + struct ext2mount *ump = 0; register struct ext2_sb_info *fs; size_t size; int error, flags; @@ -195,7 +192,7 @@ ext2_mount(mp, path, data, ndp, td) /* Double-check the length of path.. */ if (strlen(path) >= MAXMNTLEN - 1) return (ENAMETOOLONG); - error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args)); + error = copyin(data, (caddr_t)&args, sizeof (struct ext2_args)); if (error != 0) return (error); /* @@ -203,7 +200,7 @@ ext2_mount(mp, path, data, ndp, td) * read/write; if there is no device name, that's all we do. */ if (mp->mnt_flag & MNT_UPDATE) { - ump = VFSTOUFS(mp); + ump = VFSTOEXT2(mp); fs = ump->um_e2fs; error = 0; if (fs->s_rd_only == 0 && (mp->mnt_flag & MNT_RDONLY)) { @@ -310,7 +307,7 @@ ext2_mount(mp, path, data, ndp, td) vrele(devvp); return (error); } - ump = VFSTOUFS(mp); + ump = VFSTOEXT2(mp); fs = ump->um_e2fs; /* * Note that this strncpy() is ok because of a check at the start @@ -466,7 +463,7 @@ static int compute_sb_data(devvp, es, fs) V(s_db_per_group) fs->s_group_desc = bsd_malloc(db_count * sizeof (struct buf *), - M_UFSMNT, M_WAITOK); + M_EXT2MNT, M_WAITOK); /* adjust logic_sb_block */ if(fs->s_blocksize > SBSIZE) @@ -481,7 +478,7 @@ static int compute_sb_data(devvp, es, fs) if(error) { for (j = 0; j < i; j++) brelse(fs->s_group_desc[j]); - bsd_free(fs->s_group_desc, M_UFSMNT); + bsd_free(fs->s_group_desc, M_EXT2MNT); printf("EXT2-fs: unable to read group descriptors (%d)\n", error); return EIO; } @@ -491,7 +488,7 @@ static int compute_sb_data(devvp, es, fs) if(!ext2_check_descriptors(fs)) { for (j = 0; j < db_count; j++) ULCK_BUF(fs->s_group_desc[j]) - bsd_free(fs->s_group_desc, M_UFSMNT); + bsd_free(fs->s_group_desc, M_EXT2MNT); printf("EXT2-fs: (ext2_check_descriptors failure) " "unable to read group descriptors\n"); return EIO; @@ -539,7 +536,7 @@ ext2_reload(mountp, cred, td) /* * Step 1: invalidate all cached meta-data. */ - devvp = VFSTOUFS(mountp)->um_devvp; + devvp = VFSTOEXT2(mountp)->um_devvp; if (vinvalbuf(devvp, 0, cred, td, 0, 0)) panic("ext2_reload: dirty1"); /* @@ -553,7 +550,7 @@ ext2_reload(mountp, cred, td) brelse(bp); return (EIO); /* XXX needs translation */ } - fs = VFSTOUFS(mountp)->um_e2fs; + fs = VFSTOEXT2(mountp)->um_e2fs; bcopy(bp->b_data, fs->s_es, sizeof(struct ext2_super_block)); if((error = compute_sb_data(devvp, es, fs)) != 0) { @@ -600,9 +597,8 @@ loop: vput(vp); return (error); } - ext2_ei2di((struct ext2_inode *) ((char *)bp->b_data + - EXT2_INODE_SIZE * ino_to_fsbo(fs, ip->i_number)), - &ip->i_din); + ext2_ei2i((struct ext2_inode *) ((char *)bp->b_data + + EXT2_INODE_SIZE * ino_to_fsbo(fs, ip->i_number)), ip); brelse(bp); vput(vp); mtx_lock(&mntvnode_mtx); @@ -620,12 +616,12 @@ ext2_mountfs(devvp, mp, td) struct mount *mp; struct thread *td; { - register struct ufsmount *ump; + register struct ext2mount *ump; struct buf *bp; register struct ext2_sb_info *fs; struct ext2_super_block * es; dev_t dev = devvp->v_rdev; - int error, i; + int error; int ronly; /* @@ -677,22 +673,16 @@ ext2_mountfs(devvp, mp, td) goto out; } } - ump = bsd_malloc(sizeof *ump, M_UFSMNT, M_WAITOK); + ump = bsd_malloc(sizeof *ump, M_EXT2MNT, M_WAITOK); bzero((caddr_t)ump, sizeof *ump); - ump->um_malloctype = M_EXT2NODE; - ump->um_blkatoff = ext2_blkatoff; - ump->um_truncate = ext2_truncate; - ump->um_update = ext2_update; - ump->um_valloc = ext2_valloc; - ump->um_vfree = ext2_vfree; /* I don't know whether this is the right strategy. Note that we dynamically allocate both a ext2_sb_info and a ext2_super_block while Linux keeps the super block in a locked buffer */ ump->um_e2fs = bsd_malloc(sizeof(struct ext2_sb_info), - M_UFSMNT, M_WAITOK); + M_EXT2MNT, M_WAITOK); ump->um_e2fs->s_es = bsd_malloc(sizeof(struct ext2_super_block), - M_UFSMNT, M_WAITOK); + M_EXT2MNT, M_WAITOK); bcopy(es, ump->um_e2fs->s_es, (u_int)sizeof(struct ext2_super_block)); if ((error = compute_sb_data(devvp, ump->um_e2fs->s_es, ump->um_e2fs))) goto out; @@ -720,14 +710,12 @@ ext2_mountfs(devvp, mp, td) ump->um_mountp = mp; ump->um_dev = dev; ump->um_devvp = devvp; - /* setting those two parameters allows us to use + /* setting those two parameters allowed us to use ufs_bmap w/o changse ! */ ump->um_nindir = EXT2_ADDR_PER_BLOCK(fs); ump->um_bptrtodb = fs->s_es->s_log_block_size + 1; ump->um_seqinc = EXT2_FRAGS_PER_BLOCK(fs); - for (i = 0; i < MAXQUOTAS; i++) - ump->um_quotas[i] = NULLVP; devvp->v_rdev->si_mountpoint = mp; if (ronly == 0) ext2_sbupdate(ump, MNT_WAIT); @@ -737,9 +725,9 @@ out: brelse(bp); (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, td); if (ump) { - bsd_free(ump->um_e2fs->s_es, M_UFSMNT); - bsd_free(ump->um_e2fs, M_UFSMNT); - bsd_free(ump, M_UFSMNT); + bsd_free(ump->um_e2fs->s_es, M_EXT2MNT); + bsd_free(ump->um_e2fs, M_EXT2MNT); + bsd_free(ump, M_EXT2MNT); mp->mnt_data = (qaddr_t)0; } return (error); @@ -754,7 +742,7 @@ ext2_unmount(mp, mntflags, td) int mntflags; struct thread *td; { - register struct ufsmount *ump; + register struct ext2mount *ump; register struct ext2_sb_info *fs; int error, flags, ronly, i; @@ -766,7 +754,7 @@ ext2_unmount(mp, mntflags, td) } if ((error = ext2_flushfiles(mp, flags, td)) != 0) return (error); - ump = VFSTOUFS(mp); + ump = VFSTOEXT2(mp); fs = ump->um_e2fs; ronly = fs->s_rd_only; if (ronly == 0) { @@ -778,7 +766,7 @@ ext2_unmount(mp, mntflags, td) /* release buffers containing group descriptors */ for(i = 0; i < fs->s_db_per_group; i++) ULCK_BUF(fs->s_group_desc[i]) - bsd_free(fs->s_group_desc, M_UFSMNT); + bsd_free(fs->s_group_desc, M_EXT2MNT); /* release cached inode/block bitmaps */ for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++) @@ -793,9 +781,9 @@ ext2_unmount(mp, mntflags, td) error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, td); vrele(ump->um_devvp); - bsd_free(fs->s_es, M_UFSMNT); - bsd_free(fs, M_UFSMNT); - bsd_free(ump, M_UFSMNT); + bsd_free(fs->s_es, M_EXT2MNT); + bsd_free(fs, M_EXT2MNT); + bsd_free(ump, M_EXT2MNT); mp->mnt_data = (qaddr_t)0; mp->mnt_flag &= ~MNT_LOCAL; return (error); @@ -810,28 +798,8 @@ ext2_flushfiles(mp, flags, td) int flags; struct thread *td; { - register struct ufsmount *ump; int error; -#if QUOTA - int i; -#endif - ump = VFSTOUFS(mp); -#if QUOTA - if (mp->mnt_flag & MNT_QUOTA) { - if ((error = vflush(mp, 0, SKIPSYSTEM|flags)) != 0) - return (error); - for (i = 0; i < MAXQUOTAS; i++) { - if (ump->um_quotas[i] == NULLVP) - continue; - quotaoff(td, mp, i); - } - /* - * Here we fall through to vflush again to ensure - * that we have gotten rid of all the system vnodes. - */ - } -#endif error = vflush(mp, 0, flags); return (error); } @@ -847,12 +815,12 @@ ext2_statfs(mp, sbp, td) struct thread *td; { unsigned long overhead; - register struct ufsmount *ump; + register struct ext2mount *ump; register struct ext2_sb_info *fs; register struct ext2_super_block *es; int i, nsb; - ump = VFSTOUFS(mp); + ump = VFSTOEXT2(mp); fs = ump->um_e2fs; es = fs->s_es; @@ -908,7 +876,7 @@ ext2_sync(mp, waitfor, cred, td) { struct vnode *nvp, *vp; struct inode *ip; - struct ufsmount *ump = VFSTOUFS(mp); + struct ext2mount *ump = VFSTOEXT2(mp); struct ext2_sb_info *fs; int error, allerror = 0; @@ -964,9 +932,6 @@ loop: allerror = error; VOP_UNLOCK(ump->um_devvp, 0, td); } -#if QUOTA - qsync(mp); -#endif /* * Write back modified superblock. */ @@ -994,17 +959,17 @@ ext2_vget(mp, ino, flags, vpp) { register struct ext2_sb_info *fs; register struct inode *ip; - struct ufsmount *ump; + struct ext2mount *ump; struct buf *bp; struct vnode *vp; dev_t dev; int i, error; int used_blocks; - ump = VFSTOUFS(mp); + ump = VFSTOEXT2(mp); dev = ump->um_dev; restart: - if ((error = ufs_ihashget(dev, ino, flags, vpp)) != 0) + if ((error = ext2_ihashget(dev, ino, flags, vpp)) != 0) return (error); if (*vpp != NULL) return (0); @@ -1048,17 +1013,13 @@ restart: ip->i_e2fs = fs = ump->um_e2fs; ip->i_dev = dev; ip->i_number = ino; -#if QUOTA - for (i = 0; i < MAXQUOTAS; i++) - ip->i_dquot[i] = NODQUOT; -#endif /* * Put it onto its hash chain and lock it so that other requests for * this inode will block if they arrive while we are sleeping waiting * for old data structures to be purged or for the contents of the * disk portion of this inode to be read. */ - ufs_ihashins(ip); + ext2_ihashins(ip); if (ext2fs_inode_hash_lock < 0) wakeup(&ext2fs_inode_hash_lock); @@ -1082,8 +1043,8 @@ printf("ext2_vget(%d) dbn= %d ", ino, fsbtodb(fs, ino_to_fsba(fs, ino))); return (error); } /* convert ext2 inode to dinode */ - ext2_ei2di((struct ext2_inode *) ((char *)bp->b_data + EXT2_INODE_SIZE * - ino_to_fsbo(fs, ino)), &ip->i_din); + ext2_ei2i((struct ext2_inode *) ((char *)bp->b_data + EXT2_INODE_SIZE * + ino_to_fsbo(fs, ino)), ip); ip->i_block_group = ino_to_cg(fs, ino); ip->i_next_alloc_block = 0; ip->i_next_alloc_goal = 0; @@ -1107,7 +1068,7 @@ printf("ext2_vget(%d) dbn= %d ", ino, fsbtodb(fs, ino_to_fsba(fs, ino))); * Initialize the vnode from the inode, check for aliases. * Note that the underlying vnode may have changed. */ - if ((error = ufs_vinit(mp, ext2_specop_p, ext2_fifoop_p, &vp)) != 0) { + if ((error = ext2_vinit(mp, ext2_specop_p, ext2_fifoop_p, &vp)) != 0) { vput(vp); *vpp = NULL; return (error); @@ -1146,15 +1107,32 @@ ext2_fhtovp(mp, fhp, vpp) struct fid *fhp; struct vnode **vpp; { + struct inode *ip; register struct ufid *ufhp; + struct vnode *nvp; struct ext2_sb_info *fs; + int error; ufhp = (struct ufid *)fhp; - fs = VFSTOUFS(mp)->um_e2fs; + fs = VFSTOEXT2(mp)->um_e2fs; if (ufhp->ufid_ino < ROOTINO || ufhp->ufid_ino >= fs->s_groups_count * fs->s_es->s_inodes_per_group) return (ESTALE); - return (ufs_fhtovp(mp, ufhp, vpp)); + + error = VFS_VGET(mp, ufhp->ufid_ino, LK_EXCLUSIVE, &nvp); + if (error) { + *vpp = NULLVP; + return (error); + } + ip = VTOI(nvp); + if (ip->i_mode == 0 || + ip->i_gen != ufhp->ufid_gen || ip->i_nlink <= 0) { + vput(nvp); + *vpp = NULLVP; + return (ESTALE); + } + *vpp = nvp; + return (0); } /* @@ -1182,7 +1160,7 @@ ext2_vptofh(vp, fhp) */ static int ext2_sbupdate(mp, waitfor) - struct ufsmount *mp; + struct ext2mount *mp; int waitfor; { register struct ext2_sb_info *fs = mp->um_e2fs; @@ -1207,3 +1185,34 @@ printf("\nupdating superblock, waitfor=%s\n", waitfor == MNT_WAIT ? "yes":"no"); return (error); } + +/* + * Return the root of a filesystem. + */ +static int +ext2_root(mp, vpp) + struct mount *mp; + struct vnode **vpp; +{ + struct vnode *nvp; + int error; + + error = VFS_VGET(mp, (ino_t)ROOTINO, LK_EXCLUSIVE, &nvp); + if (error) + return (error); + *vpp = nvp; + return (0); +} + +static int +ext2_init(struct vfsconf *vfsp) +{ + static int done; + + if (done) + return (0); + done = 1; + ext2_ihashinit(); + + return (0); +} diff --git a/sys/gnu/ext2fs/ext2_vnops.c b/sys/gnu/ext2fs/ext2_vnops.c index 180ac3db063a..ba7b714cdaf9 100644 --- a/sys/gnu/ext2fs/ext2_vnops.c +++ b/sys/gnu/ext2fs/ext2_vnops.c @@ -46,34 +46,38 @@ * $FreeBSD$ */ -#include "opt_quota.h" #include "opt_suiddir.h" #include <sys/param.h> #include <sys/systm.h> #include <sys/resourcevar.h> #include <sys/kernel.h> +#include <sys/fcntl.h> #include <sys/stat.h> #include <sys/bio.h> #include <sys/buf.h> #include <sys/proc.h> #include <sys/mount.h> +#include <sys/unistd.h> #include <sys/time.h> #include <sys/vnode.h> #include <sys/namei.h> +#include <sys/lockf.h> +#include <sys/event.h> +#include <sys/conf.h> +#include <sys/file.h> #include <vm/vm.h> #include <vm/vm_extern.h> #include <vm/vnode_pager.h> +#include <fs/fifofs/fifo.h> + #include <sys/signalvar.h> #include <ufs/ufs/dir.h> -#include <ufs/ufs/extattr.h> -#include <ufs/ufs/quota.h> -#include <ufs/ufs/inode.h> -#include <ufs/ufs/ufsmount.h> -#include <ufs/ufs/ufs_extern.h> +#include <gnu/ext2fs/inode.h> +#include <gnu/ext2fs/ext2_mount.h> #include <gnu/ext2fs/ext2_fs_sb.h> #include <gnu/ext2fs/fs.h> #include <gnu/ext2fs/ext2_extern.h> @@ -81,38 +85,81 @@ static int ext2_makeinode(int mode, struct vnode *, struct vnode **, struct componentname *); -static int ext2_fsync(struct vop_fsync_args *); -static int ext2_read(struct vop_read_args *); -static int ext2_write(struct vop_write_args *); -static int ext2_remove(struct vop_remove_args *); -static int ext2_link(struct vop_link_args *); -static int ext2_rename(struct vop_rename_args *); -static int ext2_mkdir(struct vop_mkdir_args *); -static int ext2_rmdir(struct vop_rmdir_args *); +static int ext2_access(struct vop_access_args *); +static int ext2_advlock(struct vop_advlock_args *); +static int ext2_chmod(struct vnode *, int, struct ucred *, struct thread *); +static int ext2_chown(struct vnode *, uid_t, gid_t, struct ucred *, + struct thread *); +static int ext2_close(struct vop_close_args *); static int ext2_create(struct vop_create_args *); +static int ext2_fsync(struct vop_fsync_args *); +static int ext2_getattr(struct vop_getattr_args *); +static int ext2_kqfilter(struct vop_kqfilter_args *ap); +static int ext2_link(struct vop_link_args *); +static int ext2_mkdir(struct vop_mkdir_args *); static int ext2_mknod(struct vop_mknod_args *); +static int ext2_open(struct vop_open_args *); +static int ext2_pathconf(struct vop_pathconf_args *); +static int ext2_print(struct vop_print_args *); +static int ext2_read(struct vop_read_args *); +static int ext2_readlink(struct vop_readlink_args *); +static int ext2_remove(struct vop_remove_args *); +static int ext2_rename(struct vop_rename_args *); +static int ext2_rmdir(struct vop_rmdir_args *); +static int ext2_setattr(struct vop_setattr_args *); +static int ext2_strategy(struct vop_strategy_args *); static int ext2_symlink(struct vop_symlink_args *); +static int ext2_write(struct vop_write_args *); +static int ext2fifo_close(struct vop_close_args *); +static int ext2fifo_kqfilter(struct vop_kqfilter_args *); +static int ext2fifo_read(struct vop_read_args *); +static int ext2fifo_write(struct vop_write_args *); +static int ext2spec_close(struct vop_close_args *); +static int ext2spec_read(struct vop_read_args *); +static int ext2spec_write(struct vop_write_args *); +static int filt_ext2read(struct knote *kn, long hint); +static int filt_ext2write(struct knote *kn, long hint); +static int filt_ext2vnode(struct knote *kn, long hint); +static void filt_ext2detach(struct knote *kn); -/* Global vfs data structures for ufs. */ +/* Global vfs data structures for ext2. */ vop_t **ext2_vnodeop_p; static struct vnodeopv_entry_desc ext2_vnodeop_entries[] = { - { &vop_default_desc, (vop_t *) ufs_vnoperate }, + { &vop_default_desc, (vop_t *) vop_defaultop }, + { &vop_access_desc, (vop_t *) ext2_access }, + { &vop_advlock_desc, (vop_t *) ext2_advlock }, + { &vop_bmap_desc, (vop_t *) ext2_bmap }, { &vop_cachedlookup_desc, (vop_t *) ext2_lookup }, + { &vop_close_desc, (vop_t *) ext2_close }, + { &vop_create_desc, (vop_t *) ext2_create }, { &vop_fsync_desc, (vop_t *) ext2_fsync }, + { &vop_getattr_desc, (vop_t *) ext2_getattr }, + { &vop_getwritemount_desc, (vop_t *) vop_stdgetwritemount }, { &vop_inactive_desc, (vop_t *) ext2_inactive }, + { &vop_islocked_desc, (vop_t *) vop_stdislocked }, + { &vop_link_desc, (vop_t *) ext2_link }, + { &vop_lock_desc, (vop_t *) vop_stdlock }, { &vop_lookup_desc, (vop_t *) vfs_cache_lookup }, + { &vop_mkdir_desc, (vop_t *) ext2_mkdir }, + { &vop_mknod_desc, (vop_t *) ext2_mknod }, + { &vop_open_desc, (vop_t *) ext2_open }, + { &vop_pathconf_desc, (vop_t *) ext2_pathconf }, + { &vop_poll_desc, (vop_t *) vop_stdpoll }, + { &vop_kqfilter_desc, (vop_t *) ext2_kqfilter }, + { &vop_print_desc, (vop_t *) ext2_print }, { &vop_read_desc, (vop_t *) ext2_read }, { &vop_readdir_desc, (vop_t *) ext2_readdir }, + { &vop_readlink_desc, (vop_t *) ext2_readlink }, { &vop_reallocblks_desc, (vop_t *) ext2_reallocblks }, - { &vop_write_desc, (vop_t *) ext2_write }, + { &vop_reclaim_desc, (vop_t *) ext2_reclaim }, { &vop_remove_desc, (vop_t *) ext2_remove }, - { &vop_link_desc, (vop_t *) ext2_link }, { &vop_rename_desc, (vop_t *) ext2_rename }, - { &vop_mkdir_desc, (vop_t *) ext2_mkdir }, { &vop_rmdir_desc, (vop_t *) ext2_rmdir }, - { &vop_create_desc, (vop_t *) ext2_create }, - { &vop_mknod_desc, (vop_t *) ext2_mknod }, + { &vop_setattr_desc, (vop_t *) ext2_setattr }, + { &vop_strategy_desc, (vop_t *) ext2_strategy }, { &vop_symlink_desc, (vop_t *) ext2_symlink }, + { &vop_unlock_desc, (vop_t *) vop_stdunlock }, + { &vop_write_desc, (vop_t *) ext2_write }, { NULL, NULL } }; static struct vnodeopv_desc ext2fs_vnodeop_opv_desc = @@ -120,9 +167,20 @@ static struct vnodeopv_desc ext2fs_vnodeop_opv_desc = vop_t **ext2_specop_p; static struct vnodeopv_entry_desc ext2_specop_entries[] = { - { &vop_default_desc, (vop_t *) ufs_vnoperatespec }, + { &vop_default_desc, (vop_t *) spec_vnoperate }, + { &vop_access_desc, (vop_t *) ext2_access }, + { &vop_close_desc, (vop_t *) ext2spec_close }, { &vop_fsync_desc, (vop_t *) ext2_fsync }, + { &vop_getattr_desc, (vop_t *) ext2_getattr }, { &vop_inactive_desc, (vop_t *) ext2_inactive }, + { &vop_islocked_desc, (vop_t *) vop_stdislocked }, + { &vop_lock_desc, (vop_t *) vop_stdlock }, + { &vop_print_desc, (vop_t *) ext2_print }, + { &vop_read_desc, (vop_t *) ext2spec_read }, + { &vop_reclaim_desc, (vop_t *) ext2_reclaim }, + { &vop_setattr_desc, (vop_t *) ext2_setattr }, + { &vop_unlock_desc, (vop_t *) vop_stdunlock }, + { &vop_write_desc, (vop_t *) ext2spec_write }, { NULL, NULL } }; static struct vnodeopv_desc ext2fs_specop_opv_desc = @@ -130,9 +188,21 @@ static struct vnodeopv_desc ext2fs_specop_opv_desc = vop_t **ext2_fifoop_p; static struct vnodeopv_entry_desc ext2_fifoop_entries[] = { - { &vop_default_desc, (vop_t *) ufs_vnoperatefifo }, + { &vop_default_desc, (vop_t *) fifo_vnoperate }, + { &vop_access_desc, (vop_t *) ext2_access }, + { &vop_close_desc, (vop_t *) ext2fifo_close }, { &vop_fsync_desc, (vop_t *) ext2_fsync }, + { &vop_getattr_desc, (vop_t *) ext2_getattr }, { &vop_inactive_desc, (vop_t *) ext2_inactive }, + { &vop_islocked_desc, (vop_t *) vop_stdislocked }, + { &vop_kqfilter_desc, (vop_t *) ext2fifo_kqfilter }, + { &vop_lock_desc, (vop_t *) vop_stdlock }, + { &vop_print_desc, (vop_t *) ext2_print }, + { &vop_read_desc, (vop_t *) ext2fifo_read }, + { &vop_reclaim_desc, (vop_t *) ext2_reclaim }, + { &vop_setattr_desc, (vop_t *) ext2_setattr }, + { &vop_unlock_desc, (vop_t *) vop_stdunlock }, + { &vop_write_desc, (vop_t *) ext2fifo_write }, { NULL, NULL } }; static struct vnodeopv_desc ext2fs_fifoop_opv_desc = @@ -144,9 +214,26 @@ static struct vnodeopv_desc ext2fs_fifoop_opv_desc = #include <gnu/ext2fs/ext2_readwrite.c> +union _qcvt { + int64_t qcvt; + int32_t val[2]; +}; +#define SETHIGH(q, h) { \ + union _qcvt tmp; \ + tmp.qcvt = (q); \ + tmp.val[_QUAD_HIGHWORD] = (h); \ + (q) = tmp.qcvt; \ +} +#define SETLOW(q, l) { \ + union _qcvt tmp; \ + tmp.qcvt = (q); \ + tmp.val[_QUAD_LOWWORD] = (l); \ + (q) = tmp.qcvt; \ +} + /* * A virgin directory (no blushing please). - * Note that the type and namlen fields are reversed relative to ufs. + * Note that the type and namlen fields are reversed relative to ext2. * Also, we don't use `struct odirtemplate', since it would just cause * endianness problems. */ @@ -159,6 +246,39 @@ static struct dirtemplate omastertemplate = { 0, DIRBLKSIZ - 12, 2, EXT2_FT_UNKNOWN, ".." }; +void +ext2_itimes(vp) + struct vnode *vp; +{ + struct inode *ip; + struct timespec ts; + + ip = VTOI(vp); + if ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE)) == 0) + return; + if ((vp->v_type == VBLK || vp->v_type == VCHR)) + ip->i_flag |= IN_LAZYMOD; + else + ip->i_flag |= IN_MODIFIED; + if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { + vfs_timestamp(&ts); + if (ip->i_flag & IN_ACCESS) { + ip->i_atime = ts.tv_sec; + ip->i_atimensec = ts.tv_nsec; + } + if (ip->i_flag & IN_UPDATE) { + ip->i_mtime = ts.tv_sec; + ip->i_mtimensec = ts.tv_nsec; + ip->i_modrev++; + } + if (ip->i_flag & IN_CHANGE) { + ip->i_ctime = ts.tv_sec; + ip->i_ctimensec = ts.tv_nsec; + } + } + ip->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE); +} + /* * Create a regular file */ @@ -181,6 +301,375 @@ ext2_create(ap) return (0); } +/* + * Open called. + * + * Nothing to do. + */ +int +ext2_open(ap) + struct vop_open_args /* { + struct vnode *a_vp; + int a_mode; + struct ucred *a_cred; + struct thread *a_td; + } */ *ap; +{ + + /* + * Files marked append-only must be opened for appending. + */ + if ((VTOI(ap->a_vp)->i_flags & APPEND) && + (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE) + return (EPERM); + return (0); +} + +/* + * Close called. + * + * Update the times on the inode. + */ +static int +ext2_close(ap) + struct vop_close_args /* { + struct vnode *a_vp; + int a_fflag; + struct ucred *a_cred; + struct thread *a_td; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct mount *mp; + + mtx_lock(&vp->v_interlock); + if (vp->v_usecount > 1) { + ext2_itimes(vp); + mtx_unlock(&vp->v_interlock); + } else { + mtx_unlock(&vp->v_interlock); + /* + * If we are closing the last reference to an unlinked + * file, then it will be freed by the inactive routine. + * Because the freeing causes a the filesystem to be + * modified, it must be held up during periods when the + * filesystem is suspended. + * + * XXX - EAGAIN is returned to prevent vn_close from + * repeating the vrele operation. + */ + if (vp->v_type == VREG && VTOI(vp)->i_nlink == 0) { + (void) vn_start_write(vp, &mp, V_WAIT); + vrele(vp); + vn_finished_write(mp); + return (EAGAIN); + } + } + return (0); +} + +static int +ext2_access(ap) + struct vop_access_args /* { + struct vnode *a_vp; + int a_mode; + struct ucred *a_cred; + struct thread *a_td; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct inode *ip = VTOI(vp); + mode_t mode = ap->a_mode; + int error; + + /* + * Disallow write attempts on read-only file systems; + * unless the file is a socket, fifo, or a block or + * character device resident on the file system. + */ + if (mode & VWRITE) { + switch (vp->v_type) { + case VDIR: + case VLNK: + case VREG: + if (vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + break; + default: + break; + } + } + + /* If immutable bit set, nobody gets to write it. */ + if ((mode & VWRITE) && (ip->i_flags & (IMMUTABLE | SF_SNAPSHOT))) + return (EPERM); + + error = vaccess(vp->v_type, ip->i_mode, ip->i_uid, ip->i_gid, + ap->a_mode, ap->a_cred, NULL); + return (error); +} + +static int +ext2_getattr(ap) + struct vop_getattr_args /* { + struct vnode *a_vp; + struct vattr *a_vap; + struct ucred *a_cred; + struct thread *a_td; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct inode *ip = VTOI(vp); + struct vattr *vap = ap->a_vap; + + ext2_itimes(vp); + /* + * Copy from inode table + */ + vap->va_fsid = dev2udev(ip->i_dev); + vap->va_fileid = ip->i_number; + vap->va_mode = ip->i_mode & ~IFMT; + vap->va_nlink = ip->i_nlink; + vap->va_uid = ip->i_uid; + vap->va_gid = ip->i_gid; + vap->va_rdev = ip->i_rdev; + vap->va_size = ip->i_size; + vap->va_atime.tv_sec = ip->i_atime; + vap->va_atime.tv_nsec = ip->i_atimensec; + vap->va_mtime.tv_sec = ip->i_mtime; + vap->va_mtime.tv_nsec = ip->i_mtimensec; + vap->va_ctime.tv_sec = ip->i_ctime; + vap->va_ctime.tv_nsec = ip->i_ctimensec; + vap->va_flags = ip->i_flags; + vap->va_gen = ip->i_gen; + vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize; + vap->va_bytes = dbtob((u_quad_t)ip->i_blocks); + vap->va_type = IFTOVT(ip->i_mode); + vap->va_filerev = ip->i_modrev; + return (0); +} + +/* + * Set attribute vnode op. called from several syscalls + */ +int +ext2_setattr(ap) + struct vop_setattr_args /* { + struct vnode *a_vp; + struct vattr *a_vap; + struct ucred *a_cred; + struct thread *a_td; + } */ *ap; +{ + struct vattr *vap = ap->a_vap; + struct vnode *vp = ap->a_vp; + struct inode *ip = VTOI(vp); + struct ucred *cred = ap->a_cred; + struct thread *td = ap->a_td; + int error; + + /* + * Check for unsettable attributes. + */ + if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || + (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || + (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || + ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { + return (EINVAL); + } + if (vap->va_flags != VNOVAL) { + if (vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + /* + * Callers may only modify the file flags on objects they + * have VADMIN rights for. + */ + if ((error = VOP_ACCESS(vp, VADMIN, cred, td))) + return (error); + /* + * Unprivileged processes and privileged processes in + * jail() are not permitted to unset system flags, or + * modify flags if any system flags are set. + * Privileged non-jail processes may not modify system flags + * if securelevel > 0 and any existing system flags are set. + */ + if (!suser_cred(cred, PRISON_ROOT)) { + if (ip->i_flags + & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND)) { + error = securelevel_gt(cred, 0); + if (error) + return (error); + } + ip->i_flags = vap->va_flags; + } else { + if (ip->i_flags + & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND) || + (vap->va_flags & UF_SETTABLE) != vap->va_flags) + return (EPERM); + ip->i_flags &= SF_SETTABLE; + ip->i_flags |= (vap->va_flags & UF_SETTABLE); + } + ip->i_flag |= IN_CHANGE; + if (vap->va_flags & (IMMUTABLE | APPEND)) + return (0); + } + if (ip->i_flags & (IMMUTABLE | APPEND)) + return (EPERM); + /* + * Go through the fields and update iff not VNOVAL. + */ + if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) { + if (vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + if ((error = ext2_chown(vp, vap->va_uid, vap->va_gid, cred, + td)) != 0) + return (error); + } + if (vap->va_size != VNOVAL) { + /* + * Disallow write attempts on read-only file systems; + * unless the file is a socket, fifo, or a block or + * character device resident on the file system. + */ + switch (vp->v_type) { + case VDIR: + return (EISDIR); + case VLNK: + case VREG: + if (vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + break; + default: + break; + } + if ((error = ext2_truncate(vp, vap->va_size, 0, cred, td)) != 0) + return (error); + } + if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { + if (vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + /* + * From utimes(2): + * If times is NULL, ... The caller must be the owner of + * the file, have permission to write the file, or be the + * super-user. + * If times is non-NULL, ... The caller must be the owner of + * the file or be the super-user. + */ + if ((error = VOP_ACCESS(vp, VADMIN, cred, td)) && + ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || + (error = VOP_ACCESS(vp, VWRITE, cred, td)))) + return (error); + if (vap->va_atime.tv_sec != VNOVAL) + ip->i_flag |= IN_ACCESS; + if (vap->va_mtime.tv_sec != VNOVAL) + ip->i_flag |= IN_CHANGE | IN_UPDATE; + ext2_itimes(vp); + if (vap->va_atime.tv_sec != VNOVAL) { + ip->i_atime = vap->va_atime.tv_sec; + ip->i_atimensec = vap->va_atime.tv_nsec; + } + if (vap->va_mtime.tv_sec != VNOVAL) { + ip->i_mtime = vap->va_mtime.tv_sec; + ip->i_mtimensec = vap->va_mtime.tv_nsec; + } + error = ext2_update(vp, 0); + if (error) + return (error); + } + error = 0; + if (vap->va_mode != (mode_t)VNOVAL) { + if (vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + error = ext2_chmod(vp, (int)vap->va_mode, cred, td); + } + VN_KNOTE(vp, NOTE_ATTRIB); + return (error); +} + +/* + * Change the mode on a file. + * Inode must be locked before calling. + */ +static int +ext2_chmod(vp, mode, cred, td) + struct vnode *vp; + int mode; + struct ucred *cred; + struct thread *td; +{ + struct inode *ip = VTOI(vp); + int error; + + /* + * To modify the permissions on a file, must possess VADMIN + * for that file. + */ + if ((error = VOP_ACCESS(vp, VADMIN, cred, td))) + return (error); + /* + * Privileged processes may set the sticky bit on non-directories, + * as well as set the setgid bit on a file with a group that the + * process is not a member of. + */ + if (suser_cred(cred, PRISON_ROOT)) { + if (vp->v_type != VDIR && (mode & S_ISTXT)) + return (EFTYPE); + if (!groupmember(ip->i_gid, cred) && (mode & ISGID)) + return (EPERM); + } + ip->i_mode &= ~ALLPERMS; + ip->i_mode |= (mode & ALLPERMS); + ip->i_flag |= IN_CHANGE; + return (0); +} + +/* + * Perform chown operation on inode ip; + * inode must be locked prior to call. + */ +static int +ext2_chown(vp, uid, gid, cred, td) + struct vnode *vp; + uid_t uid; + gid_t gid; + struct ucred *cred; + struct thread *td; +{ + struct inode *ip = VTOI(vp); + uid_t ouid; + gid_t ogid; + int error = 0; + + if (uid == (uid_t)VNOVAL) + uid = ip->i_uid; + if (gid == (gid_t)VNOVAL) + gid = ip->i_gid; + /* + * To modify the ownership of a file, must possess VADMIN + * for that file. + */ + if ((error = VOP_ACCESS(vp, VADMIN, cred, td))) + return (error); + /* + * To change the owner of a file, or change the group of a file + * to a group of which we are not a member, the caller must + * have privilege. + */ + if ((uid != ip->i_uid || + (gid != ip->i_gid && !groupmember(gid, cred))) && + (error = suser_cred(cred, PRISON_ROOT))) + return (error); + ogid = ip->i_gid; + ouid = ip->i_uid; + ip->i_gid = gid; + ip->i_uid = uid; + ip->i_flag |= IN_CHANGE; + if (suser_cred(cred, PRISON_ROOT) && (ouid != uid || ogid != gid)) + ip->i_mode &= ~(ISUID | ISGID); + return (0); +} + /* * Synch an open file. */ @@ -241,7 +730,7 @@ loop: #endif } splx(s); - return (UFS_UPDATE(ap->a_vp, ap->a_waitfor == MNT_WAIT)); + return (ext2_update(ap->a_vp, ap->a_waitfor == MNT_WAIT)); } /* @@ -341,7 +830,7 @@ ext2_link(ap) #ifdef DIAGNOSTIC if ((cnp->cn_flags & HASBUF) == 0) - panic("ufs_link: no name"); + panic("ext2_link: no name"); #endif if (tdvp->v_mount != vp->v_mount) { error = EXDEV; @@ -361,7 +850,7 @@ ext2_link(ap) } ip->i_nlink++; ip->i_flag |= IN_CHANGE; - error = UFS_UPDATE(vp, 1); + error = ext2_update(vp, 1); if (!error) error = ext2_direnter(ip, tdvp, cnp); if (error) { @@ -406,7 +895,7 @@ ext2_rename(ap) #ifdef DIAGNOSTIC if ((tcnp->cn_flags & HASBUF) == 0 || (fcnp->cn_flags & HASBUF) == 0) - panic("ufs_rename: no name"); + panic("ext2_rename: no name"); #endif /* * Check for cross-device rename. @@ -447,7 +936,7 @@ abortit: * completed before the lookup. */ #ifdef UFS_RENAME_DEBUG - printf("ufs_rename: fvp == tvp for directories\n"); + printf("ext2_rename: fvp == tvp for directories\n"); #endif error = ENOENT; goto abortit; @@ -474,7 +963,7 @@ abortit: vrele(fdvp); if (fvp == NULL) { #ifdef UFS_RENAME_DEBUG - printf("ufs_rename: from name disappeared\n"); + printf("ext2_rename: from name disappeared\n"); #endif return (ENOENT); } @@ -536,7 +1025,7 @@ abortit: */ ip->i_nlink++; ip->i_flag |= IN_CHANGE; - if ((error = UFS_UPDATE(fvp, 1)) != 0) { + if ((error = ext2_update(fvp, 1)) != 0) { VOP_UNLOCK(fvp, 0, td); goto bad; } @@ -582,7 +1071,7 @@ abortit: */ if (xp == NULL) { if (dp->i_dev != ip->i_dev) - panic("ufs_rename: EXDEV"); + panic("ext2_rename: EXDEV"); /* * Account for ".." in new directory. * When source and destination have the same @@ -595,7 +1084,7 @@ abortit: } dp->i_nlink++; dp->i_flag |= IN_CHANGE; - error = UFS_UPDATE(tdvp, 1); + error = ext2_update(tdvp, 1); if (error) goto bad; } @@ -604,19 +1093,19 @@ abortit: if (doingdirectory && newparent) { dp->i_nlink--; dp->i_flag |= IN_CHANGE; - (void)UFS_UPDATE(tdvp, 1); + (void)ext2_update(tdvp, 1); } goto bad; } vput(tdvp); } else { if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) - panic("ufs_rename: EXDEV"); + panic("ext2_rename: EXDEV"); /* * Short circuit rename(foo, foo). */ if (xp->i_number == ip->i_number) - panic("ufs_rename: same file"); + panic("ext2_rename: same file"); /* * If the parent directory is "sticky", then the user must * own the parent directory, or the destination of the rename, @@ -676,8 +1165,8 @@ abortit: xp->i_nlink--; if (doingdirectory) { if (--xp->i_nlink != 0) - panic("ufs_rename: linked directory"); - error = UFS_TRUNCATE(tvp, (off_t)0, IO_SYNC, + panic("ext2_rename: linked directory"); + error = ext2_truncate(tvp, (off_t)0, IO_SYNC, tcnp->cn_cred, tcnp->cn_thread); } xp->i_flag |= IN_CHANGE; @@ -702,7 +1191,7 @@ abortit: * From name has disappeared. */ if (doingdirectory) - panic("ufs_rename: lost dir entry"); + panic("ext2_rename: lost dir entry"); vrele(ap->a_fvp); return (0); } @@ -718,7 +1207,7 @@ abortit: */ if (xp != ip) { if (doingdirectory) - panic("ufs_rename: lost dir entry"); + panic("ext2_rename: lost dir entry"); } else { /* * If the source is a directory with a @@ -739,7 +1228,7 @@ abortit: if (namlen != 2 || dirbuf.dotdot_name[0] != '.' || dirbuf.dotdot_name[1] != '.') { - ufs_dirbad(xp, (doff_t)12, + ext2_dirbad(xp, (doff_t)12, "rename: mangled dir"); } else { dirbuf.dotdot_ino = newparent; @@ -807,7 +1296,7 @@ ext2_mkdir(ap) #ifdef DIAGNOSTIC if ((cnp->cn_flags & HASBUF) == 0) - panic("ufs_mkdir: no name"); + panic("ext2_mkdir: no name"); #endif dp = VTOI(dvp); if ((nlink_t)dp->i_nlink >= LINK_MAX) { @@ -821,17 +1310,13 @@ ext2_mkdir(ap) * but not have it entered in the parent directory. The entry is * made later after writing "." and ".." entries. */ - error = UFS_VALLOC(dvp, dmode, cnp->cn_cred, &tvp); + error = ext2_valloc(dvp, dmode, cnp->cn_cred, &tvp); if (error) goto out; ip = VTOI(tvp); ip->i_gid = dp->i_gid; #ifdef SUIDDIR { -#ifdef QUOTA - struct ucred ucred, *ucp; - ucp = cnp->cn_cred; -#endif /* * if we are hacking owners here, (only do this where told to) * and we are not giving it TOO root, (would subvert quotas) @@ -844,44 +1329,12 @@ ext2_mkdir(ap) (dp->i_mode & ISUID) && dp->i_uid) { dmode |= ISUID; ip->i_uid = dp->i_uid; -#ifdef QUOTA - if (dp->i_uid != cnp->cn_cred->cr_uid) { - /* - * make sure the correct user gets charged - * for the space. - * Make a dummy credential for the victim. - * XXX This seems to never be accessed out of - * our context so a stack variable is ok. - */ - ucred.cr_ref = 1; - ucred.cr_uid = ip->i_uid; - ucred.cr_ngroups = 1; - ucred.cr_groups[0] = dp->i_gid; - ucp = &ucred; - } -#endif } else { ip->i_uid = cnp->cn_cred->cr_uid; } -#ifdef QUOTA - if ((error = getinoquota(ip)) || - (error = chkiq(ip, 1, ucp, 0))) { - UFS_VFREE(tvp, ip->i_number, dmode); - vput(tvp); - return (error); - } -#endif } #else ip->i_uid = cnp->cn_cred->cr_uid; -#ifdef QUOTA - if ((error = getinoquota(ip)) || - (error = chkiq(ip, 1, cnp->cn_cred, 0))) { - UFS_VFREE(tvp, ip->i_number, dmode); - vput(tvp); - return (error); - } -#endif #endif ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; ip->i_mode = dmode; @@ -889,7 +1342,7 @@ ext2_mkdir(ap) ip->i_nlink = 2; if (cnp->cn_flags & ISWHITEOUT) ip->i_flags |= UF_OPAQUE; - error = UFS_UPDATE(tvp, 1); + error = ext2_update(tvp, 1); /* * Bump link count in parent directory @@ -899,7 +1352,7 @@ ext2_mkdir(ap) */ dp->i_nlink++; dp->i_flag |= IN_CHANGE; - error = UFS_UPDATE(dvp, 1); + error = ext2_update(dvp, 1); if (error) goto bad; @@ -926,8 +1379,9 @@ ext2_mkdir(ap) dp->i_flag |= IN_CHANGE; goto bad; } - if (DIRBLKSIZ > VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize) - panic("ufs_mkdir: blksize"); /* XXX should grow with balloc() */ + if (DIRBLKSIZ > VFSTOEXT2(dvp->v_mount)->um_mountp->mnt_stat.f_bsize) + /* XXX should grow with balloc() */ + panic("ext2_mkdir: blksize"); else { ip->i_size = DIRBLKSIZ; ip->i_flag |= IN_CHANGE; @@ -1018,7 +1472,7 @@ ext2_rmdir(ap) * worry about them later. */ ip->i_nlink -= 2; - error = UFS_TRUNCATE(vp, (off_t)0, IO_SYNC, cnp->cn_cred, td); + error = ext2_truncate(vp, (off_t)0, IO_SYNC, cnp->cn_cred, td); cache_purge(ITOV(ip)); vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td); out: @@ -1062,6 +1516,362 @@ ext2_symlink(ap) return (error); } +/* + * Return target name of a symbolic link + */ +static int +ext2_readlink(ap) + struct vop_readlink_args /* { + struct vnode *a_vp; + struct uio *a_uio; + struct ucred *a_cred; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct inode *ip = VTOI(vp); + int isize; + + isize = ip->i_size; + if (isize < vp->v_mount->mnt_maxsymlinklen) { + uiomove((char *)ip->i_shortlink, isize, ap->a_uio); + return (0); + } + return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred)); +} + +/* + * Calculate the logical to physical mapping if not done already, + * then call the device strategy routine. + * + * In order to be able to swap to a file, the ext2_bmaparray() operation may not + * deadlock on memory. See ext2_bmap() for details. + */ +int +ext2_strategy(ap) + struct vop_strategy_args /* { + struct vnode *a_vp; + struct buf *a_bp; + } */ *ap; +{ + struct buf *bp = ap->a_bp; + struct vnode *vp = ap->a_vp; + struct inode *ip; + daddr_t blkno; + int error; + + ip = VTOI(vp); + if (vp->v_type == VBLK || vp->v_type == VCHR) + panic("ext2_strategy: spec"); + if (bp->b_blkno == bp->b_lblkno) { + error = ext2_bmaparray(vp, bp->b_lblkno, &blkno, NULL, NULL); + bp->b_blkno = blkno; + if (error) { + bp->b_error = error; + bp->b_ioflags |= BIO_ERROR; + bufdone(bp); + return (error); + } + if ((long)bp->b_blkno == -1) + vfs_bio_clrbuf(bp); + } + if ((long)bp->b_blkno == -1) { + bufdone(bp); + return (0); + } + vp = ip->i_devvp; + bp->b_dev = vp->v_rdev; + VOP_STRATEGY(vp, bp); + return (0); +} + +/* + * Print out the contents of an inode. + */ +int +ext2_print(ap) + struct vop_print_args /* { + struct vnode *a_vp; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct inode *ip = VTOI(vp); + + printf("tag VT_UFS, ino %lu, on dev %s (%d, %d)", + (u_long)ip->i_number, devtoname(ip->i_dev), major(ip->i_dev), + minor(ip->i_dev)); + if (vp->v_type == VFIFO) + fifo_printinfo(vp); + lockmgr_printinfo(&vp->v_lock); + printf("\n"); + return (0); +} + +/* + * Read wrapper for special devices. + */ +int +ext2spec_read(ap) + struct vop_read_args /* { + struct vnode *a_vp; + struct uio *a_uio; + int a_ioflag; + struct ucred *a_cred; + } */ *ap; +{ + int error, resid; + struct inode *ip; + struct uio *uio; + + uio = ap->a_uio; + resid = uio->uio_resid; + error = VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap); + /* + * The inode may have been revoked during the call, so it must not + * be accessed blindly here or in the other wrapper functions. + */ + ip = VTOI(ap->a_vp); + if (ip != NULL && (uio->uio_resid != resid || (error == 0 && resid != 0))) + ip->i_flag |= IN_ACCESS; + return (error); +} + +/* + * Write wrapper for special devices. + */ +int +ext2spec_write(ap) + struct vop_write_args /* { + struct vnode *a_vp; + struct uio *a_uio; + int a_ioflag; + struct ucred *a_cred; + } */ *ap; +{ + int error, resid; + struct inode *ip; + struct uio *uio; + + uio = ap->a_uio; + resid = uio->uio_resid; + error = VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap); + ip = VTOI(ap->a_vp); + if (ip != NULL && (uio->uio_resid != resid || (error == 0 && resid != 0))) + VTOI(ap->a_vp)->i_flag |= IN_CHANGE | IN_UPDATE; + return (error); +} + +/* + * Close wrapper for special devices. + * + * Update the times on the inode then do device close. + */ +int +ext2spec_close(ap) + struct vop_close_args /* { + struct vnode *a_vp; + int a_fflag; + struct ucred *a_cred; + struct thread *a_td; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + + mtx_lock(&vp->v_interlock); + if (vp->v_usecount > 1) + ext2_itimes(vp); + mtx_unlock(&vp->v_interlock); + return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap)); +} + +/* + * Read wrapper for fifos. + */ +int +ext2fifo_read(ap) + struct vop_read_args /* { + struct vnode *a_vp; + struct uio *a_uio; + int a_ioflag; + struct ucred *a_cred; + } */ *ap; +{ + int error, resid; + struct inode *ip; + struct uio *uio; + + uio = ap->a_uio; + resid = uio->uio_resid; + error = VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap); + ip = VTOI(ap->a_vp); + if ((ap->a_vp->v_mount->mnt_flag & MNT_NOATIME) == 0 && ip != NULL && + (uio->uio_resid != resid || (error == 0 && resid != 0))) + VTOI(ap->a_vp)->i_flag |= IN_ACCESS; + return (error); +} + +/* + * Write wrapper for fifos. + */ +int +ext2fifo_write(ap) + struct vop_write_args /* { + struct vnode *a_vp; + struct uio *a_uio; + int a_ioflag; + struct ucred *a_cred; + } */ *ap; +{ + int error, resid; + struct inode *ip; + struct uio *uio; + + uio = ap->a_uio; + resid = uio->uio_resid; + error = VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap); + ip = VTOI(ap->a_vp); + if (ip != NULL && (uio->uio_resid != resid || (error == 0 && resid != 0))) + VTOI(ap->a_vp)->i_flag |= IN_CHANGE | IN_UPDATE; + return (error); +} + +/* + * Close wrapper for fifos. + * + * Update the times on the inode then do device close. + */ +int +ext2fifo_close(ap) + struct vop_close_args /* { + struct vnode *a_vp; + int a_fflag; + struct ucred *a_cred; + struct thread *a_td; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + + mtx_lock(&vp->v_interlock); + if (vp->v_usecount > 1) + ext2_itimes(vp); + mtx_unlock(&vp->v_interlock); + return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap)); +} + +/* + * Kqfilter wrapper for fifos. + * + * Fall through to ext2 kqfilter routines if needed + */ +int +ext2fifo_kqfilter(ap) + struct vop_kqfilter_args *ap; +{ + int error; + + error = VOCALL(fifo_vnodeop_p, VOFFSET(vop_kqfilter), ap); + if (error) + error = ext2_kqfilter(ap); + return (error); +} + +/* + * Return POSIX pathconf information applicable to ext2 filesystems. + */ +int +ext2_pathconf(ap) + struct vop_pathconf_args /* { + struct vnode *a_vp; + int a_name; + int *a_retval; + } */ *ap; +{ + + switch (ap->a_name) { + case _PC_LINK_MAX: + *ap->a_retval = LINK_MAX; + return (0); + case _PC_NAME_MAX: + *ap->a_retval = NAME_MAX; + return (0); + case _PC_PATH_MAX: + *ap->a_retval = PATH_MAX; + return (0); + case _PC_PIPE_BUF: + *ap->a_retval = PIPE_BUF; + return (0); + case _PC_CHOWN_RESTRICTED: + *ap->a_retval = 1; + return (0); + case _PC_NO_TRUNC: + *ap->a_retval = 1; + return (0); + default: + return (EINVAL); + } + /* NOTREACHED */ +} + +/* + * Advisory record locking support + */ +static int +ext2_advlock(ap) + struct vop_advlock_args /* { + struct vnode *a_vp; + caddr_t a_id; + int a_op; + struct flock *a_fl; + int a_flags; + } */ *ap; +{ + struct inode *ip = VTOI(ap->a_vp); + + return (lf_advlock(ap, &(ip->i_lockf), ip->i_size)); +} + +/* + * Initialize the vnode associated with a new inode, handle aliased + * vnodes. + */ +int +ext2_vinit(mntp, specops, fifoops, vpp) + struct mount *mntp; + vop_t **specops; + vop_t **fifoops; + struct vnode **vpp; +{ + struct inode *ip; + struct vnode *vp; + struct timeval tv; + + vp = *vpp; + ip = VTOI(vp); + switch(vp->v_type = IFTOVT(ip->i_mode)) { + case VCHR: + case VBLK: + vp->v_op = specops; + vp = addaliasu(vp, ip->i_rdev); + ip->i_vnode = vp; + break; + case VFIFO: + vp->v_op = fifoops; + break; + default: + break; + + } + if (ip->i_number == ROOTINO) + vp->v_flag |= VROOT; + /* + * Initialize modrev times + */ + getmicrouptime(&tv); + SETHIGH(ip->i_modrev, tv.tv_sec); + SETLOW(ip->i_modrev, tv.tv_usec * 4294); + *vpp = vp; + return (0); +} + /* * Allocate a new inode. */ @@ -1085,7 +1895,7 @@ ext2_makeinode(mode, dvp, vpp, cnp) if ((mode & IFMT) == 0) mode |= IFREG; - error = UFS_VALLOC(dvp, mode, cnp->cn_cred, &tvp); + error = ext2_valloc(dvp, mode, cnp->cn_cred, &tvp); if (error) { return (error); } @@ -1093,10 +1903,6 @@ ext2_makeinode(mode, dvp, vpp, cnp) ip->i_gid = pdir->i_gid; #ifdef SUIDDIR { -#ifdef QUOTA - struct ucred ucred, *ucp; - ucp = cnp->cn_cred; -#endif /* * if we are * not the owner of the directory, @@ -1110,43 +1916,12 @@ ext2_makeinode(mode, dvp, vpp, cnp) (pdir->i_uid != cnp->cn_cred->cr_uid) && pdir->i_uid) { ip->i_uid = pdir->i_uid; mode &= ~07111; -#ifdef QUOTA - /* - * make sure the correct user gets charged - * for the space. - * Quickly knock up a dummy credential for the victim. - * XXX This seems to never be accessed out of our - * context so a stack variable is ok. - */ - ucred.cr_ref = 1; - ucred.cr_uid = ip->i_uid; - ucred.cr_ngroups = 1; - ucred.cr_groups[0] = pdir->i_gid; - ucp = &ucred; -#endif } else { ip->i_uid = cnp->cn_cred->cr_uid; } - -#ifdef QUOTA - if ((error = getinoquota(ip)) || - (error = chkiq(ip, 1, ucp, 0))) { - UFS_VFREE(tvp, ip->i_number, mode); - vput(tvp); - return (error); - } -#endif } #else ip->i_uid = cnp->cn_cred->cr_uid; -#ifdef QUOTA - if ((error = getinoquota(ip)) || - (error = chkiq(ip, 1, cnp->cn_cred, 0))) { - UFS_VFREE(tvp, ip->i_number, mode); - vput(tvp); - return (error); - } -#endif #endif ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; ip->i_mode = mode; @@ -1162,7 +1937,7 @@ ext2_makeinode(mode, dvp, vpp, cnp) /* * Make sure inode goes to disk before directory entry. */ - error = UFS_UPDATE(tvp, 1); + error = ext2_update(tvp, 1); if (error) goto bad; error = ext2_direnter(ip, dvp, cnp); @@ -1182,3 +1957,106 @@ bad: vput(tvp); return (error); } + +static struct filterops ext2read_filtops = + { 1, NULL, filt_ext2detach, filt_ext2read }; +static struct filterops ext2write_filtops = + { 1, NULL, filt_ext2detach, filt_ext2write }; +static struct filterops ext2vnode_filtops = + { 1, NULL, filt_ext2detach, filt_ext2vnode }; + +static int +ext2_kqfilter(ap) + struct vop_kqfilter_args /* { + struct vnode *a_vp; + struct knote *a_kn; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct knote *kn = ap->a_kn; + + switch (kn->kn_filter) { + case EVFILT_READ: + kn->kn_fop = &ext2read_filtops; + break; + case EVFILT_WRITE: + kn->kn_fop = &ext2write_filtops; + break; + case EVFILT_VNODE: + kn->kn_fop = &ext2vnode_filtops; + break; + default: + return (1); + } + + kn->kn_hook = (caddr_t)vp; + + if (vp->v_pollinfo == NULL) + v_addpollinfo(vp); + mtx_lock(&vp->v_pollinfo->vpi_lock); + SLIST_INSERT_HEAD(&vp->v_pollinfo->vpi_selinfo.si_note, kn, kn_selnext); + mtx_unlock(&vp->v_pollinfo->vpi_lock); + + return (0); +} + +static void +filt_ext2detach(struct knote *kn) +{ + struct vnode *vp = (struct vnode *)kn->kn_hook; + + KASSERT(vp->v_pollinfo != NULL, ("Mising v_pollinfo")); + mtx_lock(&vp->v_pollinfo->vpi_lock); + SLIST_REMOVE(&vp->v_pollinfo->vpi_selinfo.si_note, + kn, knote, kn_selnext); + mtx_unlock(&vp->v_pollinfo->vpi_lock); +} + +/*ARGSUSED*/ +static int +filt_ext2read(struct knote *kn, long hint) +{ + struct vnode *vp = (struct vnode *)kn->kn_hook; + struct inode *ip = VTOI(vp); + + /* + * filesystem is gone, so set the EOF flag and schedule + * the knote for deletion. + */ + if (hint == NOTE_REVOKE) { + kn->kn_flags |= (EV_EOF | EV_ONESHOT); + return (1); + } + + kn->kn_data = ip->i_size - kn->kn_fp->f_offset; + return (kn->kn_data != 0); +} + +/*ARGSUSED*/ +static int +filt_ext2write(struct knote *kn, long hint) +{ + + /* + * filesystem is gone, so set the EOF flag and schedule + * the knote for deletion. + */ + if (hint == NOTE_REVOKE) + kn->kn_flags |= (EV_EOF | EV_ONESHOT); + + kn->kn_data = 0; + return (1); +} + +static int +filt_ext2vnode(struct knote *kn, long hint) +{ + + if (kn->kn_sfflags & hint) + kn->kn_fflags |= hint; + if (hint == NOTE_REVOKE) { + kn->kn_flags |= EV_EOF; + return (1); + } + return (kn->kn_fflags != 0); +} diff --git a/sys/gnu/ext2fs/fs.h b/sys/gnu/ext2fs/fs.h index 785f267f8ac3..50fb711f371f 100644 --- a/sys/gnu/ext2fs/fs.h +++ b/sys/gnu/ext2fs/fs.h @@ -148,7 +148,7 @@ extern u_char *fragtbl[]; * I haven't figured out yet what BSD does * I think I'll try a VOP_LOCK/VOP_UNLOCK on the device vnode */ -#define DEVVP(inode) (VFSTOUFS(ITOV(inode)->v_mount)->um_devvp) +#define DEVVP(inode) (VFSTOEXT2(ITOV(inode)->v_mount)->um_devvp) #define lock_super(devvp) vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, curthread) #define unlock_super(devvp) VOP_UNLOCK(devvp, 0, curthread) diff --git a/sys/gnu/fs/ext2fs/ext2_alloc.c b/sys/gnu/fs/ext2fs/ext2_alloc.c index b9c40d37b9e1..585c5cdb4632 100644 --- a/sys/gnu/fs/ext2fs/ext2_alloc.c +++ b/sys/gnu/fs/ext2fs/ext2_alloc.c @@ -40,8 +40,6 @@ * $FreeBSD$ */ -#include "opt_quota.h" - #include <sys/param.h> #include <sys/systm.h> #include <sys/conf.h> @@ -50,11 +48,8 @@ #include <sys/mount.h> #include <sys/syslog.h> -#include <ufs/ufs/extattr.h> -#include <ufs/ufs/quota.h> -#include <ufs/ufs/inode.h> -#include <ufs/ufs/ufsmount.h> - +#include <gnu/ext2fs/inode.h> +#include <gnu/ext2fs/ext2_mount.h> #include <gnu/ext2fs/ext2_fs.h> #include <gnu/ext2fs/ext2_fs_sb.h> #include <gnu/ext2fs/fs.h> @@ -108,9 +103,6 @@ ext2_alloc(ip, lbn, bpref, size, cred, bnp) { register struct ext2_sb_info *fs; daddr_t bno; -#if QUOTA - int error; -#endif *bnp = 0; fs = ip->i_e2fs; @@ -128,10 +120,6 @@ ext2_alloc(ip, lbn, bpref, size, cred, bnp) if (cred->cr_uid != 0 && fs->s_es->s_free_blocks_count < fs->s_es->s_r_blocks_count) goto nospace; -#if QUOTA - if ((error = chkdq(ip, (long)btodb(size), cred, 0)) != 0) - return (error); -#endif if (bpref >= fs->s_es->s_blocks_count) bpref = 0; /* call the Linux code */ @@ -179,12 +167,6 @@ ext2_alloc(ip, lbn, bpref, size, cred, bnp) *bnp = bno; return (0); } -#if QUOTA - /* - * Restore user's disk quota because allocation failed. - */ - (void) chkdq(ip, (long)-btodb(size), cred, FORCE); -#endif nospace: ext2_fserr(fs, cred->cr_uid, "file system full"); uprintf("\n%s: write failed, file system is full\n", fs->fs_fsmnt); @@ -342,7 +324,7 @@ return ENOSPC; } else { ip->i_flag |= IN_CHANGE | IN_UPDATE; if (!doasyncfree) - UFS_UPDATE(vp, 1); + ext2_update(vp, 1); } if (ssize < len) if (doasyncfree) @@ -401,7 +383,7 @@ ext2_valloc(pvp, mode, cred, vpp) goto noinodes; error = VFS_VGET(pvp->v_mount, ino, LK_EXCLUSIVE, vpp); if (error) { - UFS_VFREE(pvp, ino, mode); + ext2_vfree(pvp, ino, mode); return (error); } ip = VTOI(*vpp); diff --git a/sys/gnu/fs/ext2fs/ext2_balloc.c b/sys/gnu/fs/ext2fs/ext2_balloc.c index 275849fcec52..252a29792527 100644 --- a/sys/gnu/fs/ext2fs/ext2_balloc.c +++ b/sys/gnu/fs/ext2fs/ext2_balloc.c @@ -48,10 +48,7 @@ #include <sys/ucred.h> #include <sys/vnode.h> -#include <ufs/ufs/quota.h> -#include <ufs/ufs/inode.h> -#include <ufs/ufs/ufs_extern.h> - +#include <gnu/ext2fs/inode.h> #include <gnu/ext2fs/ext2_fs.h> #include <gnu/ext2fs/ext2_fs_sb.h> #include <gnu/ext2fs/fs.h> @@ -164,11 +161,11 @@ ext2_debug("ext2_balloc called (%d, %d, %d)\n", * Determine the number of levels of indirection. */ pref = 0; - if ((error = ufs_getlbns(vp, bn, indirs, &num)) != 0) + if ((error = ext2_getlbns(vp, bn, indirs, &num)) != 0) return(error); #if DIAGNOSTIC if (num < 1) - panic ("ext2_balloc: ufs_getlbns returned indirect block"); + panic ("ext2_balloc: ext2_getlbns returned indirect block"); #endif /* * Fetch the first indirect block allocating if necessary. diff --git a/sys/gnu/fs/ext2fs/ext2_extern.h b/sys/gnu/fs/ext2fs/ext2_extern.h index 8df829b369a7..505fefd97c56 100644 --- a/sys/gnu/fs/ext2fs/ext2_extern.h +++ b/sys/gnu/fs/ext2fs/ext2_extern.h @@ -43,8 +43,8 @@ #ifndef _SYS_GNU_EXT2FS_EXT2_EXTERN_H_ #define _SYS_GNU_EXT2FS_EXT2_EXTERN_H_ -struct dinode; struct ext2_inode; +struct indir; struct inode; struct mount; struct vfsconf; @@ -58,7 +58,18 @@ int ext2_blkatoff(struct vnode *, off_t, char **, struct buf **); void ext2_blkfree(struct inode *, daddr_t, long); daddr_t ext2_blkpref(struct inode *, daddr_t, int, daddr_t *, daddr_t); int ext2_bmap(struct vop_bmap_args *); -int ext2_init(struct vfsconf *); +int ext2_bmaparray(struct vnode *, daddr_t, daddr_t *, int *, int *); +void ext2_dirbad(struct inode *ip, doff_t offset, char *how); +void ext2_ei2i(struct ext2_inode *, struct inode *); +int ext2_getlbns(struct vnode *, daddr_t, struct indir *, int *); +void ext2_i2ei(struct inode *, struct ext2_inode *); +int ext2_ihashget(dev_t, ino_t, int, struct vnode **); +void ext2_ihashinit(void); +void ext2_ihashins(struct inode *); +struct vnode * + ext2_ihashlookup(dev_t, ino_t); +void ext2_ihashrem(struct inode *); +void ext2_itimes(struct vnode *vp); int ext2_reallocblks(struct vop_reallocblks_args *); int ext2_reclaim(struct vop_reclaim_args *); void ext2_setblock(struct ext2_sb_info *, u_char *, daddr_t); @@ -66,9 +77,9 @@ int ext2_truncate(struct vnode *, off_t, int, struct ucred *, struct thread *); int ext2_update(struct vnode *, int); int ext2_valloc(struct vnode *, int, struct ucred *, struct vnode **); int ext2_vfree(struct vnode *, ino_t, int); +int ext2_vinit(struct mount *, vop_t **, vop_t **, struct vnode **vpp); int ext2_lookup(struct vop_cachedlookup_args *); int ext2_readdir(struct vop_readdir_args *); -void ext2_print_dinode(struct dinode *); void ext2_print_inode(struct inode *); int ext2_direnter(struct inode *, struct vnode *, struct componentname *); @@ -89,15 +100,13 @@ unsigned long ext2_count_free(struct buf *map, unsigned int numchars); void ext2_free_blocks(struct mount *mp, unsigned long block, unsigned long count); void ext2_free_inode(struct inode * inode); -void ext2_ei2di(struct ext2_inode *ei, struct dinode *di); -void ext2_di2ei(struct dinode *di, struct ext2_inode *ei); void mark_buffer_dirty(struct buf *bh); -/* - * This macro allows the ufs code to distinguish between an EXT2 and a - * non-ext2(FFS/LFS) vnode. - */ -#define IS_EXT2_VNODE(vp) (vp->v_mount->mnt_stat.f_type == MOUNT_EXT2FS) +/* Flags to low-level allocation routines. */ +#define B_CLRBUF 0x01 /* Request allocated buffer be cleared. */ +#define B_SYNC 0x02 /* Do all allocations synchronously. */ +#define B_METAONLY 0x04 /* Return indirect block buffer. */ +#define B_NOWAIT 0x08 /* do not sleep to await lock */ extern vop_t **ext2_vnodeop_p; extern vop_t **ext2_specop_p; diff --git a/sys/gnu/fs/ext2fs/ext2_fs.h b/sys/gnu/fs/ext2fs/ext2_fs.h index b5e9f4a92573..29435937181b 100644 --- a/sys/gnu/fs/ext2fs/ext2_fs.h +++ b/sys/gnu/fs/ext2fs/ext2_fs.h @@ -38,19 +38,6 @@ #define umode_t mode_t #define loff_t off_t -/* the Linux implementation of EXT2 stores some information about - * an inode in a ext2_inode_info structure which is part of the incore - * inode in Linux - * I decided to use the "spare" fields instead - we'll see how this - * works out - */ - -#define i_block_group i_spare[0] -#define i_next_alloc_block i_spare[1] -#define i_next_alloc_goal i_spare[2] -#define i_prealloc_block i_din.di_spare[0] -#define i_prealloc_count i_din.di_spare[1] - /* * The second extended filesystem constants/structures */ @@ -263,14 +250,6 @@ struct ext2_group_desc #define EXT2_IOC_GETVERSION _IOR('v', 1, long) #define EXT2_IOC_SETVERSION _IOW('v', 2, long) -/* - * Only declare `struct ext2_inode' if <ufs/ufs/inode.h> hasn't made things - * difficult by #defining i_mode and other struct members. The details of - * the struct are only needed in ext2_inode_cnv.c where the ext2fs on-disk - * inode is converted to a ufs in-core inode. - */ -#ifndef i_mode - /* * Structure of an inode on the disk */ @@ -351,8 +330,6 @@ struct ext2_inode { #define i_reserved2 osd2.masix2.m_i_reserved2 #endif -#endif /* i_mode */ - /* * File system states */ diff --git a/sys/gnu/fs/ext2fs/ext2_inode.c b/sys/gnu/fs/ext2fs/ext2_inode.c index 2f0aed472f09..207778c84f88 100644 --- a/sys/gnu/fs/ext2fs/ext2_inode.c +++ b/sys/gnu/fs/ext2fs/ext2_inode.c @@ -40,8 +40,6 @@ * $FreeBSD$ */ -#include "opt_quota.h" - #include <sys/param.h> #include <sys/systm.h> #include <sys/mount.h> @@ -53,12 +51,8 @@ #include <vm/vm.h> #include <vm/vm_extern.h> -#include <ufs/ufs/extattr.h> -#include <ufs/ufs/quota.h> -#include <ufs/ufs/inode.h> -#include <ufs/ufs/ufsmount.h> -#include <ufs/ufs/ufs_extern.h> - +#include <gnu/ext2fs/inode.h> +#include <gnu/ext2fs/ext2_mount.h> #include <gnu/ext2fs/ext2_fs.h> #include <gnu/ext2fs/ext2_fs_sb.h> #include <gnu/ext2fs/fs.h> @@ -67,12 +61,6 @@ static int ext2_indirtrunc(struct inode *, daddr_t, daddr_t, daddr_t, int, long *); -int -ext2_init(struct vfsconf *vfsp) -{ - return (ufs_init(vfsp)); -} - /* * Update the access, modified, and inode change times as specified by the * IN_ACCESS, IN_UPDATE, and IN_CHANGE flags respectively. Write the inode @@ -92,7 +80,7 @@ ext2_update(vp, waitfor) struct inode *ip; int error; - ufs_itimes(vp); + ext2_itimes(vp); ip = VTOI(vp); if ((ip->i_flag & IN_MODIFIED) == 0) return (0); @@ -106,8 +94,8 @@ ext2_update(vp, waitfor) brelse(bp); return (error); } - ext2_di2ei( &ip->i_din, (struct ext2_inode *) ((char *)bp->b_data + EXT2_INODE_SIZE * - ino_to_fsbo(fs, ip->i_number))); + ext2_i2ei(ip, (struct ext2_inode *)((char *)bp->b_data + + EXT2_INODE_SIZE * ino_to_fsbo(fs, ip->i_number))); /* if (waitfor && (vp->v_mount->mnt_flag & MNT_ASYNC) == 0) return (bwrite(bp)); @@ -166,16 +154,12 @@ printf("ext2_truncate called %d to %d\n", VTOI(ovp)->i_number, length); bzero((char *)&oip->i_shortlink, (u_int)oip->i_size); oip->i_size = 0; oip->i_flag |= IN_CHANGE | IN_UPDATE; - return (UFS_UPDATE(ovp, 1)); + return (ext2_update(ovp, 1)); } if (oip->i_size == length) { oip->i_flag |= IN_CHANGE | IN_UPDATE; - return (UFS_UPDATE(ovp, 0)); + return (ext2_update(ovp, 0)); } -#if QUOTA - if ((error = getinoquota(oip)) != 0) - return (error); -#endif fs = oip->i_e2fs; osize = oip->i_size; ext2_discard_prealloc(oip); @@ -200,7 +184,7 @@ printf("ext2_truncate called %d to %d\n", VTOI(ovp)->i_number, length); else bawrite(bp); oip->i_flag |= IN_CHANGE | IN_UPDATE; - return (UFS_UPDATE(ovp, 1)); + return (ext2_update(ovp, 1)); } /* * Shorten the size of the file. If the file is not being @@ -256,7 +240,7 @@ printf("ext2_truncate called %d to %d\n", VTOI(ovp)->i_number, length); for (i = NDADDR - 1; i > lastblock; i--) oip->i_db[i] = 0; oip->i_flag |= IN_CHANGE | IN_UPDATE; - allerror = UFS_UPDATE(ovp, 1); + allerror = ext2_update(ovp, 1); /* * Having written the new inode to disk, save its new configuration @@ -361,9 +345,6 @@ done: oip->i_blocks = 0; oip->i_flag |= IN_CHANGE; vnode_pager_setsize(ovp, length); -#if QUOTA - (void) chkdq(oip, -blocksreleased, NOCRED, 0); -#endif return (allerror); } @@ -488,9 +469,86 @@ int ext2_inactive(ap) struct vop_inactive_args /* { struct vnode *a_vp; + struct thread *a_td; } */ *ap; { - ext2_discard_prealloc(VTOI(ap->a_vp)); - return ufs_inactive(ap); + struct vnode *vp = ap->a_vp; + struct inode *ip = VTOI(vp); + struct thread *td = ap->a_td; + int mode, error = 0; + + ext2_discard_prealloc(ip); + if (prtactive && vp->v_usecount != 0) + vprint("ext2_inactive: pushing active", vp); + + /* + * Ignore inodes related to stale file handles. + */ + if (ip->i_mode == 0) + goto out; + if (ip->i_nlink <= 0) { + (void) vn_write_suspend_wait(vp, NULL, V_WAIT); + error = ext2_truncate(vp, (off_t)0, 0, NOCRED, td); + ip->i_rdev = 0; + mode = ip->i_mode; + ip->i_mode = 0; + ip->i_flag |= IN_CHANGE | IN_UPDATE; + ext2_vfree(vp, ip->i_number, mode); + } + if (ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) { + if ((ip->i_flag & (IN_CHANGE | IN_UPDATE | IN_MODIFIED)) == 0 && + vn_write_suspend_wait(vp, NULL, V_NOWAIT)) { + ip->i_flag &= ~IN_ACCESS; + } else { + (void) vn_write_suspend_wait(vp, NULL, V_WAIT); + ext2_update(vp, 0); + } + } +out: + VOP_UNLOCK(vp, 0, td); + /* + * If we are done with the inode, reclaim it + * so that it can be reused immediately. + */ + if (ip->i_mode == 0) + vrecycle(vp, NULL, td); + return (error); } +/* + * Reclaim an inode so that it can be used for other purposes. + */ +int +ext2_reclaim(ap) + struct vop_reclaim_args /* { + struct vnode *a_vp; + struct thread *a_td; + } */ *ap; +{ + struct inode *ip; + struct vnode *vp = ap->a_vp; + + if (prtactive && vp->v_usecount != 0) + vprint("ufs_reclaim: pushing active", vp); + ip = VTOI(vp); + if (ip->i_flag & IN_LAZYMOD) { + ip->i_flag |= IN_MODIFIED; + ext2_update(vp, 0); + } + /* + * Remove the inode from its hash chain. + */ + ext2_ihashrem(ip); + /* + * Purge old data structures associated with the inode. + */ + cache_purge(vp); + if (ip->i_devvp) { + vrele(ip->i_devvp); + ip->i_devvp = 0; + } + lockdestroy(&vp->v_lock); + FREE(vp->v_data, M_EXT2NODE); + vp->v_data = 0; + return (0); +} diff --git a/sys/gnu/fs/ext2fs/ext2_inode_cnv.c b/sys/gnu/fs/ext2fs/ext2_inode_cnv.c index 3e8e0ff73445..d64e5498776b 100644 --- a/sys/gnu/fs/ext2fs/ext2_inode_cnv.c +++ b/sys/gnu/fs/ext2fs/ext2_inode_cnv.c @@ -23,7 +23,7 @@ */ /* - * routines to convert on disk ext2 inodes in dinodes and back + * routines to convert on disk ext2 inodes into inodes and back */ #include <sys/param.h> #include <sys/systm.h> @@ -31,130 +31,101 @@ #include <sys/stat.h> #include <sys/vnode.h> -#include <ufs/ufs/quota.h> -#include <ufs/ufs/inode.h> - -/* - * Undo the definitions in <ufs/ufs/inode.h> that would destroy the include - * of <gnu/ext2fs/ext2_fs.h>. - */ -#undef i_atime -#undef i_blocks -#undef i_ctime -#undef i_db -#undef i_flags -#undef i_gen -#undef i_gid -#undef i_ib -#undef i_mode -#undef i_mtime -#undef i_nlink -#undef i_rdev -#undef i_shortlink -#undef i_size -#undef i_uid - +#include <gnu/ext2fs/inode.h> #include <gnu/ext2fs/ext2_fs.h> #include <gnu/ext2fs/ext2_extern.h> -void -ext2_print_dinode( di ) - struct dinode *di; -{ - int i; - printf( /* "Inode: %5d" */ - " Type: %10s Mode: 0x%o Flags: 0x%x Version: %d\n", - "n/a", di->di_mode, di->di_flags, di->di_gen); - printf( "User: %5lu Group: %5lu Size: %lu\n", - (unsigned long)di->di_uid, (unsigned long)di->di_gid, - (unsigned long)di->di_size); - printf( "Links: %3d Blockcount: %d\n", - di->di_nlink, di->di_blocks); - printf( "ctime: 0x%x", di->di_ctime); - printf( "atime: 0x%x", di->di_atime); - printf( "mtime: 0x%x", di->di_mtime); - printf( "BLOCKS: "); - for(i=0; i < (di->di_blocks <= 24 ? ((di->di_blocks+1)/2): 12); i++) - printf("%d ", di->di_db[i]); - printf("\n"); -} - void ext2_print_inode( in ) struct inode *in; { + int i; + printf( "Inode: %5d", in->i_number); - ext2_print_dinode(&in->i_din); + printf( /* "Inode: %5d" */ + " Type: %10s Mode: 0x%o Flags: 0x%x Version: %d\n", + "n/a", in->i_mode, in->i_flags, in->i_gen); + printf( "User: %5lu Group: %5lu Size: %lu\n", + (unsigned long)in->i_uid, (unsigned long)in->i_gid, + (unsigned long)in->i_size); + printf( "Links: %3d Blockcount: %d\n", + in->i_nlink, in->i_blocks); + printf( "ctime: 0x%x", in->i_ctime); + printf( "atime: 0x%x", in->i_atime); + printf( "mtime: 0x%x", in->i_mtime); + printf( "BLOCKS: "); + for(i=0; i < (in->i_blocks <= 24 ? ((in->i_blocks+1)/2): 12); i++) + printf("%d ", in->i_db[i]); + printf("\n"); } /* - * raw ext2 inode to dinode + * raw ext2 inode to inode */ void -ext2_ei2di(ei, di) - struct ext2_inode *ei; - struct dinode *di; +ext2_ei2i(ei, ip) + struct ext2_inode *ei; + struct inode *ip; { - int i; + int i; - di->di_nlink = ei->i_links_count; + ip->i_nlink = ei->i_links_count; /* Godmar thinks - if the link count is zero, then the inode is unused - according to ext2 standards. Ufs marks this fact by setting i_mode to zero - why ? I can see that this might lead to problems in an undelete. */ - di->di_mode = ei->i_links_count ? ei->i_mode : 0; - di->di_size = ei->i_size; - di->di_atime = ei->i_atime; - di->di_mtime = ei->i_mtime; - di->di_ctime = ei->i_ctime; - di->di_flags = 0; - di->di_flags |= (ei->i_flags & EXT2_APPEND_FL) ? APPEND : 0; - di->di_flags |= (ei->i_flags & EXT2_IMMUTABLE_FL) ? IMMUTABLE : 0; - di->di_blocks = ei->i_blocks; - di->di_gen = ei->i_generation; - di->di_uid = ei->i_uid; - di->di_gid = ei->i_gid; + ip->i_mode = ei->i_links_count ? ei->i_mode : 0; + ip->i_size = ei->i_size; + ip->i_atime = ei->i_atime; + ip->i_mtime = ei->i_mtime; + ip->i_ctime = ei->i_ctime; + ip->i_flags = 0; + ip->i_flags |= (ei->i_flags & EXT2_APPEND_FL) ? APPEND : 0; + ip->i_flags |= (ei->i_flags & EXT2_IMMUTABLE_FL) ? IMMUTABLE : 0; + ip->i_blocks = ei->i_blocks; + ip->i_gen = ei->i_generation; + ip->i_uid = ei->i_uid; + ip->i_gid = ei->i_gid; /* XXX use memcpy */ - for(i = 0; i < NDADDR; i++) - di->di_db[i] = ei->i_block[i]; - for(i = 0; i < NIADDR; i++) - di->di_ib[i] = ei->i_block[EXT2_NDIR_BLOCKS + i]; + for(i = 0; i < NDADDR; i++) + ip->i_db[i] = ei->i_block[i]; + for(i = 0; i < NIADDR; i++) + ip->i_ib[i] = ei->i_block[EXT2_NDIR_BLOCKS + i]; } /* - * dinode to raw ext2 inode + * inode to raw ext2 inode */ void -ext2_di2ei(di, ei) - struct dinode *di; - struct ext2_inode *ei; +ext2_i2ei(ip, ei) + struct inode *ip; + struct ext2_inode *ei; { - int i; + int i; - ei->i_mode = di->di_mode; - ei->i_links_count = di->di_nlink; + ei->i_mode = ip->i_mode; + ei->i_links_count = ip->i_nlink; /* Godmar thinks: if dtime is nonzero, ext2 says this inode has been deleted, this would correspond to a zero link count */ - ei->i_dtime = ei->i_links_count ? 0 : di->di_mtime; - ei->i_size = di->di_size; - ei->i_atime = di->di_atime; - ei->i_mtime = di->di_mtime; - ei->i_ctime = di->di_ctime; - ei->i_flags = di->di_flags; - ei->i_flags = 0; - ei->i_flags |= (di->di_flags & APPEND) ? EXT2_APPEND_FL: 0; - ei->i_flags |= (di->di_flags & IMMUTABLE) - ? EXT2_IMMUTABLE_FL: 0; - ei->i_blocks = di->di_blocks; - ei->i_generation = di->di_gen; - ei->i_uid = di->di_uid; - ei->i_gid = di->di_gid; + ei->i_dtime = ei->i_links_count ? 0 : ip->i_mtime; + ei->i_size = ip->i_size; + ei->i_atime = ip->i_atime; + ei->i_mtime = ip->i_mtime; + ei->i_ctime = ip->i_ctime; + ei->i_flags = ip->i_flags; + ei->i_flags = 0; + ei->i_flags |= (ip->i_flags & APPEND) ? EXT2_APPEND_FL: 0; + ei->i_flags |= (ip->i_flags & IMMUTABLE) ? EXT2_IMMUTABLE_FL: 0; + ei->i_blocks = ip->i_blocks; + ei->i_generation = ip->i_gen; + ei->i_uid = ip->i_uid; + ei->i_gid = ip->i_gid; /* XXX use memcpy */ - for(i = 0; i < NDADDR; i++) - ei->i_block[i] = di->di_db[i]; - for(i = 0; i < NIADDR; i++) - ei->i_block[EXT2_NDIR_BLOCKS + i] = di->di_ib[i]; + for(i = 0; i < NDADDR; i++) + ei->i_block[i] = ip->i_db[i]; + for(i = 0; i < NIADDR; i++) + ei->i_block[EXT2_NDIR_BLOCKS + i] = ip->i_ib[i]; } diff --git a/sys/gnu/fs/ext2fs/ext2_linux_balloc.c b/sys/gnu/fs/ext2fs/ext2_linux_balloc.c index fc723114dfa6..632044009643 100644 --- a/sys/gnu/fs/ext2fs/ext2_linux_balloc.c +++ b/sys/gnu/fs/ext2fs/ext2_linux_balloc.c @@ -35,9 +35,8 @@ #include <sys/mount.h> #include <sys/vnode.h> -#include <ufs/ufs/extattr.h> -#include <ufs/ufs/quota.h> -#include <ufs/ufs/ufsmount.h> +#include <gnu/ext2fs/inode.h> +#include <gnu/ext2fs/ext2_mount.h> #include <gnu/ext2fs/ext2_extern.h> #include <gnu/ext2fs/ext2_fs.h> #include <gnu/ext2fs/ext2_fs_sb.h> @@ -61,13 +60,13 @@ static void read_block_bitmap (struct mount * mp, unsigned int block_group, unsigned long bitmap_nr) { - struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs; + struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs; struct ext2_group_desc * gdp; struct buffer_head * bh; int error; gdp = get_group_desc (mp, block_group, NULL); - if ((error = bread (VFSTOUFS(mp)->um_devvp, + if ((error = bread (VFSTOEXT2(mp)->um_devvp, fsbtodb(sb, gdp->bg_block_bitmap),sb->s_blocksize, NOCRED, &bh)) != 0) panic ( "read_block_bitmap: " "Cannot read block bitmap - " @@ -93,7 +92,7 @@ static int load__block_bitmap (struct mount * mp, unsigned int block_group) { int i, j; - struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs; + struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs; unsigned long block_bitmap_number; struct buffer_head * block_bitmap; @@ -152,7 +151,7 @@ static int load__block_bitmap (struct mount * mp, static __inline int load_block_bitmap (struct mount * mp, unsigned int block_group) { - struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs; + struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs; if (sb->s_loaded_block_bitmaps > 0 && sb->s_block_bitmap_number[0] == block_group) return 0; @@ -168,7 +167,7 @@ static __inline int load_block_bitmap (struct mount * mp, void ext2_free_blocks (struct mount * mp, unsigned long block, unsigned long count) { - struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs; + struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs; struct buffer_head * bh; struct buffer_head * bh2; unsigned long block_group; @@ -182,13 +181,13 @@ void ext2_free_blocks (struct mount * mp, unsigned long block, printf ("ext2_free_blocks: nonexistent device"); return; } - lock_super (VFSTOUFS(mp)->um_devvp); + lock_super (VFSTOEXT2(mp)->um_devvp); if (block < es->s_first_data_block || (block + count) > es->s_blocks_count) { printf ( "ext2_free_blocks: " "Freeing blocks not in datazone - " "block = %lu, count = %lu", block, count); - unlock_super (VFSTOUFS(mp)->um_devvp); + unlock_super (VFSTOEXT2(mp)->um_devvp); return; } @@ -238,7 +237,7 @@ void ext2_free_blocks (struct mount * mp, unsigned long block, } ****/ sb->s_dirt = 1; - unlock_super (VFSTOUFS(mp)->um_devvp); + unlock_super (VFSTOEXT2(mp)->um_devvp); return; } @@ -253,7 +252,7 @@ int ext2_new_block (struct mount * mp, unsigned long goal, u_int32_t * prealloc_count, u_int32_t * prealloc_block) { - struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs; + struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs; struct buffer_head * bh; struct buffer_head * bh2; char * p, * r; @@ -269,7 +268,7 @@ int ext2_new_block (struct mount * mp, unsigned long goal, printf ("ext2_new_block: nonexistent device"); return 0; } - lock_super (VFSTOUFS(mp)->um_devvp); + lock_super (VFSTOEXT2(mp)->um_devvp); ext2_debug ("goal=%lu.\n", goal); @@ -356,7 +355,7 @@ repeat: break; } if (k >= sb->s_groups_count) { - unlock_super (VFSTOUFS(mp)->um_devvp); + unlock_super (VFSTOEXT2(mp)->um_devvp); return 0; } bitmap_nr = load_block_bitmap (mp, i); @@ -372,7 +371,7 @@ repeat: if (j >= EXT2_BLOCKS_PER_GROUP(sb)) { printf ( "ext2_new_block: " "Free blocks count corrupted for block group %d", i); - unlock_super (VFSTOUFS(mp)->um_devvp); + unlock_super (VFSTOEXT2(mp)->um_devvp); return 0; } @@ -439,7 +438,7 @@ got_block: printf ( "ext2_new_block: " "block >= blocks count - " "block_group = %d, block=%d", i, j); - unlock_super (VFSTOUFS(mp)->um_devvp); + unlock_super (VFSTOEXT2(mp)->um_devvp); return 0; } @@ -450,14 +449,14 @@ got_block: mark_buffer_dirty(bh2); es->s_free_blocks_count--; sb->s_dirt = 1; - unlock_super (VFSTOUFS(mp)->um_devvp); + unlock_super (VFSTOEXT2(mp)->um_devvp); return j; } #ifdef unused static unsigned long ext2_count_free_blocks (struct mount * mp) { - struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs; + struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs; #ifdef EXT2FS_DEBUG struct ext2_super_block * es; unsigned long desc_count, bitmap_count, x; @@ -465,7 +464,7 @@ static unsigned long ext2_count_free_blocks (struct mount * mp) struct ext2_group_desc * gdp; int i; - lock_super (VFSTOUFS(mp)->um_devvp); + lock_super (VFSTOEXT2(mp)->um_devvp); es = sb->s_es; desc_count = 0; bitmap_count = 0; @@ -482,7 +481,7 @@ static unsigned long ext2_count_free_blocks (struct mount * mp) } ext2_debug( "stored = %lu, computed = %lu, %lu\n", es->s_free_blocks_count, desc_count, bitmap_count); - unlock_super (VFSTOUFS(mp)->um_devvp); + unlock_super (VFSTOEXT2(mp)->um_devvp); return bitmap_count; #else return sb->s_es->s_free_blocks_count; @@ -520,7 +519,7 @@ int ext2_group_sparse(int group) #ifdef unused static void ext2_check_blocks_bitmap (struct mount * mp) { - struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs; + struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs; struct buffer_head * bh; struct ext2_super_block * es; unsigned long desc_count, bitmap_count, x; @@ -529,7 +528,7 @@ static void ext2_check_blocks_bitmap (struct mount * mp) struct ext2_group_desc * gdp; int i, j; - lock_super (VFSTOUFS(mp)->um_devvp); + lock_super (VFSTOEXT2(mp)->um_devvp); es = sb->s_es; desc_count = 0; bitmap_count = 0; @@ -586,7 +585,7 @@ static void ext2_check_blocks_bitmap (struct mount * mp) "Wrong free blocks count in super block, " "stored = %lu, counted = %lu", (unsigned long) es->s_free_blocks_count, bitmap_count); - unlock_super (VFSTOUFS(mp)->um_devvp); + unlock_super (VFSTOEXT2(mp)->um_devvp); } #endif /* unused */ diff --git a/sys/gnu/fs/ext2fs/ext2_linux_ialloc.c b/sys/gnu/fs/ext2fs/ext2_linux_ialloc.c index 01ae55b078dc..64d96b21104c 100644 --- a/sys/gnu/fs/ext2fs/ext2_linux_ialloc.c +++ b/sys/gnu/fs/ext2fs/ext2_linux_ialloc.c @@ -36,10 +36,8 @@ #include <sys/mount.h> #include <sys/vnode.h> -#include <ufs/ufs/extattr.h> -#include <ufs/ufs/quota.h> -#include <ufs/ufs/inode.h> -#include <ufs/ufs/ufsmount.h> +#include <gnu/ext2fs/inode.h> +#include <gnu/ext2fs/ext2_mount.h> #include <gnu/ext2fs/ext2_extern.h> #include <gnu/ext2fs/ext2_fs.h> #include <gnu/ext2fs/ext2_fs_sb.h> @@ -69,7 +67,7 @@ struct ext2_group_desc * get_group_desc (struct mount * mp, unsigned int block_group, struct buffer_head ** bh) { - struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs; + struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs; unsigned long group_desc; unsigned long desc; struct ext2_group_desc * gdp; @@ -98,13 +96,13 @@ static void read_inode_bitmap (struct mount * mp, unsigned long block_group, unsigned int bitmap_nr) { - struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs; + struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs; struct ext2_group_desc * gdp; struct buffer_head * bh; int error; gdp = get_group_desc (mp, block_group, NULL); - if ((error = bread (VFSTOUFS(mp)->um_devvp, + if ((error = bread (VFSTOEXT2(mp)->um_devvp, fsbtodb(sb, gdp->bg_inode_bitmap), sb->s_blocksize, NOCRED, &bh)) != 0) @@ -131,7 +129,7 @@ static void read_inode_bitmap (struct mount * mp, static int load_inode_bitmap (struct mount * mp, unsigned int block_group) { - struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs; + struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs; int i, j; unsigned long inode_bitmap_number; struct buffer_head * inode_bitmap; @@ -447,14 +445,14 @@ repeat: static unsigned long ext2_count_free_inodes (struct mount * mp) { #ifdef EXT2FS_DEBUG - struct ext2_sb_info *sb = VFSTOUFS(mp)->um_e2fs; + struct ext2_sb_info *sb = VFSTOEXT2(mp)->um_e2fs; struct ext2_super_block * es; unsigned long desc_count, bitmap_count, x; int bitmap_nr; struct ext2_group_desc * gdp; int i; - lock_super (VFSTOUFS(mp)->um_devvp); + lock_super (VFSTOEXT2(mp)->um_devvp); es = sb->s_es; desc_count = 0; bitmap_count = 0; @@ -471,10 +469,10 @@ static unsigned long ext2_count_free_inodes (struct mount * mp) } ext2_debug("stored = %lu, computed = %lu, %lu\n", es->s_free_inodes_count, desc_count, bitmap_count); - unlock_super (VFSTOUFS(mp)->um_devvp); + unlock_super (VFSTOEXT2(mp)->um_devvp); return desc_count; #else - return VFSTOUFS(mp)->um_e2fsb->s_free_inodes_count; + return VFSTOEXT2(mp)->um_e2fsb->s_free_inodes_count; #endif } #endif /* unused */ diff --git a/sys/gnu/fs/ext2fs/ext2_lookup.c b/sys/gnu/fs/ext2fs/ext2_lookup.c index 2c1de41414f4..14b78b58a7cf 100644 --- a/sys/gnu/fs/ext2fs/ext2_lookup.c +++ b/sys/gnu/fs/ext2fs/ext2_lookup.c @@ -55,13 +55,10 @@ #include <sys/malloc.h> #include <sys/dirent.h> -#include <ufs/ufs/extattr.h> -#include <ufs/ufs/quota.h> -#include <ufs/ufs/inode.h> #include <ufs/ufs/dir.h> -#include <ufs/ufs/ufsmount.h> -#include <ufs/ufs/ufs_extern.h> +#include <gnu/ext2fs/inode.h> +#include <gnu/ext2fs/ext2_mount.h> #include <gnu/ext2fs/ext2_extern.h> #include <gnu/ext2fs/ext2_fs.h> #include <gnu/ext2fs/ext2_fs_sb.h> @@ -364,7 +361,7 @@ ext2_lookup(ap) * profiling time and hence has been removed in the interest * of simplicity. */ - bmask = VFSTOUFS(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1; + bmask = VFSTOEXT2(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1; if (nameiop != LOOKUP || dp->i_diroff == 0 || dp->i_diroff > dp->i_size) { entryoffsetinblock = 0; @@ -373,7 +370,8 @@ ext2_lookup(ap) } else { dp->i_offset = dp->i_diroff; if ((entryoffsetinblock = dp->i_offset & bmask) && - (error = UFS_BLKATOFF(vdp, (off_t)dp->i_offset, NULL, &bp))) + (error = ext2_blkatoff(vdp, (off_t)dp->i_offset, NULL, + &bp))) return (error); numdirpasses = 2; nchstats.ncs_2passes++; @@ -391,7 +389,8 @@ searchloop: if (bp != NULL) brelse(bp); if ((error = - UFS_BLKATOFF(vdp, (off_t)dp->i_offset, NULL, &bp)) != 0) + ext2_blkatoff(vdp, (off_t)dp->i_offset, NULL, + &bp)) != 0) return (error); entryoffsetinblock = 0; } @@ -416,7 +415,7 @@ searchloop: if (ep->rec_len == 0 || (dirchk && ext2_dirbadentry(vdp, ep, entryoffsetinblock))) { int i; - ufs_dirbad(dp, dp->i_offset, "mangled entry"); + ext2_dirbad(dp, dp->i_offset, "mangled entry"); i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)); dp->i_offset += i; entryoffsetinblock += i; @@ -558,7 +557,7 @@ found: */ if (entryoffsetinblock + EXT2_DIR_REC_LEN(ep->name_len) > dp->i_size) { - ufs_dirbad(dp, dp->i_offset, "i_size too small"); + ext2_dirbad(dp, dp->i_offset, "i_size too small"); dp->i_size = entryoffsetinblock+EXT2_DIR_REC_LEN(ep->name_len); dp->i_flag |= IN_CHANGE | IN_UPDATE; } @@ -700,6 +699,21 @@ found: return (0); } +void +ext2_dirbad(ip, offset, how) + struct inode *ip; + doff_t offset; + char *how; +{ + struct mount *mp; + + mp = ITOV(ip)->v_mount; + (void)printf("%s: bad dir ino %lu at offset %ld: %s\n", + mp->mnt_stat.f_mntonname, (u_long)ip->i_number, (long)offset, how); + if ((mp->mnt_flag & MNT_RDONLY) == 0) + panic("ext2_dirbad: bad dir"); +} + /* * Do consistency checking on a directory entry: * record length must be multiple of 4 @@ -804,7 +818,7 @@ ext2_direnter(ip, dvp, cnp) auio.uio_td = (struct thread *)0; error = VOP_WRITE(dvp, &auio, IO_SYNC, cnp->cn_cred); if (DIRBLKSIZ > - VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize) + VFSTOEXT2(dvp->v_mount)->um_mountp->mnt_stat.f_bsize) /* XXX should grow with balloc() */ panic("ext2_direnter: frag size"); else if (!error) { @@ -835,7 +849,8 @@ ext2_direnter(ip, dvp, cnp) /* * Get the block containing the space for the new directory entry. */ - if ((error = UFS_BLKATOFF(dvp, (off_t)dp->i_offset, &dirbuf, &bp)) != 0) + if ((error = ext2_blkatoff(dvp, (off_t)dp->i_offset, &dirbuf, + &bp)) != 0) return (error); /* * Find space for the new entry. In the simple case, the entry at @@ -881,7 +896,7 @@ ext2_direnter(ip, dvp, cnp) error = BUF_WRITE(bp); dp->i_flag |= IN_CHANGE | IN_UPDATE; if (!error && dp->i_endoff && dp->i_endoff < dp->i_size) - error = UFS_TRUNCATE(dvp, (off_t)dp->i_endoff, IO_SYNC, + error = ext2_truncate(dvp, (off_t)dp->i_endoff, IO_SYNC, cnp->cn_cred, cnp->cn_thread); return (error); } @@ -914,7 +929,8 @@ ext2_dirremove(dvp, cnp) * First entry in block: set d_ino to zero. */ if ((error = - UFS_BLKATOFF(dvp, (off_t)dp->i_offset, (char **)&ep, &bp)) != 0) + ext2_blkatoff(dvp, (off_t)dp->i_offset, (char **)&ep, + &bp)) != 0) return (error); ep->inode = 0; error = BUF_WRITE(bp); @@ -924,7 +940,7 @@ ext2_dirremove(dvp, cnp) /* * Collapse new free space into previous entry. */ - if ((error = UFS_BLKATOFF(dvp, (off_t)(dp->i_offset - dp->i_count), + if ((error = ext2_blkatoff(dvp, (off_t)(dp->i_offset - dp->i_count), (char **)&ep, &bp)) != 0) return (error); ep->rec_len += dp->i_reclen; @@ -948,7 +964,8 @@ ext2_dirrewrite(dp, ip, cnp) struct vnode *vdp = ITOV(dp); int error; - if ((error = UFS_BLKATOFF(vdp, (off_t)dp->i_offset, (char **)&ep, &bp)) != 0) + if ((error = ext2_blkatoff(vdp, (off_t)dp->i_offset, (char **)&ep, + &bp)) != 0) return (error); ep->inode = ip->i_number; if (EXT2_HAS_INCOMPAT_FEATURE(ip->i_e2fs->s_es, diff --git a/sys/gnu/fs/ext2fs/ext2_readwrite.c b/sys/gnu/fs/ext2fs/ext2_readwrite.c index 2772f7b2306e..73f900cd3230 100644 --- a/sys/gnu/fs/ext2fs/ext2_readwrite.c +++ b/sys/gnu/fs/ext2fs/ext2_readwrite.c @@ -301,12 +301,12 @@ WRITE(ap) ip->i_mode &= ~(ISUID | ISGID); if (error) { if (ioflag & IO_UNIT) { - (void)UFS_TRUNCATE(vp, osize, + (void)ext2_truncate(vp, osize, ioflag & IO_SYNC, ap->a_cred, uio->uio_td); uio->uio_offset -= resid - uio->uio_resid; uio->uio_resid = resid; } } else if (resid > uio->uio_resid && (ioflag & IO_SYNC)) - error = UFS_UPDATE(vp, 1); + error = ext2_update(vp, 1); return (error); } diff --git a/sys/gnu/fs/ext2fs/ext2_subr.c b/sys/gnu/fs/ext2fs/ext2_subr.c index 69eecf1e236b..587ed0520f6d 100644 --- a/sys/gnu/fs/ext2fs/ext2_subr.c +++ b/sys/gnu/fs/ext2fs/ext2_subr.c @@ -50,9 +50,7 @@ #include <sys/ucred.h> #include <sys/vnode.h> -#include <ufs/ufs/quota.h> -#include <ufs/ufs/inode.h> - +#include <gnu/ext2fs/inode.h> #include <gnu/ext2fs/ext2_extern.h> #include <gnu/ext2fs/ext2_fs_sb.h> #include <gnu/ext2fs/fs.h> @@ -121,7 +119,7 @@ ext2_checkoverlap(bp, ip) continue; vprint("Disk overlap", vp); (void)printf("\tstart %d, end %d overlap start %lld, end %ld\n", - start, last, ep->b_blkno, + start, last, (long long)ep->b_blkno, (long)(ep->b_blkno + btodb(ep->b_bcount) - 1)); panic("Disk buffer overlap"); } diff --git a/sys/gnu/fs/ext2fs/ext2_vfsops.c b/sys/gnu/fs/ext2fs/ext2_vfsops.c index 54c43058cb3d..b9afe91a1f7f 100644 --- a/sys/gnu/fs/ext2fs/ext2_vfsops.c +++ b/sys/gnu/fs/ext2fs/ext2_vfsops.c @@ -40,8 +40,6 @@ * $FreeBSD$ */ -#include "opt_quota.h" - #include <sys/param.h> #include <sys/systm.h> #include <sys/namei.h> @@ -57,12 +55,8 @@ #include <sys/stat.h> #include <sys/mutex.h> -#include <ufs/ufs/extattr.h> -#include <ufs/ufs/quota.h> -#include <ufs/ufs/ufsmount.h> -#include <ufs/ufs/inode.h> -#include <ufs/ufs/ufs_extern.h> - +#include <gnu/ext2fs/ext2_mount.h> +#include <gnu/ext2fs/inode.h> #include <gnu/ext2fs/fs.h> #include <gnu/ext2fs/ext2_extern.h> @@ -71,26 +65,29 @@ static int ext2_fhtovp(struct mount *, struct fid *, struct vnode **); static int ext2_flushfiles(struct mount *mp, int flags, struct thread *td); +static int ext2_init(struct vfsconf *); static int ext2_mount(struct mount *, char *, caddr_t, struct nameidata *, struct thread *); static int ext2_mountfs(struct vnode *, struct mount *, struct thread *); static int ext2_reload(struct mount *mountp, struct ucred *cred, struct thread *td); -static int ext2_sbupdate(struct ufsmount *, int); +static int ext2_root(struct mount *, struct vnode **vpp); +static int ext2_sbupdate(struct ext2mount *, int); static int ext2_statfs(struct mount *, struct statfs *, struct thread *); static int ext2_sync(struct mount *, int, struct ucred *, struct thread *); static int ext2_unmount(struct mount *, int, struct thread *); static int ext2_vget(struct mount *, ino_t, int, struct vnode **); static int ext2_vptofh(struct vnode *, struct fid *); -static MALLOC_DEFINE(M_EXT2NODE, "EXT2 node", "EXT2 vnode private part"); +MALLOC_DEFINE(M_EXT2NODE, "EXT2 node", "EXT2 vnode private part"); +static MALLOC_DEFINE(M_EXT2MNT, "EXT2 mount", "EXT2 mount structure"); static struct vfsops ext2fs_vfsops = { ext2_mount, - ufs_start, /* empty function */ + vfs_stdstart, ext2_unmount, - ufs_root, /* root inode via vget */ - ufs_quotactl, /* does operations associated with quotas */ + ext2_root, /* root inode via vget */ + vfs_stdquotactl, ext2_statfs, ext2_sync, ext2_vget, @@ -129,7 +126,7 @@ ext2_mountroot() register struct ext2_sb_info *fs; register struct mount *mp; struct thread *td = curthread; - struct ufsmount *ump; + struct ext2mount *ump; u_int size; int error; @@ -155,7 +152,7 @@ ext2_mountroot() TAILQ_INSERT_HEAD(&mountlist, mp, mnt_list); mp->mnt_flag |= MNT_ROOTFS; mp->mnt_vnodecovered = NULLVP; - ump = VFSTOUFS(mp); + ump = VFSTOEXT2(mp); fs = ump->um_e2fs; bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt)); fs->fs_fsmnt[0] = '/'; @@ -180,13 +177,13 @@ static int ext2_mount(mp, path, data, ndp, td) register struct mount *mp; char *path; - caddr_t data; /* this is actually a (struct ufs_args *) */ + caddr_t data; /* this is actually a (struct ext2_args *) */ struct nameidata *ndp; struct thread *td; { struct vnode *devvp; - struct ufs_args args; - struct ufsmount *ump = 0; + struct ext2_args args; + struct ext2mount *ump = 0; register struct ext2_sb_info *fs; size_t size; int error, flags; @@ -195,7 +192,7 @@ ext2_mount(mp, path, data, ndp, td) /* Double-check the length of path.. */ if (strlen(path) >= MAXMNTLEN - 1) return (ENAMETOOLONG); - error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args)); + error = copyin(data, (caddr_t)&args, sizeof (struct ext2_args)); if (error != 0) return (error); /* @@ -203,7 +200,7 @@ ext2_mount(mp, path, data, ndp, td) * read/write; if there is no device name, that's all we do. */ if (mp->mnt_flag & MNT_UPDATE) { - ump = VFSTOUFS(mp); + ump = VFSTOEXT2(mp); fs = ump->um_e2fs; error = 0; if (fs->s_rd_only == 0 && (mp->mnt_flag & MNT_RDONLY)) { @@ -310,7 +307,7 @@ ext2_mount(mp, path, data, ndp, td) vrele(devvp); return (error); } - ump = VFSTOUFS(mp); + ump = VFSTOEXT2(mp); fs = ump->um_e2fs; /* * Note that this strncpy() is ok because of a check at the start @@ -466,7 +463,7 @@ static int compute_sb_data(devvp, es, fs) V(s_db_per_group) fs->s_group_desc = bsd_malloc(db_count * sizeof (struct buf *), - M_UFSMNT, M_WAITOK); + M_EXT2MNT, M_WAITOK); /* adjust logic_sb_block */ if(fs->s_blocksize > SBSIZE) @@ -481,7 +478,7 @@ static int compute_sb_data(devvp, es, fs) if(error) { for (j = 0; j < i; j++) brelse(fs->s_group_desc[j]); - bsd_free(fs->s_group_desc, M_UFSMNT); + bsd_free(fs->s_group_desc, M_EXT2MNT); printf("EXT2-fs: unable to read group descriptors (%d)\n", error); return EIO; } @@ -491,7 +488,7 @@ static int compute_sb_data(devvp, es, fs) if(!ext2_check_descriptors(fs)) { for (j = 0; j < db_count; j++) ULCK_BUF(fs->s_group_desc[j]) - bsd_free(fs->s_group_desc, M_UFSMNT); + bsd_free(fs->s_group_desc, M_EXT2MNT); printf("EXT2-fs: (ext2_check_descriptors failure) " "unable to read group descriptors\n"); return EIO; @@ -539,7 +536,7 @@ ext2_reload(mountp, cred, td) /* * Step 1: invalidate all cached meta-data. */ - devvp = VFSTOUFS(mountp)->um_devvp; + devvp = VFSTOEXT2(mountp)->um_devvp; if (vinvalbuf(devvp, 0, cred, td, 0, 0)) panic("ext2_reload: dirty1"); /* @@ -553,7 +550,7 @@ ext2_reload(mountp, cred, td) brelse(bp); return (EIO); /* XXX needs translation */ } - fs = VFSTOUFS(mountp)->um_e2fs; + fs = VFSTOEXT2(mountp)->um_e2fs; bcopy(bp->b_data, fs->s_es, sizeof(struct ext2_super_block)); if((error = compute_sb_data(devvp, es, fs)) != 0) { @@ -600,9 +597,8 @@ loop: vput(vp); return (error); } - ext2_ei2di((struct ext2_inode *) ((char *)bp->b_data + - EXT2_INODE_SIZE * ino_to_fsbo(fs, ip->i_number)), - &ip->i_din); + ext2_ei2i((struct ext2_inode *) ((char *)bp->b_data + + EXT2_INODE_SIZE * ino_to_fsbo(fs, ip->i_number)), ip); brelse(bp); vput(vp); mtx_lock(&mntvnode_mtx); @@ -620,12 +616,12 @@ ext2_mountfs(devvp, mp, td) struct mount *mp; struct thread *td; { - register struct ufsmount *ump; + register struct ext2mount *ump; struct buf *bp; register struct ext2_sb_info *fs; struct ext2_super_block * es; dev_t dev = devvp->v_rdev; - int error, i; + int error; int ronly; /* @@ -677,22 +673,16 @@ ext2_mountfs(devvp, mp, td) goto out; } } - ump = bsd_malloc(sizeof *ump, M_UFSMNT, M_WAITOK); + ump = bsd_malloc(sizeof *ump, M_EXT2MNT, M_WAITOK); bzero((caddr_t)ump, sizeof *ump); - ump->um_malloctype = M_EXT2NODE; - ump->um_blkatoff = ext2_blkatoff; - ump->um_truncate = ext2_truncate; - ump->um_update = ext2_update; - ump->um_valloc = ext2_valloc; - ump->um_vfree = ext2_vfree; /* I don't know whether this is the right strategy. Note that we dynamically allocate both a ext2_sb_info and a ext2_super_block while Linux keeps the super block in a locked buffer */ ump->um_e2fs = bsd_malloc(sizeof(struct ext2_sb_info), - M_UFSMNT, M_WAITOK); + M_EXT2MNT, M_WAITOK); ump->um_e2fs->s_es = bsd_malloc(sizeof(struct ext2_super_block), - M_UFSMNT, M_WAITOK); + M_EXT2MNT, M_WAITOK); bcopy(es, ump->um_e2fs->s_es, (u_int)sizeof(struct ext2_super_block)); if ((error = compute_sb_data(devvp, ump->um_e2fs->s_es, ump->um_e2fs))) goto out; @@ -720,14 +710,12 @@ ext2_mountfs(devvp, mp, td) ump->um_mountp = mp; ump->um_dev = dev; ump->um_devvp = devvp; - /* setting those two parameters allows us to use + /* setting those two parameters allowed us to use ufs_bmap w/o changse ! */ ump->um_nindir = EXT2_ADDR_PER_BLOCK(fs); ump->um_bptrtodb = fs->s_es->s_log_block_size + 1; ump->um_seqinc = EXT2_FRAGS_PER_BLOCK(fs); - for (i = 0; i < MAXQUOTAS; i++) - ump->um_quotas[i] = NULLVP; devvp->v_rdev->si_mountpoint = mp; if (ronly == 0) ext2_sbupdate(ump, MNT_WAIT); @@ -737,9 +725,9 @@ out: brelse(bp); (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, td); if (ump) { - bsd_free(ump->um_e2fs->s_es, M_UFSMNT); - bsd_free(ump->um_e2fs, M_UFSMNT); - bsd_free(ump, M_UFSMNT); + bsd_free(ump->um_e2fs->s_es, M_EXT2MNT); + bsd_free(ump->um_e2fs, M_EXT2MNT); + bsd_free(ump, M_EXT2MNT); mp->mnt_data = (qaddr_t)0; } return (error); @@ -754,7 +742,7 @@ ext2_unmount(mp, mntflags, td) int mntflags; struct thread *td; { - register struct ufsmount *ump; + register struct ext2mount *ump; register struct ext2_sb_info *fs; int error, flags, ronly, i; @@ -766,7 +754,7 @@ ext2_unmount(mp, mntflags, td) } if ((error = ext2_flushfiles(mp, flags, td)) != 0) return (error); - ump = VFSTOUFS(mp); + ump = VFSTOEXT2(mp); fs = ump->um_e2fs; ronly = fs->s_rd_only; if (ronly == 0) { @@ -778,7 +766,7 @@ ext2_unmount(mp, mntflags, td) /* release buffers containing group descriptors */ for(i = 0; i < fs->s_db_per_group; i++) ULCK_BUF(fs->s_group_desc[i]) - bsd_free(fs->s_group_desc, M_UFSMNT); + bsd_free(fs->s_group_desc, M_EXT2MNT); /* release cached inode/block bitmaps */ for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++) @@ -793,9 +781,9 @@ ext2_unmount(mp, mntflags, td) error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, td); vrele(ump->um_devvp); - bsd_free(fs->s_es, M_UFSMNT); - bsd_free(fs, M_UFSMNT); - bsd_free(ump, M_UFSMNT); + bsd_free(fs->s_es, M_EXT2MNT); + bsd_free(fs, M_EXT2MNT); + bsd_free(ump, M_EXT2MNT); mp->mnt_data = (qaddr_t)0; mp->mnt_flag &= ~MNT_LOCAL; return (error); @@ -810,28 +798,8 @@ ext2_flushfiles(mp, flags, td) int flags; struct thread *td; { - register struct ufsmount *ump; int error; -#if QUOTA - int i; -#endif - ump = VFSTOUFS(mp); -#if QUOTA - if (mp->mnt_flag & MNT_QUOTA) { - if ((error = vflush(mp, 0, SKIPSYSTEM|flags)) != 0) - return (error); - for (i = 0; i < MAXQUOTAS; i++) { - if (ump->um_quotas[i] == NULLVP) - continue; - quotaoff(td, mp, i); - } - /* - * Here we fall through to vflush again to ensure - * that we have gotten rid of all the system vnodes. - */ - } -#endif error = vflush(mp, 0, flags); return (error); } @@ -847,12 +815,12 @@ ext2_statfs(mp, sbp, td) struct thread *td; { unsigned long overhead; - register struct ufsmount *ump; + register struct ext2mount *ump; register struct ext2_sb_info *fs; register struct ext2_super_block *es; int i, nsb; - ump = VFSTOUFS(mp); + ump = VFSTOEXT2(mp); fs = ump->um_e2fs; es = fs->s_es; @@ -908,7 +876,7 @@ ext2_sync(mp, waitfor, cred, td) { struct vnode *nvp, *vp; struct inode *ip; - struct ufsmount *ump = VFSTOUFS(mp); + struct ext2mount *ump = VFSTOEXT2(mp); struct ext2_sb_info *fs; int error, allerror = 0; @@ -964,9 +932,6 @@ loop: allerror = error; VOP_UNLOCK(ump->um_devvp, 0, td); } -#if QUOTA - qsync(mp); -#endif /* * Write back modified superblock. */ @@ -994,17 +959,17 @@ ext2_vget(mp, ino, flags, vpp) { register struct ext2_sb_info *fs; register struct inode *ip; - struct ufsmount *ump; + struct ext2mount *ump; struct buf *bp; struct vnode *vp; dev_t dev; int i, error; int used_blocks; - ump = VFSTOUFS(mp); + ump = VFSTOEXT2(mp); dev = ump->um_dev; restart: - if ((error = ufs_ihashget(dev, ino, flags, vpp)) != 0) + if ((error = ext2_ihashget(dev, ino, flags, vpp)) != 0) return (error); if (*vpp != NULL) return (0); @@ -1048,17 +1013,13 @@ restart: ip->i_e2fs = fs = ump->um_e2fs; ip->i_dev = dev; ip->i_number = ino; -#if QUOTA - for (i = 0; i < MAXQUOTAS; i++) - ip->i_dquot[i] = NODQUOT; -#endif /* * Put it onto its hash chain and lock it so that other requests for * this inode will block if they arrive while we are sleeping waiting * for old data structures to be purged or for the contents of the * disk portion of this inode to be read. */ - ufs_ihashins(ip); + ext2_ihashins(ip); if (ext2fs_inode_hash_lock < 0) wakeup(&ext2fs_inode_hash_lock); @@ -1082,8 +1043,8 @@ printf("ext2_vget(%d) dbn= %d ", ino, fsbtodb(fs, ino_to_fsba(fs, ino))); return (error); } /* convert ext2 inode to dinode */ - ext2_ei2di((struct ext2_inode *) ((char *)bp->b_data + EXT2_INODE_SIZE * - ino_to_fsbo(fs, ino)), &ip->i_din); + ext2_ei2i((struct ext2_inode *) ((char *)bp->b_data + EXT2_INODE_SIZE * + ino_to_fsbo(fs, ino)), ip); ip->i_block_group = ino_to_cg(fs, ino); ip->i_next_alloc_block = 0; ip->i_next_alloc_goal = 0; @@ -1107,7 +1068,7 @@ printf("ext2_vget(%d) dbn= %d ", ino, fsbtodb(fs, ino_to_fsba(fs, ino))); * Initialize the vnode from the inode, check for aliases. * Note that the underlying vnode may have changed. */ - if ((error = ufs_vinit(mp, ext2_specop_p, ext2_fifoop_p, &vp)) != 0) { + if ((error = ext2_vinit(mp, ext2_specop_p, ext2_fifoop_p, &vp)) != 0) { vput(vp); *vpp = NULL; return (error); @@ -1146,15 +1107,32 @@ ext2_fhtovp(mp, fhp, vpp) struct fid *fhp; struct vnode **vpp; { + struct inode *ip; register struct ufid *ufhp; + struct vnode *nvp; struct ext2_sb_info *fs; + int error; ufhp = (struct ufid *)fhp; - fs = VFSTOUFS(mp)->um_e2fs; + fs = VFSTOEXT2(mp)->um_e2fs; if (ufhp->ufid_ino < ROOTINO || ufhp->ufid_ino >= fs->s_groups_count * fs->s_es->s_inodes_per_group) return (ESTALE); - return (ufs_fhtovp(mp, ufhp, vpp)); + + error = VFS_VGET(mp, ufhp->ufid_ino, LK_EXCLUSIVE, &nvp); + if (error) { + *vpp = NULLVP; + return (error); + } + ip = VTOI(nvp); + if (ip->i_mode == 0 || + ip->i_gen != ufhp->ufid_gen || ip->i_nlink <= 0) { + vput(nvp); + *vpp = NULLVP; + return (ESTALE); + } + *vpp = nvp; + return (0); } /* @@ -1182,7 +1160,7 @@ ext2_vptofh(vp, fhp) */ static int ext2_sbupdate(mp, waitfor) - struct ufsmount *mp; + struct ext2mount *mp; int waitfor; { register struct ext2_sb_info *fs = mp->um_e2fs; @@ -1207,3 +1185,34 @@ printf("\nupdating superblock, waitfor=%s\n", waitfor == MNT_WAIT ? "yes":"no"); return (error); } + +/* + * Return the root of a filesystem. + */ +static int +ext2_root(mp, vpp) + struct mount *mp; + struct vnode **vpp; +{ + struct vnode *nvp; + int error; + + error = VFS_VGET(mp, (ino_t)ROOTINO, LK_EXCLUSIVE, &nvp); + if (error) + return (error); + *vpp = nvp; + return (0); +} + +static int +ext2_init(struct vfsconf *vfsp) +{ + static int done; + + if (done) + return (0); + done = 1; + ext2_ihashinit(); + + return (0); +} diff --git a/sys/gnu/fs/ext2fs/ext2_vnops.c b/sys/gnu/fs/ext2fs/ext2_vnops.c index 180ac3db063a..ba7b714cdaf9 100644 --- a/sys/gnu/fs/ext2fs/ext2_vnops.c +++ b/sys/gnu/fs/ext2fs/ext2_vnops.c @@ -46,34 +46,38 @@ * $FreeBSD$ */ -#include "opt_quota.h" #include "opt_suiddir.h" #include <sys/param.h> #include <sys/systm.h> #include <sys/resourcevar.h> #include <sys/kernel.h> +#include <sys/fcntl.h> #include <sys/stat.h> #include <sys/bio.h> #include <sys/buf.h> #include <sys/proc.h> #include <sys/mount.h> +#include <sys/unistd.h> #include <sys/time.h> #include <sys/vnode.h> #include <sys/namei.h> +#include <sys/lockf.h> +#include <sys/event.h> +#include <sys/conf.h> +#include <sys/file.h> #include <vm/vm.h> #include <vm/vm_extern.h> #include <vm/vnode_pager.h> +#include <fs/fifofs/fifo.h> + #include <sys/signalvar.h> #include <ufs/ufs/dir.h> -#include <ufs/ufs/extattr.h> -#include <ufs/ufs/quota.h> -#include <ufs/ufs/inode.h> -#include <ufs/ufs/ufsmount.h> -#include <ufs/ufs/ufs_extern.h> +#include <gnu/ext2fs/inode.h> +#include <gnu/ext2fs/ext2_mount.h> #include <gnu/ext2fs/ext2_fs_sb.h> #include <gnu/ext2fs/fs.h> #include <gnu/ext2fs/ext2_extern.h> @@ -81,38 +85,81 @@ static int ext2_makeinode(int mode, struct vnode *, struct vnode **, struct componentname *); -static int ext2_fsync(struct vop_fsync_args *); -static int ext2_read(struct vop_read_args *); -static int ext2_write(struct vop_write_args *); -static int ext2_remove(struct vop_remove_args *); -static int ext2_link(struct vop_link_args *); -static int ext2_rename(struct vop_rename_args *); -static int ext2_mkdir(struct vop_mkdir_args *); -static int ext2_rmdir(struct vop_rmdir_args *); +static int ext2_access(struct vop_access_args *); +static int ext2_advlock(struct vop_advlock_args *); +static int ext2_chmod(struct vnode *, int, struct ucred *, struct thread *); +static int ext2_chown(struct vnode *, uid_t, gid_t, struct ucred *, + struct thread *); +static int ext2_close(struct vop_close_args *); static int ext2_create(struct vop_create_args *); +static int ext2_fsync(struct vop_fsync_args *); +static int ext2_getattr(struct vop_getattr_args *); +static int ext2_kqfilter(struct vop_kqfilter_args *ap); +static int ext2_link(struct vop_link_args *); +static int ext2_mkdir(struct vop_mkdir_args *); static int ext2_mknod(struct vop_mknod_args *); +static int ext2_open(struct vop_open_args *); +static int ext2_pathconf(struct vop_pathconf_args *); +static int ext2_print(struct vop_print_args *); +static int ext2_read(struct vop_read_args *); +static int ext2_readlink(struct vop_readlink_args *); +static int ext2_remove(struct vop_remove_args *); +static int ext2_rename(struct vop_rename_args *); +static int ext2_rmdir(struct vop_rmdir_args *); +static int ext2_setattr(struct vop_setattr_args *); +static int ext2_strategy(struct vop_strategy_args *); static int ext2_symlink(struct vop_symlink_args *); +static int ext2_write(struct vop_write_args *); +static int ext2fifo_close(struct vop_close_args *); +static int ext2fifo_kqfilter(struct vop_kqfilter_args *); +static int ext2fifo_read(struct vop_read_args *); +static int ext2fifo_write(struct vop_write_args *); +static int ext2spec_close(struct vop_close_args *); +static int ext2spec_read(struct vop_read_args *); +static int ext2spec_write(struct vop_write_args *); +static int filt_ext2read(struct knote *kn, long hint); +static int filt_ext2write(struct knote *kn, long hint); +static int filt_ext2vnode(struct knote *kn, long hint); +static void filt_ext2detach(struct knote *kn); -/* Global vfs data structures for ufs. */ +/* Global vfs data structures for ext2. */ vop_t **ext2_vnodeop_p; static struct vnodeopv_entry_desc ext2_vnodeop_entries[] = { - { &vop_default_desc, (vop_t *) ufs_vnoperate }, + { &vop_default_desc, (vop_t *) vop_defaultop }, + { &vop_access_desc, (vop_t *) ext2_access }, + { &vop_advlock_desc, (vop_t *) ext2_advlock }, + { &vop_bmap_desc, (vop_t *) ext2_bmap }, { &vop_cachedlookup_desc, (vop_t *) ext2_lookup }, + { &vop_close_desc, (vop_t *) ext2_close }, + { &vop_create_desc, (vop_t *) ext2_create }, { &vop_fsync_desc, (vop_t *) ext2_fsync }, + { &vop_getattr_desc, (vop_t *) ext2_getattr }, + { &vop_getwritemount_desc, (vop_t *) vop_stdgetwritemount }, { &vop_inactive_desc, (vop_t *) ext2_inactive }, + { &vop_islocked_desc, (vop_t *) vop_stdislocked }, + { &vop_link_desc, (vop_t *) ext2_link }, + { &vop_lock_desc, (vop_t *) vop_stdlock }, { &vop_lookup_desc, (vop_t *) vfs_cache_lookup }, + { &vop_mkdir_desc, (vop_t *) ext2_mkdir }, + { &vop_mknod_desc, (vop_t *) ext2_mknod }, + { &vop_open_desc, (vop_t *) ext2_open }, + { &vop_pathconf_desc, (vop_t *) ext2_pathconf }, + { &vop_poll_desc, (vop_t *) vop_stdpoll }, + { &vop_kqfilter_desc, (vop_t *) ext2_kqfilter }, + { &vop_print_desc, (vop_t *) ext2_print }, { &vop_read_desc, (vop_t *) ext2_read }, { &vop_readdir_desc, (vop_t *) ext2_readdir }, + { &vop_readlink_desc, (vop_t *) ext2_readlink }, { &vop_reallocblks_desc, (vop_t *) ext2_reallocblks }, - { &vop_write_desc, (vop_t *) ext2_write }, + { &vop_reclaim_desc, (vop_t *) ext2_reclaim }, { &vop_remove_desc, (vop_t *) ext2_remove }, - { &vop_link_desc, (vop_t *) ext2_link }, { &vop_rename_desc, (vop_t *) ext2_rename }, - { &vop_mkdir_desc, (vop_t *) ext2_mkdir }, { &vop_rmdir_desc, (vop_t *) ext2_rmdir }, - { &vop_create_desc, (vop_t *) ext2_create }, - { &vop_mknod_desc, (vop_t *) ext2_mknod }, + { &vop_setattr_desc, (vop_t *) ext2_setattr }, + { &vop_strategy_desc, (vop_t *) ext2_strategy }, { &vop_symlink_desc, (vop_t *) ext2_symlink }, + { &vop_unlock_desc, (vop_t *) vop_stdunlock }, + { &vop_write_desc, (vop_t *) ext2_write }, { NULL, NULL } }; static struct vnodeopv_desc ext2fs_vnodeop_opv_desc = @@ -120,9 +167,20 @@ static struct vnodeopv_desc ext2fs_vnodeop_opv_desc = vop_t **ext2_specop_p; static struct vnodeopv_entry_desc ext2_specop_entries[] = { - { &vop_default_desc, (vop_t *) ufs_vnoperatespec }, + { &vop_default_desc, (vop_t *) spec_vnoperate }, + { &vop_access_desc, (vop_t *) ext2_access }, + { &vop_close_desc, (vop_t *) ext2spec_close }, { &vop_fsync_desc, (vop_t *) ext2_fsync }, + { &vop_getattr_desc, (vop_t *) ext2_getattr }, { &vop_inactive_desc, (vop_t *) ext2_inactive }, + { &vop_islocked_desc, (vop_t *) vop_stdislocked }, + { &vop_lock_desc, (vop_t *) vop_stdlock }, + { &vop_print_desc, (vop_t *) ext2_print }, + { &vop_read_desc, (vop_t *) ext2spec_read }, + { &vop_reclaim_desc, (vop_t *) ext2_reclaim }, + { &vop_setattr_desc, (vop_t *) ext2_setattr }, + { &vop_unlock_desc, (vop_t *) vop_stdunlock }, + { &vop_write_desc, (vop_t *) ext2spec_write }, { NULL, NULL } }; static struct vnodeopv_desc ext2fs_specop_opv_desc = @@ -130,9 +188,21 @@ static struct vnodeopv_desc ext2fs_specop_opv_desc = vop_t **ext2_fifoop_p; static struct vnodeopv_entry_desc ext2_fifoop_entries[] = { - { &vop_default_desc, (vop_t *) ufs_vnoperatefifo }, + { &vop_default_desc, (vop_t *) fifo_vnoperate }, + { &vop_access_desc, (vop_t *) ext2_access }, + { &vop_close_desc, (vop_t *) ext2fifo_close }, { &vop_fsync_desc, (vop_t *) ext2_fsync }, + { &vop_getattr_desc, (vop_t *) ext2_getattr }, { &vop_inactive_desc, (vop_t *) ext2_inactive }, + { &vop_islocked_desc, (vop_t *) vop_stdislocked }, + { &vop_kqfilter_desc, (vop_t *) ext2fifo_kqfilter }, + { &vop_lock_desc, (vop_t *) vop_stdlock }, + { &vop_print_desc, (vop_t *) ext2_print }, + { &vop_read_desc, (vop_t *) ext2fifo_read }, + { &vop_reclaim_desc, (vop_t *) ext2_reclaim }, + { &vop_setattr_desc, (vop_t *) ext2_setattr }, + { &vop_unlock_desc, (vop_t *) vop_stdunlock }, + { &vop_write_desc, (vop_t *) ext2fifo_write }, { NULL, NULL } }; static struct vnodeopv_desc ext2fs_fifoop_opv_desc = @@ -144,9 +214,26 @@ static struct vnodeopv_desc ext2fs_fifoop_opv_desc = #include <gnu/ext2fs/ext2_readwrite.c> +union _qcvt { + int64_t qcvt; + int32_t val[2]; +}; +#define SETHIGH(q, h) { \ + union _qcvt tmp; \ + tmp.qcvt = (q); \ + tmp.val[_QUAD_HIGHWORD] = (h); \ + (q) = tmp.qcvt; \ +} +#define SETLOW(q, l) { \ + union _qcvt tmp; \ + tmp.qcvt = (q); \ + tmp.val[_QUAD_LOWWORD] = (l); \ + (q) = tmp.qcvt; \ +} + /* * A virgin directory (no blushing please). - * Note that the type and namlen fields are reversed relative to ufs. + * Note that the type and namlen fields are reversed relative to ext2. * Also, we don't use `struct odirtemplate', since it would just cause * endianness problems. */ @@ -159,6 +246,39 @@ static struct dirtemplate omastertemplate = { 0, DIRBLKSIZ - 12, 2, EXT2_FT_UNKNOWN, ".." }; +void +ext2_itimes(vp) + struct vnode *vp; +{ + struct inode *ip; + struct timespec ts; + + ip = VTOI(vp); + if ((ip->i_flag & (IN_ACCESS | IN_CHANGE | IN_UPDATE)) == 0) + return; + if ((vp->v_type == VBLK || vp->v_type == VCHR)) + ip->i_flag |= IN_LAZYMOD; + else + ip->i_flag |= IN_MODIFIED; + if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { + vfs_timestamp(&ts); + if (ip->i_flag & IN_ACCESS) { + ip->i_atime = ts.tv_sec; + ip->i_atimensec = ts.tv_nsec; + } + if (ip->i_flag & IN_UPDATE) { + ip->i_mtime = ts.tv_sec; + ip->i_mtimensec = ts.tv_nsec; + ip->i_modrev++; + } + if (ip->i_flag & IN_CHANGE) { + ip->i_ctime = ts.tv_sec; + ip->i_ctimensec = ts.tv_nsec; + } + } + ip->i_flag &= ~(IN_ACCESS | IN_CHANGE | IN_UPDATE); +} + /* * Create a regular file */ @@ -181,6 +301,375 @@ ext2_create(ap) return (0); } +/* + * Open called. + * + * Nothing to do. + */ +int +ext2_open(ap) + struct vop_open_args /* { + struct vnode *a_vp; + int a_mode; + struct ucred *a_cred; + struct thread *a_td; + } */ *ap; +{ + + /* + * Files marked append-only must be opened for appending. + */ + if ((VTOI(ap->a_vp)->i_flags & APPEND) && + (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE) + return (EPERM); + return (0); +} + +/* + * Close called. + * + * Update the times on the inode. + */ +static int +ext2_close(ap) + struct vop_close_args /* { + struct vnode *a_vp; + int a_fflag; + struct ucred *a_cred; + struct thread *a_td; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct mount *mp; + + mtx_lock(&vp->v_interlock); + if (vp->v_usecount > 1) { + ext2_itimes(vp); + mtx_unlock(&vp->v_interlock); + } else { + mtx_unlock(&vp->v_interlock); + /* + * If we are closing the last reference to an unlinked + * file, then it will be freed by the inactive routine. + * Because the freeing causes a the filesystem to be + * modified, it must be held up during periods when the + * filesystem is suspended. + * + * XXX - EAGAIN is returned to prevent vn_close from + * repeating the vrele operation. + */ + if (vp->v_type == VREG && VTOI(vp)->i_nlink == 0) { + (void) vn_start_write(vp, &mp, V_WAIT); + vrele(vp); + vn_finished_write(mp); + return (EAGAIN); + } + } + return (0); +} + +static int +ext2_access(ap) + struct vop_access_args /* { + struct vnode *a_vp; + int a_mode; + struct ucred *a_cred; + struct thread *a_td; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct inode *ip = VTOI(vp); + mode_t mode = ap->a_mode; + int error; + + /* + * Disallow write attempts on read-only file systems; + * unless the file is a socket, fifo, or a block or + * character device resident on the file system. + */ + if (mode & VWRITE) { + switch (vp->v_type) { + case VDIR: + case VLNK: + case VREG: + if (vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + break; + default: + break; + } + } + + /* If immutable bit set, nobody gets to write it. */ + if ((mode & VWRITE) && (ip->i_flags & (IMMUTABLE | SF_SNAPSHOT))) + return (EPERM); + + error = vaccess(vp->v_type, ip->i_mode, ip->i_uid, ip->i_gid, + ap->a_mode, ap->a_cred, NULL); + return (error); +} + +static int +ext2_getattr(ap) + struct vop_getattr_args /* { + struct vnode *a_vp; + struct vattr *a_vap; + struct ucred *a_cred; + struct thread *a_td; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct inode *ip = VTOI(vp); + struct vattr *vap = ap->a_vap; + + ext2_itimes(vp); + /* + * Copy from inode table + */ + vap->va_fsid = dev2udev(ip->i_dev); + vap->va_fileid = ip->i_number; + vap->va_mode = ip->i_mode & ~IFMT; + vap->va_nlink = ip->i_nlink; + vap->va_uid = ip->i_uid; + vap->va_gid = ip->i_gid; + vap->va_rdev = ip->i_rdev; + vap->va_size = ip->i_size; + vap->va_atime.tv_sec = ip->i_atime; + vap->va_atime.tv_nsec = ip->i_atimensec; + vap->va_mtime.tv_sec = ip->i_mtime; + vap->va_mtime.tv_nsec = ip->i_mtimensec; + vap->va_ctime.tv_sec = ip->i_ctime; + vap->va_ctime.tv_nsec = ip->i_ctimensec; + vap->va_flags = ip->i_flags; + vap->va_gen = ip->i_gen; + vap->va_blocksize = vp->v_mount->mnt_stat.f_iosize; + vap->va_bytes = dbtob((u_quad_t)ip->i_blocks); + vap->va_type = IFTOVT(ip->i_mode); + vap->va_filerev = ip->i_modrev; + return (0); +} + +/* + * Set attribute vnode op. called from several syscalls + */ +int +ext2_setattr(ap) + struct vop_setattr_args /* { + struct vnode *a_vp; + struct vattr *a_vap; + struct ucred *a_cred; + struct thread *a_td; + } */ *ap; +{ + struct vattr *vap = ap->a_vap; + struct vnode *vp = ap->a_vp; + struct inode *ip = VTOI(vp); + struct ucred *cred = ap->a_cred; + struct thread *td = ap->a_td; + int error; + + /* + * Check for unsettable attributes. + */ + if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) || + (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) || + (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) || + ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) { + return (EINVAL); + } + if (vap->va_flags != VNOVAL) { + if (vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + /* + * Callers may only modify the file flags on objects they + * have VADMIN rights for. + */ + if ((error = VOP_ACCESS(vp, VADMIN, cred, td))) + return (error); + /* + * Unprivileged processes and privileged processes in + * jail() are not permitted to unset system flags, or + * modify flags if any system flags are set. + * Privileged non-jail processes may not modify system flags + * if securelevel > 0 and any existing system flags are set. + */ + if (!suser_cred(cred, PRISON_ROOT)) { + if (ip->i_flags + & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND)) { + error = securelevel_gt(cred, 0); + if (error) + return (error); + } + ip->i_flags = vap->va_flags; + } else { + if (ip->i_flags + & (SF_NOUNLINK | SF_IMMUTABLE | SF_APPEND) || + (vap->va_flags & UF_SETTABLE) != vap->va_flags) + return (EPERM); + ip->i_flags &= SF_SETTABLE; + ip->i_flags |= (vap->va_flags & UF_SETTABLE); + } + ip->i_flag |= IN_CHANGE; + if (vap->va_flags & (IMMUTABLE | APPEND)) + return (0); + } + if (ip->i_flags & (IMMUTABLE | APPEND)) + return (EPERM); + /* + * Go through the fields and update iff not VNOVAL. + */ + if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) { + if (vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + if ((error = ext2_chown(vp, vap->va_uid, vap->va_gid, cred, + td)) != 0) + return (error); + } + if (vap->va_size != VNOVAL) { + /* + * Disallow write attempts on read-only file systems; + * unless the file is a socket, fifo, or a block or + * character device resident on the file system. + */ + switch (vp->v_type) { + case VDIR: + return (EISDIR); + case VLNK: + case VREG: + if (vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + break; + default: + break; + } + if ((error = ext2_truncate(vp, vap->va_size, 0, cred, td)) != 0) + return (error); + } + if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) { + if (vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + /* + * From utimes(2): + * If times is NULL, ... The caller must be the owner of + * the file, have permission to write the file, or be the + * super-user. + * If times is non-NULL, ... The caller must be the owner of + * the file or be the super-user. + */ + if ((error = VOP_ACCESS(vp, VADMIN, cred, td)) && + ((vap->va_vaflags & VA_UTIMES_NULL) == 0 || + (error = VOP_ACCESS(vp, VWRITE, cred, td)))) + return (error); + if (vap->va_atime.tv_sec != VNOVAL) + ip->i_flag |= IN_ACCESS; + if (vap->va_mtime.tv_sec != VNOVAL) + ip->i_flag |= IN_CHANGE | IN_UPDATE; + ext2_itimes(vp); + if (vap->va_atime.tv_sec != VNOVAL) { + ip->i_atime = vap->va_atime.tv_sec; + ip->i_atimensec = vap->va_atime.tv_nsec; + } + if (vap->va_mtime.tv_sec != VNOVAL) { + ip->i_mtime = vap->va_mtime.tv_sec; + ip->i_mtimensec = vap->va_mtime.tv_nsec; + } + error = ext2_update(vp, 0); + if (error) + return (error); + } + error = 0; + if (vap->va_mode != (mode_t)VNOVAL) { + if (vp->v_mount->mnt_flag & MNT_RDONLY) + return (EROFS); + error = ext2_chmod(vp, (int)vap->va_mode, cred, td); + } + VN_KNOTE(vp, NOTE_ATTRIB); + return (error); +} + +/* + * Change the mode on a file. + * Inode must be locked before calling. + */ +static int +ext2_chmod(vp, mode, cred, td) + struct vnode *vp; + int mode; + struct ucred *cred; + struct thread *td; +{ + struct inode *ip = VTOI(vp); + int error; + + /* + * To modify the permissions on a file, must possess VADMIN + * for that file. + */ + if ((error = VOP_ACCESS(vp, VADMIN, cred, td))) + return (error); + /* + * Privileged processes may set the sticky bit on non-directories, + * as well as set the setgid bit on a file with a group that the + * process is not a member of. + */ + if (suser_cred(cred, PRISON_ROOT)) { + if (vp->v_type != VDIR && (mode & S_ISTXT)) + return (EFTYPE); + if (!groupmember(ip->i_gid, cred) && (mode & ISGID)) + return (EPERM); + } + ip->i_mode &= ~ALLPERMS; + ip->i_mode |= (mode & ALLPERMS); + ip->i_flag |= IN_CHANGE; + return (0); +} + +/* + * Perform chown operation on inode ip; + * inode must be locked prior to call. + */ +static int +ext2_chown(vp, uid, gid, cred, td) + struct vnode *vp; + uid_t uid; + gid_t gid; + struct ucred *cred; + struct thread *td; +{ + struct inode *ip = VTOI(vp); + uid_t ouid; + gid_t ogid; + int error = 0; + + if (uid == (uid_t)VNOVAL) + uid = ip->i_uid; + if (gid == (gid_t)VNOVAL) + gid = ip->i_gid; + /* + * To modify the ownership of a file, must possess VADMIN + * for that file. + */ + if ((error = VOP_ACCESS(vp, VADMIN, cred, td))) + return (error); + /* + * To change the owner of a file, or change the group of a file + * to a group of which we are not a member, the caller must + * have privilege. + */ + if ((uid != ip->i_uid || + (gid != ip->i_gid && !groupmember(gid, cred))) && + (error = suser_cred(cred, PRISON_ROOT))) + return (error); + ogid = ip->i_gid; + ouid = ip->i_uid; + ip->i_gid = gid; + ip->i_uid = uid; + ip->i_flag |= IN_CHANGE; + if (suser_cred(cred, PRISON_ROOT) && (ouid != uid || ogid != gid)) + ip->i_mode &= ~(ISUID | ISGID); + return (0); +} + /* * Synch an open file. */ @@ -241,7 +730,7 @@ loop: #endif } splx(s); - return (UFS_UPDATE(ap->a_vp, ap->a_waitfor == MNT_WAIT)); + return (ext2_update(ap->a_vp, ap->a_waitfor == MNT_WAIT)); } /* @@ -341,7 +830,7 @@ ext2_link(ap) #ifdef DIAGNOSTIC if ((cnp->cn_flags & HASBUF) == 0) - panic("ufs_link: no name"); + panic("ext2_link: no name"); #endif if (tdvp->v_mount != vp->v_mount) { error = EXDEV; @@ -361,7 +850,7 @@ ext2_link(ap) } ip->i_nlink++; ip->i_flag |= IN_CHANGE; - error = UFS_UPDATE(vp, 1); + error = ext2_update(vp, 1); if (!error) error = ext2_direnter(ip, tdvp, cnp); if (error) { @@ -406,7 +895,7 @@ ext2_rename(ap) #ifdef DIAGNOSTIC if ((tcnp->cn_flags & HASBUF) == 0 || (fcnp->cn_flags & HASBUF) == 0) - panic("ufs_rename: no name"); + panic("ext2_rename: no name"); #endif /* * Check for cross-device rename. @@ -447,7 +936,7 @@ abortit: * completed before the lookup. */ #ifdef UFS_RENAME_DEBUG - printf("ufs_rename: fvp == tvp for directories\n"); + printf("ext2_rename: fvp == tvp for directories\n"); #endif error = ENOENT; goto abortit; @@ -474,7 +963,7 @@ abortit: vrele(fdvp); if (fvp == NULL) { #ifdef UFS_RENAME_DEBUG - printf("ufs_rename: from name disappeared\n"); + printf("ext2_rename: from name disappeared\n"); #endif return (ENOENT); } @@ -536,7 +1025,7 @@ abortit: */ ip->i_nlink++; ip->i_flag |= IN_CHANGE; - if ((error = UFS_UPDATE(fvp, 1)) != 0) { + if ((error = ext2_update(fvp, 1)) != 0) { VOP_UNLOCK(fvp, 0, td); goto bad; } @@ -582,7 +1071,7 @@ abortit: */ if (xp == NULL) { if (dp->i_dev != ip->i_dev) - panic("ufs_rename: EXDEV"); + panic("ext2_rename: EXDEV"); /* * Account for ".." in new directory. * When source and destination have the same @@ -595,7 +1084,7 @@ abortit: } dp->i_nlink++; dp->i_flag |= IN_CHANGE; - error = UFS_UPDATE(tdvp, 1); + error = ext2_update(tdvp, 1); if (error) goto bad; } @@ -604,19 +1093,19 @@ abortit: if (doingdirectory && newparent) { dp->i_nlink--; dp->i_flag |= IN_CHANGE; - (void)UFS_UPDATE(tdvp, 1); + (void)ext2_update(tdvp, 1); } goto bad; } vput(tdvp); } else { if (xp->i_dev != dp->i_dev || xp->i_dev != ip->i_dev) - panic("ufs_rename: EXDEV"); + panic("ext2_rename: EXDEV"); /* * Short circuit rename(foo, foo). */ if (xp->i_number == ip->i_number) - panic("ufs_rename: same file"); + panic("ext2_rename: same file"); /* * If the parent directory is "sticky", then the user must * own the parent directory, or the destination of the rename, @@ -676,8 +1165,8 @@ abortit: xp->i_nlink--; if (doingdirectory) { if (--xp->i_nlink != 0) - panic("ufs_rename: linked directory"); - error = UFS_TRUNCATE(tvp, (off_t)0, IO_SYNC, + panic("ext2_rename: linked directory"); + error = ext2_truncate(tvp, (off_t)0, IO_SYNC, tcnp->cn_cred, tcnp->cn_thread); } xp->i_flag |= IN_CHANGE; @@ -702,7 +1191,7 @@ abortit: * From name has disappeared. */ if (doingdirectory) - panic("ufs_rename: lost dir entry"); + panic("ext2_rename: lost dir entry"); vrele(ap->a_fvp); return (0); } @@ -718,7 +1207,7 @@ abortit: */ if (xp != ip) { if (doingdirectory) - panic("ufs_rename: lost dir entry"); + panic("ext2_rename: lost dir entry"); } else { /* * If the source is a directory with a @@ -739,7 +1228,7 @@ abortit: if (namlen != 2 || dirbuf.dotdot_name[0] != '.' || dirbuf.dotdot_name[1] != '.') { - ufs_dirbad(xp, (doff_t)12, + ext2_dirbad(xp, (doff_t)12, "rename: mangled dir"); } else { dirbuf.dotdot_ino = newparent; @@ -807,7 +1296,7 @@ ext2_mkdir(ap) #ifdef DIAGNOSTIC if ((cnp->cn_flags & HASBUF) == 0) - panic("ufs_mkdir: no name"); + panic("ext2_mkdir: no name"); #endif dp = VTOI(dvp); if ((nlink_t)dp->i_nlink >= LINK_MAX) { @@ -821,17 +1310,13 @@ ext2_mkdir(ap) * but not have it entered in the parent directory. The entry is * made later after writing "." and ".." entries. */ - error = UFS_VALLOC(dvp, dmode, cnp->cn_cred, &tvp); + error = ext2_valloc(dvp, dmode, cnp->cn_cred, &tvp); if (error) goto out; ip = VTOI(tvp); ip->i_gid = dp->i_gid; #ifdef SUIDDIR { -#ifdef QUOTA - struct ucred ucred, *ucp; - ucp = cnp->cn_cred; -#endif /* * if we are hacking owners here, (only do this where told to) * and we are not giving it TOO root, (would subvert quotas) @@ -844,44 +1329,12 @@ ext2_mkdir(ap) (dp->i_mode & ISUID) && dp->i_uid) { dmode |= ISUID; ip->i_uid = dp->i_uid; -#ifdef QUOTA - if (dp->i_uid != cnp->cn_cred->cr_uid) { - /* - * make sure the correct user gets charged - * for the space. - * Make a dummy credential for the victim. - * XXX This seems to never be accessed out of - * our context so a stack variable is ok. - */ - ucred.cr_ref = 1; - ucred.cr_uid = ip->i_uid; - ucred.cr_ngroups = 1; - ucred.cr_groups[0] = dp->i_gid; - ucp = &ucred; - } -#endif } else { ip->i_uid = cnp->cn_cred->cr_uid; } -#ifdef QUOTA - if ((error = getinoquota(ip)) || - (error = chkiq(ip, 1, ucp, 0))) { - UFS_VFREE(tvp, ip->i_number, dmode); - vput(tvp); - return (error); - } -#endif } #else ip->i_uid = cnp->cn_cred->cr_uid; -#ifdef QUOTA - if ((error = getinoquota(ip)) || - (error = chkiq(ip, 1, cnp->cn_cred, 0))) { - UFS_VFREE(tvp, ip->i_number, dmode); - vput(tvp); - return (error); - } -#endif #endif ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; ip->i_mode = dmode; @@ -889,7 +1342,7 @@ ext2_mkdir(ap) ip->i_nlink = 2; if (cnp->cn_flags & ISWHITEOUT) ip->i_flags |= UF_OPAQUE; - error = UFS_UPDATE(tvp, 1); + error = ext2_update(tvp, 1); /* * Bump link count in parent directory @@ -899,7 +1352,7 @@ ext2_mkdir(ap) */ dp->i_nlink++; dp->i_flag |= IN_CHANGE; - error = UFS_UPDATE(dvp, 1); + error = ext2_update(dvp, 1); if (error) goto bad; @@ -926,8 +1379,9 @@ ext2_mkdir(ap) dp->i_flag |= IN_CHANGE; goto bad; } - if (DIRBLKSIZ > VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize) - panic("ufs_mkdir: blksize"); /* XXX should grow with balloc() */ + if (DIRBLKSIZ > VFSTOEXT2(dvp->v_mount)->um_mountp->mnt_stat.f_bsize) + /* XXX should grow with balloc() */ + panic("ext2_mkdir: blksize"); else { ip->i_size = DIRBLKSIZ; ip->i_flag |= IN_CHANGE; @@ -1018,7 +1472,7 @@ ext2_rmdir(ap) * worry about them later. */ ip->i_nlink -= 2; - error = UFS_TRUNCATE(vp, (off_t)0, IO_SYNC, cnp->cn_cred, td); + error = ext2_truncate(vp, (off_t)0, IO_SYNC, cnp->cn_cred, td); cache_purge(ITOV(ip)); vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, td); out: @@ -1062,6 +1516,362 @@ ext2_symlink(ap) return (error); } +/* + * Return target name of a symbolic link + */ +static int +ext2_readlink(ap) + struct vop_readlink_args /* { + struct vnode *a_vp; + struct uio *a_uio; + struct ucred *a_cred; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct inode *ip = VTOI(vp); + int isize; + + isize = ip->i_size; + if (isize < vp->v_mount->mnt_maxsymlinklen) { + uiomove((char *)ip->i_shortlink, isize, ap->a_uio); + return (0); + } + return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred)); +} + +/* + * Calculate the logical to physical mapping if not done already, + * then call the device strategy routine. + * + * In order to be able to swap to a file, the ext2_bmaparray() operation may not + * deadlock on memory. See ext2_bmap() for details. + */ +int +ext2_strategy(ap) + struct vop_strategy_args /* { + struct vnode *a_vp; + struct buf *a_bp; + } */ *ap; +{ + struct buf *bp = ap->a_bp; + struct vnode *vp = ap->a_vp; + struct inode *ip; + daddr_t blkno; + int error; + + ip = VTOI(vp); + if (vp->v_type == VBLK || vp->v_type == VCHR) + panic("ext2_strategy: spec"); + if (bp->b_blkno == bp->b_lblkno) { + error = ext2_bmaparray(vp, bp->b_lblkno, &blkno, NULL, NULL); + bp->b_blkno = blkno; + if (error) { + bp->b_error = error; + bp->b_ioflags |= BIO_ERROR; + bufdone(bp); + return (error); + } + if ((long)bp->b_blkno == -1) + vfs_bio_clrbuf(bp); + } + if ((long)bp->b_blkno == -1) { + bufdone(bp); + return (0); + } + vp = ip->i_devvp; + bp->b_dev = vp->v_rdev; + VOP_STRATEGY(vp, bp); + return (0); +} + +/* + * Print out the contents of an inode. + */ +int +ext2_print(ap) + struct vop_print_args /* { + struct vnode *a_vp; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct inode *ip = VTOI(vp); + + printf("tag VT_UFS, ino %lu, on dev %s (%d, %d)", + (u_long)ip->i_number, devtoname(ip->i_dev), major(ip->i_dev), + minor(ip->i_dev)); + if (vp->v_type == VFIFO) + fifo_printinfo(vp); + lockmgr_printinfo(&vp->v_lock); + printf("\n"); + return (0); +} + +/* + * Read wrapper for special devices. + */ +int +ext2spec_read(ap) + struct vop_read_args /* { + struct vnode *a_vp; + struct uio *a_uio; + int a_ioflag; + struct ucred *a_cred; + } */ *ap; +{ + int error, resid; + struct inode *ip; + struct uio *uio; + + uio = ap->a_uio; + resid = uio->uio_resid; + error = VOCALL(spec_vnodeop_p, VOFFSET(vop_read), ap); + /* + * The inode may have been revoked during the call, so it must not + * be accessed blindly here or in the other wrapper functions. + */ + ip = VTOI(ap->a_vp); + if (ip != NULL && (uio->uio_resid != resid || (error == 0 && resid != 0))) + ip->i_flag |= IN_ACCESS; + return (error); +} + +/* + * Write wrapper for special devices. + */ +int +ext2spec_write(ap) + struct vop_write_args /* { + struct vnode *a_vp; + struct uio *a_uio; + int a_ioflag; + struct ucred *a_cred; + } */ *ap; +{ + int error, resid; + struct inode *ip; + struct uio *uio; + + uio = ap->a_uio; + resid = uio->uio_resid; + error = VOCALL(spec_vnodeop_p, VOFFSET(vop_write), ap); + ip = VTOI(ap->a_vp); + if (ip != NULL && (uio->uio_resid != resid || (error == 0 && resid != 0))) + VTOI(ap->a_vp)->i_flag |= IN_CHANGE | IN_UPDATE; + return (error); +} + +/* + * Close wrapper for special devices. + * + * Update the times on the inode then do device close. + */ +int +ext2spec_close(ap) + struct vop_close_args /* { + struct vnode *a_vp; + int a_fflag; + struct ucred *a_cred; + struct thread *a_td; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + + mtx_lock(&vp->v_interlock); + if (vp->v_usecount > 1) + ext2_itimes(vp); + mtx_unlock(&vp->v_interlock); + return (VOCALL(spec_vnodeop_p, VOFFSET(vop_close), ap)); +} + +/* + * Read wrapper for fifos. + */ +int +ext2fifo_read(ap) + struct vop_read_args /* { + struct vnode *a_vp; + struct uio *a_uio; + int a_ioflag; + struct ucred *a_cred; + } */ *ap; +{ + int error, resid; + struct inode *ip; + struct uio *uio; + + uio = ap->a_uio; + resid = uio->uio_resid; + error = VOCALL(fifo_vnodeop_p, VOFFSET(vop_read), ap); + ip = VTOI(ap->a_vp); + if ((ap->a_vp->v_mount->mnt_flag & MNT_NOATIME) == 0 && ip != NULL && + (uio->uio_resid != resid || (error == 0 && resid != 0))) + VTOI(ap->a_vp)->i_flag |= IN_ACCESS; + return (error); +} + +/* + * Write wrapper for fifos. + */ +int +ext2fifo_write(ap) + struct vop_write_args /* { + struct vnode *a_vp; + struct uio *a_uio; + int a_ioflag; + struct ucred *a_cred; + } */ *ap; +{ + int error, resid; + struct inode *ip; + struct uio *uio; + + uio = ap->a_uio; + resid = uio->uio_resid; + error = VOCALL(fifo_vnodeop_p, VOFFSET(vop_write), ap); + ip = VTOI(ap->a_vp); + if (ip != NULL && (uio->uio_resid != resid || (error == 0 && resid != 0))) + VTOI(ap->a_vp)->i_flag |= IN_CHANGE | IN_UPDATE; + return (error); +} + +/* + * Close wrapper for fifos. + * + * Update the times on the inode then do device close. + */ +int +ext2fifo_close(ap) + struct vop_close_args /* { + struct vnode *a_vp; + int a_fflag; + struct ucred *a_cred; + struct thread *a_td; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + + mtx_lock(&vp->v_interlock); + if (vp->v_usecount > 1) + ext2_itimes(vp); + mtx_unlock(&vp->v_interlock); + return (VOCALL(fifo_vnodeop_p, VOFFSET(vop_close), ap)); +} + +/* + * Kqfilter wrapper for fifos. + * + * Fall through to ext2 kqfilter routines if needed + */ +int +ext2fifo_kqfilter(ap) + struct vop_kqfilter_args *ap; +{ + int error; + + error = VOCALL(fifo_vnodeop_p, VOFFSET(vop_kqfilter), ap); + if (error) + error = ext2_kqfilter(ap); + return (error); +} + +/* + * Return POSIX pathconf information applicable to ext2 filesystems. + */ +int +ext2_pathconf(ap) + struct vop_pathconf_args /* { + struct vnode *a_vp; + int a_name; + int *a_retval; + } */ *ap; +{ + + switch (ap->a_name) { + case _PC_LINK_MAX: + *ap->a_retval = LINK_MAX; + return (0); + case _PC_NAME_MAX: + *ap->a_retval = NAME_MAX; + return (0); + case _PC_PATH_MAX: + *ap->a_retval = PATH_MAX; + return (0); + case _PC_PIPE_BUF: + *ap->a_retval = PIPE_BUF; + return (0); + case _PC_CHOWN_RESTRICTED: + *ap->a_retval = 1; + return (0); + case _PC_NO_TRUNC: + *ap->a_retval = 1; + return (0); + default: + return (EINVAL); + } + /* NOTREACHED */ +} + +/* + * Advisory record locking support + */ +static int +ext2_advlock(ap) + struct vop_advlock_args /* { + struct vnode *a_vp; + caddr_t a_id; + int a_op; + struct flock *a_fl; + int a_flags; + } */ *ap; +{ + struct inode *ip = VTOI(ap->a_vp); + + return (lf_advlock(ap, &(ip->i_lockf), ip->i_size)); +} + +/* + * Initialize the vnode associated with a new inode, handle aliased + * vnodes. + */ +int +ext2_vinit(mntp, specops, fifoops, vpp) + struct mount *mntp; + vop_t **specops; + vop_t **fifoops; + struct vnode **vpp; +{ + struct inode *ip; + struct vnode *vp; + struct timeval tv; + + vp = *vpp; + ip = VTOI(vp); + switch(vp->v_type = IFTOVT(ip->i_mode)) { + case VCHR: + case VBLK: + vp->v_op = specops; + vp = addaliasu(vp, ip->i_rdev); + ip->i_vnode = vp; + break; + case VFIFO: + vp->v_op = fifoops; + break; + default: + break; + + } + if (ip->i_number == ROOTINO) + vp->v_flag |= VROOT; + /* + * Initialize modrev times + */ + getmicrouptime(&tv); + SETHIGH(ip->i_modrev, tv.tv_sec); + SETLOW(ip->i_modrev, tv.tv_usec * 4294); + *vpp = vp; + return (0); +} + /* * Allocate a new inode. */ @@ -1085,7 +1895,7 @@ ext2_makeinode(mode, dvp, vpp, cnp) if ((mode & IFMT) == 0) mode |= IFREG; - error = UFS_VALLOC(dvp, mode, cnp->cn_cred, &tvp); + error = ext2_valloc(dvp, mode, cnp->cn_cred, &tvp); if (error) { return (error); } @@ -1093,10 +1903,6 @@ ext2_makeinode(mode, dvp, vpp, cnp) ip->i_gid = pdir->i_gid; #ifdef SUIDDIR { -#ifdef QUOTA - struct ucred ucred, *ucp; - ucp = cnp->cn_cred; -#endif /* * if we are * not the owner of the directory, @@ -1110,43 +1916,12 @@ ext2_makeinode(mode, dvp, vpp, cnp) (pdir->i_uid != cnp->cn_cred->cr_uid) && pdir->i_uid) { ip->i_uid = pdir->i_uid; mode &= ~07111; -#ifdef QUOTA - /* - * make sure the correct user gets charged - * for the space. - * Quickly knock up a dummy credential for the victim. - * XXX This seems to never be accessed out of our - * context so a stack variable is ok. - */ - ucred.cr_ref = 1; - ucred.cr_uid = ip->i_uid; - ucred.cr_ngroups = 1; - ucred.cr_groups[0] = pdir->i_gid; - ucp = &ucred; -#endif } else { ip->i_uid = cnp->cn_cred->cr_uid; } - -#ifdef QUOTA - if ((error = getinoquota(ip)) || - (error = chkiq(ip, 1, ucp, 0))) { - UFS_VFREE(tvp, ip->i_number, mode); - vput(tvp); - return (error); - } -#endif } #else ip->i_uid = cnp->cn_cred->cr_uid; -#ifdef QUOTA - if ((error = getinoquota(ip)) || - (error = chkiq(ip, 1, cnp->cn_cred, 0))) { - UFS_VFREE(tvp, ip->i_number, mode); - vput(tvp); - return (error); - } -#endif #endif ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE; ip->i_mode = mode; @@ -1162,7 +1937,7 @@ ext2_makeinode(mode, dvp, vpp, cnp) /* * Make sure inode goes to disk before directory entry. */ - error = UFS_UPDATE(tvp, 1); + error = ext2_update(tvp, 1); if (error) goto bad; error = ext2_direnter(ip, dvp, cnp); @@ -1182,3 +1957,106 @@ bad: vput(tvp); return (error); } + +static struct filterops ext2read_filtops = + { 1, NULL, filt_ext2detach, filt_ext2read }; +static struct filterops ext2write_filtops = + { 1, NULL, filt_ext2detach, filt_ext2write }; +static struct filterops ext2vnode_filtops = + { 1, NULL, filt_ext2detach, filt_ext2vnode }; + +static int +ext2_kqfilter(ap) + struct vop_kqfilter_args /* { + struct vnode *a_vp; + struct knote *a_kn; + } */ *ap; +{ + struct vnode *vp = ap->a_vp; + struct knote *kn = ap->a_kn; + + switch (kn->kn_filter) { + case EVFILT_READ: + kn->kn_fop = &ext2read_filtops; + break; + case EVFILT_WRITE: + kn->kn_fop = &ext2write_filtops; + break; + case EVFILT_VNODE: + kn->kn_fop = &ext2vnode_filtops; + break; + default: + return (1); + } + + kn->kn_hook = (caddr_t)vp; + + if (vp->v_pollinfo == NULL) + v_addpollinfo(vp); + mtx_lock(&vp->v_pollinfo->vpi_lock); + SLIST_INSERT_HEAD(&vp->v_pollinfo->vpi_selinfo.si_note, kn, kn_selnext); + mtx_unlock(&vp->v_pollinfo->vpi_lock); + + return (0); +} + +static void +filt_ext2detach(struct knote *kn) +{ + struct vnode *vp = (struct vnode *)kn->kn_hook; + + KASSERT(vp->v_pollinfo != NULL, ("Mising v_pollinfo")); + mtx_lock(&vp->v_pollinfo->vpi_lock); + SLIST_REMOVE(&vp->v_pollinfo->vpi_selinfo.si_note, + kn, knote, kn_selnext); + mtx_unlock(&vp->v_pollinfo->vpi_lock); +} + +/*ARGSUSED*/ +static int +filt_ext2read(struct knote *kn, long hint) +{ + struct vnode *vp = (struct vnode *)kn->kn_hook; + struct inode *ip = VTOI(vp); + + /* + * filesystem is gone, so set the EOF flag and schedule + * the knote for deletion. + */ + if (hint == NOTE_REVOKE) { + kn->kn_flags |= (EV_EOF | EV_ONESHOT); + return (1); + } + + kn->kn_data = ip->i_size - kn->kn_fp->f_offset; + return (kn->kn_data != 0); +} + +/*ARGSUSED*/ +static int +filt_ext2write(struct knote *kn, long hint) +{ + + /* + * filesystem is gone, so set the EOF flag and schedule + * the knote for deletion. + */ + if (hint == NOTE_REVOKE) + kn->kn_flags |= (EV_EOF | EV_ONESHOT); + + kn->kn_data = 0; + return (1); +} + +static int +filt_ext2vnode(struct knote *kn, long hint) +{ + + if (kn->kn_sfflags & hint) + kn->kn_fflags |= hint; + if (hint == NOTE_REVOKE) { + kn->kn_flags |= EV_EOF; + return (1); + } + return (kn->kn_fflags != 0); +} diff --git a/sys/gnu/fs/ext2fs/fs.h b/sys/gnu/fs/ext2fs/fs.h index 785f267f8ac3..50fb711f371f 100644 --- a/sys/gnu/fs/ext2fs/fs.h +++ b/sys/gnu/fs/ext2fs/fs.h @@ -148,7 +148,7 @@ extern u_char *fragtbl[]; * I haven't figured out yet what BSD does * I think I'll try a VOP_LOCK/VOP_UNLOCK on the device vnode */ -#define DEVVP(inode) (VFSTOUFS(ITOV(inode)->v_mount)->um_devvp) +#define DEVVP(inode) (VFSTOEXT2(ITOV(inode)->v_mount)->um_devvp) #define lock_super(devvp) vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, curthread) #define unlock_super(devvp) VOP_UNLOCK(devvp, 0, curthread) diff --git a/sys/modules/ext2fs/Makefile b/sys/modules/ext2fs/Makefile index 9de1d6c5e948..b746452d5baa 100644 --- a/sys/modules/ext2fs/Makefile +++ b/sys/modules/ext2fs/Makefile @@ -3,8 +3,8 @@ .PATH: ${.CURDIR}/../../gnu/ext2fs KMOD= ext2fs SRCS= opt_ddb.h opt_quota.h opt_suiddir.h vnode_if.h \ - ext2_alloc.c ext2_balloc.c ext2_inode.c ext2_inode_cnv.c \ - ext2_linux_balloc.c ext2_linux_ialloc.c ext2_lookup.c ext2_subr.c \ - ext2_vfsops.c ext2_vnops.c + ext2_alloc.c ext2_balloc.c ext2_bmap.c ext2_ihash.c ext2_inode.c \ + ext2_inode_cnv.c ext2_linux_balloc.c ext2_linux_ialloc.c \ + ext2_lookup.c ext2_subr.c ext2_vfsops.c ext2_vnops.c .include <bsd.kmod.mk>