diff options
author | tegge <tegge@FreeBSD.org> | 2005-10-09 20:15:15 +0000 |
---|---|---|
committer | tegge <tegge@FreeBSD.org> | 2005-10-09 20:15:15 +0000 |
commit | ddad01d50f900652c8bb82a40e51e8b998857e9e (patch) | |
tree | 6a4fe84f287c921267419c7f37cbaedc90d909ba | |
parent | 1448da0d3a2ecdbfd91f46cc28ce3b67d4096868 (diff) | |
download | FreeBSD-src-ddad01d50f900652c8bb82a40e51e8b998857e9e.zip FreeBSD-src-ddad01d50f900652c8bb82a40e51e8b998857e9e.tar.gz |
Reduce probability for a deadlock that can occur when a snapshot inode is
updated by a process holding the snapshot lock. Another process updating a
different inode in the same inodeblock will do copy on write checks and lock in
the opposite direction.
The snapshot code force a copy on write of these blocks manually (cf. start of
expunge_ufs[12]) and these inode blocks are later put on snapblklist.
This partial fix is to 'drain' the relevant ffs_copyonwrite() operation after
installing new snapblklist. This is not a 100% solution since a failed block
allocation can cause implicit fsync() which might deadlock before the new
snapblklist has been installed.
-rw-r--r-- | sys/ufs/ffs/ffs_snapshot.c | 11 |
1 files changed, 11 insertions, 0 deletions
diff --git a/sys/ufs/ffs/ffs_snapshot.c b/sys/ufs/ffs/ffs_snapshot.c index 0dc07e9..98a1f23 100644 --- a/sys/ufs/ffs/ffs_snapshot.c +++ b/sys/ufs/ffs/ffs_snapshot.c @@ -681,6 +681,17 @@ out1: VI_UNLOCK(devvp); if (space != NULL) FREE(space, M_UFSMNT); + /* + * If another process is currently writing the buffer containing + * the inode for this snapshot then a deadlock can occur. Drop + * the snapshot lock until the buffer has been written. + */ + VOP_UNLOCK(vp, 0, td); + (void) bread(ip->i_devvp, + fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), + (int) fs->fs_bsize, NOCRED, &nbp); + brelse(nbp); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); done: FREE(copy_fs->fs_csp, M_UFSMNT); bawrite(sbp); |