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:
Konstantin Belousov 2008-09-16 11:51:06 +00:00
parent 52dfc8d7da
commit 2814d5ba5f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=183073
6 changed files with 37 additions and 14 deletions

View File

@ -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);
}
/*

View File

@ -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;

View File

@ -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.

View File

@ -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);

View File

@ -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)
{

View File

@ -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);