Skip to content

Commit 3feec68

Browse files
Mike SnitzerAnna Schumaker
authored andcommitted
nfs/localio: add direct IO enablement with sync and async IO support
This commit simply adds the required O_DIRECT plumbing. It doesn't address the fact that NFS doesn't ensure all writes are page aligned (nor device logical block size aligned as required by O_DIRECT). Because NFS will read-modify-write for IO that isn't aligned, LOCALIO will not use O_DIRECT semantics by default if/when an application requests the use of O_DIRECT. Allow the use of O_DIRECT semantics by: 1: Adding a flag to the nfs_pgio_header struct to allow the NFS O_DIRECT layer to signal that O_DIRECT was used by the application 2: Adding a 'localio_O_DIRECT_semantics' NFS module parameter that when enabled will cause LOCALIO to use O_DIRECT semantics (this may cause IO to fail if applications do not properly align their IO). This commit is derived from code developed by Weston Andros Adamson. Signed-off-by: Mike Snitzer <[email protected]> Reviewed-by: Jeff Layton <[email protected]> Signed-off-by: Anna Schumaker <[email protected]>
1 parent 49fd4e3 commit 3feec68

File tree

4 files changed

+98
-10
lines changed

4 files changed

+98
-10
lines changed

Documentation/filesystems/nfs/localio.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,19 @@ is issuing IO to the underlying local filesystem that it is sharing with
306306
the NFS server. See: fs/nfs/localio.c:nfs_local_doio() and
307307
fs/nfs/localio.c:nfs_local_commit().
308308

309+
With normal NFS that makes use of RPC to issue IO to the server, if an
310+
application uses O_DIRECT the NFS client will bypass the pagecache but
311+
the NFS server will not. Because the NFS server's use of buffered IO
312+
affords applications to be less precise with their alignment when
313+
issuing IO to the NFS client. LOCALIO can be configured to use O_DIRECT
314+
semantics by setting the 'localio_O_DIRECT_semantics' nfs module
315+
parameter to Y, e.g.:
316+
317+
echo Y > /sys/module/nfs/parameters/localio_O_DIRECT_semantics
318+
319+
Once enabled, it will cause LOCALIO to use O_DIRECT semantics (this may
320+
cause IO to fail if applications do not properly align their IO).
321+
309322
Security
310323
========
311324

fs/nfs/direct.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ static void nfs_read_sync_pgio_error(struct list_head *head, int error)
303303
static void nfs_direct_pgio_init(struct nfs_pgio_header *hdr)
304304
{
305305
get_dreq(hdr->dreq);
306+
set_bit(NFS_IOHDR_ODIRECT, &hdr->flags);
306307
}
307308

308309
static const struct nfs_pgio_completion_ops nfs_direct_read_completion_ops = {

fs/nfs/localio.c

Lines changed: 83 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ struct nfs_local_kiocb {
3535
struct bio_vec *bvec;
3636
struct nfs_pgio_header *hdr;
3737
struct work_struct work;
38+
void (*aio_complete_work)(struct work_struct *);
3839
struct nfsd_file *localio;
3940
};
4041

@@ -48,6 +49,11 @@ struct nfs_local_fsync_ctx {
4849
static bool localio_enabled __read_mostly = true;
4950
module_param(localio_enabled, bool, 0644);
5051

52+
static bool localio_O_DIRECT_semantics __read_mostly = false;
53+
module_param(localio_O_DIRECT_semantics, bool, 0644);
54+
MODULE_PARM_DESC(localio_O_DIRECT_semantics,
55+
"LOCALIO will use O_DIRECT semantics to filesystem.");
56+
5157
static inline bool nfs_client_is_local(const struct nfs_client *clp)
5258
{
5359
return !!test_bit(NFS_CS_LOCAL_IO, &clp->cl_flags);
@@ -285,10 +291,19 @@ nfs_local_iocb_alloc(struct nfs_pgio_header *hdr,
285291
kfree(iocb);
286292
return NULL;
287293
}
288-
init_sync_kiocb(&iocb->kiocb, file);
294+
295+
if (localio_O_DIRECT_semantics &&
296+
test_bit(NFS_IOHDR_ODIRECT, &hdr->flags)) {
297+
iocb->kiocb.ki_filp = file;
298+
iocb->kiocb.ki_flags = IOCB_DIRECT;
299+
} else
300+
init_sync_kiocb(&iocb->kiocb, file);
301+
289302
iocb->kiocb.ki_pos = hdr->args.offset;
290303
iocb->hdr = hdr;
291304
iocb->kiocb.ki_flags &= ~IOCB_APPEND;
305+
iocb->aio_complete_work = NULL;
306+
292307
return iocb;
293308
}
294309

@@ -343,6 +358,18 @@ nfs_local_pgio_release(struct nfs_local_kiocb *iocb)
343358
nfs_local_hdr_release(hdr, hdr->task.tk_ops);
344359
}
345360

361+
/*
362+
* Complete the I/O from iocb->kiocb.ki_complete()
363+
*
364+
* Note that this function can be called from a bottom half context,
365+
* hence we need to queue the rpc_call_done() etc to a workqueue
366+
*/
367+
static inline void nfs_local_pgio_aio_complete(struct nfs_local_kiocb *iocb)
368+
{
369+
INIT_WORK(&iocb->work, iocb->aio_complete_work);
370+
queue_work(nfsiod_workqueue, &iocb->work);
371+
}
372+
346373
static void
347374
nfs_local_read_done(struct nfs_local_kiocb *iocb, long status)
348375
{
@@ -365,6 +392,23 @@ nfs_local_read_done(struct nfs_local_kiocb *iocb, long status)
365392
status > 0 ? status : 0, hdr->res.eof);
366393
}
367394

