@@ -1768,6 +1768,44 @@ static bool fuse_use_writeback_cache(struct fuse_conn *fc, struct kiocb *iocb,
17681768 return ret ;
17691769}
17701770
1771+ /*
1772+ * @return true if an exclusive lock is needed for a cached (buffered) write.
1773+ *
1774+ * Buffered writes normally take the inode lock exclusively, serialising every
1775+ * writer to the same inode even when they target disjoint regions. When the
1776+ * connection uses the DLM (fc->dlm) and writeback caching is in effect for the
1777+ * write, the server is the authority that serialises writers across the
1778+ * cluster (the cached data carries a DLM write lock; the synchronous
1779+ * writethrough path above sends data straight to the server). The inode rwsem
1780+ * then no longer has to provide that exclusion - it only needs to keep i_size
1781+ * and the file-modified bookkeeping stable. Such writes may therefore share
1782+ * the inode lock, letting multiple writers to disjoint regions of one file
1783+ * proceed concurrently (e.g. MPI-IO / IOR shared-file workloads).
1784+ */
1785+ static bool fuse_cache_wr_exclusive_lock (struct kiocb * iocb , bool cache_mode )
1786+ {
1787+ struct inode * inode = file_inode (iocb -> ki_filp );
1788+ struct fuse_conn * fc = get_fuse_conn (inode );
1789+
1790+ /*
1791+ * Without the DLM the inode rwsem is the only writer exclusion, and
1792+ * outside writeback-cache mode the write is covered by neither the DLM
1793+ * write lock nor the synchronous-server path described above.
1794+ */
1795+ if (!fc -> dlm || !cache_mode )
1796+ return true;
1797+
1798+ /* O_DIRECT writes fall back to generic_file_direct_write(). */
1799+ if (iocb -> ki_flags & IOCB_DIRECT )
1800+ return true;
1801+
1802+ /* Append needs the eventual EOF - always needs an exclusive lock. */
1803+ if (iocb -> ki_flags & IOCB_APPEND )
1804+ return true;
1805+
1806+ return false;
1807+ }
1808+
17711809static ssize_t fuse_direct_write_iter (struct kiocb * iocb , struct iov_iter * from );
17721810
17731811static ssize_t fuse_cache_write_iter (struct kiocb * iocb , struct iov_iter * from )
@@ -1779,7 +1817,10 @@ static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from)
17791817 struct inode * inode = mapping -> host ;
17801818 ssize_t err , count ;
17811819 struct fuse_conn * fc = get_fuse_conn (inode );
1820+ struct fuse_inode * fi = get_fuse_inode (inode );
17821821 bool writeback = false;
1822+ bool cache_mode = false;
1823+ bool exclusive ;
17831824
17841825 /*
17851826 * The inode may have been latched into forced direct IO after this
@@ -1797,9 +1838,10 @@ static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from)
17971838 if (err )
17981839 return err ;
17991840
1800- if ((!fc -> handle_killpriv_v2 ||
1801- !setattr_should_drop_suidgid (idmap , file_inode (file ))) &&
1802- fuse_use_writeback_cache (fc , iocb , from )) {
1841+ cache_mode = !fc -> handle_killpriv_v2 ||
1842+ !setattr_should_drop_suidgid (idmap , file_inode (file ));
1843+
1844+ if (cache_mode && fuse_use_writeback_cache (fc , iocb , from )) {
18031845 writeback = true;
18041846
18051847 /*
@@ -1827,7 +1869,11 @@ static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from)
18271869 }
18281870 }
18291871
1830- inode_lock (inode );
1872+ exclusive = fuse_cache_wr_exclusive_lock (iocb , cache_mode );
1873+ if (exclusive )
1874+ inode_lock (inode );
1875+ else
1876+ inode_lock_shared (inode );
18311877
18321878 err = count = generic_write_checks (iocb , from );
18331879 if (err <= 0 )
@@ -1846,7 +1892,58 @@ static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from)
18461892 written = direct_write_fallback (iocb , from , written ,
18471893 fuse_perform_write (iocb , from ));
18481894 } else if (writeback ) {
1895+ loff_t pos = iocb -> ki_pos ;
1896+ loff_t end = pos + count ;
1897+ loff_t orig_size = 0 ;
1898+ bool extended = false;
1899+
1900+ if (fc -> dlm && !exclusive && end > i_size_read (inode )) {
1901+ /*
1902+ * Lockless pre-check above keeps in-bounds writes off
1903+ * fi->lock; under the shared inode lock i_size only grows
1904+ * (extenders take fi->lock, truncate is excluded), so a
1905+ * stale read can only over-trigger this slow path, never
1906+ * miss an extension. Re-check authoritatively here.
1907+ *
1908+ * Pre-growing under fi->lock is required: iomap's own
1909+ * i_size update (iomap_write_iter) is a non-atomic
1910+ * read-modify-write done under only the folio lock, so
1911+ * concurrent shared extenders would lose updates. Once
1912+ * i_size already covers our range iomap's update becomes
1913+ * a no-op and all growth stays serialised on fi->lock.
1914+ */
1915+ spin_lock (& fi -> lock );
1916+ orig_size = i_size_read (inode );
1917+ if (end > orig_size ) {
1918+ i_size_write (inode , end );
1919+ extended = true;
1920+ }
1921+ spin_unlock (& fi -> lock );
1922+
1923+ /* Zero the tail of the folio straddling the old EOF. */
1924+ if (extended && orig_size < pos )
1925+ pagecache_isize_extended (inode , orig_size , pos );
1926+ }
1927+
18491928 written = fuse_writeback_write_iter (iocb , from , file );
1929+
1930+ /*
1931+ * Reconcile the speculative extension with what was actually
1932+ * written. Only retract the tail if no concurrent extender has
1933+ * pushed i_size past our claim; otherwise [reached, end) is a
1934+ * legitimate hole inside their extension and must remain.
1935+ */
1936+ if (extended ) {
1937+ loff_t reached = written > 0 ? pos + written : orig_size ;
1938+
1939+ if (reached < end ) {
1940+ spin_lock (& fi -> lock );
1941+ if (i_size_read (inode ) == end )
1942+ i_size_write (inode , reached );
1943+ spin_unlock (& fi -> lock );
1944+ }
1945+ }
1946+
18501947 if (written < 0 ) {
18511948 err = written ;
18521949 goto out ;
@@ -1855,7 +1952,10 @@ static ssize_t fuse_cache_write_iter(struct kiocb *iocb, struct iov_iter *from)
18551952 written = fuse_perform_write (iocb , from );
18561953 }
18571954out :
1858- inode_unlock (inode );
1955+ if (exclusive )
1956+ inode_unlock (inode );
1957+ else
1958+ inode_unlock_shared (inode );
18591959 if (written > 0 )
18601960 written = generic_write_sync (iocb , written );
18611961
0 commit comments