Skip to content

Commit 25ba2b8

Browse files
Mike SnitzerAnna Schumaker
authored andcommitted
nfs/localio: avoid issuing misaligned IO using O_DIRECT
Add nfsd_file_dio_alignment and use it to avoid issuing misaligned IO using O_DIRECT. Any misaligned DIO falls back to using buffered IO. Because misaligned DIO is now handled safely, remove the nfs modparam 'localio_O_DIRECT_semantics' that was added to require users opt-in to the requirement that all O_DIRECT be properly DIO-aligned. Also, introduce nfs_iov_iter_aligned_bvec() which is a variant of iov_iter_aligned_bvec() that also verifies the offset associated with an iov_iter is DIO-aligned. NOTE: in a parallel effort, iov_iter_aligned_bvec() is being removed along with iov_iter_is_aligned(). Lastly, add pr_info_ratelimited if underlying filesystem returns -EINVAL because it was made to try O_DIRECT for IO that is not DIO-aligned (shouldn't happen, so its best to be louder if it does). Fixes: 3feec68 ("nfs/localio: add direct IO enablement with sync and async IO support") Signed-off-by: Mike Snitzer <[email protected]> Reviewed-by: Jeff Layton <[email protected]> Signed-off-by: Anna Schumaker <[email protected]>
1 parent fd6d93c commit 25ba2b8

File tree

3 files changed

+68
-10
lines changed

3 files changed

+68
-10
lines changed

fs/nfs/localio.c

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,6 @@ struct nfs_local_fsync_ctx {
4949
static bool localio_enabled __read_mostly = true;
5050
module_param(localio_enabled, bool, 0644);
5151

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-
5752
static inline bool nfs_client_is_local(const struct nfs_client *clp)
5853
{
5954
return !!rcu_access_pointer(clp->cl_uuid.net);
@@ -322,12 +317,9 @@ nfs_local_iocb_alloc(struct nfs_pgio_header *hdr,
322317
return NULL;
323318
}
324319

325-
if (localio_O_DIRECT_semantics &&
326-
test_bit(NFS_IOHDR_ODIRECT, &hdr->flags)) {
327-
iocb->kiocb.ki_filp = file;
320+
init_sync_kiocb(&iocb->kiocb, file);
321+
if (test_bit(NFS_IOHDR_ODIRECT, &hdr->flags))
328322
iocb->kiocb.ki_flags = IOCB_DIRECT;
329-
} else
330-
init_sync_kiocb(&iocb->kiocb, file);
331323

332324
iocb->kiocb.ki_pos = hdr->args.offset;
333325
iocb->hdr = hdr;
@@ -337,6 +329,30 @@ nfs_local_iocb_alloc(struct nfs_pgio_header *hdr,
337329
return iocb;
338330
}
339331

332+
static bool nfs_iov_iter_aligned_bvec(const struct iov_iter *i,
333+
loff_t offset, unsigned int addr_mask, unsigned int len_mask)
334+
{
335+
const struct bio_vec *bvec = i->bvec;
336+
size_t skip = i->iov_offset;
337+
size_t size = i->count;
338+
339+
if ((offset | size) & len_mask)
340+
return false;
341+
do {
342+
size_t len = bvec->bv_len;
343+
344+
if (len > size)
345+
len = size;
346+
if ((unsigned long)(bvec->bv_offset + skip) & addr_mask)
347+
return false;
348+
bvec++;
349+
size -= len;
350+
skip = 0;
351+
} while (size);
352+
353+
return true;
354+
}
355+
340356
static void
341357
nfs_local_iter_init(struct iov_iter *i, struct nfs_local_kiocb *iocb, int dir)
342358
{
@@ -346,6 +362,25 @@ nfs_local_iter_init(struct iov_iter *i, struct nfs_local_kiocb *iocb, int dir)
346362
hdr->args.count + hdr->args.pgbase);
347363
if (hdr->args.pgbase != 0)
348364
iov_iter_advance(i, hdr->args.pgbase);
365+
366+
if (iocb->kiocb.ki_flags & IOCB_DIRECT) {
367+
u32 nf_dio_mem_align, nf_dio_offset_align, nf_dio_read_offset_align;
368+
/* Verify the IO is DIO-aligned as required */
369+
nfs_to->nfsd_file_dio_alignment(iocb->localio, &nf_dio_mem_align,
370+
&nf_dio_offset_align,
371+
&nf_dio_read_offset_align);
372+
if (dir == READ)
373+
nf_dio_offset_align = nf_dio_read_offset_align;
374+
375+
if (nf_dio_mem_align && nf_dio_offset_align &&
376+
nfs_iov_iter_aligned_bvec(i, hdr->args.offset,
377+
nf_dio_mem_align - 1,
378+
nf_dio_offset_align - 1))
379+
return; /* is DIO-aligned */
380+
381+
/* Fallback to using buffered for this misaligned IO */
382+
iocb->kiocb.ki_flags &= ~IOCB_DIRECT;
383+
}
349384
}
350385

351386
static void
@@ -406,6 +441,11 @@ nfs_local_read_done(struct nfs_local_kiocb *iocb, long status)
406441
struct nfs_pgio_header *hdr = iocb->hdr;
407442
struct file *filp = iocb->kiocb.ki_filp;
408443

444+
if ((iocb->kiocb.ki_flags & IOCB_DIRECT) && status == -EINVAL) {
445+
/* Underlying FS will return -EINVAL if misaligned DIO is attempted. */
446+
pr_info_ratelimited("nfs: Unexpected direct I/O read alignment failure\n");
447+
}
448+
409449
nfs_local_pgio_done(hdr, status);
410450

411451
/*
@@ -598,6 +638,11 @@ nfs_local_write_done(struct nfs_local_kiocb *iocb, long status)
598638

599639
dprintk("%s: wrote %ld bytes.\n", __func__, status > 0 ? status : 0);
600640

641+
if ((iocb->kiocb.ki_flags & IOCB_DIRECT) && status == -EINVAL) {
642+
/* Underlying FS will return -EINVAL if misaligned DIO is attempted. */
643+
pr_info_ratelimited("nfs: Unexpected direct I/O write alignment failure\n");
644+
}
645+
601646
/* Handle short writes as if they are ENOSPC */
602647
if (status > 0 && status < hdr->args.count) {
603648
hdr->mds_offset += status;

fs/nfsd/localio.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,13 +117,24 @@ nfsd_open_local_fh(struct net *net, struct auth_domain *dom,
117117
return localio;
118118
}
119119

120+
static void nfsd_file_dio_alignment(struct nfsd_file *nf,
121+
u32 *nf_dio_mem_align,
122+
u32 *nf_dio_offset_align,
123+
u32 *nf_dio_read_offset_align)
124+
{
125+
*nf_dio_mem_align = nf->nf_dio_mem_align;
126+
*nf_dio_offset_align = nf->nf_dio_offset_align;
127+
*nf_dio_read_offset_align = nf->nf_dio_read_offset_align;
128+
}
129+
120130
static const struct nfsd_localio_operations nfsd_localio_ops = {
121131
.nfsd_net_try_get = nfsd_net_try_get,
122132
.nfsd_net_put = nfsd_net_put,
123133
.nfsd_open_local_fh = nfsd_open_local_fh,
124134
.nfsd_file_put_local = nfsd_file_put_local,
125135
.nfsd_file_get_local = nfsd_file_get_local,
126136
.nfsd_file_file = nfsd_file_file,
137+
.nfsd_file_dio_alignment = nfsd_file_dio_alignment,
127138
};
128139

129140
void nfsd_localio_ops_init(void)

include/linux/nfslocalio.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ struct nfsd_localio_operations {
6565
struct net *(*nfsd_file_put_local)(struct nfsd_file __rcu **);
6666
struct nfsd_file *(*nfsd_file_get_local)(struct nfsd_file *);
6767
struct file *(*nfsd_file_file)(struct nfsd_file *);
68+
void (*nfsd_file_dio_alignment)(struct nfsd_file *,
69+
u32 *, u32 *, u32 *);
6870
} ____cacheline_aligned;
6971

7072
extern void nfsd_localio_ops_init(void);

0 commit comments

Comments
 (0)