Skip to content

Commit 389a4a4

Browse files
committed
ovl: punt write aio completion to workqueue
We want to protect concurrent updates of ovl inode size and mtime (i.e. ovl_copyattr()) from aio completion context. Punt write aio completion to a workqueue so that we can protect ovl_copyattr() with a spinlock. Export sb_init_dio_done_wq(), so that overlayfs can use its own dio workqueue to punt aio completions. Suggested-by: Jens Axboe <axboe@kernel.dk> Link: https://lore.kernel.org/r/8620dfd3-372d-4ae0-aa3f-2fe97dda1bca@kernel.dk/ Signed-off-by: Amir Goldstein <amir73il@gmail.com>
1 parent 5f034d3 commit 389a4a4

2 files changed

Lines changed: 42 additions & 1 deletion

File tree

fs/overlayfs/file.c

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,15 @@
1515
#include <linux/fs.h>
1616
#include "overlayfs.h"
1717

18+
#include "../internal.h" /* for sb_init_dio_done_wq */
19+
1820
struct ovl_aio_req {
1921
struct kiocb iocb;
2022
refcount_t ref;
2123
struct kiocb *orig_iocb;
24+
/* used for aio completion */
25+
struct work_struct work;
26+
long res;
2227
};
2328

2429
static struct kmem_cache *ovl_aio_request_cachep;
@@ -305,6 +310,37 @@ static void ovl_aio_rw_complete(struct kiocb *iocb, long res)
305310
orig_iocb->ki_complete(orig_iocb, res);
306311
}
307312

313+
static void ovl_aio_complete_work(struct work_struct *work)
314+
{
315+
struct ovl_aio_req *aio_req = container_of(work,
316+
struct ovl_aio_req, work);
317+
318+
ovl_aio_rw_complete(&aio_req->iocb, aio_req->res);
319+
}
320+
321+
static void ovl_aio_queue_completion(struct kiocb *iocb, long res)
322+
{
323+
struct ovl_aio_req *aio_req = container_of(iocb,
324+
struct ovl_aio_req, iocb);
325+
struct kiocb *orig_iocb = aio_req->orig_iocb;
326+
327+
/*
328+
* Punt to a work queue to serialize updates of mtime/size.
329+
*/
330+
aio_req->res = res;
331+
INIT_WORK(&aio_req->work, ovl_aio_complete_work);
332+
queue_work(file_inode(orig_iocb->ki_filp)->i_sb->s_dio_done_wq,
333+
&aio_req->work);
334+
}
335+
336+
static int ovl_init_aio_done_wq(struct super_block *sb)
337+
{
338+
if (sb->s_dio_done_wq)
339+
return 0;
340+
341+
return sb_init_dio_done_wq(sb);
342+
}
343+
308344
static ssize_t ovl_read_iter(struct kiocb *iocb, struct iov_iter *iter)
309345
{
310346
struct file *file = iocb->ki_filp;
@@ -404,6 +440,10 @@ static ssize_t ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter)
404440
} else {
405441
struct ovl_aio_req *aio_req;
406442

443+
ret = ovl_init_aio_done_wq(inode->i_sb);
444+
if (ret)
445+
goto out;
446+
407447
ret = -ENOMEM;
408448
aio_req = kmem_cache_zalloc(ovl_aio_request_cachep, GFP_KERNEL);
409449
if (!aio_req)
@@ -412,7 +452,7 @@ static ssize_t ovl_write_iter(struct kiocb *iocb, struct iov_iter *iter)
412452
aio_req->orig_iocb = iocb;
413453
kiocb_clone(&aio_req->iocb, iocb, get_file(real.file));
414454
aio_req->iocb.ki_flags = ifl;
415-
aio_req->iocb.ki_complete = ovl_aio_rw_complete;
455+
aio_req->iocb.ki_complete = ovl_aio_queue_completion;
416456
refcount_set(&aio_req->ref, 2);
417457
kiocb_start_write(&aio_req->iocb);
418458
ret = vfs_iocb_iter_write(real.file, &aio_req->iocb, iter);

fs/super.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2157,3 +2157,4 @@ int sb_init_dio_done_wq(struct super_block *sb)
21572157
destroy_workqueue(wq);
21582158
return 0;
21592159
}
2160+
EXPORT_SYMBOL_GPL(sb_init_dio_done_wq);

0 commit comments

Comments
 (0)