/* * Grab the exclusive iolock for a data copy from src to dest, making * sure to abide vfs locking order (lowest pointer value goes first) and * breaking the pnfs layout leases on dest before proceeding. The loop * is needed because we cannot call the blocking break_layout() with the * src iolock held, and therefore have to back out both locks. */ static int xfs_iolock_two_inodes_and_break_layout( struct inode *src, struct inode *dest) { int error; retry: if (src < dest) { inode_lock_shared(src); inode_lock_nested(dest, I_MUTEX_NONDIR2); } else { /* src >= dest */ inode_lock(dest); } error = break_layout(dest, false); if (error == -EWOULDBLOCK) { inode_unlock(dest); if (src < dest) inode_unlock_shared(src); error = break_layout(dest, true); if (error) return error; goto retry; } if (error) { inode_unlock(dest); if (src < dest) inode_unlock_shared(src); return error; } if (src > dest) inode_lock_shared_nested(src, I_MUTEX_NONDIR2); return 0; }
/* * Ensure that we do not have any outstanding pNFS layouts that can be used by * clients to directly read from or write to this inode. This must be called * before every operation that can remove blocks from the extent map. * Additionally we call it during the write operation, where aren't concerned * about exposing unallocated blocks but just want to provide basic * synchronization between a local writer and pNFS clients. mmap writes would * also benefit from this sort of synchronization, but due to the tricky locking * rules in the page fault path we don't bother. */ int xfs_break_layouts( struct inode *inode, uint *iolock, bool with_imutex) { struct xfs_inode *ip = XFS_I(inode); int error; ASSERT(xfs_isilocked(ip, XFS_IOLOCK_SHARED|XFS_IOLOCK_EXCL)); while ((error = break_layout(inode, false) == -EWOULDBLOCK)) { xfs_iunlock(ip, *iolock); if (with_imutex && (*iolock & XFS_IOLOCK_EXCL)) inode_unlock(inode); error = break_layout(inode, true); *iolock = XFS_IOLOCK_EXCL; if (with_imutex) inode_lock(inode); xfs_ilock(ip, *iolock); } return error; }