395+
static void nfs_local_read_aio_complete_work(struct work_struct *work)
396+
{
397+
struct nfs_local_kiocb *iocb =
398+
container_of(work, struct nfs_local_kiocb, work);
399+
400+
nfs_local_pgio_release(iocb);
401+
}
402+
403+
static void nfs_local_read_aio_complete(struct kiocb *kiocb, long ret)
404+
{
405+
struct nfs_local_kiocb *iocb =
406+
container_of(kiocb, struct nfs_local_kiocb, kiocb);
407+
408+
nfs_local_read_done(iocb, ret);
409+
nfs_local_pgio_aio_complete(iocb); /* Calls nfs_local_read_aio_complete_work */
410+
}
411+
368412
static void nfs_local_call_read(struct work_struct *work)
369413
{
370414
struct nfs_local_kiocb *iocb =
@@ -379,10 +423,10 @@ static void nfs_local_call_read(struct work_struct *work)
379423
nfs_local_iter_init(&iter, iocb, READ);
380424

381425
status = filp->f_op->read_iter(&iocb->kiocb, &iter);
382-
WARN_ON_ONCE(status == -EIOCBQUEUED);
383-
384-
nfs_local_read_done(iocb, status);
385-
nfs_local_pgio_release(iocb);
426+
if (status != -EIOCBQUEUED) {
427+
nfs_local_read_done(iocb, status);
428+
nfs_local_pgio_release(iocb);
429+
}
386430

387431
revert_creds(save_cred);
388432
}
@@ -410,6 +454,11 @@ nfs_do_local_read(struct nfs_pgio_header *hdr,
410454
nfs_local_pgio_init(hdr, call_ops);
411455
hdr->res.eof = false;
412456

457+
if (iocb->kiocb.ki_flags & IOCB_DIRECT) {
458+
iocb->kiocb.ki_complete = nfs_local_read_aio_complete;
459+
iocb->aio_complete_work = nfs_local_read_aio_complete_work;
460+
}
461+
413462
INIT_WORK(&iocb->work, nfs_local_call_read);
414463
queue_work(nfslocaliod_workqueue, &iocb->work);
415464

@@ -534,6 +583,24 @@ nfs_local_write_done(struct nfs_local_kiocb *iocb, long status)
534583
nfs_local_pgio_done(hdr, status);
535584
}
536585

586+
static void nfs_local_write_aio_complete_work(struct work_struct *work)
587+
{
588+
struct nfs_local_kiocb *iocb =
589+
container_of(work, struct nfs_local_kiocb, work);
590+
591+
nfs_local_vfs_getattr(iocb);
592+
nfs_local_pgio_release(iocb);
593+
}
594+
595+
static void nfs_local_write_aio_complete(struct kiocb *kiocb, long ret)
596+
{
597+
struct nfs_local_kiocb *iocb =
598+
container_of(kiocb, struct nfs_local_kiocb, kiocb);
599+
600+
nfs_local_write_done(iocb, ret);
601+
nfs_local_pgio_aio_complete(iocb); /* Calls nfs_local_write_aio_complete_work */
602+
}
603+
537604
static void nfs_local_call_write(struct work_struct *work)
538605
{
539606
struct nfs_local_kiocb *iocb =
@@ -552,11 +619,11 @@ static void nfs_local_call_write(struct work_struct *work)
552619
file_start_write(filp);
553620
status = filp->f_op->write_iter(&iocb->kiocb, &iter);
554621
file_end_write(filp);
555-
WARN_ON_ONCE(status == -EIOCBQUEUED);
556-
557-
nfs_local_write_done(iocb, status);
558-
nfs_local_vfs_getattr(iocb);
559-
nfs_local_pgio_release(iocb);
622+
if (status != -EIOCBQUEUED) {
623+
nfs_local_write_done(iocb, status);
624+
nfs_local_vfs_getattr(iocb);
625+
nfs_local_pgio_release(iocb);
626+
}
560627

561628
revert_creds(save_cred);
562629
current->flags = old_flags;
@@ -592,10 +659,16 @@ nfs_do_local_write(struct nfs_pgio_header *hdr,
592659
case NFS_FILE_SYNC:
593660
iocb->kiocb.ki_flags |= IOCB_DSYNC|IOCB_SYNC;
594661
}
662+
595663
nfs_local_pgio_init(hdr, call_ops);
596664

597665
nfs_set_local_verifier(hdr->inode, hdr->res.verf, hdr->args.stable);
598666

667+
if (iocb->kiocb.ki_flags & IOCB_DIRECT) {
668+
iocb->kiocb.ki_complete = nfs_local_write_aio_complete;
669+
iocb->aio_complete_work = nfs_local_write_aio_complete_work;
670+
}
671+
599672
INIT_WORK(&iocb->work, nfs_local_call_write);
600673
queue_work(nfslocaliod_workqueue, &iocb->work);
601674

include/linux/nfs_xdr.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1637,6 +1637,7 @@ enum {
16371637
NFS_IOHDR_RESEND_PNFS,
16381638
NFS_IOHDR_RESEND_MDS,
16391639
NFS_IOHDR_UNSTABLE_WRITES,
1640+
NFS_IOHDR_ODIRECT,
16401641
};
16411642

16421643
struct nfs_io_completion;

0 commit comments

Comments
 (0)