* Re: [PATCH v24 12/24] x86/sgx: Linux Enclave Driver
From: Jarkko Sakkinen @ 2019-12-09 19:08 UTC (permalink / raw)
To: Haitao Huang
Cc: linux-kernel, x86, linux-sgx, akpm, dave.hansen,
sean.j.christopherson, nhorman, npmccallum, serge.ayoun,
shay.katz-zamir, haitao.huang, andriy.shevchenko, tglx, kai.svahn,
bp, josh, luto, kai.huang, rientjes, cedric.xing, puiterwijk,
linux-security-module, Suresh Siddha
In-Reply-To: <op.0b6gvhtiwjvjmi@hhuan26-mobl.amr.corp.intel.com>
On Mon, Dec 02, 2019 at 09:48:43AM -0600, Haitao Huang wrote:
> On Fri, 29 Nov 2019 17:13:14 -0600, Jarkko Sakkinen
> <jarkko.sakkinen@linux.intel.com> wrote:
>
>
> > +
> > + for (c = 0 ; c < addp.length; c += PAGE_SIZE) {
> > + if (signal_pending(current)) {
> > + ret = -ERESTARTSYS;
> > + break;
> > + }
>
> This IOC is not idempotent as pages EADDed at this point can not be
> re-EADDed again. So we can't return ERESTARTSYS
Agreed, should be -EINTR.
I added these entries to the v25 change log based on your recent
reports:
* Fix a double-free issue when SGX_IOC_ENCLAVE_ADD_PAGES
fails on executing ENCLS[EADD]. The rollback path executed
radix_tree_delete() on the same address twice when this happened.
[fixes v24, reported by Haitao]
* Return -EINTR instead of -ERESTARTSYS in SGX_IOC_ENCLAVE_ADD_PAGES when
a signal is pending [fixes v23, reported by Haitao]
The master branch [1] has been updated accordingly. There is also a
tag v24 for looking up easily what has overally changed e.g.
$ git --no-pager diff v24..master
diff --git a/arch/x86/kernel/cpu/sgx/ioctl.c b/arch/x86/kernel/cpu/sgx/ioctl.c
index ab9e48cd294b..5c9e6e161698 100644
--- a/arch/x86/kernel/cpu/sgx/ioctl.c
+++ b/arch/x86/kernel/cpu/sgx/ioctl.c
@@ -413,13 +413,8 @@ static int sgx_encl_add_page(struct sgx_encl *encl, unsigned long src,
ret = __sgx_encl_add_page(encl, encl_page, epc_page, secinfo,
src);
- if (ret) {
- /* ENCLS failure. */
- if (ret == -EIO)
- sgx_encl_destroy(encl);
-
+ if (ret)
goto err_out;
- }
/*
* Complete the "add" before doing the "extend" so that the "add"
@@ -432,17 +427,11 @@ static int sgx_encl_add_page(struct sgx_encl *encl, unsigned long src,
if (flags & SGX_PAGE_MEASURE) {
ret = __sgx_encl_extend(encl, epc_page);
-
- /* ENCLS failure. */
- if (ret) {
- sgx_encl_destroy(encl);
- goto out_unlock;
- }
+ if (ret)
+ goto err_out;
}
sgx_mark_page_reclaimable(encl_page->epc_page);
-
-out_unlock:
mutex_unlock(&encl->lock);
up_read(¤t->mm->mmap_sem);
return ret;
@@ -460,6 +449,13 @@ static int sgx_encl_add_page(struct sgx_encl *encl, unsigned long src,
sgx_free_page(epc_page);
kfree(encl_page);
+ /*
+ * Destroy enclave on ENCLS failure as this means that EPC has been
+ * invalidated.
+ */
+ if (ret == -EIO)
+ sgx_encl_destroy(encl);
+
return ret;
}
@@ -536,7 +532,7 @@ static long sgx_ioc_enclave_add_pages(struct sgx_encl *encl, void __user *arg)
for (c = 0 ; c < addp.length; c += PAGE_SIZE) {
if (signal_pending(current)) {
- ret = -ERESTARTSYS;
+ ret = -EINTR;
break;
}
[1] https://github.com/jsakkine-intel/linux-sgx
/Jarkko
^ permalink raw reply related
* Re: [PATCH v24 12/24] x86/sgx: Linux Enclave Driver
From: Jarkko Sakkinen @ 2019-12-09 19:38 UTC (permalink / raw)
To: Sean Christopherson
Cc: Haitao Huang, linux-kernel, x86, linux-sgx, akpm, dave.hansen,
nhorman, npmccallum, serge.ayoun, shay.katz-zamir, haitao.huang,
andriy.shevchenko, tglx, kai.svahn, bp, josh, luto, kai.huang,
rientjes, cedric.xing, puiterwijk, linux-security-module,
Suresh Siddha
In-Reply-To: <20191202182102.GF4063@linux.intel.com>
On Mon, Dec 02, 2019 at 10:21:03AM -0800, Sean Christopherson wrote:
> On Mon, Dec 02, 2019 at 09:48:43AM -0600, Haitao Huang wrote:
> > On Fri, 29 Nov 2019 17:13:14 -0600, Jarkko Sakkinen
> > <jarkko.sakkinen@linux.intel.com> wrote:
> >
> >
> > >+
> > >+ for (c = 0 ; c < addp.length; c += PAGE_SIZE) {
> > >+ if (signal_pending(current)) {
> > >+ ret = -ERESTARTSYS;
> > >+ break;
> > >+ }
> >
> > This IOC is not idempotent as pages EADDed at this point can not be
> > re-EADDed again. So we can't return ERESTARTSYS
>
> Ah, and now I remember why I opted for modifying the parameters directly
> instead of including a "number processed" field. Andy pointed out the
> ERESTARTSYS thing in the original multi-page add RFC[*], so presumably
> updating the params and returning ERESTARTSYS is legal/acceptable.
>
> [*] https://lkml.kernel.org/r/CALCETrUb4X9_L9RXKhmyNpfSCsbNodP=BfbfO8Fz_efq24jp8w@mail.gmail.com
There are exactly two primary options to pick from given the
non-idempotent nature:
A. Return zero (since we support partial operation with the changes I
did in v24).
B. Return -EINTR.
If we wanted to follow common syscall semantics in IO operations, then
the semantics would be a mix of these:
1. Return -EINTR if signals are pending before any pages got added.
2. Return 0 if at least one page got added.
This is how write() works for example according to the documentation
[1]. As far as the user code goes [2] I think for that it is best
idea to rely on semantics that developers are used to instead of
being clever here.
[1] http://man7.org/linux/man-pages/man2/write.2.html
[2] https://lkml.kernel.org/r/CALCETrUb4X9_L9RXKhmyNpfSCsbNodP=BfbfO8Fz_efq24jp8w@mail.gmail.com
/Jarkko
^ permalink raw reply
* Re: [PATCH 0/2] Revert patches fixing probing of interrupts
From: Jarkko Sakkinen @ 2019-12-09 19:42 UTC (permalink / raw)
To: Stefan Berger, Stefan Berger, linux-integrity, linux-kernel,
stable, linux-security-module
In-Reply-To: <20191202185520.57w2h3dgs5q7lhob@cantor>
On Mon, Dec 02, 2019 at 11:55:20AM -0700, Jerry Snitselaar wrote:
> On Sun Dec 01 19, Stefan Berger wrote:
> > On 11/29/19 5:37 PM, Jarkko Sakkinen wrote:
> > > On Tue, Nov 26, 2019 at 08:17:51AM -0500, Stefan Berger wrote:
> > > > From: Stefan Berger <stefanb@linux.ibm.com>
> > > >
> > > > Revert the patches that were fixing the probing of interrupts due
> > > > to reports of interrupt stroms on some systems
> > > Can you explain how reverting is going to fix the issue?
> >
> >
> > The reverts fix 'the interrupt storm issue' that they are causing on
> > some systems but don't fix the issue with the interrupt mode not being
> > used. I was hoping Jerry would get access to a system faster but this
> > didn't seem to be the case. So sending these patches seemed the better
> > solution than leaving 5.4.x with the problem but going back to when it
> > worked 'better.'
> >
>
> I finally heard back from IT support, and unfortunately they don't
> have any T490s systems to give out on temp loan. So I can only send
> patched kernels to the end user that had the problem.
At least it is a fact that tpm_chip_stop() is called too early and that
is destined to cause issues.
Should I bake a patch or do you have already something?
/Jarkko
^ permalink raw reply
* Re: [PATCH v23 12/24] x86/sgx: Linux Enclave Driver
From: Jarkko Sakkinen @ 2019-12-09 19:57 UTC (permalink / raw)
To: Greg KH
Cc: linux-kernel, x86, linux-sgx, akpm, dave.hansen,
sean.j.christopherson, nhorman, npmccallum, serge.ayoun,
shay.katz-zamir, haitao.huang, andriy.shevchenko, tglx, kai.svahn,
bp, josh, luto, kai.huang, rientjes, cedric.xing, puiterwijk,
linux-security-module, Suresh Siddha
In-Reply-To: <20191207080939.GA193518@kroah.com>
On Sat, Dec 07, 2019 at 09:09:39AM +0100, Greg KH wrote:
> On Fri, Dec 06, 2019 at 10:38:07PM +0200, Jarkko Sakkinen wrote:
> > > Why a whole cdev?
> > >
> > > Why not use a misc device? YOu only have 2 devices right? Why not 2
> > > misc devices then? That saves the use of a whole major number and makes
> > > your code a _LOT_ simpler.
> >
> > The downside would be that if we ever want to add sysfs attributes, that
> > could not be done synchronously with the device creation.
>
> That is what the groups member of struct misc_device is for.
OK, cool, then there is no problem changing to misc.
I haven't seen misc drivers (not that I've looked through every single
of them so I suppose there are such) to use it and somehow have been
blind to seeing it that it si there.
Thanks again for the feedback. I'll fix this for the next patch set
version.
/Jarkko
^ permalink raw reply
* Re: [PATCH v2] tomoyo: Don't check open/getattr permission on sockets.
From: James Morris @ 2019-12-09 21:37 UTC (permalink / raw)
To: Tetsuo Handa
Cc: Andrew Morton, Stephen Rothwell, linux-security-module,
Linus Torvalds
In-Reply-To: <579b10bb-990f-ae4c-8098-b39e56a4c475@i-love.sakura.ne.jp>
On Wed, 4 Dec 2019, Tetsuo Handa wrote:
>
> I decided to drop tomoyo_get_socket_name(). Will you pick up the following commit?
>
> commit c39593ab0500fcd6db290b311c120349927ddc04
> Author: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
> Date: Mon Nov 25 10:46:51 2019 +0900
>
> tomoyo: Don't use nifty names on sockets.
>
From where?
Please send a patch.
--
James Morris
<jmorris@namei.org>
^ permalink raw reply
* Re: [PATCH 0/2] Revert patches fixing probing of interrupts
From: Jerry Snitselaar @ 2019-12-09 21:55 UTC (permalink / raw)
To: Jarkko Sakkinen
Cc: Stefan Berger, Stefan Berger, linux-integrity, linux-kernel,
stable, linux-security-module
In-Reply-To: <20191209194248.GC19243@linux.intel.com>
On Mon Dec 09 19, Jarkko Sakkinen wrote:
>On Mon, Dec 02, 2019 at 11:55:20AM -0700, Jerry Snitselaar wrote:
>> On Sun Dec 01 19, Stefan Berger wrote:
>> > On 11/29/19 5:37 PM, Jarkko Sakkinen wrote:
>> > > On Tue, Nov 26, 2019 at 08:17:51AM -0500, Stefan Berger wrote:
>> > > > From: Stefan Berger <stefanb@linux.ibm.com>
>> > > >
>> > > > Revert the patches that were fixing the probing of interrupts due
>> > > > to reports of interrupt stroms on some systems
>> > > Can you explain how reverting is going to fix the issue?
>> >
>> >
>> > The reverts fix 'the interrupt storm issue' that they are causing on
>> > some systems but don't fix the issue with the interrupt mode not being
>> > used. I was hoping Jerry would get access to a system faster but this
>> > didn't seem to be the case. So sending these patches seemed the better
>> > solution than leaving 5.4.x with the problem but going back to when it
>> > worked 'better.'
>> >
>>
>> I finally heard back from IT support, and unfortunately they don't
>> have any T490s systems to give out on temp loan. So I can only send
>> patched kernels to the end user that had the problem.
>
>At least it is a fact that tpm_chip_stop() is called too early and that
>is destined to cause issues.
>
>Should I bake a patch or do you have already something?
>
>/Jarkko
>
This is what I'm currently building:
diff --git a/drivers/char/tpm/tpm_tis_core.c b/drivers/char/tpm/tpm_tis_core.c
index 270f43acbb77..17184c07eb51 100644
--- a/drivers/char/tpm/tpm_tis_core.c
+++ b/drivers/char/tpm/tpm_tis_core.c
@@ -899,13 +899,13 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
if (wait_startup(chip, 0) != 0) {
rc = -ENODEV;
- goto out_err;
+ goto out_start;
}
/* Take control of the TPM's interrupt hardware and shut it off */
rc = tpm_tis_read32(priv, TPM_INT_ENABLE(priv->locality), &intmask);
if (rc < 0)
- goto out_err;
+ goto out_start;
intmask |= TPM_INTF_CMD_READY_INT | TPM_INTF_LOCALITY_CHANGE_INT |
TPM_INTF_DATA_AVAIL_INT | TPM_INTF_STS_VALID_INT;
@@ -914,9 +914,8 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
rc = tpm_chip_start(chip);
if (rc)
- goto out_err;
+ goto out_start;
rc = tpm2_probe(chip);
- tpm_chip_stop(chip);
if (rc)
goto out_err;
@@ -980,7 +979,6 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
goto out_err;
}
- tpm_chip_start(chip);
chip->flags |= TPM_CHIP_FLAG_IRQ;
if (irq) {
tpm_tis_probe_irq_single(chip, intmask, IRQF_SHARED,
@@ -991,18 +989,17 @@ int tpm_tis_core_init(struct device *dev, struct tpm_tis_data *priv, int irq,
} else {
tpm_tis_probe_irq(chip, intmask);
}
- tpm_chip_stop(chip);
}
+ tpm_chip_stop(chip);
rc = tpm_chip_register(chip);
if (rc)
- goto out_err;
-
- if (chip->ops->clk_enable != NULL)
- chip->ops->clk_enable(chip, false);
+ goto out_start;
return 0;
out_err:
+ tpm_chip_stop(chip);
+out_start:
if ((chip->ops != NULL) && (chip->ops->clk_enable != NULL))
chip->ops->clk_enable(chip, false);
^ permalink raw reply related
* Re: [RFC PATCH v2] security,lockdown,selinux: implement SELinux lockdown
From: Paul Moore @ 2019-12-09 23:12 UTC (permalink / raw)
To: Stephen Smalley
Cc: selinux, linux-security-module, linux-audit, James Morris,
matthewgarrett
In-Reply-To: <20191127170436.4237-1-sds@tycho.nsa.gov>
On Wed, Nov 27, 2019 at 12:04 PM Stephen Smalley <sds@tycho.nsa.gov> wrote:
> Implement a SELinux hook for lockdown. If the lockdown module is also
> enabled, then a denial by the lockdown module will take precedence over
> SELinux, so SELinux can only further restrict lockdown decisions.
> The SELinux hook only distinguishes at the granularity of integrity
> versus confidentiality similar to the lockdown module, but includes the
> full lockdown reason as part of the audit record as a hint in diagnosing
> what triggered the denial. To support this auditing, move the
> lockdown_reasons[] string array from being private to the lockdown
> module to the security framework so that it can be used by the lsm audit
> code and so that it is always available even when the lockdown module
> is disabled.
>
> Note that the SELinux implementation allows the integrity and
> confidentiality reasons to be controlled independently from one another.
> Thus, in an SELinux policy, one could allow operations that specify
> an integrity reason while blocking operations that specify a
> confidentiality reason. The SELinux hook implementation is
> stricter than the lockdown module in validating the provided reason value.
>
> Sample AVC audit output from denials:
> avc: denied { integrity } for pid=3402 comm="fwupd"
> lockdown_reason="/dev/mem,kmem,port" scontext=system_u:system_r:fwupd_t:s0
> tcontext=system_u:system_r:fwupd_t:s0 tclass=lockdown permissive=0
>
> avc: denied { confidentiality } for pid=4628 comm="cp"
> lockdown_reason="/proc/kcore access"
> scontext=unconfined_u:unconfined_r:test_lockdown_integrity_t:s0-s0:c0.c1023
> tcontext=unconfined_u:unconfined_r:test_lockdown_integrity_t:s0-s0:c0.c1023
> tclass=lockdown permissive=0
>
> Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
> ---
> include/linux/lsm_audit.h | 2 ++
> include/linux/security.h | 2 ++
> security/lockdown/lockdown.c | 24 -----------------------
> security/lsm_audit.c | 5 +++++
> security/security.c | 30 +++++++++++++++++++++++++++++
> security/selinux/hooks.c | 30 +++++++++++++++++++++++++++++
> security/selinux/include/classmap.h | 2 ++
> 7 files changed, 71 insertions(+), 24 deletions(-)
While I remain concerned about the granularity, I think this is about
as good as we can get right now without potentially messing things up
in the future. Applied to selinux/next, thanks Stephen.
--
paul moore
www.paul-moore.com
^ permalink raw reply
* Re: [PATCH 1/2] selinux: revert "stop passing MAY_NOT_BLOCK to the AVC upon follow_link"
From: Paul Moore @ 2019-12-09 23:42 UTC (permalink / raw)
To: Stephen Smalley
Cc: selinux, will, viro, neilb, linux-fsdevel, linux-security-module
In-Reply-To: <20191122172245.7875-1-sds@tycho.nsa.gov>
On Fri, Nov 22, 2019 at 12:23 PM Stephen Smalley <sds@tycho.nsa.gov> wrote:
> This reverts commit e46e01eebbbc ("selinux: stop passing MAY_NOT_BLOCK
> to the AVC upon follow_link"). The correct fix is to instead fall
> back to ref-walk if audit is required irrespective of the specific
> audit data type. This is done in the next commit.
>
> Fixes: e46e01eebbbc ("selinux: stop passing MAY_NOT_BLOCK to the AVC upon follow_link")
> Reported-by: Will Deacon <will@kernel.org>
> Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
> ---
> security/selinux/avc.c | 24 ++++++++++++++++++++++--
> security/selinux/hooks.c | 5 +++--
> security/selinux/include/avc.h | 5 +++++
> 3 files changed, 30 insertions(+), 4 deletions(-)
Merged into selinux/next, thanks.
--
paul moore
www.paul-moore.com
^ permalink raw reply
* Re: [PATCH 2/2] selinux: fall back to ref-walk if audit is required
From: Paul Moore @ 2019-12-09 23:42 UTC (permalink / raw)
To: Stephen Smalley
Cc: selinux, will, viro, neilb, linux-fsdevel, linux-security-module
In-Reply-To: <20191122172245.7875-2-sds@tycho.nsa.gov>
On Fri, Nov 22, 2019 at 12:23 PM Stephen Smalley <sds@tycho.nsa.gov> wrote:
> commit bda0be7ad994 ("security: make inode_follow_link RCU-walk aware")
> passed down the rcu flag to the SELinux AVC, but failed to adjust the
> test in slow_avc_audit() to also return -ECHILD on LSM_AUDIT_DATA_DENTRY.
> Previously, we only returned -ECHILD if generating an audit record with
> LSM_AUDIT_DATA_INODE since this was only relevant from inode_permission.
> Move the handling of MAY_NOT_BLOCK to avc_audit() and its inlined
> equivalent in selinux_inode_permission() immediately after we determine
> that audit is required, and always fall back to ref-walk in this case.
>
> Fixes: bda0be7ad994 ("security: make inode_follow_link RCU-walk aware")
> Reported-by: Will Deacon <will@kernel.org>
> Suggested-by: Al Viro <viro@zeniv.linux.org.uk>
> Signed-off-by: Stephen Smalley <sds@tycho.nsa.gov>
> ---
> security/selinux/avc.c | 24 +++++-------------------
> security/selinux/hooks.c | 11 +++++++----
> security/selinux/include/avc.h | 8 +++++---
> 3 files changed, 17 insertions(+), 26 deletions(-)
Also merged into selinux/next, thanks.
--
paul moore
www.paul-moore.com
^ permalink raw reply
* [RFC PATCH] selinux: ensure we cleanup the internal AVC counters on error in avc_insert()
From: Paul Moore @ 2019-12-10 1:53 UTC (permalink / raw)
To: selinux; +Cc: rsiddoji, sds, linux-security-module
In AVC insert we don't call avc_node_kill() when avc_xperms_populate()
fails, resulting in the avc->avc_cache.active_nodes counter having a
false value. This patch corrects this problem and does some cleanup
in avc_insert() while we are there.
Reported-by: rsiddoji@codeaurora.org
Suggested-by: Stephen Smalley <sds@tycho.nsa.gov>
Signed-off-by: Paul Moore <paul@paul-moore.com>
---
security/selinux/avc.c | 51 +++++++++++++++++++++++-------------------------
1 file changed, 24 insertions(+), 27 deletions(-)
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 23dc888ae305..6646300f7ccb 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -617,40 +617,37 @@ static struct avc_node *avc_insert(struct selinux_avc *avc,
struct avc_node *pos, *node = NULL;
int hvalue;
unsigned long flag;
+ spinlock_t *lock;
+ struct hlist_head *head;
if (avc_latest_notif_update(avc, avd->seqno, 1))
- goto out;
+ return NULL;
node = avc_alloc_node(avc);
- if (node) {
- struct hlist_head *head;
- spinlock_t *lock;
- int rc = 0;
-
- hvalue = avc_hash(ssid, tsid, tclass);
- avc_node_populate(node, ssid, tsid, tclass, avd);
- rc = avc_xperms_populate(node, xp_node);
- if (rc) {
- kmem_cache_free(avc_node_cachep, node);
- return NULL;
- }
- head = &avc->avc_cache.slots[hvalue];
- lock = &avc->avc_cache.slots_lock[hvalue];
+ if (!node)
+ return NULL;
- spin_lock_irqsave(lock, flag);
- hlist_for_each_entry(pos, head, list) {
- if (pos->ae.ssid == ssid &&
- pos->ae.tsid == tsid &&
- pos->ae.tclass == tclass) {
- avc_node_replace(avc, node, pos);
- goto found;
- }
+ avc_node_populate(node, ssid, tsid, tclass, avd);
+ if (avc_xperms_populate(node, xp_node)) {
+ avc_node_kill(avc, node);
+ return NULL;
+ }
+
+ hvalue = avc_hash(ssid, tsid, tclass);
+ head = &avc->avc_cache.slots[hvalue];
+ lock = &avc->avc_cache.slots_lock[hvalue];
+ spin_lock_irqsave(lock, flag);
+ hlist_for_each_entry(pos, head, list) {
+ if (pos->ae.ssid == ssid &&
+ pos->ae.tsid == tsid &&
+ pos->ae.tclass == tclass) {
+ avc_node_replace(avc, node, pos);
+ goto found;
}
- hlist_add_head_rcu(&node->list, head);
-found:
- spin_unlock_irqrestore(lock, flag);
}
-out:
+ hlist_add_head_rcu(&node->list, head);
+found:
+ spin_unlock_irqrestore(lock, flag);
return node;
}
^ permalink raw reply related
* Re: [RFC PATCH] selinux: ensure we cleanup the internal AVC counters on error in avc_insert()
From: Paul Moore @ 2019-12-10 1:54 UTC (permalink / raw)
To: selinux; +Cc: rsiddoji, Stephen Smalley, linux-security-module
In-Reply-To: <157594281322.676903.11041338053333686450.stgit@chester>
On Mon, Dec 9, 2019 at 8:53 PM Paul Moore <paul@paul-moore.com> wrote:
> In AVC insert we don't call avc_node_kill() when avc_xperms_populate()
> fails, resulting in the avc->avc_cache.active_nodes counter having a
> false value. This patch corrects this problem and does some cleanup
> in avc_insert() while we are there.
>
> Reported-by: rsiddoji@codeaurora.org
> Suggested-by: Stephen Smalley <sds@tycho.nsa.gov>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
> ---
> security/selinux/avc.c | 51 +++++++++++++++++++++++-------------------------
> 1 file changed, 24 insertions(+), 27 deletions(-)
FYI, only compiled tested, thus the RFC.
--
paul moore
www.paul-moore.com
^ permalink raw reply
* [RFC PATCH] security: add an interface to lookup the lockdown reason
From: Paul Moore @ 2019-12-10 2:28 UTC (permalink / raw)
To: selinux, linux-security-module; +Cc: linux-next, sds, jamorris
With CONFIG_AUDIT enabled but CONFIG_SECURITY disabled we run into
a problem where the lockdown reason table is missing. This patch
attempts to fix this by hiding the table behind a lookup function.
Signed-off-by: Paul Moore <paul@paul-moore.com>
---
include/linux/security.h | 7 +++++++
security/lsm_audit.c | 12 +++++++++---
security/security.c | 5 +++++
3 files changed, 21 insertions(+), 3 deletions(-)
diff --git a/include/linux/security.h b/include/linux/security.h
index 64b19f050343..295509a809d6 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -447,6 +447,8 @@ int security_inode_notifysecctx(struct inode *inode, void *ctx, u32 ctxlen);
int security_inode_setsecctx(struct dentry *dentry, void *ctx, u32 ctxlen);
int security_inode_getsecctx(struct inode *inode, void **ctx, u32 *ctxlen);
int security_locked_down(enum lockdown_reason what);
+const char *security_locked_reasonstr(enum lockdown_reason what);
+
#else /* CONFIG_SECURITY */
static inline int call_blocking_lsm_notifier(enum lsm_event event, void *data)
@@ -1274,6 +1276,11 @@ static inline int security_locked_down(enum lockdown_reason what)
{
return 0;
}
+
+static inline const char *security_locked_reasonstr(enum lockdown_reason what)
+{
+ return NULL;
+}
#endif /* CONFIG_SECURITY */
#ifdef CONFIG_SECURITY_NETWORK
diff --git a/security/lsm_audit.c b/security/lsm_audit.c
index 2d2bf49016f4..519ef6046638 100644
--- a/security/lsm_audit.c
+++ b/security/lsm_audit.c
@@ -426,10 +426,16 @@ static void dump_common_audit_data(struct audit_buffer *ab,
a->u.ibendport->dev_name,
a->u.ibendport->port);
break;
- case LSM_AUDIT_DATA_LOCKDOWN:
- audit_log_format(ab, " lockdown_reason=");
- audit_log_string(ab, lockdown_reasons[a->u.reason]);
+ case LSM_AUDIT_DATA_LOCKDOWN: {
+ const char *str = security_locked_reasonstr(a->u.reason);
+
+ if (str) {
+ audit_log_format(ab, " lockdown_reason=");
+ audit_log_string(ab, str);
+ } else
+ audit_log_format(ab, " lockdown_reason=?");
break;
+ }
} /* switch (a->type) */
}
diff --git a/security/security.c b/security/security.c
index 2b5473d92416..2f228fdbebf5 100644
--- a/security/security.c
+++ b/security/security.c
@@ -2438,6 +2438,11 @@ int security_locked_down(enum lockdown_reason what)
}
EXPORT_SYMBOL(security_locked_down);
+const char *security_locked_reasonstr(enum lockdown_reason what)
+{
+ return lockdown_reasons[what];
+}
+
#ifdef CONFIG_PERF_EVENTS
int security_perf_event_open(struct perf_event_attr *attr, int type)
{
^ permalink raw reply related
* Re: [RFC PATCH] security: add an interface to lookup the lockdown reason
From: James Morris @ 2019-12-10 5:39 UTC (permalink / raw)
To: Paul Moore; +Cc: selinux, linux-security-module, linux-next, sds, jamorris
In-Reply-To: <157594493094.748324.9234611948545428995.stgit@chester>
On Mon, 9 Dec 2019, Paul Moore wrote:
> With CONFIG_AUDIT enabled but CONFIG_SECURITY disabled we run into
> a problem where the lockdown reason table is missing. This patch
> attempts to fix this by hiding the table behind a lookup function.
>
> Signed-off-by: Paul Moore <paul@paul-moore.com>
Acked-by: James Morris <jamorris@linux.microsoft.com>
--
James Morris
<jmorris@namei.org>
^ permalink raw reply
* Re: [PATCH v2] tomoyo: Don't check open/getattr permission on sockets.
From: Tetsuo Handa @ 2019-12-10 10:21 UTC (permalink / raw)
To: James Morris
Cc: Andrew Morton, Stephen Rothwell, linux-security-module,
Linus Torvalds
In-Reply-To: <alpine.LRH.2.21.1912100837160.4379@namei.org>
On 2019/12/10 6:37, James Morris wrote:
> On Wed, 4 Dec 2019, Tetsuo Handa wrote:
>
>>
>> I decided to drop tomoyo_get_socket_name(). Will you pick up the following commit?
>>
>> commit c39593ab0500fcd6db290b311c120349927ddc04
>> Author: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
>> Date: Mon Nov 25 10:46:51 2019 +0900
>>
>> tomoyo: Don't use nifty names on sockets.
>>
>
>>From where?
>
> Please send a patch.
>
Patch is at https://scm.osdn.net/gitroot/tomoyo/tomoyo-test1 and was tested on linux-next.git .
But if you pick up c39593ab0500, what do I need to do (in order to avoid trying to apply the same
patch) ? Could you explain me (using command line) how I can send only c39593ab0500 to linux.git ?
https://osdn.net/projects/tomoyo/scm/git/tomoyo-test1/commits has only master branch.
c39593ab0500 (HEAD -> master, origin/master) tomoyo: Don't use nifty names on sockets.
cbf8353d474c Merge branch 'master' of https://scm.osdn.net/gitroot/tomoyo/tomoyo-test1
fd46afeac605 Revert "tomoyo: Don't check open/getattr permission on sockets."
19768fdc4025 Revert "printk: Monitor change of console loglevel."
07fca3f339d7 printk: Monitor change of console loglevel.
df8aec8cd8b2 tomoyo: Don't check open/getattr permission on sockets.
219d54332a09 (tag: v5.4, upstream/master) Linux 5.4
^ permalink raw reply
* Re: [PATCH] selinux: reorder hooks to make runtime disable less broken
From: Ondrej Mosnacek @ 2019-12-10 11:27 UTC (permalink / raw)
To: Casey Schaufler; +Cc: Stephen Smalley, SElinux list, Paul Moore, LSM
In-Reply-To: <2fadcd3d-96d2-82bf-f221-a7961853be50@schaufler-ca.com>
On Mon, Dec 9, 2019 at 6:20 PM Casey Schaufler <casey@schaufler-ca.com> wrote:
> On 12/9/2019 5:58 AM, Stephen Smalley wrote:
> > On 12/9/19 8:21 AM, Stephen Smalley wrote:
> >> On 12/9/19 2:57 AM, Ondrej Mosnacek wrote:
> >>> Commit b1d9e6b0646d ("LSM: Switch to lists of hooks") switched the LSM
> >>> infrastructure to use per-hook lists, which meant that removing the
> >>> hooks for a given module was no longer atomic. Even though the commit
> >>> clearly documents that modules implementing runtime revmoval of hooks
> >>> (only SELinux attempts this madness) need to take special precautions to
> >>> avoid race conditions, SELinux has never addressed this.
> >>>
> >>> By inserting an artificial delay between the loop iterations of
> >>> security_delete_hooks() (I used 100 ms), booting to a state where
> >>> SELinux is enabled, but policy is not yet loaded, and running these
> >>> commands:
> >>>
> >>> while true; do ping -c 1 <some IP>; done &
> >>> echo -n 1 >/sys/fs/selinux/disable
> >>> kill %1
> >>> wait
> >>>
> >>> ...I was able to trigger NULL pointer dereferences in various places. I
> >>> also have a report of someone getting panics on a stock RHEL-8 kernel
> >>> after setting SELINUX=disabled in /etc/selinux/config and rebooting
> >>> (without adding "selinux=0" to kernel command-line).
> >>>
> >>> Reordering the SELinux hooks such that those that allocate structures
> >>> are removed last seems to prevent these panics. It is very much possible
> >>> that this doesn't make the runtime disable completely race-free, but at
> >>> least it makes the operation much less fragile.
> >>>
> >>> An alternative (and safer) solution would be to add NULL checks to each
> >>> hook, but doing this just to support the runtime disable hack doesn't
> >>> seem to be worth the effort...
> >>
> >> Personally, I would prefer to just get rid of runtime disable altogether; it also precludes making the hooks read-only after initialization. IMHO, selinux=0 is the proper way to disable SELinux if necessary. I believe there is an open bugzilla on Fedora related to this issue, since runtime disable was originally introduced for Fedora.
> >
> > Also, if we have to retain this support, it seems like this ought to be fixed in the LSM framework especially since it was a change there that broke the SELinux implementation.
>
> Agreed, mostly. Deleting an LSM is fundamentally something the infrastructure
> should handle *if* we allow it. Should we decide at some point to allow loadable
> modules, as Tetsuo has advocated from time to time, we would need a general
> solution. We don't have a general solution now because only SELinux wants it.
> The previous implementation was under #ifdef for SELinux. At the time I understood
> that there was no interest in investing in it. The implementation passed tests
> at the time.
>
> I propose that until such time as someone decides to seriously investigate
> loadable security modules* the sole user of the deletion mechanism is
> welcome to invest whatever they like in their special case, and I will be
> happy to lend whatever assistance I can.
On my way to lunch I came up with another relatively simple solution
that should address this problem at the infrastructure level. Let me
try to write it up into a patch, hopefully it will work...
>
> ---
> * I do not plan to propose an implementation of loadable modules.
> I leave that as an exercise for the next generation.
>
>
--
Ondrej Mosnacek <omosnace at redhat dot com>
Software Engineer, Security Technologies
Red Hat, Inc.
^ permalink raw reply
* [PATCH v6 22/27] NFS: Do some tidying of the parsing code
From: Scott Mayhew @ 2019-12-10 12:31 UTC (permalink / raw)
To: anna.schumaker, trond.myklebust
Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel,
linux-security-module
In-Reply-To: <20191210123115.1655-1-smayhew@redhat.com>
From: David Howells <dhowells@redhat.com>
Do some tidying of the parsing code, including:
(*) Returning 0/error rather than true/false.
(*) Putting the nfs_fs_context pointer first in some arg lists.
(*) Unwrap some lines that will now fit on one line.
(*) Provide unioned sockaddr/sockaddr_storage fields to avoid casts.
(*) nfs_parse_devname() can paste its return values directly into the
nfs_fs_context struct as that's where the caller puts them.
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/nfs/fs_context.c | 126 +++++++++++++++++++-------------------------
fs/nfs/internal.h | 16 ++++--
fs/nfs/super.c | 2 +-
3 files changed, 66 insertions(+), 78 deletions(-)
diff --git a/fs/nfs/fs_context.c b/fs/nfs/fs_context.c
index 2921c5820c31..44531443a92b 100644
--- a/fs/nfs/fs_context.c
+++ b/fs/nfs/fs_context.c
@@ -343,8 +343,9 @@ static void nfs_set_mount_transport_protocol(struct nfs_fs_context *ctx)
* Add 'flavor' to 'auth_info' if not already present.
* Returns true if 'flavor' ends up in the list, false otherwise
*/
-static bool nfs_auth_info_add(struct nfs_auth_info *auth_info,
- rpc_authflavor_t flavor)
+static int nfs_auth_info_add(struct nfs_fs_context *ctx,
+ struct nfs_auth_info *auth_info,
+ rpc_authflavor_t flavor)
{
unsigned int i;
unsigned int max_flavor_len = ARRAY_SIZE(auth_info->flavors);
@@ -352,26 +353,27 @@ static bool nfs_auth_info_add(struct nfs_auth_info *auth_info,
/* make sure this flavor isn't already in the list */
for (i = 0; i < auth_info->flavor_len; i++) {
if (flavor == auth_info->flavors[i])
- return true;
+ return 0;
}
if (auth_info->flavor_len + 1 >= max_flavor_len) {
dfprintk(MOUNT, "NFS: too many sec= flavors\n");
- return false;
+ return -EINVAL;
}
auth_info->flavors[auth_info->flavor_len++] = flavor;
- return true;
+ return 0;
}
/*
* Parse the value of the 'sec=' option.
*/
-static int nfs_parse_security_flavors(char *value, struct nfs_fs_context *ctx)
+static int nfs_parse_security_flavors(struct nfs_fs_context *ctx, char *value)
{
substring_t args[MAX_OPT_ARGS];
rpc_authflavor_t pseudoflavor;
char *p;
+ int ret;
dfprintk(MOUNT, "NFS: parsing sec=%s option\n", value);
@@ -413,19 +415,20 @@ static int nfs_parse_security_flavors(char *value, struct nfs_fs_context *ctx)
default:
dfprintk(MOUNT,
"NFS: sec= option '%s' not recognized\n", p);
- return 0;
+ return -EINVAL;
}
- if (!nfs_auth_info_add(&ctx->auth_info, pseudoflavor))
- return 0;
+ ret = nfs_auth_info_add(ctx, &ctx->auth_info, pseudoflavor);
+ if (ret < 0)
+ return ret;
}
- return 1;
+ return 0;
}
-static int nfs_parse_version_string(char *string,
- struct nfs_fs_context *ctx,
- substring_t *args)
+static int nfs_parse_version_string(struct nfs_fs_context *ctx,
+ char *string,
+ substring_t *args)
{
ctx->flags &= ~NFS_MOUNT_VER3;
switch (match_token(string, nfs_vers_tokens, args)) {
@@ -456,9 +459,10 @@ static int nfs_parse_version_string(char *string,
ctx->minorversion = 2;
break;
default:
- return 0;
+ dfprintk(MOUNT, "NFS: Unsupported NFS version\n");
+ return -EINVAL;
}
- return 1;
+ return 0;
}
static int nfs_get_option_str(substring_t args[], char **option)
@@ -513,7 +517,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
{
substring_t args[MAX_OPT_ARGS];
char *string;
- int token, rc;
+ int token, ret;
dfprintk(MOUNT, "NFS: parsing nfs mount option '%s'\n", p);
@@ -553,13 +557,11 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
break;
case Opt_lock:
ctx->flags &= ~NFS_MOUNT_NONLM;
- ctx->flags &= ~(NFS_MOUNT_LOCAL_FLOCK |
- NFS_MOUNT_LOCAL_FCNTL);
+ ctx->flags &= ~(NFS_MOUNT_LOCAL_FLOCK | NFS_MOUNT_LOCAL_FCNTL);
break;
case Opt_nolock:
ctx->flags |= NFS_MOUNT_NONLM;
- ctx->flags |= (NFS_MOUNT_LOCAL_FLOCK |
- NFS_MOUNT_LOCAL_FCNTL);
+ ctx->flags |= (NFS_MOUNT_LOCAL_FLOCK | NFS_MOUNT_LOCAL_FCNTL);
break;
case Opt_udp:
ctx->flags &= ~NFS_MOUNT_TCP;
@@ -692,29 +694,25 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
string = match_strdup(args);
if (string == NULL)
goto out_nomem;
- rc = nfs_parse_version_string(string, ctx, args);
+ ret = nfs_parse_version_string(ctx, string, args);
kfree(string);
- if (!rc)
- goto out_invalid_value;
+ if (ret < 0)
+ return ret;
break;
case Opt_sec:
string = match_strdup(args);
if (string == NULL)
goto out_nomem;
- rc = nfs_parse_security_flavors(string, ctx);
+ ret = nfs_parse_security_flavors(ctx, string);
kfree(string);
- if (!rc) {
- dfprintk(MOUNT, "NFS: unrecognized "
- "security flavor\n");
- return -EINVAL;
- }
+ if (ret < 0)
+ return ret;
break;
case Opt_proto:
string = match_strdup(args);
if (string == NULL)
goto out_nomem;
- token = match_token(string,
- nfs_xprt_protocol_tokens, args);
+ token = match_token(string, nfs_xprt_protocol_tokens, args);
ctx->protofamily = AF_INET;
switch (token) {
@@ -742,9 +740,8 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
xprt_load_transport(string);
break;
default:
- dfprintk(MOUNT, "NFS: unrecognized "
- "transport protocol\n");
kfree(string);
+ dfprintk(MOUNT, "NFS: unrecognized transport protocol\n");
return -EINVAL;
}
kfree(string);
@@ -753,8 +750,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
string = match_strdup(args);
if (string == NULL)
goto out_nomem;
- token = match_token(string,
- nfs_xprt_protocol_tokens, args);
+ token = match_token(string, nfs_xprt_protocol_tokens, args);
kfree(string);
ctx->mountfamily = AF_INET;
@@ -773,8 +769,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
break;
case Opt_xprt_rdma: /* not used for side protocols */
default:
- dfprintk(MOUNT, "NFS: unrecognized "
- "transport protocol\n");
+ dfprintk(MOUNT, "NFS: unrecognized transport protocol\n");
return -EINVAL;
}
break;
@@ -784,9 +779,8 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
goto out_nomem;
ctx->nfs_server.addrlen =
rpc_pton(ctx->net, string, strlen(string),
- (struct sockaddr *)
&ctx->nfs_server.address,
- sizeof(ctx->nfs_server.address));
+ sizeof(ctx->nfs_server._address));
kfree(string);
if (ctx->nfs_server.addrlen == 0)
goto out_invalid_address;
@@ -796,8 +790,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
goto out_nomem;
break;
case Opt_mounthost:
- if (nfs_get_option_str(args,
- &ctx->mount_server.hostname))
+ if (nfs_get_option_str(args, &ctx->mount_server.hostname))
goto out_nomem;
break;
case Opt_mountaddr:
@@ -806,9 +799,8 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
goto out_nomem;
ctx->mount_server.addrlen =
rpc_pton(ctx->net, string, strlen(string),
- (struct sockaddr *)
&ctx->mount_server.address,
- sizeof(ctx->mount_server.address));
+ sizeof(ctx->mount_server._address));
kfree(string);
if (ctx->mount_server.addrlen == 0)
goto out_invalid_address;
@@ -822,8 +814,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
string = match_strdup(args);
if (string == NULL)
goto out_nomem;
- token = match_token(string,
- nfs_lookupcache_tokens, args);
+ token = match_token(string, nfs_lookupcache_tokens, args);
kfree(string);
switch (token) {
case Opt_lookupcache_all:
@@ -837,8 +828,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
ctx->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE;
break;
default:
- dfprintk(MOUNT, "NFS: invalid "
- "lookupcache argument\n");
+ dfprintk(MOUNT, "NFS: invalid lookupcache argument\n");
return -EINVAL;
}
break;
@@ -851,8 +841,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
string = match_strdup(args);
if (string == NULL)
goto out_nomem;
- token = match_token(string, nfs_local_lock_tokens,
- args);
+ token = match_token(string, nfs_local_lock_tokens, args);
kfree(string);
switch (token) {
case Opt_local_lock_all:
@@ -870,8 +859,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
NFS_MOUNT_LOCAL_FCNTL);
break;
default:
- dfprintk(MOUNT, "NFS: invalid "
- "local_lock argument\n");
+ dfprintk(MOUNT, "NFS: invalid local_lock argument\n");
return -EINVAL;
}
break;
@@ -885,13 +873,11 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
break;
case Opt_userspace:
case Opt_deprecated:
- dfprintk(MOUNT, "NFS: ignoring mount option "
- "'%s'\n", p);
+ dfprintk(MOUNT, "NFS: ignoring mount option '%s'\n", p);
break;
default:
- dfprintk(MOUNT, "NFS: unrecognized mount option "
- "'%s'\n", p);
+ dfprintk(MOUNT, "NFS: unrecognized mount option '%s'\n", p);
return -EINVAL;
}
@@ -951,15 +937,15 @@ int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx)
* families in the addr=/mountaddr= options.
*/
if (ctx->protofamily != AF_UNSPEC &&
- ctx->protofamily != ctx->nfs_server.address.ss_family)
+ ctx->protofamily != ctx->nfs_server.address.sa_family)
goto out_proto_mismatch;
if (ctx->mountfamily != AF_UNSPEC) {
if (ctx->mount_server.addrlen) {
- if (ctx->mountfamily != ctx->mount_server.address.ss_family)
+ if (ctx->mountfamily != ctx->mount_server.address.sa_family)
goto out_mountproto_mismatch;
} else {
- if (ctx->mountfamily != ctx->nfs_server.address.ss_family)
+ if (ctx->mountfamily != ctx->nfs_server.address.sa_family)
goto out_mountproto_mismatch;
}
}
@@ -995,9 +981,9 @@ int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx)
*
* Note: caller frees hostname and export path, even on error.
*/
-static int nfs_parse_devname(const char *dev_name,
- char **hostname, size_t maxnamlen,
- char **export_path, size_t maxpathlen)
+static int nfs_parse_devname(struct nfs_fs_context *ctx,
+ const char *dev_name,
+ size_t maxnamlen, size_t maxpathlen)
{
size_t len;
char *end;
@@ -1033,17 +1019,17 @@ static int nfs_parse_devname(const char *dev_name,
goto out_hostname;
/* N.B. caller will free nfs_server.hostname in all cases */
- *hostname = kstrndup(dev_name, len, GFP_KERNEL);
- if (*hostname == NULL)
+ ctx->nfs_server.hostname = kmemdup_nul(dev_name, len, GFP_KERNEL);
+ if (!ctx->nfs_server.hostname)
goto out_nomem;
len = strlen(++end);
if (len > maxpathlen)
goto out_path;
- *export_path = kstrndup(end, len, GFP_KERNEL);
- if (!*export_path)
+ ctx->nfs_server.export_path = kmemdup_nul(end, len, GFP_KERNEL);
+ if (!ctx->nfs_server.export_path)
goto out_nomem;
- dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", *export_path);
+ dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", ctx->nfs_server.export_path);
return 0;
out_bad_devname:
@@ -1064,7 +1050,7 @@ static int nfs_parse_devname(const char *dev_name,
}
/*
- * Validate the NFS2/NFS3 mount data
+ * Parse monolithic NFS2/NFS3 mount data
* - fills in the mount root filehandle
*
* For option strings, user space handles the following behaviors:
@@ -1393,11 +1379,7 @@ int nfs_validate_text_mount_data(void *options,
nfs_set_port(sap, &ctx->nfs_server.port, port);
- return nfs_parse_devname(dev_name,
- &ctx->nfs_server.hostname,
- max_namelen,
- &ctx->nfs_server.export_path,
- max_pathlen);
+ return nfs_parse_devname(ctx, dev_name, max_namelen, max_pathlen);
#if !IS_ENABLED(CONFIG_NFS_V4)
out_v4_not_compiled:
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 5342f3e4d565..003c2b8eb1e6 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -82,11 +82,11 @@ struct nfs_client_initdata {
* In-kernel mount arguments
*/
struct nfs_fs_context {
- int flags;
+ unsigned int flags; /* NFS{,4}_MOUNT_* flags */
unsigned int rsize, wsize;
unsigned int timeo, retrans;
- unsigned int acregmin, acregmax,
- acdirmin, acdirmax;
+ unsigned int acregmin, acregmax;
+ unsigned int acdirmin, acdirmax;
unsigned int namlen;
unsigned int options;
unsigned int bsize;
@@ -102,7 +102,10 @@ struct nfs_fs_context {
bool sloppy;
struct {
- struct sockaddr_storage address;
+ union {
+ struct sockaddr address;
+ struct sockaddr_storage _address;
+ };
size_t addrlen;
char *hostname;
u32 version;
@@ -111,7 +114,10 @@ struct nfs_fs_context {
} mount_server;
struct {
- struct sockaddr_storage address;
+ union {
+ struct sockaddr address;
+ struct sockaddr_storage _address;
+ };
size_t addrlen;
char *hostname;
char *export_path;
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 83527515590e..59962bc0118f 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -816,7 +816,7 @@ static int nfs_request_mount(struct nfs_fs_context *cfg,
/*
* Construct the mount server's address.
*/
- if (cfg->mount_server.address.ss_family == AF_UNSPEC) {
+ if (cfg->mount_server.address.sa_family == AF_UNSPEC) {
memcpy(request.sap, &cfg->nfs_server.address,
cfg->nfs_server.addrlen);
cfg->mount_server.addrlen = cfg->nfs_server.addrlen;
--
2.17.2
^ permalink raw reply related
* [PATCH v6 01/27] saner calling conventions for nfs_fs_mount_common()
From: Scott Mayhew @ 2019-12-10 12:30 UTC (permalink / raw)
To: anna.schumaker, trond.myklebust
Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel,
linux-security-module
In-Reply-To: <20191210123115.1655-1-smayhew@redhat.com>
From: Al Viro <viro@zeniv.linux.org.uk>
Allow it to take ERR_PTR() for server and return ERR_CAST() of it in
such case. All callers used to open-code that...
Reviewed-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/nfs/nfs4super.c | 16 +---------------
fs/nfs/super.c | 11 ++++-------
2 files changed, 5 insertions(+), 22 deletions(-)
diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c
index 2c9cbade561a..beeaed872e6c 100644
--- a/fs/nfs/nfs4super.c
+++ b/fs/nfs/nfs4super.c
@@ -110,21 +110,12 @@ nfs4_remote_mount(struct file_system_type *fs_type, int flags,
{
struct nfs_mount_info *mount_info = info;
struct nfs_server *server;
- struct dentry *mntroot = ERR_PTR(-ENOMEM);
mount_info->set_security = nfs_set_sb_security;
/* Get a volume representation */
server = nfs4_create_server(mount_info, &nfs_v4);
- if (IS_ERR(server)) {
- mntroot = ERR_CAST(server);
- goto out;
- }
-
- mntroot = nfs_fs_mount_common(server, flags, dev_name, mount_info, &nfs_v4);
-
-out:
- return mntroot;
+ return nfs_fs_mount_common(server, flags, dev_name, mount_info, &nfs_v4);
}
static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type,
@@ -280,11 +271,6 @@ nfs4_remote_referral_mount(struct file_system_type *fs_type, int flags,
/* create a new volume representation */
server = nfs4_create_referral_server(mount_info.cloned, mount_info.mntfh);
- if (IS_ERR(server)) {
- mntroot = ERR_CAST(server);
- goto out;
- }
-
mntroot = nfs_fs_mount_common(server, flags, dev_name, &mount_info, &nfs_v4);
out:
nfs_free_fhandle(mount_info.mntfh);
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 8d8d04bb9d64..f074c3773f0e 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -1903,9 +1903,6 @@ struct dentry *nfs_try_mount(int flags, const char *dev_name,
else
server = nfs_mod->rpc_ops->create_server(mount_info, nfs_mod);
- if (IS_ERR(server))
- return ERR_CAST(server);
-
return nfs_fs_mount_common(server, flags, dev_name, mount_info, nfs_mod);
}
EXPORT_SYMBOL_GPL(nfs_try_mount);
@@ -2666,6 +2663,9 @@ struct dentry *nfs_fs_mount_common(struct nfs_server *server,
};
int error;
+ if (IS_ERR(server))
+ return ERR_CAST(server);
+
if (server->flags & NFS_MOUNT_UNSHARED)
compare_super = NULL;
@@ -2814,10 +2814,7 @@ nfs_xdev_mount(struct file_system_type *fs_type, int flags,
/* create a new volume representation */
server = nfs_mod->rpc_ops->clone_server(NFS_SB(data->sb), data->fh, data->fattr, data->authflavor);
- if (IS_ERR(server))
- mntroot = ERR_CAST(server);
- else
- mntroot = nfs_fs_mount_common(server, flags,
+ mntroot = nfs_fs_mount_common(server, flags,
dev_name, &mount_info, nfs_mod);
dprintk("<-- nfs_xdev_mount() = %ld\n",
--
2.17.2
^ permalink raw reply related
* [PATCH v6 16/27] NFS: Move mount parameterisation bits into their own file
From: Scott Mayhew @ 2019-12-10 12:31 UTC (permalink / raw)
To: anna.schumaker, trond.myklebust
Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel,
linux-security-module
In-Reply-To: <20191210123115.1655-1-smayhew@redhat.com>
From: David Howells <dhowells@redhat.com>
Split various bits relating to mount parameterisation out from
fs/nfs/super.c into their own file to form the basis of filesystem context
handling for NFS.
No other changes are made to the code beyond removing 'static' qualifiers.
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/nfs/Makefile | 2 +-
fs/nfs/fs_context.c | 1414 +++++++++++++++++++++++++++++++++++++++++++
fs/nfs/internal.h | 30 +
fs/nfs/super.c | 1411 ------------------------------------------
4 files changed, 1445 insertions(+), 1412 deletions(-)
create mode 100644 fs/nfs/fs_context.c
diff --git a/fs/nfs/Makefile b/fs/nfs/Makefile
index 34cdeaecccf6..2433c3e03cfa 100644
--- a/fs/nfs/Makefile
+++ b/fs/nfs/Makefile
@@ -9,7 +9,7 @@ CFLAGS_nfstrace.o += -I$(src)
nfs-y := client.o dir.o file.o getroot.o inode.o super.o \
io.o direct.o pagelist.o read.o symlink.o unlink.o \
write.o namespace.o mount_clnt.o nfstrace.o \
- export.o sysfs.o
+ export.o sysfs.o fs_context.o
nfs-$(CONFIG_ROOT_NFS) += nfsroot.o
nfs-$(CONFIG_SYSCTL) += sysctl.o
nfs-$(CONFIG_NFS_FSCACHE) += fscache.o fscache-index.o
diff --git a/fs/nfs/fs_context.c b/fs/nfs/fs_context.c
new file mode 100644
index 000000000000..c8f99a3c7264
--- /dev/null
+++ b/fs/nfs/fs_context.c
@@ -0,0 +1,1414 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * linux/fs/nfs/fs_context.c
+ *
+ * Copyright (C) 1992 Rick Sladkey
+ *
+ * NFS mount handling.
+ *
+ * Split from fs/nfs/super.c by David Howells <dhowells@redhat.com>
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/parser.h>
+#include <linux/nfs_fs.h>
+#include <linux/nfs_mount.h>
+#include <linux/nfs4_mount.h>
+#include "nfs.h"
+#include "internal.h"
+
+#define NFSDBG_FACILITY NFSDBG_MOUNT
+
+#if IS_ENABLED(CONFIG_NFS_V3)
+#define NFS_DEFAULT_VERSION 3
+#else
+#define NFS_DEFAULT_VERSION 2
+#endif
+
+#define NFS_MAX_CONNECTIONS 16
+
+enum {
+ /* Mount options that take no arguments */
+ Opt_soft, Opt_softerr, Opt_hard,
+ Opt_posix, Opt_noposix,
+ Opt_cto, Opt_nocto,
+ Opt_ac, Opt_noac,
+ Opt_lock, Opt_nolock,
+ Opt_udp, Opt_tcp, Opt_rdma,
+ Opt_acl, Opt_noacl,
+ Opt_rdirplus, Opt_nordirplus,
+ Opt_sharecache, Opt_nosharecache,
+ Opt_resvport, Opt_noresvport,
+ Opt_fscache, Opt_nofscache,
+ Opt_migration, Opt_nomigration,
+
+ /* Mount options that take integer arguments */
+ Opt_port,
+ Opt_rsize, Opt_wsize, Opt_bsize,
+ Opt_timeo, Opt_retrans,
+ Opt_acregmin, Opt_acregmax,
+ Opt_acdirmin, Opt_acdirmax,
+ Opt_actimeo,
+ Opt_namelen,
+ Opt_mountport,
+ Opt_mountvers,
+ Opt_minorversion,
+
+ /* Mount options that take string arguments */
+ Opt_nfsvers,
+ Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost,
+ Opt_addr, Opt_mountaddr, Opt_clientaddr,
+ Opt_nconnect,
+ Opt_lookupcache,
+ Opt_fscache_uniq,
+ Opt_local_lock,
+
+ /* Special mount options */
+ Opt_userspace, Opt_deprecated, Opt_sloppy,
+
+ Opt_err
+};
+
+static const match_table_t nfs_mount_option_tokens = {
+ { Opt_userspace, "bg" },
+ { Opt_userspace, "fg" },
+ { Opt_userspace, "retry=%s" },
+
+ { Opt_sloppy, "sloppy" },
+
+ { Opt_soft, "soft" },
+ { Opt_softerr, "softerr" },
+ { Opt_hard, "hard" },
+ { Opt_deprecated, "intr" },
+ { Opt_deprecated, "nointr" },
+ { Opt_posix, "posix" },
+ { Opt_noposix, "noposix" },
+ { Opt_cto, "cto" },
+ { Opt_nocto, "nocto" },
+ { Opt_ac, "ac" },
+ { Opt_noac, "noac" },
+ { Opt_lock, "lock" },
+ { Opt_nolock, "nolock" },
+ { Opt_udp, "udp" },
+ { Opt_tcp, "tcp" },
+ { Opt_rdma, "rdma" },
+ { Opt_acl, "acl" },
+ { Opt_noacl, "noacl" },
+ { Opt_rdirplus, "rdirplus" },
+ { Opt_nordirplus, "nordirplus" },
+ { Opt_sharecache, "sharecache" },
+ { Opt_nosharecache, "nosharecache" },
+ { Opt_resvport, "resvport" },
+ { Opt_noresvport, "noresvport" },
+ { Opt_fscache, "fsc" },
+ { Opt_nofscache, "nofsc" },
+ { Opt_migration, "migration" },
+ { Opt_nomigration, "nomigration" },
+
+ { Opt_port, "port=%s" },
+ { Opt_rsize, "rsize=%s" },
+ { Opt_wsize, "wsize=%s" },
+ { Opt_bsize, "bsize=%s" },
+ { Opt_timeo, "timeo=%s" },
+ { Opt_retrans, "retrans=%s" },
+ { Opt_acregmin, "acregmin=%s" },
+ { Opt_acregmax, "acregmax=%s" },
+ { Opt_acdirmin, "acdirmin=%s" },
+ { Opt_acdirmax, "acdirmax=%s" },
+ { Opt_actimeo, "actimeo=%s" },
+ { Opt_namelen, "namlen=%s" },
+ { Opt_mountport, "mountport=%s" },
+ { Opt_mountvers, "mountvers=%s" },
+ { Opt_minorversion, "minorversion=%s" },
+
+ { Opt_nfsvers, "nfsvers=%s" },
+ { Opt_nfsvers, "vers=%s" },
+
+ { Opt_sec, "sec=%s" },
+ { Opt_proto, "proto=%s" },
+ { Opt_mountproto, "mountproto=%s" },
+ { Opt_addr, "addr=%s" },
+ { Opt_clientaddr, "clientaddr=%s" },
+ { Opt_mounthost, "mounthost=%s" },
+ { Opt_mountaddr, "mountaddr=%s" },
+
+ { Opt_nconnect, "nconnect=%s" },
+
+ { Opt_lookupcache, "lookupcache=%s" },
+ { Opt_fscache_uniq, "fsc=%s" },
+ { Opt_local_lock, "local_lock=%s" },
+
+ /* The following needs to be listed after all other options */
+ { Opt_nfsvers, "v%s" },
+
+ { Opt_err, NULL }
+};
+
+enum {
+ Opt_xprt_udp, Opt_xprt_udp6, Opt_xprt_tcp, Opt_xprt_tcp6, Opt_xprt_rdma,
+ Opt_xprt_rdma6,
+
+ Opt_xprt_err
+};
+
+static const match_table_t nfs_xprt_protocol_tokens = {
+ { Opt_xprt_udp, "udp" },
+ { Opt_xprt_udp6, "udp6" },
+ { Opt_xprt_tcp, "tcp" },
+ { Opt_xprt_tcp6, "tcp6" },
+ { Opt_xprt_rdma, "rdma" },
+ { Opt_xprt_rdma6, "rdma6" },
+
+ { Opt_xprt_err, NULL }
+};
+
+enum {
+ Opt_sec_none, Opt_sec_sys,
+ Opt_sec_krb5, Opt_sec_krb5i, Opt_sec_krb5p,
+ Opt_sec_lkey, Opt_sec_lkeyi, Opt_sec_lkeyp,
+ Opt_sec_spkm, Opt_sec_spkmi, Opt_sec_spkmp,
+
+ Opt_sec_err
+};
+
+static const match_table_t nfs_secflavor_tokens = {
+ { Opt_sec_none, "none" },
+ { Opt_sec_none, "null" },
+ { Opt_sec_sys, "sys" },
+
+ { Opt_sec_krb5, "krb5" },
+ { Opt_sec_krb5i, "krb5i" },
+ { Opt_sec_krb5p, "krb5p" },
+
+ { Opt_sec_lkey, "lkey" },
+ { Opt_sec_lkeyi, "lkeyi" },
+ { Opt_sec_lkeyp, "lkeyp" },
+
+ { Opt_sec_spkm, "spkm3" },
+ { Opt_sec_spkmi, "spkm3i" },
+ { Opt_sec_spkmp, "spkm3p" },
+
+ { Opt_sec_err, NULL }
+};
+
+enum {
+ Opt_lookupcache_all, Opt_lookupcache_positive,
+ Opt_lookupcache_none,
+
+ Opt_lookupcache_err
+};
+
+static match_table_t nfs_lookupcache_tokens = {
+ { Opt_lookupcache_all, "all" },
+ { Opt_lookupcache_positive, "pos" },
+ { Opt_lookupcache_positive, "positive" },
+ { Opt_lookupcache_none, "none" },
+
+ { Opt_lookupcache_err, NULL }
+};
+
+enum {
+ Opt_local_lock_all, Opt_local_lock_flock, Opt_local_lock_posix,
+ Opt_local_lock_none,
+
+ Opt_local_lock_err
+};
+
+static match_table_t nfs_local_lock_tokens = {
+ { Opt_local_lock_all, "all" },
+ { Opt_local_lock_flock, "flock" },
+ { Opt_local_lock_posix, "posix" },
+ { Opt_local_lock_none, "none" },
+
+ { Opt_local_lock_err, NULL }
+};
+
+enum {
+ Opt_vers_2, Opt_vers_3, Opt_vers_4, Opt_vers_4_0,
+ Opt_vers_4_1, Opt_vers_4_2,
+
+ Opt_vers_err
+};
+
+static match_table_t nfs_vers_tokens = {
+ { Opt_vers_2, "2" },
+ { Opt_vers_3, "3" },
+ { Opt_vers_4, "4" },
+ { Opt_vers_4_0, "4.0" },
+ { Opt_vers_4_1, "4.1" },
+ { Opt_vers_4_2, "4.2" },
+
+ { Opt_vers_err, NULL }
+};
+
+struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(void)
+{
+ struct nfs_parsed_mount_data *data;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (data) {
+ data->timeo = NFS_UNSPEC_TIMEO;
+ data->retrans = NFS_UNSPEC_RETRANS;
+ data->acregmin = NFS_DEF_ACREGMIN;
+ data->acregmax = NFS_DEF_ACREGMAX;
+ data->acdirmin = NFS_DEF_ACDIRMIN;
+ data->acdirmax = NFS_DEF_ACDIRMAX;
+ data->mount_server.port = NFS_UNSPEC_PORT;
+ data->nfs_server.port = NFS_UNSPEC_PORT;
+ data->nfs_server.protocol = XPRT_TRANSPORT_TCP;
+ data->selected_flavor = RPC_AUTH_MAXFLAVOR;
+ data->minorversion = 0;
+ data->need_mount = true;
+ data->net = current->nsproxy->net_ns;
+ data->lsm_opts = NULL;
+ }
+ return data;
+}
+
+void nfs_free_parsed_mount_data(struct nfs_parsed_mount_data *data)
+{
+ if (data) {
+ kfree(data->client_address);
+ kfree(data->mount_server.hostname);
+ kfree(data->nfs_server.export_path);
+ kfree(data->nfs_server.hostname);
+ kfree(data->fscache_uniq);
+ security_free_mnt_opts(&data->lsm_opts);
+ kfree(data);
+ }
+}
+
+/*
+ * Sanity-check a server address provided by the mount command.
+ *
+ * Address family must be initialized, and address must not be
+ * the ANY address for that family.
+ */
+static int nfs_verify_server_address(struct sockaddr *addr)
+{
+ switch (addr->sa_family) {
+ case AF_INET: {
+ struct sockaddr_in *sa = (struct sockaddr_in *)addr;
+ return sa->sin_addr.s_addr != htonl(INADDR_ANY);
+ }
+ case AF_INET6: {
+ struct in6_addr *sa = &((struct sockaddr_in6 *)addr)->sin6_addr;
+ return !ipv6_addr_any(sa);
+ }
+ }
+
+ dfprintk(MOUNT, "NFS: Invalid IP address specified\n");
+ return 0;
+}
+
+/*
+ * Sanity check the NFS transport protocol.
+ *
+ */
+static void nfs_validate_transport_protocol(struct nfs_parsed_mount_data *mnt)
+{
+ switch (mnt->nfs_server.protocol) {
+ case XPRT_TRANSPORT_UDP:
+ case XPRT_TRANSPORT_TCP:
+ case XPRT_TRANSPORT_RDMA:
+ break;
+ default:
+ mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
+ }
+}
+
+/*
+ * For text based NFSv2/v3 mounts, the mount protocol transport default
+ * settings should depend upon the specified NFS transport.
+ */
+static void nfs_set_mount_transport_protocol(struct nfs_parsed_mount_data *mnt)
+{
+ nfs_validate_transport_protocol(mnt);
+
+ if (mnt->mount_server.protocol == XPRT_TRANSPORT_UDP ||
+ mnt->mount_server.protocol == XPRT_TRANSPORT_TCP)
+ return;
+ switch (mnt->nfs_server.protocol) {
+ case XPRT_TRANSPORT_UDP:
+ mnt->mount_server.protocol = XPRT_TRANSPORT_UDP;
+ break;
+ case XPRT_TRANSPORT_TCP:
+ case XPRT_TRANSPORT_RDMA:
+ mnt->mount_server.protocol = XPRT_TRANSPORT_TCP;
+ }
+}
+
+/*
+ * Add 'flavor' to 'auth_info' if not already present.
+ * Returns true if 'flavor' ends up in the list, false otherwise
+ */
+static bool nfs_auth_info_add(struct nfs_auth_info *auth_info,
+ rpc_authflavor_t flavor)
+{
+ unsigned int i;
+ unsigned int max_flavor_len = ARRAY_SIZE(auth_info->flavors);
+
+ /* make sure this flavor isn't already in the list */
+ for (i = 0; i < auth_info->flavor_len; i++) {
+ if (flavor == auth_info->flavors[i])
+ return true;
+ }
+
+ if (auth_info->flavor_len + 1 >= max_flavor_len) {
+ dfprintk(MOUNT, "NFS: too many sec= flavors\n");
+ return false;
+ }
+
+ auth_info->flavors[auth_info->flavor_len++] = flavor;
+ return true;
+}
+
+/*
+ * Parse the value of the 'sec=' option.
+ */
+static int nfs_parse_security_flavors(char *value,
+ struct nfs_parsed_mount_data *mnt)
+{
+ substring_t args[MAX_OPT_ARGS];
+ rpc_authflavor_t pseudoflavor;
+ char *p;
+
+ dfprintk(MOUNT, "NFS: parsing sec=%s option\n", value);
+
+ while ((p = strsep(&value, ":")) != NULL) {
+ switch (match_token(p, nfs_secflavor_tokens, args)) {
+ case Opt_sec_none:
+ pseudoflavor = RPC_AUTH_NULL;
+ break;
+ case Opt_sec_sys:
+ pseudoflavor = RPC_AUTH_UNIX;
+ break;
+ case Opt_sec_krb5:
+ pseudoflavor = RPC_AUTH_GSS_KRB5;
+ break;
+ case Opt_sec_krb5i:
+ pseudoflavor = RPC_AUTH_GSS_KRB5I;
+ break;
+ case Opt_sec_krb5p:
+ pseudoflavor = RPC_AUTH_GSS_KRB5P;
+ break;
+ case Opt_sec_lkey:
+ pseudoflavor = RPC_AUTH_GSS_LKEY;
+ break;
+ case Opt_sec_lkeyi:
+ pseudoflavor = RPC_AUTH_GSS_LKEYI;
+ break;
+ case Opt_sec_lkeyp:
+ pseudoflavor = RPC_AUTH_GSS_LKEYP;
+ break;
+ case Opt_sec_spkm:
+ pseudoflavor = RPC_AUTH_GSS_SPKM;
+ break;
+ case Opt_sec_spkmi:
+ pseudoflavor = RPC_AUTH_GSS_SPKMI;
+ break;
+ case Opt_sec_spkmp:
+ pseudoflavor = RPC_AUTH_GSS_SPKMP;
+ break;
+ default:
+ dfprintk(MOUNT,
+ "NFS: sec= option '%s' not recognized\n", p);
+ return 0;
+ }
+
+ if (!nfs_auth_info_add(&mnt->auth_info, pseudoflavor))
+ return 0;
+ }
+
+ return 1;
+}
+
+static int nfs_parse_version_string(char *string,
+ struct nfs_parsed_mount_data *mnt,
+ substring_t *args)
+{
+ mnt->flags &= ~NFS_MOUNT_VER3;
+ switch (match_token(string, nfs_vers_tokens, args)) {
+ case Opt_vers_2:
+ mnt->version = 2;
+ break;
+ case Opt_vers_3:
+ mnt->flags |= NFS_MOUNT_VER3;
+ mnt->version = 3;
+ break;
+ case Opt_vers_4:
+ /* Backward compatibility option. In future,
+ * the mount program should always supply
+ * a NFSv4 minor version number.
+ */
+ mnt->version = 4;
+ break;
+ case Opt_vers_4_0:
+ mnt->version = 4;
+ mnt->minorversion = 0;
+ break;
+ case Opt_vers_4_1:
+ mnt->version = 4;
+ mnt->minorversion = 1;
+ break;
+ case Opt_vers_4_2:
+ mnt->version = 4;
+ mnt->minorversion = 2;
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
+
+static int nfs_get_option_str(substring_t args[], char **option)
+{
+ kfree(*option);
+ *option = match_strdup(args);
+ return !*option;
+}
+
+static int nfs_get_option_ul(substring_t args[], unsigned long *option)
+{
+ int rc;
+ char *string;
+
+ string = match_strdup(args);
+ if (string == NULL)
+ return -ENOMEM;
+ rc = kstrtoul(string, 10, option);
+ kfree(string);
+
+ return rc;
+}
+
+static int nfs_get_option_ul_bound(substring_t args[], unsigned long *option,
+ unsigned long l_bound, unsigned long u_bound)
+{
+ int ret;
+
+ ret = nfs_get_option_ul(args, option);
+ if (ret != 0)
+ return ret;
+ if (*option < l_bound || *option > u_bound)
+ return -ERANGE;
+ return 0;
+}
+
+/*
+ * Error-check and convert a string of mount options from user space into
+ * a data structure. The whole mount string is processed; bad options are
+ * skipped as they are encountered. If there were no errors, return 1;
+ * otherwise return 0 (zero).
+ */
+int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
+{
+ char *p, *string;
+ int rc, sloppy = 0, invalid_option = 0;
+ unsigned short protofamily = AF_UNSPEC;
+ unsigned short mountfamily = AF_UNSPEC;
+
+ if (!raw) {
+ dfprintk(MOUNT, "NFS: mount options string was NULL.\n");
+ return 1;
+ }
+ dfprintk(MOUNT, "NFS: nfs mount opts='%s'\n", raw);
+
+ rc = security_sb_eat_lsm_opts(raw, &mnt->lsm_opts);
+ if (rc)
+ goto out_security_failure;
+
+ while ((p = strsep(&raw, ",")) != NULL) {
+ substring_t args[MAX_OPT_ARGS];
+ unsigned long option;
+ int token;
+
+ if (!*p)
+ continue;
+
+ dfprintk(MOUNT, "NFS: parsing nfs mount option '%s'\n", p);
+
+ token = match_token(p, nfs_mount_option_tokens, args);
+ switch (token) {
+
+ /*
+ * boolean options: foo/nofoo
+ */
+ case Opt_soft:
+ mnt->flags |= NFS_MOUNT_SOFT;
+ mnt->flags &= ~NFS_MOUNT_SOFTERR;
+ break;
+ case Opt_softerr:
+ mnt->flags |= NFS_MOUNT_SOFTERR;
+ mnt->flags &= ~NFS_MOUNT_SOFT;
+ break;
+ case Opt_hard:
+ mnt->flags &= ~(NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR);
+ break;
+ case Opt_posix:
+ mnt->flags |= NFS_MOUNT_POSIX;
+ break;
+ case Opt_noposix:
+ mnt->flags &= ~NFS_MOUNT_POSIX;
+ break;
+ case Opt_cto:
+ mnt->flags &= ~NFS_MOUNT_NOCTO;
+ break;
+ case Opt_nocto:
+ mnt->flags |= NFS_MOUNT_NOCTO;
+ break;
+ case Opt_ac:
+ mnt->flags &= ~NFS_MOUNT_NOAC;
+ break;
+ case Opt_noac:
+ mnt->flags |= NFS_MOUNT_NOAC;
+ break;
+ case Opt_lock:
+ mnt->flags &= ~NFS_MOUNT_NONLM;
+ mnt->flags &= ~(NFS_MOUNT_LOCAL_FLOCK |
+ NFS_MOUNT_LOCAL_FCNTL);
+ break;
+ case Opt_nolock:
+ mnt->flags |= NFS_MOUNT_NONLM;
+ mnt->flags |= (NFS_MOUNT_LOCAL_FLOCK |
+ NFS_MOUNT_LOCAL_FCNTL);
+ break;
+ case Opt_udp:
+ mnt->flags &= ~NFS_MOUNT_TCP;
+ mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
+ break;
+ case Opt_tcp:
+ mnt->flags |= NFS_MOUNT_TCP;
+ mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
+ break;
+ case Opt_rdma:
+ mnt->flags |= NFS_MOUNT_TCP; /* for side protocols */
+ mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
+ xprt_load_transport(p);
+ break;
+ case Opt_acl:
+ mnt->flags &= ~NFS_MOUNT_NOACL;
+ break;
+ case Opt_noacl:
+ mnt->flags |= NFS_MOUNT_NOACL;
+ break;
+ case Opt_rdirplus:
+ mnt->flags &= ~NFS_MOUNT_NORDIRPLUS;
+ break;
+ case Opt_nordirplus:
+ mnt->flags |= NFS_MOUNT_NORDIRPLUS;
+ break;
+ case Opt_sharecache:
+ mnt->flags &= ~NFS_MOUNT_UNSHARED;
+ break;
+ case Opt_nosharecache:
+ mnt->flags |= NFS_MOUNT_UNSHARED;
+ break;
+ case Opt_resvport:
+ mnt->flags &= ~NFS_MOUNT_NORESVPORT;
+ break;
+ case Opt_noresvport:
+ mnt->flags |= NFS_MOUNT_NORESVPORT;
+ break;
+ case Opt_fscache:
+ mnt->options |= NFS_OPTION_FSCACHE;
+ kfree(mnt->fscache_uniq);
+ mnt->fscache_uniq = NULL;
+ break;
+ case Opt_nofscache:
+ mnt->options &= ~NFS_OPTION_FSCACHE;
+ kfree(mnt->fscache_uniq);
+ mnt->fscache_uniq = NULL;
+ break;
+ case Opt_migration:
+ mnt->options |= NFS_OPTION_MIGRATION;
+ break;
+ case Opt_nomigration:
+ mnt->options &= ~NFS_OPTION_MIGRATION;
+ break;
+
+ /*
+ * options that take numeric values
+ */
+ case Opt_port:
+ if (nfs_get_option_ul(args, &option) ||
+ option > USHRT_MAX)
+ goto out_invalid_value;
+ mnt->nfs_server.port = option;
+ break;
+ case Opt_rsize:
+ if (nfs_get_option_ul(args, &option))
+ goto out_invalid_value;
+ mnt->rsize = option;
+ break;
+ case Opt_wsize:
+ if (nfs_get_option_ul(args, &option))
+ goto out_invalid_value;
+ mnt->wsize = option;
+ break;
+ case Opt_bsize:
+ if (nfs_get_option_ul(args, &option))
+ goto out_invalid_value;
+ mnt->bsize = option;
+ break;
+ case Opt_timeo:
+ if (nfs_get_option_ul_bound(args, &option, 1, INT_MAX))
+ goto out_invalid_value;
+ mnt->timeo = option;
+ break;
+ case Opt_retrans:
+ if (nfs_get_option_ul_bound(args, &option, 0, INT_MAX))
+ goto out_invalid_value;
+ mnt->retrans = option;
+ break;
+ case Opt_acregmin:
+ if (nfs_get_option_ul(args, &option))
+ goto out_invalid_value;
+ mnt->acregmin = option;
+ break;
+ case Opt_acregmax:
+ if (nfs_get_option_ul(args, &option))
+ goto out_invalid_value;
+ mnt->acregmax = option;
+ break;
+ case Opt_acdirmin:
+ if (nfs_get_option_ul(args, &option))
+ goto out_invalid_value;
+ mnt->acdirmin = option;
+ break;
+ case Opt_acdirmax:
+ if (nfs_get_option_ul(args, &option))
+ goto out_invalid_value;
+ mnt->acdirmax = option;
+ break;
+ case Opt_actimeo:
+ if (nfs_get_option_ul(args, &option))
+ goto out_invalid_value;
+ mnt->acregmin = mnt->acregmax =
+ mnt->acdirmin = mnt->acdirmax = option;
+ break;
+ case Opt_namelen:
+ if (nfs_get_option_ul(args, &option))
+ goto out_invalid_value;
+ mnt->namlen = option;
+ break;
+ case Opt_mountport:
+ if (nfs_get_option_ul(args, &option) ||
+ option > USHRT_MAX)
+ goto out_invalid_value;
+ mnt->mount_server.port = option;
+ break;
+ case Opt_mountvers:
+ if (nfs_get_option_ul(args, &option) ||
+ option < NFS_MNT_VERSION ||
+ option > NFS_MNT3_VERSION)
+ goto out_invalid_value;
+ mnt->mount_server.version = option;
+ break;
+ case Opt_minorversion:
+ if (nfs_get_option_ul(args, &option))
+ goto out_invalid_value;
+ if (option > NFS4_MAX_MINOR_VERSION)
+ goto out_invalid_value;
+ mnt->minorversion = option;
+ break;
+
+ /*
+ * options that take text values
+ */
+ case Opt_nfsvers:
+ string = match_strdup(args);
+ if (string == NULL)
+ goto out_nomem;
+ rc = nfs_parse_version_string(string, mnt, args);
+ kfree(string);
+ if (!rc)
+ goto out_invalid_value;
+ break;
+ case Opt_sec:
+ string = match_strdup(args);
+ if (string == NULL)
+ goto out_nomem;
+ rc = nfs_parse_security_flavors(string, mnt);
+ kfree(string);
+ if (!rc) {
+ dfprintk(MOUNT, "NFS: unrecognized "
+ "security flavor\n");
+ return 0;
+ }
+ break;
+ case Opt_proto:
+ string = match_strdup(args);
+ if (string == NULL)
+ goto out_nomem;
+ token = match_token(string,
+ nfs_xprt_protocol_tokens, args);
+
+ protofamily = AF_INET;
+ switch (token) {
+ case Opt_xprt_udp6:
+ protofamily = AF_INET6;
+ /* fall through */
+ case Opt_xprt_udp:
+ mnt->flags &= ~NFS_MOUNT_TCP;
+ mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
+ break;
+ case Opt_xprt_tcp6:
+ protofamily = AF_INET6;
+ /* fall through */
+ case Opt_xprt_tcp:
+ mnt->flags |= NFS_MOUNT_TCP;
+ mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
+ break;
+ case Opt_xprt_rdma6:
+ protofamily = AF_INET6;
+ /* fall through */
+ case Opt_xprt_rdma:
+ /* vector side protocols to TCP */
+ mnt->flags |= NFS_MOUNT_TCP;
+ mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
+ xprt_load_transport(string);
+ break;
+ default:
+ dfprintk(MOUNT, "NFS: unrecognized "
+ "transport protocol\n");
+ kfree(string);
+ return 0;
+ }
+ kfree(string);
+ break;
+ case Opt_mountproto:
+ string = match_strdup(args);
+ if (string == NULL)
+ goto out_nomem;
+ token = match_token(string,
+ nfs_xprt_protocol_tokens, args);
+ kfree(string);
+
+ mountfamily = AF_INET;
+ switch (token) {
+ case Opt_xprt_udp6:
+ mountfamily = AF_INET6;
+ /* fall through */
+ case Opt_xprt_udp:
+ mnt->mount_server.protocol = XPRT_TRANSPORT_UDP;
+ break;
+ case Opt_xprt_tcp6:
+ mountfamily = AF_INET6;
+ /* fall through */
+ case Opt_xprt_tcp:
+ mnt->mount_server.protocol = XPRT_TRANSPORT_TCP;
+ break;
+ case Opt_xprt_rdma: /* not used for side protocols */
+ default:
+ dfprintk(MOUNT, "NFS: unrecognized "
+ "transport protocol\n");
+ return 0;
+ }
+ break;
+ case Opt_addr:
+ string = match_strdup(args);
+ if (string == NULL)
+ goto out_nomem;
+ mnt->nfs_server.addrlen =
+ rpc_pton(mnt->net, string, strlen(string),
+ (struct sockaddr *)
+ &mnt->nfs_server.address,
+ sizeof(mnt->nfs_server.address));
+ kfree(string);
+ if (mnt->nfs_server.addrlen == 0)
+ goto out_invalid_address;
+ break;
+ case Opt_clientaddr:
+ if (nfs_get_option_str(args, &mnt->client_address))
+ goto out_nomem;
+ break;
+ case Opt_mounthost:
+ if (nfs_get_option_str(args,
+ &mnt->mount_server.hostname))
+ goto out_nomem;
+ break;
+ case Opt_mountaddr:
+ string = match_strdup(args);
+ if (string == NULL)
+ goto out_nomem;
+ mnt->mount_server.addrlen =
+ rpc_pton(mnt->net, string, strlen(string),
+ (struct sockaddr *)
+ &mnt->mount_server.address,
+ sizeof(mnt->mount_server.address));
+ kfree(string);
+ if (mnt->mount_server.addrlen == 0)
+ goto out_invalid_address;
+ break;
+ case Opt_nconnect:
+ if (nfs_get_option_ul_bound(args, &option, 1, NFS_MAX_CONNECTIONS))
+ goto out_invalid_value;
+ mnt->nfs_server.nconnect = option;
+ break;
+ case Opt_lookupcache:
+ string = match_strdup(args);
+ if (string == NULL)
+ goto out_nomem;
+ token = match_token(string,
+ nfs_lookupcache_tokens, args);
+ kfree(string);
+ switch (token) {
+ case Opt_lookupcache_all:
+ mnt->flags &= ~(NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE);
+ break;
+ case Opt_lookupcache_positive:
+ mnt->flags &= ~NFS_MOUNT_LOOKUP_CACHE_NONE;
+ mnt->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG;
+ break;
+ case Opt_lookupcache_none:
+ mnt->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE;
+ break;
+ default:
+ dfprintk(MOUNT, "NFS: invalid "
+ "lookupcache argument\n");
+ return 0;
+ }
+ break;
+ case Opt_fscache_uniq:
+ if (nfs_get_option_str(args, &mnt->fscache_uniq))
+ goto out_nomem;
+ mnt->options |= NFS_OPTION_FSCACHE;
+ break;
+ case Opt_local_lock:
+ string = match_strdup(args);
+ if (string == NULL)
+ goto out_nomem;
+ token = match_token(string, nfs_local_lock_tokens,
+ args);
+ kfree(string);
+ switch (token) {
+ case Opt_local_lock_all:
+ mnt->flags |= (NFS_MOUNT_LOCAL_FLOCK |
+ NFS_MOUNT_LOCAL_FCNTL);
+ break;
+ case Opt_local_lock_flock:
+ mnt->flags |= NFS_MOUNT_LOCAL_FLOCK;
+ break;
+ case Opt_local_lock_posix:
+ mnt->flags |= NFS_MOUNT_LOCAL_FCNTL;
+ break;
+ case Opt_local_lock_none:
+ mnt->flags &= ~(NFS_MOUNT_LOCAL_FLOCK |
+ NFS_MOUNT_LOCAL_FCNTL);
+ break;
+ default:
+ dfprintk(MOUNT, "NFS: invalid "
+ "local_lock argument\n");
+ return 0;
+ }
+ break;
+
+ /*
+ * Special options
+ */
+ case Opt_sloppy:
+ sloppy = 1;
+ dfprintk(MOUNT, "NFS: relaxing parsing rules\n");
+ break;
+ case Opt_userspace:
+ case Opt_deprecated:
+ dfprintk(MOUNT, "NFS: ignoring mount option "
+ "'%s'\n", p);
+ break;
+
+ default:
+ invalid_option = 1;
+ dfprintk(MOUNT, "NFS: unrecognized mount option "
+ "'%s'\n", p);
+ }
+ }
+
+ if (!sloppy && invalid_option)
+ return 0;
+
+ if (mnt->minorversion && mnt->version != 4)
+ goto out_minorversion_mismatch;
+
+ if (mnt->options & NFS_OPTION_MIGRATION &&
+ (mnt->version != 4 || mnt->minorversion != 0))
+ goto out_migration_misuse;
+
+ /*
+ * verify that any proto=/mountproto= options match the address
+ * families in the addr=/mountaddr= options.
+ */
+ if (protofamily != AF_UNSPEC &&
+ protofamily != mnt->nfs_server.address.ss_family)
+ goto out_proto_mismatch;
+
+ if (mountfamily != AF_UNSPEC) {
+ if (mnt->mount_server.addrlen) {
+ if (mountfamily != mnt->mount_server.address.ss_family)
+ goto out_mountproto_mismatch;
+ } else {
+ if (mountfamily != mnt->nfs_server.address.ss_family)
+ goto out_mountproto_mismatch;
+ }
+ }
+
+ return 1;
+
+out_mountproto_mismatch:
+ printk(KERN_INFO "NFS: mount server address does not match mountproto= "
+ "option\n");
+ return 0;
+out_proto_mismatch:
+ printk(KERN_INFO "NFS: server address does not match proto= option\n");
+ return 0;
+out_invalid_address:
+ printk(KERN_INFO "NFS: bad IP address specified: %s\n", p);
+ return 0;
+out_invalid_value:
+ printk(KERN_INFO "NFS: bad mount option value specified: %s\n", p);
+ return 0;
+out_minorversion_mismatch:
+ printk(KERN_INFO "NFS: mount option vers=%u does not support "
+ "minorversion=%u\n", mnt->version, mnt->minorversion);
+ return 0;
+out_migration_misuse:
+ printk(KERN_INFO
+ "NFS: 'migration' not supported for this NFS version\n");
+ return 0;
+out_nomem:
+ printk(KERN_INFO "NFS: not enough memory to parse option\n");
+ return 0;
+out_security_failure:
+ printk(KERN_INFO "NFS: security options invalid: %d\n", rc);
+ return 0;
+}
+
+/*
+ * Split "dev_name" into "hostname:export_path".
+ *
+ * The leftmost colon demarks the split between the server's hostname
+ * and the export path. If the hostname starts with a left square
+ * bracket, then it may contain colons.
+ *
+ * Note: caller frees hostname and export path, even on error.
+ */
+static int nfs_parse_devname(const char *dev_name,
+ char **hostname, size_t maxnamlen,
+ char **export_path, size_t maxpathlen)
+{
+ size_t len;
+ char *end;
+
+ if (unlikely(!dev_name || !*dev_name)) {
+ dfprintk(MOUNT, "NFS: device name not specified\n");
+ return -EINVAL;
+ }
+
+ /* Is the host name protected with square brakcets? */
+ if (*dev_name == '[') {
+ end = strchr(++dev_name, ']');
+ if (end == NULL || end[1] != ':')
+ goto out_bad_devname;
+
+ len = end - dev_name;
+ end++;
+ } else {
+ char *comma;
+
+ end = strchr(dev_name, ':');
+ if (end == NULL)
+ goto out_bad_devname;
+ len = end - dev_name;
+
+ /* kill possible hostname list: not supported */
+ comma = strchr(dev_name, ',');
+ if (comma != NULL && comma < end)
+ len = comma - dev_name;
+ }
+
+ if (len > maxnamlen)
+ goto out_hostname;
+
+ /* N.B. caller will free nfs_server.hostname in all cases */
+ *hostname = kstrndup(dev_name, len, GFP_KERNEL);
+ if (*hostname == NULL)
+ goto out_nomem;
+ len = strlen(++end);
+ if (len > maxpathlen)
+ goto out_path;
+ *export_path = kstrndup(end, len, GFP_KERNEL);
+ if (!*export_path)
+ goto out_nomem;
+
+ dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", *export_path);
+ return 0;
+
+out_bad_devname:
+ dfprintk(MOUNT, "NFS: device name not in host:path format\n");
+ return -EINVAL;
+
+out_nomem:
+ dfprintk(MOUNT, "NFS: not enough memory to parse device name\n");
+ return -ENOMEM;
+
+out_hostname:
+ dfprintk(MOUNT, "NFS: server hostname too long\n");
+ return -ENAMETOOLONG;
+
+out_path:
+ dfprintk(MOUNT, "NFS: export pathname too long\n");
+ return -ENAMETOOLONG;
+}
+
+/*
+ * Validate the NFS2/NFS3 mount data
+ * - fills in the mount root filehandle
+ *
+ * For option strings, user space handles the following behaviors:
+ *
+ * + DNS: mapping server host name to IP address ("addr=" option)
+ *
+ * + failure mode: how to behave if a mount request can't be handled
+ * immediately ("fg/bg" option)
+ *
+ * + retry: how often to retry a mount request ("retry=" option)
+ *
+ * + breaking back: trying proto=udp after proto=tcp, v2 after v3,
+ * mountproto=tcp after mountproto=udp, and so on
+ */
+static int nfs23_validate_mount_data(void *options,
+ struct nfs_parsed_mount_data *args,
+ struct nfs_fh *mntfh,
+ const char *dev_name)
+{
+ struct nfs_mount_data *data = (struct nfs_mount_data *)options;
+ struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address;
+ int extra_flags = NFS_MOUNT_LEGACY_INTERFACE;
+
+ if (data == NULL)
+ goto out_no_data;
+
+ args->version = NFS_DEFAULT_VERSION;
+ switch (data->version) {
+ case 1:
+ data->namlen = 0; /* fall through */
+ case 2:
+ data->bsize = 0; /* fall through */
+ case 3:
+ if (data->flags & NFS_MOUNT_VER3)
+ goto out_no_v3;
+ data->root.size = NFS2_FHSIZE;
+ memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE);
+ /* Turn off security negotiation */
+ extra_flags |= NFS_MOUNT_SECFLAVOUR;
+ /* fall through */
+ case 4:
+ if (data->flags & NFS_MOUNT_SECFLAVOUR)
+ goto out_no_sec;
+ /* fall through */
+ case 5:
+ memset(data->context, 0, sizeof(data->context));
+ /* fall through */
+ case 6:
+ if (data->flags & NFS_MOUNT_VER3) {
+ if (data->root.size > NFS3_FHSIZE || data->root.size == 0)
+ goto out_invalid_fh;
+ mntfh->size = data->root.size;
+ args->version = 3;
+ } else {
+ mntfh->size = NFS2_FHSIZE;
+ args->version = 2;
+ }
+
+
+ memcpy(mntfh->data, data->root.data, mntfh->size);
+ if (mntfh->size < sizeof(mntfh->data))
+ memset(mntfh->data + mntfh->size, 0,
+ sizeof(mntfh->data) - mntfh->size);
+
+ /*
+ * Translate to nfs_parsed_mount_data, which nfs_fill_super
+ * can deal with.
+ */
+ args->flags = data->flags & NFS_MOUNT_FLAGMASK;
+ args->flags |= extra_flags;
+ args->rsize = data->rsize;
+ args->wsize = data->wsize;
+ args->timeo = data->timeo;
+ args->retrans = data->retrans;
+ args->acregmin = data->acregmin;
+ args->acregmax = data->acregmax;
+ args->acdirmin = data->acdirmin;
+ args->acdirmax = data->acdirmax;
+ args->need_mount = false;
+
+ memcpy(sap, &data->addr, sizeof(data->addr));
+ args->nfs_server.addrlen = sizeof(data->addr);
+ args->nfs_server.port = ntohs(data->addr.sin_port);
+ if (sap->sa_family != AF_INET ||
+ !nfs_verify_server_address(sap))
+ goto out_no_address;
+
+ if (!(data->flags & NFS_MOUNT_TCP))
+ args->nfs_server.protocol = XPRT_TRANSPORT_UDP;
+ /* N.B. caller will free nfs_server.hostname in all cases */
+ args->nfs_server.hostname = kstrdup(data->hostname, GFP_KERNEL);
+ args->namlen = data->namlen;
+ args->bsize = data->bsize;
+
+ if (data->flags & NFS_MOUNT_SECFLAVOUR)
+ args->selected_flavor = data->pseudoflavor;
+ else
+ args->selected_flavor = RPC_AUTH_UNIX;
+ if (!args->nfs_server.hostname)
+ goto out_nomem;
+
+ if (!(data->flags & NFS_MOUNT_NONLM))
+ args->flags &= ~(NFS_MOUNT_LOCAL_FLOCK|
+ NFS_MOUNT_LOCAL_FCNTL);
+ else
+ args->flags |= (NFS_MOUNT_LOCAL_FLOCK|
+ NFS_MOUNT_LOCAL_FCNTL);
+ /*
+ * The legacy version 6 binary mount data from userspace has a
+ * field used only to transport selinux information into the
+ * the kernel. To continue to support that functionality we
+ * have a touch of selinux knowledge here in the NFS code. The
+ * userspace code converted context=blah to just blah so we are
+ * converting back to the full string selinux understands.
+ */
+ if (data->context[0]){
+#ifdef CONFIG_SECURITY_SELINUX
+ int rc;
+ data->context[NFS_MAX_CONTEXT_LEN] = '\0';
+ rc = security_add_mnt_opt("context", data->context,
+ strlen(data->context), &args->lsm_opts);
+ if (rc)
+ return rc;
+#else
+ return -EINVAL;
+#endif
+ }
+
+ break;
+ default:
+ return NFS_TEXT_DATA;
+ }
+
+ return 0;
+
+out_no_data:
+ dfprintk(MOUNT, "NFS: mount program didn't pass any mount data\n");
+ return -EINVAL;
+
+out_no_v3:
+ dfprintk(MOUNT, "NFS: nfs_mount_data version %d does not support v3\n",
+ data->version);
+ return -EINVAL;
+
+out_no_sec:
+ dfprintk(MOUNT, "NFS: nfs_mount_data version supports only AUTH_SYS\n");
+ return -EINVAL;
+
+out_nomem:
+ dfprintk(MOUNT, "NFS: not enough memory to handle mount options\n");
+ return -ENOMEM;
+
+out_no_address:
+ dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n");
+ return -EINVAL;
+
+out_invalid_fh:
+ dfprintk(MOUNT, "NFS: invalid root filehandle\n");
+ return -EINVAL;
+}
+
+#if IS_ENABLED(CONFIG_NFS_V4)
+
+static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *args)
+{
+ args->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3|
+ NFS_MOUNT_LOCAL_FLOCK|NFS_MOUNT_LOCAL_FCNTL);
+}
+
+/*
+ * Validate NFSv4 mount options
+ */
+static int nfs4_validate_mount_data(void *options,
+ struct nfs_parsed_mount_data *args,
+ const char *dev_name)
+{
+ struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address;
+ struct nfs4_mount_data *data = (struct nfs4_mount_data *)options;
+ char *c;
+
+ if (data == NULL)
+ goto out_no_data;
+
+ args->version = 4;
+
+ switch (data->version) {
+ case 1:
+ if (data->host_addrlen > sizeof(args->nfs_server.address))
+ goto out_no_address;
+ if (data->host_addrlen == 0)
+ goto out_no_address;
+ args->nfs_server.addrlen = data->host_addrlen;
+ if (copy_from_user(sap, data->host_addr, data->host_addrlen))
+ return -EFAULT;
+ if (!nfs_verify_server_address(sap))
+ goto out_no_address;
+ args->nfs_server.port = ntohs(((struct sockaddr_in *)sap)->sin_port);
+
+ if (data->auth_flavourlen) {
+ rpc_authflavor_t pseudoflavor;
+ if (data->auth_flavourlen > 1)
+ goto out_inval_auth;
+ if (copy_from_user(&pseudoflavor,
+ data->auth_flavours,
+ sizeof(pseudoflavor)))
+ return -EFAULT;
+ args->selected_flavor = pseudoflavor;
+ } else
+ args->selected_flavor = RPC_AUTH_UNIX;
+
+ c = strndup_user(data->hostname.data, NFS4_MAXNAMLEN);
+ if (IS_ERR(c))
+ return PTR_ERR(c);
+ args->nfs_server.hostname = c;
+
+ c = strndup_user(data->mnt_path.data, NFS4_MAXPATHLEN);
+ if (IS_ERR(c))
+ return PTR_ERR(c);
+ args->nfs_server.export_path = c;
+ dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", c);
+
+ c = strndup_user(data->client_addr.data, 16);
+ if (IS_ERR(c))
+ return PTR_ERR(c);
+ args->client_address = c;
+
+ /*
+ * Translate to nfs_parsed_mount_data, which nfs4_fill_super
+ * can deal with.
+ */
+
+ args->flags = data->flags & NFS4_MOUNT_FLAGMASK;
+ args->rsize = data->rsize;
+ args->wsize = data->wsize;
+ args->timeo = data->timeo;
+ args->retrans = data->retrans;
+ args->acregmin = data->acregmin;
+ args->acregmax = data->acregmax;
+ args->acdirmin = data->acdirmin;
+ args->acdirmax = data->acdirmax;
+ args->nfs_server.protocol = data->proto;
+ nfs_validate_transport_protocol(args);
+ if (args->nfs_server.protocol == XPRT_TRANSPORT_UDP)
+ goto out_invalid_transport_udp;
+
+ break;
+ default:
+ return NFS_TEXT_DATA;
+ }
+
+ return 0;
+
+out_no_data:
+ dfprintk(MOUNT, "NFS4: mount program didn't pass any mount data\n");
+ return -EINVAL;
+
+out_inval_auth:
+ dfprintk(MOUNT, "NFS4: Invalid number of RPC auth flavours %d\n",
+ data->auth_flavourlen);
+ return -EINVAL;
+
+out_no_address:
+ dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n");
+ return -EINVAL;
+
+out_invalid_transport_udp:
+ dfprintk(MOUNT, "NFSv4: Unsupported transport protocol udp\n");
+ return -EINVAL;
+}
+
+int nfs_validate_mount_data(struct file_system_type *fs_type,
+ void *options,
+ struct nfs_parsed_mount_data *args,
+ struct nfs_fh *mntfh,
+ const char *dev_name)
+{
+ if (fs_type == &nfs_fs_type)
+ return nfs23_validate_mount_data(options, args, mntfh, dev_name);
+ return nfs4_validate_mount_data(options, args, dev_name);
+}
+#else
+int nfs_validate_mount_data(struct file_system_type *fs_type,
+ void *options,
+ struct nfs_parsed_mount_data *args,
+ struct nfs_fh *mntfh,
+ const char *dev_name)
+{
+ return nfs23_validate_mount_data(options, args, mntfh, dev_name);
+}
+#endif
+
+int nfs_validate_text_mount_data(void *options,
+ struct nfs_parsed_mount_data *args,
+ const char *dev_name)
+{
+ int port = 0;
+ int max_namelen = PAGE_SIZE;
+ int max_pathlen = NFS_MAXPATHLEN;
+ struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address;
+
+ if (nfs_parse_mount_options((char *)options, args) == 0)
+ return -EINVAL;
+
+ if (!nfs_verify_server_address(sap))
+ goto out_no_address;
+
+ if (args->version == 4) {
+#if IS_ENABLED(CONFIG_NFS_V4)
+ if (args->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
+ port = NFS_RDMA_PORT;
+ else
+ port = NFS_PORT;
+ max_namelen = NFS4_MAXNAMLEN;
+ max_pathlen = NFS4_MAXPATHLEN;
+ nfs_validate_transport_protocol(args);
+ if (args->nfs_server.protocol == XPRT_TRANSPORT_UDP)
+ goto out_invalid_transport_udp;
+ nfs4_validate_mount_flags(args);
+#else
+ goto out_v4_not_compiled;
+#endif /* CONFIG_NFS_V4 */
+ } else {
+ nfs_set_mount_transport_protocol(args);
+ if (args->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
+ port = NFS_RDMA_PORT;
+ }
+
+ nfs_set_port(sap, &args->nfs_server.port, port);
+
+ return nfs_parse_devname(dev_name,
+ &args->nfs_server.hostname,
+ max_namelen,
+ &args->nfs_server.export_path,
+ max_pathlen);
+
+#if !IS_ENABLED(CONFIG_NFS_V4)
+out_v4_not_compiled:
+ dfprintk(MOUNT, "NFS: NFSv4 is not compiled into kernel\n");
+ return -EPROTONOSUPPORT;
+#else
+out_invalid_transport_udp:
+ dfprintk(MOUNT, "NFSv4: Unsupported transport protocol udp\n");
+ return -EINVAL;
+#endif /* !CONFIG_NFS_V4 */
+
+out_no_address:
+ dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n");
+ return -EINVAL;
+}
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index a467e43fc682..28ab31fc5aa6 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -7,6 +7,7 @@
#include <linux/mount.h>
#include <linux/security.h>
#include <linux/crc32.h>
+#include <linux/sunrpc/addr.h>
#include <linux/nfs_page.h>
#include <linux/wait_bit.h>
@@ -224,6 +225,22 @@ extern const struct svc_version nfs4_callback_version1;
extern const struct svc_version nfs4_callback_version4;
struct nfs_pageio_descriptor;
+
+/* mount.c */
+#define NFS_TEXT_DATA 1
+
+extern struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(void);
+extern void nfs_free_parsed_mount_data(struct nfs_parsed_mount_data *data);
+extern int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt);
+extern int nfs_validate_mount_data(struct file_system_type *fs_type,
+ void *options,
+ struct nfs_parsed_mount_data *args,
+ struct nfs_fh *mntfh,
+ const char *dev_name);
+extern int nfs_validate_text_mount_data(void *options,
+ struct nfs_parsed_mount_data *args,
+ const char *dev_name);
+
/* pagelist.c */
extern int __init nfs_init_nfspagecache(void);
extern void nfs_destroy_nfspagecache(void);
@@ -765,3 +782,16 @@ static inline bool nfs_error_is_fatal_on_server(int err)
}
return nfs_error_is_fatal(err);
}
+
+/*
+ * Select between a default port value and a user-specified port value.
+ * If a zero value is set, then autobind will be used.
+ */
+static inline void nfs_set_port(struct sockaddr *sap, int *port,
+ const unsigned short default_port)
+{
+ if (*port == NFS_UNSPEC_PORT)
+ *port = default_port;
+
+ rpc_set_port(sap, *port);
+}
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index de00f89dbe6e..b07585f62c65 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -69,229 +69,6 @@
#include "nfs.h"
#define NFSDBG_FACILITY NFSDBG_VFS
-#define NFS_TEXT_DATA 1
-
-#if IS_ENABLED(CONFIG_NFS_V3)
-#define NFS_DEFAULT_VERSION 3
-#else
-#define NFS_DEFAULT_VERSION 2
-#endif
-
-#define NFS_MAX_CONNECTIONS 16
-
-enum {
- /* Mount options that take no arguments */
- Opt_soft, Opt_softerr, Opt_hard,
- Opt_posix, Opt_noposix,
- Opt_cto, Opt_nocto,
- Opt_ac, Opt_noac,
- Opt_lock, Opt_nolock,
- Opt_udp, Opt_tcp, Opt_rdma,
- Opt_acl, Opt_noacl,
- Opt_rdirplus, Opt_nordirplus,
- Opt_sharecache, Opt_nosharecache,
- Opt_resvport, Opt_noresvport,
- Opt_fscache, Opt_nofscache,
- Opt_migration, Opt_nomigration,
-
- /* Mount options that take integer arguments */
- Opt_port,
- Opt_rsize, Opt_wsize, Opt_bsize,
- Opt_timeo, Opt_retrans,
- Opt_acregmin, Opt_acregmax,
- Opt_acdirmin, Opt_acdirmax,
- Opt_actimeo,
- Opt_namelen,
- Opt_mountport,
- Opt_mountvers,
- Opt_minorversion,
-
- /* Mount options that take string arguments */
- Opt_nfsvers,
- Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost,
- Opt_addr, Opt_mountaddr, Opt_clientaddr,
- Opt_nconnect,
- Opt_lookupcache,
- Opt_fscache_uniq,
- Opt_local_lock,
-
- /* Special mount options */
- Opt_userspace, Opt_deprecated, Opt_sloppy,
-
- Opt_err
-};
-
-static const match_table_t nfs_mount_option_tokens = {
- { Opt_userspace, "bg" },
- { Opt_userspace, "fg" },
- { Opt_userspace, "retry=%s" },
-
- { Opt_sloppy, "sloppy" },
-
- { Opt_soft, "soft" },
- { Opt_softerr, "softerr" },
- { Opt_hard, "hard" },
- { Opt_deprecated, "intr" },
- { Opt_deprecated, "nointr" },
- { Opt_posix, "posix" },
- { Opt_noposix, "noposix" },
- { Opt_cto, "cto" },
- { Opt_nocto, "nocto" },
- { Opt_ac, "ac" },
- { Opt_noac, "noac" },
- { Opt_lock, "lock" },
- { Opt_nolock, "nolock" },
- { Opt_udp, "udp" },
- { Opt_tcp, "tcp" },
- { Opt_rdma, "rdma" },
- { Opt_acl, "acl" },
- { Opt_noacl, "noacl" },
- { Opt_rdirplus, "rdirplus" },
- { Opt_nordirplus, "nordirplus" },
- { Opt_sharecache, "sharecache" },
- { Opt_nosharecache, "nosharecache" },
- { Opt_resvport, "resvport" },
- { Opt_noresvport, "noresvport" },
- { Opt_fscache, "fsc" },
- { Opt_nofscache, "nofsc" },
- { Opt_migration, "migration" },
- { Opt_nomigration, "nomigration" },
-
- { Opt_port, "port=%s" },
- { Opt_rsize, "rsize=%s" },
- { Opt_wsize, "wsize=%s" },
- { Opt_bsize, "bsize=%s" },
- { Opt_timeo, "timeo=%s" },
- { Opt_retrans, "retrans=%s" },
- { Opt_acregmin, "acregmin=%s" },
- { Opt_acregmax, "acregmax=%s" },
- { Opt_acdirmin, "acdirmin=%s" },
- { Opt_acdirmax, "acdirmax=%s" },
- { Opt_actimeo, "actimeo=%s" },
- { Opt_namelen, "namlen=%s" },
- { Opt_mountport, "mountport=%s" },
- { Opt_mountvers, "mountvers=%s" },
- { Opt_minorversion, "minorversion=%s" },
-
- { Opt_nfsvers, "nfsvers=%s" },
- { Opt_nfsvers, "vers=%s" },
-
- { Opt_sec, "sec=%s" },
- { Opt_proto, "proto=%s" },
- { Opt_mountproto, "mountproto=%s" },
- { Opt_addr, "addr=%s" },
- { Opt_clientaddr, "clientaddr=%s" },
- { Opt_mounthost, "mounthost=%s" },
- { Opt_mountaddr, "mountaddr=%s" },
-
- { Opt_nconnect, "nconnect=%s" },
-
- { Opt_lookupcache, "lookupcache=%s" },
- { Opt_fscache_uniq, "fsc=%s" },
- { Opt_local_lock, "local_lock=%s" },
-
- /* The following needs to be listed after all other options */
- { Opt_nfsvers, "v%s" },
-
- { Opt_err, NULL }
-};
-
-enum {
- Opt_xprt_udp, Opt_xprt_udp6, Opt_xprt_tcp, Opt_xprt_tcp6, Opt_xprt_rdma,
- Opt_xprt_rdma6,
-
- Opt_xprt_err
-};
-
-static const match_table_t nfs_xprt_protocol_tokens = {
- { Opt_xprt_udp, "udp" },
- { Opt_xprt_udp6, "udp6" },
- { Opt_xprt_tcp, "tcp" },
- { Opt_xprt_tcp6, "tcp6" },
- { Opt_xprt_rdma, "rdma" },
- { Opt_xprt_rdma6, "rdma6" },
-
- { Opt_xprt_err, NULL }
-};
-
-enum {
- Opt_sec_none, Opt_sec_sys,
- Opt_sec_krb5, Opt_sec_krb5i, Opt_sec_krb5p,
- Opt_sec_lkey, Opt_sec_lkeyi, Opt_sec_lkeyp,
- Opt_sec_spkm, Opt_sec_spkmi, Opt_sec_spkmp,
-
- Opt_sec_err
-};
-
-static const match_table_t nfs_secflavor_tokens = {
- { Opt_sec_none, "none" },
- { Opt_sec_none, "null" },
- { Opt_sec_sys, "sys" },
-
- { Opt_sec_krb5, "krb5" },
- { Opt_sec_krb5i, "krb5i" },
- { Opt_sec_krb5p, "krb5p" },
-
- { Opt_sec_lkey, "lkey" },
- { Opt_sec_lkeyi, "lkeyi" },
- { Opt_sec_lkeyp, "lkeyp" },
-
- { Opt_sec_spkm, "spkm3" },
- { Opt_sec_spkmi, "spkm3i" },
- { Opt_sec_spkmp, "spkm3p" },
-
- { Opt_sec_err, NULL }
-};
-
-enum {
- Opt_lookupcache_all, Opt_lookupcache_positive,
- Opt_lookupcache_none,
-
- Opt_lookupcache_err
-};
-
-static match_table_t nfs_lookupcache_tokens = {
- { Opt_lookupcache_all, "all" },
- { Opt_lookupcache_positive, "pos" },
- { Opt_lookupcache_positive, "positive" },
- { Opt_lookupcache_none, "none" },
-
- { Opt_lookupcache_err, NULL }
-};
-
-enum {
- Opt_local_lock_all, Opt_local_lock_flock, Opt_local_lock_posix,
- Opt_local_lock_none,
-
- Opt_local_lock_err
-};
-
-static match_table_t nfs_local_lock_tokens = {
- { Opt_local_lock_all, "all" },
- { Opt_local_lock_flock, "flock" },
- { Opt_local_lock_posix, "posix" },
- { Opt_local_lock_none, "none" },
-
- { Opt_local_lock_err, NULL }
-};
-
-enum {
- Opt_vers_2, Opt_vers_3, Opt_vers_4, Opt_vers_4_0,
- Opt_vers_4_1, Opt_vers_4_2,
-
- Opt_vers_err
-};
-
-static match_table_t nfs_vers_tokens = {
- { Opt_vers_2, "2" },
- { Opt_vers_3, "3" },
- { Opt_vers_4, "4" },
- { Opt_vers_4_0, "4.0" },
- { Opt_vers_4_1, "4.1" },
- { Opt_vers_4_2, "4.2" },
-
- { Opt_vers_err, NULL }
-};
static struct dentry *nfs_prepared_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *raw_data);
@@ -332,10 +109,6 @@ const struct super_operations nfs_sops = {
EXPORT_SYMBOL_GPL(nfs_sops);
#if IS_ENABLED(CONFIG_NFS_V4)
-static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *);
-static int nfs4_validate_mount_data(void *options,
- struct nfs_parsed_mount_data *args, const char *dev_name);
-
struct file_system_type nfs4_fs_type = {
.owner = THIS_MODULE,
.name = "nfs4",
@@ -932,141 +705,6 @@ void nfs_umount_begin(struct super_block *sb)
}
EXPORT_SYMBOL_GPL(nfs_umount_begin);
-static struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(void)
-{
- struct nfs_parsed_mount_data *data;
-
- data = kzalloc(sizeof(*data), GFP_KERNEL);
- if (data) {
- data->timeo = NFS_UNSPEC_TIMEO;
- data->retrans = NFS_UNSPEC_RETRANS;
- data->acregmin = NFS_DEF_ACREGMIN;
- data->acregmax = NFS_DEF_ACREGMAX;
- data->acdirmin = NFS_DEF_ACDIRMIN;
- data->acdirmax = NFS_DEF_ACDIRMAX;
- data->mount_server.port = NFS_UNSPEC_PORT;
- data->nfs_server.port = NFS_UNSPEC_PORT;
- data->nfs_server.protocol = XPRT_TRANSPORT_TCP;
- data->selected_flavor = RPC_AUTH_MAXFLAVOR;
- data->minorversion = 0;
- data->need_mount = true;
- data->net = current->nsproxy->net_ns;
- data->lsm_opts = NULL;
- }
- return data;
-}
-
-static void nfs_free_parsed_mount_data(struct nfs_parsed_mount_data *data)
-{
- if (data) {
- kfree(data->client_address);
- kfree(data->mount_server.hostname);
- kfree(data->nfs_server.export_path);
- kfree(data->nfs_server.hostname);
- kfree(data->fscache_uniq);
- security_free_mnt_opts(&data->lsm_opts);
- kfree(data);
- }
-}
-
-/*
- * Sanity-check a server address provided by the mount command.
- *
- * Address family must be initialized, and address must not be
- * the ANY address for that family.
- */
-static int nfs_verify_server_address(struct sockaddr *addr)
-{
- switch (addr->sa_family) {
- case AF_INET: {
- struct sockaddr_in *sa = (struct sockaddr_in *)addr;
- return sa->sin_addr.s_addr != htonl(INADDR_ANY);
- }
- case AF_INET6: {
- struct in6_addr *sa = &((struct sockaddr_in6 *)addr)->sin6_addr;
- return !ipv6_addr_any(sa);
- }
- }
-
- dfprintk(MOUNT, "NFS: Invalid IP address specified\n");
- return 0;
-}
-
-/*
- * Select between a default port value and a user-specified port value.
- * If a zero value is set, then autobind will be used.
- */
-static void nfs_set_port(struct sockaddr *sap, int *port,
- const unsigned short default_port)
-{
- if (*port == NFS_UNSPEC_PORT)
- *port = default_port;
-
- rpc_set_port(sap, *port);
-}
-
-/*
- * Sanity check the NFS transport protocol.
- *
- */
-static void nfs_validate_transport_protocol(struct nfs_parsed_mount_data *mnt)
-{
- switch (mnt->nfs_server.protocol) {
- case XPRT_TRANSPORT_UDP:
- case XPRT_TRANSPORT_TCP:
- case XPRT_TRANSPORT_RDMA:
- break;
- default:
- mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
- }
-}
-
-/*
- * For text based NFSv2/v3 mounts, the mount protocol transport default
- * settings should depend upon the specified NFS transport.
- */
-static void nfs_set_mount_transport_protocol(struct nfs_parsed_mount_data *mnt)
-{
- nfs_validate_transport_protocol(mnt);
-
- if (mnt->mount_server.protocol == XPRT_TRANSPORT_UDP ||
- mnt->mount_server.protocol == XPRT_TRANSPORT_TCP)
- return;
- switch (mnt->nfs_server.protocol) {
- case XPRT_TRANSPORT_UDP:
- mnt->mount_server.protocol = XPRT_TRANSPORT_UDP;
- break;
- case XPRT_TRANSPORT_TCP:
- case XPRT_TRANSPORT_RDMA:
- mnt->mount_server.protocol = XPRT_TRANSPORT_TCP;
- }
-}
-
-/*
- * Add 'flavor' to 'auth_info' if not already present.
- * Returns true if 'flavor' ends up in the list, false otherwise
- */
-static bool nfs_auth_info_add(struct nfs_auth_info *auth_info,
- rpc_authflavor_t flavor)
-{
- unsigned int i;
- unsigned int max_flavor_len = ARRAY_SIZE(auth_info->flavors);
-
- /* make sure this flavor isn't already in the list */
- for (i = 0; i < auth_info->flavor_len; i++) {
- if (flavor == auth_info->flavors[i])
- return true;
- }
-
- if (auth_info->flavor_len + 1 >= max_flavor_len) {
- dfprintk(MOUNT, "NFS: too many sec= flavors\n");
- return false;
- }
-
- auth_info->flavors[auth_info->flavor_len++] = flavor;
- return true;
-}
-
/*
* Return true if 'match' is in auth_info or auth_info is empty.
* Return false otherwise.
@@ -1087,627 +725,6 @@ bool nfs_auth_info_match(const struct nfs_auth_info *auth_info,
}
EXPORT_SYMBOL_GPL(nfs_auth_info_match);
-/*
- * Parse the value of the 'sec=' option.
- */
-static int nfs_parse_security_flavors(char *value,
- struct nfs_parsed_mount_data *mnt)
-{
- substring_t args[MAX_OPT_ARGS];
- rpc_authflavor_t pseudoflavor;
- char *p;
-
- dfprintk(MOUNT, "NFS: parsing sec=%s option\n", value);
-
- while ((p = strsep(&value, ":")) != NULL) {
- switch (match_token(p, nfs_secflavor_tokens, args)) {
- case Opt_sec_none:
- pseudoflavor = RPC_AUTH_NULL;
- break;
- case Opt_sec_sys:
- pseudoflavor = RPC_AUTH_UNIX;
- break;
- case Opt_sec_krb5:
- pseudoflavor = RPC_AUTH_GSS_KRB5;
- break;
- case Opt_sec_krb5i:
- pseudoflavor = RPC_AUTH_GSS_KRB5I;
- break;
- case Opt_sec_krb5p:
- pseudoflavor = RPC_AUTH_GSS_KRB5P;
- break;
- case Opt_sec_lkey:
- pseudoflavor = RPC_AUTH_GSS_LKEY;
- break;
- case Opt_sec_lkeyi:
- pseudoflavor = RPC_AUTH_GSS_LKEYI;
- break;
- case Opt_sec_lkeyp:
- pseudoflavor = RPC_AUTH_GSS_LKEYP;
- break;
- case Opt_sec_spkm:
- pseudoflavor = RPC_AUTH_GSS_SPKM;
- break;
- case Opt_sec_spkmi:
- pseudoflavor = RPC_AUTH_GSS_SPKMI;
- break;
- case Opt_sec_spkmp:
- pseudoflavor = RPC_AUTH_GSS_SPKMP;
- break;
- default:
- dfprintk(MOUNT,
- "NFS: sec= option '%s' not recognized\n", p);
- return 0;
- }
-
- if (!nfs_auth_info_add(&mnt->auth_info, pseudoflavor))
- return 0;
- }
-
- return 1;
-}
-
-static int nfs_parse_version_string(char *string,
- struct nfs_parsed_mount_data *mnt,
- substring_t *args)
-{
- mnt->flags &= ~NFS_MOUNT_VER3;
- switch (match_token(string, nfs_vers_tokens, args)) {
- case Opt_vers_2:
- mnt->version = 2;
- break;
- case Opt_vers_3:
- mnt->flags |= NFS_MOUNT_VER3;
- mnt->version = 3;
- break;
- case Opt_vers_4:
- /* Backward compatibility option. In future,
- * the mount program should always supply
- * a NFSv4 minor version number.
- */
- mnt->version = 4;
- break;
- case Opt_vers_4_0:
- mnt->version = 4;
- mnt->minorversion = 0;
- break;
- case Opt_vers_4_1:
- mnt->version = 4;
- mnt->minorversion = 1;
- break;
- case Opt_vers_4_2:
- mnt->version = 4;
- mnt->minorversion = 2;
- break;
- default:
- return 0;
- }
- return 1;
-}
-
-static int nfs_get_option_str(substring_t args[], char **option)
-{
- kfree(*option);
- *option = match_strdup(args);
- return !*option;
-}
-
-static int nfs_get_option_ul(substring_t args[], unsigned long *option)
-{
- int rc;
- char *string;
-
- string = match_strdup(args);
- if (string == NULL)
- return -ENOMEM;
- rc = kstrtoul(string, 10, option);
- kfree(string);
-
- return rc;
-}
-
-static int nfs_get_option_ul_bound(substring_t args[], unsigned long *option,
- unsigned long l_bound, unsigned long u_bound)
-{
- int ret;
-
- ret = nfs_get_option_ul(args, option);
- if (ret != 0)
- return ret;
- if (*option < l_bound || *option > u_bound)
- return -ERANGE;
- return 0;
-}
-
-/*
- * Error-check and convert a string of mount options from user space into
- * a data structure. The whole mount string is processed; bad options are
- * skipped as they are encountered. If there were no errors, return 1;
- * otherwise return 0 (zero).
- */
-static int nfs_parse_mount_options(char *raw,
- struct nfs_parsed_mount_data *mnt)
-{
- char *p, *string;
- int rc, sloppy = 0, invalid_option = 0;
- unsigned short protofamily = AF_UNSPEC;
- unsigned short mountfamily = AF_UNSPEC;
-
- if (!raw) {
- dfprintk(MOUNT, "NFS: mount options string was NULL.\n");
- return 1;
- }
- dfprintk(MOUNT, "NFS: nfs mount opts='%s'\n", raw);
-
- rc = security_sb_eat_lsm_opts(raw, &mnt->lsm_opts);
- if (rc)
- goto out_security_failure;
-
- while ((p = strsep(&raw, ",")) != NULL) {
- substring_t args[MAX_OPT_ARGS];
- unsigned long option;
- int token;
-
- if (!*p)
- continue;
-
- dfprintk(MOUNT, "NFS: parsing nfs mount option '%s'\n", p);
-
- token = match_token(p, nfs_mount_option_tokens, args);
- switch (token) {
-
- /*
- * boolean options: foo/nofoo
- */
- case Opt_soft:
- mnt->flags |= NFS_MOUNT_SOFT;
- mnt->flags &= ~NFS_MOUNT_SOFTERR;
- break;
- case Opt_softerr:
- mnt->flags |= NFS_MOUNT_SOFTERR;
- mnt->flags &= ~NFS_MOUNT_SOFT;
- break;
- case Opt_hard:
- mnt->flags &= ~(NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR);
- break;
- case Opt_posix:
- mnt->flags |= NFS_MOUNT_POSIX;
- break;
- case Opt_noposix:
- mnt->flags &= ~NFS_MOUNT_POSIX;
- break;
- case Opt_cto:
- mnt->flags &= ~NFS_MOUNT_NOCTO;
- break;
- case Opt_nocto:
- mnt->flags |= NFS_MOUNT_NOCTO;
- break;
- case Opt_ac:
- mnt->flags &= ~NFS_MOUNT_NOAC;
- break;
- case Opt_noac:
- mnt->flags |= NFS_MOUNT_NOAC;
- break;
- case Opt_lock:
- mnt->flags &= ~NFS_MOUNT_NONLM;
- mnt->flags &= ~(NFS_MOUNT_LOCAL_FLOCK |
- NFS_MOUNT_LOCAL_FCNTL);
- break;
- case Opt_nolock:
- mnt->flags |= NFS_MOUNT_NONLM;
- mnt->flags |= (NFS_MOUNT_LOCAL_FLOCK |
- NFS_MOUNT_LOCAL_FCNTL);
- break;
- case Opt_udp:
- mnt->flags &= ~NFS_MOUNT_TCP;
- mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
- break;
- case Opt_tcp:
- mnt->flags |= NFS_MOUNT_TCP;
- mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
- break;
- case Opt_rdma:
- mnt->flags |= NFS_MOUNT_TCP; /* for side protocols */
- mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
- xprt_load_transport(p);
- break;
- case Opt_acl:
- mnt->flags &= ~NFS_MOUNT_NOACL;
- break;
- case Opt_noacl:
- mnt->flags |= NFS_MOUNT_NOACL;
- break;
- case Opt_rdirplus:
- mnt->flags &= ~NFS_MOUNT_NORDIRPLUS;
- break;
- case Opt_nordirplus:
- mnt->flags |= NFS_MOUNT_NORDIRPLUS;
- break;
- case Opt_sharecache:
- mnt->flags &= ~NFS_MOUNT_UNSHARED;
- break;
- case Opt_nosharecache:
- mnt->flags |= NFS_MOUNT_UNSHARED;
- break;
- case Opt_resvport:
- mnt->flags &= ~NFS_MOUNT_NORESVPORT;
- break;
- case Opt_noresvport:
- mnt->flags |= NFS_MOUNT_NORESVPORT;
- break;
- case Opt_fscache:
- mnt->options |= NFS_OPTION_FSCACHE;
- kfree(mnt->fscache_uniq);
- mnt->fscache_uniq = NULL;
- break;
- case Opt_nofscache:
- mnt->options &= ~NFS_OPTION_FSCACHE;
- kfree(mnt->fscache_uniq);
- mnt->fscache_uniq = NULL;
- break;
- case Opt_migration:
- mnt->options |= NFS_OPTION_MIGRATION;
- break;
- case Opt_nomigration:
- mnt->options &= ~NFS_OPTION_MIGRATION;
- break;
-
- /*
- * options that take numeric values
- */
- case Opt_port:
- if (nfs_get_option_ul(args, &option) ||
- option > USHRT_MAX)
- goto out_invalid_value;
- mnt->nfs_server.port = option;
- break;
- case Opt_rsize:
- if (nfs_get_option_ul(args, &option))
- goto out_invalid_value;
- mnt->rsize = option;
- break;
- case Opt_wsize:
- if (nfs_get_option_ul(args, &option))
- goto out_invalid_value;
- mnt->wsize = option;
- break;
- case Opt_bsize:
- if (nfs_get_option_ul(args, &option))
- goto out_invalid_value;
- mnt->bsize = option;
- break;
- case Opt_timeo:
- if (nfs_get_option_ul_bound(args, &option, 1, INT_MAX))
- goto out_invalid_value;
- mnt->timeo = option;
- break;
- case Opt_retrans:
- if (nfs_get_option_ul_bound(args, &option, 0, INT_MAX))
- goto out_invalid_value;
- mnt->retrans = option;
- break;
- case Opt_acregmin:
- if (nfs_get_option_ul(args, &option))
- goto out_invalid_value;
- mnt->acregmin = option;
- break;
- case Opt_acregmax:
- if (nfs_get_option_ul(args, &option))
- goto out_invalid_value;
- mnt->acregmax = option;
- break;
- case Opt_acdirmin:
- if (nfs_get_option_ul(args, &option))
- goto out_invalid_value;
- mnt->acdirmin = option;
- break;
- case Opt_acdirmax:
- if (nfs_get_option_ul(args, &option))
- goto out_invalid_value;
- mnt->acdirmax = option;
- break;
- case Opt_actimeo:
- if (nfs_get_option_ul(args, &option))
- goto out_invalid_value;
- mnt->acregmin = mnt->acregmax =
- mnt->acdirmin = mnt->acdirmax = option;
- break;
- case Opt_namelen:
- if (nfs_get_option_ul(args, &option))
- goto out_invalid_value;
- mnt->namlen = option;
- break;
- case Opt_mountport:
- if (nfs_get_option_ul(args, &option) ||
- option > USHRT_MAX)
- goto out_invalid_value;
- mnt->mount_server.port = option;
- break;
- case Opt_mountvers:
- if (nfs_get_option_ul(args, &option) ||
- option < NFS_MNT_VERSION ||
- option > NFS_MNT3_VERSION)
- goto out_invalid_value;
- mnt->mount_server.version = option;
- break;
- case Opt_minorversion:
- if (nfs_get_option_ul(args, &option))
- goto out_invalid_value;
- if (option > NFS4_MAX_MINOR_VERSION)
- goto out_invalid_value;
- mnt->minorversion = option;
- break;
-
- /*
- * options that take text values
- */
- case Opt_nfsvers:
- string = match_strdup(args);
- if (string == NULL)
- goto out_nomem;
- rc = nfs_parse_version_string(string, mnt, args);
- kfree(string);
- if (!rc)
- goto out_invalid_value;
- break;
- case Opt_sec:
- string = match_strdup(args);
- if (string == NULL)
- goto out_nomem;
- rc = nfs_parse_security_flavors(string, mnt);
- kfree(string);
- if (!rc) {
- dfprintk(MOUNT, "NFS: unrecognized "
- "security flavor\n");
- return 0;
- }
- break;
- case Opt_proto:
- string = match_strdup(args);
- if (string == NULL)
- goto out_nomem;
- token = match_token(string,
- nfs_xprt_protocol_tokens, args);
-
- protofamily = AF_INET;
- switch (token) {
- case Opt_xprt_udp6:
- protofamily = AF_INET6;
- /* fall through */
- case Opt_xprt_udp:
- mnt->flags &= ~NFS_MOUNT_TCP;
- mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
- break;
- case Opt_xprt_tcp6:
- protofamily = AF_INET6;
- /* fall through */
- case Opt_xprt_tcp:
- mnt->flags |= NFS_MOUNT_TCP;
- mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
- break;
- case Opt_xprt_rdma6:
- protofamily = AF_INET6;
- /* fall through */
- case Opt_xprt_rdma:
- /* vector side protocols to TCP */
- mnt->flags |= NFS_MOUNT_TCP;
- mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
- xprt_load_transport(string);
- break;
- default:
- dfprintk(MOUNT, "NFS: unrecognized "
- "transport protocol\n");
- kfree(string);
- return 0;
- }
- kfree(string);
- break;
- case Opt_mountproto:
- string = match_strdup(args);
- if (string == NULL)
- goto out_nomem;
- token = match_token(string,
- nfs_xprt_protocol_tokens, args);
- kfree(string);
-
- mountfamily = AF_INET;
- switch (token) {
- case Opt_xprt_udp6:
- mountfamily = AF_INET6;
- /* fall through */
- case Opt_xprt_udp:
- mnt->mount_server.protocol = XPRT_TRANSPORT_UDP;
- break;
- case Opt_xprt_tcp6:
- mountfamily = AF_INET6;
- /* fall through */
- case Opt_xprt_tcp:
- mnt->mount_server.protocol = XPRT_TRANSPORT_TCP;
- break;
- case Opt_xprt_rdma: /* not used for side protocols */
- default:
- dfprintk(MOUNT, "NFS: unrecognized "
- "transport protocol\n");
- return 0;
- }
- break;
- case Opt_addr:
- string = match_strdup(args);
- if (string == NULL)
- goto out_nomem;
- mnt->nfs_server.addrlen =
- rpc_pton(mnt->net, string, strlen(string),
- (struct sockaddr *)
- &mnt->nfs_server.address,
- sizeof(mnt->nfs_server.address));
- kfree(string);
- if (mnt->nfs_server.addrlen == 0)
- goto out_invalid_address;
- break;
- case Opt_clientaddr:
- if (nfs_get_option_str(args, &mnt->client_address))
- goto out_nomem;
- break;
- case Opt_mounthost:
- if (nfs_get_option_str(args,
- &mnt->mount_server.hostname))
- goto out_nomem;
- break;
- case Opt_mountaddr:
- string = match_strdup(args);
- if (string == NULL)
- goto out_nomem;
- mnt->mount_server.addrlen =
- rpc_pton(mnt->net, string, strlen(string),
- (struct sockaddr *)
- &mnt->mount_server.address,
- sizeof(mnt->mount_server.address));
- kfree(string);
- if (mnt->mount_server.addrlen == 0)
- goto out_invalid_address;
- break;
- case Opt_nconnect:
- if (nfs_get_option_ul_bound(args, &option, 1, NFS_MAX_CONNECTIONS))
- goto out_invalid_value;
- mnt->nfs_server.nconnect = option;
- break;
- case Opt_lookupcache:
- string = match_strdup(args);
- if (string == NULL)
- goto out_nomem;
- token = match_token(string,
- nfs_lookupcache_tokens, args);
- kfree(string);
- switch (token) {
- case Opt_lookupcache_all:
- mnt->flags &= ~(NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE);
- break;
- case Opt_lookupcache_positive:
- mnt->flags &= ~NFS_MOUNT_LOOKUP_CACHE_NONE;
- mnt->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG;
- break;
- case Opt_lookupcache_none:
- mnt->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE;
- break;
- default:
- dfprintk(MOUNT, "NFS: invalid "
- "lookupcache argument\n");
- return 0;
- }
- break;
- case Opt_fscache_uniq:
- if (nfs_get_option_str(args, &mnt->fscache_uniq))
- goto out_nomem;
- mnt->options |= NFS_OPTION_FSCACHE;
- break;
- case Opt_local_lock:
- string = match_strdup(args);
- if (string == NULL)
- goto out_nomem;
- token = match_token(string, nfs_local_lock_tokens,
- args);
- kfree(string);
- switch (token) {
- case Opt_local_lock_all:
- mnt->flags |= (NFS_MOUNT_LOCAL_FLOCK |
- NFS_MOUNT_LOCAL_FCNTL);
- break;
- case Opt_local_lock_flock:
- mnt->flags |= NFS_MOUNT_LOCAL_FLOCK;
- break;
- case Opt_local_lock_posix:
- mnt->flags |= NFS_MOUNT_LOCAL_FCNTL;
- break;
- case Opt_local_lock_none:
- mnt->flags &= ~(NFS_MOUNT_LOCAL_FLOCK |
- NFS_MOUNT_LOCAL_FCNTL);
- break;
- default:
- dfprintk(MOUNT, "NFS: invalid "
- "local_lock argument\n");
- return 0;
- }
- break;
-
- /*
- * Special options
- */
- case Opt_sloppy:
- sloppy = 1;
- dfprintk(MOUNT, "NFS: relaxing parsing rules\n");
- break;
- case Opt_userspace:
- case Opt_deprecated:
- dfprintk(MOUNT, "NFS: ignoring mount option "
- "'%s'\n", p);
- break;
-
- default:
- invalid_option = 1;
- dfprintk(MOUNT, "NFS: unrecognized mount option "
- "'%s'\n", p);
- }
- }
-
- if (!sloppy && invalid_option)
- return 0;
-
- if (mnt->minorversion && mnt->version != 4)
- goto out_minorversion_mismatch;
-
- if (mnt->options & NFS_OPTION_MIGRATION &&
- (mnt->version != 4 || mnt->minorversion != 0))
- goto out_migration_misuse;
-
- /*
- * verify that any proto=/mountproto= options match the address
- * families in the addr=/mountaddr= options.
- */
- if (protofamily != AF_UNSPEC &&
- protofamily != mnt->nfs_server.address.ss_family)
- goto out_proto_mismatch;
-
- if (mountfamily != AF_UNSPEC) {
- if (mnt->mount_server.addrlen) {
- if (mountfamily != mnt->mount_server.address.ss_family)
- goto out_mountproto_mismatch;
- } else {
- if (mountfamily != mnt->nfs_server.address.ss_family)
- goto out_mountproto_mismatch;
- }
- }
-
- return 1;
-
-out_mountproto_mismatch:
- printk(KERN_INFO "NFS: mount server address does not match mountproto= "
- "option\n");
- return 0;
-out_proto_mismatch:
- printk(KERN_INFO "NFS: server address does not match proto= option\n");
- return 0;
-out_invalid_address:
- printk(KERN_INFO "NFS: bad IP address specified: %s\n", p);
- return 0;
-out_invalid_value:
- printk(KERN_INFO "NFS: bad mount option value specified: %s\n", p);
- return 0;
-out_minorversion_mismatch:
- printk(KERN_INFO "NFS: mount option vers=%u does not support "
- "minorversion=%u\n", mnt->version, mnt->minorversion);
- return 0;
-out_migration_misuse:
- printk(KERN_INFO
- "NFS: 'migration' not supported for this NFS version\n");
- return 0;
-out_nomem:
- printk(KERN_INFO "NFS: not enough memory to parse option\n");
- return 0;
-out_security_failure:
- printk(KERN_INFO "NFS: security options invalid: %d\n", rc);
- return 0;
-}
-
/*
* Ensure that a specified authtype in args->auth_info is supported by
* the server. Returns 0 and sets args->selected_flavor if it's ok, and
@@ -1908,327 +925,6 @@ struct dentry *nfs_try_mount(int flags, const char *dev_name,
}
EXPORT_SYMBOL_GPL(nfs_try_mount);
-/*
- * Split "dev_name" into "hostname:export_path".
- *
- * The leftmost colon demarks the split between the server's hostname
- * and the export path. If the hostname starts with a left square
- * bracket, then it may contain colons.
- *
- * Note: caller frees hostname and export path, even on error.
- */
-static int nfs_parse_devname(const char *dev_name,
- char **hostname, size_t maxnamlen,
- char **export_path, size_t maxpathlen)
-{
- size_t len;
- char *end;
-
- if (unlikely(!dev_name || !*dev_name)) {
- dfprintk(MOUNT, "NFS: device name not specified\n");
- return -EINVAL;
- }
-
- /* Is the host name protected with square brakcets? */
- if (*dev_name == '[') {
- end = strchr(++dev_name, ']');
- if (end == NULL || end[1] != ':')
- goto out_bad_devname;
-
- len = end - dev_name;
- end++;
- } else {
- char *comma;
-
- end = strchr(dev_name, ':');
- if (end == NULL)
- goto out_bad_devname;
- len = end - dev_name;
-
- /* kill possible hostname list: not supported */
- comma = strchr(dev_name, ',');
- if (comma != NULL && comma < end)
- len = comma - dev_name;
- }
-
- if (len > maxnamlen)
- goto out_hostname;
-
- /* N.B. caller will free nfs_server.hostname in all cases */
- *hostname = kstrndup(dev_name, len, GFP_KERNEL);
- if (*hostname == NULL)
- goto out_nomem;
- len = strlen(++end);
- if (len > maxpathlen)
- goto out_path;
- *export_path = kstrndup(end, len, GFP_KERNEL);
- if (!*export_path)
- goto out_nomem;
-
- dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", *export_path);
- return 0;
-
-out_bad_devname:
- dfprintk(MOUNT, "NFS: device name not in host:path format\n");
- return -EINVAL;
-
-out_nomem:
- dfprintk(MOUNT, "NFS: not enough memory to parse device name\n");
- return -ENOMEM;
-
-out_hostname:
- dfprintk(MOUNT, "NFS: server hostname too long\n");
- return -ENAMETOOLONG;
-
-out_path:
- dfprintk(MOUNT, "NFS: export pathname too long\n");
- return -ENAMETOOLONG;
-}
-
-/*
- * Validate the NFS2/NFS3 mount data
- * - fills in the mount root filehandle
- *
- * For option strings, user space handles the following behaviors:
- *
- * + DNS: mapping server host name to IP address ("addr=" option)
- *
- * + failure mode: how to behave if a mount request can't be handled
- * immediately ("fg/bg" option)
- *
- * + retry: how often to retry a mount request ("retry=" option)
- *
- * + breaking back: trying proto=udp after proto=tcp, v2 after v3,
- * mountproto=tcp after mountproto=udp, and so on
- */
-static int nfs23_validate_mount_data(void *options,
- struct nfs_parsed_mount_data *args,
- struct nfs_fh *mntfh,
- const char *dev_name)
-{
- struct nfs_mount_data *data = (struct nfs_mount_data *)options;
- struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address;
- int extra_flags = NFS_MOUNT_LEGACY_INTERFACE;
-
- if (data == NULL)
- goto out_no_data;
-
- args->version = NFS_DEFAULT_VERSION;
- switch (data->version) {
- case 1:
- data->namlen = 0; /* fall through */
- case 2:
- data->bsize = 0; /* fall through */
- case 3:
- if (data->flags & NFS_MOUNT_VER3)
- goto out_no_v3;
- data->root.size = NFS2_FHSIZE;
- memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE);
- /* Turn off security negotiation */
- extra_flags |= NFS_MOUNT_SECFLAVOUR;
- /* fall through */
- case 4:
- if (data->flags & NFS_MOUNT_SECFLAVOUR)
- goto out_no_sec;
- /* fall through */
- case 5:
- memset(data->context, 0, sizeof(data->context));
- /* fall through */
- case 6:
- if (data->flags & NFS_MOUNT_VER3) {
- if (data->root.size > NFS3_FHSIZE || data->root.size == 0)
- goto out_invalid_fh;
- mntfh->size = data->root.size;
- args->version = 3;
- } else {
- mntfh->size = NFS2_FHSIZE;
- args->version = 2;
- }
-
-
- memcpy(mntfh->data, data->root.data, mntfh->size);
- if (mntfh->size < sizeof(mntfh->data))
- memset(mntfh->data + mntfh->size, 0,
- sizeof(mntfh->data) - mntfh->size);
-
- /*
- * Translate to nfs_parsed_mount_data, which nfs_fill_super
- * can deal with.
- */
- args->flags = data->flags & NFS_MOUNT_FLAGMASK;
- args->flags |= extra_flags;
- args->rsize = data->rsize;
- args->wsize = data->wsize;
- args->timeo = data->timeo;
- args->retrans = data->retrans;
- args->acregmin = data->acregmin;
- args->acregmax = data->acregmax;
- args->acdirmin = data->acdirmin;
- args->acdirmax = data->acdirmax;
- args->need_mount = false;
-
- memcpy(sap, &data->addr, sizeof(data->addr));
- args->nfs_server.addrlen = sizeof(data->addr);
- args->nfs_server.port = ntohs(data->addr.sin_port);
- if (sap->sa_family != AF_INET ||
- !nfs_verify_server_address(sap))
- goto out_no_address;
-
- if (!(data->flags & NFS_MOUNT_TCP))
- args->nfs_server.protocol = XPRT_TRANSPORT_UDP;
- /* N.B. caller will free nfs_server.hostname in all cases */
- args->nfs_server.hostname = kstrdup(data->hostname, GFP_KERNEL);
- args->namlen = data->namlen;
- args->bsize = data->bsize;
-
- if (data->flags & NFS_MOUNT_SECFLAVOUR)
- args->selected_flavor = data->pseudoflavor;
- else
- args->selected_flavor = RPC_AUTH_UNIX;
- if (!args->nfs_server.hostname)
- goto out_nomem;
-
- if (!(data->flags & NFS_MOUNT_NONLM))
- args->flags &= ~(NFS_MOUNT_LOCAL_FLOCK|
- NFS_MOUNT_LOCAL_FCNTL);
- else
- args->flags |= (NFS_MOUNT_LOCAL_FLOCK|
- NFS_MOUNT_LOCAL_FCNTL);
- /*
- * The legacy version 6 binary mount data from userspace has a
- * field used only to transport selinux information into the
- * the kernel. To continue to support that functionality we
- * have a touch of selinux knowledge here in the NFS code. The
- * userspace code converted context=blah to just blah so we are
- * converting back to the full string selinux understands.
- */
- if (data->context[0]){
-#ifdef CONFIG_SECURITY_SELINUX
- int rc;
- data->context[NFS_MAX_CONTEXT_LEN] = '\0';
- rc = security_add_mnt_opt("context", data->context,
- strlen(data->context), &args->lsm_opts);
- if (rc)
- return rc;
-#else
- return -EINVAL;
-#endif
- }
-
- break;
- default:
- return NFS_TEXT_DATA;
- }
-
- return 0;
-
-out_no_data:
- dfprintk(MOUNT, "NFS: mount program didn't pass any mount data\n");
- return -EINVAL;
-
-out_no_v3:
- dfprintk(MOUNT, "NFS: nfs_mount_data version %d does not support v3\n",
- data->version);
- return -EINVAL;
-
-out_no_sec:
- dfprintk(MOUNT, "NFS: nfs_mount_data version supports only AUTH_SYS\n");
- return -EINVAL;
-
-out_nomem:
- dfprintk(MOUNT, "NFS: not enough memory to handle mount options\n");
- return -ENOMEM;
-
-out_no_address:
- dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n");
- return -EINVAL;
-
-out_invalid_fh:
- dfprintk(MOUNT, "NFS: invalid root filehandle\n");
- return -EINVAL;
-}
-
-#if IS_ENABLED(CONFIG_NFS_V4)
-static int nfs_validate_mount_data(struct file_system_type *fs_type,
- void *options,
- struct nfs_parsed_mount_data *args,
- struct nfs_fh *mntfh,
- const char *dev_name)
-{
- if (fs_type == &nfs_fs_type)
- return nfs23_validate_mount_data(options, args, mntfh, dev_name);
- return nfs4_validate_mount_data(options, args, dev_name);
-}
-#else
-static int nfs_validate_mount_data(struct file_system_type *fs_type,
- void *options,
- struct nfs_parsed_mount_data *args,
- struct nfs_fh *mntfh,
- const char *dev_name)
-{
- return nfs23_validate_mount_data(options, args, mntfh, dev_name);
-}
-#endif
-
-static int nfs_validate_text_mount_data(void *options,
- struct nfs_parsed_mount_data *args,
- const char *dev_name)
-{
- int port = 0;
- int max_namelen = PAGE_SIZE;
- int max_pathlen = NFS_MAXPATHLEN;
- struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address;
-
- if (nfs_parse_mount_options((char *)options, args) == 0)
- return -EINVAL;
-
- if (!nfs_verify_server_address(sap))
- goto out_no_address;
-
- if (args->version == 4) {
-#if IS_ENABLED(CONFIG_NFS_V4)
- if (args->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
- port = NFS_RDMA_PORT;
- else
- port = NFS_PORT;
- max_namelen = NFS4_MAXNAMLEN;
- max_pathlen = NFS4_MAXPATHLEN;
- nfs_validate_transport_protocol(args);
- if (args->nfs_server.protocol == XPRT_TRANSPORT_UDP)
- goto out_invalid_transport_udp;
- nfs4_validate_mount_flags(args);
-#else
- goto out_v4_not_compiled;
-#endif /* CONFIG_NFS_V4 */
- } else {
- nfs_set_mount_transport_protocol(args);
- if (args->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
- port = NFS_RDMA_PORT;
- }
-
- nfs_set_port(sap, &args->nfs_server.port, port);
-
- return nfs_parse_devname(dev_name,
- &args->nfs_server.hostname,
- max_namelen,
- &args->nfs_server.export_path,
- max_pathlen);
-
-#if !IS_ENABLED(CONFIG_NFS_V4)
-out_v4_not_compiled:
- dfprintk(MOUNT, "NFS: NFSv4 is not compiled into kernel\n");
- return -EPROTONOSUPPORT;
-#else
-out_invalid_transport_udp:
- dfprintk(MOUNT, "NFSv4: Unsupported transport protocol udp\n");
- return -EINVAL;
-#endif /* !CONFIG_NFS_V4 */
-
-out_no_address:
- dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n");
- return -EINVAL;
-}
-
#define NFS_REMOUNT_CMP_FLAGMASK ~(NFS_MOUNT_INTR \
| NFS_MOUNT_SECURE \
| NFS_MOUNT_TCP \
@@ -2735,113 +1431,6 @@ nfs_prepared_mount(struct file_system_type *fs_type, int flags,
#if IS_ENABLED(CONFIG_NFS_V4)
-static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *args)
-{
- args->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3|
- NFS_MOUNT_LOCAL_FLOCK|NFS_MOUNT_LOCAL_FCNTL);
-}
-
-/*
- * Validate NFSv4 mount options
- */
-static int nfs4_validate_mount_data(void *options,
- struct nfs_parsed_mount_data *args,
- const char *dev_name)
-{
- struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address;
- struct nfs4_mount_data *data = (struct nfs4_mount_data *)options;
- char *c;
-
- if (data == NULL)
- goto out_no_data;
-
- args->version = 4;
-
- switch (data->version) {
- case 1:
- if (data->host_addrlen > sizeof(args->nfs_server.address))
- goto out_no_address;
- if (data->host_addrlen == 0)
- goto out_no_address;
- args->nfs_server.addrlen = data->host_addrlen;
- if (copy_from_user(sap, data->host_addr, data->host_addrlen))
- return -EFAULT;
- if (!nfs_verify_server_address(sap))
- goto out_no_address;
- args->nfs_server.port = ntohs(((struct sockaddr_in *)sap)->sin_port);
-
- if (data->auth_flavourlen) {
- rpc_authflavor_t pseudoflavor;
- if (data->auth_flavourlen > 1)
- goto out_inval_auth;
- if (copy_from_user(&pseudoflavor,
- data->auth_flavours,
- sizeof(pseudoflavor)))
- return -EFAULT;
- args->selected_flavor = pseudoflavor;
- } else
- args->selected_flavor = RPC_AUTH_UNIX;
-
- c = strndup_user(data->hostname.data, NFS4_MAXNAMLEN);
- if (IS_ERR(c))
- return PTR_ERR(c);
- args->nfs_server.hostname = c;
-
- c = strndup_user(data->mnt_path.data, NFS4_MAXPATHLEN);
- if (IS_ERR(c))
- return PTR_ERR(c);
- args->nfs_server.export_path = c;
- dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", c);
-
- c = strndup_user(data->client_addr.data, 16);
- if (IS_ERR(c))
- return PTR_ERR(c);
- args->client_address = c;
-
- /*
- * Translate to nfs_parsed_mount_data, which nfs4_fill_super
- * can deal with.
- */
-
- args->flags = data->flags & NFS4_MOUNT_FLAGMASK;
- args->rsize = data->rsize;
- args->wsize = data->wsize;
- args->timeo = data->timeo;
- args->retrans = data->retrans;
- args->acregmin = data->acregmin;
- args->acregmax = data->acregmax;
- args->acdirmin = data->acdirmin;
- args->acdirmax = data->acdirmax;
- args->nfs_server.protocol = data->proto;
- nfs_validate_transport_protocol(args);
- if (args->nfs_server.protocol == XPRT_TRANSPORT_UDP)
- goto out_invalid_transport_udp;
-
- break;
- default:
- return NFS_TEXT_DATA;
- }
-
- return 0;
-
-out_no_data:
- dfprintk(MOUNT, "NFS4: mount program didn't pass any mount data\n");
- return -EINVAL;
-
-out_inval_auth:
- dfprintk(MOUNT, "NFS4: Invalid number of RPC auth flavours %d\n",
- data->auth_flavourlen);
- return -EINVAL;
-
-out_no_address:
- dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n");
- return -EINVAL;
-
-out_invalid_transport_udp:
- dfprintk(MOUNT, "NFSv4: Unsupported transport protocol udp\n");
- return -EINVAL;
-}
-
/*
* NFS v4 module parameters need to stay in the
* NFS client for backwards compatibility
--
2.17.2
^ permalink raw reply related
* [PATCH v6 18/27] NFS: Rename struct nfs_parsed_mount_data to struct nfs_fs_context
From: Scott Mayhew @ 2019-12-10 12:31 UTC (permalink / raw)
To: anna.schumaker, trond.myklebust
Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel,
linux-security-module
In-Reply-To: <20191210123115.1655-1-smayhew@redhat.com>
From: David Howells <dhowells@redhat.com>
Rename struct nfs_parsed_mount_data to struct nfs_fs_context and rename
pointers to it to "ctx". At some point this will be pointed to by an
fs_context struct's fs_private pointer.
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/nfs/client.c | 66 +++----
fs/nfs/fs_context.c | 446 ++++++++++++++++++++++----------------------
fs/nfs/internal.h | 14 +-
fs/nfs/nfs4client.c | 60 +++---
fs/nfs/nfs4super.c | 6 +-
fs/nfs/super.c | 194 +++++++++----------
6 files changed, 393 insertions(+), 393 deletions(-)
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index a2049747adc4..0a00df8e71bb 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -658,28 +658,28 @@ EXPORT_SYMBOL_GPL(nfs_init_client);
* Create a version 2 or 3 client
*/
static int nfs_init_server(struct nfs_server *server,
- const struct nfs_parsed_mount_data *data,
+ const struct nfs_fs_context *cfg,
struct nfs_subversion *nfs_mod)
{
struct rpc_timeout timeparms;
struct nfs_client_initdata cl_init = {
- .hostname = data->nfs_server.hostname,
- .addr = (const struct sockaddr *)&data->nfs_server.address,
- .addrlen = data->nfs_server.addrlen,
+ .hostname = cfg->nfs_server.hostname,
+ .addr = (const struct sockaddr *)&cfg->nfs_server.address,
+ .addrlen = cfg->nfs_server.addrlen,
.nfs_mod = nfs_mod,
- .proto = data->nfs_server.protocol,
- .net = data->net,
+ .proto = cfg->nfs_server.protocol,
+ .net = cfg->net,
.timeparms = &timeparms,
.cred = server->cred,
- .nconnect = data->nfs_server.nconnect,
+ .nconnect = cfg->nfs_server.nconnect,
.init_flags = (1UL << NFS_CS_REUSEPORT),
};
struct nfs_client *clp;
int error;
- nfs_init_timeout_values(&timeparms, data->nfs_server.protocol,
- data->timeo, data->retrans);
- if (data->flags & NFS_MOUNT_NORESVPORT)
+ nfs_init_timeout_values(&timeparms, cfg->nfs_server.protocol,
+ cfg->timeo, cfg->retrans);
+ if (cfg->flags & NFS_MOUNT_NORESVPORT)
set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
/* Allocate or find a client reference we can use */
@@ -690,46 +690,46 @@ static int nfs_init_server(struct nfs_server *server,
server->nfs_client = clp;
/* Initialise the client representation from the mount data */
- server->flags = data->flags;
- server->options = data->options;
+ server->flags = cfg->flags;
+ server->options = cfg->options;
server->caps |= NFS_CAP_HARDLINKS|NFS_CAP_SYMLINKS|NFS_CAP_FILEID|
NFS_CAP_MODE|NFS_CAP_NLINK|NFS_CAP_OWNER|NFS_CAP_OWNER_GROUP|
NFS_CAP_ATIME|NFS_CAP_CTIME|NFS_CAP_MTIME;
- if (data->rsize)
- server->rsize = nfs_block_size(data->rsize, NULL);
- if (data->wsize)
- server->wsize = nfs_block_size(data->wsize, NULL);
+ if (cfg->rsize)
+ server->rsize = nfs_block_size(cfg->rsize, NULL);
+ if (cfg->wsize)
+ server->wsize = nfs_block_size(cfg->wsize, NULL);
- server->acregmin = data->acregmin * HZ;
- server->acregmax = data->acregmax * HZ;
- server->acdirmin = data->acdirmin * HZ;
- server->acdirmax = data->acdirmax * HZ;
+ server->acregmin = cfg->acregmin * HZ;
+ server->acregmax = cfg->acregmax * HZ;
+ server->acdirmin = cfg->acdirmin * HZ;
+ server->acdirmax = cfg->acdirmax * HZ;
/* Start lockd here, before we might error out */
error = nfs_start_lockd(server);
if (error < 0)
goto error;
- server->port = data->nfs_server.port;
- server->auth_info = data->auth_info;
+ server->port = cfg->nfs_server.port;
+ server->auth_info = cfg->auth_info;
error = nfs_init_server_rpcclient(server, &timeparms,
- data->selected_flavor);
+ cfg->selected_flavor);
if (error < 0)
goto error;
/* Preserve the values of mount_server-related mount options */
- if (data->mount_server.addrlen) {
- memcpy(&server->mountd_address, &data->mount_server.address,
- data->mount_server.addrlen);
- server->mountd_addrlen = data->mount_server.addrlen;
+ if (cfg->mount_server.addrlen) {
+ memcpy(&server->mountd_address, &cfg->mount_server.address,
+ cfg->mount_server.addrlen);
+ server->mountd_addrlen = cfg->mount_server.addrlen;
}
- server->mountd_version = data->mount_server.version;
- server->mountd_port = data->mount_server.port;
- server->mountd_protocol = data->mount_server.protocol;
+ server->mountd_version = cfg->mount_server.version;
+ server->mountd_port = cfg->mount_server.port;
+ server->mountd_protocol = cfg->mount_server.protocol;
- server->namelen = data->namlen;
+ server->namelen = cfg->namlen;
return 0;
error:
@@ -970,7 +970,7 @@ struct nfs_server *nfs_create_server(struct nfs_mount_info *mount_info)
goto error;
/* Get a client representation */
- error = nfs_init_server(server, mount_info->parsed, nfs_mod);
+ error = nfs_init_server(server, mount_info->ctx, nfs_mod);
if (error < 0)
goto error;
@@ -981,7 +981,7 @@ struct nfs_server *nfs_create_server(struct nfs_mount_info *mount_info)
if (server->nfs_client->rpc_ops->version == 3) {
if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
server->namelen = NFS3_MAXNAMLEN;
- if (!(mount_info->parsed->flags & NFS_MOUNT_NORDIRPLUS))
+ if (!(mount_info->ctx->flags & NFS_MOUNT_NORDIRPLUS))
server->caps |= NFS_CAP_READDIRPLUS;
} else {
if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN)
diff --git a/fs/nfs/fs_context.c b/fs/nfs/fs_context.c
index 8fbfd526d6b8..52aa2b8522f0 100644
--- a/fs/nfs/fs_context.c
+++ b/fs/nfs/fs_context.c
@@ -242,40 +242,40 @@ static const match_table_t nfs_vers_tokens = {
{ Opt_vers_err, NULL }
};
-struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(void)
+struct nfs_fs_context *nfs_alloc_parsed_mount_data(void)
{
- struct nfs_parsed_mount_data *data;
-
- data = kzalloc(sizeof(*data), GFP_KERNEL);
- if (data) {
- data->timeo = NFS_UNSPEC_TIMEO;
- data->retrans = NFS_UNSPEC_RETRANS;
- data->acregmin = NFS_DEF_ACREGMIN;
- data->acregmax = NFS_DEF_ACREGMAX;
- data->acdirmin = NFS_DEF_ACDIRMIN;
- data->acdirmax = NFS_DEF_ACDIRMAX;
- data->mount_server.port = NFS_UNSPEC_PORT;
- data->nfs_server.port = NFS_UNSPEC_PORT;
- data->nfs_server.protocol = XPRT_TRANSPORT_TCP;
- data->selected_flavor = RPC_AUTH_MAXFLAVOR;
- data->minorversion = 0;
- data->need_mount = true;
- data->net = current->nsproxy->net_ns;
- data->lsm_opts = NULL;
+ struct nfs_fs_context *ctx;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (ctx) {
+ ctx->timeo = NFS_UNSPEC_TIMEO;
+ ctx->retrans = NFS_UNSPEC_RETRANS;
+ ctx->acregmin = NFS_DEF_ACREGMIN;
+ ctx->acregmax = NFS_DEF_ACREGMAX;
+ ctx->acdirmin = NFS_DEF_ACDIRMIN;
+ ctx->acdirmax = NFS_DEF_ACDIRMAX;
+ ctx->mount_server.port = NFS_UNSPEC_PORT;
+ ctx->nfs_server.port = NFS_UNSPEC_PORT;
+ ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP;
+ ctx->selected_flavor = RPC_AUTH_MAXFLAVOR;
+ ctx->minorversion = 0;
+ ctx->need_mount = true;
+ ctx->net = current->nsproxy->net_ns;
+ ctx->lsm_opts = NULL;
}
- return data;
+ return ctx;
}
-void nfs_free_parsed_mount_data(struct nfs_parsed_mount_data *data)
+void nfs_free_parsed_mount_data(struct nfs_fs_context *ctx)
{
- if (data) {
- kfree(data->client_address);
- kfree(data->mount_server.hostname);
- kfree(data->nfs_server.export_path);
- kfree(data->nfs_server.hostname);
- kfree(data->fscache_uniq);
- security_free_mnt_opts(&data->lsm_opts);
- kfree(data);
+ if (ctx) {
+ kfree(ctx->client_address);
+ kfree(ctx->mount_server.hostname);
+ kfree(ctx->nfs_server.export_path);
+ kfree(ctx->nfs_server.hostname);
+ kfree(ctx->fscache_uniq);
+ security_free_mnt_opts(&ctx->lsm_opts);
+ kfree(ctx);
}
}
@@ -306,15 +306,15 @@ static int nfs_verify_server_address(struct sockaddr *addr)
* Sanity check the NFS transport protocol.
*
*/
-static void nfs_validate_transport_protocol(struct nfs_parsed_mount_data *mnt)
+static void nfs_validate_transport_protocol(struct nfs_fs_context *ctx)
{
- switch (mnt->nfs_server.protocol) {
+ switch (ctx->nfs_server.protocol) {
case XPRT_TRANSPORT_UDP:
case XPRT_TRANSPORT_TCP:
case XPRT_TRANSPORT_RDMA:
break;
default:
- mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
+ ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP;
}
}
@@ -322,20 +322,20 @@ static void nfs_validate_transport_protocol(struct nfs_parsed_mount_data *mnt)
* For text based NFSv2/v3 mounts, the mount protocol transport default
* settings should depend upon the specified NFS transport.
*/
-static void nfs_set_mount_transport_protocol(struct nfs_parsed_mount_data *mnt)
+static void nfs_set_mount_transport_protocol(struct nfs_fs_context *ctx)
{
- nfs_validate_transport_protocol(mnt);
+ nfs_validate_transport_protocol(ctx);
- if (mnt->mount_server.protocol == XPRT_TRANSPORT_UDP ||
- mnt->mount_server.protocol == XPRT_TRANSPORT_TCP)
+ if (ctx->mount_server.protocol == XPRT_TRANSPORT_UDP ||
+ ctx->mount_server.protocol == XPRT_TRANSPORT_TCP)
return;
- switch (mnt->nfs_server.protocol) {
+ switch (ctx->nfs_server.protocol) {
case XPRT_TRANSPORT_UDP:
- mnt->mount_server.protocol = XPRT_TRANSPORT_UDP;
+ ctx->mount_server.protocol = XPRT_TRANSPORT_UDP;
break;
case XPRT_TRANSPORT_TCP:
case XPRT_TRANSPORT_RDMA:
- mnt->mount_server.protocol = XPRT_TRANSPORT_TCP;
+ ctx->mount_server.protocol = XPRT_TRANSPORT_TCP;
}
}
@@ -367,8 +367,7 @@ static bool nfs_auth_info_add(struct nfs_auth_info *auth_info,
/*
* Parse the value of the 'sec=' option.
*/
-static int nfs_parse_security_flavors(char *value,
- struct nfs_parsed_mount_data *mnt)
+static int nfs_parse_security_flavors(char *value, struct nfs_fs_context *ctx)
{
substring_t args[MAX_OPT_ARGS];
rpc_authflavor_t pseudoflavor;
@@ -417,7 +416,7 @@ static int nfs_parse_security_flavors(char *value,
return 0;
}
- if (!nfs_auth_info_add(&mnt->auth_info, pseudoflavor))
+ if (!nfs_auth_info_add(&ctx->auth_info, pseudoflavor))
return 0;
}
@@ -425,36 +424,36 @@ static int nfs_parse_security_flavors(char *value,
}
static int nfs_parse_version_string(char *string,
- struct nfs_parsed_mount_data *mnt,
+ struct nfs_fs_context *ctx,
substring_t *args)
{
- mnt->flags &= ~NFS_MOUNT_VER3;
+ ctx->flags &= ~NFS_MOUNT_VER3;
switch (match_token(string, nfs_vers_tokens, args)) {
case Opt_vers_2:
- mnt->version = 2;
+ ctx->version = 2;
break;
case Opt_vers_3:
- mnt->flags |= NFS_MOUNT_VER3;
- mnt->version = 3;
+ ctx->flags |= NFS_MOUNT_VER3;
+ ctx->version = 3;
break;
case Opt_vers_4:
/* Backward compatibility option. In future,
* the mount program should always supply
* a NFSv4 minor version number.
*/
- mnt->version = 4;
+ ctx->version = 4;
break;
case Opt_vers_4_0:
- mnt->version = 4;
- mnt->minorversion = 0;
+ ctx->version = 4;
+ ctx->minorversion = 0;
break;
case Opt_vers_4_1:
- mnt->version = 4;
- mnt->minorversion = 1;
+ ctx->version = 4;
+ ctx->minorversion = 1;
break;
case Opt_vers_4_2:
- mnt->version = 4;
- mnt->minorversion = 2;
+ ctx->version = 4;
+ ctx->minorversion = 2;
break;
default:
return 0;
@@ -502,7 +501,7 @@ static int nfs_get_option_ul_bound(substring_t args[], unsigned long *option,
* skipped as they are encountered. If there were no errors, return 1;
* otherwise return 0 (zero).
*/
-int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
+int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx)
{
char *p, *string;
int rc, sloppy = 0, invalid_option = 0;
@@ -515,7 +514,7 @@ int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
}
dfprintk(MOUNT, "NFS: nfs mount opts='%s'\n", raw);
- rc = security_sb_eat_lsm_opts(raw, &mnt->lsm_opts);
+ rc = security_sb_eat_lsm_opts(raw, &ctx->lsm_opts);
if (rc)
goto out_security_failure;
@@ -536,96 +535,96 @@ int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
* boolean options: foo/nofoo
*/
case Opt_soft:
- mnt->flags |= NFS_MOUNT_SOFT;
- mnt->flags &= ~NFS_MOUNT_SOFTERR;
+ ctx->flags |= NFS_MOUNT_SOFT;
+ ctx->flags &= ~NFS_MOUNT_SOFTERR;
break;
case Opt_softerr:
- mnt->flags |= NFS_MOUNT_SOFTERR;
- mnt->flags &= ~NFS_MOUNT_SOFT;
+ ctx->flags |= NFS_MOUNT_SOFTERR;
+ ctx->flags &= ~NFS_MOUNT_SOFT;
break;
case Opt_hard:
- mnt->flags &= ~(NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR);
+ ctx->flags &= ~(NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR);
break;
case Opt_posix:
- mnt->flags |= NFS_MOUNT_POSIX;
+ ctx->flags |= NFS_MOUNT_POSIX;
break;
case Opt_noposix:
- mnt->flags &= ~NFS_MOUNT_POSIX;
+ ctx->flags &= ~NFS_MOUNT_POSIX;
break;
case Opt_cto:
- mnt->flags &= ~NFS_MOUNT_NOCTO;
+ ctx->flags &= ~NFS_MOUNT_NOCTO;
break;
case Opt_nocto:
- mnt->flags |= NFS_MOUNT_NOCTO;
+ ctx->flags |= NFS_MOUNT_NOCTO;
break;
case Opt_ac:
- mnt->flags &= ~NFS_MOUNT_NOAC;
+ ctx->flags &= ~NFS_MOUNT_NOAC;
break;
case Opt_noac:
- mnt->flags |= NFS_MOUNT_NOAC;
+ ctx->flags |= NFS_MOUNT_NOAC;
break;
case Opt_lock:
- mnt->flags &= ~NFS_MOUNT_NONLM;
- mnt->flags &= ~(NFS_MOUNT_LOCAL_FLOCK |
+ ctx->flags &= ~NFS_MOUNT_NONLM;
+ ctx->flags &= ~(NFS_MOUNT_LOCAL_FLOCK |
NFS_MOUNT_LOCAL_FCNTL);
break;
case Opt_nolock:
- mnt->flags |= NFS_MOUNT_NONLM;
- mnt->flags |= (NFS_MOUNT_LOCAL_FLOCK |
+ ctx->flags |= NFS_MOUNT_NONLM;
+ ctx->flags |= (NFS_MOUNT_LOCAL_FLOCK |
NFS_MOUNT_LOCAL_FCNTL);
break;
case Opt_udp:
- mnt->flags &= ~NFS_MOUNT_TCP;
- mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
+ ctx->flags &= ~NFS_MOUNT_TCP;
+ ctx->nfs_server.protocol = XPRT_TRANSPORT_UDP;
break;
case Opt_tcp:
- mnt->flags |= NFS_MOUNT_TCP;
- mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
+ ctx->flags |= NFS_MOUNT_TCP;
+ ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP;
break;
case Opt_rdma:
- mnt->flags |= NFS_MOUNT_TCP; /* for side protocols */
- mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
+ ctx->flags |= NFS_MOUNT_TCP; /* for side protocols */
+ ctx->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
xprt_load_transport(p);
break;
case Opt_acl:
- mnt->flags &= ~NFS_MOUNT_NOACL;
+ ctx->flags &= ~NFS_MOUNT_NOACL;
break;
case Opt_noacl:
- mnt->flags |= NFS_MOUNT_NOACL;
+ ctx->flags |= NFS_MOUNT_NOACL;
break;
case Opt_rdirplus:
- mnt->flags &= ~NFS_MOUNT_NORDIRPLUS;
+ ctx->flags &= ~NFS_MOUNT_NORDIRPLUS;
break;
case Opt_nordirplus:
- mnt->flags |= NFS_MOUNT_NORDIRPLUS;
+ ctx->flags |= NFS_MOUNT_NORDIRPLUS;
break;
case Opt_sharecache:
- mnt->flags &= ~NFS_MOUNT_UNSHARED;
+ ctx->flags &= ~NFS_MOUNT_UNSHARED;
break;
case Opt_nosharecache:
- mnt->flags |= NFS_MOUNT_UNSHARED;
+ ctx->flags |= NFS_MOUNT_UNSHARED;
break;
case Opt_resvport:
- mnt->flags &= ~NFS_MOUNT_NORESVPORT;
+ ctx->flags &= ~NFS_MOUNT_NORESVPORT;
break;
case Opt_noresvport:
- mnt->flags |= NFS_MOUNT_NORESVPORT;
+ ctx->flags |= NFS_MOUNT_NORESVPORT;
break;
case Opt_fscache:
- mnt->options |= NFS_OPTION_FSCACHE;
- kfree(mnt->fscache_uniq);
- mnt->fscache_uniq = NULL;
+ ctx->options |= NFS_OPTION_FSCACHE;
+ kfree(ctx->fscache_uniq);
+ ctx->fscache_uniq = NULL;
break;
case Opt_nofscache:
- mnt->options &= ~NFS_OPTION_FSCACHE;
- kfree(mnt->fscache_uniq);
- mnt->fscache_uniq = NULL;
+ ctx->options &= ~NFS_OPTION_FSCACHE;
+ kfree(ctx->fscache_uniq);
+ ctx->fscache_uniq = NULL;
break;
case Opt_migration:
- mnt->options |= NFS_OPTION_MIGRATION;
+ ctx->options |= NFS_OPTION_MIGRATION;
break;
case Opt_nomigration:
- mnt->options &= ~NFS_OPTION_MIGRATION;
+ ctx->options &= ~NFS_OPTION_MIGRATION;
break;
/*
@@ -635,83 +634,83 @@ int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
if (nfs_get_option_ul(args, &option) ||
option > USHRT_MAX)
goto out_invalid_value;
- mnt->nfs_server.port = option;
+ ctx->nfs_server.port = option;
break;
case Opt_rsize:
if (nfs_get_option_ul(args, &option))
goto out_invalid_value;
- mnt->rsize = option;
+ ctx->rsize = option;
break;
case Opt_wsize:
if (nfs_get_option_ul(args, &option))
goto out_invalid_value;
- mnt->wsize = option;
+ ctx->wsize = option;
break;
case Opt_bsize:
if (nfs_get_option_ul(args, &option))
goto out_invalid_value;
- mnt->bsize = option;
+ ctx->bsize = option;
break;
case Opt_timeo:
if (nfs_get_option_ul_bound(args, &option, 1, INT_MAX))
goto out_invalid_value;
- mnt->timeo = option;
+ ctx->timeo = option;
break;
case Opt_retrans:
if (nfs_get_option_ul_bound(args, &option, 0, INT_MAX))
goto out_invalid_value;
- mnt->retrans = option;
+ ctx->retrans = option;
break;
case Opt_acregmin:
if (nfs_get_option_ul(args, &option))
goto out_invalid_value;
- mnt->acregmin = option;
+ ctx->acregmin = option;
break;
case Opt_acregmax:
if (nfs_get_option_ul(args, &option))
goto out_invalid_value;
- mnt->acregmax = option;
+ ctx->acregmax = option;
break;
case Opt_acdirmin:
if (nfs_get_option_ul(args, &option))
goto out_invalid_value;
- mnt->acdirmin = option;
+ ctx->acdirmin = option;
break;
case Opt_acdirmax:
if (nfs_get_option_ul(args, &option))
goto out_invalid_value;
- mnt->acdirmax = option;
+ ctx->acdirmax = option;
break;
case Opt_actimeo:
if (nfs_get_option_ul(args, &option))
goto out_invalid_value;
- mnt->acregmin = mnt->acregmax =
- mnt->acdirmin = mnt->acdirmax = option;
+ ctx->acregmin = ctx->acregmax =
+ ctx->acdirmin = ctx->acdirmax = option;
break;
case Opt_namelen:
if (nfs_get_option_ul(args, &option))
goto out_invalid_value;
- mnt->namlen = option;
+ ctx->namlen = option;
break;
case Opt_mountport:
if (nfs_get_option_ul(args, &option) ||
option > USHRT_MAX)
goto out_invalid_value;
- mnt->mount_server.port = option;
+ ctx->mount_server.port = option;
break;
case Opt_mountvers:
if (nfs_get_option_ul(args, &option) ||
option < NFS_MNT_VERSION ||
option > NFS_MNT3_VERSION)
goto out_invalid_value;
- mnt->mount_server.version = option;
+ ctx->mount_server.version = option;
break;
case Opt_minorversion:
if (nfs_get_option_ul(args, &option))
goto out_invalid_value;
if (option > NFS4_MAX_MINOR_VERSION)
goto out_invalid_value;
- mnt->minorversion = option;
+ ctx->minorversion = option;
break;
/*
@@ -721,7 +720,7 @@ int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
string = match_strdup(args);
if (string == NULL)
goto out_nomem;
- rc = nfs_parse_version_string(string, mnt, args);
+ rc = nfs_parse_version_string(string, ctx, args);
kfree(string);
if (!rc)
goto out_invalid_value;
@@ -730,7 +729,7 @@ int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
string = match_strdup(args);
if (string == NULL)
goto out_nomem;
- rc = nfs_parse_security_flavors(string, mnt);
+ rc = nfs_parse_security_flavors(string, ctx);
kfree(string);
if (!rc) {
dfprintk(MOUNT, "NFS: unrecognized "
@@ -751,23 +750,23 @@ int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
protofamily = AF_INET6;
/* fall through */
case Opt_xprt_udp:
- mnt->flags &= ~NFS_MOUNT_TCP;
- mnt->nfs_server.protocol = XPRT_TRANSPORT_UDP;
+ ctx->flags &= ~NFS_MOUNT_TCP;
+ ctx->nfs_server.protocol = XPRT_TRANSPORT_UDP;
break;
case Opt_xprt_tcp6:
protofamily = AF_INET6;
/* fall through */
case Opt_xprt_tcp:
- mnt->flags |= NFS_MOUNT_TCP;
- mnt->nfs_server.protocol = XPRT_TRANSPORT_TCP;
+ ctx->flags |= NFS_MOUNT_TCP;
+ ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP;
break;
case Opt_xprt_rdma6:
protofamily = AF_INET6;
/* fall through */
case Opt_xprt_rdma:
/* vector side protocols to TCP */
- mnt->flags |= NFS_MOUNT_TCP;
- mnt->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
+ ctx->flags |= NFS_MOUNT_TCP;
+ ctx->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
xprt_load_transport(string);
break;
default:
@@ -792,13 +791,13 @@ int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
mountfamily = AF_INET6;
/* fall through */
case Opt_xprt_udp:
- mnt->mount_server.protocol = XPRT_TRANSPORT_UDP;
+ ctx->mount_server.protocol = XPRT_TRANSPORT_UDP;
break;
case Opt_xprt_tcp6:
mountfamily = AF_INET6;
/* fall through */
case Opt_xprt_tcp:
- mnt->mount_server.protocol = XPRT_TRANSPORT_TCP;
+ ctx->mount_server.protocol = XPRT_TRANSPORT_TCP;
break;
case Opt_xprt_rdma: /* not used for side protocols */
default:
@@ -811,41 +810,41 @@ int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
string = match_strdup(args);
if (string == NULL)
goto out_nomem;
- mnt->nfs_server.addrlen =
- rpc_pton(mnt->net, string, strlen(string),
+ ctx->nfs_server.addrlen =
+ rpc_pton(ctx->net, string, strlen(string),
(struct sockaddr *)
- &mnt->nfs_server.address,
- sizeof(mnt->nfs_server.address));
+ &ctx->nfs_server.address,
+ sizeof(ctx->nfs_server.address));
kfree(string);
- if (mnt->nfs_server.addrlen == 0)
+ if (ctx->nfs_server.addrlen == 0)
goto out_invalid_address;
break;
case Opt_clientaddr:
- if (nfs_get_option_str(args, &mnt->client_address))
+ if (nfs_get_option_str(args, &ctx->client_address))
goto out_nomem;
break;
case Opt_mounthost:
if (nfs_get_option_str(args,
- &mnt->mount_server.hostname))
+ &ctx->mount_server.hostname))
goto out_nomem;
break;
case Opt_mountaddr:
string = match_strdup(args);
if (string == NULL)
goto out_nomem;
- mnt->mount_server.addrlen =
- rpc_pton(mnt->net, string, strlen(string),
+ ctx->mount_server.addrlen =
+ rpc_pton(ctx->net, string, strlen(string),
(struct sockaddr *)
- &mnt->mount_server.address,
- sizeof(mnt->mount_server.address));
+ &ctx->mount_server.address,
+ sizeof(ctx->mount_server.address));
kfree(string);
- if (mnt->mount_server.addrlen == 0)
+ if (ctx->mount_server.addrlen == 0)
goto out_invalid_address;
break;
case Opt_nconnect:
if (nfs_get_option_ul_bound(args, &option, 1, NFS_MAX_CONNECTIONS))
goto out_invalid_value;
- mnt->nfs_server.nconnect = option;
+ ctx->nfs_server.nconnect = option;
break;
case Opt_lookupcache:
string = match_strdup(args);
@@ -856,14 +855,14 @@ int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
kfree(string);
switch (token) {
case Opt_lookupcache_all:
- mnt->flags &= ~(NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE);
+ ctx->flags &= ~(NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE);
break;
case Opt_lookupcache_positive:
- mnt->flags &= ~NFS_MOUNT_LOOKUP_CACHE_NONE;
- mnt->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG;
+ ctx->flags &= ~NFS_MOUNT_LOOKUP_CACHE_NONE;
+ ctx->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG;
break;
case Opt_lookupcache_none:
- mnt->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE;
+ ctx->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE;
break;
default:
dfprintk(MOUNT, "NFS: invalid "
@@ -872,9 +871,9 @@ int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
}
break;
case Opt_fscache_uniq:
- if (nfs_get_option_str(args, &mnt->fscache_uniq))
+ if (nfs_get_option_str(args, &ctx->fscache_uniq))
goto out_nomem;
- mnt->options |= NFS_OPTION_FSCACHE;
+ ctx->options |= NFS_OPTION_FSCACHE;
break;
case Opt_local_lock:
string = match_strdup(args);
@@ -885,17 +884,17 @@ int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
kfree(string);
switch (token) {
case Opt_local_lock_all:
- mnt->flags |= (NFS_MOUNT_LOCAL_FLOCK |
+ ctx->flags |= (NFS_MOUNT_LOCAL_FLOCK |
NFS_MOUNT_LOCAL_FCNTL);
break;
case Opt_local_lock_flock:
- mnt->flags |= NFS_MOUNT_LOCAL_FLOCK;
+ ctx->flags |= NFS_MOUNT_LOCAL_FLOCK;
break;
case Opt_local_lock_posix:
- mnt->flags |= NFS_MOUNT_LOCAL_FCNTL;
+ ctx->flags |= NFS_MOUNT_LOCAL_FCNTL;
break;
case Opt_local_lock_none:
- mnt->flags &= ~(NFS_MOUNT_LOCAL_FLOCK |
+ ctx->flags &= ~(NFS_MOUNT_LOCAL_FLOCK |
NFS_MOUNT_LOCAL_FCNTL);
break;
default:
@@ -928,11 +927,11 @@ int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
if (!sloppy && invalid_option)
return 0;
- if (mnt->minorversion && mnt->version != 4)
+ if (ctx->minorversion && ctx->version != 4)
goto out_minorversion_mismatch;
- if (mnt->options & NFS_OPTION_MIGRATION &&
- (mnt->version != 4 || mnt->minorversion != 0))
+ if (ctx->options & NFS_OPTION_MIGRATION &&
+ (ctx->version != 4 || ctx->minorversion != 0))
goto out_migration_misuse;
/*
@@ -940,15 +939,15 @@ int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
* families in the addr=/mountaddr= options.
*/
if (protofamily != AF_UNSPEC &&
- protofamily != mnt->nfs_server.address.ss_family)
+ protofamily != ctx->nfs_server.address.ss_family)
goto out_proto_mismatch;
if (mountfamily != AF_UNSPEC) {
- if (mnt->mount_server.addrlen) {
- if (mountfamily != mnt->mount_server.address.ss_family)
+ if (ctx->mount_server.addrlen) {
+ if (mountfamily != ctx->mount_server.address.ss_family)
goto out_mountproto_mismatch;
} else {
- if (mountfamily != mnt->nfs_server.address.ss_family)
+ if (mountfamily != ctx->nfs_server.address.ss_family)
goto out_mountproto_mismatch;
}
}
@@ -970,7 +969,7 @@ int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt)
return 0;
out_minorversion_mismatch:
printk(KERN_INFO "NFS: mount option vers=%u does not support "
- "minorversion=%u\n", mnt->version, mnt->minorversion);
+ "minorversion=%u\n", ctx->version, ctx->minorversion);
return 0;
out_migration_misuse:
printk(KERN_INFO
@@ -1078,18 +1077,18 @@ static int nfs_parse_devname(const char *dev_name,
* mountproto=tcp after mountproto=udp, and so on
*/
static int nfs23_validate_mount_data(void *options,
- struct nfs_parsed_mount_data *args,
+ struct nfs_fs_context *ctx,
struct nfs_fh *mntfh,
const char *dev_name)
{
struct nfs_mount_data *data = (struct nfs_mount_data *)options;
- struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address;
+ struct sockaddr *sap = (struct sockaddr *)&ctx->nfs_server.address;
int extra_flags = NFS_MOUNT_LEGACY_INTERFACE;
if (data == NULL)
goto out_no_data;
- args->version = NFS_DEFAULT_VERSION;
+ ctx->version = NFS_DEFAULT_VERSION;
switch (data->version) {
case 1:
data->namlen = 0; /* fall through */
@@ -1115,10 +1114,10 @@ static int nfs23_validate_mount_data(void *options,
if (data->root.size > NFS3_FHSIZE || data->root.size == 0)
goto out_invalid_fh;
mntfh->size = data->root.size;
- args->version = 3;
+ ctx->version = 3;
} else {
mntfh->size = NFS2_FHSIZE;
- args->version = 2;
+ ctx->version = 2;
}
@@ -1128,47 +1127,47 @@ static int nfs23_validate_mount_data(void *options,
sizeof(mntfh->data) - mntfh->size);
/*
- * Translate to nfs_parsed_mount_data, which nfs_fill_super
+ * Translate to nfs_fs_context, which nfs_fill_super
* can deal with.
*/
- args->flags = data->flags & NFS_MOUNT_FLAGMASK;
- args->flags |= extra_flags;
- args->rsize = data->rsize;
- args->wsize = data->wsize;
- args->timeo = data->timeo;
- args->retrans = data->retrans;
- args->acregmin = data->acregmin;
- args->acregmax = data->acregmax;
- args->acdirmin = data->acdirmin;
- args->acdirmax = data->acdirmax;
- args->need_mount = false;
+ ctx->flags = data->flags & NFS_MOUNT_FLAGMASK;
+ ctx->flags |= extra_flags;
+ ctx->rsize = data->rsize;
+ ctx->wsize = data->wsize;
+ ctx->timeo = data->timeo;
+ ctx->retrans = data->retrans;
+ ctx->acregmin = data->acregmin;
+ ctx->acregmax = data->acregmax;
+ ctx->acdirmin = data->acdirmin;
+ ctx->acdirmax = data->acdirmax;
+ ctx->need_mount = false;
memcpy(sap, &data->addr, sizeof(data->addr));
- args->nfs_server.addrlen = sizeof(data->addr);
- args->nfs_server.port = ntohs(data->addr.sin_port);
+ ctx->nfs_server.addrlen = sizeof(data->addr);
+ ctx->nfs_server.port = ntohs(data->addr.sin_port);
if (sap->sa_family != AF_INET ||
!nfs_verify_server_address(sap))
goto out_no_address;
if (!(data->flags & NFS_MOUNT_TCP))
- args->nfs_server.protocol = XPRT_TRANSPORT_UDP;
+ ctx->nfs_server.protocol = XPRT_TRANSPORT_UDP;
/* N.B. caller will free nfs_server.hostname in all cases */
- args->nfs_server.hostname = kstrdup(data->hostname, GFP_KERNEL);
- args->namlen = data->namlen;
- args->bsize = data->bsize;
+ ctx->nfs_server.hostname = kstrdup(data->hostname, GFP_KERNEL);
+ ctx->namlen = data->namlen;
+ ctx->bsize = data->bsize;
if (data->flags & NFS_MOUNT_SECFLAVOUR)
- args->selected_flavor = data->pseudoflavor;
+ ctx->selected_flavor = data->pseudoflavor;
else
- args->selected_flavor = RPC_AUTH_UNIX;
- if (!args->nfs_server.hostname)
+ ctx->selected_flavor = RPC_AUTH_UNIX;
+ if (!ctx->nfs_server.hostname)
goto out_nomem;
if (!(data->flags & NFS_MOUNT_NONLM))
- args->flags &= ~(NFS_MOUNT_LOCAL_FLOCK|
+ ctx->flags &= ~(NFS_MOUNT_LOCAL_FLOCK|
NFS_MOUNT_LOCAL_FCNTL);
else
- args->flags |= (NFS_MOUNT_LOCAL_FLOCK|
+ ctx->flags |= (NFS_MOUNT_LOCAL_FLOCK|
NFS_MOUNT_LOCAL_FCNTL);
/*
* The legacy version 6 binary mount data from userspace has a
@@ -1183,7 +1182,7 @@ static int nfs23_validate_mount_data(void *options,
int rc;
data->context[NFS_MAX_CONTEXT_LEN] = '\0';
rc = security_add_mnt_opt("context", data->context,
- strlen(data->context), &args->lsm_opts);
+ strlen(data->context), ctx->lsm_opts);
if (rc)
return rc;
#else
@@ -1225,10 +1224,9 @@ static int nfs23_validate_mount_data(void *options,
}
#if IS_ENABLED(CONFIG_NFS_V4)
-
-static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *args)
+static void nfs4_validate_mount_flags(struct nfs_fs_context *ctx)
{
- args->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3|
+ ctx->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3|
NFS_MOUNT_LOCAL_FLOCK|NFS_MOUNT_LOCAL_FCNTL);
}
@@ -1236,30 +1234,30 @@ static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *args)
* Validate NFSv4 mount options
*/
static int nfs4_validate_mount_data(void *options,
- struct nfs_parsed_mount_data *args,
+ struct nfs_fs_context *ctx,
const char *dev_name)
{
- struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address;
+ struct sockaddr *sap = (struct sockaddr *)&ctx->nfs_server.address;
struct nfs4_mount_data *data = (struct nfs4_mount_data *)options;
char *c;
if (data == NULL)
goto out_no_data;
- args->version = 4;
+ ctx->version = 4;
switch (data->version) {
case 1:
- if (data->host_addrlen > sizeof(args->nfs_server.address))
+ if (data->host_addrlen > sizeof(ctx->nfs_server.address))
goto out_no_address;
if (data->host_addrlen == 0)
goto out_no_address;
- args->nfs_server.addrlen = data->host_addrlen;
+ ctx->nfs_server.addrlen = data->host_addrlen;
if (copy_from_user(sap, data->host_addr, data->host_addrlen))
return -EFAULT;
if (!nfs_verify_server_address(sap))
goto out_no_address;
- args->nfs_server.port = ntohs(((struct sockaddr_in *)sap)->sin_port);
+ ctx->nfs_server.port = ntohs(((struct sockaddr_in *)sap)->sin_port);
if (data->auth_flavourlen) {
rpc_authflavor_t pseudoflavor;
@@ -1269,43 +1267,43 @@ static int nfs4_validate_mount_data(void *options,
data->auth_flavours,
sizeof(pseudoflavor)))
return -EFAULT;
- args->selected_flavor = pseudoflavor;
+ ctx->selected_flavor = pseudoflavor;
} else
- args->selected_flavor = RPC_AUTH_UNIX;
+ ctx->selected_flavor = RPC_AUTH_UNIX;
c = strndup_user(data->hostname.data, NFS4_MAXNAMLEN);
if (IS_ERR(c))
return PTR_ERR(c);
- args->nfs_server.hostname = c;
+ ctx->nfs_server.hostname = c;
c = strndup_user(data->mnt_path.data, NFS4_MAXPATHLEN);
if (IS_ERR(c))
return PTR_ERR(c);
- args->nfs_server.export_path = c;
+ ctx->nfs_server.export_path = c;
dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", c);
c = strndup_user(data->client_addr.data, 16);
if (IS_ERR(c))
return PTR_ERR(c);
- args->client_address = c;
+ ctx->client_address = c;
/*
- * Translate to nfs_parsed_mount_data, which nfs4_fill_super
+ * Translate to nfs_fs_context, which nfs4_fill_super
* can deal with.
*/
- args->flags = data->flags & NFS4_MOUNT_FLAGMASK;
- args->rsize = data->rsize;
- args->wsize = data->wsize;
- args->timeo = data->timeo;
- args->retrans = data->retrans;
- args->acregmin = data->acregmin;
- args->acregmax = data->acregmax;
- args->acdirmin = data->acdirmin;
- args->acdirmax = data->acdirmax;
- args->nfs_server.protocol = data->proto;
- nfs_validate_transport_protocol(args);
- if (args->nfs_server.protocol == XPRT_TRANSPORT_UDP)
+ ctx->flags = data->flags & NFS4_MOUNT_FLAGMASK;
+ ctx->rsize = data->rsize;
+ ctx->wsize = data->wsize;
+ ctx->timeo = data->timeo;
+ ctx->retrans = data->retrans;
+ ctx->acregmin = data->acregmin;
+ ctx->acregmax = data->acregmax;
+ ctx->acdirmin = data->acdirmin;
+ ctx->acdirmax = data->acdirmax;
+ ctx->nfs_server.protocol = data->proto;
+ nfs_validate_transport_protocol(ctx);
+ if (ctx->nfs_server.protocol == XPRT_TRANSPORT_UDP)
goto out_invalid_transport_udp;
break;
@@ -1335,67 +1333,67 @@ static int nfs4_validate_mount_data(void *options,
int nfs_validate_mount_data(struct file_system_type *fs_type,
void *options,
- struct nfs_parsed_mount_data *args,
+ struct nfs_fs_context *ctx,
struct nfs_fh *mntfh,
const char *dev_name)
{
if (fs_type == &nfs_fs_type)
- return nfs23_validate_mount_data(options, args, mntfh, dev_name);
- return nfs4_validate_mount_data(options, args, dev_name);
+ return nfs23_validate_mount_data(options, ctx, mntfh, dev_name);
+ return nfs4_validate_mount_data(options, ctx, dev_name);
}
#else
int nfs_validate_mount_data(struct file_system_type *fs_type,
void *options,
- struct nfs_parsed_mount_data *args,
+ struct nfs_fs_context *ctx,
struct nfs_fh *mntfh,
const char *dev_name)
{
- return nfs23_validate_mount_data(options, args, mntfh, dev_name);
+ return nfs23_validate_mount_data(options, ctx, mntfh, dev_name);
}
#endif
int nfs_validate_text_mount_data(void *options,
- struct nfs_parsed_mount_data *args,
+ struct nfs_fs_context *ctx,
const char *dev_name)
{
int port = 0;
int max_namelen = PAGE_SIZE;
int max_pathlen = NFS_MAXPATHLEN;
- struct sockaddr *sap = (struct sockaddr *)&args->nfs_server.address;
+ struct sockaddr *sap = (struct sockaddr *)&ctx->nfs_server.address;
- if (nfs_parse_mount_options((char *)options, args) == 0)
+ if (nfs_parse_mount_options((char *)options, ctx) == 0)
return -EINVAL;
if (!nfs_verify_server_address(sap))
goto out_no_address;
- if (args->version == 4) {
+ if (ctx->version == 4) {
#if IS_ENABLED(CONFIG_NFS_V4)
- if (args->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
+ if (ctx->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
port = NFS_RDMA_PORT;
else
port = NFS_PORT;
max_namelen = NFS4_MAXNAMLEN;
max_pathlen = NFS4_MAXPATHLEN;
- nfs_validate_transport_protocol(args);
- if (args->nfs_server.protocol == XPRT_TRANSPORT_UDP)
+ nfs_validate_transport_protocol(ctx);
+ if (ctx->nfs_server.protocol == XPRT_TRANSPORT_UDP)
goto out_invalid_transport_udp;
- nfs4_validate_mount_flags(args);
+ nfs4_validate_mount_flags(ctx);
#else
goto out_v4_not_compiled;
#endif /* CONFIG_NFS_V4 */
} else {
- nfs_set_mount_transport_protocol(args);
- if (args->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
+ nfs_set_mount_transport_protocol(ctx);
+ if (ctx->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
port = NFS_RDMA_PORT;
}
- nfs_set_port(sap, &args->nfs_server.port, port);
+ nfs_set_port(sap, &ctx->nfs_server.port, port);
return nfs_parse_devname(dev_name,
- &args->nfs_server.hostname,
+ &ctx->nfs_server.hostname,
max_namelen,
- &args->nfs_server.export_path,
+ &ctx->nfs_server.export_path,
max_pathlen);
#if !IS_ENABLED(CONFIG_NFS_V4)
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 28ab31fc5aa6..7131fa150d1b 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -81,7 +81,7 @@ struct nfs_client_initdata {
/*
* In-kernel mount arguments
*/
-struct nfs_parsed_mount_data {
+struct nfs_fs_context {
int flags;
unsigned int rsize, wsize;
unsigned int timeo, retrans;
@@ -138,7 +138,7 @@ struct nfs_mount_request {
struct nfs_mount_info {
unsigned int inherited_bsize;
- struct nfs_parsed_mount_data *parsed;
+ struct nfs_fs_context *ctx;
struct nfs_clone_mount *cloned;
struct nfs_server *server;
struct nfs_fh *mntfh;
@@ -229,16 +229,16 @@ struct nfs_pageio_descriptor;
/* mount.c */
#define NFS_TEXT_DATA 1
-extern struct nfs_parsed_mount_data *nfs_alloc_parsed_mount_data(void);
-extern void nfs_free_parsed_mount_data(struct nfs_parsed_mount_data *data);
-extern int nfs_parse_mount_options(char *raw, struct nfs_parsed_mount_data *mnt);
+extern struct nfs_fs_context *nfs_alloc_parsed_mount_data(void);
+extern void nfs_free_parsed_mount_data(struct nfs_fs_context *ctx);
+extern int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx);
extern int nfs_validate_mount_data(struct file_system_type *fs_type,
void *options,
- struct nfs_parsed_mount_data *args,
+ struct nfs_fs_context *ctx,
struct nfs_fh *mntfh,
const char *dev_name);
extern int nfs_validate_text_mount_data(void *options,
- struct nfs_parsed_mount_data *args,
+ struct nfs_fs_context *ctx,
const char *dev_name);
/* pagelist.c */
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c
index 538fd036b69d..2216d166768b 100644
--- a/fs/nfs/nfs4client.c
+++ b/fs/nfs/nfs4client.c
@@ -1056,61 +1056,61 @@ static int nfs4_server_common_setup(struct nfs_server *server,
* Create a version 4 volume record
*/
static int nfs4_init_server(struct nfs_server *server,
- struct nfs_parsed_mount_data *data)
+ struct nfs_fs_context *ctx)
{
struct rpc_timeout timeparms;
int error;
- nfs_init_timeout_values(&timeparms, data->nfs_server.protocol,
- data->timeo, data->retrans);
+ nfs_init_timeout_values(&timeparms, ctx->nfs_server.protocol,
+ ctx->timeo, ctx->retrans);
/* Initialise the client representation from the mount data */
- server->flags = data->flags;
- server->options = data->options;
- server->auth_info = data->auth_info;
+ server->flags = ctx->flags;
+ server->options = ctx->options;
+ server->auth_info = ctx->auth_info;
/* Use the first specified auth flavor. If this flavor isn't
* allowed by the server, use the SECINFO path to try the
* other specified flavors */
- if (data->auth_info.flavor_len >= 1)
- data->selected_flavor = data->auth_info.flavors[0];
+ if (ctx->auth_info.flavor_len >= 1)
+ ctx->selected_flavor = ctx->auth_info.flavors[0];
else
- data->selected_flavor = RPC_AUTH_UNIX;
+ ctx->selected_flavor = RPC_AUTH_UNIX;
/* Get a client record */
error = nfs4_set_client(server,
- data->nfs_server.hostname,
- (const struct sockaddr *)&data->nfs_server.address,
- data->nfs_server.addrlen,
- data->client_address,
- data->nfs_server.protocol,
+ ctx->nfs_server.hostname,
+ (const struct sockaddr *)&ctx->nfs_server.address,
+ ctx->nfs_server.addrlen,
+ ctx->client_address,
+ ctx->nfs_server.protocol,
&timeparms,
- data->minorversion,
- data->nfs_server.nconnect,
- data->net);
+ ctx->minorversion,
+ ctx->nfs_server.nconnect,
+ ctx->net);
if (error < 0)
return error;
- if (data->rsize)
- server->rsize = nfs_block_size(data->rsize, NULL);
- if (data->wsize)
- server->wsize = nfs_block_size(data->wsize, NULL);
+ if (ctx->rsize)
+ server->rsize = nfs_block_size(ctx->rsize, NULL);
+ if (ctx->wsize)
+ server->wsize = nfs_block_size(ctx->wsize, NULL);
- server->acregmin = data->acregmin * HZ;
- server->acregmax = data->acregmax * HZ;
- server->acdirmin = data->acdirmin * HZ;
- server->acdirmax = data->acdirmax * HZ;
- server->port = data->nfs_server.port;
+ server->acregmin = ctx->acregmin * HZ;
+ server->acregmax = ctx->acregmax * HZ;
+ server->acdirmin = ctx->acdirmin * HZ;
+ server->acdirmax = ctx->acdirmax * HZ;
+ server->port = ctx->nfs_server.port;
return nfs_init_server_rpcclient(server, &timeparms,
- data->selected_flavor);
+ ctx->selected_flavor);
}
/*
* Create a version 4 volume record
* - keyed on server and FSID
*/
-/*struct nfs_server *nfs4_create_server(const struct nfs_parsed_mount_data *data,
+/*struct nfs_server *nfs4_create_server(const struct nfs_fs_context *data,
struct nfs_fh *mntfh)*/
struct nfs_server *nfs4_create_server(struct nfs_mount_info *mount_info)
{
@@ -1124,10 +1124,10 @@ struct nfs_server *nfs4_create_server(struct nfs_mount_info *mount_info)
server->cred = get_cred(current_cred());
- auth_probe = mount_info->parsed->auth_info.flavor_len < 1;
+ auth_probe = mount_info->ctx->auth_info.flavor_len < 1;
/* set up the general RPC client */
- error = nfs4_init_server(server, mount_info->parsed);
+ error = nfs4_init_server(server, mount_info->ctx);
if (error < 0)
goto error;
diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c
index f1c2d294073a..f931e8f49b05 100644
--- a/fs/nfs/nfs4super.c
+++ b/fs/nfs/nfs4super.c
@@ -198,15 +198,15 @@ static struct dentry *do_nfs4_mount(struct nfs_server *server, int flags,
struct dentry *nfs4_try_mount(int flags, const char *dev_name,
struct nfs_mount_info *mount_info)
{
- struct nfs_parsed_mount_data *data = mount_info->parsed;
+ struct nfs_fs_context *ctx = mount_info->ctx;
struct dentry *res;
dfprintk(MOUNT, "--> nfs4_try_mount()\n");
res = do_nfs4_mount(nfs4_create_server(mount_info),
flags, mount_info,
- data->nfs_server.hostname,
- data->nfs_server.export_path);
+ ctx->nfs_server.hostname,
+ ctx->nfs_server.export_path);
dfprintk(MOUNT, "<-- nfs4_try_mount() = %d%s\n",
PTR_ERR_OR_ZERO(res),
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index b07585f62c65..83527515590e 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -726,12 +726,13 @@ bool nfs_auth_info_match(const struct nfs_auth_info *auth_info,
EXPORT_SYMBOL_GPL(nfs_auth_info_match);
/*
- * Ensure that a specified authtype in args->auth_info is supported by
- * the server. Returns 0 and sets args->selected_flavor if it's ok, and
+ * Ensure that a specified authtype in cfg->auth_info is supported by
+ * the server. Returns 0 and sets cfg->selected_flavor if it's ok, and
* -EACCES if not.
*/
-static int nfs_verify_authflavors(struct nfs_parsed_mount_data *args,
- rpc_authflavor_t *server_authlist, unsigned int count)
+static int nfs_verify_authflavors(struct nfs_fs_context *cfg,
+ rpc_authflavor_t *server_authlist,
+ unsigned int count)
{
rpc_authflavor_t flavor = RPC_AUTH_MAXFLAVOR;
bool found_auth_null = false;
@@ -752,7 +753,7 @@ static int nfs_verify_authflavors(struct nfs_parsed_mount_data *args,
for (i = 0; i < count; i++) {
flavor = server_authlist[i];
- if (nfs_auth_info_match(&args->auth_info, flavor))
+ if (nfs_auth_info_match(&cfg->auth_info, flavor))
goto out;
if (flavor == RPC_AUTH_NULL)
@@ -760,7 +761,7 @@ static int nfs_verify_authflavors(struct nfs_parsed_mount_data *args,
}
if (found_auth_null) {
- flavor = args->auth_info.flavors[0];
+ flavor = cfg->auth_info.flavors[0];
goto out;
}
@@ -769,8 +770,8 @@ static int nfs_verify_authflavors(struct nfs_parsed_mount_data *args,
return -EACCES;
out:
- args->selected_flavor = flavor;
- dfprintk(MOUNT, "NFS: using auth flavor %u\n", args->selected_flavor);
+ cfg->selected_flavor = flavor;
+ dfprintk(MOUNT, "NFS: using auth flavor %u\n", cfg->selected_flavor);
return 0;
}
@@ -778,50 +779,50 @@ static int nfs_verify_authflavors(struct nfs_parsed_mount_data *args,
* Use the remote server's MOUNT service to request the NFS file handle
* corresponding to the provided path.
*/
-static int nfs_request_mount(struct nfs_parsed_mount_data *args,
+static int nfs_request_mount(struct nfs_fs_context *cfg,
struct nfs_fh *root_fh,
rpc_authflavor_t *server_authlist,
unsigned int *server_authlist_len)
{
struct nfs_mount_request request = {
.sap = (struct sockaddr *)
- &args->mount_server.address,
- .dirpath = args->nfs_server.export_path,
- .protocol = args->mount_server.protocol,
+ &cfg->mount_server.address,
+ .dirpath = cfg->nfs_server.export_path,
+ .protocol = cfg->mount_server.protocol,
.fh = root_fh,
- .noresvport = args->flags & NFS_MOUNT_NORESVPORT,
+ .noresvport = cfg->flags & NFS_MOUNT_NORESVPORT,
.auth_flav_len = server_authlist_len,
.auth_flavs = server_authlist,
- .net = args->net,
+ .net = cfg->net,
};
int status;
- if (args->mount_server.version == 0) {
- switch (args->version) {
+ if (cfg->mount_server.version == 0) {
+ switch (cfg->version) {
default:
- args->mount_server.version = NFS_MNT3_VERSION;
+ cfg->mount_server.version = NFS_MNT3_VERSION;
break;
case 2:
- args->mount_server.version = NFS_MNT_VERSION;
+ cfg->mount_server.version = NFS_MNT_VERSION;
}
}
- request.version = args->mount_server.version;
+ request.version = cfg->mount_server.version;
- if (args->mount_server.hostname)
- request.hostname = args->mount_server.hostname;
+ if (cfg->mount_server.hostname)
+ request.hostname = cfg->mount_server.hostname;
else
- request.hostname = args->nfs_server.hostname;
+ request.hostname = cfg->nfs_server.hostname;
/*
* Construct the mount server's address.
*/
- if (args->mount_server.address.ss_family == AF_UNSPEC) {
- memcpy(request.sap, &args->nfs_server.address,
- args->nfs_server.addrlen);
- args->mount_server.addrlen = args->nfs_server.addrlen;
+ if (cfg->mount_server.address.ss_family == AF_UNSPEC) {
+ memcpy(request.sap, &cfg->nfs_server.address,
+ cfg->nfs_server.addrlen);
+ cfg->mount_server.addrlen = cfg->nfs_server.addrlen;
}
- request.salen = args->mount_server.addrlen;
- nfs_set_port(request.sap, &args->mount_server.port, 0);
+ request.salen = cfg->mount_server.addrlen;
+ nfs_set_port(request.sap, &cfg->mount_server.port, 0);
/*
* Now ask the mount server to map our export path
@@ -844,12 +845,12 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf
bool tried_auth_unix = false;
bool auth_null_in_list = false;
struct nfs_server *server = ERR_PTR(-EACCES);
- struct nfs_parsed_mount_data *args = mount_info->parsed;
+ struct nfs_fs_context *ctx = mount_info->ctx;
rpc_authflavor_t authlist[NFS_MAX_SECFLAVORS];
unsigned int authlist_len = ARRAY_SIZE(authlist);
struct nfs_subversion *nfs_mod = mount_info->nfs_mod;
- status = nfs_request_mount(args, mount_info->mntfh, authlist,
+ status = nfs_request_mount(ctx, mount_info->mntfh, authlist,
&authlist_len);
if (status)
return ERR_PTR(status);
@@ -858,10 +859,10 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf
* Was a sec= authflavor specified in the options? First, verify
* whether the server supports it, and then just try to use it if so.
*/
- if (args->auth_info.flavor_len > 0) {
- status = nfs_verify_authflavors(args, authlist, authlist_len);
+ if (ctx->auth_info.flavor_len > 0) {
+ status = nfs_verify_authflavors(ctx, authlist, authlist_len);
dfprintk(MOUNT, "NFS: using auth flavor %u\n",
- args->selected_flavor);
+ ctx->selected_flavor);
if (status)
return ERR_PTR(status);
return nfs_mod->rpc_ops->create_server(mount_info);
@@ -890,7 +891,7 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf
/* Fallthrough */
}
dfprintk(MOUNT, "NFS: attempting to use auth flavor %u\n", flavor);
- args->selected_flavor = flavor;
+ ctx->selected_flavor = flavor;
server = nfs_mod->rpc_ops->create_server(mount_info);
if (!IS_ERR(server))
return server;
@@ -906,7 +907,7 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf
/* Last chance! Try AUTH_UNIX */
dfprintk(MOUNT, "NFS: attempting to use auth flavor %u\n", RPC_AUTH_UNIX);
- args->selected_flavor = RPC_AUTH_UNIX;
+ ctx->selected_flavor = RPC_AUTH_UNIX;
return nfs_mod->rpc_ops->create_server(mount_info);
}
@@ -916,7 +917,7 @@ struct dentry *nfs_try_mount(int flags, const char *dev_name,
struct nfs_mount_info *mount_info)
{
struct nfs_subversion *nfs_mod = mount_info->nfs_mod;
- if (mount_info->parsed->need_mount)
+ if (mount_info->ctx->need_mount)
mount_info->server = nfs_try_mount_request(mount_info);
else
mount_info->server = nfs_mod->rpc_ops->create_server(mount_info);
@@ -940,24 +941,24 @@ EXPORT_SYMBOL_GPL(nfs_try_mount);
static int
nfs_compare_remount_data(struct nfs_server *nfss,
- struct nfs_parsed_mount_data *data)
+ struct nfs_fs_context *ctx)
{
- if ((data->flags ^ nfss->flags) & NFS_REMOUNT_CMP_FLAGMASK ||
- data->rsize != nfss->rsize ||
- data->wsize != nfss->wsize ||
- data->version != nfss->nfs_client->rpc_ops->version ||
- data->minorversion != nfss->nfs_client->cl_minorversion ||
- data->retrans != nfss->client->cl_timeout->to_retries ||
- !nfs_auth_info_match(&data->auth_info, nfss->client->cl_auth->au_flavor) ||
- data->acregmin != nfss->acregmin / HZ ||
- data->acregmax != nfss->acregmax / HZ ||
- data->acdirmin != nfss->acdirmin / HZ ||
- data->acdirmax != nfss->acdirmax / HZ ||
- data->timeo != (10U * nfss->client->cl_timeout->to_initval / HZ) ||
- (data->options & NFS_OPTION_FSCACHE) != (nfss->options & NFS_OPTION_FSCACHE) ||
- data->nfs_server.port != nfss->port ||
- data->nfs_server.addrlen != nfss->nfs_client->cl_addrlen ||
- !rpc_cmp_addr((struct sockaddr *)&data->nfs_server.address,
+ if ((ctx->flags ^ nfss->flags) & NFS_REMOUNT_CMP_FLAGMASK ||
+ ctx->rsize != nfss->rsize ||
+ ctx->wsize != nfss->wsize ||
+ ctx->version != nfss->nfs_client->rpc_ops->version ||
+ ctx->minorversion != nfss->nfs_client->cl_minorversion ||
+ ctx->retrans != nfss->client->cl_timeout->to_retries ||
+ !nfs_auth_info_match(&ctx->auth_info, nfss->client->cl_auth->au_flavor) ||
+ ctx->acregmin != nfss->acregmin / HZ ||
+ ctx->acregmax != nfss->acregmax / HZ ||
+ ctx->acdirmin != nfss->acdirmin / HZ ||
+ ctx->acdirmax != nfss->acdirmax / HZ ||
+ ctx->timeo != (10U * nfss->client->cl_timeout->to_initval / HZ) ||
+ (ctx->options & NFS_OPTION_FSCACHE) != (nfss->options & NFS_OPTION_FSCACHE) ||
+ ctx->nfs_server.port != nfss->port ||
+ ctx->nfs_server.addrlen != nfss->nfs_client->cl_addrlen ||
+ !rpc_cmp_addr((struct sockaddr *)&ctx->nfs_server.address,
(struct sockaddr *)&nfss->nfs_client->cl_addr))
return -EINVAL;
@@ -969,7 +970,7 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data)
{
int error;
struct nfs_server *nfss = sb->s_fs_info;
- struct nfs_parsed_mount_data *data;
+ struct nfs_fs_context *ctx;
struct nfs_mount_data *options = (struct nfs_mount_data *)raw_data;
struct nfs4_mount_data *options4 = (struct nfs4_mount_data *)raw_data;
u32 nfsvers = nfss->nfs_client->rpc_ops->version;
@@ -987,32 +988,32 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data)
options->version <= 6))))
return 0;
- data = nfs_alloc_parsed_mount_data();
- if (data == NULL)
+ ctx = nfs_alloc_parsed_mount_data();
+ if (ctx == NULL)
return -ENOMEM;
/* fill out struct with values from existing mount */
- data->flags = nfss->flags;
- data->rsize = nfss->rsize;
- data->wsize = nfss->wsize;
- data->retrans = nfss->client->cl_timeout->to_retries;
- data->selected_flavor = nfss->client->cl_auth->au_flavor;
- data->acregmin = nfss->acregmin / HZ;
- data->acregmax = nfss->acregmax / HZ;
- data->acdirmin = nfss->acdirmin / HZ;
- data->acdirmax = nfss->acdirmax / HZ;
- data->timeo = 10U * nfss->client->cl_timeout->to_initval / HZ;
- data->nfs_server.port = nfss->port;
- data->nfs_server.addrlen = nfss->nfs_client->cl_addrlen;
- data->version = nfsvers;
- data->minorversion = nfss->nfs_client->cl_minorversion;
- data->net = current->nsproxy->net_ns;
- memcpy(&data->nfs_server.address, &nfss->nfs_client->cl_addr,
- data->nfs_server.addrlen);
+ ctx->flags = nfss->flags;
+ ctx->rsize = nfss->rsize;
+ ctx->wsize = nfss->wsize;
+ ctx->retrans = nfss->client->cl_timeout->to_retries;
+ ctx->selected_flavor = nfss->client->cl_auth->au_flavor;
+ ctx->acregmin = nfss->acregmin / HZ;
+ ctx->acregmax = nfss->acregmax / HZ;
+ ctx->acdirmin = nfss->acdirmin / HZ;
+ ctx->acdirmax = nfss->acdirmax / HZ;
+ ctx->timeo = 10U * nfss->client->cl_timeout->to_initval / HZ;
+ ctx->nfs_server.port = nfss->port;
+ ctx->nfs_server.addrlen = nfss->nfs_client->cl_addrlen;
+ ctx->version = nfsvers;
+ ctx->minorversion = nfss->nfs_client->cl_minorversion;
+ ctx->net = current->nsproxy->net_ns;
+ memcpy(&ctx->nfs_server.address, &nfss->nfs_client->cl_addr,
+ ctx->nfs_server.addrlen);
/* overwrite those values with any that were specified */
error = -EINVAL;
- if (!nfs_parse_mount_options((char *)options, data))
+ if (!nfs_parse_mount_options((char *)options, ctx))
goto out;
/*
@@ -1021,15 +1022,15 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data)
* will clear SB_SYNCHRONOUS if -o sync wasn't specified in the
* remount options, so we have to explicitly reset it.
*/
- if (data->flags & NFS_MOUNT_NOAC)
+ if (ctx->flags & NFS_MOUNT_NOAC)
*flags |= SB_SYNCHRONOUS;
/* compare new mount options with old ones */
- error = nfs_compare_remount_data(nfss, data);
+ error = nfs_compare_remount_data(nfss, ctx);
if (!error)
- error = security_sb_remount(sb, data->lsm_opts);
+ error = security_sb_remount(sb, ctx->lsm_opts);
out:
- nfs_free_parsed_mount_data(data);
+ nfs_free_parsed_mount_data(ctx);
return error;
}
EXPORT_SYMBOL_GPL(nfs_remount);
@@ -1039,15 +1040,15 @@ EXPORT_SYMBOL_GPL(nfs_remount);
*/
static void nfs_fill_super(struct super_block *sb, struct nfs_mount_info *mount_info)
{
- struct nfs_parsed_mount_data *data = mount_info->parsed;
+ struct nfs_fs_context *ctx = mount_info->ctx;
struct nfs_server *server = NFS_SB(sb);
sb->s_blocksize_bits = 0;
sb->s_blocksize = 0;
sb->s_xattr = server->nfs_client->cl_nfs_mod->xattr;
sb->s_op = server->nfs_client->cl_nfs_mod->sops;
- if (data && data->bsize)
- sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits);
+ if (ctx && ctx->bsize)
+ sb->s_blocksize = nfs_block_size(ctx->bsize, &sb->s_blocksize_bits);
if (server->nfs_client->rpc_ops->version != 2) {
/* The VFS shouldn't apply the umask to mode bits. We will do
@@ -1208,7 +1209,7 @@ static int nfs_compare_super(struct super_block *sb, void *data)
#ifdef CONFIG_NFS_FSCACHE
static void nfs_get_cache_cookie(struct super_block *sb,
- struct nfs_parsed_mount_data *parsed,
+ struct nfs_fs_context *ctx,
struct nfs_clone_mount *cloned)
{
struct nfs_server *nfss = NFS_SB(sb);
@@ -1218,12 +1219,12 @@ static void nfs_get_cache_cookie(struct super_block *sb,
nfss->fscache_key = NULL;
nfss->fscache = NULL;
- if (parsed) {
- if (!(parsed->options & NFS_OPTION_FSCACHE))
+ if (ctx) {
+ if (!(ctx->options & NFS_OPTION_FSCACHE))
return;
- if (parsed->fscache_uniq) {
- uniq = parsed->fscache_uniq;
- ulen = strlen(parsed->fscache_uniq);
+ if (ctx->fscache_uniq) {
+ uniq = ctx->fscache_uniq;
+ ulen = strlen(ctx->fscache_uniq);
}
} else if (cloned) {
struct nfs_server *mnt_s = NFS_SB(cloned->sb);
@@ -1240,7 +1241,7 @@ static void nfs_get_cache_cookie(struct super_block *sb,
}
#else
static void nfs_get_cache_cookie(struct super_block *sb,
- struct nfs_parsed_mount_data *parsed,
+ struct nfs_fs_context *parsed,
struct nfs_clone_mount *cloned)
{
}
@@ -1312,7 +1313,7 @@ static struct dentry *nfs_fs_mount_common(int flags, const char *dev_name,
s->s_blocksize_bits = bsize;
s->s_blocksize = 1U << bsize;
}
- nfs_get_cache_cookie(s, mount_info->parsed, mount_info->cloned);
+ nfs_get_cache_cookie(s, mount_info->ctx, mount_info->cloned);
if (!(server->flags & NFS_MOUNT_UNSHARED))
s->s_iflags |= SB_I_MULTIROOT;
}
@@ -1333,7 +1334,7 @@ static struct dentry *nfs_fs_mount_common(int flags, const char *dev_name,
error = security_sb_clone_mnt_opts(mount_info->cloned->sb, s, kflags,
&kflags_out);
} else {
- error = security_sb_set_mnt_opts(s, mount_info->parsed->lsm_opts,
+ error = security_sb_set_mnt_opts(s, mount_info->ctx->lsm_opts,
kflags, &kflags_out);
}
if (error)
@@ -1370,21 +1371,22 @@ struct dentry *nfs_fs_mount(struct file_system_type *fs_type,
struct nfs_subversion *nfs_mod;
int error;
- mount_info.parsed = nfs_alloc_parsed_mount_data();
+ mount_info.ctx = nfs_alloc_parsed_mount_data();
mount_info.mntfh = nfs_alloc_fhandle();
- if (mount_info.parsed == NULL || mount_info.mntfh == NULL)
+ if (mount_info.ctx == NULL || mount_info.mntfh == NULL)
goto out;
/* Validate the mount data */
- error = nfs_validate_mount_data(fs_type, raw_data, mount_info.parsed, mount_info.mntfh, dev_name);
+ error = nfs_validate_mount_data(fs_type, raw_data, mount_info.ctx, mount_info.mntfh, dev_name);
if (error == NFS_TEXT_DATA)
- error = nfs_validate_text_mount_data(raw_data, mount_info.parsed, dev_name);
+ error = nfs_validate_text_mount_data(raw_data,
+ mount_info.ctx, dev_name);
if (error < 0) {
mntroot = ERR_PTR(error);
goto out;
}
- nfs_mod = get_nfs_version(mount_info.parsed->version);
+ nfs_mod = get_nfs_version(mount_info.ctx->version);
if (IS_ERR(nfs_mod)) {
mntroot = ERR_CAST(nfs_mod);
goto out;
@@ -1395,7 +1397,7 @@ struct dentry *nfs_fs_mount(struct file_system_type *fs_type,
put_nfs_version(nfs_mod);
out:
- nfs_free_parsed_mount_data(mount_info.parsed);
+ nfs_free_parsed_mount_data(mount_info.ctx);
nfs_free_fhandle(mount_info.mntfh);
return mntroot;
}
--
2.17.2
^ permalink raw reply related
* [PATCH v6 23/27] NFS: rename nfs_fs_context pointer arg in a few functions
From: Scott Mayhew @ 2019-12-10 12:31 UTC (permalink / raw)
To: anna.schumaker, trond.myklebust
Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel,
linux-security-module
In-Reply-To: <20191210123115.1655-1-smayhew@redhat.com>
Split out from commit "NFS: Add fs_context support."
Rename cfg to ctx in nfs_init_server(), nfs_verify_authflavors(),
and nfs_request_mount(). No functional changes.
Signed-off-by: Scott Mayhew <smayhew@redhat.com>
---
fs/nfs/client.c | 62 ++++++++++++++++++++++++-------------------------
fs/nfs/super.c | 54 +++++++++++++++++++++---------------------
2 files changed, 58 insertions(+), 58 deletions(-)
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 0a00df8e71bb..69c0708b2acc 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -658,28 +658,28 @@ EXPORT_SYMBOL_GPL(nfs_init_client);
* Create a version 2 or 3 client
*/
static int nfs_init_server(struct nfs_server *server,
- const struct nfs_fs_context *cfg,
+ const struct nfs_fs_context *ctx,
struct nfs_subversion *nfs_mod)
{
struct rpc_timeout timeparms;
struct nfs_client_initdata cl_init = {
- .hostname = cfg->nfs_server.hostname,
- .addr = (const struct sockaddr *)&cfg->nfs_server.address,
- .addrlen = cfg->nfs_server.addrlen,
+ .hostname = ctx->nfs_server.hostname,
+ .addr = (const struct sockaddr *)&ctx->nfs_server.address,
+ .addrlen = ctx->nfs_server.addrlen,
.nfs_mod = nfs_mod,
- .proto = cfg->nfs_server.protocol,
- .net = cfg->net,
+ .proto = ctx->nfs_server.protocol,
+ .net = ctx->net,
.timeparms = &timeparms,
.cred = server->cred,
- .nconnect = cfg->nfs_server.nconnect,
+ .nconnect = ctx->nfs_server.nconnect,
.init_flags = (1UL << NFS_CS_REUSEPORT),
};
struct nfs_client *clp;
int error;
- nfs_init_timeout_values(&timeparms, cfg->nfs_server.protocol,
- cfg->timeo, cfg->retrans);
- if (cfg->flags & NFS_MOUNT_NORESVPORT)
+ nfs_init_timeout_values(&timeparms, ctx->nfs_server.protocol,
+ ctx->timeo, ctx->retrans);
+ if (ctx->flags & NFS_MOUNT_NORESVPORT)
set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags);
/* Allocate or find a client reference we can use */
@@ -690,46 +690,46 @@ static int nfs_init_server(struct nfs_server *server,
server->nfs_client = clp;
/* Initialise the client representation from the mount data */
- server->flags = cfg->flags;
- server->options = cfg->options;
+ server->flags = ctx->flags;
+ server->options = ctx->options;
server->caps |= NFS_CAP_HARDLINKS|NFS_CAP_SYMLINKS|NFS_CAP_FILEID|
NFS_CAP_MODE|NFS_CAP_NLINK|NFS_CAP_OWNER|NFS_CAP_OWNER_GROUP|
NFS_CAP_ATIME|NFS_CAP_CTIME|NFS_CAP_MTIME;
- if (cfg->rsize)
- server->rsize = nfs_block_size(cfg->rsize, NULL);
- if (cfg->wsize)
- server->wsize = nfs_block_size(cfg->wsize, NULL);
+ if (ctx->rsize)
+ server->rsize = nfs_block_size(ctx->rsize, NULL);
+ if (ctx->wsize)
+ server->wsize = nfs_block_size(ctx->wsize, NULL);
- server->acregmin = cfg->acregmin * HZ;
- server->acregmax = cfg->acregmax * HZ;
- server->acdirmin = cfg->acdirmin * HZ;
- server->acdirmax = cfg->acdirmax * HZ;
+ server->acregmin = ctx->acregmin * HZ;
+ server->acregmax = ctx->acregmax * HZ;
+ server->acdirmin = ctx->acdirmin * HZ;
+ server->acdirmax = ctx->acdirmax * HZ;
/* Start lockd here, before we might error out */
error = nfs_start_lockd(server);
if (error < 0)
goto error;
- server->port = cfg->nfs_server.port;
- server->auth_info = cfg->auth_info;
+ server->port = ctx->nfs_server.port;
+ server->auth_info = ctx->auth_info;
error = nfs_init_server_rpcclient(server, &timeparms,
- cfg->selected_flavor);
+ ctx->selected_flavor);
if (error < 0)
goto error;
/* Preserve the values of mount_server-related mount options */
- if (cfg->mount_server.addrlen) {
- memcpy(&server->mountd_address, &cfg->mount_server.address,
- cfg->mount_server.addrlen);
- server->mountd_addrlen = cfg->mount_server.addrlen;
+ if (ctx->mount_server.addrlen) {
+ memcpy(&server->mountd_address, &ctx->mount_server.address,
+ ctx->mount_server.addrlen);
+ server->mountd_addrlen = ctx->mount_server.addrlen;
}
- server->mountd_version = cfg->mount_server.version;
- server->mountd_port = cfg->mount_server.port;
- server->mountd_protocol = cfg->mount_server.protocol;
+ server->mountd_version = ctx->mount_server.version;
+ server->mountd_port = ctx->mount_server.port;
+ server->mountd_protocol = ctx->mount_server.protocol;
- server->namelen = cfg->namlen;
+ server->namelen = ctx->namlen;
return 0;
error:
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 59962bc0118f..6c9573a32a69 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -726,11 +726,11 @@ bool nfs_auth_info_match(const struct nfs_auth_info *auth_info,
EXPORT_SYMBOL_GPL(nfs_auth_info_match);
/*
- * Ensure that a specified authtype in cfg->auth_info is supported by
- * the server. Returns 0 and sets cfg->selected_flavor if it's ok, and
+ * Ensure that a specified authtype in ctx->auth_info is supported by
+ * the server. Returns 0 and sets ctx->selected_flavor if it's ok, and
* -EACCES if not.
*/
-static int nfs_verify_authflavors(struct nfs_fs_context *cfg,
+static int nfs_verify_authflavors(struct nfs_fs_context *ctx,
rpc_authflavor_t *server_authlist,
unsigned int count)
{
@@ -753,7 +753,7 @@ static int nfs_verify_authflavors(struct nfs_fs_context *cfg,
for (i = 0; i < count; i++) {
flavor = server_authlist[i];
- if (nfs_auth_info_match(&cfg->auth_info, flavor))
+ if (nfs_auth_info_match(&ctx->auth_info, flavor))
goto out;
if (flavor == RPC_AUTH_NULL)
@@ -761,7 +761,7 @@ static int nfs_verify_authflavors(struct nfs_fs_context *cfg,
}
if (found_auth_null) {
- flavor = cfg->auth_info.flavors[0];
+ flavor = ctx->auth_info.flavors[0];
goto out;
}
@@ -770,8 +770,8 @@ static int nfs_verify_authflavors(struct nfs_fs_context *cfg,
return -EACCES;
out:
- cfg->selected_flavor = flavor;
- dfprintk(MOUNT, "NFS: using auth flavor %u\n", cfg->selected_flavor);
+ ctx->selected_flavor = flavor;
+ dfprintk(MOUNT, "NFS: using auth flavor %u\n", ctx->selected_flavor);
return 0;
}
@@ -779,50 +779,50 @@ static int nfs_verify_authflavors(struct nfs_fs_context *cfg,
* Use the remote server's MOUNT service to request the NFS file handle
* corresponding to the provided path.
*/
-static int nfs_request_mount(struct nfs_fs_context *cfg,
+static int nfs_request_mount(struct nfs_fs_context *ctx,
struct nfs_fh *root_fh,
rpc_authflavor_t *server_authlist,
unsigned int *server_authlist_len)
{
struct nfs_mount_request request = {
.sap = (struct sockaddr *)
- &cfg->mount_server.address,
- .dirpath = cfg->nfs_server.export_path,
- .protocol = cfg->mount_server.protocol,
+ &ctx->mount_server.address,
+ .dirpath = ctx->nfs_server.export_path,
+ .protocol = ctx->mount_server.protocol,
.fh = root_fh,
- .noresvport = cfg->flags & NFS_MOUNT_NORESVPORT,
+ .noresvport = ctx->flags & NFS_MOUNT_NORESVPORT,
.auth_flav_len = server_authlist_len,
.auth_flavs = server_authlist,
- .net = cfg->net,
+ .net = ctx->net,
};
int status;
- if (cfg->mount_server.version == 0) {
- switch (cfg->version) {
+ if (ctx->mount_server.version == 0) {
+ switch (ctx->version) {
default:
- cfg->mount_server.version = NFS_MNT3_VERSION;
+ ctx->mount_server.version = NFS_MNT3_VERSION;
break;
case 2:
- cfg->mount_server.version = NFS_MNT_VERSION;
+ ctx->mount_server.version = NFS_MNT_VERSION;
}
}
- request.version = cfg->mount_server.version;
+ request.version = ctx->mount_server.version;
- if (cfg->mount_server.hostname)
- request.hostname = cfg->mount_server.hostname;
+ if (ctx->mount_server.hostname)
+ request.hostname = ctx->mount_server.hostname;
else
- request.hostname = cfg->nfs_server.hostname;
+ request.hostname = ctx->nfs_server.hostname;
/*
* Construct the mount server's address.
*/
- if (cfg->mount_server.address.sa_family == AF_UNSPEC) {
- memcpy(request.sap, &cfg->nfs_server.address,
- cfg->nfs_server.addrlen);
- cfg->mount_server.addrlen = cfg->nfs_server.addrlen;
+ if (ctx->mount_server.address.sa_family == AF_UNSPEC) {
+ memcpy(request.sap, &ctx->nfs_server.address,
+ ctx->nfs_server.addrlen);
+ ctx->mount_server.addrlen = ctx->nfs_server.addrlen;
}
- request.salen = cfg->mount_server.addrlen;
- nfs_set_port(request.sap, &cfg->mount_server.port, 0);
+ request.salen = ctx->mount_server.addrlen;
+ nfs_set_port(request.sap, &ctx->mount_server.port, 0);
/*
* Now ask the mount server to map our export path
--
2.17.2
^ permalink raw reply related
* [PATCH v6 25/27] NFS: Add fs_context support.
From: Scott Mayhew @ 2019-12-10 12:31 UTC (permalink / raw)
To: anna.schumaker, trond.myklebust
Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel,
linux-security-module
In-Reply-To: <20191210123115.1655-1-smayhew@redhat.com>
From: David Howells <dhowells@redhat.com>
Add filesystem context support to NFS, parsing the options in advance and
attaching the information to struct nfs_fs_context. The highlights are:
(*) Merge nfs_mount_info and nfs_clone_mount into nfs_fs_context. This
structure represents NFS's superblock config.
(*) Make use of the VFS's parsing support to split comma-separated lists
(*) Pin the NFS protocol module in the nfs_fs_context.
(*) Attach supplementary error information to fs_context. This has the
downside that these strings must be static and can't be formatted.
(*) Remove the auxiliary file_system_type structs since the information
necessary can be conveyed in the nfs_fs_context struct instead.
(*) Root mounts are made by duplicating the config for the requested mount
so as to have the same parameters. Submounts pick up their parameters
from the parent superblock.
[AV -- retrans is u32, not string]
[SM -- Renamed cfg to ctx in a few functions in an earlier patch]
[SM -- Moved fs_context mount option parsing to an earlier patch]
[SM -- Moved fs_context error logging to a later patch]
[SM -- Fixed printks in nfs4_try_get_tree() and nfs4_get_referral_tree()]
[SM -- Added is_remount_fc() helper]
[SM -- Deferred some refactoring to a later patch]
[SM -- Fixed referral mounts, which were broken in the original patch]
[SM -- Fixed leak of nfs_fattr when fs_context is freed]
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Scott Mayhew <smayhew@redhat.com>
---
fs/nfs/fs_context.c | 470 +++++++++++++++++++++++++++-------------
fs/nfs/internal.h | 74 +++----
fs/nfs/namespace.c | 136 +++++++-----
fs/nfs/nfs3proc.c | 2 +-
fs/nfs/nfs4_fs.h | 9 +-
fs/nfs/nfs4file.c | 1 +
fs/nfs/nfs4namespace.c | 293 ++++++++++++++-----------
fs/nfs/nfs4proc.c | 2 +-
fs/nfs/nfs4super.c | 151 +++++++------
fs/nfs/proc.c | 2 +-
fs/nfs/super.c | 286 +++++++-----------------
include/linux/nfs_xdr.h | 6 +-
12 files changed, 773 insertions(+), 659 deletions(-)
diff --git a/fs/nfs/fs_context.c b/fs/nfs/fs_context.c
index 9a3162055d5d..ac1a8d7d7393 100644
--- a/fs/nfs/fs_context.c
+++ b/fs/nfs/fs_context.c
@@ -3,6 +3,7 @@
* linux/fs/nfs/fs_context.c
*
* Copyright (C) 1992 Rick Sladkey
+ * Conversion to new mount api Copyright (C) David Howells
*
* NFS mount handling.
*
@@ -467,21 +468,31 @@ static int nfs_parse_version_string(struct nfs_fs_context *ctx,
/*
* Parse a single mount parameter.
*/
-static int nfs_fs_context_parse_param(struct nfs_fs_context *ctx,
+static int nfs_fs_context_parse_param(struct fs_context *fc,
struct fs_parameter *param)
{
struct fs_parse_result result;
+ struct nfs_fs_context *ctx = nfs_fc2context(fc);
unsigned short protofamily, mountfamily;
unsigned int len;
int ret, opt;
dfprintk(MOUNT, "NFS: parsing nfs mount option '%s'\n", param->key);
- opt = fs_parse(NULL, &nfs_fs_parameters, param, &result);
+ opt = fs_parse(fc, &nfs_fs_parameters, param, &result);
if (opt < 0)
return ctx->sloppy ? 1 : opt;
switch (opt) {
+ case Opt_source:
+ if (fc->source) {
+ dfprintk(MOUNT, "NFS: Multiple sources not supported\n");
+ return -EINVAL;
+ }
+ fc->source = param->string;
+ param->string = NULL;
+ break;
+
/*
* boolean options: foo/nofoo
*/
@@ -807,112 +818,6 @@ static int nfs_fs_context_parse_param(struct nfs_fs_context *ctx,
return -ERANGE;
}
-/* cribbed from generic_parse_monolithic and vfs_parse_fs_string */
-static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
-{
- int ret;
- char *key = p, *value;
- size_t v_size = 0;
- struct fs_parameter param;
-
- memset(¶m, 0, sizeof(param));
- value = strchr(key, '=');
- if (value && value != key) {
- *value++ = 0;
- v_size = strlen(value);
- }
- param.key = key;
- param.type = fs_value_is_flag;
- param.size = v_size;
- if (v_size > 0) {
- param.type = fs_value_is_string;
- param.string = kmemdup_nul(value, v_size, GFP_KERNEL);
- if (!param.string)
- return -ENOMEM;
- }
- ret = nfs_fs_context_parse_param(ctx, ¶m);
- kfree(param.string);
- return ret;
-}
-
-/*
- * Error-check and convert a string of mount options from user space into
- * a data structure. The whole mount string is processed; bad options are
- * skipped as they are encountered. If there were no errors, return 1;
- * otherwise return 0 (zero).
- */
-int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx)
-{
- char *p;
- int rc, sloppy = 0, invalid_option = 0;
-
- if (!raw) {
- dfprintk(MOUNT, "NFS: mount options string was NULL.\n");
- return 1;
- }
- dfprintk(MOUNT, "NFS: nfs mount opts='%s'\n", raw);
-
- rc = security_sb_eat_lsm_opts(raw, &ctx->lsm_opts);
- if (rc)
- goto out_security_failure;
-
- while ((p = strsep(&raw, ",")) != NULL) {
- if (!*p)
- continue;
- if (nfs_fs_context_parse_option(ctx, p) < 0)
- invalid_option = true;
- }
-
- if (!sloppy && invalid_option)
- return 0;
-
- if (ctx->minorversion && ctx->version != 4)
- goto out_minorversion_mismatch;
-
- if (ctx->options & NFS_OPTION_MIGRATION &&
- (ctx->version != 4 || ctx->minorversion != 0))
- goto out_migration_misuse;
-
- /*
- * verify that any proto=/mountproto= options match the address
- * families in the addr=/mountaddr= options.
- */
- if (ctx->protofamily != AF_UNSPEC &&
- ctx->protofamily != ctx->nfs_server.address.sa_family)
- goto out_proto_mismatch;
-
- if (ctx->mountfamily != AF_UNSPEC) {
- if (ctx->mount_server.addrlen) {
- if (ctx->mountfamily != ctx->mount_server.address.sa_family)
- goto out_mountproto_mismatch;
- } else {
- if (ctx->mountfamily != ctx->nfs_server.address.sa_family)
- goto out_mountproto_mismatch;
- }
- }
-
- return 1;
-
-out_minorversion_mismatch:
- printk(KERN_INFO "NFS: mount option vers=%u does not support "
- "minorversion=%u\n", ctx->version, ctx->minorversion);
- return 0;
-out_mountproto_mismatch:
- printk(KERN_INFO "NFS: mount server address does not match mountproto= "
- "option\n");
- return 0;
-out_proto_mismatch:
- printk(KERN_INFO "NFS: server address does not match proto= option\n");
- return 0;
-out_migration_misuse:
- printk(KERN_INFO
- "NFS: 'migration' not supported for this NFS version\n");
- return -EINVAL;
-out_security_failure:
- printk(KERN_INFO "NFS: security options invalid: %d\n", rc);
- return 0;
-}
-
/*
* Split "dev_name" into "hostname:export_path".
*
@@ -990,6 +895,11 @@ static int nfs_parse_devname(struct nfs_fs_context *ctx,
return -ENAMETOOLONG;
}
+static inline bool is_remount_fc(struct fs_context *fc)
+{
+ return fc->root != NULL;
+}
+
/*
* Parse monolithic NFS2/NFS3 mount data
* - fills in the mount root filehandle
@@ -1006,12 +916,11 @@ static int nfs_parse_devname(struct nfs_fs_context *ctx,
* + breaking back: trying proto=udp after proto=tcp, v2 after v3,
* mountproto=tcp after mountproto=udp, and so on
*/
-static int nfs23_validate_mount_data(void *options,
- struct nfs_fs_context *ctx,
- struct nfs_fh *mntfh,
- const char *dev_name)
+static int nfs23_parse_monolithic(struct fs_context *fc,
+ struct nfs_mount_data *data)
{
- struct nfs_mount_data *data = (struct nfs_mount_data *)options;
+ struct nfs_fs_context *ctx = nfs_fc2context(fc);
+ struct nfs_fh *mntfh = ctx->mount_info.mntfh;
struct sockaddr *sap = (struct sockaddr *)&ctx->nfs_server.address;
int extra_flags = NFS_MOUNT_LEGACY_INTERFACE;
@@ -1083,6 +992,9 @@ static int nfs23_validate_mount_data(void *options,
ctx->nfs_server.protocol = XPRT_TRANSPORT_UDP;
/* N.B. caller will free nfs_server.hostname in all cases */
ctx->nfs_server.hostname = kstrdup(data->hostname, GFP_KERNEL);
+ if (!ctx->nfs_server.hostname)
+ goto out_nomem;
+
ctx->namlen = data->namlen;
ctx->bsize = data->bsize;
@@ -1090,8 +1002,6 @@ static int nfs23_validate_mount_data(void *options,
ctx->selected_flavor = data->pseudoflavor;
else
ctx->selected_flavor = RPC_AUTH_UNIX;
- if (!ctx->nfs_server.hostname)
- goto out_nomem;
if (!(data->flags & NFS_MOUNT_NONLM))
ctx->flags &= ~(NFS_MOUNT_LOCAL_FLOCK|
@@ -1109,12 +1019,13 @@ static int nfs23_validate_mount_data(void *options,
*/
if (data->context[0]){
#ifdef CONFIG_SECURITY_SELINUX
- int rc;
+ int ret;
+
data->context[NFS_MAX_CONTEXT_LEN] = '\0';
- rc = security_add_mnt_opt("context", data->context,
- strlen(data->context), ctx->lsm_opts);
- if (rc)
- return rc;
+ ret = vfs_parse_fs_string(fc, "context",
+ data->context, strlen(data->context));
+ if (ret < 0)
+ return ret;
#else
return -EINVAL;
#endif
@@ -1122,12 +1033,20 @@ static int nfs23_validate_mount_data(void *options,
break;
default:
- return NFS_TEXT_DATA;
+ goto generic;
}
+ ctx->skip_reconfig_option_check = true;
return 0;
+generic:
+ return generic_parse_monolithic(fc, data);
+
out_no_data:
+ if (is_remount_fc(fc)) {
+ ctx->skip_reconfig_option_check = true;
+ return 0;
+ }
dfprintk(MOUNT, "NFS: mount program didn't pass any mount data\n");
return -EINVAL;
@@ -1163,12 +1082,11 @@ static void nfs4_validate_mount_flags(struct nfs_fs_context *ctx)
/*
* Validate NFSv4 mount options
*/
-static int nfs4_validate_mount_data(void *options,
- struct nfs_fs_context *ctx,
- const char *dev_name)
+static int nfs4_parse_monolithic(struct fs_context *fc,
+ struct nfs4_mount_data *data)
{
+ struct nfs_fs_context *ctx = nfs_fc2context(fc);
struct sockaddr *sap = (struct sockaddr *)&ctx->nfs_server.address;
- struct nfs4_mount_data *data = (struct nfs4_mount_data *)options;
char *c;
if (data == NULL)
@@ -1218,7 +1136,7 @@ static int nfs4_validate_mount_data(void *options,
ctx->client_address = c;
/*
- * Translate to nfs_fs_context, which nfs4_fill_super
+ * Translate to nfs_fs_context, which nfs_fill_super
* can deal with.
*/
@@ -1238,12 +1156,20 @@ static int nfs4_validate_mount_data(void *options,
break;
default:
- return NFS_TEXT_DATA;
+ goto generic;
}
+ ctx->skip_reconfig_option_check = true;
return 0;
+generic:
+ return generic_parse_monolithic(fc, data);
+
out_no_data:
+ if (is_remount_fc(fc)) {
+ ctx->skip_reconfig_option_check = true;
+ return 0;
+ }
dfprintk(MOUNT, "NFS4: mount program didn't pass any mount data\n");
return -EINVAL;
@@ -1260,39 +1186,66 @@ static int nfs4_validate_mount_data(void *options,
dfprintk(MOUNT, "NFSv4: Unsupported transport protocol udp\n");
return -EINVAL;
}
+#endif
-int nfs_validate_mount_data(struct file_system_type *fs_type,
- void *options,
- struct nfs_fs_context *ctx,
- struct nfs_fh *mntfh,
- const char *dev_name)
-{
- if (fs_type == &nfs_fs_type)
- return nfs23_validate_mount_data(options, ctx, mntfh, dev_name);
- return nfs4_validate_mount_data(options, ctx, dev_name);
-}
-#else
-int nfs_validate_mount_data(struct file_system_type *fs_type,
- void *options,
- struct nfs_fs_context *ctx,
- struct nfs_fh *mntfh,
- const char *dev_name)
+/*
+ * Parse a monolithic block of data from sys_mount().
+ */
+static int nfs_fs_context_parse_monolithic(struct fs_context *fc,
+ void *data)
{
- return nfs23_validate_mount_data(options, ctx, mntfh, dev_name);
-}
+ if (fc->fs_type == &nfs_fs_type)
+ return nfs23_parse_monolithic(fc, data);
+
+#if IS_ENABLED(CONFIG_NFS_V4)
+ if (fc->fs_type == &nfs4_fs_type)
+ return nfs4_parse_monolithic(fc, data);
#endif
-int nfs_validate_text_mount_data(void *options,
- struct nfs_fs_context *ctx,
- const char *dev_name)
+ dfprintk(MOUNT, "NFS: Unsupported monolithic data version\n");
+ return -EINVAL;
+}
+
+/*
+ * Validate the preparsed information in the config.
+ */
+static int nfs_fs_context_validate(struct fs_context *fc)
{
- int port = 0;
+ struct nfs_fs_context *ctx = nfs_fc2context(fc);
+ struct nfs_subversion *nfs_mod;
+ struct sockaddr *sap = (struct sockaddr *)&ctx->nfs_server.address;
int max_namelen = PAGE_SIZE;
int max_pathlen = NFS_MAXPATHLEN;
- struct sockaddr *sap = (struct sockaddr *)&ctx->nfs_server.address;
+ int port = 0;
+ int ret;
- if (nfs_parse_mount_options((char *)options, ctx) == 0)
- return -EINVAL;
+ if (!fc->source)
+ goto out_no_device_name;
+
+ /* Check for sanity first. */
+ if (ctx->minorversion && ctx->version != 4)
+ goto out_minorversion_mismatch;
+
+ if (ctx->options & NFS_OPTION_MIGRATION &&
+ (ctx->version != 4 || ctx->minorversion != 0))
+ goto out_migration_misuse;
+
+ /* Verify that any proto=/mountproto= options match the address
+ * families in the addr=/mountaddr= options.
+ */
+ if (ctx->protofamily != AF_UNSPEC &&
+ ctx->protofamily != ctx->nfs_server.address.sa_family)
+ goto out_proto_mismatch;
+
+ if (ctx->mountfamily != AF_UNSPEC) {
+ if (ctx->mount_server.addrlen) {
+ if (ctx->mountfamily != ctx->mount_server.address.sa_family)
+ goto out_mountproto_mismatch;
+ } else {
+ if (ctx->mountfamily != ctx->nfs_server.address.sa_family)
+ goto out_mountproto_mismatch;
+ }
+ }
if (!nfs_verify_server_address(sap))
goto out_no_address;
@@ -1320,8 +1273,24 @@ int nfs_validate_text_mount_data(void *options,
nfs_set_port(sap, &ctx->nfs_server.port, port);
- return nfs_parse_devname(ctx, dev_name, max_namelen, max_pathlen);
+ ret = nfs_parse_devname(ctx, fc->source, max_namelen, max_pathlen);
+ if (ret < 0)
+ return ret;
+
+ /* Load the NFS protocol module if we haven't done so yet */
+ if (!ctx->mount_info.nfs_mod) {
+ nfs_mod = get_nfs_version(ctx->version);
+ if (IS_ERR(nfs_mod)) {
+ ret = PTR_ERR(nfs_mod);
+ goto out_version_unavailable;
+ }
+ ctx->mount_info.nfs_mod = nfs_mod;
+ }
+ return 0;
+out_no_device_name:
+ dfprintk(MOUNT, "NFS: Device name not specified\n");
+ return -EINVAL;
#if !IS_ENABLED(CONFIG_NFS_V4)
out_v4_not_compiled:
dfprintk(MOUNT, "NFS: NFSv4 is not compiled into kernel\n");
@@ -1331,8 +1300,201 @@ int nfs_validate_text_mount_data(void *options,
dfprintk(MOUNT, "NFSv4: Unsupported transport protocol udp\n");
return -EINVAL;
#endif /* !CONFIG_NFS_V4 */
-
out_no_address:
dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n");
return -EINVAL;
+out_mountproto_mismatch:
+ dfprintk(MOUNT, "NFS: Mount server address does not match mountproto= option\n");
+ return -EINVAL;
+out_proto_mismatch:
+ dfprintk(MOUNT, "NFS: Server address does not match proto= option\n");
+ return -EINVAL;
+out_minorversion_mismatch:
+ dfprintk(MOUNT, "NFS: Mount option vers=%u does not support minorversion=%u\n",
+ ctx->version, ctx->minorversion);
+ return -EINVAL;
+out_migration_misuse:
+ dfprintk(MOUNT, "NFS: 'Migration' not supported for this NFS version\n");
+ return -EINVAL;
+out_version_unavailable:
+ dfprintk(MOUNT, "NFS: Version unavailable\n");
+ return ret;
+}
+
+/*
+ * Create an NFS superblock by the appropriate method.
+ */
+static int nfs_get_tree(struct fs_context *fc)
+{
+ struct nfs_fs_context *ctx = nfs_fc2context(fc);
+ int err = nfs_fs_context_validate(fc);
+
+ if (err)
+ return err;
+ if (!ctx->internal)
+ return ctx->mount_info.nfs_mod->rpc_ops->try_get_tree(fc);
+ else
+ return nfs_get_tree_common(fc);
}
+
+/*
+ * Handle duplication of a configuration. The caller copied *src into *sc, but
+ * it can't deal with resource pointers in the filesystem context, so we have
+ * to do that. We need to clear pointers, copy data or get extra refs as
+ * appropriate.
+ */
+static int nfs_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc)
+{
+ struct nfs_fs_context *src = nfs_fc2context(src_fc), *ctx;
+
+ ctx = kmemdup(src, sizeof(struct nfs_fs_context), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->mount_info.mntfh = nfs_alloc_fhandle();
+ if (!ctx->mount_info.mntfh) {
+ kfree(ctx);
+ return -ENOMEM;
+ }
+ nfs_copy_fh(ctx->mount_info.mntfh, src->mount_info.mntfh);
+
+ __module_get(ctx->mount_info.nfs_mod->owner);
+ ctx->client_address = NULL;
+ ctx->mount_server.hostname = NULL;
+ ctx->nfs_server.export_path = NULL;
+ ctx->nfs_server.hostname = NULL;
+ ctx->fscache_uniq = NULL;
+ ctx->clone_data.addr = NULL;
+ ctx->clone_data.fattr = NULL;
+ fc->fs_private = ctx;
+ return 0;
+}
+
+static void nfs_fs_context_free(struct fs_context *fc)
+{
+ struct nfs_fs_context *ctx = nfs_fc2context(fc);
+
+ if (ctx) {
+ if (ctx->mount_info.server)
+ nfs_free_server(ctx->mount_info.server);
+ if (ctx->mount_info.nfs_mod)
+ put_nfs_version(ctx->mount_info.nfs_mod);
+ kfree(ctx->client_address);
+ kfree(ctx->mount_server.hostname);
+ kfree(ctx->nfs_server.export_path);
+ kfree(ctx->nfs_server.hostname);
+ kfree(ctx->fscache_uniq);
+ nfs_free_fhandle(ctx->mount_info.mntfh);
+ kfree(ctx->clone_data.addr);
+ nfs_free_fattr(ctx->clone_data.fattr);
+ kfree(ctx);
+ }
+}
+
+static const struct fs_context_operations nfs_fs_context_ops = {
+ .free = nfs_fs_context_free,
+ .dup = nfs_fs_context_dup,
+ .parse_param = nfs_fs_context_parse_param,
+ .parse_monolithic = nfs_fs_context_parse_monolithic,
+ .get_tree = nfs_get_tree,
+ .reconfigure = nfs_reconfigure,
+};
+
+/*
+ * Prepare superblock configuration. We use the namespaces attached to the
+ * context. This may be the current process's namespaces, or it may be a
+ * container's namespaces.
+ */
+static int nfs_init_fs_context(struct fs_context *fc)
+{
+ struct nfs_fs_context *ctx;
+
+ ctx = kzalloc(sizeof(struct nfs_fs_context), GFP_KERNEL);
+ if (unlikely(!ctx))
+ return -ENOMEM;
+
+ ctx->mount_info.ctx = ctx;
+ ctx->mount_info.mntfh = nfs_alloc_fhandle();
+ if (unlikely(!ctx->mount_info.mntfh)) {
+ kfree(ctx);
+ return -ENOMEM;
+ }
+
+ ctx->protofamily = AF_UNSPEC;
+ ctx->mountfamily = AF_UNSPEC;
+ ctx->mount_server.port = NFS_UNSPEC_PORT;
+
+ if (fc->root) {
+ /* reconfigure, start with the current config */
+ struct nfs_server *nfss = fc->root->d_sb->s_fs_info;
+ struct net *net = nfss->nfs_client->cl_net;
+
+ ctx->flags = nfss->flags;
+ ctx->rsize = nfss->rsize;
+ ctx->wsize = nfss->wsize;
+ ctx->retrans = nfss->client->cl_timeout->to_retries;
+ ctx->selected_flavor = nfss->client->cl_auth->au_flavor;
+ ctx->acregmin = nfss->acregmin / HZ;
+ ctx->acregmax = nfss->acregmax / HZ;
+ ctx->acdirmin = nfss->acdirmin / HZ;
+ ctx->acdirmax = nfss->acdirmax / HZ;
+ ctx->timeo = 10U * nfss->client->cl_timeout->to_initval / HZ;
+ ctx->nfs_server.port = nfss->port;
+ ctx->nfs_server.addrlen = nfss->nfs_client->cl_addrlen;
+ ctx->version = nfss->nfs_client->rpc_ops->version;
+ ctx->minorversion = nfss->nfs_client->cl_minorversion;
+
+ memcpy(&ctx->nfs_server.address, &nfss->nfs_client->cl_addr,
+ ctx->nfs_server.addrlen);
+
+ if (fc->net_ns != net) {
+ put_net(fc->net_ns);
+ fc->net_ns = get_net(net);
+ }
+
+ ctx->mount_info.nfs_mod = nfss->nfs_client->cl_nfs_mod;
+ __module_get(ctx->mount_info.nfs_mod->owner);
+ } else {
+ /* defaults */
+ ctx->timeo = NFS_UNSPEC_TIMEO;
+ ctx->retrans = NFS_UNSPEC_RETRANS;
+ ctx->acregmin = NFS_DEF_ACREGMIN;
+ ctx->acregmax = NFS_DEF_ACREGMAX;
+ ctx->acdirmin = NFS_DEF_ACDIRMIN;
+ ctx->acdirmax = NFS_DEF_ACDIRMAX;
+ ctx->nfs_server.port = NFS_UNSPEC_PORT;
+ ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP;
+ ctx->selected_flavor = RPC_AUTH_MAXFLAVOR;
+ ctx->minorversion = 0;
+ ctx->need_mount = true;
+ }
+ ctx->net = fc->net_ns;
+ fc->fs_private = ctx;
+ fc->ops = &nfs_fs_context_ops;
+ return 0;
+}
+
+struct file_system_type nfs_fs_type = {
+ .owner = THIS_MODULE,
+ .name = "nfs",
+ .init_fs_context = nfs_init_fs_context,
+ .parameters = &nfs_fs_parameters,
+ .kill_sb = nfs_kill_super,
+ .fs_flags = FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA,
+};
+MODULE_ALIAS_FS("nfs");
+EXPORT_SYMBOL_GPL(nfs_fs_type);
+
+#if IS_ENABLED(CONFIG_NFS_V4)
+struct file_system_type nfs4_fs_type = {
+ .owner = THIS_MODULE,
+ .name = "nfs4",
+ .init_fs_context = nfs_init_fs_context,
+ .parameters = &nfs_fs_parameters,
+ .kill_sb = nfs_kill_super,
+ .fs_flags = FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA,
+};
+MODULE_ALIAS_FS("nfs4");
+MODULE_ALIAS("nfs4");
+EXPORT_SYMBOL_GPL(nfs4_fs_type);
+#endif /* CONFIG_NFS_V4 */
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 003c2b8eb1e6..1cd09df9e0b5 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -4,7 +4,7 @@
*/
#include "nfs4_fs.h"
-#include <linux/mount.h>
+#include <linux/fs_context.h>
#include <linux/security.h>
#include <linux/crc32.h>
#include <linux/sunrpc/addr.h>
@@ -16,6 +16,7 @@
extern const struct export_operations nfs_export_ops;
struct nfs_string;
+struct nfs_pageio_descriptor;
static inline void nfs_attr_check_mountpoint(struct super_block *parent, struct nfs_fattr *fattr)
{
@@ -34,12 +35,13 @@ static inline int nfs_attr_use_mounted_on_fileid(struct nfs_fattr *fattr)
struct nfs_clone_mount {
const struct super_block *sb;
- const struct dentry *dentry;
+ struct dentry *dentry;
char *hostname;
char *mnt_path;
struct sockaddr *addr;
size_t addrlen;
rpc_authflavor_t authflavor;
+ struct nfs_fattr *fattr;
};
/*
@@ -78,10 +80,23 @@ struct nfs_client_initdata {
const struct cred *cred;
};
+struct nfs_mount_info {
+ unsigned int inherited_bsize;
+ struct nfs_fs_context *ctx;
+ struct nfs_clone_mount *cloned;
+ struct nfs_server *server;
+ struct nfs_fh *mntfh;
+ struct nfs_subversion *nfs_mod;
+};
+
/*
* In-kernel mount arguments
*/
struct nfs_fs_context {
+ bool internal;
+ bool skip_reconfig_option_check;
+ bool need_mount;
+ bool sloppy;
unsigned int flags; /* NFS{,4}_MOUNT_* flags */
unsigned int rsize, wsize;
unsigned int timeo, retrans;
@@ -98,8 +113,6 @@ struct nfs_fs_context {
char *fscache_uniq;
unsigned short protofamily;
unsigned short mountfamily;
- bool need_mount;
- bool sloppy;
struct {
union {
@@ -124,14 +137,23 @@ struct nfs_fs_context {
int port;
unsigned short protocol;
unsigned short nconnect;
+ unsigned short export_path_len;
} nfs_server;
void *lsm_opts;
struct net *net;
char buf[32]; /* Parse buffer */
+
+ struct nfs_mount_info mount_info;
+ struct nfs_clone_mount clone_data;
};
+static inline struct nfs_fs_context *nfs_fc2context(const struct fs_context *fc)
+{
+ return fc->fs_private;
+}
+
/* mount_clnt.c */
struct nfs_mount_request {
struct sockaddr *sap;
@@ -147,15 +169,6 @@ struct nfs_mount_request {
struct net *net;
};
-struct nfs_mount_info {
- unsigned int inherited_bsize;
- struct nfs_fs_context *ctx;
- struct nfs_clone_mount *cloned;
- struct nfs_server *server;
- struct nfs_fh *mntfh;
- struct nfs_subversion *nfs_mod;
-};
-
extern int nfs_mount(struct nfs_mount_request *info);
extern void nfs_umount(const struct nfs_mount_request *info);
@@ -235,22 +248,8 @@ static inline void nfs_fs_proc_exit(void)
extern const struct svc_version nfs4_callback_version1;
extern const struct svc_version nfs4_callback_version4;
-struct nfs_pageio_descriptor;
-
-/* mount.c */
-#define NFS_TEXT_DATA 1
-
-extern struct nfs_fs_context *nfs_alloc_parsed_mount_data(void);
-extern void nfs_free_parsed_mount_data(struct nfs_fs_context *ctx);
-extern int nfs_parse_mount_options(char *raw, struct nfs_fs_context *ctx);
-extern int nfs_validate_mount_data(struct file_system_type *fs_type,
- void *options,
- struct nfs_fs_context *ctx,
- struct nfs_fh *mntfh,
- const char *dev_name);
-extern int nfs_validate_text_mount_data(void *options,
- struct nfs_fs_context *ctx,
- const char *dev_name);
+/* fs_context.c */
+extern struct file_system_type nfs_fs_type;
/* pagelist.c */
extern int __init nfs_init_nfspagecache(void);
@@ -411,14 +410,9 @@ extern int nfs_wait_atomic_killable(atomic_t *p, unsigned int mode);
/* super.c */
extern const struct super_operations nfs_sops;
-extern struct file_system_type nfs_fs_type;
-extern struct file_system_type nfs_prepared_fs_type;
-#if IS_ENABLED(CONFIG_NFS_V4)
-extern struct file_system_type nfs4_referral_fs_type;
-#endif
bool nfs_auth_info_match(const struct nfs_auth_info *, rpc_authflavor_t);
-struct dentry *nfs_try_mount(int, const char *, struct nfs_mount_info *);
-struct dentry *nfs_fs_mount(struct file_system_type *, int, const char *, void *);
+int nfs_try_get_tree(struct fs_context *);
+int nfs_get_tree_common(struct fs_context *);
void nfs_kill_super(struct super_block *);
extern struct rpc_stat nfs_rpcstat;
@@ -446,10 +440,8 @@ static inline bool nfs_file_io_is_buffered(struct nfs_inode *nfsi)
extern char *nfs_path(char **p, struct dentry *dentry,
char *buffer, ssize_t buflen, unsigned flags);
extern struct vfsmount *nfs_d_automount(struct path *path);
-struct vfsmount *nfs_submount(struct nfs_server *, struct dentry *,
- struct nfs_fh *, struct nfs_fattr *);
-struct vfsmount *nfs_do_submount(struct dentry *, struct nfs_fh *,
- struct nfs_fattr *, rpc_authflavor_t);
+int nfs_submount(struct fs_context *, struct nfs_server *);
+int nfs_do_submount(struct fs_context *);
/* getroot.c */
extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *,
@@ -476,7 +468,7 @@ int nfs_show_options(struct seq_file *, struct dentry *);
int nfs_show_devname(struct seq_file *, struct dentry *);
int nfs_show_path(struct seq_file *, struct dentry *);
int nfs_show_stats(struct seq_file *, struct dentry *);
-int nfs_remount(struct super_block *sb, int *flags, char *raw_data);
+int nfs_reconfigure(struct fs_context *);
/* write.c */
extern void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio,
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
index bfe607374feb..9b344fcd23b0 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -140,34 +140,65 @@ EXPORT_SYMBOL_GPL(nfs_path);
*/
struct vfsmount *nfs_d_automount(struct path *path)
{
- struct vfsmount *mnt;
+ struct nfs_fs_context *ctx;
+ struct fs_context *fc;
+ struct vfsmount *mnt = ERR_PTR(-ENOMEM);
struct nfs_server *server = NFS_SERVER(d_inode(path->dentry));
- struct nfs_fh *fh = NULL;
- struct nfs_fattr *fattr = NULL;
+ struct nfs_client *client = server->nfs_client;
+ int ret;
if (IS_ROOT(path->dentry))
return ERR_PTR(-ESTALE);
- mnt = ERR_PTR(-ENOMEM);
- fh = nfs_alloc_fhandle();
- fattr = nfs_alloc_fattr();
- if (fh == NULL || fattr == NULL)
- goto out;
+ /* Open a new filesystem context, transferring parameters from the
+ * parent superblock, including the network namespace.
+ */
+ fc = fs_context_for_submount(&nfs_fs_type, path->dentry);
+ if (IS_ERR(fc))
+ return ERR_CAST(fc);
- mnt = server->nfs_client->rpc_ops->submount(server, path->dentry, fh, fattr);
+ ctx = nfs_fc2context(fc);
+ ctx->clone_data.dentry = path->dentry;
+ ctx->clone_data.sb = path->dentry->d_sb;
+ ctx->clone_data.fattr = nfs_alloc_fattr();
+ if (!ctx->clone_data.fattr)
+ goto out_fc;
+
+ if (fc->net_ns != client->cl_net) {
+ put_net(fc->net_ns);
+ fc->net_ns = get_net(client->cl_net);
+ }
+
+ /* for submounts we want the same server; referrals will reassign */
+ memcpy(&ctx->nfs_server.address, &client->cl_addr, client->cl_addrlen);
+ ctx->nfs_server.addrlen = client->cl_addrlen;
+ ctx->nfs_server.port = server->port;
+
+ ctx->version = client->rpc_ops->version;
+ ctx->minorversion = client->cl_minorversion;
+ ctx->mount_info.nfs_mod = client->cl_nfs_mod;
+ __module_get(ctx->mount_info.nfs_mod->owner);
+
+ ret = client->rpc_ops->submount(fc, server);
+ if (ret < 0) {
+ mnt = ERR_PTR(ret);
+ goto out_fc;
+ }
+
+ up_write(&fc->root->d_sb->s_umount);
+ mnt = vfs_create_mount(fc);
if (IS_ERR(mnt))
- goto out;
+ goto out_fc;
if (nfs_mountpoint_expiry_timeout < 0)
- goto out;
+ goto out_fc;
mntget(mnt); /* prevent immediate expiration */
mnt_set_expiry(mnt, &nfs_automount_list);
schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout);
-out:
- nfs_free_fattr(fattr);
- nfs_free_fhandle(fh);
+out_fc:
+ put_fs_context(fc);
return mnt;
}
@@ -222,61 +253,62 @@ void nfs_release_automount_timer(void)
* @authflavor: security flavor to use when performing the mount
*
*/
-struct vfsmount *nfs_do_submount(struct dentry *dentry, struct nfs_fh *fh,
- struct nfs_fattr *fattr, rpc_authflavor_t authflavor)
+int nfs_do_submount(struct fs_context *fc)
{
- struct super_block *sb = dentry->d_sb;
- struct nfs_clone_mount mountdata = {
- .sb = sb,
- .dentry = dentry,
- .authflavor = authflavor,
- };
- struct nfs_mount_info mount_info = {
- .inherited_bsize = sb->s_blocksize_bits,
- .cloned = &mountdata,
- .mntfh = fh,
- .nfs_mod = NFS_SB(sb)->nfs_client->cl_nfs_mod,
- };
+ struct nfs_fs_context *ctx = nfs_fc2context(fc);
+ struct dentry *dentry = ctx->clone_data.dentry;
struct nfs_server *server;
- struct vfsmount *mnt;
- char *page = (char *) __get_free_page(GFP_USER);
- char *devname;
+ char *buffer, *p;
+ int ret;
- if (page == NULL)
- return ERR_PTR(-ENOMEM);
+ /* create a new volume representation */
+ server = ctx->mount_info.nfs_mod->rpc_ops->clone_server(NFS_SB(ctx->clone_data.sb),
+ ctx->mount_info.mntfh,
+ ctx->clone_data.fattr,
+ ctx->selected_flavor);
- server = mount_info.nfs_mod->rpc_ops->clone_server(NFS_SB(sb), fh,
- fattr, authflavor);
if (IS_ERR(server))
- return ERR_CAST(server);
+ return PTR_ERR(server);
- mount_info.server = server;
+ ctx->mount_info.server = server;
- devname = nfs_devname(dentry, page, PAGE_SIZE);
- if (IS_ERR(devname))
- mnt = ERR_CAST(devname);
- else
- mnt = vfs_submount(dentry, &nfs_prepared_fs_type, devname, &mount_info);
+ buffer = kmalloc(4096, GFP_USER);
+ if (!buffer)
+ return -ENOMEM;
- if (mount_info.server)
- nfs_free_server(mount_info.server);
- free_page((unsigned long)page);
- return mnt;
+ ctx->internal = true;
+ ctx->mount_info.inherited_bsize = ctx->clone_data.sb->s_blocksize_bits;
+
+ p = nfs_devname(dentry, buffer, 4096);
+ if (IS_ERR(p)) {
+ dprintk("NFS: Couldn't determine submount pathname\n");
+ ret = PTR_ERR(p);
+ } else {
+ ret = vfs_parse_fs_string(fc, "source", p, buffer + 4096 - p);
+ if (!ret)
+ ret = vfs_get_tree(fc);
+ }
+ kfree(buffer);
+ return ret;
}
EXPORT_SYMBOL_GPL(nfs_do_submount);
-struct vfsmount *nfs_submount(struct nfs_server *server, struct dentry *dentry,
- struct nfs_fh *fh, struct nfs_fattr *fattr)
+int nfs_submount(struct fs_context *fc, struct nfs_server *server)
{
- int err;
+ struct nfs_fs_context *ctx = nfs_fc2context(fc);
+ struct dentry *dentry = ctx->clone_data.dentry;
struct dentry *parent = dget_parent(dentry);
+ int err;
/* Look it up again to get its attributes */
- err = server->nfs_client->rpc_ops->lookup(d_inode(parent), &dentry->d_name, fh, fattr, NULL);
+ err = server->nfs_client->rpc_ops->lookup(d_inode(parent), &dentry->d_name,
+ ctx->mount_info.mntfh, ctx->clone_data.fattr,
+ NULL);
dput(parent);
if (err != 0)
- return ERR_PTR(err);
+ return err;
- return nfs_do_submount(dentry, fh, fattr, server->client->cl_auth->au_flavor);
+ ctx->selected_flavor = server->client->cl_auth->au_flavor;
+ return nfs_do_submount(fc);
}
EXPORT_SYMBOL_GPL(nfs_submount);
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index 9eb2f1a503ab..657041c3a03f 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -990,7 +990,7 @@ const struct nfs_rpc_ops nfs_v3_clientops = {
.nlmclnt_ops = &nlmclnt_fl_close_lock_ops,
.getroot = nfs3_proc_get_root,
.submount = nfs_submount,
- .try_mount = nfs_try_mount,
+ .try_get_tree = nfs_try_get_tree,
.getattr = nfs3_proc_getattr,
.setattr = nfs3_proc_setattr,
.lookup = nfs3_proc_lookup,
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index 5d539dce9cef..9c136d53987d 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -268,14 +268,13 @@ extern const struct dentry_operations nfs4_dentry_operations;
int nfs_atomic_open(struct inode *, struct dentry *, struct file *,
unsigned, umode_t);
-/* super.c */
+/* fs_context.c */
extern struct file_system_type nfs4_fs_type;
/* nfs4namespace.c */
struct rpc_clnt *nfs4_negotiate_security(struct rpc_clnt *, struct inode *,
const struct qstr *);
-struct vfsmount *nfs4_submount(struct nfs_server *, struct dentry *,
- struct nfs_fh *, struct nfs_fattr *);
+int nfs4_submount(struct fs_context *, struct nfs_server *);
int nfs4_replace_transport(struct nfs_server *server,
const struct nfs4_fs_locations *locations);
@@ -526,7 +525,6 @@ extern const nfs4_stateid invalid_stateid;
/* nfs4super.c */
struct nfs_mount_info;
extern struct nfs_subversion nfs_v4;
-struct dentry *nfs4_try_mount(int, const char *, struct nfs_mount_info *);
extern bool nfs4_disable_idmapping;
extern unsigned short max_session_slots;
extern unsigned short max_session_cb_slots;
@@ -536,6 +534,9 @@ extern bool recover_lost_locks;
#define NFS4_CLIENT_ID_UNIQ_LEN (64)
extern char nfs4_client_id_uniquifier[NFS4_CLIENT_ID_UNIQ_LEN];
+extern int nfs4_try_get_tree(struct fs_context *);
+extern int nfs4_get_referral_tree(struct fs_context *);
+
/* nfs4sysctl.c */
#ifdef CONFIG_SYSCTL
int nfs4_register_sysctl(void);
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c
index 620de905cba9..be4eb720d5b6 100644
--- a/fs/nfs/nfs4file.c
+++ b/fs/nfs/nfs4file.c
@@ -7,6 +7,7 @@
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/falloc.h>
+#include <linux/mount.h>
#include <linux/nfs_fs.h>
#include "delegation.h"
#include "internal.h"
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c
index 2e460c33ae48..a1a0c4c53ce1 100644
--- a/fs/nfs/nfs4namespace.c
+++ b/fs/nfs/nfs4namespace.c
@@ -8,6 +8,7 @@
* NFSv4 namespace
*/
+#include <linux/module.h>
#include <linux/dcache.h>
#include <linux/mount.h>
#include <linux/namei.h>
@@ -21,37 +22,64 @@
#include <linux/inet.h>
#include "internal.h"
#include "nfs4_fs.h"
+#include "nfs.h"
#include "dns_resolve.h"
#define NFSDBG_FACILITY NFSDBG_VFS
+/*
+ * Work out the length that an NFSv4 path would render to as a standard posix
+ * path, with a leading slash but no terminating slash.
+ */
+static ssize_t nfs4_pathname_len(const struct nfs4_pathname *pathname)
+{
+ ssize_t len = 0;
+ int i;
+
+ for (i = 0; i < pathname->ncomponents; i++) {
+ const struct nfs4_string *component = &pathname->components[i];
+
+ if (component->len > NAME_MAX)
+ goto too_long;
+ len += 1 + component->len; /* Adding "/foo" */
+ if (len > PATH_MAX)
+ goto too_long;
+ }
+ return len;
+
+too_long:
+ return -ENAMETOOLONG;
+}
+
/*
* Convert the NFSv4 pathname components into a standard posix path.
- *
- * Note that the resulting string will be placed at the end of the buffer
*/
-static inline char *nfs4_pathname_string(const struct nfs4_pathname *pathname,
- char *buffer, ssize_t buflen)
+static char *nfs4_pathname_string(const struct nfs4_pathname *pathname,
+ unsigned short *_len)
{
- char *end = buffer + buflen;
- int n;
+ ssize_t len;
+ char *buf, *p;
+ int i;
+
+ len = nfs4_pathname_len(pathname);
+ if (len < 0)
+ return ERR_PTR(len);
+ *_len = len;
+
+ p = buf = kmalloc(len + 1, GFP_KERNEL);
+ if (!buf)
+ return ERR_PTR(-ENOMEM);
+
+ for (i = 0; i < pathname->ncomponents; i++) {
+ const struct nfs4_string *component = &pathname->components[i];
- *--end = '\0';
- buflen--;
-
- n = pathname->ncomponents;
- while (--n >= 0) {
- const struct nfs4_string *component = &pathname->components[n];
- buflen -= component->len + 1;
- if (buflen < 0)
- goto Elong;
- end -= component->len;
- memcpy(end, component->data, component->len);
- *--end = '/';
+ *p++ = '/';
+ memcpy(p, component->data, component->len);
+ p += component->len;
}
- return end;
-Elong:
- return ERR_PTR(-ENAMETOOLONG);
+
+ *p = 0;
+ return buf;
}
/*
@@ -100,21 +128,32 @@ static char *nfs4_path(struct dentry *dentry, char *buffer, ssize_t buflen)
*/
static int nfs4_validate_fspath(struct dentry *dentry,
const struct nfs4_fs_locations *locations,
- char *page, char *page2)
+ struct nfs_fs_context *ctx)
{
const char *path, *fs_path;
+ char *buf;
+ unsigned short len;
+ int n;
- path = nfs4_path(dentry, page, PAGE_SIZE);
- if (IS_ERR(path))
+ buf = kmalloc(4096, GFP_KERNEL);
+ path = nfs4_path(dentry, buf, 4096);
+ if (IS_ERR(path)) {
+ kfree(buf);
return PTR_ERR(path);
+ }
- fs_path = nfs4_pathname_string(&locations->fs_path, page2, PAGE_SIZE);
- if (IS_ERR(fs_path))
+ fs_path = nfs4_pathname_string(&locations->fs_path, &len);
+ if (IS_ERR(fs_path)) {
+ kfree(buf);
return PTR_ERR(fs_path);
+ }
- if (strncmp(path, fs_path, strlen(fs_path)) != 0) {
+ n = strncmp(path, fs_path, len);
+ kfree(buf);
+ kfree(fs_path);
+ if (n != 0) {
dprintk("%s: path %s does not begin with fsroot %s\n",
- __func__, path, fs_path);
+ __func__, path, ctx->nfs_server.export_path);
return -ENOENT;
}
@@ -236,55 +275,83 @@ nfs4_negotiate_security(struct rpc_clnt *clnt, struct inode *inode,
return new;
}
-static struct vfsmount *try_location(struct nfs_clone_mount *mountdata,
- char *page, char *page2,
- const struct nfs4_fs_location *location)
+static int try_location(struct fs_context *fc,
+ const struct nfs4_fs_location *location)
{
const size_t addr_bufsize = sizeof(struct sockaddr_storage);
- struct net *net = rpc_net_ns(NFS_SB(mountdata->sb)->client);
- struct vfsmount *mnt = ERR_PTR(-ENOENT);
- char *mnt_path;
- unsigned int maxbuflen;
- unsigned int s;
+ struct nfs_fs_context *ctx = nfs_fc2context(fc);
+ unsigned int len, s;
+ char *export_path, *source, *p;
+ int ret = -ENOENT;
+
+ /* Allocate a buffer big enough to hold any of the hostnames plus a
+ * terminating char and also a buffer big enough to hold the hostname
+ * plus a colon plus the path.
+ */
+ len = 0;
+ for (s = 0; s < location->nservers; s++) {
+ const struct nfs4_string *buf = &location->servers[s];
+ if (buf->len > len)
+ len = buf->len;
+ }
- mnt_path = nfs4_pathname_string(&location->rootpath, page2, PAGE_SIZE);
- if (IS_ERR(mnt_path))
- return ERR_CAST(mnt_path);
- mountdata->mnt_path = mnt_path;
- maxbuflen = mnt_path - 1 - page2;
+ kfree(ctx->nfs_server.hostname);
+ ctx->nfs_server.hostname = kmalloc(len + 1, GFP_KERNEL);
+ if (!ctx->nfs_server.hostname)
+ return -ENOMEM;
- mountdata->addr = kmalloc(addr_bufsize, GFP_KERNEL);
- if (mountdata->addr == NULL)
- return ERR_PTR(-ENOMEM);
+ export_path = nfs4_pathname_string(&location->rootpath,
+ &ctx->nfs_server.export_path_len);
+ if (IS_ERR(export_path))
+ return PTR_ERR(export_path);
+ ctx->nfs_server.export_path = export_path;
+
+ source = kmalloc(len + 1 + ctx->nfs_server.export_path_len + 1,
+ GFP_KERNEL);
+ if (!source)
+ return -ENOMEM;
+
+ kfree(fc->source);
+ fc->source = source;
+
+ ctx->clone_data.addr = kmalloc(addr_bufsize, GFP_KERNEL);
+ if (ctx->clone_data.addr == NULL)
+ return -ENOMEM;
for (s = 0; s < location->nservers; s++) {
const struct nfs4_string *buf = &location->servers[s];
- if (buf->len <= 0 || buf->len >= maxbuflen)
- continue;
-
if (memchr(buf->data, IPV6_SCOPE_DELIMITER, buf->len))
continue;
- mountdata->addrlen = nfs_parse_server_name(buf->data, buf->len,
- mountdata->addr, addr_bufsize, net);
- if (mountdata->addrlen == 0)
+ ctx->clone_data.addrlen =
+ nfs_parse_server_name(buf->data, buf->len,
+ ctx->clone_data.addr,
+ addr_bufsize,
+ fc->net_ns);
+ if (ctx->clone_data.addrlen == 0)
continue;
- memcpy(page2, buf->data, buf->len);
- page2[buf->len] = '\0';
- mountdata->hostname = page2;
+ rpc_set_port(ctx->clone_data.addr, NFS_PORT);
- snprintf(page, PAGE_SIZE, "%s:%s",
- mountdata->hostname,
- mountdata->mnt_path);
+ memcpy(ctx->nfs_server.hostname, buf->data, buf->len);
+ ctx->nfs_server.hostname[buf->len] = '\0';
+ ctx->clone_data.hostname = ctx->nfs_server.hostname;
- mnt = vfs_submount(mountdata->dentry, &nfs4_referral_fs_type, page, mountdata);
- if (!IS_ERR(mnt))
- break;
+ p = source;
+ memcpy(p, buf->data, buf->len);
+ p += buf->len;
+ *p++ = ':';
+ memcpy(p, ctx->nfs_server.export_path, ctx->nfs_server.export_path_len);
+ p += ctx->nfs_server.export_path_len;
+ *p = 0;
+
+ ret = nfs4_get_referral_tree(fc);
+ if (ret == 0)
+ return 0;
}
- kfree(mountdata->addr);
- return mnt;
+
+ return ret;
}
/**
@@ -293,38 +360,23 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata,
* @locations: array of NFSv4 server location information
*
*/
-static struct vfsmount *nfs_follow_referral(struct dentry *dentry,
- const struct nfs4_fs_locations *locations)
+static int nfs_follow_referral(struct fs_context *fc,
+ const struct nfs4_fs_locations *locations)
{
- struct vfsmount *mnt = ERR_PTR(-ENOENT);
- struct nfs_clone_mount mountdata = {
- .sb = dentry->d_sb,
- .dentry = dentry,
- .authflavor = NFS_SB(dentry->d_sb)->client->cl_auth->au_flavor,
- };
- char *page = NULL, *page2 = NULL;
+ struct nfs_fs_context *ctx = nfs_fc2context(fc);
int loc, error;
if (locations == NULL || locations->nlocations <= 0)
- goto out;
-
- dprintk("%s: referral at %pd2\n", __func__, dentry);
-
- page = (char *) __get_free_page(GFP_USER);
- if (!page)
- goto out;
+ return -ENOENT;
- page2 = (char *) __get_free_page(GFP_USER);
- if (!page2)
- goto out;
+ dprintk("%s: referral at %pd2\n", __func__, ctx->clone_data.dentry);
/* Ensure fs path is a prefix of current dentry path */
- error = nfs4_validate_fspath(dentry, locations, page, page2);
- if (error < 0) {
- mnt = ERR_PTR(error);
- goto out;
- }
+ error = nfs4_validate_fspath(ctx->clone_data.dentry, locations, ctx);
+ if (error < 0)
+ return error;
+ error = -ENOENT;
for (loc = 0; loc < locations->nlocations; loc++) {
const struct nfs4_fs_location *location = &locations->locations[loc];
@@ -332,15 +384,12 @@ static struct vfsmount *nfs_follow_referral(struct dentry *dentry,
location->rootpath.ncomponents == 0)
continue;
- mnt = try_location(&mountdata, page, page2, location);
- if (!IS_ERR(mnt))
- break;
+ error = try_location(fc, location);
+ if (error == 0)
+ return 0;
}
-out:
- free_page((unsigned long) page);
- free_page((unsigned long) page2);
- return mnt;
+ return error;
}
/*
@@ -348,71 +397,73 @@ static struct vfsmount *nfs_follow_referral(struct dentry *dentry,
* @dentry - dentry of referral
*
*/
-static struct vfsmount *nfs_do_refmount(struct rpc_clnt *client, struct dentry *dentry)
+static int nfs_do_refmount(struct fs_context *fc, struct rpc_clnt *client)
{
- struct vfsmount *mnt = ERR_PTR(-ENOMEM);
- struct dentry *parent;
+ struct nfs_fs_context *ctx = nfs_fc2context(fc);
+ struct dentry *dentry, *parent;
struct nfs4_fs_locations *fs_locations = NULL;
struct page *page;
- int err;
+ int err = -ENOMEM;
/* BUG_ON(IS_ROOT(dentry)); */
page = alloc_page(GFP_KERNEL);
- if (page == NULL)
- return mnt;
+ if (!page)
+ return -ENOMEM;
fs_locations = kmalloc(sizeof(struct nfs4_fs_locations), GFP_KERNEL);
- if (fs_locations == NULL)
+ if (!fs_locations)
goto out_free;
/* Get locations */
- mnt = ERR_PTR(-ENOENT);
-
+ dentry = ctx->clone_data.dentry;
parent = dget_parent(dentry);
dprintk("%s: getting locations for %pd2\n",
__func__, dentry);
err = nfs4_proc_fs_locations(client, d_inode(parent), &dentry->d_name, fs_locations, page);
dput(parent);
- if (err != 0 ||
- fs_locations->nlocations <= 0 ||
+ if (err != 0)
+ goto out_free_2;
+
+ err = -ENOENT;
+ if (fs_locations->nlocations <= 0 ||
fs_locations->fs_path.ncomponents <= 0)
- goto out_free;
+ goto out_free_2;
- mnt = nfs_follow_referral(dentry, fs_locations);
+ err = nfs_follow_referral(fc, fs_locations);
+out_free_2:
+ kfree(fs_locations);
out_free:
__free_page(page);
- kfree(fs_locations);
- return mnt;
+ return err;
}
-struct vfsmount *nfs4_submount(struct nfs_server *server, struct dentry *dentry,
- struct nfs_fh *fh, struct nfs_fattr *fattr)
+int nfs4_submount(struct fs_context *fc, struct nfs_server *server)
{
- rpc_authflavor_t flavor = server->client->cl_auth->au_flavor;
+ struct nfs_fs_context *ctx = nfs_fc2context(fc);
+ struct dentry *dentry = ctx->clone_data.dentry;
struct dentry *parent = dget_parent(dentry);
struct inode *dir = d_inode(parent);
const struct qstr *name = &dentry->d_name;
struct rpc_clnt *client;
- struct vfsmount *mnt;
+ int ret;
/* Look it up again to get its attributes and sec flavor */
- client = nfs4_proc_lookup_mountpoint(dir, name, fh, fattr);
+ client = nfs4_proc_lookup_mountpoint(dir, name, ctx->mount_info.mntfh,
+ ctx->clone_data.fattr);
dput(parent);
if (IS_ERR(client))
- return ERR_CAST(client);
+ return PTR_ERR(client);
- if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) {
- mnt = nfs_do_refmount(client, dentry);
- goto out;
+ ctx->selected_flavor = client->cl_auth->au_flavor;
+ if (ctx->clone_data.fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) {
+ ret = nfs_do_refmount(fc, client);
+ } else {
+ ret = nfs_do_submount(fc);
}
- if (client->cl_auth->au_flavor != flavor)
- flavor = client->cl_auth->au_flavor;
- mnt = nfs_do_submount(dentry, fh, fattr, flavor);
-out:
rpc_shutdown_client(client);
- return mnt;
+ return ret;
}
/*
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 76d37161409a..5f51f62b0652 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -10001,7 +10001,7 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
.file_ops = &nfs4_file_operations,
.getroot = nfs4_proc_get_root,
.submount = nfs4_submount,
- .try_mount = nfs4_try_mount,
+ .try_get_tree = nfs4_try_get_tree,
.getattr = nfs4_proc_getattr,
.setattr = nfs4_proc_setattr,
.lookup = nfs4_proc_lookup,
diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c
index f931e8f49b05..469726410c5c 100644
--- a/fs/nfs/nfs4super.c
+++ b/fs/nfs/nfs4super.c
@@ -4,6 +4,7 @@
*/
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/mount.h>
#include <linux/nfs4_mount.h>
#include <linux/nfs_fs.h>
#include "delegation.h"
@@ -18,16 +19,6 @@
static int nfs4_write_inode(struct inode *inode, struct writeback_control *wbc);
static void nfs4_evict_inode(struct inode *inode);
-static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *raw_data);
-
-struct file_system_type nfs4_referral_fs_type = {
- .owner = THIS_MODULE,
- .name = "nfs4",
- .mount = nfs4_referral_mount,
- .kill_sb = nfs_kill_super,
- .fs_flags = FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA,
-};
static const struct super_operations nfs4_sops = {
.alloc_inode = nfs_alloc_inode,
@@ -41,7 +32,6 @@ static const struct super_operations nfs4_sops = {
.show_devname = nfs_show_devname,
.show_path = nfs_show_path,
.show_stats = nfs_show_stats,
- .remount_fs = nfs_remount,
};
struct nfs_subversion nfs_v4 = {
@@ -147,102 +137,121 @@ static void nfs_referral_loop_unprotect(void)
kfree(p);
}
-static struct dentry *do_nfs4_mount(struct nfs_server *server, int flags,
- struct nfs_mount_info *info,
- const char *hostname,
- const char *export_path)
+static int do_nfs4_mount(struct nfs_server *server,
+ struct fs_context *fc,
+ const char *hostname,
+ const char *export_path)
{
+ struct nfs_fs_context *root_ctx;
+ struct fs_context *root_fc;
struct vfsmount *root_mnt;
struct dentry *dentry;
- char *root_devname;
- int err;
size_t len;
+ int ret;
+
+ struct fs_parameter param = {
+ .key = "source",
+ .type = fs_value_is_string,
+ .dirfd = -1,
+ };
if (IS_ERR(server))
- return ERR_CAST(server);
+ return PTR_ERR(server);
- len = strlen(hostname) + 5;
- root_devname = kmalloc(len, GFP_KERNEL);
- if (root_devname == NULL) {
+ root_fc = vfs_dup_fs_context(fc);
+ if (IS_ERR(root_fc)) {
nfs_free_server(server);
- return ERR_PTR(-ENOMEM);
+ return PTR_ERR(root_fc);
+ }
+ kfree(root_fc->source);
+ root_fc->source = NULL;
+
+ root_ctx = nfs_fc2context(root_fc);
+ root_ctx->internal = true;
+ root_ctx->mount_info.server = server;
+ /* We leave export_path unset as it's not used to find the root. */
+
+ len = strlen(hostname) + 5;
+ param.string = kmalloc(len, GFP_KERNEL);
+ if (param.string == NULL) {
+ put_fs_context(root_fc);
+ return -ENOMEM;
}
/* Does hostname needs to be enclosed in brackets? */
if (strchr(hostname, ':'))
- snprintf(root_devname, len, "[%s]:/", hostname);
+ param.size = snprintf(param.string, len, "[%s]:/", hostname);
else
- snprintf(root_devname, len, "%s:/", hostname);
- info->server = server;
- root_mnt = vfs_kern_mount(&nfs_prepared_fs_type, flags, root_devname, info);
- if (info->server)
- nfs_free_server(info->server);
- info->server = NULL;
- kfree(root_devname);
+ param.size = snprintf(param.string, len, "%s:/", hostname);
+ ret = vfs_parse_fs_param(root_fc, ¶m);
+ kfree(param.string);
+ if (ret < 0) {
+ put_fs_context(root_fc);
+ return ret;
+ }
+ root_mnt = fc_mount(root_fc);
+ put_fs_context(root_fc);
if (IS_ERR(root_mnt))
- return ERR_CAST(root_mnt);
+ return PTR_ERR(root_mnt);
- err = nfs_referral_loop_protect();
- if (err) {
+ ret = nfs_referral_loop_protect();
+ if (ret) {
mntput(root_mnt);
- return ERR_PTR(err);
+ return ret;
}
dentry = mount_subtree(root_mnt, export_path);
nfs_referral_loop_unprotect();
- return dentry;
+ if (IS_ERR(dentry))
+ return PTR_ERR(dentry);
+
+ fc->root = dentry;
+ return 0;
}
-struct dentry *nfs4_try_mount(int flags, const char *dev_name,
- struct nfs_mount_info *mount_info)
+int nfs4_try_get_tree(struct fs_context *fc)
{
- struct nfs_fs_context *ctx = mount_info->ctx;
- struct dentry *res;
-
- dfprintk(MOUNT, "--> nfs4_try_mount()\n");
+ struct nfs_fs_context *ctx = nfs_fc2context(fc);
+ int err;
- res = do_nfs4_mount(nfs4_create_server(mount_info),
- flags, mount_info,
- ctx->nfs_server.hostname,
- ctx->nfs_server.export_path);
+ dfprintk(MOUNT, "--> nfs4_try_get_tree()\n");
- dfprintk(MOUNT, "<-- nfs4_try_mount() = %d%s\n",
- PTR_ERR_OR_ZERO(res),
- IS_ERR(res) ? " [error]" : "");
- return res;
+ /* We create a mount for the server's root, walk to the requested
+ * location and then create another mount for that.
+ */
+ err= do_nfs4_mount(nfs4_create_server(&ctx->mount_info),
+ fc, ctx->nfs_server.hostname,
+ ctx->nfs_server.export_path);
+ if (err) {
+ dfprintk(MOUNT, "<-- nfs4_try_get_tree() = %d [error]\n", err);
+ } else {
+ dfprintk(MOUNT, "<-- nfs4_try_get_tree() = 0\n");
+ }
+ return err;
}
/*
* Create an NFS4 server record on referral traversal
*/
-static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *raw_data)
+int nfs4_get_referral_tree(struct fs_context *fc)
{
- struct nfs_clone_mount *data = raw_data;
- struct nfs_mount_info mount_info = {
- .cloned = data,
- .nfs_mod = &nfs_v4,
- };
- struct dentry *res;
+ struct nfs_fs_context *ctx = nfs_fc2context(fc);
+ int err;
dprintk("--> nfs4_referral_mount()\n");
- mount_info.mntfh = nfs_alloc_fhandle();
- if (!mount_info.mntfh)
- return ERR_PTR(-ENOMEM);
-
- res = do_nfs4_mount(nfs4_create_referral_server(mount_info.cloned,
- mount_info.mntfh),
- flags, &mount_info, data->hostname, data->mnt_path);
-
- dprintk("<-- nfs4_referral_mount() = %d%s\n",
- PTR_ERR_OR_ZERO(res),
- IS_ERR(res) ? " [error]" : "");
-
- nfs_free_fhandle(mount_info.mntfh);
- return res;
+ /* create a new volume representation */
+ err = do_nfs4_mount(nfs4_create_referral_server(&ctx->clone_data, ctx->mount_info.mntfh),
+ fc, ctx->nfs_server.hostname,
+ ctx->nfs_server.export_path);
+ if (err) {
+ dfprintk(MOUNT, "<-- nfs4_get_referral_tree() = %d [error]\n", err);
+ } else {
+ dfprintk(MOUNT, "<-- nfs4_get_referral_tree() = 0\n");
+ }
+ return err;
}
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index 0f7288b94633..44a15523bf40 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -710,7 +710,7 @@ const struct nfs_rpc_ops nfs_v2_clientops = {
.file_ops = &nfs_file_operations,
.getroot = nfs_proc_get_root,
.submount = nfs_submount,
- .try_mount = nfs_try_mount,
+ .try_get_tree = nfs_try_get_tree,
.getattr = nfs_proc_getattr,
.setattr = nfs_proc_setattr,
.lookup = nfs_proc_lookup,
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 6c9573a32a69..6ff99da978a8 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -70,28 +70,6 @@
#define NFSDBG_FACILITY NFSDBG_VFS
-static struct dentry *nfs_prepared_mount(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *raw_data);
-
-struct file_system_type nfs_fs_type = {
- .owner = THIS_MODULE,
- .name = "nfs",
- .mount = nfs_fs_mount,
- .kill_sb = nfs_kill_super,
- .fs_flags = FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA,
-};
-MODULE_ALIAS_FS("nfs");
-EXPORT_SYMBOL_GPL(nfs_fs_type);
-
-struct file_system_type nfs_prepared_fs_type = {
- .owner = THIS_MODULE,
- .name = "nfs",
- .mount = nfs_prepared_mount,
- .kill_sb = nfs_kill_super,
- .fs_flags = FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA,
-};
-EXPORT_SYMBOL_GPL(nfs_prepared_fs_type);
-
const struct super_operations nfs_sops = {
.alloc_inode = nfs_alloc_inode,
.free_inode = nfs_free_inode,
@@ -104,22 +82,10 @@ const struct super_operations nfs_sops = {
.show_devname = nfs_show_devname,
.show_path = nfs_show_path,
.show_stats = nfs_show_stats,
- .remount_fs = nfs_remount,
};
EXPORT_SYMBOL_GPL(nfs_sops);
#if IS_ENABLED(CONFIG_NFS_V4)
-struct file_system_type nfs4_fs_type = {
- .owner = THIS_MODULE,
- .name = "nfs4",
- .mount = nfs_fs_mount,
- .kill_sb = nfs_kill_super,
- .fs_flags = FS_RENAME_DOES_D_MOVE|FS_BINARY_MOUNTDATA,
-};
-MODULE_ALIAS_FS("nfs4");
-MODULE_ALIAS("nfs4");
-EXPORT_SYMBOL_GPL(nfs4_fs_type);
-
static int __init register_nfs4_fs(void)
{
return register_filesystem(&nfs4_fs_type);
@@ -911,20 +877,19 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf
return nfs_mod->rpc_ops->create_server(mount_info);
}
-static struct dentry *nfs_fs_mount_common(int, const char *, struct nfs_mount_info *);
-
-struct dentry *nfs_try_mount(int flags, const char *dev_name,
- struct nfs_mount_info *mount_info)
+int nfs_try_get_tree(struct fs_context *fc)
{
- struct nfs_subversion *nfs_mod = mount_info->nfs_mod;
- if (mount_info->ctx->need_mount)
- mount_info->server = nfs_try_mount_request(mount_info);
+ struct nfs_fs_context *ctx = nfs_fc2context(fc);
+
+ if (ctx->need_mount)
+ ctx->mount_info.server = nfs_try_mount_request(&ctx->mount_info);
else
- mount_info->server = nfs_mod->rpc_ops->create_server(mount_info);
+ ctx->mount_info.server = ctx->mount_info.nfs_mod->rpc_ops->create_server(&ctx->mount_info);
- return nfs_fs_mount_common(flags, dev_name, mount_info);
+ return nfs_get_tree_common(fc);
}
-EXPORT_SYMBOL_GPL(nfs_try_mount);
+EXPORT_SYMBOL_GPL(nfs_try_get_tree);
+
#define NFS_REMOUNT_CMP_FLAGMASK ~(NFS_MOUNT_INTR \
| NFS_MOUNT_SECURE \
@@ -965,15 +930,11 @@ nfs_compare_remount_data(struct nfs_server *nfss,
return 0;
}
-int
-nfs_remount(struct super_block *sb, int *flags, char *raw_data)
+int nfs_reconfigure(struct fs_context *fc)
{
- int error;
+ struct nfs_fs_context *ctx = nfs_fc2context(fc);
+ struct super_block *sb = fc->root->d_sb;
struct nfs_server *nfss = sb->s_fs_info;
- struct nfs_fs_context *ctx;
- struct nfs_mount_data *options = (struct nfs_mount_data *)raw_data;
- struct nfs4_mount_data *options4 = (struct nfs4_mount_data *)raw_data;
- u32 nfsvers = nfss->nfs_client->rpc_ops->version;
sync_filesystem(sb);
@@ -983,57 +944,24 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data)
* ones were explicitly specified. Fall back to legacy behavior and
* just return success.
*/
- if ((nfsvers == 4 && (!options4 || options4->version == 1)) ||
- (nfsvers <= 3 && (!options || (options->version >= 1 &&
- options->version <= 6))))
+ if (ctx->skip_reconfig_option_check)
return 0;
- ctx = nfs_alloc_parsed_mount_data();
- if (ctx == NULL)
- return -ENOMEM;
-
- /* fill out struct with values from existing mount */
- ctx->flags = nfss->flags;
- ctx->rsize = nfss->rsize;
- ctx->wsize = nfss->wsize;
- ctx->retrans = nfss->client->cl_timeout->to_retries;
- ctx->selected_flavor = nfss->client->cl_auth->au_flavor;
- ctx->acregmin = nfss->acregmin / HZ;
- ctx->acregmax = nfss->acregmax / HZ;
- ctx->acdirmin = nfss->acdirmin / HZ;
- ctx->acdirmax = nfss->acdirmax / HZ;
- ctx->timeo = 10U * nfss->client->cl_timeout->to_initval / HZ;
- ctx->nfs_server.port = nfss->port;
- ctx->nfs_server.addrlen = nfss->nfs_client->cl_addrlen;
- ctx->version = nfsvers;
- ctx->minorversion = nfss->nfs_client->cl_minorversion;
- ctx->net = current->nsproxy->net_ns;
- memcpy(&ctx->nfs_server.address, &nfss->nfs_client->cl_addr,
- ctx->nfs_server.addrlen);
-
- /* overwrite those values with any that were specified */
- error = -EINVAL;
- if (!nfs_parse_mount_options((char *)options, ctx))
- goto out;
-
/*
* noac is a special case. It implies -o sync, but that's not
- * necessarily reflected in the mtab options. do_remount_sb
+ * necessarily reflected in the mtab options. reconfigure_super
* will clear SB_SYNCHRONOUS if -o sync wasn't specified in the
* remount options, so we have to explicitly reset it.
*/
- if (ctx->flags & NFS_MOUNT_NOAC)
- *flags |= SB_SYNCHRONOUS;
+ if (ctx->flags & NFS_MOUNT_NOAC) {
+ fc->sb_flags |= SB_SYNCHRONOUS;
+ fc->sb_flags_mask |= SB_SYNCHRONOUS;
+ }
/* compare new mount options with old ones */
- error = nfs_compare_remount_data(nfss, ctx);
- if (!error)
- error = security_sb_remount(sb, ctx->lsm_opts);
-out:
- nfs_free_parsed_mount_data(ctx);
- return error;
+ return nfs_compare_remount_data(nfss, ctx);
}
-EXPORT_SYMBOL_GPL(nfs_remount);
+EXPORT_SYMBOL_GPL(nfs_reconfigure);
/*
* Finish setting up an NFS superblock
@@ -1112,19 +1040,11 @@ static int nfs_compare_mount_options(const struct super_block *s, const struct n
return 0;
}
-struct nfs_sb_mountdata {
- struct nfs_server *server;
- int mntflags;
-};
-
-static int nfs_set_super(struct super_block *s, void *data)
+static int nfs_set_super(struct super_block *s, struct fs_context *fc)
{
- struct nfs_sb_mountdata *sb_mntdata = data;
- struct nfs_server *server = sb_mntdata->server;
+ struct nfs_server *server = fc->s_fs_info;
int ret;
- s->s_flags = sb_mntdata->mntflags;
- s->s_fs_info = server;
s->s_d_op = server->nfs_client->rpc_ops->dentry_ops;
ret = set_anon_super(s, server);
if (ret == 0)
@@ -1189,11 +1109,9 @@ static int nfs_compare_userns(const struct nfs_server *old,
return 1;
}
-static int nfs_compare_super(struct super_block *sb, void *data)
+static int nfs_compare_super(struct super_block *sb, struct fs_context *fc)
{
- struct nfs_sb_mountdata *sb_mntdata = data;
- struct nfs_server *server = sb_mntdata->server, *old = NFS_SB(sb);
- int mntflags = sb_mntdata->mntflags;
+ struct nfs_server *server = fc->s_fs_info, *old = NFS_SB(sb);
if (!nfs_compare_super_address(old, server))
return 0;
@@ -1204,13 +1122,12 @@ static int nfs_compare_super(struct super_block *sb, void *data)
return 0;
if (!nfs_compare_userns(old, server))
return 0;
- return nfs_compare_mount_options(sb, server, mntflags);
+ return nfs_compare_mount_options(sb, server, fc->sb_flags);
}
#ifdef CONFIG_NFS_FSCACHE
static void nfs_get_cache_cookie(struct super_block *sb,
- struct nfs_fs_context *ctx,
- struct nfs_clone_mount *cloned)
+ struct nfs_fs_context *ctx)
{
struct nfs_server *nfss = NFS_SB(sb);
char *uniq = NULL;
@@ -1219,30 +1136,32 @@ static void nfs_get_cache_cookie(struct super_block *sb,
nfss->fscache_key = NULL;
nfss->fscache = NULL;
- if (ctx) {
- if (!(ctx->options & NFS_OPTION_FSCACHE))
- return;
- if (ctx->fscache_uniq) {
- uniq = ctx->fscache_uniq;
- ulen = strlen(ctx->fscache_uniq);
- }
- } else if (cloned) {
- struct nfs_server *mnt_s = NFS_SB(cloned->sb);
+ if (!ctx)
+ return;
+
+ if (ctx->clone_data.sb) {
+ struct nfs_server *mnt_s = NFS_SB(ctx->clone_data.sb);
if (!(mnt_s->options & NFS_OPTION_FSCACHE))
return;
if (mnt_s->fscache_key) {
uniq = mnt_s->fscache_key->key.uniquifier;
ulen = mnt_s->fscache_key->key.uniq_len;
}
- } else
+ } else {
+ if (!(ctx->options & NFS_OPTION_FSCACHE))
+ return;
+ if (ctx->fscache_uniq) {
+ uniq = ctx->fscache_uniq;
+ ulen = strlen(ctx->fscache_uniq);
+ }
return;
+ }
nfs_fscache_get_super_cookie(sb, uniq, ulen);
}
#else
static void nfs_get_cache_cookie(struct super_block *sb,
- struct nfs_fs_context *parsed,
- struct nfs_clone_mount *cloned)
+ struct nfs_fs_context *ctx)
{
}
#endif
@@ -1254,40 +1173,41 @@ static void nfs_set_readahead(struct backing_dev_info *bdi,
bdi->io_pages = iomax_pages;
}
-static struct dentry *nfs_fs_mount_common(int flags, const char *dev_name,
- struct nfs_mount_info *mount_info)
+int nfs_get_tree_common(struct fs_context *fc)
{
+ struct nfs_fs_context *ctx = nfs_fc2context(fc);
struct super_block *s;
struct dentry *mntroot = ERR_PTR(-ENOMEM);
- int (*compare_super)(struct super_block *, void *) = nfs_compare_super;
- struct nfs_server *server = mount_info->server;
+ int (*compare_super)(struct super_block *, struct fs_context *) = nfs_compare_super;
+ struct nfs_server *server = ctx->mount_info.server;
unsigned long kflags = 0, kflags_out = 0;
- struct nfs_sb_mountdata sb_mntdata = {
- .mntflags = flags,
- .server = server,
- };
int error;
- mount_info->server = NULL;
+ ctx->mount_info.server = NULL;
if (IS_ERR(server))
- return ERR_CAST(server);
+ return PTR_ERR(server);
if (server->flags & NFS_MOUNT_UNSHARED)
compare_super = NULL;
/* -o noac implies -o sync */
if (server->flags & NFS_MOUNT_NOAC)
- sb_mntdata.mntflags |= SB_SYNCHRONOUS;
+ fc->sb_flags |= SB_SYNCHRONOUS;
+
+ if (ctx->clone_data.sb)
+ if (ctx->clone_data.sb->s_flags & SB_SYNCHRONOUS)
+ fc->sb_flags |= SB_SYNCHRONOUS;
- if (mount_info->cloned != NULL && mount_info->cloned->sb != NULL)
- if (mount_info->cloned->sb->s_flags & SB_SYNCHRONOUS)
- sb_mntdata.mntflags |= SB_SYNCHRONOUS;
+ if (server->caps & NFS_CAP_SECURITY_LABEL)
+ fc->lsm_flags |= SECURITY_LSM_NATIVE_LABELS;
/* Get a superblock - note that we may end up sharing one that already exists */
- s = sget(mount_info->nfs_mod->nfs_fs, compare_super, nfs_set_super,
- flags, &sb_mntdata);
+ fc->s_fs_info = server;
+ s = sget_fc(fc, compare_super, nfs_set_super);
+ fc->s_fs_info = NULL;
if (IS_ERR(s)) {
- mntroot = ERR_CAST(s);
+ error = PTR_ERR(s);
+ dfprintk(MOUNT, "NFS: Couldn't get superblock\n");
goto out_err_nosb;
}
@@ -1297,44 +1217,43 @@ static struct dentry *nfs_fs_mount_common(int flags, const char *dev_name,
} else {
error = super_setup_bdi_name(s, "%u:%u", MAJOR(server->s_dev),
MINOR(server->s_dev));
- if (error) {
- mntroot = ERR_PTR(error);
+ if (error)
goto error_splat_super;
- }
nfs_set_readahead(s->s_bdi, server->rpages);
server->super = s;
}
if (!s->s_root) {
- unsigned bsize = mount_info->inherited_bsize;
+ unsigned bsize = ctx->mount_info.inherited_bsize;
/* initial superblock/root creation */
- nfs_fill_super(s, mount_info);
+ nfs_fill_super(s, &ctx->mount_info);
if (bsize) {
s->s_blocksize_bits = bsize;
s->s_blocksize = 1U << bsize;
}
- nfs_get_cache_cookie(s, mount_info->ctx, mount_info->cloned);
- if (!(server->flags & NFS_MOUNT_UNSHARED))
- s->s_iflags |= SB_I_MULTIROOT;
+ nfs_get_cache_cookie(s, ctx);
}
- mntroot = nfs_get_root(s, mount_info->mntfh, dev_name);
- if (IS_ERR(mntroot))
+ mntroot = nfs_get_root(s, ctx->mount_info.mntfh, fc->source);
+ if (IS_ERR(mntroot)) {
+ error = PTR_ERR(mntroot);
+ dfprintk(MOUNT, "NFS: Couldn't get root dentry\n");
goto error_splat_super;
-
+ }
+ fc->root = mntroot;
if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL)
kflags |= SECURITY_LSM_NATIVE_LABELS;
- if (mount_info->cloned) {
- if (d_inode(mntroot)->i_fop != &nfs_dir_operations) {
+ if (ctx->clone_data.sb) {
+ if (d_inode(fc->root)->i_fop != &nfs_dir_operations) {
error = -ESTALE;
goto error_splat_root;
}
/* clone any lsm security options from the parent to the new sb */
- error = security_sb_clone_mnt_opts(mount_info->cloned->sb, s, kflags,
+ error = security_sb_clone_mnt_opts(ctx->clone_data.sb, s, kflags,
&kflags_out);
} else {
- error = security_sb_set_mnt_opts(s, mount_info->ctx->lsm_opts,
+ error = security_sb_set_mnt_opts(s, fc->security,
kflags, &kflags_out);
}
if (error)
@@ -1342,67 +1261,25 @@ static struct dentry *nfs_fs_mount_common(int flags, const char *dev_name,
if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL &&
!(kflags_out & SECURITY_LSM_NATIVE_LABELS))
NFS_SB(s)->caps &= ~NFS_CAP_SECURITY_LABEL;
- if (error)
- goto error_splat_root;
s->s_flags |= SB_ACTIVE;
+ error = 0;
out:
- return mntroot;
+ return error;
out_err_nosb:
nfs_free_server(server);
goto out;
error_splat_root:
- dput(mntroot);
- mntroot = ERR_PTR(error);
+ dput(fc->root);
+ fc->root = NULL;
error_splat_super:
deactivate_locked_super(s);
goto out;
}
-struct dentry *nfs_fs_mount(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *raw_data)
-{
- struct nfs_mount_info mount_info = {
- };
- struct dentry *mntroot = ERR_PTR(-ENOMEM);
- struct nfs_subversion *nfs_mod;
- int error;
-
- mount_info.ctx = nfs_alloc_parsed_mount_data();
- mount_info.mntfh = nfs_alloc_fhandle();
- if (mount_info.ctx == NULL || mount_info.mntfh == NULL)
- goto out;
-
- /* Validate the mount data */
- error = nfs_validate_mount_data(fs_type, raw_data, mount_info.ctx, mount_info.mntfh, dev_name);
- if (error == NFS_TEXT_DATA)
- error = nfs_validate_text_mount_data(raw_data,
- mount_info.ctx, dev_name);
- if (error < 0) {
- mntroot = ERR_PTR(error);
- goto out;
- }
-
- nfs_mod = get_nfs_version(mount_info.ctx->version);
- if (IS_ERR(nfs_mod)) {
- mntroot = ERR_CAST(nfs_mod);
- goto out;
- }
- mount_info.nfs_mod = nfs_mod;
-
- mntroot = nfs_mod->rpc_ops->try_mount(flags, dev_name, &mount_info);
-
- put_nfs_version(nfs_mod);
-out:
- nfs_free_parsed_mount_data(mount_info.ctx);
- nfs_free_fhandle(mount_info.mntfh);
- return mntroot;
-}
-EXPORT_SYMBOL_GPL(nfs_fs_mount);
-
/*
* Destroy an NFS2/3 superblock
*/
@@ -1420,17 +1297,6 @@ void nfs_kill_super(struct super_block *s)
}
EXPORT_SYMBOL_GPL(nfs_kill_super);
-/*
- * Internal use only: mount_info is already set up by caller.
- * Used for mountpoint crossings and for nfs4 root.
- */
-static struct dentry *
-nfs_prepared_mount(struct file_system_type *fs_type, int flags,
- const char *dev_name, void *raw_data)
-{
- return nfs_fs_mount_common(flags, dev_name, raw_data);
-}
-
#if IS_ENABLED(CONFIG_NFS_V4)
/*
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 17527f6e6360..574741d5418d 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1639,6 +1639,7 @@ struct nfs_subversion;
struct nfs_mount_info;
struct nfs_client_initdata;
struct nfs_pageio_descriptor;
+struct fs_context;
/*
* RPC procedure vector for NFSv2/NFSv3 demuxing
@@ -1653,9 +1654,8 @@ struct nfs_rpc_ops {
int (*getroot) (struct nfs_server *, struct nfs_fh *,
struct nfs_fsinfo *);
- struct vfsmount *(*submount) (struct nfs_server *, struct dentry *,
- struct nfs_fh *, struct nfs_fattr *);
- struct dentry *(*try_mount) (int, const char *, struct nfs_mount_info *);
+ int (*submount) (struct fs_context *, struct nfs_server *);
+ int (*try_get_tree) (struct fs_context *);
int (*getattr) (struct nfs_server *, struct nfs_fh *,
struct nfs_fattr *, struct nfs4_label *,
struct inode *);
--
2.17.2
^ permalink raw reply related
* [PATCH v6 13/27] nfs: get rid of mount_info ->fill_super()
From: Scott Mayhew @ 2019-12-10 12:31 UTC (permalink / raw)
To: anna.schumaker, trond.myklebust
Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel,
linux-security-module
In-Reply-To: <20191210123115.1655-1-smayhew@redhat.com>
From: Al Viro <viro@zeniv.linux.org.uk>
The only possible values are nfs_fill_super and nfs_clone_super. The
latter is used only when crossing into a submount and it is almost
identical to the former; the only differences are
* ->s_time_gran unconditionally set to 1 (even for v2 mounts).
Regression dating back to 2012, actually.
* ->s_blocksize/->s_blocksize_bits set to that of parent.
Rather than messing with the method, stash ->s_blocksize_bits in
mount_info in submount case and after the (now unconditional)
call of nfs_fill_super() override ->s_blocksize/->s_blocksize_bits
if that has been set.
Reviewed-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/nfs/internal.h | 4 +--
fs/nfs/namespace.c | 2 +-
fs/nfs/nfs4super.c | 1 -
fs/nfs/super.c | 75 ++++++++++------------------------------------
4 files changed, 18 insertions(+), 64 deletions(-)
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 0bb0493785fc..65c8e353cb6b 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -136,7 +136,7 @@ struct nfs_mount_request {
};
struct nfs_mount_info {
- void (*fill_super)(struct super_block *, struct nfs_mount_info *);
+ unsigned int inherited_bsize;
int (*set_security)(struct super_block *, struct dentry *, struct nfs_mount_info *);
struct nfs_parsed_mount_data *parsed;
struct nfs_clone_mount *cloned;
@@ -395,8 +395,6 @@ int nfs_set_sb_security(struct super_block *, struct dentry *, struct nfs_mount_
int nfs_clone_sb_security(struct super_block *, struct dentry *, struct nfs_mount_info *);
struct dentry *nfs_fs_mount(struct file_system_type *, int, const char *, void *);
void nfs_kill_super(struct super_block *);
-void nfs_fill_super(struct super_block *, struct nfs_mount_info *);
-void nfs_clone_super(struct super_block *, struct nfs_mount_info *);
extern struct rpc_stat nfs_rpcstat;
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
index e5f4f2d760af..30331558bd8e 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -232,7 +232,7 @@ struct vfsmount *nfs_do_submount(struct dentry *dentry, struct nfs_fh *fh,
.authflavor = authflavor,
};
struct nfs_mount_info mount_info = {
- .fill_super = nfs_clone_super,
+ .inherited_bsize = sb->s_blocksize_bits,
.set_security = nfs_clone_sb_security,
.cloned = &mountdata,
.mntfh = fh,
diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c
index e5d8a76bd144..5020a43b31c9 100644
--- a/fs/nfs/nfs4super.c
+++ b/fs/nfs/nfs4super.c
@@ -224,7 +224,6 @@ static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type,
{
struct nfs_clone_mount *data = raw_data;
struct nfs_mount_info mount_info = {
- .fill_super = nfs_fill_super,
.set_security = nfs_clone_sb_security,
.cloned = data,
.nfs_mod = &nfs_v4,
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 6239c78d8f54..2bcf0f8295e0 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -2339,29 +2339,9 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data)
EXPORT_SYMBOL_GPL(nfs_remount);
/*
- * Initialise the common bits of the superblock
+ * Finish setting up an NFS superblock
*/
-static void nfs_initialise_sb(struct super_block *sb)
-{
- struct nfs_server *server = NFS_SB(sb);
-
- sb->s_magic = NFS_SUPER_MAGIC;
-
- /* We probably want something more informative here */
- snprintf(sb->s_id, sizeof(sb->s_id),
- "%u:%u", MAJOR(sb->s_dev), MINOR(sb->s_dev));
-
- if (sb->s_blocksize == 0)
- sb->s_blocksize = nfs_block_bits(server->wsize,
- &sb->s_blocksize_bits);
-
- nfs_super_set_maxbytes(sb, server->maxfilesize);
-}
-
-/*
- * Finish setting up an NFS2/3 superblock
- */
-void nfs_fill_super(struct super_block *sb, struct nfs_mount_info *mount_info)
+static void nfs_fill_super(struct super_block *sb, struct nfs_mount_info *mount_info)
{
struct nfs_parsed_mount_data *data = mount_info->parsed;
struct nfs_server *server = NFS_SB(sb);
@@ -2391,44 +2371,17 @@ void nfs_fill_super(struct super_block *sb, struct nfs_mount_info *mount_info)
sb->s_time_max = S64_MAX;
}
- nfs_initialise_sb(sb);
-}
-EXPORT_SYMBOL_GPL(nfs_fill_super);
-
-/*
- * Finish setting up a cloned NFS2/3/4 superblock
- */
-void nfs_clone_super(struct super_block *sb,
- struct nfs_mount_info *mount_info)
-{
- const struct super_block *old_sb = mount_info->cloned->sb;
- struct nfs_server *server = NFS_SB(sb);
-
- sb->s_blocksize_bits = old_sb->s_blocksize_bits;
- sb->s_blocksize = old_sb->s_blocksize;
- sb->s_maxbytes = old_sb->s_maxbytes;
- sb->s_xattr = old_sb->s_xattr;
- sb->s_op = old_sb->s_op;
- sb->s_export_op = old_sb->s_export_op;
+ sb->s_magic = NFS_SUPER_MAGIC;
- if (server->nfs_client->rpc_ops->version != 2) {
- /* The VFS shouldn't apply the umask to mode bits. We will do
- * so ourselves when necessary.
- */
- sb->s_flags |= SB_POSIXACL;
- sb->s_time_gran = 1;
- } else
- sb->s_time_gran = 1000;
+ /* We probably want something more informative here */
+ snprintf(sb->s_id, sizeof(sb->s_id),
+ "%u:%u", MAJOR(sb->s_dev), MINOR(sb->s_dev));
- if (server->nfs_client->rpc_ops->version != 4) {
- sb->s_time_min = 0;
- sb->s_time_max = U32_MAX;
- } else {
- sb->s_time_min = S64_MIN;
- sb->s_time_max = S64_MAX;
- }
+ if (sb->s_blocksize == 0)
+ sb->s_blocksize = nfs_block_bits(server->wsize,
+ &sb->s_blocksize_bits);
- nfs_initialise_sb(sb);
+ nfs_super_set_maxbytes(sb, server->maxfilesize);
}
static int nfs_compare_mount_options(const struct super_block *s, const struct nfs_server *b, int flags)
@@ -2701,8 +2654,13 @@ static struct dentry *nfs_fs_mount_common(int flags, const char *dev_name,
}
if (!s->s_root) {
+ unsigned bsize = mount_info->inherited_bsize;
/* initial superblock/root creation */
- mount_info->fill_super(s, mount_info);
+ nfs_fill_super(s, mount_info);
+ if (bsize) {
+ s->s_blocksize_bits = bsize;
+ s->s_blocksize = 1U << bsize;
+ }
nfs_get_cache_cookie(s, mount_info->parsed, mount_info->cloned);
if (!(server->flags & NFS_MOUNT_UNSHARED))
s->s_iflags |= SB_I_MULTIROOT;
@@ -2737,7 +2695,6 @@ struct dentry *nfs_fs_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *raw_data)
{
struct nfs_mount_info mount_info = {
- .fill_super = nfs_fill_super,
.set_security = nfs_set_sb_security,
};
struct dentry *mntroot = ERR_PTR(-ENOMEM);
--
2.17.2
^ permalink raw reply related
* [PATCH v6 26/27] NFS: Additional refactoring for fs_context conversion
From: Scott Mayhew @ 2019-12-10 12:31 UTC (permalink / raw)
To: anna.schumaker, trond.myklebust
Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel,
linux-security-module
In-Reply-To: <20191210123115.1655-1-smayhew@redhat.com>
Split out from commit "NFS: Add fs_context support."
This patch adds additional refactoring for the conversion of NFS to use
fs_context, namely:
(*) Merge nfs_mount_info and nfs_clone_mount into nfs_fs_context.
nfs_clone_mount has had several fields removed, and nfs_mount_info
has been removed altogether.
(*) Various functions now take an fs_context as an argument instead
of nfs_mount_info, nfs_fs_context, etc.
Signed-off-by: Scott Mayhew <smayhew@redhat.com>
---
fs/nfs/client.c | 22 +++---
fs/nfs/fs_context.c | 155 +++++++++++++++-------------------------
fs/nfs/fscache.c | 2 +-
fs/nfs/getroot.c | 70 +++++++++---------
fs/nfs/internal.h | 53 +++++---------
fs/nfs/namespace.c | 14 ++--
fs/nfs/nfs3_fs.h | 2 +-
fs/nfs/nfs3client.c | 5 +-
fs/nfs/nfs4client.c | 62 ++++++++--------
fs/nfs/nfs4namespace.c | 23 +++---
fs/nfs/nfs4super.c | 19 +++--
fs/nfs/super.c | 48 ++++++-------
include/linux/nfs_xdr.h | 2 +-
13 files changed, 204 insertions(+), 273 deletions(-)
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index 69c0708b2acc..8f760f23748c 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -658,17 +658,17 @@ EXPORT_SYMBOL_GPL(nfs_init_client);
* Create a version 2 or 3 client
*/
static int nfs_init_server(struct nfs_server *server,
- const struct nfs_fs_context *ctx,
- struct nfs_subversion *nfs_mod)
+ const struct fs_context *fc)
{
+ const struct nfs_fs_context *ctx = nfs_fc2context(fc);
struct rpc_timeout timeparms;
struct nfs_client_initdata cl_init = {
.hostname = ctx->nfs_server.hostname,
.addr = (const struct sockaddr *)&ctx->nfs_server.address,
.addrlen = ctx->nfs_server.addrlen,
- .nfs_mod = nfs_mod,
+ .nfs_mod = ctx->nfs_mod,
.proto = ctx->nfs_server.protocol,
- .net = ctx->net,
+ .net = fc->net_ns,
.timeparms = &timeparms,
.cred = server->cred,
.nconnect = ctx->nfs_server.nconnect,
@@ -951,10 +951,10 @@ EXPORT_SYMBOL_GPL(nfs_free_server);
* Create a version 2 or 3 volume record
* - keyed on server and FSID
*/
-struct nfs_server *nfs_create_server(struct nfs_mount_info *mount_info)
+struct nfs_server *nfs_create_server(struct fs_context *fc)
{
+ struct nfs_fs_context *ctx = nfs_fc2context(fc);
struct nfs_server *server;
- struct nfs_subversion *nfs_mod = mount_info->nfs_mod;
struct nfs_fattr *fattr;
int error;
@@ -970,18 +970,18 @@ struct nfs_server *nfs_create_server(struct nfs_mount_info *mount_info)
goto error;
/* Get a client representation */
- error = nfs_init_server(server, mount_info->ctx, nfs_mod);
+ error = nfs_init_server(server, fc);
if (error < 0)
goto error;
/* Probe the root fh to retrieve its FSID */
- error = nfs_probe_fsinfo(server, mount_info->mntfh, fattr);
+ error = nfs_probe_fsinfo(server, ctx->mntfh, fattr);
if (error < 0)
goto error;
if (server->nfs_client->rpc_ops->version == 3) {
if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
server->namelen = NFS3_MAXNAMLEN;
- if (!(mount_info->ctx->flags & NFS_MOUNT_NORDIRPLUS))
+ if (!(ctx->flags & NFS_MOUNT_NORDIRPLUS))
server->caps |= NFS_CAP_READDIRPLUS;
} else {
if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN)
@@ -989,8 +989,8 @@ struct nfs_server *nfs_create_server(struct nfs_mount_info *mount_info)
}
if (!(fattr->valid & NFS_ATTR_FATTR)) {
- error = nfs_mod->rpc_ops->getattr(server, mount_info->mntfh,
- fattr, NULL, NULL);
+ error = ctx->nfs_mod->rpc_ops->getattr(server, ctx->mntfh,
+ fattr, NULL, NULL);
if (error < 0) {
dprintk("nfs_create_server: getattr error = %d\n", -error);
goto error;
diff --git a/fs/nfs/fs_context.c b/fs/nfs/fs_context.c
index ac1a8d7d7393..e472334b978d 100644
--- a/fs/nfs/fs_context.c
+++ b/fs/nfs/fs_context.c
@@ -241,43 +241,6 @@ static const struct constant_table nfs_secflavor_tokens[] = {
{ "sys", Opt_sec_sys },
};
-struct nfs_fs_context *nfs_alloc_parsed_mount_data(void)
-{
- struct nfs_fs_context *ctx;
-
- ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
- if (ctx) {
- ctx->timeo = NFS_UNSPEC_TIMEO;
- ctx->retrans = NFS_UNSPEC_RETRANS;
- ctx->acregmin = NFS_DEF_ACREGMIN;
- ctx->acregmax = NFS_DEF_ACREGMAX;
- ctx->acdirmin = NFS_DEF_ACDIRMIN;
- ctx->acdirmax = NFS_DEF_ACDIRMAX;
- ctx->mount_server.port = NFS_UNSPEC_PORT;
- ctx->nfs_server.port = NFS_UNSPEC_PORT;
- ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP;
- ctx->selected_flavor = RPC_AUTH_MAXFLAVOR;
- ctx->minorversion = 0;
- ctx->need_mount = true;
- ctx->net = current->nsproxy->net_ns;
- ctx->lsm_opts = NULL;
- }
- return ctx;
-}
-
-void nfs_free_parsed_mount_data(struct nfs_fs_context *ctx)
-{
- if (ctx) {
- kfree(ctx->client_address);
- kfree(ctx->mount_server.hostname);
- kfree(ctx->nfs_server.export_path);
- kfree(ctx->nfs_server.hostname);
- kfree(ctx->fscache_uniq);
- security_free_mnt_opts(&ctx->lsm_opts);
- kfree(ctx);
- }
-}
-
/*
* Sanity-check a server address provided by the mount command.
*
@@ -342,7 +305,7 @@ static void nfs_set_mount_transport_protocol(struct nfs_fs_context *ctx)
* Add 'flavor' to 'auth_info' if not already present.
* Returns true if 'flavor' ends up in the list, false otherwise
*/
-static int nfs_auth_info_add(struct nfs_fs_context *ctx,
+static int nfs_auth_info_add(struct fs_context *fc,
struct nfs_auth_info *auth_info,
rpc_authflavor_t flavor)
{
@@ -367,9 +330,10 @@ static int nfs_auth_info_add(struct nfs_fs_context *ctx,
/*
* Parse the value of the 'sec=' option.
*/
-static int nfs_parse_security_flavors(struct nfs_fs_context *ctx,
+static int nfs_parse_security_flavors(struct fs_context *fc,
struct fs_parameter *param)
{
+ struct nfs_fs_context *ctx = nfs_fc2context(fc);
rpc_authflavor_t pseudoflavor;
char *string = param->string, *p;
int ret;
@@ -419,7 +383,7 @@ static int nfs_parse_security_flavors(struct nfs_fs_context *ctx,
return -EINVAL;
}
- ret = nfs_auth_info_add(ctx, &ctx->auth_info, pseudoflavor);
+ ret = nfs_auth_info_add(fc, &ctx->auth_info, pseudoflavor);
if (ret < 0)
return ret;
}
@@ -427,9 +391,11 @@ static int nfs_parse_security_flavors(struct nfs_fs_context *ctx,
return 0;
}
-static int nfs_parse_version_string(struct nfs_fs_context *ctx,
+static int nfs_parse_version_string(struct fs_context *fc,
const char *string)
{
+ struct nfs_fs_context *ctx = nfs_fc2context(fc);
+
ctx->flags &= ~NFS_MOUNT_VER3;
switch (lookup_constant(nfs_vers_tokens, string, -1)) {
case Opt_vers_2:
@@ -656,17 +622,17 @@ static int nfs_fs_context_parse_param(struct fs_context *fc,
* options that take text values
*/
case Opt_v:
- ret = nfs_parse_version_string(ctx, param->key + 1);
+ ret = nfs_parse_version_string(fc, param->key + 1);
if (ret < 0)
return ret;
break;
case Opt_vers:
- ret = nfs_parse_version_string(ctx, param->string);
+ ret = nfs_parse_version_string(fc, param->string);
if (ret < 0)
return ret;
break;
case Opt_sec:
- ret = nfs_parse_security_flavors(ctx, param);
+ ret = nfs_parse_security_flavors(fc, param);
if (ret < 0)
return ret;
break;
@@ -729,7 +695,7 @@ static int nfs_fs_context_parse_param(struct fs_context *fc,
break;
case Opt_addr:
- len = rpc_pton(ctx->net, param->string, param->size,
+ len = rpc_pton(fc->net_ns, param->string, param->size,
&ctx->nfs_server.address,
sizeof(ctx->nfs_server._address));
if (len == 0)
@@ -747,7 +713,7 @@ static int nfs_fs_context_parse_param(struct fs_context *fc,
param->string = NULL;
break;
case Opt_mountaddr:
- len = rpc_pton(ctx->net, param->string, param->size,
+ len = rpc_pton(fc->net_ns, param->string, param->size,
&ctx->mount_server.address,
sizeof(ctx->mount_server._address));
if (len == 0)
@@ -819,7 +785,7 @@ static int nfs_fs_context_parse_param(struct fs_context *fc,
}
/*
- * Split "dev_name" into "hostname:export_path".
+ * Split fc->source into "hostname:export_path".
*
* The leftmost colon demarks the split between the server's hostname
* and the export path. If the hostname starts with a left square
@@ -827,12 +793,13 @@ static int nfs_fs_context_parse_param(struct fs_context *fc,
*
* Note: caller frees hostname and export path, even on error.
*/
-static int nfs_parse_devname(struct nfs_fs_context *ctx,
- const char *dev_name,
- size_t maxnamlen, size_t maxpathlen)
+static int nfs_parse_source(struct fs_context *fc,
+ size_t maxnamlen, size_t maxpathlen)
{
+ struct nfs_fs_context *ctx = nfs_fc2context(fc);
+ const char *dev_name = fc->source;
size_t len;
- char *end;
+ const char *end;
if (unlikely(!dev_name || !*dev_name)) {
dfprintk(MOUNT, "NFS: device name not specified\n");
@@ -848,7 +815,7 @@ static int nfs_parse_devname(struct nfs_fs_context *ctx,
len = end - dev_name;
end++;
} else {
- char *comma;
+ const char *comma;
end = strchr(dev_name, ':');
if (end == NULL)
@@ -856,8 +823,8 @@ static int nfs_parse_devname(struct nfs_fs_context *ctx,
len = end - dev_name;
/* kill possible hostname list: not supported */
- comma = strchr(dev_name, ',');
- if (comma != NULL && comma < end)
+ comma = memchr(dev_name, ',', len);
+ if (comma)
len = comma - dev_name;
}
@@ -920,7 +887,7 @@ static int nfs23_parse_monolithic(struct fs_context *fc,
struct nfs_mount_data *data)
{
struct nfs_fs_context *ctx = nfs_fc2context(fc);
- struct nfs_fh *mntfh = ctx->mount_info.mntfh;
+ struct nfs_fh *mntfh = ctx->mntfh;
struct sockaddr *sap = (struct sockaddr *)&ctx->nfs_server.address;
int extra_flags = NFS_MOUNT_LEGACY_INTERFACE;
@@ -1009,6 +976,7 @@ static int nfs23_parse_monolithic(struct fs_context *fc,
else
ctx->flags |= (NFS_MOUNT_LOCAL_FLOCK|
NFS_MOUNT_LOCAL_FCNTL);
+
/*
* The legacy version 6 binary mount data from userspace has a
* field used only to transport selinux information into the
@@ -1073,12 +1041,6 @@ static int nfs23_parse_monolithic(struct fs_context *fc,
}
#if IS_ENABLED(CONFIG_NFS_V4)
-static void nfs4_validate_mount_flags(struct nfs_fs_context *ctx)
-{
- ctx->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3|
- NFS_MOUNT_LOCAL_FLOCK|NFS_MOUNT_LOCAL_FCNTL);
-}
-
/*
* Validate NFSv4 mount options
*/
@@ -1251,20 +1213,22 @@ static int nfs_fs_context_validate(struct fs_context *fc)
goto out_no_address;
if (ctx->version == 4) {
-#if IS_ENABLED(CONFIG_NFS_V4)
- if (ctx->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
- port = NFS_RDMA_PORT;
- else
- port = NFS_PORT;
- max_namelen = NFS4_MAXNAMLEN;
- max_pathlen = NFS4_MAXPATHLEN;
- nfs_validate_transport_protocol(ctx);
- if (ctx->nfs_server.protocol == XPRT_TRANSPORT_UDP)
- goto out_invalid_transport_udp;
- nfs4_validate_mount_flags(ctx);
-#else
- goto out_v4_not_compiled;
-#endif /* CONFIG_NFS_V4 */
+ if (IS_ENABLED(CONFIG_NFS_V4)) {
+ if (ctx->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
+ port = NFS_RDMA_PORT;
+ else
+ port = NFS_PORT;
+ max_namelen = NFS4_MAXNAMLEN;
+ max_pathlen = NFS4_MAXPATHLEN;
+ nfs_validate_transport_protocol(ctx);
+ if (ctx->nfs_server.protocol == XPRT_TRANSPORT_UDP)
+ goto out_invalid_transport_udp;
+ ctx->flags &= ~(NFS_MOUNT_NONLM | NFS_MOUNT_NOACL |
+ NFS_MOUNT_VER3 | NFS_MOUNT_LOCAL_FLOCK |
+ NFS_MOUNT_LOCAL_FCNTL);
+ } else {
+ goto out_v4_not_compiled;
+ }
} else {
nfs_set_mount_transport_protocol(ctx);
if (ctx->nfs_server.protocol == XPRT_TRANSPORT_RDMA)
@@ -1273,33 +1237,30 @@ static int nfs_fs_context_validate(struct fs_context *fc)
nfs_set_port(sap, &ctx->nfs_server.port, port);
- ret = nfs_parse_devname(ctx, fc->source, max_namelen, max_pathlen);
+ ret = nfs_parse_source(fc, max_namelen, max_pathlen);
if (ret < 0)
return ret;
/* Load the NFS protocol module if we haven't done so yet */
- if (!ctx->mount_info.nfs_mod) {
+ if (!ctx->nfs_mod) {
nfs_mod = get_nfs_version(ctx->version);
if (IS_ERR(nfs_mod)) {
ret = PTR_ERR(nfs_mod);
goto out_version_unavailable;
}
- ctx->mount_info.nfs_mod = nfs_mod;
+ ctx->nfs_mod = nfs_mod;
}
return 0;
out_no_device_name:
dfprintk(MOUNT, "NFS: Device name not specified\n");
return -EINVAL;
-#if !IS_ENABLED(CONFIG_NFS_V4)
out_v4_not_compiled:
dfprintk(MOUNT, "NFS: NFSv4 is not compiled into kernel\n");
return -EPROTONOSUPPORT;
-#else
out_invalid_transport_udp:
dfprintk(MOUNT, "NFSv4: Unsupported transport protocol udp\n");
return -EINVAL;
-#endif /* !CONFIG_NFS_V4 */
out_no_address:
dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n");
return -EINVAL;
@@ -1332,7 +1293,7 @@ static int nfs_get_tree(struct fs_context *fc)
if (err)
return err;
if (!ctx->internal)
- return ctx->mount_info.nfs_mod->rpc_ops->try_get_tree(fc);
+ return ctx->nfs_mod->rpc_ops->try_get_tree(fc);
else
return nfs_get_tree_common(fc);
}
@@ -1351,20 +1312,19 @@ static int nfs_fs_context_dup(struct fs_context *fc, struct fs_context *src_fc)
if (!ctx)
return -ENOMEM;
- ctx->mount_info.mntfh = nfs_alloc_fhandle();
- if (!ctx->mount_info.mntfh) {
+ ctx->mntfh = nfs_alloc_fhandle();
+ if (!ctx->mntfh) {
kfree(ctx);
return -ENOMEM;
}
- nfs_copy_fh(ctx->mount_info.mntfh, src->mount_info.mntfh);
+ nfs_copy_fh(ctx->mntfh, src->mntfh);
- __module_get(ctx->mount_info.nfs_mod->owner);
+ __module_get(ctx->nfs_mod->owner);
ctx->client_address = NULL;
ctx->mount_server.hostname = NULL;
ctx->nfs_server.export_path = NULL;
ctx->nfs_server.hostname = NULL;
ctx->fscache_uniq = NULL;
- ctx->clone_data.addr = NULL;
ctx->clone_data.fattr = NULL;
fc->fs_private = ctx;
return 0;
@@ -1375,17 +1335,16 @@ static void nfs_fs_context_free(struct fs_context *fc)
struct nfs_fs_context *ctx = nfs_fc2context(fc);
if (ctx) {
- if (ctx->mount_info.server)
- nfs_free_server(ctx->mount_info.server);
- if (ctx->mount_info.nfs_mod)
- put_nfs_version(ctx->mount_info.nfs_mod);
+ if (ctx->server)
+ nfs_free_server(ctx->server);
+ if (ctx->nfs_mod)
+ put_nfs_version(ctx->nfs_mod);
kfree(ctx->client_address);
kfree(ctx->mount_server.hostname);
kfree(ctx->nfs_server.export_path);
kfree(ctx->nfs_server.hostname);
kfree(ctx->fscache_uniq);
- nfs_free_fhandle(ctx->mount_info.mntfh);
- kfree(ctx->clone_data.addr);
+ nfs_free_fhandle(ctx->mntfh);
nfs_free_fattr(ctx->clone_data.fattr);
kfree(ctx);
}
@@ -1413,9 +1372,8 @@ static int nfs_init_fs_context(struct fs_context *fc)
if (unlikely(!ctx))
return -ENOMEM;
- ctx->mount_info.ctx = ctx;
- ctx->mount_info.mntfh = nfs_alloc_fhandle();
- if (unlikely(!ctx->mount_info.mntfh)) {
+ ctx->mntfh = nfs_alloc_fhandle();
+ if (unlikely(!ctx->mntfh)) {
kfree(ctx);
return -ENOMEM;
}
@@ -1452,8 +1410,8 @@ static int nfs_init_fs_context(struct fs_context *fc)
fc->net_ns = get_net(net);
}
- ctx->mount_info.nfs_mod = nfss->nfs_client->cl_nfs_mod;
- __module_get(ctx->mount_info.nfs_mod->owner);
+ ctx->nfs_mod = nfss->nfs_client->cl_nfs_mod;
+ __module_get(ctx->nfs_mod->owner);
} else {
/* defaults */
ctx->timeo = NFS_UNSPEC_TIMEO;
@@ -1468,7 +1426,6 @@ static int nfs_init_fs_context(struct fs_context *fc)
ctx->minorversion = 0;
ctx->need_mount = true;
}
- ctx->net = fc->net_ns;
fc->fs_private = ctx;
fc->ops = &nfs_fs_context_ops;
return 0;
diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c
index 3800ab6f08fa..4a8df8c30a03 100644
--- a/fs/nfs/fscache.c
+++ b/fs/nfs/fscache.c
@@ -128,7 +128,7 @@ void nfs_fscache_get_super_cookie(struct super_block *sb, const char *uniq, int
return;
key->nfs_client = nfss->nfs_client;
- key->key.super.s_flags = sb->s_flags & NFS_MS_MASK;
+ key->key.super.s_flags = sb->s_flags & NFS_SB_MASK;
key->key.nfs_server.flags = nfss->flags;
key->key.nfs_server.rsize = nfss->rsize;
key->key.nfs_server.wsize = nfss->wsize;
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c
index 878c4c5982d9..ab45496d23a6 100644
--- a/fs/nfs/getroot.c
+++ b/fs/nfs/getroot.c
@@ -64,66 +64,68 @@ static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *i
/*
* get an NFS2/NFS3 root dentry from the root filehandle
*/
-struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh,
- const char *devname)
+int nfs_get_root(struct super_block *s, struct fs_context *fc)
{
- struct nfs_server *server = NFS_SB(sb);
+ struct nfs_fs_context *ctx = nfs_fc2context(fc);
+ struct nfs_server *server = NFS_SB(s);
struct nfs_fsinfo fsinfo;
- struct dentry *ret;
+ struct dentry *root;
struct inode *inode;
- void *name = kstrdup(devname, GFP_KERNEL);
- int error;
+ char *name;
+ int error = -ENOMEM;
+ name = kstrdup(fc->source, GFP_KERNEL);
if (!name)
- return ERR_PTR(-ENOMEM);
+ goto out;
/* get the actual root for this mount */
fsinfo.fattr = nfs_alloc_fattr();
- if (fsinfo.fattr == NULL) {
- kfree(name);
- return ERR_PTR(-ENOMEM);
- }
+ if (fsinfo.fattr == NULL)
+ goto out_name;
- error = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo);
+ error = server->nfs_client->rpc_ops->getroot(server, ctx->mntfh, &fsinfo);
if (error < 0) {
dprintk("nfs_get_root: getattr error = %d\n", -error);
- ret = ERR_PTR(error);
- goto out;
+ goto out_fattr;
}
- inode = nfs_fhget(sb, mntfh, fsinfo.fattr, NULL);
+ inode = nfs_fhget(s, ctx->mntfh, fsinfo.fattr, NULL);
if (IS_ERR(inode)) {
dprintk("nfs_get_root: get root inode failed\n");
- ret = ERR_CAST(inode);
- goto out;
+ error = PTR_ERR(inode);
+ goto out_fattr;
}
- error = nfs_superblock_set_dummy_root(sb, inode);
- if (error != 0) {
- ret = ERR_PTR(error);
- goto out;
- }
+ error = nfs_superblock_set_dummy_root(s, inode);
+ if (error != 0)
+ goto out_fattr;
/* root dentries normally start off anonymous and get spliced in later
* if the dentry tree reaches them; however if the dentry already
* exists, we'll pick it up at this point and use it as the root
*/
- ret = d_obtain_root(inode);
- if (IS_ERR(ret)) {
+ root = d_obtain_root(inode);
+ if (IS_ERR(root)) {
dprintk("nfs_get_root: get root dentry failed\n");
- goto out;
+ error = PTR_ERR(root);
+ goto out_fattr;
}
- security_d_instantiate(ret, inode);
- spin_lock(&ret->d_lock);
- if (IS_ROOT(ret) && !ret->d_fsdata &&
- !(ret->d_flags & DCACHE_NFSFS_RENAMED)) {
- ret->d_fsdata = name;
+ security_d_instantiate(root, inode);
+ spin_lock(&root->d_lock);
+ if (IS_ROOT(root) && !root->d_fsdata &&
+ !(root->d_flags & DCACHE_NFSFS_RENAMED)) {
+ root->d_fsdata = name;
name = NULL;
}
- spin_unlock(&ret->d_lock);
-out:
- kfree(name);
+ spin_unlock(&root->d_lock);
+ fc->root = root;
+ error = 0;
+
+out_fattr:
nfs_free_fattr(fsinfo.fattr);
- return ret;
+out_name:
+ kfree(name);
+out:
+ return error;
}
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 1cd09df9e0b5..a1fd4c3ebc4e 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -11,7 +11,7 @@
#include <linux/nfs_page.h>
#include <linux/wait_bit.h>
-#define NFS_MS_MASK (SB_RDONLY|SB_NOSUID|SB_NODEV|SB_NOEXEC|SB_SYNCHRONOUS)
+#define NFS_SB_MASK (SB_RDONLY|SB_NOSUID|SB_NODEV|SB_NOEXEC|SB_SYNCHRONOUS)
extern const struct export_operations nfs_export_ops;
@@ -33,17 +33,6 @@ static inline int nfs_attr_use_mounted_on_fileid(struct nfs_fattr *fattr)
return 1;
}
-struct nfs_clone_mount {
- const struct super_block *sb;
- struct dentry *dentry;
- char *hostname;
- char *mnt_path;
- struct sockaddr *addr;
- size_t addrlen;
- rpc_authflavor_t authflavor;
- struct nfs_fattr *fattr;
-};
-
/*
* Note: RFC 1813 doesn't limit the number of auth flavors that
* a server can return, so make something up.
@@ -80,15 +69,6 @@ struct nfs_client_initdata {
const struct cred *cred;
};
-struct nfs_mount_info {
- unsigned int inherited_bsize;
- struct nfs_fs_context *ctx;
- struct nfs_clone_mount *cloned;
- struct nfs_server *server;
- struct nfs_fh *mntfh;
- struct nfs_subversion *nfs_mod;
-};
-
/*
* In-kernel mount arguments
*/
@@ -140,13 +120,17 @@ struct nfs_fs_context {
unsigned short export_path_len;
} nfs_server;
- void *lsm_opts;
- struct net *net;
-
- char buf[32]; /* Parse buffer */
-
- struct nfs_mount_info mount_info;
- struct nfs_clone_mount clone_data;
+ struct nfs_fh *mntfh;
+ struct nfs_server *server;
+ struct nfs_subversion *nfs_mod;
+
+ /* Information for a cloned mount. */
+ struct nfs_clone_mount {
+ struct super_block *sb;
+ struct dentry *dentry;
+ struct nfs_fattr *fattr;
+ unsigned int inherited_bsize;
+ } clone_data;
};
static inline struct nfs_fs_context *nfs_fc2context(const struct fs_context *fc)
@@ -194,10 +178,9 @@ extern struct nfs_client *nfs4_find_client_ident(struct net *, int);
extern struct nfs_client *
nfs4_find_client_sessionid(struct net *, const struct sockaddr *,
struct nfs4_sessionid *, u32);
-extern struct nfs_server *nfs_create_server(struct nfs_mount_info *);
-extern struct nfs_server *nfs4_create_server(struct nfs_mount_info *);
-extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *,
- struct nfs_fh *);
+extern struct nfs_server *nfs_create_server(struct fs_context *);
+extern struct nfs_server *nfs4_create_server(struct fs_context *);
+extern struct nfs_server *nfs4_create_referral_server(struct fs_context *);
extern int nfs4_update_server(struct nfs_server *server, const char *hostname,
struct sockaddr *sap, size_t salen,
struct net *net);
@@ -444,12 +427,8 @@ int nfs_submount(struct fs_context *, struct nfs_server *);
int nfs_do_submount(struct fs_context *);
/* getroot.c */
-extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *,
- const char *);
+extern int nfs_get_root(struct super_block *s, struct fs_context *fc);
#if IS_ENABLED(CONFIG_NFS_V4)
-extern struct dentry *nfs4_get_root(struct super_block *, struct nfs_fh *,
- const char *);
-
extern int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh, bool);
#endif
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c
index 9b344fcd23b0..d537350c1fb7 100644
--- a/fs/nfs/namespace.c
+++ b/fs/nfs/namespace.c
@@ -176,8 +176,8 @@ struct vfsmount *nfs_d_automount(struct path *path)
ctx->version = client->rpc_ops->version;
ctx->minorversion = client->cl_minorversion;
- ctx->mount_info.nfs_mod = client->cl_nfs_mod;
- __module_get(ctx->mount_info.nfs_mod->owner);
+ ctx->nfs_mod = client->cl_nfs_mod;
+ __module_get(ctx->nfs_mod->owner);
ret = client->rpc_ops->submount(fc, server);
if (ret < 0) {
@@ -262,22 +262,22 @@ int nfs_do_submount(struct fs_context *fc)
int ret;
/* create a new volume representation */
- server = ctx->mount_info.nfs_mod->rpc_ops->clone_server(NFS_SB(ctx->clone_data.sb),
- ctx->mount_info.mntfh,
+ server = ctx->nfs_mod->rpc_ops->clone_server(NFS_SB(ctx->clone_data.sb),
+ ctx->mntfh,
ctx->clone_data.fattr,
ctx->selected_flavor);
if (IS_ERR(server))
return PTR_ERR(server);
- ctx->mount_info.server = server;
+ ctx->server = server;
buffer = kmalloc(4096, GFP_USER);
if (!buffer)
return -ENOMEM;
ctx->internal = true;
- ctx->mount_info.inherited_bsize = ctx->clone_data.sb->s_blocksize_bits;
+ ctx->clone_data.inherited_bsize = ctx->clone_data.sb->s_blocksize_bits;
p = nfs_devname(dentry, buffer, 4096);
if (IS_ERR(p)) {
@@ -302,7 +302,7 @@ int nfs_submount(struct fs_context *fc, struct nfs_server *server)
/* Look it up again to get its attributes */
err = server->nfs_client->rpc_ops->lookup(d_inode(parent), &dentry->d_name,
- ctx->mount_info.mntfh, ctx->clone_data.fattr,
+ ctx->mntfh, ctx->clone_data.fattr,
NULL);
dput(parent);
if (err != 0)
diff --git a/fs/nfs/nfs3_fs.h b/fs/nfs/nfs3_fs.h
index 09602dc1889f..1b950b66b3bb 100644
--- a/fs/nfs/nfs3_fs.h
+++ b/fs/nfs/nfs3_fs.h
@@ -27,7 +27,7 @@ static inline int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
#endif /* CONFIG_NFS_V3_ACL */
/* nfs3client.c */
-struct nfs_server *nfs3_create_server(struct nfs_mount_info *);
+struct nfs_server *nfs3_create_server(struct fs_context *);
struct nfs_server *nfs3_clone_server(struct nfs_server *, struct nfs_fh *,
struct nfs_fattr *, rpc_authflavor_t);
diff --git a/fs/nfs/nfs3client.c b/fs/nfs/nfs3client.c
index 54727d3d3042..5601e47360c2 100644
--- a/fs/nfs/nfs3client.c
+++ b/fs/nfs/nfs3client.c
@@ -46,9 +46,10 @@ static inline void nfs_init_server_aclclient(struct nfs_server *server)
}
#endif
-struct nfs_server *nfs3_create_server(struct nfs_mount_info *mount_info)
+struct nfs_server *nfs3_create_server(struct fs_context *fc)
{
- struct nfs_server *server = nfs_create_server(mount_info);
+ struct nfs_server *server = nfs_create_server(fc);
+
/* Create a client RPC handle for the NFS v3 ACL management interface */
if (!IS_ERR(server))
nfs_init_server_aclclient(server);
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c
index 2216d166768b..0cd767e5c977 100644
--- a/fs/nfs/nfs4client.c
+++ b/fs/nfs/nfs4client.c
@@ -1055,9 +1055,9 @@ static int nfs4_server_common_setup(struct nfs_server *server,
/*
* Create a version 4 volume record
*/
-static int nfs4_init_server(struct nfs_server *server,
- struct nfs_fs_context *ctx)
+static int nfs4_init_server(struct nfs_server *server, struct fs_context *fc)
{
+ struct nfs_fs_context *ctx = nfs_fc2context(fc);
struct rpc_timeout timeparms;
int error;
@@ -1079,15 +1079,15 @@ static int nfs4_init_server(struct nfs_server *server,
/* Get a client record */
error = nfs4_set_client(server,
- ctx->nfs_server.hostname,
- (const struct sockaddr *)&ctx->nfs_server.address,
- ctx->nfs_server.addrlen,
- ctx->client_address,
- ctx->nfs_server.protocol,
- &timeparms,
- ctx->minorversion,
- ctx->nfs_server.nconnect,
- ctx->net);
+ ctx->nfs_server.hostname,
+ &ctx->nfs_server.address,
+ ctx->nfs_server.addrlen,
+ ctx->client_address,
+ ctx->nfs_server.protocol,
+ &timeparms,
+ ctx->minorversion,
+ ctx->nfs_server.nconnect,
+ fc->net_ns);
if (error < 0)
return error;
@@ -1110,10 +1110,9 @@ static int nfs4_init_server(struct nfs_server *server,
* Create a version 4 volume record
* - keyed on server and FSID
*/
-/*struct nfs_server *nfs4_create_server(const struct nfs_fs_context *data,
- struct nfs_fh *mntfh)*/
-struct nfs_server *nfs4_create_server(struct nfs_mount_info *mount_info)
+struct nfs_server *nfs4_create_server(struct fs_context *fc)
{
+ struct nfs_fs_context *ctx = nfs_fc2context(fc);
struct nfs_server *server;
bool auth_probe;
int error;
@@ -1124,14 +1123,14 @@ struct nfs_server *nfs4_create_server(struct nfs_mount_info *mount_info)
server->cred = get_cred(current_cred());
- auth_probe = mount_info->ctx->auth_info.flavor_len < 1;
+ auth_probe = ctx->auth_info.flavor_len < 1;
/* set up the general RPC client */
- error = nfs4_init_server(server, mount_info->ctx);
+ error = nfs4_init_server(server, fc);
if (error < 0)
goto error;
- error = nfs4_server_common_setup(server, mount_info->mntfh, auth_probe);
+ error = nfs4_server_common_setup(server, ctx->mntfh, auth_probe);
if (error < 0)
goto error;
@@ -1145,9 +1144,9 @@ struct nfs_server *nfs4_create_server(struct nfs_mount_info *mount_info)
/*
* Create an NFS4 referral server record
*/
-struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
- struct nfs_fh *mntfh)
+struct nfs_server *nfs4_create_referral_server(struct fs_context *fc)
{
+ struct nfs_fs_context *ctx = nfs_fc2context(fc);
struct nfs_client *parent_client;
struct nfs_server *server, *parent_server;
bool auth_probe;
@@ -1157,7 +1156,7 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
if (!server)
return ERR_PTR(-ENOMEM);
- parent_server = NFS_SB(data->sb);
+ parent_server = NFS_SB(ctx->clone_data.sb);
parent_client = parent_server->nfs_client;
server->cred = get_cred(parent_server->cred);
@@ -1167,10 +1166,11 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
/* Get a client representation */
#if IS_ENABLED(CONFIG_SUNRPC_XPRT_RDMA)
- rpc_set_port(data->addr, NFS_RDMA_PORT);
- error = nfs4_set_client(server, data->hostname,
- data->addr,
- data->addrlen,
+ rpc_set_port(&ctx->nfs_server.address, NFS_RDMA_PORT);
+ error = nfs4_set_client(server,
+ ctx->nfs_server.hostname,
+ &ctx->nfs_server.address,
+ ctx->nfs_server.addrlen,
parent_client->cl_ipaddr,
XPRT_TRANSPORT_RDMA,
parent_server->client->cl_timeout,
@@ -1181,10 +1181,11 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
goto init_server;
#endif /* IS_ENABLED(CONFIG_SUNRPC_XPRT_RDMA) */
- rpc_set_port(data->addr, NFS_PORT);
- error = nfs4_set_client(server, data->hostname,
- data->addr,
- data->addrlen,
+ rpc_set_port(&ctx->nfs_server.address, NFS_PORT);
+ error = nfs4_set_client(server,
+ ctx->nfs_server.hostname,
+ &ctx->nfs_server.address,
+ ctx->nfs_server.addrlen,
parent_client->cl_ipaddr,
XPRT_TRANSPORT_TCP,
parent_server->client->cl_timeout,
@@ -1197,13 +1198,14 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
#if IS_ENABLED(CONFIG_SUNRPC_XPRT_RDMA)
init_server:
#endif
- error = nfs_init_server_rpcclient(server, parent_server->client->cl_timeout, data->authflavor);
+ error = nfs_init_server_rpcclient(server, parent_server->client->cl_timeout,
+ ctx->selected_flavor);
if (error < 0)
goto error;
auth_probe = parent_server->auth_info.flavor_len < 1;
- error = nfs4_server_common_setup(server, mntfh, auth_probe);
+ error = nfs4_server_common_setup(server, ctx->mntfh, auth_probe);
if (error < 0)
goto error;
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c
index a1a0c4c53ce1..10e9e1887841 100644
--- a/fs/nfs/nfs4namespace.c
+++ b/fs/nfs/nfs4namespace.c
@@ -130,9 +130,10 @@ static int nfs4_validate_fspath(struct dentry *dentry,
const struct nfs4_fs_locations *locations,
struct nfs_fs_context *ctx)
{
- const char *path, *fs_path;
- char *buf;
+ const char *path;
+ char *fs_path;
unsigned short len;
+ char *buf;
int n;
buf = kmalloc(4096, GFP_KERNEL);
@@ -278,7 +279,6 @@ nfs4_negotiate_security(struct rpc_clnt *clnt, struct inode *inode,
static int try_location(struct fs_context *fc,
const struct nfs4_fs_location *location)
{
- const size_t addr_bufsize = sizeof(struct sockaddr_storage);
struct nfs_fs_context *ctx = nfs_fc2context(fc);
unsigned int len, s;
char *export_path, *source, *p;
@@ -314,29 +314,24 @@ static int try_location(struct fs_context *fc,
kfree(fc->source);
fc->source = source;
-
- ctx->clone_data.addr = kmalloc(addr_bufsize, GFP_KERNEL);
- if (ctx->clone_data.addr == NULL)
- return -ENOMEM;
for (s = 0; s < location->nservers; s++) {
const struct nfs4_string *buf = &location->servers[s];
if (memchr(buf->data, IPV6_SCOPE_DELIMITER, buf->len))
continue;
- ctx->clone_data.addrlen =
+ ctx->nfs_server.addrlen =
nfs_parse_server_name(buf->data, buf->len,
- ctx->clone_data.addr,
- addr_bufsize,
+ &ctx->nfs_server.address,
+ sizeof(ctx->nfs_server._address),
fc->net_ns);
- if (ctx->clone_data.addrlen == 0)
+ if (ctx->nfs_server.addrlen == 0)
continue;
- rpc_set_port(ctx->clone_data.addr, NFS_PORT);
+ rpc_set_port(&ctx->nfs_server.address, NFS_PORT);
memcpy(ctx->nfs_server.hostname, buf->data, buf->len);
ctx->nfs_server.hostname[buf->len] = '\0';
- ctx->clone_data.hostname = ctx->nfs_server.hostname;
p = source;
memcpy(p, buf->data, buf->len);
@@ -449,7 +444,7 @@ int nfs4_submount(struct fs_context *fc, struct nfs_server *server)
int ret;
/* Look it up again to get its attributes and sec flavor */
- client = nfs4_proc_lookup_mountpoint(dir, name, ctx->mount_info.mntfh,
+ client = nfs4_proc_lookup_mountpoint(dir, name, ctx->mntfh,
ctx->clone_data.fattr);
dput(parent);
if (IS_ERR(client))
diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c
index 469726410c5c..7d5ed37633d8 100644
--- a/fs/nfs/nfs4super.c
+++ b/fs/nfs/nfs4super.c
@@ -35,12 +35,12 @@ static const struct super_operations nfs4_sops = {
};
struct nfs_subversion nfs_v4 = {
- .owner = THIS_MODULE,
- .nfs_fs = &nfs4_fs_type,
- .rpc_vers = &nfs_version4,
- .rpc_ops = &nfs_v4_clientops,
- .sops = &nfs4_sops,
- .xattr = nfs4_xattr_handlers,
+ .owner = THIS_MODULE,
+ .nfs_fs = &nfs4_fs_type,
+ .rpc_vers = &nfs_version4,
+ .rpc_ops = &nfs_v4_clientops,
+ .sops = &nfs4_sops,
+ .xattr = nfs4_xattr_handlers,
};
static int nfs4_write_inode(struct inode *inode, struct writeback_control *wbc)
@@ -168,7 +168,7 @@ static int do_nfs4_mount(struct nfs_server *server,
root_ctx = nfs_fc2context(root_fc);
root_ctx->internal = true;
- root_ctx->mount_info.server = server;
+ root_ctx->server = server;
/* We leave export_path unset as it's not used to find the root. */
len = strlen(hostname) + 5;
@@ -221,7 +221,7 @@ int nfs4_try_get_tree(struct fs_context *fc)
/* We create a mount for the server's root, walk to the requested
* location and then create another mount for that.
*/
- err= do_nfs4_mount(nfs4_create_server(&ctx->mount_info),
+ err= do_nfs4_mount(nfs4_create_server(fc),
fc, ctx->nfs_server.hostname,
ctx->nfs_server.export_path);
if (err) {
@@ -243,7 +243,7 @@ int nfs4_get_referral_tree(struct fs_context *fc)
dprintk("--> nfs4_referral_mount()\n");
/* create a new volume representation */
- err = do_nfs4_mount(nfs4_create_referral_server(&ctx->clone_data, ctx->mount_info.mntfh),
+ err = do_nfs4_mount(nfs4_create_referral_server(fc),
fc, ctx->nfs_server.hostname,
ctx->nfs_server.export_path);
if (err) {
@@ -254,7 +254,6 @@ int nfs4_get_referral_tree(struct fs_context *fc)
return err;
}
-
static int __init init_nfs_v4(void)
{
int err;
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 6ff99da978a8..ed0290d5ebf3 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -745,11 +745,12 @@ static int nfs_verify_authflavors(struct nfs_fs_context *ctx,
* Use the remote server's MOUNT service to request the NFS file handle
* corresponding to the provided path.
*/
-static int nfs_request_mount(struct nfs_fs_context *ctx,
+static int nfs_request_mount(struct fs_context *fc,
struct nfs_fh *root_fh,
rpc_authflavor_t *server_authlist,
unsigned int *server_authlist_len)
{
+ struct nfs_fs_context *ctx = nfs_fc2context(fc);
struct nfs_mount_request request = {
.sap = (struct sockaddr *)
&ctx->mount_server.address,
@@ -759,7 +760,7 @@ static int nfs_request_mount(struct nfs_fs_context *ctx,
.noresvport = ctx->flags & NFS_MOUNT_NORESVPORT,
.auth_flav_len = server_authlist_len,
.auth_flavs = server_authlist,
- .net = ctx->net,
+ .net = fc->net_ns,
};
int status;
@@ -804,20 +805,18 @@ static int nfs_request_mount(struct nfs_fs_context *ctx,
return 0;
}
-static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_info)
+static struct nfs_server *nfs_try_mount_request(struct fs_context *fc)
{
+ struct nfs_fs_context *ctx = nfs_fc2context(fc);
int status;
unsigned int i;
bool tried_auth_unix = false;
bool auth_null_in_list = false;
struct nfs_server *server = ERR_PTR(-EACCES);
- struct nfs_fs_context *ctx = mount_info->ctx;
rpc_authflavor_t authlist[NFS_MAX_SECFLAVORS];
unsigned int authlist_len = ARRAY_SIZE(authlist);
- struct nfs_subversion *nfs_mod = mount_info->nfs_mod;
- status = nfs_request_mount(ctx, mount_info->mntfh, authlist,
- &authlist_len);
+ status = nfs_request_mount(fc, ctx->mntfh, authlist, &authlist_len);
if (status)
return ERR_PTR(status);
@@ -831,7 +830,7 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf
ctx->selected_flavor);
if (status)
return ERR_PTR(status);
- return nfs_mod->rpc_ops->create_server(mount_info);
+ return ctx->nfs_mod->rpc_ops->create_server(fc);
}
/*
@@ -858,7 +857,7 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf
}
dfprintk(MOUNT, "NFS: attempting to use auth flavor %u\n", flavor);
ctx->selected_flavor = flavor;
- server = nfs_mod->rpc_ops->create_server(mount_info);
+ server = ctx->nfs_mod->rpc_ops->create_server(fc);
if (!IS_ERR(server))
return server;
}
@@ -874,7 +873,7 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf
/* Last chance! Try AUTH_UNIX */
dfprintk(MOUNT, "NFS: attempting to use auth flavor %u\n", RPC_AUTH_UNIX);
ctx->selected_flavor = RPC_AUTH_UNIX;
- return nfs_mod->rpc_ops->create_server(mount_info);
+ return ctx->nfs_mod->rpc_ops->create_server(fc);
}
int nfs_try_get_tree(struct fs_context *fc)
@@ -882,9 +881,9 @@ int nfs_try_get_tree(struct fs_context *fc)
struct nfs_fs_context *ctx = nfs_fc2context(fc);
if (ctx->need_mount)
- ctx->mount_info.server = nfs_try_mount_request(&ctx->mount_info);
+ ctx->server = nfs_try_mount_request(fc);
else
- ctx->mount_info.server = ctx->mount_info.nfs_mod->rpc_ops->create_server(&ctx->mount_info);
+ ctx->server = ctx->nfs_mod->rpc_ops->create_server(fc);
return nfs_get_tree_common(fc);
}
@@ -966,9 +965,8 @@ EXPORT_SYMBOL_GPL(nfs_reconfigure);
/*
* Finish setting up an NFS superblock
*/
-static void nfs_fill_super(struct super_block *sb, struct nfs_mount_info *mount_info)
+static void nfs_fill_super(struct super_block *sb, struct nfs_fs_context *ctx)
{
- struct nfs_fs_context *ctx = mount_info->ctx;
struct nfs_server *server = NFS_SB(sb);
sb->s_blocksize_bits = 0;
@@ -1009,13 +1007,14 @@ static void nfs_fill_super(struct super_block *sb, struct nfs_mount_info *mount_
nfs_super_set_maxbytes(sb, server->maxfilesize);
}
-static int nfs_compare_mount_options(const struct super_block *s, const struct nfs_server *b, int flags)
+static int nfs_compare_mount_options(const struct super_block *s, const struct nfs_server *b,
+ const struct fs_context *fc)
{
const struct nfs_server *a = s->s_fs_info;
const struct rpc_clnt *clnt_a = a->client;
const struct rpc_clnt *clnt_b = b->client;
- if ((s->s_flags & NFS_MS_MASK) != (flags & NFS_MS_MASK))
+ if ((s->s_flags & NFS_SB_MASK) != (fc->sb_flags & NFS_SB_MASK))
goto Ebusy;
if (a->nfs_client != b->nfs_client)
goto Ebusy;
@@ -1122,7 +1121,7 @@ static int nfs_compare_super(struct super_block *sb, struct fs_context *fc)
return 0;
if (!nfs_compare_userns(old, server))
return 0;
- return nfs_compare_mount_options(sb, server, fc->sb_flags);
+ return nfs_compare_mount_options(sb, server, fc);
}
#ifdef CONFIG_NFS_FSCACHE
@@ -1177,13 +1176,12 @@ int nfs_get_tree_common(struct fs_context *fc)
{
struct nfs_fs_context *ctx = nfs_fc2context(fc);
struct super_block *s;
- struct dentry *mntroot = ERR_PTR(-ENOMEM);
int (*compare_super)(struct super_block *, struct fs_context *) = nfs_compare_super;
- struct nfs_server *server = ctx->mount_info.server;
+ struct nfs_server *server = ctx->server;
unsigned long kflags = 0, kflags_out = 0;
int error;
- ctx->mount_info.server = NULL;
+ ctx->server = NULL;
if (IS_ERR(server))
return PTR_ERR(server);
@@ -1224,9 +1222,9 @@ int nfs_get_tree_common(struct fs_context *fc)
}
if (!s->s_root) {
- unsigned bsize = ctx->mount_info.inherited_bsize;
+ unsigned bsize = ctx->clone_data.inherited_bsize;
/* initial superblock/root creation */
- nfs_fill_super(s, &ctx->mount_info);
+ nfs_fill_super(s, ctx);
if (bsize) {
s->s_blocksize_bits = bsize;
s->s_blocksize = 1U << bsize;
@@ -1234,13 +1232,11 @@ int nfs_get_tree_common(struct fs_context *fc)
nfs_get_cache_cookie(s, ctx);
}
- mntroot = nfs_get_root(s, ctx->mount_info.mntfh, fc->source);
- if (IS_ERR(mntroot)) {
- error = PTR_ERR(mntroot);
+ error = nfs_get_root(s, fc);
+ if (error < 0) {
dfprintk(MOUNT, "NFS: Couldn't get root dentry\n");
goto error_splat_super;
}
- fc->root = mntroot;
if (NFS_SB(s)->caps & NFS_CAP_SECURITY_LABEL)
kflags |= SECURITY_LSM_NATIVE_LABELS;
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 574741d5418d..0a36c6f62b58 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1722,7 +1722,7 @@ struct nfs_rpc_ops {
struct nfs_client *(*init_client) (struct nfs_client *,
const struct nfs_client_initdata *);
void (*free_client) (struct nfs_client *);
- struct nfs_server *(*create_server)(struct nfs_mount_info *);
+ struct nfs_server *(*create_server)(struct fs_context *);
struct nfs_server *(*clone_server)(struct nfs_server *, struct nfs_fh *,
struct nfs_fattr *, rpc_authflavor_t);
};
--
2.17.2
^ permalink raw reply related
* [PATCH v6 17/27] NFS: Constify mount argument match tables
From: Scott Mayhew @ 2019-12-10 12:31 UTC (permalink / raw)
To: anna.schumaker, trond.myklebust
Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel,
linux-security-module
In-Reply-To: <20191210123115.1655-1-smayhew@redhat.com>
From: David Howells <dhowells@redhat.com>
The mount argument match tables should never be altered so constify them.
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
fs/nfs/fs_context.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/fs/nfs/fs_context.c b/fs/nfs/fs_context.c
index c8f99a3c7264..8fbfd526d6b8 100644
--- a/fs/nfs/fs_context.c
+++ b/fs/nfs/fs_context.c
@@ -199,7 +199,7 @@ enum {
Opt_lookupcache_err
};
-static match_table_t nfs_lookupcache_tokens = {
+static const match_table_t nfs_lookupcache_tokens = {
{ Opt_lookupcache_all, "all" },
{ Opt_lookupcache_positive, "pos" },
{ Opt_lookupcache_positive, "positive" },
@@ -215,7 +215,7 @@ enum {
Opt_local_lock_err
};
-static match_table_t nfs_local_lock_tokens = {
+static const match_table_t nfs_local_lock_tokens = {
{ Opt_local_lock_all, "all" },
{ Opt_local_lock_flock, "flock" },
{ Opt_local_lock_posix, "posix" },
@@ -231,7 +231,7 @@ enum {
Opt_vers_err
};
-static match_table_t nfs_vers_tokens = {
+static const match_table_t nfs_vers_tokens = {
{ Opt_vers_2, "2" },
{ Opt_vers_3, "3" },
{ Opt_vers_4, "4" },
--
2.17.2
^ permalink raw reply related
* [PATCH v6 24/27] NFS: Convert mount option parsing to use functionality from fs_parser.h
From: Scott Mayhew @ 2019-12-10 12:31 UTC (permalink / raw)
To: anna.schumaker, trond.myklebust
Cc: dhowells, viro, linux-nfs, linux-fsdevel, linux-kernel,
linux-security-module
In-Reply-To: <20191210123115.1655-1-smayhew@redhat.com>
Split out from commit "NFS: Add fs_context support."
Convert existing mount option definitions to fs_parameter_enum's and
fs_parameter_spec's. Parse mount options using fs_parse() and
lookup_constant().
Notes:
1) Fixed a typo in the udp6 definition in nfs_xprt_protocol_tokens
from the original commit.
2) fs_parse() expects an fs_context as the first arg so that any
errors can be logged to the fs_context. We're passing NULL for the
fs_context (this will change in commit "NFS: Add fs_context support.")
which is okay as it will cause logfc() to do a printk() instead.
3) fs_parse() expects an fs_paramter as the third arg. We're
building an fs_parameter manually in nfs_fs_context_parse_option(),
which will go away in commit "NFS: Add fs_context support.".
Signed-off-by: Scott Mayhew <smayhew@redhat.com>
---
fs/nfs/fs_context.c | 787 ++++++++++++++++++++------------------------
1 file changed, 364 insertions(+), 423 deletions(-)
diff --git a/fs/nfs/fs_context.c b/fs/nfs/fs_context.c
index 44531443a92b..9a3162055d5d 100644
--- a/fs/nfs/fs_context.c
+++ b/fs/nfs/fs_context.c
@@ -11,7 +11,8 @@
#include <linux/module.h>
#include <linux/fs.h>
-#include <linux/parser.h>
+#include <linux/fs_context.h>
+#include <linux/fs_parser.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_mount.h>
#include <linux/nfs4_mount.h>
@@ -28,218 +29,215 @@
#define NFS_MAX_CONNECTIONS 16
-enum {
- /* Mount options that take no arguments */
- Opt_soft, Opt_softerr, Opt_hard,
- Opt_posix, Opt_noposix,
- Opt_cto, Opt_nocto,
- Opt_ac, Opt_noac,
- Opt_lock, Opt_nolock,
- Opt_udp, Opt_tcp, Opt_rdma,
- Opt_acl, Opt_noacl,
- Opt_rdirplus, Opt_nordirplus,
- Opt_sharecache, Opt_nosharecache,
- Opt_resvport, Opt_noresvport,
- Opt_fscache, Opt_nofscache,
- Opt_migration, Opt_nomigration,
-
- /* Mount options that take integer arguments */
- Opt_port,
- Opt_rsize, Opt_wsize, Opt_bsize,
- Opt_timeo, Opt_retrans,
- Opt_acregmin, Opt_acregmax,
- Opt_acdirmin, Opt_acdirmax,
+enum nfs_param {
+ Opt_ac,
+ Opt_acdirmax,
+ Opt_acdirmin,
+ Opt_acl,
+ Opt_acregmax,
+ Opt_acregmin,
Opt_actimeo,
- Opt_namelen,
+ Opt_addr,
+ Opt_bg,
+ Opt_bsize,
+ Opt_clientaddr,
+ Opt_cto,
+ Opt_fg,
+ Opt_fscache,
+ Opt_hard,
+ Opt_intr,
+ Opt_local_lock,
+ Opt_lock,
+ Opt_lookupcache,
+ Opt_migration,
+ Opt_minorversion,
+ Opt_mountaddr,
+ Opt_mounthost,
Opt_mountport,
+ Opt_mountproto,
Opt_mountvers,
- Opt_minorversion,
-
- /* Mount options that take string arguments */
- Opt_nfsvers,
- Opt_sec, Opt_proto, Opt_mountproto, Opt_mounthost,
- Opt_addr, Opt_mountaddr, Opt_clientaddr,
+ Opt_namelen,
Opt_nconnect,
- Opt_lookupcache,
- Opt_fscache_uniq,
- Opt_local_lock,
-
- /* Special mount options */
- Opt_userspace, Opt_deprecated, Opt_sloppy,
-
- Opt_err
+ Opt_port,
+ Opt_posix,
+ Opt_proto,
+ Opt_rdirplus,
+ Opt_rdma,
+ Opt_resvport,
+ Opt_retrans,
+ Opt_retry,
+ Opt_rsize,
+ Opt_sec,
+ Opt_sharecache,
+ Opt_sloppy,
+ Opt_soft,
+ Opt_softerr,
+ Opt_source,
+ Opt_tcp,
+ Opt_timeo,
+ Opt_udp,
+ Opt_v,
+ Opt_vers,
+ Opt_wsize,
};
-static const match_table_t nfs_mount_option_tokens = {
- { Opt_userspace, "bg" },
- { Opt_userspace, "fg" },
- { Opt_userspace, "retry=%s" },
-
- { Opt_sloppy, "sloppy" },
-
- { Opt_soft, "soft" },
- { Opt_softerr, "softerr" },
- { Opt_hard, "hard" },
- { Opt_deprecated, "intr" },
- { Opt_deprecated, "nointr" },
- { Opt_posix, "posix" },
- { Opt_noposix, "noposix" },
- { Opt_cto, "cto" },
- { Opt_nocto, "nocto" },
- { Opt_ac, "ac" },
- { Opt_noac, "noac" },
- { Opt_lock, "lock" },
- { Opt_nolock, "nolock" },
- { Opt_udp, "udp" },
- { Opt_tcp, "tcp" },
- { Opt_rdma, "rdma" },
- { Opt_acl, "acl" },
- { Opt_noacl, "noacl" },
- { Opt_rdirplus, "rdirplus" },
- { Opt_nordirplus, "nordirplus" },
- { Opt_sharecache, "sharecache" },
- { Opt_nosharecache, "nosharecache" },
- { Opt_resvport, "resvport" },
- { Opt_noresvport, "noresvport" },
- { Opt_fscache, "fsc" },
- { Opt_nofscache, "nofsc" },
- { Opt_migration, "migration" },
- { Opt_nomigration, "nomigration" },
-
- { Opt_port, "port=%s" },
- { Opt_rsize, "rsize=%s" },
- { Opt_wsize, "wsize=%s" },
- { Opt_bsize, "bsize=%s" },
- { Opt_timeo, "timeo=%s" },
- { Opt_retrans, "retrans=%s" },
- { Opt_acregmin, "acregmin=%s" },
- { Opt_acregmax, "acregmax=%s" },
- { Opt_acdirmin, "acdirmin=%s" },
- { Opt_acdirmax, "acdirmax=%s" },
- { Opt_actimeo, "actimeo=%s" },
- { Opt_namelen, "namlen=%s" },
- { Opt_mountport, "mountport=%s" },
- { Opt_mountvers, "mountvers=%s" },
- { Opt_minorversion, "minorversion=%s" },
-
- { Opt_nfsvers, "nfsvers=%s" },
- { Opt_nfsvers, "vers=%s" },
-
- { Opt_sec, "sec=%s" },
- { Opt_proto, "proto=%s" },
- { Opt_mountproto, "mountproto=%s" },
- { Opt_addr, "addr=%s" },
- { Opt_clientaddr, "clientaddr=%s" },
- { Opt_mounthost, "mounthost=%s" },
- { Opt_mountaddr, "mountaddr=%s" },
-
- { Opt_nconnect, "nconnect=%s" },
-
- { Opt_lookupcache, "lookupcache=%s" },
- { Opt_fscache_uniq, "fsc=%s" },
- { Opt_local_lock, "local_lock=%s" },
-
- /* The following needs to be listed after all other options */
- { Opt_nfsvers, "v%s" },
-
- { Opt_err, NULL }
+static const struct fs_parameter_spec nfs_param_specs[] = {
+ fsparam_flag_no("ac", Opt_ac),
+ fsparam_u32 ("acdirmax", Opt_acdirmax),
+ fsparam_u32 ("acdirmin", Opt_acdirmin),
+ fsparam_flag_no("acl", Opt_acl),
+ fsparam_u32 ("acregmax", Opt_acregmax),
+ fsparam_u32 ("acregmin", Opt_acregmin),
+ fsparam_u32 ("actimeo", Opt_actimeo),
+ fsparam_string("addr", Opt_addr),
+ fsparam_flag ("bg", Opt_bg),
+ fsparam_u32 ("bsize", Opt_bsize),
+ fsparam_string("clientaddr", Opt_clientaddr),
+ fsparam_flag_no("cto", Opt_cto),
+ fsparam_flag ("fg", Opt_fg),
+ __fsparam(fs_param_is_string, "fsc", Opt_fscache,
+ fs_param_neg_with_no|fs_param_v_optional),
+ fsparam_flag ("hard", Opt_hard),
+ __fsparam(fs_param_is_flag, "intr", Opt_intr,
+ fs_param_neg_with_no|fs_param_deprecated),
+ fsparam_enum ("local_lock", Opt_local_lock),
+ fsparam_flag_no("lock", Opt_lock),
+ fsparam_enum ("lookupcache", Opt_lookupcache),
+ fsparam_flag_no("migration", Opt_migration),
+ fsparam_u32 ("minorversion", Opt_minorversion),
+ fsparam_string("mountaddr", Opt_mountaddr),
+ fsparam_string("mounthost", Opt_mounthost),
+ fsparam_u32 ("mountport", Opt_mountport),
+ fsparam_string("mountproto", Opt_mountproto),
+ fsparam_u32 ("mountvers", Opt_mountvers),
+ fsparam_u32 ("namlen", Opt_namelen),
+ fsparam_u32 ("nconnect", Opt_nconnect),
+ fsparam_string("nfsvers", Opt_vers),
+ fsparam_u32 ("port", Opt_port),
+ fsparam_flag_no("posix", Opt_posix),
+ fsparam_string("proto", Opt_proto),
+ fsparam_flag_no("rdirplus", Opt_rdirplus),
+ fsparam_flag ("rdma", Opt_rdma),
+ fsparam_flag_no("resvport", Opt_resvport),
+ fsparam_u32 ("retrans", Opt_retrans),
+ fsparam_string("retry", Opt_retry),
+ fsparam_u32 ("rsize", Opt_rsize),
+ fsparam_string("sec", Opt_sec),
+ fsparam_flag_no("sharecache", Opt_sharecache),
+ fsparam_flag ("sloppy", Opt_sloppy),
+ fsparam_flag ("soft", Opt_soft),
+ fsparam_flag ("softerr", Opt_softerr),
+ fsparam_string("source", Opt_source),
+ fsparam_flag ("tcp", Opt_tcp),
+ fsparam_u32 ("timeo", Opt_timeo),
+ fsparam_flag ("udp", Opt_udp),
+ fsparam_flag ("v2", Opt_v),
+ fsparam_flag ("v3", Opt_v),
+ fsparam_flag ("v4", Opt_v),
+ fsparam_flag ("v4.0", Opt_v),
+ fsparam_flag ("v4.1", Opt_v),
+ fsparam_flag ("v4.2", Opt_v),
+ fsparam_string("vers", Opt_vers),
+ fsparam_u32 ("wsize", Opt_wsize),
+ {}
};
enum {
- Opt_xprt_udp, Opt_xprt_udp6, Opt_xprt_tcp, Opt_xprt_tcp6, Opt_xprt_rdma,
- Opt_xprt_rdma6,
-
- Opt_xprt_err
-};
-
-static const match_table_t nfs_xprt_protocol_tokens = {
- { Opt_xprt_udp, "udp" },
- { Opt_xprt_udp6, "udp6" },
- { Opt_xprt_tcp, "tcp" },
- { Opt_xprt_tcp6, "tcp6" },
- { Opt_xprt_rdma, "rdma" },
- { Opt_xprt_rdma6, "rdma6" },
-
- { Opt_xprt_err, NULL }
+ Opt_local_lock_all,
+ Opt_local_lock_flock,
+ Opt_local_lock_none,
+ Opt_local_lock_posix,
};
enum {
- Opt_sec_none, Opt_sec_sys,
- Opt_sec_krb5, Opt_sec_krb5i, Opt_sec_krb5p,
- Opt_sec_lkey, Opt_sec_lkeyi, Opt_sec_lkeyp,
- Opt_sec_spkm, Opt_sec_spkmi, Opt_sec_spkmp,
-
- Opt_sec_err
+ Opt_lookupcache_all,
+ Opt_lookupcache_none,
+ Opt_lookupcache_positive,
};
-static const match_table_t nfs_secflavor_tokens = {
- { Opt_sec_none, "none" },
- { Opt_sec_none, "null" },
- { Opt_sec_sys, "sys" },
-
- { Opt_sec_krb5, "krb5" },
- { Opt_sec_krb5i, "krb5i" },
- { Opt_sec_krb5p, "krb5p" },
-
- { Opt_sec_lkey, "lkey" },
- { Opt_sec_lkeyi, "lkeyi" },
- { Opt_sec_lkeyp, "lkeyp" },
-
- { Opt_sec_spkm, "spkm3" },
- { Opt_sec_spkmi, "spkm3i" },
- { Opt_sec_spkmp, "spkm3p" },
+static const struct fs_parameter_enum nfs_param_enums[] = {
+ { Opt_local_lock, "all", Opt_local_lock_all },
+ { Opt_local_lock, "flock", Opt_local_lock_flock },
+ { Opt_local_lock, "none", Opt_local_lock_none },
+ { Opt_local_lock, "posix", Opt_local_lock_posix },
+ { Opt_lookupcache, "all", Opt_lookupcache_all },
+ { Opt_lookupcache, "none", Opt_lookupcache_none },
+ { Opt_lookupcache, "pos", Opt_lookupcache_positive },
+ { Opt_lookupcache, "positive", Opt_lookupcache_positive },
+ {}
+};
- { Opt_sec_err, NULL }
+static const struct fs_parameter_description nfs_fs_parameters = {
+ .name = "nfs",
+ .specs = nfs_param_specs,
+ .enums = nfs_param_enums,
};
enum {
- Opt_lookupcache_all, Opt_lookupcache_positive,
- Opt_lookupcache_none,
-
- Opt_lookupcache_err
+ Opt_vers_2,
+ Opt_vers_3,
+ Opt_vers_4,
+ Opt_vers_4_0,
+ Opt_vers_4_1,
+ Opt_vers_4_2,
};
-static const match_table_t nfs_lookupcache_tokens = {
- { Opt_lookupcache_all, "all" },
- { Opt_lookupcache_positive, "pos" },
- { Opt_lookupcache_positive, "positive" },
- { Opt_lookupcache_none, "none" },
-
- { Opt_lookupcache_err, NULL }
+static const struct constant_table nfs_vers_tokens[] = {
+ { "2", Opt_vers_2 },
+ { "3", Opt_vers_3 },
+ { "4", Opt_vers_4 },
+ { "4.0", Opt_vers_4_0 },
+ { "4.1", Opt_vers_4_1 },
+ { "4.2", Opt_vers_4_2 },
};
enum {
- Opt_local_lock_all, Opt_local_lock_flock, Opt_local_lock_posix,
- Opt_local_lock_none,
-
- Opt_local_lock_err
+ Opt_xprt_rdma,
+ Opt_xprt_rdma6,
+ Opt_xprt_tcp,
+ Opt_xprt_tcp6,
+ Opt_xprt_udp,
+ Opt_xprt_udp6,
+ nr__Opt_xprt
};
-static const match_table_t nfs_local_lock_tokens = {
- { Opt_local_lock_all, "all" },
- { Opt_local_lock_flock, "flock" },
- { Opt_local_lock_posix, "posix" },
- { Opt_local_lock_none, "none" },
-
- { Opt_local_lock_err, NULL }
+static const struct constant_table nfs_xprt_protocol_tokens[nr__Opt_xprt] = {
+ { "rdma", Opt_xprt_rdma },
+ { "rdma6", Opt_xprt_rdma6 },
+ { "tcp", Opt_xprt_tcp },
+ { "tcp6", Opt_xprt_tcp6 },
+ { "udp", Opt_xprt_udp },
+ { "udp6", Opt_xprt_udp6 },
};
enum {
- Opt_vers_2, Opt_vers_3, Opt_vers_4, Opt_vers_4_0,
- Opt_vers_4_1, Opt_vers_4_2,
-
- Opt_vers_err
+ Opt_sec_krb5,
+ Opt_sec_krb5i,
+ Opt_sec_krb5p,
+ Opt_sec_lkey,
+ Opt_sec_lkeyi,
+ Opt_sec_lkeyp,
+ Opt_sec_none,
+ Opt_sec_spkm,
+ Opt_sec_spkmi,
+ Opt_sec_spkmp,
+ Opt_sec_sys,
+ nr__Opt_sec
};
-static const match_table_t nfs_vers_tokens = {
- { Opt_vers_2, "2" },
- { Opt_vers_3, "3" },
- { Opt_vers_4, "4" },
- { Opt_vers_4_0, "4.0" },
- { Opt_vers_4_1, "4.1" },
- { Opt_vers_4_2, "4.2" },
-
- { Opt_vers_err, NULL }
+static const struct constant_table nfs_secflavor_tokens[] = {
+ { "krb5", Opt_sec_krb5 },
+ { "krb5i", Opt_sec_krb5i },
+ { "krb5p", Opt_sec_krb5p },
+ { "lkey", Opt_sec_lkey },
+ { "lkeyi", Opt_sec_lkeyi },
+ { "lkeyp", Opt_sec_lkeyp },
+ { "none", Opt_sec_none },
+ { "null", Opt_sec_none },
+ { "spkm3", Opt_sec_spkm },
+ { "spkm3i", Opt_sec_spkmi },
+ { "spkm3p", Opt_sec_spkmp },
+ { "sys", Opt_sec_sys },
};
struct nfs_fs_context *nfs_alloc_parsed_mount_data(void)
@@ -368,17 +366,19 @@ static int nfs_auth_info_add(struct nfs_fs_context *ctx,
/*
* Parse the value of the 'sec=' option.
*/
-static int nfs_parse_security_flavors(struct nfs_fs_context *ctx, char *value)
+static int nfs_parse_security_flavors(struct nfs_fs_context *ctx,
+ struct fs_parameter *param)
{
- substring_t args[MAX_OPT_ARGS];
rpc_authflavor_t pseudoflavor;
- char *p;
+ char *string = param->string, *p;
int ret;
- dfprintk(MOUNT, "NFS: parsing sec=%s option\n", value);
+ dfprintk(MOUNT, "NFS: parsing %s=%s option\n", param->key, param->string);
- while ((p = strsep(&value, ":")) != NULL) {
- switch (match_token(p, nfs_secflavor_tokens, args)) {
+ while ((p = strsep(&string, ":")) != NULL) {
+ if (!*p)
+ continue;
+ switch (lookup_constant(nfs_secflavor_tokens, p, -1)) {
case Opt_sec_none:
pseudoflavor = RPC_AUTH_NULL;
break;
@@ -427,11 +427,10 @@ static int nfs_parse_security_flavors(struct nfs_fs_context *ctx, char *value)
}
static int nfs_parse_version_string(struct nfs_fs_context *ctx,
- char *string,
- substring_t *args)
+ const char *string)
{
ctx->flags &= ~NFS_MOUNT_VER3;
- switch (match_token(string, nfs_vers_tokens, args)) {
+ switch (lookup_constant(nfs_vers_tokens, string, -1)) {
case Opt_vers_2:
ctx->version = 2;
break;
@@ -465,64 +464,24 @@ static int nfs_parse_version_string(struct nfs_fs_context *ctx,
return 0;
}
-static int nfs_get_option_str(substring_t args[], char **option)
-{
- kfree(*option);
- *option = match_strdup(args);
- return !*option;
-}
-
-static int nfs_get_option_ui(struct nfs_fs_context *ctx,
- substring_t args[], unsigned int *option)
-{
- match_strlcpy(ctx->buf, args, sizeof(ctx->buf));
- return kstrtouint(ctx->buf, 10, option);
-}
-
-static int nfs_get_option_ui_bound(struct nfs_fs_context *ctx,
- substring_t args[], unsigned int *option,
- unsigned int l_bound, unsigned u_bound)
-{
- int ret;
-
- match_strlcpy(ctx->buf, args, sizeof(ctx->buf));
- ret = kstrtouint(ctx->buf, 10, option);
- if (ret < 0)
- return ret;
- if (*option < l_bound || *option > u_bound)
- return -ERANGE;
- return 0;
-}
-
-static int nfs_get_option_us_bound(struct nfs_fs_context *ctx,
- substring_t args[], unsigned short *option,
- unsigned short l_bound,
- unsigned short u_bound)
-{
- int ret;
-
- match_strlcpy(ctx->buf, args, sizeof(ctx->buf));
- ret = kstrtou16(ctx->buf, 10, option);
- if (ret < 0)
- return ret;
- if (*option < l_bound || *option > u_bound)
- return -ERANGE;
- return 0;
-}
-
/*
- * Parse a single mount option in "key[=val]" form.
+ * Parse a single mount parameter.
*/
-static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
+static int nfs_fs_context_parse_param(struct nfs_fs_context *ctx,
+ struct fs_parameter *param)
{
- substring_t args[MAX_OPT_ARGS];
- char *string;
- int token, ret;
+ struct fs_parse_result result;
+ unsigned short protofamily, mountfamily;
+ unsigned int len;
+ int ret, opt;
+
+ dfprintk(MOUNT, "NFS: parsing nfs mount option '%s'\n", param->key);
- dfprintk(MOUNT, "NFS: parsing nfs mount option '%s'\n", p);
+ opt = fs_parse(NULL, &nfs_fs_parameters, param, &result);
+ if (opt < 0)
+ return ctx->sloppy ? 1 : opt;
- token = match_token(p, nfs_mount_option_tokens, args);
- switch (token) {
+ switch (opt) {
/*
* boolean options: foo/nofoo
*/
@@ -538,30 +497,31 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
ctx->flags &= ~(NFS_MOUNT_SOFT|NFS_MOUNT_SOFTERR);
break;
case Opt_posix:
- ctx->flags |= NFS_MOUNT_POSIX;
- break;
- case Opt_noposix:
- ctx->flags &= ~NFS_MOUNT_POSIX;
+ if (result.negated)
+ ctx->flags &= ~NFS_MOUNT_POSIX;
+ else
+ ctx->flags |= NFS_MOUNT_POSIX;
break;
case Opt_cto:
- ctx->flags &= ~NFS_MOUNT_NOCTO;
- break;
- case Opt_nocto:
- ctx->flags |= NFS_MOUNT_NOCTO;
+ if (result.negated)
+ ctx->flags |= NFS_MOUNT_NOCTO;
+ else
+ ctx->flags &= ~NFS_MOUNT_NOCTO;
break;
case Opt_ac:
- ctx->flags &= ~NFS_MOUNT_NOAC;
- break;
- case Opt_noac:
- ctx->flags |= NFS_MOUNT_NOAC;
+ if (result.negated)
+ ctx->flags |= NFS_MOUNT_NOAC;
+ else
+ ctx->flags &= ~NFS_MOUNT_NOAC;
break;
case Opt_lock:
- ctx->flags &= ~NFS_MOUNT_NONLM;
- ctx->flags &= ~(NFS_MOUNT_LOCAL_FLOCK | NFS_MOUNT_LOCAL_FCNTL);
- break;
- case Opt_nolock:
- ctx->flags |= NFS_MOUNT_NONLM;
- ctx->flags |= (NFS_MOUNT_LOCAL_FLOCK | NFS_MOUNT_LOCAL_FCNTL);
+ if (result.negated) {
+ ctx->flags |= NFS_MOUNT_NONLM;
+ ctx->flags |= (NFS_MOUNT_LOCAL_FLOCK | NFS_MOUNT_LOCAL_FCNTL);
+ } else {
+ ctx->flags &= ~NFS_MOUNT_NONLM;
+ ctx->flags &= ~(NFS_MOUNT_LOCAL_FLOCK | NFS_MOUNT_LOCAL_FCNTL);
+ }
break;
case Opt_udp:
ctx->flags &= ~NFS_MOUNT_TCP;
@@ -574,195 +534,177 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
case Opt_rdma:
ctx->flags |= NFS_MOUNT_TCP; /* for side protocols */
ctx->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
- xprt_load_transport(p);
+ xprt_load_transport(param->key);
break;
case Opt_acl:
- ctx->flags &= ~NFS_MOUNT_NOACL;
- break;
- case Opt_noacl:
- ctx->flags |= NFS_MOUNT_NOACL;
+ if (result.negated)
+ ctx->flags |= NFS_MOUNT_NOACL;
+ else
+ ctx->flags &= ~NFS_MOUNT_NOACL;
break;
case Opt_rdirplus:
- ctx->flags &= ~NFS_MOUNT_NORDIRPLUS;
- break;
- case Opt_nordirplus:
- ctx->flags |= NFS_MOUNT_NORDIRPLUS;
+ if (result.negated)
+ ctx->flags |= NFS_MOUNT_NORDIRPLUS;
+ else
+ ctx->flags &= ~NFS_MOUNT_NORDIRPLUS;
break;
case Opt_sharecache:
- ctx->flags &= ~NFS_MOUNT_UNSHARED;
- break;
- case Opt_nosharecache:
- ctx->flags |= NFS_MOUNT_UNSHARED;
+ if (result.negated)
+ ctx->flags |= NFS_MOUNT_UNSHARED;
+ else
+ ctx->flags &= ~NFS_MOUNT_UNSHARED;
break;
case Opt_resvport:
- ctx->flags &= ~NFS_MOUNT_NORESVPORT;
- break;
- case Opt_noresvport:
- ctx->flags |= NFS_MOUNT_NORESVPORT;
+ if (result.negated)
+ ctx->flags |= NFS_MOUNT_NORESVPORT;
+ else
+ ctx->flags &= ~NFS_MOUNT_NORESVPORT;
break;
case Opt_fscache:
- ctx->options |= NFS_OPTION_FSCACHE;
kfree(ctx->fscache_uniq);
- ctx->fscache_uniq = NULL;
- break;
- case Opt_nofscache:
- ctx->options &= ~NFS_OPTION_FSCACHE;
- kfree(ctx->fscache_uniq);
- ctx->fscache_uniq = NULL;
+ ctx->fscache_uniq = param->string;
+ param->string = NULL;
+ if (result.negated)
+ ctx->options &= ~NFS_OPTION_FSCACHE;
+ else
+ ctx->options |= NFS_OPTION_FSCACHE;
break;
case Opt_migration:
- ctx->options |= NFS_OPTION_MIGRATION;
- break;
- case Opt_nomigration:
- ctx->options &= ~NFS_OPTION_MIGRATION;
+ if (result.negated)
+ ctx->options &= ~NFS_OPTION_MIGRATION;
+ else
+ ctx->options |= NFS_OPTION_MIGRATION;
break;
/*
* options that take numeric values
*/
case Opt_port:
- if (nfs_get_option_ui_bound(ctx, args, &ctx->nfs_server.port,
- 0, USHRT_MAX))
- goto out_invalid_value;
+ if (result.uint_32 > USHRT_MAX)
+ goto out_of_bounds;
+ ctx->nfs_server.port = result.uint_32;
break;
case Opt_rsize:
- if (nfs_get_option_ui(ctx, args, &ctx->rsize))
- goto out_invalid_value;
+ ctx->rsize = result.uint_32;
break;
case Opt_wsize:
- if (nfs_get_option_ui(ctx, args, &ctx->wsize))
- goto out_invalid_value;
+ ctx->wsize = result.uint_32;
break;
case Opt_bsize:
- if (nfs_get_option_ui(ctx, args, &ctx->bsize))
- goto out_invalid_value;
+ ctx->bsize = result.uint_32;
break;
case Opt_timeo:
- if (nfs_get_option_ui_bound(ctx, args, &ctx->timeo, 1, INT_MAX))
- goto out_invalid_value;
+ if (result.uint_32 < 1 || result.uint_32 > INT_MAX)
+ goto out_of_bounds;
+ ctx->timeo = result.uint_32;
break;
case Opt_retrans:
- if (nfs_get_option_ui_bound(ctx, args, &ctx->retrans, 0, INT_MAX))
- goto out_invalid_value;
+ if (result.uint_32 > INT_MAX)
+ goto out_of_bounds;
+ ctx->retrans = result.uint_32;
break;
case Opt_acregmin:
- if (nfs_get_option_ui(ctx, args, &ctx->acregmin))
- goto out_invalid_value;
+ ctx->acregmin = result.uint_32;
break;
case Opt_acregmax:
- if (nfs_get_option_ui(ctx, args, &ctx->acregmax))
- goto out_invalid_value;
+ ctx->acregmax = result.uint_32;
break;
case Opt_acdirmin:
- if (nfs_get_option_ui(ctx, args, &ctx->acdirmin))
- goto out_invalid_value;
+ ctx->acdirmin = result.uint_32;
break;
case Opt_acdirmax:
- if (nfs_get_option_ui(ctx, args, &ctx->acdirmax))
- goto out_invalid_value;
+ ctx->acdirmax = result.uint_32;
break;
case Opt_actimeo:
- if (nfs_get_option_ui(ctx, args, &ctx->acdirmax))
- goto out_invalid_value;
- ctx->acregmin = ctx->acregmax =
- ctx->acdirmin = ctx->acdirmax;
+ ctx->acregmin = result.uint_32;
+ ctx->acregmax = result.uint_32;
+ ctx->acdirmin = result.uint_32;
+ ctx->acdirmax = result.uint_32;
break;
case Opt_namelen:
- if (nfs_get_option_ui(ctx, args, &ctx->namlen))
- goto out_invalid_value;
+ ctx->namlen = result.uint_32;
break;
case Opt_mountport:
- if (nfs_get_option_ui_bound(ctx, args, &ctx->mount_server.port,
- 0, USHRT_MAX))
- goto out_invalid_value;
+ if (result.uint_32 > USHRT_MAX)
+ goto out_of_bounds;
+ ctx->mount_server.port = result.uint_32;
break;
case Opt_mountvers:
- if (nfs_get_option_ui_bound(ctx, args, &ctx->mount_server.version,
- NFS_MNT_VERSION, NFS_MNT3_VERSION))
- goto out_invalid_value;
+ if (result.uint_32 < NFS_MNT_VERSION ||
+ result.uint_32 > NFS_MNT3_VERSION)
+ goto out_of_bounds;
+ ctx->mount_server.version = result.uint_32;
break;
case Opt_minorversion:
- if (nfs_get_option_ui_bound(ctx, args, &ctx->minorversion,
- 0, NFS4_MAX_MINOR_VERSION))
- goto out_invalid_value;
+ if (result.uint_32 > NFS4_MAX_MINOR_VERSION)
+ goto out_of_bounds;
+ ctx->minorversion = result.uint_32;
break;
/*
* options that take text values
*/
- case Opt_nfsvers:
- string = match_strdup(args);
- if (string == NULL)
- goto out_nomem;
- ret = nfs_parse_version_string(ctx, string, args);
- kfree(string);
+ case Opt_v:
+ ret = nfs_parse_version_string(ctx, param->key + 1);
+ if (ret < 0)
+ return ret;
+ break;
+ case Opt_vers:
+ ret = nfs_parse_version_string(ctx, param->string);
if (ret < 0)
return ret;
break;
case Opt_sec:
- string = match_strdup(args);
- if (string == NULL)
- goto out_nomem;
- ret = nfs_parse_security_flavors(ctx, string);
- kfree(string);
+ ret = nfs_parse_security_flavors(ctx, param);
if (ret < 0)
return ret;
break;
- case Opt_proto:
- string = match_strdup(args);
- if (string == NULL)
- goto out_nomem;
- token = match_token(string, nfs_xprt_protocol_tokens, args);
- ctx->protofamily = AF_INET;
- switch (token) {
+ case Opt_proto:
+ protofamily = AF_INET;
+ switch (lookup_constant(nfs_xprt_protocol_tokens, param->string, -1)) {
case Opt_xprt_udp6:
- ctx->protofamily = AF_INET6;
+ protofamily = AF_INET6;
/* fall through */
case Opt_xprt_udp:
ctx->flags &= ~NFS_MOUNT_TCP;
ctx->nfs_server.protocol = XPRT_TRANSPORT_UDP;
break;
case Opt_xprt_tcp6:
- ctx->protofamily = AF_INET6;
+ protofamily = AF_INET6;
/* fall through */
case Opt_xprt_tcp:
ctx->flags |= NFS_MOUNT_TCP;
ctx->nfs_server.protocol = XPRT_TRANSPORT_TCP;
break;
case Opt_xprt_rdma6:
- ctx->protofamily = AF_INET6;
+ protofamily = AF_INET6;
/* fall through */
case Opt_xprt_rdma:
/* vector side protocols to TCP */
ctx->flags |= NFS_MOUNT_TCP;
ctx->nfs_server.protocol = XPRT_TRANSPORT_RDMA;
- xprt_load_transport(string);
+ xprt_load_transport(param->string);
break;
default:
- kfree(string);
dfprintk(MOUNT, "NFS: unrecognized transport protocol\n");
return -EINVAL;
}
- kfree(string);
+
+ ctx->protofamily = protofamily;
break;
- case Opt_mountproto:
- string = match_strdup(args);
- if (string == NULL)
- goto out_nomem;
- token = match_token(string, nfs_xprt_protocol_tokens, args);
- kfree(string);
- ctx->mountfamily = AF_INET;
- switch (token) {
+ case Opt_mountproto:
+ mountfamily = AF_INET;
+ switch (lookup_constant(nfs_xprt_protocol_tokens, param->string, -1)) {
case Opt_xprt_udp6:
- ctx->mountfamily = AF_INET6;
+ mountfamily = AF_INET6;
/* fall through */
case Opt_xprt_udp:
ctx->mount_server.protocol = XPRT_TRANSPORT_UDP;
break;
case Opt_xprt_tcp6:
- ctx->mountfamily = AF_INET6;
+ mountfamily = AF_INET6;
/* fall through */
case Opt_xprt_tcp:
ctx->mount_server.protocol = XPRT_TRANSPORT_TCP;
@@ -772,51 +714,42 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
dfprintk(MOUNT, "NFS: unrecognized transport protocol\n");
return -EINVAL;
}
+ ctx->mountfamily = mountfamily;
break;
+
case Opt_addr:
- string = match_strdup(args);
- if (string == NULL)
- goto out_nomem;
- ctx->nfs_server.addrlen =
- rpc_pton(ctx->net, string, strlen(string),
- &ctx->nfs_server.address,
- sizeof(ctx->nfs_server._address));
- kfree(string);
- if (ctx->nfs_server.addrlen == 0)
+ len = rpc_pton(ctx->net, param->string, param->size,
+ &ctx->nfs_server.address,
+ sizeof(ctx->nfs_server._address));
+ if (len == 0)
goto out_invalid_address;
+ ctx->nfs_server.addrlen = len;
break;
case Opt_clientaddr:
- if (nfs_get_option_str(args, &ctx->client_address))
- goto out_nomem;
+ kfree(ctx->client_address);
+ ctx->client_address = param->string;
+ param->string = NULL;
break;
case Opt_mounthost:
- if (nfs_get_option_str(args, &ctx->mount_server.hostname))
- goto out_nomem;
+ kfree(ctx->mount_server.hostname);
+ ctx->mount_server.hostname = param->string;
+ param->string = NULL;
break;
case Opt_mountaddr:
- string = match_strdup(args);
- if (string == NULL)
- goto out_nomem;
- ctx->mount_server.addrlen =
- rpc_pton(ctx->net, string, strlen(string),
- &ctx->mount_server.address,
- sizeof(ctx->mount_server._address));
- kfree(string);
- if (ctx->mount_server.addrlen == 0)
+ len = rpc_pton(ctx->net, param->string, param->size,
+ &ctx->mount_server.address,
+ sizeof(ctx->mount_server._address));
+ if (len == 0)
goto out_invalid_address;
+ ctx->mount_server.addrlen = len;
break;
case Opt_nconnect:
- if (nfs_get_option_us_bound(ctx, args, &ctx->nfs_server.nconnect,
- 1, NFS_MAX_CONNECTIONS))
- goto out_invalid_value;
+ if (result.uint_32 < 1 || result.uint_32 > NFS_MAX_CONNECTIONS)
+ goto out_of_bounds;
+ ctx->nfs_server.nconnect = result.uint_32;
break;
case Opt_lookupcache:
- string = match_strdup(args);
- if (string == NULL)
- goto out_nomem;
- token = match_token(string, nfs_lookupcache_tokens, args);
- kfree(string);
- switch (token) {
+ switch (result.uint_32) {
case Opt_lookupcache_all:
ctx->flags &= ~(NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE);
break;
@@ -828,22 +761,11 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
ctx->flags |= NFS_MOUNT_LOOKUP_CACHE_NONEG|NFS_MOUNT_LOOKUP_CACHE_NONE;
break;
default:
- dfprintk(MOUNT, "NFS: invalid lookupcache argument\n");
- return -EINVAL;
+ goto out_invalid_value;
}
break;
- case Opt_fscache_uniq:
- if (nfs_get_option_str(args, &ctx->fscache_uniq))
- goto out_nomem;
- ctx->options |= NFS_OPTION_FSCACHE;
- break;
case Opt_local_lock:
- string = match_strdup(args);
- if (string == NULL)
- goto out_nomem;
- token = match_token(string, nfs_local_lock_tokens, args);
- kfree(string);
- switch (token) {
+ switch (result.uint_32) {
case Opt_local_lock_all:
ctx->flags |= (NFS_MOUNT_LOCAL_FLOCK |
NFS_MOUNT_LOCAL_FCNTL);
@@ -859,8 +781,7 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
NFS_MOUNT_LOCAL_FCNTL);
break;
default:
- dfprintk(MOUNT, "NFS: invalid local_lock argument\n");
- return -EINVAL;
+ goto out_invalid_value;
}
break;
@@ -868,30 +789,50 @@ static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
* Special options
*/
case Opt_sloppy:
- ctx->sloppy = 1;
+ ctx->sloppy = true;
dfprintk(MOUNT, "NFS: relaxing parsing rules\n");
break;
- case Opt_userspace:
- case Opt_deprecated:
- dfprintk(MOUNT, "NFS: ignoring mount option '%s'\n", p);
- break;
-
- default:
- dfprintk(MOUNT, "NFS: unrecognized mount option '%s'\n", p);
- return -EINVAL;
}
return 0;
-out_invalid_address:
- printk(KERN_INFO "NFS: bad IP address specified: %s\n", p);
- return -EINVAL;
out_invalid_value:
- printk(KERN_INFO "NFS: bad mount option value specified: %s\n", p);
+ printk(KERN_INFO "NFS: Bad mount option value specified\n");
return -EINVAL;
-out_nomem:
- printk(KERN_INFO "NFS: not enough memory to parse option\n");
- return -ENOMEM;
+out_invalid_address:
+ printk(KERN_INFO "NFS: Bad IP address specified\n");
+ return -EINVAL;
+out_of_bounds:
+ printk(KERN_INFO "NFS: Value for '%s' out of range\n", param->key);
+ return -ERANGE;
+}
+
+/* cribbed from generic_parse_monolithic and vfs_parse_fs_string */
+static int nfs_fs_context_parse_option(struct nfs_fs_context *ctx, char *p)
+{
+ int ret;
+ char *key = p, *value;
+ size_t v_size = 0;
+ struct fs_parameter param;
+
+ memset(¶m, 0, sizeof(param));
+ value = strchr(key, '=');
+ if (value && value != key) {
+ *value++ = 0;
+ v_size = strlen(value);
+ }
+ param.key = key;
+ param.type = fs_value_is_flag;
+ param.size = v_size;
+ if (v_size > 0) {
+ param.type = fs_value_is_string;
+ param.string = kmemdup_nul(value, v_size, GFP_KERNEL);
+ if (!param.string)
+ return -ENOMEM;
+ }
+ ret = nfs_fs_context_parse_param(ctx, ¶m);
+ kfree(param.string);
+ return ret;
}
/*
--
2.17.2
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox