Skip to content

Commit e43e9a3

Browse files
Mike SnitzerAnna Schumaker
authored andcommitted
nfs/localio: refactor iocb initialization
The goal of this commit's various refactoring is to have LOCALIO's per IO initialization occur in process context so that we don't get into a situation where IO fails to be issued from workqueue (e.g. due to lack of memory, etc). Better to have LOCALIO's iocb initialization fail early. There isn't immediate need but this commit makes it possible for LOCALIO to fallback to NFS pagelist code in process context to allow for immediate retry over RPC. Signed-off-by: Mike Snitzer <[email protected]> Signed-off-by: Anna Schumaker <[email protected]>
1 parent 091bdcf commit e43e9a3

File tree

1 file changed

+55
-38
lines changed

1 file changed

+55
-38
lines changed

fs/nfs/localio.c

Lines changed: 55 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ struct nfs_local_kiocb {
3636
struct nfs_pgio_header *hdr;
3737
struct work_struct work;
3838
void (*aio_complete_work)(struct work_struct *);
39+
struct iov_iter iter ____cacheline_aligned;
3940
struct nfsd_file *localio;
4041
};
4142

@@ -411,13 +412,19 @@ nfs_local_pgio_done(struct nfs_pgio_header *hdr, long status)
411412
}
412413
}
413414

415+
static void
416+
nfs_local_iocb_release(struct nfs_local_kiocb *iocb)
417+
{
418+
nfs_local_file_put(iocb->localio);
419+
nfs_local_iocb_free(iocb);
420+
}
421+
414422
static void
415423
nfs_local_pgio_release(struct nfs_local_kiocb *iocb)
416424
{
417425
struct nfs_pgio_header *hdr = iocb->hdr;
418426

419-
nfs_local_file_put(iocb->localio);
420-
nfs_local_iocb_free(iocb);
427+
nfs_local_iocb_release(iocb);
421428
nfs_local_hdr_release(hdr, hdr->task.tk_ops);
422429
}
423430

@@ -483,18 +490,16 @@ static void nfs_local_call_read(struct work_struct *work)
483490
container_of(work, struct nfs_local_kiocb, work);
484491
struct file *filp = iocb->kiocb.ki_filp;
485492
const struct cred *save_cred;
486-
struct iov_iter iter;
487493
ssize_t status;
488494

489495
save_cred = override_creds(filp->f_cred);
490496

491-
nfs_local_iter_init(&iter, iocb, ITER_DEST);
492497
if (iocb->kiocb.ki_flags & IOCB_DIRECT) {
493498
iocb->kiocb.ki_complete = nfs_local_read_aio_complete;
494499
iocb->aio_complete_work = nfs_local_read_aio_complete_work;
495500
}
496501

497-
status = filp->f_op->read_iter(&iocb->kiocb, &iter);
502+
status = filp->f_op->read_iter(&iocb->kiocb, &iocb->iter);
498503

499504
revert_creds(save_cred);
500505

@@ -505,25 +510,14 @@ static void nfs_local_call_read(struct work_struct *work)
505510
}
506511

