Skip to content

Commit 9449bfe

Browse files
bsberndhbirth
authored andcommitted
fuse: allow parallel direct writes past EOF
Extending FOPEN_PARALLEL_DIRECT_WRITES writes were forced onto the exclusive inode lock, re-serializing the parallel phase. The exclusive lock only bundled "write + advance i_size + undo-on-failure" into one unit. But i_size is committed by fuse_write_update_attr() under fi->lock, only on a successful growing write and independent of the inode rwsem -- so shared-lock writers commit size correctly and have nothing to undo. Drop the past-EOF exclusive triggers and gate the whole-file fuse_do_truncate() rollback on holding the exclusive lock. Lock mode is passed to __fuse_direct_IO(); i_size is committed at the same point in every path, only the failure rollback differs: non-exclusive (relaxed, parallel): fuse_direct_write_iter fuse_dio_lock -> inode_lock_shared (exclusive=false) __fuse_direct_IO(.., false) fuse_direct_io() write to server fuse_write_update_attr() commit i_size (on success) no rollback exclusive (append / caching / !parallel): fuse_direct_write_iter fuse_dio_lock -> inode_lock (exclusive=true) __fuse_direct_IO(.., true) fuse_direct_io() write to server fuse_write_update_attr() commit i_size (on success) ret<0 & extend -> fuse_do_truncate() rollback exclusive (caching-mode O_DIRECT): fuse_cache_write_iter -> inode_lock (exclusive) generic_file_direct_write -> fuse_direct_IO __fuse_direct_IO(.., true) fuse_direct_io() write to server fuse_write_update_attr() commit i_size (on success) ret<0 & extend -> fuse_do_truncate() rollback Signed-off-by: Bernd Schubert <bschubert@ddn.com>
1 parent 5889fa2 commit 9449bfe

1 file changed

Lines changed: 28 additions & 27 deletions

File tree

fs/fuse/file.c

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1560,13 +1560,6 @@ static ssize_t fuse_perform_write(struct kiocb *iocb, struct iov_iter *ii)
15601560
return res;
15611561
}
15621562

1563-
static bool fuse_io_past_eof(struct kiocb *iocb, struct iov_iter *iter)
1564-
{
1565-
struct inode *inode = file_inode(iocb->ki_filp);
1566-
1567-
return iocb->ki_pos + iov_iter_count(iter) > i_size_read(inode);
1568-
}
1569-
15701563
/*
15711564
* @return true if an exclusive lock for direct IO writes is needed
15721565
*/
@@ -1598,10 +1591,6 @@ static bool fuse_dio_wr_exclusive_lock(struct kiocb *iocb, struct iov_iter *from
15981591
if (!force_dio && test_bit(FUSE_I_CACHE_IO_MODE, &fi->state))
15991592
return true;
16001593

1601-
/* Parallel dio beyond EOF is not supported, at least for now. */
1602-
if (fuse_io_past_eof(iocb, from))
1603-
return true;
1604-
16051594
return false;
16061595
}
16071596

@@ -1620,18 +1609,15 @@ static void fuse_dio_lock(struct kiocb *iocb, struct iov_iter *from,
16201609
* New parallal dio allowed only if inode is not in caching
16211610
* mode and denies new opens in caching mode. This check
16221611
* should be performed only after taking shared inode lock.
1623-
* Previous past eof check was without inode lock and might
1624-
* have raced, so check it again.
16251612
*
1626-
* Under the forced-dio latch the cached/uncached accounting is
1627-
* bypassed (the latch already guarantees the cache is flushed
1628-
* and not repopulated), so just take the shared lock, only
1629-
* re-checking the past-eof condition. The latch is stable
1630-
* while the shared lock is held, keeping start/end balanced.
1613+
* Under the forced-dio latch the uncached-io accounting is
1614+
* bypassed entirely -- fuse_dio_unlock() likewise skips
1615+
* fuse_inode_uncached_io_end() -- so do not take a reference
1616+
* here. An unbalanced start would drive fi->iocachectr
1617+
* permanently negative and hang the next caching-mode open.
16311618
*/
1632-
if (fuse_io_past_eof(iocb, from) ||
1633-
(!test_bit(FUSE_I_FORCE_DIO, &fi->state) &&
1634-
fuse_inode_uncached_io_start(fi, NULL) != 0)) {
1619+
if (!test_bit(FUSE_I_FORCE_DIO, &fi->state) &&
1620+
fuse_inode_uncached_io_start(fi, NULL) != 0) {
16351621
inode_unlock_shared(inode);
16361622
inode_lock(inode);
16371623
*exclusive = true;
@@ -2148,14 +2134,16 @@ static ssize_t __fuse_direct_read(struct fuse_io_priv *io,
21482134
return res;
21492135
}
21502136

2151-
static ssize_t fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter);
2137+
static ssize_t __fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter,
2138+
bool exclusive);
21522139

21532140
static ssize_t fuse_direct_read_iter(struct kiocb *iocb, struct iov_iter *to)
21542141
{
21552142
ssize_t res;
21562143

21572144
if (!is_sync_kiocb(iocb)) {
2158-
res = fuse_direct_IO(iocb, to);
2145+
/* exclusive is unused on reads; rollback is write-only */
2146+
res = __fuse_direct_IO(iocb, to, true);
21592147
} else {
21602148
struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(iocb);
21612149

@@ -2178,7 +2166,7 @@ static ssize_t fuse_direct_write_iter(struct kiocb *iocb, struct iov_iter *from)
21782166
if (res > 0) {
21792167
task_io_account_write(res);
21802168
if (!is_sync_kiocb(iocb)) {
2181-
res = fuse_direct_IO(iocb, from);
2169+
res = __fuse_direct_IO(iocb, from, exclusive);
21822170
} else {
21832171
struct fuse_io_priv io = FUSE_IO_PRIV_SYNC(iocb);
21842172

@@ -3313,7 +3301,7 @@ static inline loff_t fuse_round_up(struct fuse_conn *fc, loff_t off)
33133301
}
33143302

33153303
static ssize_t
3316-
fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
3304+
__fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter, bool exclusive)
33173305
{
33183306
DECLARE_COMPLETION_ONSTACK(wait);
33193307
ssize_t ret = 0;
@@ -3407,14 +3395,27 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
34073395

34083396
if (iov_iter_rw(iter) == WRITE) {
34093397
fuse_write_update_attr(inode, pos, ret);
3410-
/* For extending writes we already hold exclusive lock */
3411-
if (ret < 0 && offset + count > i_size)
3398+
/*
3399+
* Whole-file rollback is only safe under an exclusive lock.
3400+
* Parallel writers commit i_size only on success (nothing to
3401+
* undo); the server owns failed-extend cleanup.
3402+
*/
3403+
if (exclusive && ret < 0 && offset + count > i_size)
34123404
fuse_do_truncate(file);
34133405
}
34143406

34153407
return ret;
34163408
}
34173409

3410+
static ssize_t fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
3411+
{
3412+
/*
3413+
* Only reached via generic_file_direct_write() (caching-mode
3414+
* O_DIRECT), which holds the inode lock exclusively.
3415+
*/
3416+
return __fuse_direct_IO(iocb, iter, true);
3417+
}
3418+
34183419
static int fuse_writeback_range(struct inode *inode, loff_t start, loff_t end)
34193420
{
34203421
int err = filemap_write_and_wait_range(inode->i_mapping, start, LLONG_MAX);

0 commit comments

Comments
 (0)