@@ -19,6 +19,7 @@
#include "xfs_shared.h"
#include "xfs_bit.h"
#include "xfs_pnfs.h"
+#include "xfs_reflink.h"
/*
* Ensure that we do not have any outstanding pNFS layouts that can be used by
@@ -110,13 +111,6 @@ xfs_fs_map_blocks(
return -ENXIO;
/*
- * The pNFS block layout spec actually supports reflink like
- * functionality, but the Linux pNFS server doesn't implement it yet.
- */
- if (xfs_is_reflink_inode(ip))
- return -ENXIO;
-
- /*
* Lock out any other I/O before we flush and invalidate the pagecache,
* and then hand out a layout to the remote system. This is very
* similar to direct I/O, except that the synchronization is much more
@@ -125,6 +119,14 @@ xfs_fs_map_blocks(
*/
xfs_ilock(ip, XFS_IOLOCK_EXCL);
+ /* Try to unshare the blocks if we want write access */
+ xfs_ilock(ip, XFS_MMAPLOCK_EXCL);
+ if (write) {
+ error = xfs_reflink_unshare(ip, offset, length);
+ if (error)
+ goto out_unlock;
+ }
+
error = -EINVAL;
limit = mp->m_super->s_maxbytes;
if (!write)
@@ -140,7 +142,7 @@ xfs_fs_map_blocks(
goto out_unlock;
error = invalidate_inode_pages2(inode->i_mapping);
if (WARN_ON_ONCE(error))
- return error;
+ goto out_unlock;
end_fsb = XFS_B_TO_FSB(mp, (xfs_ufsize_t)offset + length);
offset_fsb = XFS_B_TO_FSBT(mp, offset);
@@ -176,18 +178,32 @@ xfs_fs_map_blocks(
* present even after a server crash.
*/
flags |= XFS_PREALLOC_SET | XFS_PREALLOC_SYNC;
+ } else {
+ bool shared, trimmed;
+
+ /* Make sure the extent really isn't shared. */
+ error = xfs_reflink_trim_around_shared(ip, &imap,
+ &shared, &trimmed);
+ if (error)
+ goto out_unlock;
+ if (shared || trimmed) {
+ error = -ENXIO;
+ goto out_unlock;
+ }
}
error = xfs_update_prealloc_flags(ip, flags);
if (error)
goto out_unlock;
}
+ xfs_iunlock(ip, XFS_MMAPLOCK_EXCL);
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
xfs_bmbt_to_iomap(ip, iomap, &imap);
*device_generation = mp->m_generation;
return error;
out_unlock:
+ xfs_iunlock(ip, XFS_MMAPLOCK_EXCL);
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
return error;
}