summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiall O'Higgins <niallo@cvs.openbsd.org>2005-04-30 13:58:56 +0000
committerNiall O'Higgins <niallo@cvs.openbsd.org>2005-04-30 13:58:56 +0000
commit514bc6a5729982dd3c7efdc28baecc1f45061898 (patch)
treee0902c81534b844c63dab4530603b0fa066babdc
parente723898372517d7a195b4eb18912751f9316ae2e (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.h5
-rw-r--r--sys/ufs/ext2fs/ext2fs_extern.h4
-rw-r--r--sys/ufs/ext2fs/ext2fs_inode.c67
-rw-r--r--sys/ufs/ext2fs/ext2fs_lookup.c29
-rw-r--r--sys/ufs/ext2fs/ext2fs_readwrite.c24
-rw-r--r--sys/ufs/ext2fs/ext2fs_vfsops.c5
-rw-r--r--sys/ufs/ext2fs/ext2fs_vnops.c23
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));
}