Partially lift suspension when ffs_reload() finished with cgs and

going to re-read inodes.

Secondary write initiators, e.g. ufs_inactive(), might need to start a
write while owning the vnode lock.  Since the suspended state
established by /dev/ufssuspend prevents them from entering
vn_start_secondary_write(), we get deadlock otherwise.

Note that it is arguably not very useful to re-read inodes after
/dev/ufssuspend suspension, because the suspension does not block
readers, and other threads might read existing files in parallel with
suspension owner (for now, only growfs(8)) operations.  This
effectively means that suspension owner cannot safely modify existing
inodes, and then there is no sense in re-reading.  But keep the code
enabled for now.

Reported and tested by:	pho
Reviewed by:	mckusick
Sponsored by:	The FreeBSD Foundation
MFC after:	2 weeks
This commit is contained in:
Konstantin Belousov 2016-09-08 12:01:28 +00:00
parent d4a08767ba
commit df4265774e
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=305592
3 changed files with 16 additions and 5 deletions

View File

@ -106,6 +106,9 @@ void ffs_susp_uninitialize(void);
#define FFSV_FORCEINSMQ 0x0001
#define FFSR_FORCE 0x0001
#define FFSR_UNSUSPEND 0x0002
extern struct vop_vector ffs_vnodeops1;
extern struct vop_vector ffs_fifoops1;
extern struct vop_vector ffs_vnodeops2;

View File

@ -235,7 +235,7 @@ ffs_susp_dtor(void *data)
KASSERT((mp->mnt_kern_flag & MNTK_SUSPEND) != 0,
("MNTK_SUSPEND not set"));
error = ffs_reload(mp, curthread, 1);
error = ffs_reload(mp, curthread, FFSR_FORCE | FFSR_UNSUSPEND);
if (error != 0)
panic("failed to unsuspend writes on %s", fs->fs_fsmnt);

View File

@ -573,11 +573,13 @@ ffs_cmount(struct mntarg *ma, void *data, uint64_t flags)
* 2) re-read superblock from disk.
* 3) re-read summary information from disk.
* 4) invalidate all inactive vnodes.
* 5) invalidate all cached file data.
* 6) re-read inode data for all active vnodes.
* 5) clear MNTK_SUSPEND2 and MNTK_SUSPENDED flags, allowing secondary
* writers, if requested.
* 6) invalidate all cached file data.
* 7) re-read inode data for all active vnodes.
*/
int
ffs_reload(struct mount *mp, struct thread *td, int force)
ffs_reload(struct mount *mp, struct thread *td, int flags)
{
struct vnode *vp, *mvp, *devvp;
struct inode *ip;
@ -592,7 +594,7 @@ ffs_reload(struct mount *mp, struct thread *td, int force)
ump = VFSTOUFS(mp);
MNT_ILOCK(mp);
if ((mp->mnt_flag & MNT_RDONLY) == 0 && force == 0) {
if ((mp->mnt_flag & MNT_RDONLY) == 0 && (flags & FFSR_FORCE) == 0) {
MNT_IUNLOCK(mp);
return (EINVAL);
}
@ -682,6 +684,12 @@ ffs_reload(struct mount *mp, struct thread *td, int force)
size = fs->fs_ncg * sizeof(u_int8_t);
fs->fs_contigdirs = (u_int8_t *)space;
bzero(fs->fs_contigdirs, size);
if ((flags & FFSR_UNSUSPEND) != 0) {
MNT_ILOCK(mp);
mp->mnt_kern_flag &= ~(MNTK_SUSPENDED | MNTK_SUSPEND2);
wakeup(&mp->mnt_flag);
MNT_IUNLOCK(mp);
}
loop:
MNT_VNODE_FOREACH_ALL(vp, mp, mvp) {