Skip to content

Commit fac47b4

Browse files
lxbszidryomov
authored andcommitted
netfs: do not unlock and put the folio twice
check_write_begin() will unlock and put the folio when return non-zero. So we should avoid unlocking and putting it twice in netfs layer. Change the way ->check_write_begin() works in the following two ways: (1) Pass it a pointer to the folio pointer, allowing it to unlock and put the folio prior to doing the stuff it wants to do, provided it clears the folio pointer. (2) Change the return values such that 0 with folio pointer set means continue, 0 with folio pointer cleared means re-get and all error codes indicating an error (no special treatment for -EAGAIN). [ bagasdotme: use Sphinx code text syntax for *foliop pointer ] Cc: [email protected] Link: https://tracker.ceph.com/issues/56423 Link: https://lore.kernel.org/r/[email protected] Co-developed-by: David Howells <[email protected]> Signed-off-by: Xiubo Li <[email protected]> Signed-off-by: David Howells <[email protected]> Signed-off-by: Bagas Sanjaya <[email protected]> Signed-off-by: Ilya Dryomov <[email protected]>
1 parent 3234649 commit fac47b4

File tree

5 files changed

+23
-17
lines changed

5 files changed

+23
-17
lines changed

Documentation/filesystems/netfs_library.rst

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,7 @@ through which it can issue requests and negotiate::
301301
void (*issue_read)(struct netfs_io_subrequest *subreq);
302302
bool (*is_still_valid)(struct netfs_io_request *rreq);
303303
int (*check_write_begin)(struct file *file, loff_t pos, unsigned len,
304-
struct folio *folio, void **_fsdata);
304+
struct folio **foliop, void **_fsdata);
305305
void (*done)(struct netfs_io_request *rreq);
306306
};
307307

@@ -381,8 +381,10 @@ The operations are as follows:
381381
allocated/grabbed the folio to be modified to allow the filesystem to flush
382382
conflicting state before allowing it to be modified.
383383

384-
It should return 0 if everything is now fine, -EAGAIN if the folio should be
385-
regrabbed and any other error code to abort the operation.
384+
It may unlock and discard the folio it was given and set the caller's folio
385+
pointer to NULL. It should return 0 if everything is now fine (``*foliop``
386+
left set) or the op should be retried (``*foliop`` cleared) and any other
387+
error code to abort the operation.
386388

387389
* ``done``
388390

fs/afs/file.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ static int afs_begin_cache_operation(struct netfs_io_request *rreq)
375375
}
376376

377377
static int afs_check_write_begin(struct file *file, loff_t pos, unsigned len,
378-
struct folio *folio, void **_fsdata)
378+
struct folio **foliop, void **_fsdata)
379379
{
380380
struct afs_vnode *vnode = AFS_FS_I(file_inode(file));
381381

fs/ceph/addr.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
(CONGESTION_ON_THRESH(congestion_kb) >> 2))
6464

6565
static int ceph_netfs_check_write_begin(struct file *file, loff_t pos, unsigned int len,
66-
struct folio *folio, void **_fsdata);
66+
struct folio **foliop, void **_fsdata);
6767

6868
static inline struct ceph_snap_context *page_snap_context(struct page *page)
6969
{
@@ -1288,18 +1288,19 @@ ceph_find_incompatible(struct page *page)
12881288
}
12891289

12901290
static int ceph_netfs_check_write_begin(struct file *file, loff_t pos, unsigned int len,
1291-
struct folio *folio, void **_fsdata)
1291+
struct folio **foliop, void **_fsdata)
12921292
{
12931293
struct inode *inode = file_inode(file);
12941294
struct ceph_inode_info *ci = ceph_inode(inode);
12951295
struct ceph_snap_context *snapc;
12961296

1297-
snapc = ceph_find_incompatible(folio_page(folio, 0));
1297+
snapc = ceph_find_incompatible(folio_page(*foliop, 0));
12981298
if (snapc) {
12991299
int r;
13001300

1301-
folio_unlock(folio);
1302-
folio_put(folio);
1301+
folio_unlock(*foliop);
1302+
folio_put(*foliop);
1303+
*foliop = NULL;
13031304
if (IS_ERR(snapc))
13041305
return PTR_ERR(snapc);
13051306

fs/netfs/buffered_read.c

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -319,8 +319,9 @@ static bool netfs_skip_folio_read(struct folio *folio, loff_t pos, size_t len,
319319
* conflicting writes once the folio is grabbed and locked. It is passed a
320320
* pointer to the fsdata cookie that gets returned to the VM to be passed to
321321
* write_end. It is permitted to sleep. It should return 0 if the request
322-
* should go ahead; unlock the folio and return -EAGAIN to cause the folio to
323-
* be regot; or return an error.
322+
* should go ahead or it may return an error. It may also unlock and put the
323+
* folio, provided it sets ``*foliop`` to NULL, in which case a return of 0
324+
* will cause the folio to be re-got and the process to be retried.
324325
*
325326
* The calling netfs must initialise a netfs context contiguous to the vfs
326327
* inode before calling this.
@@ -348,13 +349,13 @@ int netfs_write_begin(struct netfs_inode *ctx,
348349

349350
if (ctx->ops->check_write_begin) {
350351
/* Allow the netfs (eg. ceph) to flush conflicts. */
351-
ret = ctx->ops->check_write_begin(file, pos, len, folio, _fsdata);
352+
ret = ctx->ops->check_write_begin(file, pos, len, &folio, _fsdata);
352353
if (ret < 0) {
353354
trace_netfs_failure(NULL, NULL, ret, netfs_fail_check_write_begin);
354-
if (ret == -EAGAIN)
355-
goto retry;
356355
goto error;
357356
}
357+
if (!folio)
358+
goto retry;
358359
}
359360

360361
if (folio_test_uptodate(folio))
@@ -416,8 +417,10 @@ int netfs_write_begin(struct netfs_inode *ctx,
416417
error_put:
417418
netfs_put_request(rreq, false, netfs_rreq_trace_put_failed);
418419
error:
419-
folio_unlock(folio);
420-
folio_put(folio);
420+
if (folio) {
421+
folio_unlock(folio);
422+
folio_put(folio);
423+
}
421424
_leave(" = %d", ret);
422425
return ret;
423426
}

include/linux/netfs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ struct netfs_request_ops {
214214
void (*issue_read)(struct netfs_io_subrequest *subreq);
215215
bool (*is_still_valid)(struct netfs_io_request *rreq);
216216
int (*check_write_begin)(struct file *file, loff_t pos, unsigned len,
217-
struct folio *folio, void **_fsdata);
217+
struct folio **foliop, void **_fsdata);
218218
void (*done)(struct netfs_io_request *rreq);
219219
};
220220

0 commit comments

Comments
 (0)