diff options
author | Niall O'Higgins <niallo@cvs.openbsd.org> | 2005-04-30 13:58:56 +0000 |
---|---|---|
committer | Niall O'Higgins <niallo@cvs.openbsd.org> | 2005-04-30 13:58:56 +0000 |
commit | 514bc6a5729982dd3c7efdc28baecc1f45061898 (patch) | |
tree | e0902c81534b844c63dab4530603b0fa066babdc | |
parent | e723898372517d7a195b4eb18912751f9316ae2e (diff) |
Add support for large files (> 4GB).
Automatically converts old filesystems to use this if they are already at
revision 1 (like Linux). Revision 0 filesystems don't get converted (unlike
Linux).
From NetBSD
-rw-r--r-- | sys/ufs/ext2fs/ext2fs.h | 5 | ||||
-rw-r--r-- | sys/ufs/ext2fs/ext2fs_extern.h | 4 | ||||
-rw-r--r-- | sys/ufs/ext2fs/ext2fs_inode.c | 67 | ||||
-rw-r--r-- | sys/ufs/ext2fs/ext2fs_lookup.c | 29 | ||||
-rw-r--r-- | sys/ufs/ext2fs/ext2fs_readwrite.c | 24 | ||||
-rw-r--r-- | sys/ufs/ext2fs/ext2fs_vfsops.c | 5 | ||||
-rw-r--r-- | sys/ufs/ext2fs/ext2fs_vnops.c | 23 |
7 files changed, 111 insertions, 46 deletions
diff --git a/sys/ufs/ext2fs/ext2fs.h b/sys/ufs/ext2fs/ext2fs.h index 62c44cf5eeb..14d5aa57ad8 100644 --- a/sys/ufs/ext2fs/ext2fs.h +++ b/sys/ufs/ext2fs/ext2fs.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ext2fs.h,v 1.9 2003/06/02 23:28:22 millert Exp $ */ +/* $OpenBSD: ext2fs.h,v 1.10 2005/04/30 13:58:55 niallo Exp $ */ /* $NetBSD: ext2fs.h,v 1.10 2000/01/28 16:00:23 bouyer Exp $ */ /* @@ -182,7 +182,8 @@ struct m_ext2fs { /* features supported in this implementation */ #define EXT2F_COMPAT_SUPP 0x0000 -#define EXT2F_ROCOMPAT_SUPP EXT2F_ROCOMPAT_SPARSESUPER +#define EXT2F_ROCOMPAT_SUPP (EXT2F_ROCOMPAT_SPARSESUPER \ + | EXT2F_ROCOMPAT_LARGEFILE) #define EXT2F_INCOMPAT_SUPP EXT2F_INCOMPAT_FTYPE /* diff --git a/sys/ufs/ext2fs/ext2fs_extern.h b/sys/ufs/ext2fs/ext2fs_extern.h index 141b6177ca6..d4b68ae3039 100644 --- a/sys/ufs/ext2fs/ext2fs_extern.h +++ b/sys/ufs/ext2fs/ext2fs_extern.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ext2fs_extern.h,v 1.20 2004/07/13 21:04:29 millert Exp $ */ +/* $OpenBSD: ext2fs_extern.h,v 1.21 2005/04/30 13:58:55 niallo Exp $ */ /* $NetBSD: ext2fs_extern.h,v 1.1 1997/06/11 09:33:55 bouyer Exp $ */ /*- @@ -76,6 +76,8 @@ int ext2fs_bmap(void *); /* ext2fs_inode.c */ int ext2fs_init(struct vfsconf *); +u_int64_t ext2fs_size(struct inode *); +int ext2fs_setsize(struct inode *, u_int64_t); int ext2fs_update(struct inode *ip, struct timespec *atime, struct timespec *mtime, int waitfor); int ext2fs_truncate(struct inode *, off_t, int, struct ucred *); diff --git a/sys/ufs/ext2fs/ext2fs_inode.c b/sys/ufs/ext2fs/ext2fs_inode.c index 05978497fdf..343f029acb5 100644 --- a/sys/ufs/ext2fs/ext2fs_inode.c +++ b/sys/ufs/ext2fs/ext2fs_inode.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ext2fs_inode.c,v 1.25 2004/06/24 19:35:26 tholo Exp $ */ +/* $OpenBSD: ext2fs_inode.c,v 1.26 2005/04/30 13:58:55 niallo Exp $ */ /* $NetBSD: ext2fs_inode.c,v 1.24 2001/06/19 12:59:18 wiz Exp $ */ /* @@ -60,6 +60,48 @@ static int ext2fs_indirtrunc(struct inode *, ufs1_daddr_t, ufs1_daddr_t, ufs1_daddr_t, int, long *); /* + * Get the size of an inode. + */ +u_int64_t +ext2fs_size(struct inode *ip) +{ + u_int64_t size = ip->i_e2fs_size; + + if ((ip->i_e2fs_mode & IFMT) == IFREG) + size |= (u_int64_t)ip->i_e2fs_dacl << 32; + return size; +} + +int +ext2fs_setsize(struct inode *ip, u_int64_t size) +{ + if ((ip->i_e2fs_mode & IFMT) == IFREG || + ip->i_e2fs_mode == 0) { + ip->i_e2fs_dacl = size >> 32; + if (size >= 0x80000000U) { + struct m_ext2fs *fs = ip->i_e2fs; + + if (fs->e2fs.e2fs_rev <= E2FS_REV0) { + /* Linux automagically upgrades to REV1 here! */ + return EFBIG; + } + if (!(fs->e2fs.e2fs_features_rocompat + & EXT2F_ROCOMPAT_LARGEFILE)) { + fs->e2fs.e2fs_features_rocompat |= + EXT2F_ROCOMPAT_LARGEFILE; + fs->e2fs_fmod = 1; + } + } + } else if (size >= 0x80000000U) + return EFBIG; + + ip->i_e2fs_size = size; + + return 0; +} + + +/* * Last reference to an inode. If necessary, write or delete it. */ int @@ -85,7 +127,7 @@ ext2fs_inactive(v) error = 0; if (ip->i_e2fs_nlink == 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) { - if (ip->i_e2fs_size != 0) { + if (ext2fs_size(ip) != 0) { error = ext2fs_truncate(ip, (off_t)0, 0, NOCRED); } getnanotime(&ts); @@ -187,7 +229,7 @@ ext2fs_truncate(struct inode *oip, off_t length, int flags, struct ucred *cred) return (0); if (ovp->v_type == VLNK && - (oip->i_e2fs_size < ovp->v_mount->mnt_maxsymlinklen || + (ext2fs_size(oip) < ovp->v_mount->mnt_maxsymlinklen || (ovp->v_mount->mnt_maxsymlinklen == 0 && oip->i_e2fs_nblock == 0))) { #ifdef DIAGNOSTIC @@ -195,17 +237,18 @@ ext2fs_truncate(struct inode *oip, off_t length, int flags, struct ucred *cred) panic("ext2fs_truncate: partial truncate of symlink"); #endif bzero((char *)&oip->i_e2din.e2di_shortlink, - (u_int)oip->i_e2fs_size); - oip->i_e2fs_size = 0; + (u_int)ext2fs_size(oip)); + (void)ext2fs_setsize(oip, 0); oip->i_flag |= IN_CHANGE | IN_UPDATE; return (ext2fs_update(oip, NULL, NULL, 1)); } - if (oip->i_e2fs_size == length) { + + if (ext2fs_size(oip) == length) { oip->i_flag |= IN_CHANGE | IN_UPDATE; return (ext2fs_update(oip, NULL, NULL, 0)); } fs = oip->i_e2fs; - osize = oip->i_e2fs_size; + osize = ext2fs_size(oip); /* * Lengthen the size of the file. We must ensure that the * last byte of the file is allocated. Since the smallest @@ -225,7 +268,7 @@ ext2fs_truncate(struct inode *oip, off_t length, int flags, struct ucred *cred) aflags); if (error) return (error); - oip->i_e2fs_size = length; + (void)ext2fs_setsize(oip, length); uvm_vnp_setsize(ovp, length); uvm_vnp_uncache(ovp); if (aflags & B_SYNC) @@ -244,7 +287,7 @@ ext2fs_truncate(struct inode *oip, off_t length, int flags, struct ucred *cred) */ offset = blkoff(fs, length); if (offset == 0) { - oip->i_e2fs_size = length; + (void)ext2fs_setsize(oip, length); } else { lbn = lblkno(fs, length); aflags = B_CLRBUF; @@ -254,7 +297,7 @@ ext2fs_truncate(struct inode *oip, off_t length, int flags, struct ucred *cred) aflags); if (error) return (error); - oip->i_e2fs_size = length; + (void)ext2fs_setsize(oip, length); size = fs->e2fs_bsize; uvm_vnp_setsize(ovp, length); uvm_vnp_uncache(ovp); @@ -301,7 +344,7 @@ ext2fs_truncate(struct inode *oip, off_t length, int flags, struct ucred *cred) */ bcopy((caddr_t)&oip->i_e2fs_blocks[0], (caddr_t)newblks, sizeof newblks); bcopy((caddr_t)oldblks, (caddr_t)&oip->i_e2fs_blocks[0], sizeof oldblks); - oip->i_e2fs_size = osize; + (void)ext2fs_setsize(oip, osize); vflags = ((length > 0) ? V_SAVE : 0) | V_SAVEMETA; allerror = vinvalbuf(ovp, vflags, cred, curproc, 0, 0); @@ -358,7 +401,7 @@ done: /* * Put back the real size. */ - oip->i_e2fs_size = length; + (void)ext2fs_setsize(oip, length); oip->i_e2fs_nblock -= blocksreleased; if (oip->i_e2fs_nblock < 0) /* sanity */ oip->i_e2fs_nblock = 0; diff --git a/sys/ufs/ext2fs/ext2fs_lookup.c b/sys/ufs/ext2fs/ext2fs_lookup.c index 1b08a6c813a..ae6b7a5b9c7 100644 --- a/sys/ufs/ext2fs/ext2fs_lookup.c +++ b/sys/ufs/ext2fs/ext2fs_lookup.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ext2fs_lookup.c,v 1.17 2003/12/06 09:23:25 grange Exp $ */ +/* $OpenBSD: ext2fs_lookup.c,v 1.18 2005/04/30 13:58:55 niallo Exp $ */ /* $NetBSD: ext2fs_lookup.c,v 1.16 2000/08/03 20:29:26 thorpej Exp $ */ /* @@ -209,7 +209,7 @@ ext2fs_readdir(v) uio->uio_offset = off; } FREE(dirbuf, M_TEMP); - *ap->a_eofflag = VTOI(ap->a_vp)->i_e2fs_size <= uio->uio_offset; + *ap->a_eofflag = ext2fs_size(VTOI(ap->a_vp)) <= uio->uio_offset; if (ap->a_ncookies) { if (error) { free(*ap->a_cookies, M_TEMP); @@ -345,7 +345,7 @@ ext2fs_lookup(v) */ bmask = VFSTOUFS(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1; if (nameiop != LOOKUP || dp->i_diroff == 0 || - dp->i_diroff > dp->i_e2fs_size) { + dp->i_diroff >ext2fs_size(dp)) { entryoffsetinblock = 0; dp->i_offset = 0; numdirpasses = 1; @@ -358,7 +358,7 @@ ext2fs_lookup(v) numdirpasses = 2; } prevoff = dp->i_offset; - endsearch = roundup(dp->i_e2fs_size, dirblksize); + endsearch = roundup(ext2fs_size(dp), dirblksize); enduseful = 0; searchloop: @@ -501,7 +501,7 @@ searchloop: * dp->i_offset + dp->i_count. */ if (slotstatus == NONE) { - dp->i_offset = roundup(dp->i_e2fs_size, dirblksize); + dp->i_offset = roundup(ext2fs_size(dp), dirblksize); dp->i_count = 0; enduseful = dp->i_offset; } else { @@ -545,10 +545,14 @@ found: * of this entry. */ if (entryoffsetinblock + EXT2FS_DIRSIZ(ep->e2d_namlen) - > dp->i_e2fs_size) { + > ext2fs_size(dp)) { ufs_dirbad(dp, dp->i_offset, "i_size too small"); - dp->i_e2fs_size = entryoffsetinblock + - EXT2FS_DIRSIZ(ep->e2d_namlen); + error = ext2fs_setsize(dp, + entryoffsetinblock + EXT2FS_DIRSIZ(ep->e2d_namlen)); + if (error) { + brelse(bp); + return(error); + } dp->i_flag |= IN_CHANGE | IN_UPDATE; } @@ -807,7 +811,10 @@ ext2fs_direnter(ip, dvp, cnp) /* XXX should grow with balloc() */ panic("ext2fs_direnter: frag size"); else if (!error) { - dp->i_e2fs_size = roundup(dp->i_e2fs_size, dirblksize); + error = ext2fs_setsize(dp, + roundup(ext2fs_size(dp), dirblksize)); + if (error) + return (error); dp->i_flag |= IN_CHANGE; } return (error); @@ -878,7 +885,7 @@ ext2fs_direnter(ip, dvp, cnp) memcpy((caddr_t)ep, (caddr_t)&newdir, (u_int)newentrysize); error = VOP_BWRITE(bp); dp->i_flag |= IN_CHANGE | IN_UPDATE; - if (!error && dp->i_endoff && dp->i_endoff < dp->i_e2fs_size) + if (!error && dp->i_endoff && dp->i_endoff < ext2fs_size(dp)) error = ext2fs_truncate(dp, (off_t)dp->i_endoff, IO_SYNC, cnp->cn_cred); return (error); @@ -985,7 +992,7 @@ ext2fs_dirempty(ip, parentino, cred) #define MINDIRSIZ (sizeof (struct ext2fs_dirtemplate) / 2) - for (off = 0; off < ip->i_e2fs_size; off += fs2h16(dp->e2d_reclen)) { + for (off = 0; off < ext2fs_size(ip); off += fs2h16(dp->e2d_reclen)) { error = vn_rdwr(UIO_READ, ITOV(ip), (caddr_t)dp, MINDIRSIZ, off, UIO_SYSSPACE, IO_NODELOCKED, cred, &count, (struct proc *)0); /* diff --git a/sys/ufs/ext2fs/ext2fs_readwrite.c b/sys/ufs/ext2fs/ext2fs_readwrite.c index 22088c7825f..49819d64432 100644 --- a/sys/ufs/ext2fs/ext2fs_readwrite.c +++ b/sys/ufs/ext2fs/ext2fs_readwrite.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ext2fs_readwrite.c,v 1.16 2003/06/02 23:28:22 millert Exp $ */ +/* $OpenBSD: ext2fs_readwrite.c,v 1.17 2005/04/30 13:58:55 niallo Exp $ */ /* $NetBSD: ext2fs_readwrite.c,v 1.16 2001/02/27 04:37:47 chs Exp $ */ /*- @@ -90,7 +90,7 @@ ext2fs_read(v) panic("%s: mode", "ext2fs_read"); if (vp->v_type == VLNK) { - if ((int)ip->i_e2fs_size < vp->v_mount->mnt_maxsymlinklen || + if ((int)ext2fs_size(ip) < vp->v_mount->mnt_maxsymlinklen || (vp->v_mount->mnt_maxsymlinklen == 0 && ip->i_e2fs_nblock == 0)) panic("%s: short symlink", "ext2fs_read"); @@ -105,7 +105,7 @@ ext2fs_read(v) return (0); for (error = 0, bp = NULL; uio->uio_resid > 0; bp = NULL) { - if ((bytesinfile = ip->i_e2fs_size - uio->uio_offset) <= 0) + if ((bytesinfile = ext2fs_size(ip) - uio->uio_offset) <= 0) break; lbn = lblkno(fs, uio->uio_offset); nextlbn = lbn + 1; @@ -117,11 +117,11 @@ ext2fs_read(v) if (bytesinfile < xfersize) xfersize = bytesinfile; - if (lblktosize(fs, nextlbn) >= ip->i_e2fs_size) + if (lblktosize(fs, nextlbn) >= ext2fs_size(ip)) error = bread(vp, lbn, size, NOCRED, &bp); else if (doclusterread) error = cluster_read(vp, &ip->i_ci, - ip->i_e2fs_size, lbn, size, NOCRED, &bp); + ext2fs_size(ip), lbn, size, NOCRED, &bp); else if (lbn - 1 == ip->i_ci.ci_lastr) { int nextsize = fs->e2fs_bsize; error = breadn(vp, lbn, @@ -202,9 +202,9 @@ ext2fs_write(v) switch (vp->v_type) { case VREG: if (ioflag & IO_APPEND) - uio->uio_offset = ip->i_e2fs_size; + uio->uio_offset = ext2fs_size(ip); if ((ip->i_e2fs_flags & EXT2_APPEND) && - uio->uio_offset != ip->i_e2fs_size) + uio->uio_offset != ext2fs_size(ip)) return (EPERM); /* FALLTHROUGH */ case VLNK: @@ -235,7 +235,7 @@ ext2fs_write(v) } resid = uio->uio_resid; - osize = ip->i_e2fs_size; + osize = ext2fs_size(ip); flags = ioflag & IO_SYNC ? B_SYNC : 0; for (error = 0; uio->uio_resid > 0;) { @@ -253,8 +253,10 @@ ext2fs_write(v) lbn, blkoffset + xfersize, ap->a_cred, &bp, flags); if (error) break; - if (uio->uio_offset + xfersize > ip->i_e2fs_size) { - ip->i_e2fs_size = uio->uio_offset + xfersize; + if (uio->uio_offset + xfersize > ext2fs_size(ip)) { + error = ext2fs_setsize(ip, uio->uio_offset + xfersize); + if (error) + break; uvm_vnp_setsize(vp, ip->i_e2fs_size); } uvm_vnp_uncache(vp); @@ -269,7 +271,7 @@ ext2fs_write(v) (void)bwrite(bp); else if (xfersize + blkoffset == fs->e2fs_bsize) { if (doclusterwrite) - cluster_write(bp, &ip->i_ci, ip->i_e2fs_size); + cluster_write(bp, &ip->i_ci, ext2fs_size(ip)); else bawrite(bp); } else diff --git a/sys/ufs/ext2fs/ext2fs_vfsops.c b/sys/ufs/ext2fs/ext2fs_vfsops.c index be2943cbf10..158235fb503 100644 --- a/sys/ufs/ext2fs/ext2fs_vfsops.c +++ b/sys/ufs/ext2fs/ext2fs_vfsops.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ext2fs_vfsops.c,v 1.35 2004/12/26 21:22:14 miod Exp $ */ +/* $OpenBSD: ext2fs_vfsops.c,v 1.36 2005/04/30 13:58:55 niallo Exp $ */ /* $NetBSD: ext2fs_vfsops.c,v 1.1 1997/06/11 09:34:07 bouyer Exp $ */ /* @@ -902,7 +902,8 @@ ext2fs_vget(mp, ino, vpp) /* If the inode was deleted, reset all fields */ if (ip->i_e2fs_dtime != 0) { - ip->i_e2fs_mode = ip->i_e2fs_size = ip->i_e2fs_nblock = 0; + ip->i_e2fs_mode = ip->i_e2fs_nblock = 0; + (void)ext2fs_setsize(ip, 0); } /* diff --git a/sys/ufs/ext2fs/ext2fs_vnops.c b/sys/ufs/ext2fs/ext2fs_vnops.c index aff52e500fc..4ba2d3fd780 100644 --- a/sys/ufs/ext2fs/ext2fs_vnops.c +++ b/sys/ufs/ext2fs/ext2fs_vnops.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ext2fs_vnops.c,v 1.37 2004/09/18 22:01:18 tedu Exp $ */ +/* $OpenBSD: ext2fs_vnops.c,v 1.38 2005/04/30 13:58:55 niallo Exp $ */ /* $NetBSD: ext2fs_vnops.c,v 1.1 1997/06/11 09:34:09 bouyer Exp $ */ /* @@ -230,7 +230,7 @@ ext2fs_getattr(v) vap->va_uid = ip->i_e2fs_uid; vap->va_gid = ip->i_e2fs_gid; vap->va_rdev = (dev_t)fs2h32(ip->i_e2din.e2di_rdev); - vap->va_size = ip->i_e2fs_size; + vap->va_size = ext2fs_size(ip); vap->va_atime.tv_sec = ip->i_e2fs_atime; vap->va_atime.tv_nsec = 0; vap->va_mtime.tv_sec = ip->i_e2fs_mtime; @@ -1047,7 +1047,12 @@ ext2fs_mkdir(v) VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize) panic("ext2fs_mkdir: blksize"); /* XXX should grow with balloc() */ else { - ip->i_e2fs_size = VTOI(dvp)->i_e2fs->e2fs_bsize; + error = ext2fs_setsize(ip, VTOI(dvp)->i_e2fs->e2fs_bsize); + if (error) { + dp->i_e2fs_nlink--; + dp->i_flag |= IN_CHANGE; + goto bad; + } ip->i_flag |= IN_CHANGE; } @@ -1181,13 +1186,17 @@ ext2fs_symlink(v) if (len < vp->v_mount->mnt_maxsymlinklen) { ip = VTOI(vp); bcopy(ap->a_target, (char *)ip->i_e2din.e2di_shortlink, len); - ip->i_e2fs_size = len; + error = ext2fs_setsize(ip, len); + if (error) + goto bad; ip->i_flag |= IN_CHANGE | IN_UPDATE; } else error = vn_rdwr(UIO_WRITE, vp, ap->a_target, len, (off_t)0, UIO_SYSSPACE, IO_NODELOCKED, ap->a_cnp->cn_cred, NULL, (struct proc *)0); - vput(vp); +bad: + if (error) + vput(vp); return (error); } @@ -1207,7 +1216,7 @@ ext2fs_readlink(v) register struct inode *ip = VTOI(vp); int isize; - isize = ip->i_e2fs_size; + isize = ext2fs_size(ip); if (isize < vp->v_mount->mnt_maxsymlinklen || (vp->v_mount->mnt_maxsymlinklen == 0 && ip->i_e2fs_nblock == 0)) { uiomove((char *)ip->i_e2din.e2di_shortlink, isize, ap->a_uio); @@ -1232,7 +1241,7 @@ ext2fs_advlock(v) } */ *ap = v; register struct inode *ip = VTOI(ap->a_vp); - return (lf_advlock(&ip->i_lockf, ip->i_e2fs_size, ap->a_id, ap->a_op, + return (lf_advlock(&ip->i_lockf, ext2fs_size(ip), ap->a_id, ap->a_op, ap->a_fl, ap->a_flags)); } |