summaryrefslogtreecommitdiff
path: root/sys/ufs
diff options
context:
space:
mode:
authorChuck Silvers <chs@FreeBSD.org>2020-06-17 23:39:52 +0000
committerChuck Silvers <chs@FreeBSD.org>2020-06-17 23:39:52 +0000
commitd9a8abf6c245f7f3f448269d58f71ef89536377b (patch)
treec3842cbf0f3c4dba419393f0cdfe125ead508176 /sys/ufs
parent78ef79139e8c399d47736f910c030be5c3554c34 (diff)
downloadsrc-test-d9a8abf6c245f7f3f448269d58f71ef89536377b.tar.gz
src-test-d9a8abf6c245f7f3f448269d58f71ef89536377b.zip
Notes
Diffstat (limited to 'sys/ufs')
-rw-r--r--sys/ufs/ffs/ffs_extern.h3
-rw-r--r--sys/ufs/ffs/ffs_subr.c211
-rw-r--r--sys/ufs/ffs/ffs_vfsops.c211
-rw-r--r--sys/ufs/ufs/ufs_vnops.c2
4 files changed, 212 insertions, 215 deletions
diff --git a/sys/ufs/ffs/ffs_extern.h b/sys/ufs/ffs/ffs_extern.h
index 98aace3a3430d..cc148c0ff042b 100644
--- a/sys/ufs/ffs/ffs_extern.h
+++ b/sys/ufs/ffs/ffs_extern.h
@@ -61,7 +61,6 @@ int ffs_balloc_ufs1(struct vnode *a_vp, off_t a_startoffset, int a_size,
struct ucred *a_cred, int a_flags, struct buf **a_bpp);
int ffs_balloc_ufs2(struct vnode *a_vp, off_t a_startoffset, int a_size,
struct ucred *a_cred, int a_flags, struct buf **a_bpp);
-int ffs_blkatoff(struct vnode *, off_t, char **, struct buf **);
void ffs_blkfree(struct ufsmount *, struct fs *, struct vnode *,
ufs2_daddr_t, long, ino_t, enum vtype, struct workhead *, u_long);
ufs2_daddr_t ffs_blkpref_ufs1(struct inode *, ufs_lbn_t, int, ufs1_daddr_t *);
@@ -69,7 +68,6 @@ ufs2_daddr_t ffs_blkpref_ufs2(struct inode *, ufs_lbn_t, int, ufs2_daddr_t *);
void ffs_blkrelease_finish(struct ufsmount *, u_long);
u_long ffs_blkrelease_start(struct ufsmount *, struct vnode *, ino_t);
uint32_t ffs_calc_sbhash(struct fs *);
-int ffs_check_blkno(struct mount *, ino_t, ufs2_daddr_t, int);
int ffs_checkfreefile(struct fs *, struct vnode *, ino_t);
void ffs_clrblock(struct fs *, u_char *, ufs1_daddr_t);
void ffs_clusteracct(struct fs *, struct cg *, ufs1_daddr_t, int);
@@ -84,7 +82,6 @@ int ffs_getcg(struct fs *, struct vnode *, u_int, int, struct buf **,
struct cg **);
int ffs_isblock(struct fs *, u_char *, ufs1_daddr_t);
int ffs_isfreeblock(struct fs *, u_char *, ufs1_daddr_t);
-int ffs_load_inode(struct buf *, struct inode *, struct fs *, ino_t);
void ffs_oldfscompat_write(struct fs *, struct ufsmount *);
int ffs_own_mount(const struct mount *mp);
int ffs_reallocblks(struct vop_reallocblks_args *);
diff --git a/sys/ufs/ffs/ffs_subr.c b/sys/ufs/ffs/ffs_subr.c
index 158c09b096d07..93bbdba72e7c8 100644
--- a/sys/ufs/ffs/ffs_subr.c
+++ b/sys/ufs/ffs/ffs_subr.c
@@ -67,7 +67,6 @@ struct malloc_type;
#include <sys/bio.h>
#include <sys/buf.h>
#include <sys/ucred.h>
-#include <sys/taskqueue.h>
#include <ufs/ufs/quota.h>
#include <ufs/ufs/inode.h>
@@ -81,216 +80,6 @@ struct malloc_type;
#define UFS_FREE(ptr, type) free(ptr, type)
#define UFS_TIME time_second
-/*
- * Return buffer with the contents of block "offset" from the beginning of
- * directory "ip". If "res" is non-zero, fill it in with a pointer to the
- * remaining space in the directory.
- */
-int
-ffs_blkatoff(struct vnode *vp, off_t offset, char **res, struct buf **bpp)
-{
- struct inode *ip;
- struct fs *fs;
- struct buf *bp;
- ufs_lbn_t lbn;
- int bsize, error;
-
- ip = VTOI(vp);
- fs = ITOFS(ip);
- lbn = lblkno(fs, offset);
- bsize = blksize(fs, ip, lbn);
-
- *bpp = NULL;
- error = bread(vp, lbn, bsize, NOCRED, &bp);
- if (error) {
- return (error);
- }
- if (res)
- *res = (char *)bp->b_data + blkoff(fs, offset);
- *bpp = bp;
- return (0);
-}
-
-/*
- * Load up the contents of an inode and copy the appropriate pieces
- * to the incore copy.
- */
-int
-ffs_load_inode(struct buf *bp, struct inode *ip, struct fs *fs, ino_t ino)
-{
- struct ufs1_dinode *dip1;
- struct ufs2_dinode *dip2;
- int error;
-
- if (I_IS_UFS1(ip)) {
- dip1 = ip->i_din1;
- *dip1 =
- *((struct ufs1_dinode *)bp->b_data + ino_to_fsbo(fs, ino));
- ip->i_mode = dip1->di_mode;
- ip->i_nlink = dip1->di_nlink;
- ip->i_effnlink = dip1->di_nlink;
- ip->i_size = dip1->di_size;
- ip->i_flags = dip1->di_flags;
- ip->i_gen = dip1->di_gen;
- ip->i_uid = dip1->di_uid;
- ip->i_gid = dip1->di_gid;
- return (0);
- }
- dip2 = ((struct ufs2_dinode *)bp->b_data + ino_to_fsbo(fs, ino));
- if ((error = ffs_verify_dinode_ckhash(fs, dip2)) != 0 &&
- !ffs_fsfail_cleanup(ITOUMP(ip), error)) {
- printf("%s: inode %jd: check-hash failed\n", fs->fs_fsmnt,
- (intmax_t)ino);
- return (error);
- }
- *ip->i_din2 = *dip2;
- dip2 = ip->i_din2;
- ip->i_mode = dip2->di_mode;
- ip->i_nlink = dip2->di_nlink;
- ip->i_effnlink = dip2->di_nlink;
- ip->i_size = dip2->di_size;
- ip->i_flags = dip2->di_flags;
- ip->i_gen = dip2->di_gen;
- ip->i_uid = dip2->di_uid;
- ip->i_gid = dip2->di_gid;
- return (0);
-}
-
-/*
- * Verify that a filesystem block number is a valid data block.
- * This routine is only called on untrusted filesystems.
- */
-int
-ffs_check_blkno(struct mount *mp, ino_t inum, ufs2_daddr_t daddr, int blksize)
-{
- struct fs *fs;
- struct ufsmount *ump;
- ufs2_daddr_t end_daddr;
- int cg, havemtx;
-
- KASSERT((mp->mnt_flag & MNT_UNTRUSTED) != 0,
- ("ffs_check_blkno called on a trusted file system"));
- ump = VFSTOUFS(mp);
- fs = ump->um_fs;
- cg = dtog(fs, daddr);
- end_daddr = daddr + numfrags(fs, blksize);
- /*
- * Verify that the block number is a valid data block. Also check
- * that it does not point to an inode block or a superblock. Accept
- * blocks that are unalloacted (0) or part of snapshot metadata
- * (BLK_NOCOPY or BLK_SNAP).
- *
- * Thus, the block must be in a valid range for the filesystem and
- * either in the space before a backup superblock (except the first
- * cylinder group where that space is used by the bootstrap code) or
- * after the inode blocks and before the end of the cylinder group.
- */
- if ((uint64_t)daddr <= BLK_SNAP ||
- ((uint64_t)end_daddr <= fs->fs_size &&
- ((cg > 0 && end_daddr <= cgsblock(fs, cg)) ||
- (daddr >= cgdmin(fs, cg) &&
- end_daddr <= cgbase(fs, cg) + fs->fs_fpg))))
- return (0);
- if ((havemtx = mtx_owned(UFS_MTX(ump))) == 0)
- UFS_LOCK(ump);
- if (ppsratecheck(&ump->um_last_integritymsg,
- &ump->um_secs_integritymsg, 1)) {
- UFS_UNLOCK(ump);
- uprintf("\n%s: inode %jd, out-of-range indirect block "
- "number %jd\n", mp->mnt_stat.f_mntonname, inum, daddr);
- if (havemtx)
- UFS_LOCK(ump);
- } else if (!havemtx)
- UFS_UNLOCK(ump);
- return (EINTEGRITY);
-}
-
-/*
- * Initiate a forcible unmount.
- * Used to unmount filesystems whose underlying media has gone away.
- */
-static void
-ffs_fsfail_unmount(void *v, int pending)
-{
- struct fsfail_task *etp;
- struct mount *mp;
-
- etp = v;
-
- /*
- * Find our mount and get a ref on it, then try to unmount.
- */
- mp = vfs_getvfs(&etp->fsid);
- if (mp != NULL)
- dounmount(mp, MNT_FORCE, curthread);
- free(etp, M_UFSMNT);
-}
-
-/*
- * On first ENXIO error, start a task that forcibly unmounts the filesystem.
- *
- * Return true if a cleanup is in progress.
- */
-int
-ffs_fsfail_cleanup(struct ufsmount *ump, int error)
-{
- int retval;
-
- UFS_LOCK(ump);
- retval = ffs_fsfail_cleanup_locked(ump, error);
- UFS_UNLOCK(ump);
- return (retval);
-}
-
-int
-ffs_fsfail_cleanup_locked(struct ufsmount *ump, int error)
-{
- struct fsfail_task *etp;
- struct task *tp;
-
- mtx_assert(UFS_MTX(ump), MA_OWNED);
- if (error == ENXIO && (ump->um_flags & UM_FSFAIL_CLEANUP) == 0) {
- ump->um_flags |= UM_FSFAIL_CLEANUP;
- /*
- * Queue an async forced unmount.
- */
- etp = ump->um_fsfail_task;
- ump->um_fsfail_task = NULL;
- if (etp != NULL) {
- tp = &etp->task;
- TASK_INIT(tp, 0, ffs_fsfail_unmount, etp);
- taskqueue_enqueue(taskqueue_thread, tp);
- printf("UFS: forcibly unmounting %s from %s\n",
- ump->um_mountp->mnt_stat.f_mntfromname,
- ump->um_mountp->mnt_stat.f_mntonname);
- }
- }
- return ((ump->um_flags & UM_FSFAIL_CLEANUP) != 0);
-}
-
-/*
- * Wrapper used during ENXIO cleanup to allocate empty buffers when
- * the kernel is unable to read the real one. They are needed so that
- * the soft updates code can use them to unwind its dependencies.
- */
-int
-ffs_breadz(struct ufsmount *ump, struct vnode *vp, daddr_t lblkno,
- daddr_t dblkno, int size, daddr_t *rablkno, int *rabsize, int cnt,
- struct ucred *cred, int flags, void (*ckhashfunc)(struct buf *),
- struct buf **bpp)
-{
- int error;
-
- flags |= GB_CVTENXIO;
- error = breadn_flags(vp, lblkno, dblkno, size, rablkno, rabsize, cnt,
- cred, flags, ckhashfunc, bpp);
- if (error != 0 && ffs_fsfail_cleanup(ump, error)) {
- error = getblkx(vp, lblkno, dblkno, size, 0, 0, flags, bpp);
- KASSERT(error == 0, ("getblkx failed"));
- vfs_bio_bzero_buf(*bpp, 0, size);
- }
- return (error);
-}
#endif /* _KERNEL */
/*
diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c
index 52504d684dfea..4c4ac8401fa46 100644
--- a/sys/ufs/ffs/ffs_vfsops.c
+++ b/sys/ufs/ffs/ffs_vfsops.c
@@ -155,6 +155,217 @@ SYSCTL_INT(_vfs_ffs, OID_AUTO, enxio_enable, CTLFLAG_RWTUN,
&ffs_enxio_enable, 0,
"enable mapping of other disk I/O errors to ENXIO");
+/*
+ * Return buffer with the contents of block "offset" from the beginning of
+ * directory "ip". If "res" is non-zero, fill it in with a pointer to the
+ * remaining space in the directory.
+ */
+static int
+ffs_blkatoff(struct vnode *vp, off_t offset, char **res, struct buf **bpp)
+{
+ struct inode *ip;
+ struct fs *fs;
+ struct buf *bp;
+ ufs_lbn_t lbn;
+ int bsize, error;
+
+ ip = VTOI(vp);
+ fs = ITOFS(ip);
+ lbn = lblkno(fs, offset);
+ bsize = blksize(fs, ip, lbn);
+
+ *bpp = NULL;
+ error = bread(vp, lbn, bsize, NOCRED, &bp);
+ if (error) {
+ return (error);
+ }
+ if (res)
+ *res = (char *)bp->b_data + blkoff(fs, offset);
+ *bpp = bp;
+ return (0);
+}
+
+/*
+ * Load up the contents of an inode and copy the appropriate pieces
+ * to the incore copy.
+ */
+static int
+ffs_load_inode(struct buf *bp, struct inode *ip, struct fs *fs, ino_t ino)
+{
+ struct ufs1_dinode *dip1;
+ struct ufs2_dinode *dip2;
+ int error;
+
+ if (I_IS_UFS1(ip)) {
+ dip1 = ip->i_din1;
+ *dip1 =
+ *((struct ufs1_dinode *)bp->b_data + ino_to_fsbo(fs, ino));
+ ip->i_mode = dip1->di_mode;
+ ip->i_nlink = dip1->di_nlink;
+ ip->i_effnlink = dip1->di_nlink;
+ ip->i_size = dip1->di_size;
+ ip->i_flags = dip1->di_flags;
+ ip->i_gen = dip1->di_gen;
+ ip->i_uid = dip1->di_uid;
+ ip->i_gid = dip1->di_gid;
+ return (0);
+ }
+ dip2 = ((struct ufs2_dinode *)bp->b_data + ino_to_fsbo(fs, ino));
+ if ((error = ffs_verify_dinode_ckhash(fs, dip2)) != 0 &&
+ !ffs_fsfail_cleanup(ITOUMP(ip), error)) {
+ printf("%s: inode %jd: check-hash failed\n", fs->fs_fsmnt,
+ (intmax_t)ino);
+ return (error);
+ }
+ *ip->i_din2 = *dip2;
+ dip2 = ip->i_din2;
+ ip->i_mode = dip2->di_mode;
+ ip->i_nlink = dip2->di_nlink;
+ ip->i_effnlink = dip2->di_nlink;
+ ip->i_size = dip2->di_size;
+ ip->i_flags = dip2->di_flags;
+ ip->i_gen = dip2->di_gen;
+ ip->i_uid = dip2->di_uid;
+ ip->i_gid = dip2->di_gid;
+ return (0);
+}
+
+/*
+ * Verify that a filesystem block number is a valid data block.
+ * This routine is only called on untrusted filesystems.
+ */
+static int
+ffs_check_blkno(struct mount *mp, ino_t inum, ufs2_daddr_t daddr, int blksize)
+{
+ struct fs *fs;
+ struct ufsmount *ump;
+ ufs2_daddr_t end_daddr;
+ int cg, havemtx;
+
+ KASSERT((mp->mnt_flag & MNT_UNTRUSTED) != 0,
+ ("ffs_check_blkno called on a trusted file system"));
+ ump = VFSTOUFS(mp);
+ fs = ump->um_fs;
+ cg = dtog(fs, daddr);
+ end_daddr = daddr + numfrags(fs, blksize);
+ /*
+ * Verify that the block number is a valid data block. Also check
+ * that it does not point to an inode block or a superblock. Accept
+ * blocks that are unalloacted (0) or part of snapshot metadata
+ * (BLK_NOCOPY or BLK_SNAP).
+ *
+ * Thus, the block must be in a valid range for the filesystem and
+ * either in the space before a backup superblock (except the first
+ * cylinder group where that space is used by the bootstrap code) or
+ * after the inode blocks and before the end of the cylinder group.
+ */
+ if ((uint64_t)daddr <= BLK_SNAP ||
+ ((uint64_t)end_daddr <= fs->fs_size &&
+ ((cg > 0 && end_daddr <= cgsblock(fs, cg)) ||
+ (daddr >= cgdmin(fs, cg) &&
+ end_daddr <= cgbase(fs, cg) + fs->fs_fpg))))
+ return (0);
+ if ((havemtx = mtx_owned(UFS_MTX(ump))) == 0)
+ UFS_LOCK(ump);
+ if (ppsratecheck(&ump->um_last_integritymsg,
+ &ump->um_secs_integritymsg, 1)) {
+ UFS_UNLOCK(ump);
+ uprintf("\n%s: inode %jd, out-of-range indirect block "
+ "number %jd\n", mp->mnt_stat.f_mntonname, inum, daddr);
+ if (havemtx)
+ UFS_LOCK(ump);
+ } else if (!havemtx)
+ UFS_UNLOCK(ump);
+ return (EINTEGRITY);
+}
+
+/*
+ * Initiate a forcible unmount.
+ * Used to unmount filesystems whose underlying media has gone away.
+ */
+static void
+ffs_fsfail_unmount(void *v, int pending)
+{
+ struct fsfail_task *etp;
+ struct mount *mp;
+
+ etp = v;
+
+ /*
+ * Find our mount and get a ref on it, then try to unmount.
+ */
+ mp = vfs_getvfs(&etp->fsid);
+ if (mp != NULL)
+ dounmount(mp, MNT_FORCE, curthread);
+ free(etp, M_UFSMNT);
+}
+
+/*
+ * On first ENXIO error, start a task that forcibly unmounts the filesystem.
+ *
+ * Return true if a cleanup is in progress.
+ */
+int
+ffs_fsfail_cleanup(struct ufsmount *ump, int error)
+{
+ int retval;
+
+ UFS_LOCK(ump);
+ retval = ffs_fsfail_cleanup_locked(ump, error);
+ UFS_UNLOCK(ump);
+ return (retval);
+}
+
+int
+ffs_fsfail_cleanup_locked(struct ufsmount *ump, int error)
+{
+ struct fsfail_task *etp;
+ struct task *tp;
+
+ mtx_assert(UFS_MTX(ump), MA_OWNED);
+ if (error == ENXIO && (ump->um_flags & UM_FSFAIL_CLEANUP) == 0) {
+ ump->um_flags |= UM_FSFAIL_CLEANUP;
+ /*
+ * Queue an async forced unmount.
+ */
+ etp = ump->um_fsfail_task;
+ ump->um_fsfail_task = NULL;
+ if (etp != NULL) {
+ tp = &etp->task;
+ TASK_INIT(tp, 0, ffs_fsfail_unmount, etp);
+ taskqueue_enqueue(taskqueue_thread, tp);
+ printf("UFS: forcibly unmounting %s from %s\n",
+ ump->um_mountp->mnt_stat.f_mntfromname,
+ ump->um_mountp->mnt_stat.f_mntonname);
+ }
+ }
+ return ((ump->um_flags & UM_FSFAIL_CLEANUP) != 0);
+}
+
+/*
+ * Wrapper used during ENXIO cleanup to allocate empty buffers when
+ * the kernel is unable to read the real one. They are needed so that
+ * the soft updates code can use them to unwind its dependencies.
+ */
+int
+ffs_breadz(struct ufsmount *ump, struct vnode *vp, daddr_t lblkno,
+ daddr_t dblkno, int size, daddr_t *rablkno, int *rabsize, int cnt,
+ struct ucred *cred, int flags, void (*ckhashfunc)(struct buf *),
+ struct buf **bpp)
+{
+ int error;
+
+ flags |= GB_CVTENXIO;
+ error = breadn_flags(vp, lblkno, dblkno, size, rablkno, rabsize, cnt,
+ cred, flags, ckhashfunc, bpp);
+ if (error != 0 && ffs_fsfail_cleanup(ump, error)) {
+ error = getblkx(vp, lblkno, dblkno, size, 0, 0, flags, bpp);
+ KASSERT(error == 0, ("getblkx failed"));
+ vfs_bio_bzero_buf(*bpp, 0, size);
+ }
+ return (error);
+}
+
static int
ffs_mount(struct mount *mp)
{
diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c
index dc3535432e3c1..2e6aa283fc802 100644
--- a/sys/ufs/ufs/ufs_vnops.c
+++ b/sys/ufs/ufs/ufs_vnops.c
@@ -2184,7 +2184,7 @@ ufs_readdir(ap)
error = 0;
while (error == 0 && uio->uio_resid > 0 &&
uio->uio_offset < ip->i_size) {
- error = ffs_blkatoff(vp, uio->uio_offset, NULL, &bp);
+ error = UFS_BLKATOFF(vp, uio->uio_offset, NULL, &bp);
if (error)
break;
if (bp->b_offset + bp->b_bcount > ip->i_size)