507512
static int
508-
nfs_do_local_read(struct nfs_pgio_header *hdr,
509-
struct nfsd_file *localio,
513+
nfs_local_do_read(struct nfs_local_kiocb *iocb,
510514
const struct rpc_call_ops *call_ops)
511515
{
512-
struct nfs_local_kiocb *iocb;
513-
struct file *file = nfs_to->nfsd_file_file(localio);
514-
515-
/* Don't support filesystems without read_iter */
516-
if (!file->f_op->read_iter)
517-
return -EAGAIN;
516+
struct nfs_pgio_header *hdr = iocb->hdr;
518517

519518
dprintk("%s: vfs_read count=%u pos=%llu\n",
520519
__func__, hdr->args.count, hdr->args.offset);
521520

522-
iocb = nfs_local_iocb_alloc(hdr, file, GFP_KERNEL);
523-
if (iocb == NULL)
524-
return -ENOMEM;
525-
iocb->localio = localio;
526-
527521
nfs_local_pgio_init(hdr, call_ops);
528522
hdr->res.eof = false;
529523

@@ -680,20 +674,18 @@ static void nfs_local_call_write(struct work_struct *work)
680674
struct file *filp = iocb->kiocb.ki_filp;
681675
unsigned long old_flags = current->flags;
682676
const struct cred *save_cred;
683-
struct iov_iter iter;
684677
ssize_t status;
685678

686679
current->flags |= PF_LOCAL_THROTTLE | PF_MEMALLOC_NOIO;
687680
save_cred = override_creds(filp->f_cred);
688681

689-
nfs_local_iter_init(&iter, iocb, ITER_SOURCE);
690682
if (iocb->kiocb.ki_flags & IOCB_DIRECT) {
691683
iocb->kiocb.ki_complete = nfs_local_write_aio_complete;
692684
iocb->aio_complete_work = nfs_local_write_aio_complete_work;
693685
}
694686

695687
file_start_write(filp);
696-
status = filp->f_op->write_iter(&iocb->kiocb, &iter);
688+
status = filp->f_op->write_iter(&iocb->kiocb, &iocb->iter);
697689
file_end_write(filp);
698690

699691
revert_creds(save_cred);
@@ -707,26 +699,15 @@ static void nfs_local_call_write(struct work_struct *work)
707699
}
708700

709701
static int
710-
nfs_do_local_write(struct nfs_pgio_header *hdr,
711-
struct nfsd_file *localio,
702+
nfs_local_do_write(struct nfs_local_kiocb *iocb,
712703
const struct rpc_call_ops *call_ops)
713704
{
714-
struct nfs_local_kiocb *iocb;
715-
struct file *file = nfs_to->nfsd_file_file(localio);
716-
717-
/* Don't support filesystems without write_iter */
718-
if (!file->f_op->write_iter)
719-
return -EAGAIN;
705+
struct nfs_pgio_header *hdr = iocb->hdr;
720706

721707
dprintk("%s: vfs_write count=%u pos=%llu %s\n",
722708
__func__, hdr->args.count, hdr->args.offset,
723709
(hdr->args.stable == NFS_UNSTABLE) ? "unstable" : "stable");
724710

725-
iocb = nfs_local_iocb_alloc(hdr, file, GFP_NOIO);
726-
if (iocb == NULL)
727-
return -ENOMEM;
728-
iocb->localio = localio;
729-
730711
switch (hdr->args.stable) {
731712
default:
732713
break;
@@ -747,32 +728,68 @@ nfs_do_local_write(struct nfs_pgio_header *hdr,
747728
return 0;
748729
}
749730

731+
static struct nfs_local_kiocb *
732+
nfs_local_iocb_init(struct nfs_pgio_header *hdr, struct nfsd_file *localio)
733+
{
734+
struct file *file = nfs_to->nfsd_file_file(localio);
735+
struct nfs_local_kiocb *iocb;
736+
gfp_t gfp_mask;
737+
int rw;
738+
739+
if (hdr->rw_mode & FMODE_READ) {
740+
if (!file->f_op->read_iter)
741+
return ERR_PTR(-EOPNOTSUPP);
742+
gfp_mask = GFP_KERNEL;
743+
rw = ITER_DEST;
744+
} else {
745+
if (!file->f_op->write_iter)
746+
return ERR_PTR(-EOPNOTSUPP);
747+
gfp_mask = GFP_NOIO;
748+
rw = ITER_SOURCE;
749+
}
750+
751+
iocb = nfs_local_iocb_alloc(hdr, file, gfp_mask);
752+
if (iocb == NULL)
753+
return ERR_PTR(-ENOMEM);
754+
iocb->hdr = hdr;
755+
iocb->localio = localio;
756+
757+
nfs_local_iter_init(&iocb->iter, iocb, rw);
758+
759+
return iocb;
760+
}
761+
750762
int nfs_local_doio(struct nfs_client *clp, struct nfsd_file *localio,
751763
struct nfs_pgio_header *hdr,
752764
const struct rpc_call_ops *call_ops)
753765
{
766+
struct nfs_local_kiocb *iocb;
754767
int status = 0;
755768

756769
if (!hdr->args.count)
757770
return 0;
758771

772+
iocb = nfs_local_iocb_init(hdr, localio);
773+
if (IS_ERR(iocb))
774+
return PTR_ERR(iocb);
775+
759776
switch (hdr->rw_mode) {
760777
case FMODE_READ:
761-
status = nfs_do_local_read(hdr, localio, call_ops);
778+
status = nfs_local_do_read(iocb, call_ops);
762779
break;
763780
case FMODE_WRITE:
764-
status = nfs_do_local_write(hdr, localio, call_ops);
781+
status = nfs_local_do_write(iocb, call_ops);
765782
break;
766783
default:
767784
dprintk("%s: invalid mode: %d\n", __func__,
768785
hdr->rw_mode);
769-
status = -EINVAL;
786+
status = -EOPNOTSUPP;
770787
}
771788

772789
if (status != 0) {
773790
if (status == -EAGAIN)
774791
nfs_localio_disable_client(clp);
775-
nfs_local_file_put(localio);
792+
nfs_local_iocb_release(iocb);
776793
hdr->task.tk_status = status;
777794
nfs_local_hdr_release(hdr, call_ops);
778795
}

0 commit comments

Comments
 (0)