Move all of the functions in ffs_subr.c that are only used by the ufs kernel
module from that file into ffs_vfsops.c. This fixes the build for kernel configs that don't include FFS. PR: 247256 Submitted by: glebius Reviewed by: mckusick (earlier version) Sponsored by: Netflix Differential Revision: https://reviews.freebsd.org/D25285
This commit is contained in:
parent
78ef79139e
commit
d9a8abf6c2
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=362292
@ -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);
|
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,
|
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);
|
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 *,
|
void ffs_blkfree(struct ufsmount *, struct fs *, struct vnode *,
|
||||||
ufs2_daddr_t, long, ino_t, enum vtype, struct workhead *, u_long);
|
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 *);
|
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);
|
void ffs_blkrelease_finish(struct ufsmount *, u_long);
|
||||||
u_long ffs_blkrelease_start(struct ufsmount *, struct vnode *, ino_t);
|
u_long ffs_blkrelease_start(struct ufsmount *, struct vnode *, ino_t);
|
||||||
uint32_t ffs_calc_sbhash(struct fs *);
|
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);
|
int ffs_checkfreefile(struct fs *, struct vnode *, ino_t);
|
||||||
void ffs_clrblock(struct fs *, u_char *, ufs1_daddr_t);
|
void ffs_clrblock(struct fs *, u_char *, ufs1_daddr_t);
|
||||||
void ffs_clusteracct(struct fs *, struct cg *, ufs1_daddr_t, int);
|
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 **);
|
struct cg **);
|
||||||
int ffs_isblock(struct fs *, u_char *, ufs1_daddr_t);
|
int ffs_isblock(struct fs *, u_char *, ufs1_daddr_t);
|
||||||
int ffs_isfreeblock(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 *);
|
void ffs_oldfscompat_write(struct fs *, struct ufsmount *);
|
||||||
int ffs_own_mount(const struct mount *mp);
|
int ffs_own_mount(const struct mount *mp);
|
||||||
int ffs_reallocblks(struct vop_reallocblks_args *);
|
int ffs_reallocblks(struct vop_reallocblks_args *);
|
||||||
|
@ -67,7 +67,6 @@ struct malloc_type;
|
|||||||
#include <sys/bio.h>
|
#include <sys/bio.h>
|
||||||
#include <sys/buf.h>
|
#include <sys/buf.h>
|
||||||
#include <sys/ucred.h>
|
#include <sys/ucred.h>
|
||||||
#include <sys/taskqueue.h>
|
|
||||||
|
|
||||||
#include <ufs/ufs/quota.h>
|
#include <ufs/ufs/quota.h>
|
||||||
#include <ufs/ufs/inode.h>
|
#include <ufs/ufs/inode.h>
|
||||||
@ -81,216 +80,6 @@ struct malloc_type;
|
|||||||
#define UFS_FREE(ptr, type) free(ptr, type)
|
#define UFS_FREE(ptr, type) free(ptr, type)
|
||||||
#define UFS_TIME time_second
|
#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 */
|
#endif /* _KERNEL */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -155,6 +155,217 @@ SYSCTL_INT(_vfs_ffs, OID_AUTO, enxio_enable, CTLFLAG_RWTUN,
|
|||||||
&ffs_enxio_enable, 0,
|
&ffs_enxio_enable, 0,
|
||||||
"enable mapping of other disk I/O errors to ENXIO");
|
"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
|
static int
|
||||||
ffs_mount(struct mount *mp)
|
ffs_mount(struct mount *mp)
|
||||||
{
|
{
|
||||||
|
@ -2184,7 +2184,7 @@ ufs_readdir(ap)
|
|||||||
error = 0;
|
error = 0;
|
||||||
while (error == 0 && uio->uio_resid > 0 &&
|
while (error == 0 && uio->uio_resid > 0 &&
|
||||||
uio->uio_offset < ip->i_size) {
|
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)
|
if (error)
|
||||||
break;
|
break;
|
||||||
if (bp->b_offset + bp->b_bcount > ip->i_size)
|
if (bp->b_offset + bp->b_bcount > ip->i_size)
|
||||||
|
Loading…
Reference in New Issue
Block a user