When attempt is made to suspend a filesystem that is already syspended,
wait until the current suspension is lifted instead of silently returning success immediately. The consequences of calling vfs_write() resume when not owning the suspension are not well-defined at best. Add the vfs_susp_clean() mount method to be called from vfs_write_resume(). Set it to process_deferred_inactive() for ffs, and stop calling it manually. Add the thread flag TDP_IGNSUSP that allows to bypass the suspension point in the vn_start_write. It is intended for use by VFS in the situations where the suspender want to do some i/o requiring calls to vn_start_write(), and this i/o cannot be done later. Reviewed by: tegge In collaboration with: pho MFC after: 1 month
This commit is contained in:
parent
52dfc8d7da
commit
2814d5ba5f
@ -947,15 +947,18 @@ vn_start_write(vp, mpp, flags)
|
||||
/*
|
||||
* Check on status of suspension.
|
||||
*/
|
||||
while ((mp->mnt_kern_flag & MNTK_SUSPEND) != 0) {
|
||||
if (flags & V_NOWAIT) {
|
||||
error = EWOULDBLOCK;
|
||||
goto unlock;
|
||||
if ((curthread->td_pflags & TDP_IGNSUSP) == 0 ||
|
||||
mp->mnt_susp_owner != curthread) {
|
||||
while ((mp->mnt_kern_flag & MNTK_SUSPEND) != 0) {
|
||||
if (flags & V_NOWAIT) {
|
||||
error = EWOULDBLOCK;
|
||||
goto unlock;
|
||||
}
|
||||
error = msleep(&mp->mnt_flag, MNT_MTX(mp),
|
||||
(PUSER - 1) | (flags & PCATCH), "suspfs", 0);
|
||||
if (error)
|
||||
goto unlock;
|
||||
}
|
||||
error = msleep(&mp->mnt_flag, MNT_MTX(mp),
|
||||
(PUSER - 1) | (flags & PCATCH), "suspfs", 0);
|
||||
if (error)
|
||||
goto unlock;
|
||||
}
|
||||
if (flags & V_XSLEEP)
|
||||
goto unlock;
|
||||
@ -1079,11 +1082,14 @@ vfs_write_suspend(mp)
|
||||
int error;
|
||||
|
||||
MNT_ILOCK(mp);
|
||||
if (mp->mnt_kern_flag & MNTK_SUSPEND) {
|
||||
if (mp->mnt_susp_owner == curthread) {
|
||||
MNT_IUNLOCK(mp);
|
||||
return (0);
|
||||
return (EALREADY);
|
||||
}
|
||||
while (mp->mnt_kern_flag & MNTK_SUSPEND)
|
||||
msleep(&mp->mnt_flag, MNT_MTX(mp), PUSER - 1, "wsuspfs", 0);
|
||||
mp->mnt_kern_flag |= MNTK_SUSPEND;
|
||||
mp->mnt_susp_owner = curthread;
|
||||
if (mp->mnt_writeopcount > 0)
|
||||
(void) msleep(&mp->mnt_writeopcount,
|
||||
MNT_MTX(mp), (PUSER - 1)|PDROP, "suspwt", 0);
|
||||
@ -1104,12 +1110,17 @@ vfs_write_resume(mp)
|
||||
|
||||
MNT_ILOCK(mp);
|
||||
if ((mp->mnt_kern_flag & MNTK_SUSPEND) != 0) {
|
||||
KASSERT(mp->mnt_susp_owner == curthread, ("mnt_susp_owner"));
|
||||
mp->mnt_kern_flag &= ~(MNTK_SUSPEND | MNTK_SUSPEND2 |
|
||||
MNTK_SUSPENDED);
|
||||
mp->mnt_susp_owner = NULL;
|
||||
wakeup(&mp->mnt_writeopcount);
|
||||
wakeup(&mp->mnt_flag);
|
||||
}
|
||||
MNT_IUNLOCK(mp);
|
||||
curthread->td_pflags &= ~TDP_IGNSUSP;
|
||||
MNT_IUNLOCK(mp);
|
||||
VFS_SUSP_CLEAN(mp);
|
||||
} else
|
||||
MNT_IUNLOCK(mp);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -180,6 +180,7 @@ struct mount {
|
||||
int mnt_holdcntwaiters; /* waits on hold count */
|
||||
int mnt_secondary_writes; /* (i) # of secondary writes */
|
||||
int mnt_secondary_accwrites;/* (i) secondary wr. starts */
|
||||
struct thread *mnt_susp_owner; /* (i) thread owning suspension */
|
||||
#define mnt_endzero mnt_gjprovider
|
||||
char *mnt_gjprovider; /* gjournal provider name */
|
||||
struct lock mnt_explock; /* vfs_export walkers lock */
|
||||
@ -544,6 +545,7 @@ typedef int vfs_extattrctl_t(struct mount *mp, int cmd,
|
||||
typedef int vfs_mount_t(struct mount *mp, struct thread *td);
|
||||
typedef int vfs_sysctl_t(struct mount *mp, fsctlop_t op,
|
||||
struct sysctl_req *req);
|
||||
typedef void vfs_susp_clean_t(struct mount *mp);
|
||||
|
||||
struct vfsops {
|
||||
vfs_mount_t *vfs_mount;
|
||||
@ -560,6 +562,7 @@ struct vfsops {
|
||||
vfs_uninit_t *vfs_uninit;
|
||||
vfs_extattrctl_t *vfs_extattrctl;
|
||||
vfs_sysctl_t *vfs_sysctl;
|
||||
vfs_susp_clean_t *vfs_susp_clean;
|
||||
};
|
||||
|
||||
vfs_statfs_t __vfs_statfs;
|
||||
@ -581,6 +584,9 @@ vfs_statfs_t __vfs_statfs;
|
||||
(*(MP)->mnt_op->vfs_extattrctl)(MP, C, FN, NS, N, P)
|
||||
#define VFS_SYSCTL(MP, OP, REQ) \
|
||||
(*(MP)->mnt_op->vfs_sysctl)(MP, OP, REQ)
|
||||
#define VFS_SUSP_CLEAN(MP) \
|
||||
({if (*(MP)->mnt_op->vfs_susp_clean != NULL) \
|
||||
(*(MP)->mnt_op->vfs_susp_clean)(MP); })
|
||||
|
||||
extern int mpsafe_vfs;
|
||||
|
||||
|
@ -359,6 +359,7 @@ do { \
|
||||
#define TDP_INBDFLUSH 0x00100000 /* Already in BO_BDFLUSH, do not recurse */
|
||||
#define TDP_KTHREAD 0x00200000 /* This is an official kernel thread */
|
||||
#define TDP_CALLCHAIN 0x00400000 /* Capture thread's callchain */
|
||||
#define TDP_IGNSUSP 0x00800000 /* Permission to ignore the MNTK_SUSPEND* */
|
||||
|
||||
/*
|
||||
* Reasons that the current thread can not be run yet.
|
||||
|
@ -80,6 +80,7 @@ void ffs_snapremove(struct vnode *vp);
|
||||
int ffs_snapshot(struct mount *mp, char *snapfile);
|
||||
void ffs_snapshot_mount(struct mount *mp);
|
||||
void ffs_snapshot_unmount(struct mount *mp);
|
||||
void process_deferred_inactive(struct mount *mp);
|
||||
int ffs_syncvnode(struct vnode *vp, int waitfor);
|
||||
int ffs_truncate(struct vnode *, off_t, int, struct ucred *, struct thread *);
|
||||
int ffs_update(struct vnode *, int);
|
||||
|
@ -167,7 +167,6 @@ static int snapacct_ufs2(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *,
|
||||
static int mapacct_ufs2(struct vnode *, ufs2_daddr_t *, ufs2_daddr_t *,
|
||||
struct fs *, ufs_lbn_t, int);
|
||||
static int readblock(struct vnode *vp, struct buf *, ufs2_daddr_t);
|
||||
static void process_deferred_inactive(struct mount *);
|
||||
static void try_free_snapdata(struct vnode *devvp);
|
||||
static struct snapdata *ffs_snapdata_acquire(struct vnode *devvp);
|
||||
static int ffs_bp_snapblk(struct vnode *, struct buf *);
|
||||
@ -2375,12 +2374,14 @@ readblock(vp, bp, lbn)
|
||||
return (bp->b_error);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Process file deletes that were deferred by ufs_inactive() due to
|
||||
* the file system being suspended. Transfer IN_LAZYACCESS into
|
||||
* IN_MODIFIED for vnodes that were accessed during suspension.
|
||||
*/
|
||||
static void
|
||||
void
|
||||
process_deferred_inactive(struct mount *mp)
|
||||
{
|
||||
struct vnode *vp, *mvp;
|
||||
@ -2453,6 +2454,8 @@ process_deferred_inactive(struct mount *mp)
|
||||
vn_finished_secondary_write(mp);
|
||||
}
|
||||
|
||||
#ifndef NO_FFS_SNAPSHOT
|
||||
|
||||
static struct snapdata *
|
||||
ffs_snapdata_alloc(void)
|
||||
{
|
||||
|
@ -105,6 +105,7 @@ static struct vfsops ufs_vfsops = {
|
||||
.vfs_uninit = ffs_uninit,
|
||||
.vfs_unmount = ffs_unmount,
|
||||
.vfs_vget = ffs_vget,
|
||||
.vfs_susp_clean = process_deferred_inactive,
|
||||
};
|
||||
|
||||
VFS_SET(ufs_vfsops, ufs, 0);
|
||||
|
Loading…
x
Reference in New Issue
Block a user