diff options
author | kib <kib@FreeBSD.org> | 2008-09-16 11:51:06 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2008-09-16 11:51:06 +0000 |
commit | f6863a9ef79ec34cd371070704d592a2b5c019c1 (patch) | |
tree | 916cd048737fbe3376fc7973f694d424abd09e34 /sys | |
parent | 0488506405edd848b205c59066a7f0b5d53e55e7 (diff) | |
download | FreeBSD-src-f6863a9ef79ec34cd371070704d592a2b5c019c1.zip FreeBSD-src-f6863a9ef79ec34cd371070704d592a2b5c019c1.tar.gz |
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
Diffstat (limited to 'sys')
-rw-r--r-- | sys/kern/vfs_vnops.c | 35 | ||||
-rw-r--r-- | sys/sys/mount.h | 6 | ||||
-rw-r--r-- | sys/sys/proc.h | 1 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_extern.h | 1 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_snapshot.c | 7 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_vfsops.c | 1 |
6 files changed, 37 insertions, 14 deletions
diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index 58863f4..c66e49c 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -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); } /* diff --git a/sys/sys/mount.h b/sys/sys/mount.h index 7e9534e..27a4a60 100644 --- a/sys/sys/mount.h +++ b/sys/sys/mount.h @@ -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; diff --git a/sys/sys/proc.h b/sys/sys/proc.h index 2ec5d20..66e95ac 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -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. diff --git a/sys/ufs/ffs/ffs_extern.h b/sys/ufs/ffs/ffs_extern.h index d5dfa12..4a2f3a2 100644 --- a/sys/ufs/ffs/ffs_extern.h +++ b/sys/ufs/ffs/ffs_extern.h @@ -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); diff --git a/sys/ufs/ffs/ffs_snapshot.c b/sys/ufs/ffs/ffs_snapshot.c index c367d66..fab6798 100644 --- a/sys/ufs/ffs/ffs_snapshot.c +++ b/sys/ufs/ffs/ffs_snapshot.c @@ -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) { diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index 93e0b48..86b3f60 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -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); |