summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2008-09-16 11:51:06 +0000
committerkib <kib@FreeBSD.org>2008-09-16 11:51:06 +0000
commitf6863a9ef79ec34cd371070704d592a2b5c019c1 (patch)
tree916cd048737fbe3376fc7973f694d424abd09e34 /sys
parent0488506405edd848b205c59066a7f0b5d53e55e7 (diff)
downloadFreeBSD-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.c35
-rw-r--r--sys/sys/mount.h6
-rw-r--r--sys/sys/proc.h1
-rw-r--r--sys/ufs/ffs/ffs_extern.h1
-rw-r--r--sys/ufs/ffs/ffs_snapshot.c7
-rw-r--r--sys/ufs/ffs/ffs_vfsops.c1
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);
OpenPOWER on IntegriCloud