Merge 24717cfbbb ("Merge tag 'nfsd-5.10' of git://linux-nfs.org/~bfields/linux") into android-mainline
Steps on the way to 5.10-rc1 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com> Change-Id: I6357a7a9490cf8092ef9769d04906290cb878ce6
This commit is contained in:
@@ -1,70 +0,0 @@
|
||||
===================
|
||||
NFS Fault Injection
|
||||
===================
|
||||
|
||||
Fault injection is a method for forcing errors that may not normally occur, or
|
||||
may be difficult to reproduce. Forcing these errors in a controlled environment
|
||||
can help the developer find and fix bugs before their code is shipped in a
|
||||
production system. Injecting an error on the Linux NFS server will allow us to
|
||||
observe how the client reacts and if it manages to recover its state correctly.
|
||||
|
||||
NFSD_FAULT_INJECTION must be selected when configuring the kernel to use this
|
||||
feature.
|
||||
|
||||
|
||||
Using Fault Injection
|
||||
=====================
|
||||
On the client, mount the fault injection server through NFS v4.0+ and do some
|
||||
work over NFS (open files, take locks, ...).
|
||||
|
||||
On the server, mount the debugfs filesystem to <debug_dir> and ls
|
||||
<debug_dir>/nfsd. This will show a list of files that will be used for
|
||||
injecting faults on the NFS server. As root, write a number n to the file
|
||||
corresponding to the action you want the server to take. The server will then
|
||||
process the first n items it finds. So if you want to forget 5 locks, echo '5'
|
||||
to <debug_dir>/nfsd/forget_locks. A value of 0 will tell the server to forget
|
||||
all corresponding items. A log message will be created containing the number
|
||||
of items forgotten (check dmesg).
|
||||
|
||||
Go back to work on the client and check if the client recovered from the error
|
||||
correctly.
|
||||
|
||||
|
||||
Available Faults
|
||||
================
|
||||
forget_clients:
|
||||
The NFS server keeps a list of clients that have placed a mount call. If
|
||||
this list is cleared, the server will have no knowledge of who the client
|
||||
is, forcing the client to reauthenticate with the server.
|
||||
|
||||
forget_openowners:
|
||||
The NFS server keeps a list of what files are currently opened and who
|
||||
they were opened by. Clearing this list will force the client to reopen
|
||||
its files.
|
||||
|
||||
forget_locks:
|
||||
The NFS server keeps a list of what files are currently locked in the VFS.
|
||||
Clearing this list will force the client to reclaim its locks (files are
|
||||
unlocked through the VFS as they are cleared from this list).
|
||||
|
||||
forget_delegations:
|
||||
A delegation is used to assure the client that a file, or part of a file,
|
||||
has not changed since the delegation was awarded. Clearing this list will
|
||||
force the client to reacquire its delegation before accessing the file
|
||||
again.
|
||||
|
||||
recall_delegations:
|
||||
Delegations can be recalled by the server when another client attempts to
|
||||
access a file. This test will notify the client that its delegation has
|
||||
been revoked, forcing the client to reacquire the delegation before using
|
||||
the file again.
|
||||
|
||||
|
||||
tools/nfs/inject_faults.sh script
|
||||
=================================
|
||||
This script has been created to ease the fault injection process. This script
|
||||
will detect the mounted debugfs directory and write to the files located there
|
||||
based on the arguments passed by the user. For example, running
|
||||
`inject_faults.sh forget_locks 1` as root will instruct the server to forget
|
||||
one lock. Running `inject_faults forget_locks` will instruct the server to
|
||||
forgetall locks.
|
||||
@@ -12,4 +12,3 @@ NFS
|
||||
nfs-idmapper
|
||||
pnfs-block-server
|
||||
pnfs-scsi-server
|
||||
fault_injection
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
|
||||
# Copyright 2020 Toshiba Electronic Devices & Storage Corporation
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: "http://devicetree.org/schemas/watchdog/toshiba,visconti-wdt.yaml#"
|
||||
$schema: "http://devicetree.org/meta-schemas/core.yaml#"
|
||||
|
||||
title: Toshiba Visconti SoCs PIUWDT Watchdog timer
|
||||
|
||||
maintainers:
|
||||
- Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
|
||||
|
||||
allOf:
|
||||
- $ref: watchdog.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- toshiba,visconti-wdt
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
timeout-sec: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- clocks
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
soc {
|
||||
#address-cells = <2>;
|
||||
#size-cells = <2>;
|
||||
|
||||
wdt_clk: wdt-clk {
|
||||
compatible = "fixed-clock";
|
||||
clock-frequency = <150000000>;
|
||||
#clock-cells = <0>;
|
||||
};
|
||||
|
||||
watchdog@28330000 {
|
||||
compatible = "toshiba,visconti-wdt";
|
||||
reg = <0 0x28330000 0 0x1000>;
|
||||
clocks = <&wdt_clk>;
|
||||
timeout-sec = <20>;
|
||||
};
|
||||
};
|
||||
@@ -13,10 +13,9 @@ RPCGSS is specified in a few IETF documents:
|
||||
- RFC2203 v1: https://tools.ietf.org/rfc/rfc2203.txt
|
||||
- RFC5403 v2: https://tools.ietf.org/rfc/rfc5403.txt
|
||||
|
||||
and there is a 3rd version being proposed:
|
||||
There is a third version that we don't currently implement:
|
||||
|
||||
- https://tools.ietf.org/id/draft-williams-rpcsecgssv3.txt
|
||||
(At draft n. 02 at the time of writing)
|
||||
- RFC7861 v3: https://tools.ietf.org/rfc/rfc7861.txt
|
||||
|
||||
Background
|
||||
==========
|
||||
|
||||
@@ -9564,6 +9564,7 @@ F: include/linux/sunrpc/
|
||||
F: include/uapi/linux/nfsd/
|
||||
F: include/uapi/linux/sunrpc/
|
||||
F: net/sunrpc/
|
||||
F: Documentation/filesystems/nfs/
|
||||
|
||||
KERNEL SELFTEST FRAMEWORK
|
||||
M: Shuah Khan <shuah@kernel.org>
|
||||
@@ -12345,6 +12346,7 @@ F: include/linux/sunrpc/
|
||||
F: include/uapi/linux/nfs*
|
||||
F: include/uapi/linux/sunrpc/
|
||||
F: net/sunrpc/
|
||||
F: Documentation/filesystems/nfs/
|
||||
|
||||
NILFS2 FILESYSTEM
|
||||
M: Ryusuke Konishi <konishi.ryusuke@gmail.com>
|
||||
|
||||
@@ -1015,6 +1015,14 @@ config PM8916_WATCHDOG
|
||||
Say Y here to include support watchdog timer embedded into the
|
||||
pm8916 module.
|
||||
|
||||
config VISCONTI_WATCHDOG
|
||||
tristate "Toshiba Visconti series watchdog support"
|
||||
depends on ARCH_VISCONTI || COMPILE_TEST
|
||||
select WATCHDOG_CORE
|
||||
help
|
||||
Say Y here to include support for the watchdog timer in Toshiba
|
||||
Visconti SoCs.
|
||||
|
||||
# X86 (i386 + ia64 + x86_64) Architecture
|
||||
|
||||
config ACQUIRE_WDT
|
||||
|
||||
@@ -95,6 +95,7 @@ obj-$(CONFIG_RTD119X_WATCHDOG) += rtd119x_wdt.o
|
||||
obj-$(CONFIG_SPRD_WATCHDOG) += sprd_wdt.o
|
||||
obj-$(CONFIG_PM8916_WATCHDOG) += pm8916_wdt.o
|
||||
obj-$(CONFIG_ARM_SMC_WATCHDOG) += arm_smc_wdt.o
|
||||
obj-$(CONFIG_VISCONTI_WATCHDOG) += visconti_wdt.o
|
||||
|
||||
# X86 (i386 + ia64 + x86_64) Architecture
|
||||
obj-$(CONFIG_ACQUIRE_WDT) += acquirewdt.o
|
||||
|
||||
@@ -334,12 +334,9 @@ static int cdns_wdt_probe(struct platform_device *pdev)
|
||||
watchdog_set_drvdata(cdns_wdt_device, wdt);
|
||||
|
||||
wdt->clk = devm_clk_get(dev, NULL);
|
||||
if (IS_ERR(wdt->clk)) {
|
||||
ret = PTR_ERR(wdt->clk);
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(dev, "input clock not found\n");
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(wdt->clk))
|
||||
return dev_err_probe(dev, PTR_ERR(wdt->clk),
|
||||
"input clock not found\n");
|
||||
|
||||
ret = clk_prepare_enable(wdt->clk);
|
||||
if (ret) {
|
||||
|
||||
@@ -206,12 +206,9 @@ static int davinci_wdt_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
davinci_wdt->clk = devm_clk_get(dev, NULL);
|
||||
|
||||
if (IS_ERR(davinci_wdt->clk)) {
|
||||
if (PTR_ERR(davinci_wdt->clk) != -EPROBE_DEFER)
|
||||
dev_err(dev, "failed to get clock node\n");
|
||||
return PTR_ERR(davinci_wdt->clk);
|
||||
}
|
||||
if (IS_ERR(davinci_wdt->clk))
|
||||
return dev_err_probe(dev, PTR_ERR(davinci_wdt->clk),
|
||||
"failed to get clock node\n");
|
||||
|
||||
ret = clk_prepare_enable(davinci_wdt->clk);
|
||||
if (ret) {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
@@ -21,6 +22,8 @@
|
||||
#define WDOG_CS_CLK (LPO_CLK << LPO_CLK_SHIFT)
|
||||
#define WDOG_CS_EN BIT(7)
|
||||
#define WDOG_CS_UPDATE BIT(5)
|
||||
#define WDOG_CS_WAIT BIT(1)
|
||||
#define WDOG_CS_STOP BIT(0)
|
||||
|
||||
#define WDOG_CNT 0x4
|
||||
#define WDOG_TOVAL 0x8
|
||||
@@ -36,6 +39,7 @@
|
||||
#define DEFAULT_TIMEOUT 60
|
||||
#define MAX_TIMEOUT 128
|
||||
#define WDOG_CLOCK_RATE 1000
|
||||
#define WDOG_WAIT_TIMEOUT 20
|
||||
|
||||
static bool nowayout = WATCHDOG_NOWAYOUT;
|
||||
module_param(nowayout, bool, 0000);
|
||||
@@ -48,17 +52,40 @@ struct imx7ulp_wdt_device {
|
||||
struct clk *clk;
|
||||
};
|
||||
|
||||
static void imx7ulp_wdt_enable(struct watchdog_device *wdog, bool enable)
|
||||
static int imx7ulp_wdt_wait(void __iomem *base, u32 mask)
|
||||
{
|
||||
u32 val = readl(base + WDOG_CS);
|
||||
|
||||
if (!(val & mask) && readl_poll_timeout_atomic(base + WDOG_CS, val,
|
||||
val & mask, 0,
|
||||
WDOG_WAIT_TIMEOUT))
|
||||
return -ETIMEDOUT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx7ulp_wdt_enable(struct watchdog_device *wdog, bool enable)
|
||||
{
|
||||
struct imx7ulp_wdt_device *wdt = watchdog_get_drvdata(wdog);
|
||||
|
||||
u32 val = readl(wdt->base + WDOG_CS);
|
||||
int ret;
|
||||
|
||||
local_irq_disable();
|
||||
writel(UNLOCK, wdt->base + WDOG_CNT);
|
||||
ret = imx7ulp_wdt_wait(wdt->base, WDOG_CS_ULK);
|
||||
if (ret)
|
||||
goto enable_out;
|
||||
if (enable)
|
||||
writel(val | WDOG_CS_EN, wdt->base + WDOG_CS);
|
||||
else
|
||||
writel(val & ~WDOG_CS_EN, wdt->base + WDOG_CS);
|
||||
imx7ulp_wdt_wait(wdt->base, WDOG_CS_RCS);
|
||||
|
||||
enable_out:
|
||||
local_irq_enable();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool imx7ulp_wdt_is_enabled(void __iomem *base)
|
||||
@@ -79,17 +106,12 @@ static int imx7ulp_wdt_ping(struct watchdog_device *wdog)
|
||||
|
||||
static int imx7ulp_wdt_start(struct watchdog_device *wdog)
|
||||
{
|
||||
|
||||
imx7ulp_wdt_enable(wdog, true);
|
||||
|
||||
return 0;
|
||||
return imx7ulp_wdt_enable(wdog, true);
|
||||
}
|
||||
|
||||
static int imx7ulp_wdt_stop(struct watchdog_device *wdog)
|
||||
{
|
||||
imx7ulp_wdt_enable(wdog, false);
|
||||
|
||||
return 0;
|
||||
return imx7ulp_wdt_enable(wdog, false);
|
||||
}
|
||||
|
||||
static int imx7ulp_wdt_set_timeout(struct watchdog_device *wdog,
|
||||
@@ -97,22 +119,37 @@ static int imx7ulp_wdt_set_timeout(struct watchdog_device *wdog,
|
||||
{
|
||||
struct imx7ulp_wdt_device *wdt = watchdog_get_drvdata(wdog);
|
||||
u32 val = WDOG_CLOCK_RATE * timeout;
|
||||
int ret;
|
||||
|
||||
local_irq_disable();
|
||||
writel(UNLOCK, wdt->base + WDOG_CNT);
|
||||
ret = imx7ulp_wdt_wait(wdt->base, WDOG_CS_ULK);
|
||||
if (ret)
|
||||
goto timeout_out;
|
||||
writel(val, wdt->base + WDOG_TOVAL);
|
||||
imx7ulp_wdt_wait(wdt->base, WDOG_CS_RCS);
|
||||
|
||||
wdog->timeout = timeout;
|
||||
|
||||
return 0;
|
||||
timeout_out:
|
||||
local_irq_enable();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int imx7ulp_wdt_restart(struct watchdog_device *wdog,
|
||||
unsigned long action, void *data)
|
||||
{
|
||||
struct imx7ulp_wdt_device *wdt = watchdog_get_drvdata(wdog);
|
||||
int ret;
|
||||
|
||||
imx7ulp_wdt_enable(wdog, true);
|
||||
imx7ulp_wdt_set_timeout(&wdt->wdd, 1);
|
||||
ret = imx7ulp_wdt_enable(wdog, true);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = imx7ulp_wdt_set_timeout(&wdt->wdd, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* wait for wdog to fire */
|
||||
while (true)
|
||||
@@ -136,19 +173,31 @@ static const struct watchdog_info imx7ulp_wdt_info = {
|
||||
WDIOF_MAGICCLOSE,
|
||||
};
|
||||
|
||||
static void imx7ulp_wdt_init(void __iomem *base, unsigned int timeout)
|
||||
static int imx7ulp_wdt_init(void __iomem *base, unsigned int timeout)
|
||||
{
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
local_irq_disable();
|
||||
/* unlock the wdog for reconfiguration */
|
||||
writel_relaxed(UNLOCK_SEQ0, base + WDOG_CNT);
|
||||
writel_relaxed(UNLOCK_SEQ1, base + WDOG_CNT);
|
||||
ret = imx7ulp_wdt_wait(base, WDOG_CS_ULK);
|
||||
if (ret)
|
||||
goto init_out;
|
||||
|
||||
/* set an initial timeout value in TOVAL */
|
||||
writel(timeout, base + WDOG_TOVAL);
|
||||
/* enable 32bit command sequence and reconfigure */
|
||||
val = WDOG_CS_CMD32EN | WDOG_CS_CLK | WDOG_CS_UPDATE;
|
||||
val = WDOG_CS_CMD32EN | WDOG_CS_CLK | WDOG_CS_UPDATE |
|
||||
WDOG_CS_WAIT | WDOG_CS_STOP;
|
||||
writel(val, base + WDOG_CS);
|
||||
imx7ulp_wdt_wait(base, WDOG_CS_RCS);
|
||||
|
||||
init_out:
|
||||
local_irq_enable();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void imx7ulp_wdt_action(void *data)
|
||||
@@ -199,7 +248,9 @@ static int imx7ulp_wdt_probe(struct platform_device *pdev)
|
||||
watchdog_stop_on_reboot(wdog);
|
||||
watchdog_stop_on_unregister(wdog);
|
||||
watchdog_set_drvdata(wdog, imx7ulp_wdt);
|
||||
imx7ulp_wdt_init(imx7ulp_wdt->base, wdog->timeout * WDOG_CLOCK_RATE);
|
||||
ret = imx7ulp_wdt_init(imx7ulp_wdt->base, wdog->timeout * WDOG_CLOCK_RATE);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_watchdog_register_device(dev, wdog);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
* Support of the watchdog timers, which are available on
|
||||
* IT8607, IT8620, IT8622, IT8625, IT8628, IT8655, IT8665, IT8686,
|
||||
* IT8702, IT8712, IT8716, IT8718, IT8720, IT8721, IT8726, IT8728,
|
||||
* and IT8783.
|
||||
* IT8772, IT8783 and IT8784.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
@@ -66,7 +66,9 @@
|
||||
#define IT8721_ID 0x8721
|
||||
#define IT8726_ID 0x8726 /* the data sheet suggest wrongly 0x8716 */
|
||||
#define IT8728_ID 0x8728
|
||||
#define IT8772_ID 0x8772
|
||||
#define IT8783_ID 0x8783
|
||||
#define IT8784_ID 0x8784
|
||||
#define IT8786_ID 0x8786
|
||||
|
||||
/* GPIO Configuration Registers LDN=0x07 */
|
||||
@@ -294,7 +296,9 @@ static int __init it87_wdt_init(void)
|
||||
case IT8720_ID:
|
||||
case IT8721_ID:
|
||||
case IT8728_ID:
|
||||
case IT8772_ID:
|
||||
case IT8783_ID:
|
||||
case IT8784_ID:
|
||||
case IT8786_ID:
|
||||
max_units = 65535;
|
||||
break;
|
||||
|
||||
@@ -656,7 +656,7 @@ static int usb_pcwd_probe(struct usb_interface *interface,
|
||||
|
||||
/* set up the memory buffer's */
|
||||
usb_pcwd->intr_buffer = usb_alloc_coherent(udev, usb_pcwd->intr_size,
|
||||
GFP_ATOMIC, &usb_pcwd->intr_dma);
|
||||
GFP_KERNEL, &usb_pcwd->intr_dma);
|
||||
if (!usb_pcwd->intr_buffer) {
|
||||
pr_err("Out of memory\n");
|
||||
goto error;
|
||||
|
||||
@@ -231,6 +231,8 @@ static int rdc321x_wdt_probe(struct platform_device *pdev)
|
||||
|
||||
rdc321x_wdt_device.sb_pdev = pdata->sb_pdev;
|
||||
rdc321x_wdt_device.base_reg = r->start;
|
||||
rdc321x_wdt_device.queue = 0;
|
||||
rdc321x_wdt_device.default_ticks = ticks;
|
||||
|
||||
err = misc_register(&rdc321x_wdt_misc);
|
||||
if (err < 0) {
|
||||
@@ -245,14 +247,11 @@ static int rdc321x_wdt_probe(struct platform_device *pdev)
|
||||
rdc321x_wdt_device.base_reg, RDC_WDT_RST);
|
||||
|
||||
init_completion(&rdc321x_wdt_device.stop);
|
||||
rdc321x_wdt_device.queue = 0;
|
||||
|
||||
clear_bit(0, &rdc321x_wdt_device.inuse);
|
||||
|
||||
timer_setup(&rdc321x_wdt_device.timer, rdc321x_wdt_trigger, 0);
|
||||
|
||||
rdc321x_wdt_device.default_ticks = ticks;
|
||||
|
||||
dev_info(&pdev->dev, "watchdog init success\n");
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -194,6 +194,7 @@ static int rwdt_probe(struct platform_device *pdev)
|
||||
struct clk *clk;
|
||||
unsigned long clks_per_sec;
|
||||
int ret, i;
|
||||
u8 csra;
|
||||
|
||||
if (rwdt_blacklisted(dev))
|
||||
return -ENODEV;
|
||||
@@ -213,8 +214,8 @@ static int rwdt_probe(struct platform_device *pdev)
|
||||
pm_runtime_enable(dev);
|
||||
pm_runtime_get_sync(dev);
|
||||
priv->clk_rate = clk_get_rate(clk);
|
||||
priv->wdev.bootstatus = (readb_relaxed(priv->base + RWTCSRA) &
|
||||
RWTCSRA_WOVF) ? WDIOF_CARDRESET : 0;
|
||||
csra = readb_relaxed(priv->base + RWTCSRA);
|
||||
priv->wdev.bootstatus = csra & RWTCSRA_WOVF ? WDIOF_CARDRESET : 0;
|
||||
pm_runtime_put(dev);
|
||||
|
||||
if (!priv->clk_rate) {
|
||||
@@ -252,6 +253,13 @@ static int rwdt_probe(struct platform_device *pdev)
|
||||
/* This overrides the default timeout only if DT configuration was found */
|
||||
watchdog_init_timeout(&priv->wdev, 0, dev);
|
||||
|
||||
/* Check if FW enabled the watchdog */
|
||||
if (csra & RWTCSRA_TME) {
|
||||
/* Ensure properly initialized dividers */
|
||||
rwdt_start(&priv->wdev);
|
||||
set_bit(WDOG_HW_RUNNING, &priv->wdev.status);
|
||||
}
|
||||
|
||||
ret = watchdog_register_device(&priv->wdev);
|
||||
if (ret < 0)
|
||||
goto out_pm_disable;
|
||||
|
||||
@@ -205,11 +205,8 @@ static int rti_wdt_probe(struct platform_device *pdev)
|
||||
return -ENOMEM;
|
||||
|
||||
clk = clk_get(dev, NULL);
|
||||
if (IS_ERR(clk)) {
|
||||
if (PTR_ERR(clk) != -EPROBE_DEFER)
|
||||
dev_err(dev, "failed to get clock\n");
|
||||
return PTR_ERR(clk);
|
||||
}
|
||||
if (IS_ERR(clk))
|
||||
return dev_err_probe(dev, PTR_ERR(clk), "failed to get clock\n");
|
||||
|
||||
wdt->freq = clk_get_rate(clk);
|
||||
|
||||
@@ -230,11 +227,8 @@ static int rti_wdt_probe(struct platform_device *pdev)
|
||||
|
||||
pm_runtime_enable(dev);
|
||||
ret = pm_runtime_get_sync(dev);
|
||||
if (ret) {
|
||||
if (ret != -EPROBE_DEFER)
|
||||
dev_err(&pdev->dev, "runtime pm failed\n");
|
||||
return ret;
|
||||
}
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "runtime pm failed\n");
|
||||
|
||||
platform_set_drvdata(pdev, wdt);
|
||||
|
||||
|
||||
@@ -17,6 +17,12 @@
|
||||
* AMD Publication 51192 "AMD Bolton FCH Register Reference Guide"
|
||||
* AMD Publication 52740 "BIOS and Kernel Developer’s Guide (BKDG)
|
||||
* for AMD Family 16h Models 30h-3Fh Processors"
|
||||
* AMD Publication 55570-B1-PUB "Processor Programming Reference (PPR)
|
||||
* for AMD Family 17h Model 18h, Revision B1
|
||||
* Processors (PUB)
|
||||
* AMD Publication 55772-A1-PUB "Processor Programming Reference (PPR)
|
||||
* for AMD Family 17h Model 20h, Revision A1
|
||||
* Processors (PUB)
|
||||
*/
|
||||
|
||||
/*
|
||||
@@ -241,6 +247,18 @@ static int sp5100_tco_setupdevice(struct device *dev,
|
||||
break;
|
||||
case efch:
|
||||
dev_name = SB800_DEVNAME;
|
||||
/*
|
||||
* On Family 17h devices, the EFCH_PM_DECODEEN_WDT_TMREN bit of
|
||||
* EFCH_PM_DECODEEN not only enables the EFCH_PM_WDT_ADDR memory
|
||||
* region, it also enables the watchdog itself.
|
||||
*/
|
||||
if (boot_cpu_data.x86 == 0x17) {
|
||||
val = sp5100_tco_read_pm_reg8(EFCH_PM_DECODEEN);
|
||||
if (!(val & EFCH_PM_DECODEEN_WDT_TMREN)) {
|
||||
sp5100_tco_update_pm_reg8(EFCH_PM_DECODEEN, 0xff,
|
||||
EFCH_PM_DECODEEN_WDT_TMREN);
|
||||
}
|
||||
}
|
||||
val = sp5100_tco_read_pm_reg8(EFCH_PM_DECODEEN);
|
||||
if (val & EFCH_PM_DECODEEN_WDT_TMREN)
|
||||
mmio_addr = EFCH_PM_WDT_ADDR;
|
||||
|
||||
@@ -70,7 +70,7 @@
|
||||
#define EFCH_PM_DECODEEN_WDT_TMREN BIT(7)
|
||||
|
||||
|
||||
#define EFCH_PM_DECODEEN3 0x00
|
||||
#define EFCH_PM_DECODEEN3 0x03
|
||||
#define EFCH_PM_DECODEEN_SECOND_RES GENMASK(1, 0)
|
||||
#define EFCH_PM_WATCHDOG_DISABLE ((u8)GENMASK(3, 2))
|
||||
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2020 TOSHIBA CORPORATION
|
||||
* Copyright (c) 2020 Toshiba Electronic Devices & Storage Corporation
|
||||
* Copyright (c) 2020 Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/watchdog.h>
|
||||
|
||||
#define WDT_CNT 0x00
|
||||
#define WDT_MIN 0x04
|
||||
#define WDT_MAX 0x08
|
||||
#define WDT_CTL 0x0c
|
||||
#define WDT_CMD 0x10
|
||||
#define WDT_CMD_CLEAR 0x4352
|
||||
#define WDT_CMD_START_STOP 0x5354
|
||||
#define WDT_DIV 0x30
|
||||
|
||||
#define VISCONTI_WDT_FREQ 2000000 /* 2MHz */
|
||||
#define WDT_DEFAULT_TIMEOUT 10U /* in seconds */
|
||||
|
||||
static bool nowayout = WATCHDOG_NOWAYOUT;
|
||||
module_param(nowayout, bool, 0);
|
||||
MODULE_PARM_DESC(
|
||||
nowayout,
|
||||
"Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT)")");
|
||||
|
||||
struct visconti_wdt_priv {
|
||||
struct watchdog_device wdev;
|
||||
void __iomem *base;
|
||||
u32 div;
|
||||
};
|
||||
|
||||
static int visconti_wdt_start(struct watchdog_device *wdev)
|
||||
{
|
||||
struct visconti_wdt_priv *priv = watchdog_get_drvdata(wdev);
|
||||
u32 timeout = wdev->timeout * VISCONTI_WDT_FREQ;
|
||||
|
||||
writel(priv->div, priv->base + WDT_DIV);
|
||||
writel(0, priv->base + WDT_MIN);
|
||||
writel(timeout, priv->base + WDT_MAX);
|
||||
writel(0, priv->base + WDT_CTL);
|
||||
writel(WDT_CMD_START_STOP, priv->base + WDT_CMD);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int visconti_wdt_stop(struct watchdog_device *wdev)
|
||||
{
|
||||
struct visconti_wdt_priv *priv = watchdog_get_drvdata(wdev);
|
||||
|
||||
writel(1, priv->base + WDT_CTL);
|
||||
writel(WDT_CMD_START_STOP, priv->base + WDT_CMD);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int visconti_wdt_ping(struct watchdog_device *wdd)
|
||||
{
|
||||
struct visconti_wdt_priv *priv = watchdog_get_drvdata(wdd);
|
||||
|
||||
writel(WDT_CMD_CLEAR, priv->base + WDT_CMD);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int visconti_wdt_get_timeleft(struct watchdog_device *wdev)
|
||||
{
|
||||
struct visconti_wdt_priv *priv = watchdog_get_drvdata(wdev);
|
||||
u32 timeout = wdev->timeout * VISCONTI_WDT_FREQ;
|
||||
u32 cnt = readl(priv->base + WDT_CNT);
|
||||
|
||||
if (timeout <= cnt)
|
||||
return 0;
|
||||
timeout -= cnt;
|
||||
|
||||
return timeout / VISCONTI_WDT_FREQ;
|
||||
}
|
||||
|
||||
static int visconti_wdt_set_timeout(struct watchdog_device *wdev, unsigned int timeout)
|
||||
{
|
||||
u32 val;
|
||||
struct visconti_wdt_priv *priv = watchdog_get_drvdata(wdev);
|
||||
|
||||
wdev->timeout = timeout;
|
||||
val = wdev->timeout * VISCONTI_WDT_FREQ;
|
||||
|
||||
/* Clear counter before setting timeout because WDT expires */
|
||||
writel(WDT_CMD_CLEAR, priv->base + WDT_CMD);
|
||||
writel(val, priv->base + WDT_MAX);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct watchdog_info visconti_wdt_info = {
|
||||
.options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
|
||||
.identity = "Visconti Watchdog",
|
||||
};
|
||||
|
||||
static const struct watchdog_ops visconti_wdt_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.start = visconti_wdt_start,
|
||||
.stop = visconti_wdt_stop,
|
||||
.ping = visconti_wdt_ping,
|
||||
.get_timeleft = visconti_wdt_get_timeleft,
|
||||
.set_timeout = visconti_wdt_set_timeout,
|
||||
};
|
||||
|
||||
static void visconti_clk_disable_unprepare(void *data)
|
||||
{
|
||||
clk_disable_unprepare(data);
|
||||
}
|
||||
|
||||
static int visconti_wdt_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct watchdog_device *wdev;
|
||||
struct visconti_wdt_priv *priv;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct clk *clk;
|
||||
int ret;
|
||||
unsigned long clk_freq;
|
||||
|
||||
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
priv->base = devm_platform_ioremap_resource(pdev, 0);
|
||||
if (IS_ERR(priv->base))
|
||||
return PTR_ERR(priv->base);
|
||||
|
||||
clk = devm_clk_get(dev, NULL);
|
||||
if (IS_ERR(clk))
|
||||
return dev_err_probe(dev, PTR_ERR(clk), "Could not get clock\n");
|
||||
|
||||
ret = clk_prepare_enable(clk);
|
||||
if (ret) {
|
||||
dev_err(dev, "Could not enable clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = devm_add_action_or_reset(dev, visconti_clk_disable_unprepare, clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
clk_freq = clk_get_rate(clk);
|
||||
if (!clk_freq)
|
||||
return -EINVAL;
|
||||
|
||||
priv->div = clk_freq / VISCONTI_WDT_FREQ;
|
||||
|
||||
/* Initialize struct watchdog_device. */
|
||||
wdev = &priv->wdev;
|
||||
wdev->info = &visconti_wdt_info;
|
||||
wdev->ops = &visconti_wdt_ops;
|
||||
wdev->parent = dev;
|
||||
wdev->min_timeout = 1;
|
||||
wdev->max_timeout = 0xffffffff / VISCONTI_WDT_FREQ;
|
||||
wdev->timeout = min(wdev->max_timeout, WDT_DEFAULT_TIMEOUT);
|
||||
|
||||
watchdog_set_drvdata(wdev, priv);
|
||||
watchdog_set_nowayout(wdev, nowayout);
|
||||
watchdog_stop_on_unregister(wdev);
|
||||
|
||||
/* This overrides the default timeout only if DT configuration was found */
|
||||
ret = watchdog_init_timeout(wdev, 0, dev);
|
||||
if (ret)
|
||||
dev_warn(dev, "Specified timeout value invalid, using default\n");
|
||||
|
||||
return devm_watchdog_register_device(dev, wdev);
|
||||
}
|
||||
|
||||
static const struct of_device_id visconti_wdt_of_match[] = {
|
||||
{ .compatible = "toshiba,visconti-wdt", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, visconti_wdt_of_match);
|
||||
|
||||
static struct platform_driver visconti_wdt_driver = {
|
||||
.driver = {
|
||||
.name = "visconti_wdt",
|
||||
.of_match_table = visconti_wdt_of_match,
|
||||
},
|
||||
.probe = visconti_wdt_probe,
|
||||
};
|
||||
module_platform_driver(visconti_wdt_driver);
|
||||
|
||||
MODULE_DESCRIPTION("TOSHIBA Visconti Watchdog Driver");
|
||||
MODULE_AUTHOR("Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@@ -43,8 +43,6 @@
|
||||
#include <linux/watchdog.h> /* For watchdog specific items */
|
||||
#include <linux/uaccess.h> /* For copy_to_user/put_user/... */
|
||||
|
||||
#include <uapi/linux/sched/types.h> /* For struct sched_param */
|
||||
|
||||
#include "watchdog_core.h"
|
||||
#include "watchdog_pretimeout.h"
|
||||
|
||||
@@ -994,8 +992,10 @@ static int watchdog_cdev_register(struct watchdog_device *wdd)
|
||||
wd_data->wdd = wdd;
|
||||
wdd->wd_data = wd_data;
|
||||
|
||||
if (IS_ERR_OR_NULL(watchdog_kworker))
|
||||
if (IS_ERR_OR_NULL(watchdog_kworker)) {
|
||||
kfree(wd_data);
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
device_initialize(&wd_data->dev);
|
||||
wd_data->dev.devt = MKDEV(MAJOR(watchdog_devt), wdd->id);
|
||||
@@ -1021,7 +1021,7 @@ static int watchdog_cdev_register(struct watchdog_device *wdd)
|
||||
pr_err("%s: a legacy watchdog module is probably present.\n",
|
||||
wdd->info->identity);
|
||||
old_wd_data = NULL;
|
||||
kfree(wd_data);
|
||||
put_device(&wd_data->dev);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -612,9 +612,9 @@ static void v9fs_mmap_vm_close(struct vm_area_struct *vma)
|
||||
struct writeback_control wbc = {
|
||||
.nr_to_write = LONG_MAX,
|
||||
.sync_mode = WB_SYNC_ALL,
|
||||
.range_start = vma->vm_pgoff * PAGE_SIZE,
|
||||
.range_start = (loff_t)vma->vm_pgoff * PAGE_SIZE,
|
||||
/* absolute end, byte at end included */
|
||||
.range_end = vma->vm_pgoff * PAGE_SIZE +
|
||||
.range_end = (loff_t)vma->vm_pgoff * PAGE_SIZE +
|
||||
(vma->vm_end - vma->vm_start - 1),
|
||||
};
|
||||
|
||||
|
||||
+11
-18
@@ -59,9 +59,9 @@ static void exfat_get_uniname_from_ext_entry(struct super_block *sb,
|
||||
}
|
||||
|
||||
/* read a directory entry from the opened directory */
|
||||
static int exfat_readdir(struct inode *inode, struct exfat_dir_entry *dir_entry)
|
||||
static int exfat_readdir(struct inode *inode, loff_t *cpos, struct exfat_dir_entry *dir_entry)
|
||||
{
|
||||
int i, dentries_per_clu, dentries_per_clu_bits = 0;
|
||||
int i, dentries_per_clu, dentries_per_clu_bits = 0, num_ext;
|
||||
unsigned int type, clu_offset;
|
||||
sector_t sector;
|
||||
struct exfat_chain dir, clu;
|
||||
@@ -70,7 +70,7 @@ static int exfat_readdir(struct inode *inode, struct exfat_dir_entry *dir_entry)
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct exfat_sb_info *sbi = EXFAT_SB(sb);
|
||||
struct exfat_inode_info *ei = EXFAT_I(inode);
|
||||
unsigned int dentry = ei->rwoffset & 0xFFFFFFFF;
|
||||
unsigned int dentry = EXFAT_B_TO_DEN(*cpos) & 0xFFFFFFFF;
|
||||
struct buffer_head *bh;
|
||||
|
||||
/* check if the given file ID is opened */
|
||||
@@ -127,6 +127,7 @@ static int exfat_readdir(struct inode *inode, struct exfat_dir_entry *dir_entry)
|
||||
continue;
|
||||
}
|
||||
|
||||
num_ext = ep->dentry.file.num_ext;
|
||||
dir_entry->attr = le16_to_cpu(ep->dentry.file.attr);
|
||||
exfat_get_entry_time(sbi, &dir_entry->crtime,
|
||||
ep->dentry.file.create_tz,
|
||||
@@ -157,12 +158,13 @@ static int exfat_readdir(struct inode *inode, struct exfat_dir_entry *dir_entry)
|
||||
return -EIO;
|
||||
dir_entry->size =
|
||||
le64_to_cpu(ep->dentry.stream.valid_size);
|
||||
dir_entry->entry = dentry;
|
||||
brelse(bh);
|
||||
|
||||
ei->hint_bmap.off = dentry >> dentries_per_clu_bits;
|
||||
ei->hint_bmap.clu = clu.dir;
|
||||
|
||||
ei->rwoffset = ++dentry;
|
||||
*cpos = EXFAT_DEN_TO_B(dentry + 1 + num_ext);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -178,7 +180,7 @@ static int exfat_readdir(struct inode *inode, struct exfat_dir_entry *dir_entry)
|
||||
}
|
||||
|
||||
dir_entry->namebuf.lfn[0] = '\0';
|
||||
ei->rwoffset = dentry;
|
||||
*cpos = EXFAT_DEN_TO_B(dentry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -242,12 +244,10 @@ static int exfat_iterate(struct file *filp, struct dir_context *ctx)
|
||||
if (err)
|
||||
goto unlock;
|
||||
get_new:
|
||||
ei->rwoffset = EXFAT_B_TO_DEN(cpos);
|
||||
|
||||
if (cpos >= i_size_read(inode))
|
||||
goto end_of_dir;
|
||||
|
||||
err = exfat_readdir(inode, &de);
|
||||
err = exfat_readdir(inode, &cpos, &de);
|
||||
if (err) {
|
||||
/*
|
||||
* At least we tried to read a sector. Move cpos to next sector
|
||||
@@ -262,13 +262,10 @@ get_new:
|
||||
goto end_of_dir;
|
||||
}
|
||||
|
||||
cpos = EXFAT_DEN_TO_B(ei->rwoffset);
|
||||
|
||||
if (!nb->lfn[0])
|
||||
goto end_of_dir;
|
||||
|
||||
i_pos = ((loff_t)ei->start_clu << 32) |
|
||||
((ei->rwoffset - 1) & 0xffffffff);
|
||||
i_pos = ((loff_t)ei->start_clu << 32) | (de.entry & 0xffffffff);
|
||||
tmp = exfat_iget(sb, i_pos);
|
||||
if (tmp) {
|
||||
inum = tmp->i_ino;
|
||||
@@ -911,7 +908,6 @@ enum {
|
||||
/*
|
||||
* return values:
|
||||
* >= 0 : return dir entiry position with the name in dir
|
||||
* -EEXIST : (root dir, ".") it is the root dir itself
|
||||
* -ENOENT : entry with the name does not exist
|
||||
* -EIO : I/O error
|
||||
*/
|
||||
@@ -979,11 +975,8 @@ rewind:
|
||||
if (ei->hint_femp.eidx ==
|
||||
EXFAT_HINT_NONE ||
|
||||
candi_empty.eidx <=
|
||||
ei->hint_femp.eidx) {
|
||||
memcpy(&ei->hint_femp,
|
||||
&candi_empty,
|
||||
sizeof(candi_empty));
|
||||
}
|
||||
ei->hint_femp.eidx)
|
||||
ei->hint_femp = candi_empty;
|
||||
}
|
||||
|
||||
brelse(bh);
|
||||
|
||||
+1
-3
@@ -128,7 +128,7 @@ enum {
|
||||
|
||||
struct exfat_dentry_namebuf {
|
||||
char *lfn;
|
||||
int lfnbuf_len; /* usally MAX_UNINAME_BUF_SIZE */
|
||||
int lfnbuf_len; /* usually MAX_UNINAME_BUF_SIZE */
|
||||
};
|
||||
|
||||
/* unicode name structure */
|
||||
@@ -265,8 +265,6 @@ struct exfat_inode_info {
|
||||
* the validation of hint_stat.
|
||||
*/
|
||||
unsigned int version;
|
||||
/* file offset or dentry index for readdir */
|
||||
loff_t rwoffset;
|
||||
|
||||
/* hint for cluster last accessed */
|
||||
struct exfat_hint hint_bmap;
|
||||
|
||||
+1
-3
@@ -208,8 +208,6 @@ int __exfat_truncate(struct inode *inode, loff_t new_size)
|
||||
/* hint information */
|
||||
ei->hint_bmap.off = EXFAT_EOF_CLUSTER;
|
||||
ei->hint_bmap.clu = EXFAT_EOF_CLUSTER;
|
||||
if (ei->rwoffset > new_size)
|
||||
ei->rwoffset = new_size;
|
||||
|
||||
/* hint_stat will be used if this is directory. */
|
||||
ei->hint_stat.eidx = 0;
|
||||
@@ -229,7 +227,7 @@ void exfat_truncate(struct inode *inode, loff_t size)
|
||||
{
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct exfat_sb_info *sbi = EXFAT_SB(sb);
|
||||
unsigned int blocksize = 1 << inode->i_blkbits;
|
||||
unsigned int blocksize = i_blocksize(inode);
|
||||
loff_t aligned_size;
|
||||
int err;
|
||||
|
||||
|
||||
+1
-4
@@ -114,8 +114,6 @@ static int exfat_map_cluster(struct inode *inode, unsigned int clu_offset,
|
||||
unsigned int local_clu_offset = clu_offset;
|
||||
unsigned int num_to_be_allocated = 0, num_clusters = 0;
|
||||
|
||||
ei->rwoffset = EXFAT_CLU_TO_B(clu_offset, sbi);
|
||||
|
||||
if (EXFAT_I(inode)->i_size_ondisk > 0)
|
||||
num_clusters =
|
||||
EXFAT_B_TO_CLU_ROUND_UP(EXFAT_I(inode)->i_size_ondisk,
|
||||
@@ -556,7 +554,7 @@ static int exfat_fill_inode(struct inode *inode, struct exfat_dir_entry *info)
|
||||
struct exfat_inode_info *ei = EXFAT_I(inode);
|
||||
loff_t size = info->size;
|
||||
|
||||
memcpy(&ei->dir, &info->dir, sizeof(struct exfat_chain));
|
||||
ei->dir = info->dir;
|
||||
ei->entry = info->entry;
|
||||
ei->attr = info->attr;
|
||||
ei->start_clu = info->start_clu;
|
||||
@@ -567,7 +565,6 @@ static int exfat_fill_inode(struct inode *inode, struct exfat_dir_entry *info)
|
||||
ei->hint_stat.eidx = 0;
|
||||
ei->hint_stat.clu = info->start_clu;
|
||||
ei->hint_femp.eidx = EXFAT_HINT_NONE;
|
||||
ei->rwoffset = 0;
|
||||
ei->hint_bmap.off = EXFAT_EOF_CLUSTER;
|
||||
ei->i_pos = 0;
|
||||
|
||||
|
||||
+55
-96
@@ -290,7 +290,7 @@ static int exfat_check_max_dentries(struct inode *inode)
|
||||
{
|
||||
if (EXFAT_B_TO_DEN(i_size_read(inode)) >= MAX_EXFAT_DENTRIES) {
|
||||
/*
|
||||
* exFAT spec allows a dir to grow upto 8388608(256MB)
|
||||
* exFAT spec allows a dir to grow up to 8388608(256MB)
|
||||
* dentries
|
||||
*/
|
||||
return -ENOSPC;
|
||||
@@ -318,8 +318,7 @@ static int exfat_find_empty_entry(struct inode *inode,
|
||||
hint_femp.eidx = EXFAT_HINT_NONE;
|
||||
|
||||
if (ei->hint_femp.eidx != EXFAT_HINT_NONE) {
|
||||
memcpy(&hint_femp, &ei->hint_femp,
|
||||
sizeof(struct exfat_hint_femp));
|
||||
hint_femp = ei->hint_femp;
|
||||
ei->hint_femp.eidx = EXFAT_HINT_NONE;
|
||||
}
|
||||
|
||||
@@ -519,7 +518,7 @@ static int exfat_add_entry(struct inode *inode, const char *path,
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
memcpy(&info->dir, p_dir, sizeof(struct exfat_chain));
|
||||
info->dir = *p_dir;
|
||||
info->entry = dentry;
|
||||
info->flags = ALLOC_NO_FAT_CHAIN;
|
||||
info->type = type;
|
||||
@@ -530,19 +529,10 @@ static int exfat_add_entry(struct inode *inode, const char *path,
|
||||
info->size = 0;
|
||||
info->num_subdirs = 0;
|
||||
} else {
|
||||
int count;
|
||||
struct exfat_chain cdir;
|
||||
|
||||
info->attr = ATTR_SUBDIR;
|
||||
info->start_clu = start_clu;
|
||||
info->size = clu_size;
|
||||
|
||||
exfat_chain_set(&cdir, info->start_clu,
|
||||
EXFAT_B_TO_CLU(info->size, sbi), info->flags);
|
||||
count = exfat_count_dir_entries(sb, &cdir);
|
||||
if (count < 0)
|
||||
return -EIO;
|
||||
info->num_subdirs = count + EXFAT_MIN_SUBDIR;
|
||||
info->num_subdirs = EXFAT_MIN_SUBDIR;
|
||||
}
|
||||
memset(&info->crtime, 0, sizeof(info->crtime));
|
||||
memset(&info->mtime, 0, sizeof(info->mtime));
|
||||
@@ -604,6 +594,8 @@ static int exfat_find(struct inode *dir, struct qstr *qname,
|
||||
struct super_block *sb = dir->i_sb;
|
||||
struct exfat_sb_info *sbi = EXFAT_SB(sb);
|
||||
struct exfat_inode_info *ei = EXFAT_I(dir);
|
||||
struct exfat_dentry *ep, *ep2;
|
||||
struct exfat_entry_set_cache *es;
|
||||
|
||||
if (qname->len == 0)
|
||||
return -ENOENT;
|
||||
@@ -629,91 +621,63 @@ static int exfat_find(struct inode *dir, struct qstr *qname,
|
||||
dentry = exfat_find_dir_entry(sb, ei, &cdir, &uni_name,
|
||||
num_entries, TYPE_ALL);
|
||||
|
||||
if ((dentry < 0) && (dentry != -EEXIST))
|
||||
if (dentry < 0)
|
||||
return dentry; /* -error value */
|
||||
|
||||
memcpy(&info->dir, &cdir.dir, sizeof(struct exfat_chain));
|
||||
info->dir = cdir;
|
||||
info->entry = dentry;
|
||||
info->num_subdirs = 0;
|
||||
|
||||
/* root directory itself */
|
||||
if (unlikely(dentry == -EEXIST)) {
|
||||
int num_clu = 0;
|
||||
es = exfat_get_dentry_set(sb, &cdir, dentry, ES_2_ENTRIES);
|
||||
if (!es)
|
||||
return -EIO;
|
||||
ep = exfat_get_dentry_cached(es, 0);
|
||||
ep2 = exfat_get_dentry_cached(es, 1);
|
||||
|
||||
info->type = TYPE_DIR;
|
||||
info->attr = ATTR_SUBDIR;
|
||||
info->flags = ALLOC_FAT_CHAIN;
|
||||
info->start_clu = sbi->root_dir;
|
||||
memset(&info->crtime, 0, sizeof(info->crtime));
|
||||
memset(&info->mtime, 0, sizeof(info->mtime));
|
||||
memset(&info->atime, 0, sizeof(info->atime));
|
||||
info->type = exfat_get_entry_type(ep);
|
||||
info->attr = le16_to_cpu(ep->dentry.file.attr);
|
||||
info->size = le64_to_cpu(ep2->dentry.stream.valid_size);
|
||||
if ((info->type == TYPE_FILE) && (info->size == 0)) {
|
||||
info->flags = ALLOC_NO_FAT_CHAIN;
|
||||
info->start_clu = EXFAT_EOF_CLUSTER;
|
||||
} else {
|
||||
info->flags = ep2->dentry.stream.flags;
|
||||
info->start_clu =
|
||||
le32_to_cpu(ep2->dentry.stream.start_clu);
|
||||
}
|
||||
|
||||
exfat_chain_set(&cdir, sbi->root_dir, 0, ALLOC_FAT_CHAIN);
|
||||
if (exfat_count_num_clusters(sb, &cdir, &num_clu))
|
||||
return -EIO;
|
||||
info->size = num_clu << sbi->cluster_size_bits;
|
||||
exfat_get_entry_time(sbi, &info->crtime,
|
||||
ep->dentry.file.create_tz,
|
||||
ep->dentry.file.create_time,
|
||||
ep->dentry.file.create_date,
|
||||
ep->dentry.file.create_time_cs);
|
||||
exfat_get_entry_time(sbi, &info->mtime,
|
||||
ep->dentry.file.modify_tz,
|
||||
ep->dentry.file.modify_time,
|
||||
ep->dentry.file.modify_date,
|
||||
ep->dentry.file.modify_time_cs);
|
||||
exfat_get_entry_time(sbi, &info->atime,
|
||||
ep->dentry.file.access_tz,
|
||||
ep->dentry.file.access_time,
|
||||
ep->dentry.file.access_date,
|
||||
0);
|
||||
exfat_free_dentry_set(es, false);
|
||||
|
||||
if (ei->start_clu == EXFAT_FREE_CLUSTER) {
|
||||
exfat_fs_error(sb,
|
||||
"non-zero size file starts with zero cluster (size : %llu, p_dir : %u, entry : 0x%08x)",
|
||||
i_size_read(dir), ei->dir.dir, ei->entry);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (info->type == TYPE_DIR) {
|
||||
exfat_chain_set(&cdir, info->start_clu,
|
||||
EXFAT_B_TO_CLU(info->size, sbi), info->flags);
|
||||
count = exfat_count_dir_entries(sb, &cdir);
|
||||
if (count < 0)
|
||||
return -EIO;
|
||||
|
||||
info->num_subdirs = count;
|
||||
} else {
|
||||
struct exfat_dentry *ep, *ep2;
|
||||
struct exfat_entry_set_cache *es;
|
||||
|
||||
es = exfat_get_dentry_set(sb, &cdir, dentry, ES_2_ENTRIES);
|
||||
if (!es)
|
||||
return -EIO;
|
||||
ep = exfat_get_dentry_cached(es, 0);
|
||||
ep2 = exfat_get_dentry_cached(es, 1);
|
||||
|
||||
info->type = exfat_get_entry_type(ep);
|
||||
info->attr = le16_to_cpu(ep->dentry.file.attr);
|
||||
info->size = le64_to_cpu(ep2->dentry.stream.valid_size);
|
||||
if ((info->type == TYPE_FILE) && (info->size == 0)) {
|
||||
info->flags = ALLOC_NO_FAT_CHAIN;
|
||||
info->start_clu = EXFAT_EOF_CLUSTER;
|
||||
} else {
|
||||
info->flags = ep2->dentry.stream.flags;
|
||||
info->start_clu =
|
||||
le32_to_cpu(ep2->dentry.stream.start_clu);
|
||||
}
|
||||
|
||||
if (ei->start_clu == EXFAT_FREE_CLUSTER) {
|
||||
exfat_fs_error(sb,
|
||||
"non-zero size file starts with zero cluster (size : %llu, p_dir : %u, entry : 0x%08x)",
|
||||
i_size_read(dir), ei->dir.dir, ei->entry);
|
||||
exfat_free_dentry_set(es, false);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
exfat_get_entry_time(sbi, &info->crtime,
|
||||
ep->dentry.file.create_tz,
|
||||
ep->dentry.file.create_time,
|
||||
ep->dentry.file.create_date,
|
||||
ep->dentry.file.create_time_cs);
|
||||
exfat_get_entry_time(sbi, &info->mtime,
|
||||
ep->dentry.file.modify_tz,
|
||||
ep->dentry.file.modify_time,
|
||||
ep->dentry.file.modify_date,
|
||||
ep->dentry.file.modify_time_cs);
|
||||
exfat_get_entry_time(sbi, &info->atime,
|
||||
ep->dentry.file.access_tz,
|
||||
ep->dentry.file.access_time,
|
||||
ep->dentry.file.access_date,
|
||||
0);
|
||||
exfat_free_dentry_set(es, false);
|
||||
|
||||
if (info->type == TYPE_DIR) {
|
||||
exfat_chain_set(&cdir, info->start_clu,
|
||||
EXFAT_B_TO_CLU(info->size, sbi), info->flags);
|
||||
count = exfat_count_dir_entries(sb, &cdir);
|
||||
if (count < 0)
|
||||
return -EIO;
|
||||
|
||||
info->num_subdirs = count + EXFAT_MIN_SUBDIR;
|
||||
}
|
||||
info->num_subdirs = count + EXFAT_MIN_SUBDIR;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -1065,7 +1029,7 @@ static int exfat_rename_file(struct inode *inode, struct exfat_chain *p_dir,
|
||||
if (!epnew)
|
||||
return -EIO;
|
||||
|
||||
memcpy(epnew, epold, DENTRY_SIZE);
|
||||
*epnew = *epold;
|
||||
if (exfat_get_entry_type(epnew) == TYPE_FILE) {
|
||||
epnew->dentry.file.attr |= cpu_to_le16(ATTR_ARCHIVE);
|
||||
ei->attr |= ATTR_ARCHIVE;
|
||||
@@ -1085,7 +1049,7 @@ static int exfat_rename_file(struct inode *inode, struct exfat_chain *p_dir,
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
memcpy(epnew, epold, DENTRY_SIZE);
|
||||
*epnew = *epold;
|
||||
exfat_update_bh(new_bh, sync);
|
||||
brelse(old_bh);
|
||||
brelse(new_bh);
|
||||
@@ -1130,11 +1094,6 @@ static int exfat_move_file(struct inode *inode, struct exfat_chain *p_olddir,
|
||||
if (!epmov)
|
||||
return -EIO;
|
||||
|
||||
/* check if the source and target directory is the same */
|
||||
if (exfat_get_entry_type(epmov) == TYPE_DIR &&
|
||||
le32_to_cpu(epmov->dentry.stream.start_clu) == p_newdir->dir)
|
||||
return -EINVAL;
|
||||
|
||||
num_old_entries = exfat_count_ext_entries(sb, p_olddir, oldentry,
|
||||
epmov);
|
||||
if (num_old_entries < 0)
|
||||
@@ -1153,7 +1112,7 @@ static int exfat_move_file(struct inode *inode, struct exfat_chain *p_olddir,
|
||||
if (!epnew)
|
||||
return -EIO;
|
||||
|
||||
memcpy(epnew, epmov, DENTRY_SIZE);
|
||||
*epnew = *epmov;
|
||||
if (exfat_get_entry_type(epnew) == TYPE_FILE) {
|
||||
epnew->dentry.file.attr |= cpu_to_le16(ATTR_ARCHIVE);
|
||||
ei->attr |= ATTR_ARCHIVE;
|
||||
@@ -1173,7 +1132,7 @@ static int exfat_move_file(struct inode *inode, struct exfat_chain *p_olddir,
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
memcpy(epnew, epmov, DENTRY_SIZE);
|
||||
*epnew = *epmov;
|
||||
exfat_update_bh(new_bh, IS_DIRSYNC(inode));
|
||||
brelse(mov_bh);
|
||||
brelse(new_bh);
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@
|
||||
#include "exfat_raw.h"
|
||||
#include "exfat_fs.h"
|
||||
|
||||
/* Upcase tabel macro */
|
||||
/* Upcase table macro */
|
||||
#define EXFAT_NUM_UPCASE (2918)
|
||||
#define UTBL_COUNT (0x10000)
|
||||
|
||||
|
||||
@@ -342,7 +342,6 @@ static int exfat_read_root(struct inode *inode)
|
||||
ei->flags = ALLOC_FAT_CHAIN;
|
||||
ei->type = TYPE_DIR;
|
||||
ei->version = 0;
|
||||
ei->rwoffset = 0;
|
||||
ei->hint_bmap.off = EXFAT_EOF_CLUSTER;
|
||||
ei->hint_stat.eidx = 0;
|
||||
ei->hint_stat.clu = sbi->root_dir;
|
||||
|
||||
+199
-49
@@ -486,65 +486,215 @@ nlm4svc_proc_granted_res(struct svc_rqst *rqstp)
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
static __be32
|
||||
nlm4svc_proc_unused(struct svc_rqst *rqstp)
|
||||
{
|
||||
return rpc_proc_unavail;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* NLM Server procedures.
|
||||
*/
|
||||
|
||||
#define nlm4svc_encode_norep nlm4svc_encode_void
|
||||
#define nlm4svc_decode_norep nlm4svc_decode_void
|
||||
#define nlm4svc_decode_testres nlm4svc_decode_void
|
||||
#define nlm4svc_decode_lockres nlm4svc_decode_void
|
||||
#define nlm4svc_decode_unlockres nlm4svc_decode_void
|
||||
#define nlm4svc_decode_cancelres nlm4svc_decode_void
|
||||
#define nlm4svc_decode_grantedres nlm4svc_decode_void
|
||||
|
||||
#define nlm4svc_proc_none nlm4svc_proc_null
|
||||
#define nlm4svc_proc_test_res nlm4svc_proc_null
|
||||
#define nlm4svc_proc_lock_res nlm4svc_proc_null
|
||||
#define nlm4svc_proc_cancel_res nlm4svc_proc_null
|
||||
#define nlm4svc_proc_unlock_res nlm4svc_proc_null
|
||||
|
||||
struct nlm_void { int dummy; };
|
||||
|
||||
#define PROC(name, xargt, xrest, argt, rest, respsize) \
|
||||
{ .pc_func = nlm4svc_proc_##name, \
|
||||
.pc_decode = nlm4svc_decode_##xargt, \
|
||||
.pc_encode = nlm4svc_encode_##xrest, \
|
||||
.pc_release = NULL, \
|
||||
.pc_argsize = sizeof(struct nlm_##argt), \
|
||||
.pc_ressize = sizeof(struct nlm_##rest), \
|
||||
.pc_xdrressize = respsize, \
|
||||
}
|
||||
#define Ck (1+XDR_QUADLEN(NLM_MAXCOOKIELEN)) /* cookie */
|
||||
#define No (1+1024/4) /* netobj */
|
||||
#define St 1 /* status */
|
||||
#define Rg 4 /* range (offset + length) */
|
||||
const struct svc_procedure nlmsvc_procedures4[] = {
|
||||
PROC(null, void, void, void, void, 1),
|
||||
PROC(test, testargs, testres, args, res, Ck+St+2+No+Rg),
|
||||
PROC(lock, lockargs, res, args, res, Ck+St),
|
||||
PROC(cancel, cancargs, res, args, res, Ck+St),
|
||||
PROC(unlock, unlockargs, res, args, res, Ck+St),
|
||||
PROC(granted, testargs, res, args, res, Ck+St),
|
||||
PROC(test_msg, testargs, norep, args, void, 1),
|
||||
PROC(lock_msg, lockargs, norep, args, void, 1),
|
||||
PROC(cancel_msg, cancargs, norep, args, void, 1),
|
||||
PROC(unlock_msg, unlockargs, norep, args, void, 1),
|
||||
PROC(granted_msg, testargs, norep, args, void, 1),
|
||||
PROC(test_res, testres, norep, res, void, 1),
|
||||
PROC(lock_res, lockres, norep, res, void, 1),
|
||||
PROC(cancel_res, cancelres, norep, res, void, 1),
|
||||
PROC(unlock_res, unlockres, norep, res, void, 1),
|
||||
PROC(granted_res, res, norep, res, void, 1),
|
||||
/* statd callback */
|
||||
PROC(sm_notify, reboot, void, reboot, void, 1),
|
||||
PROC(none, void, void, void, void, 0),
|
||||
PROC(none, void, void, void, void, 0),
|
||||
PROC(none, void, void, void, void, 0),
|
||||
PROC(share, shareargs, shareres, args, res, Ck+St+1),
|
||||
PROC(unshare, shareargs, shareres, args, res, Ck+St+1),
|
||||
PROC(nm_lock, lockargs, res, args, res, Ck+St),
|
||||
PROC(free_all, notify, void, args, void, 1),
|
||||
|
||||
const struct svc_procedure nlmsvc_procedures4[24] = {
|
||||
[NLMPROC_NULL] = {
|
||||
.pc_func = nlm4svc_proc_null,
|
||||
.pc_decode = nlm4svc_decode_void,
|
||||
.pc_encode = nlm4svc_encode_void,
|
||||
.pc_argsize = sizeof(struct nlm_void),
|
||||
.pc_ressize = sizeof(struct nlm_void),
|
||||
.pc_xdrressize = St,
|
||||
},
|
||||
[NLMPROC_TEST] = {
|
||||
.pc_func = nlm4svc_proc_test,
|
||||
.pc_decode = nlm4svc_decode_testargs,
|
||||
.pc_encode = nlm4svc_encode_testres,
|
||||
.pc_argsize = sizeof(struct nlm_args),
|
||||
.pc_ressize = sizeof(struct nlm_res),
|
||||
.pc_xdrressize = Ck+St+2+No+Rg,
|
||||
},
|
||||
[NLMPROC_LOCK] = {
|
||||
.pc_func = nlm4svc_proc_lock,
|
||||
.pc_decode = nlm4svc_decode_lockargs,
|
||||
.pc_encode = nlm4svc_encode_res,
|
||||
.pc_argsize = sizeof(struct nlm_args),
|
||||
.pc_ressize = sizeof(struct nlm_res),
|
||||
.pc_xdrressize = Ck+St,
|
||||
},
|
||||
[NLMPROC_CANCEL] = {
|
||||
.pc_func = nlm4svc_proc_cancel,
|
||||
.pc_decode = nlm4svc_decode_cancargs,
|
||||
.pc_encode = nlm4svc_encode_res,
|
||||
.pc_argsize = sizeof(struct nlm_args),
|
||||
.pc_ressize = sizeof(struct nlm_res),
|
||||
.pc_xdrressize = Ck+St,
|
||||
},
|
||||
[NLMPROC_UNLOCK] = {
|
||||
.pc_func = nlm4svc_proc_unlock,
|
||||
.pc_decode = nlm4svc_decode_unlockargs,
|
||||
.pc_encode = nlm4svc_encode_res,
|
||||
.pc_argsize = sizeof(struct nlm_args),
|
||||
.pc_ressize = sizeof(struct nlm_res),
|
||||
.pc_xdrressize = Ck+St,
|
||||
},
|
||||
[NLMPROC_GRANTED] = {
|
||||
.pc_func = nlm4svc_proc_granted,
|
||||
.pc_decode = nlm4svc_decode_testargs,
|
||||
.pc_encode = nlm4svc_encode_res,
|
||||
.pc_argsize = sizeof(struct nlm_args),
|
||||
.pc_ressize = sizeof(struct nlm_res),
|
||||
.pc_xdrressize = Ck+St,
|
||||
},
|
||||
[NLMPROC_TEST_MSG] = {
|
||||
.pc_func = nlm4svc_proc_test_msg,
|
||||
.pc_decode = nlm4svc_decode_testargs,
|
||||
.pc_encode = nlm4svc_encode_void,
|
||||
.pc_argsize = sizeof(struct nlm_args),
|
||||
.pc_ressize = sizeof(struct nlm_void),
|
||||
.pc_xdrressize = St,
|
||||
},
|
||||
[NLMPROC_LOCK_MSG] = {
|
||||
.pc_func = nlm4svc_proc_lock_msg,
|
||||
.pc_decode = nlm4svc_decode_lockargs,
|
||||
.pc_encode = nlm4svc_encode_void,
|
||||
.pc_argsize = sizeof(struct nlm_args),
|
||||
.pc_ressize = sizeof(struct nlm_void),
|
||||
.pc_xdrressize = St,
|
||||
},
|
||||
[NLMPROC_CANCEL_MSG] = {
|
||||
.pc_func = nlm4svc_proc_cancel_msg,
|
||||
.pc_decode = nlm4svc_decode_cancargs,
|
||||
.pc_encode = nlm4svc_encode_void,
|
||||
.pc_argsize = sizeof(struct nlm_args),
|
||||
.pc_ressize = sizeof(struct nlm_void),
|
||||
.pc_xdrressize = St,
|
||||
},
|
||||
[NLMPROC_UNLOCK_MSG] = {
|
||||
.pc_func = nlm4svc_proc_unlock_msg,
|
||||
.pc_decode = nlm4svc_decode_unlockargs,
|
||||
.pc_encode = nlm4svc_encode_void,
|
||||
.pc_argsize = sizeof(struct nlm_args),
|
||||
.pc_ressize = sizeof(struct nlm_void),
|
||||
.pc_xdrressize = St,
|
||||
},
|
||||
[NLMPROC_GRANTED_MSG] = {
|
||||
.pc_func = nlm4svc_proc_granted_msg,
|
||||
.pc_decode = nlm4svc_decode_testargs,
|
||||
.pc_encode = nlm4svc_encode_void,
|
||||
.pc_argsize = sizeof(struct nlm_args),
|
||||
.pc_ressize = sizeof(struct nlm_void),
|
||||
.pc_xdrressize = St,
|
||||
},
|
||||
[NLMPROC_TEST_RES] = {
|
||||
.pc_func = nlm4svc_proc_null,
|
||||
.pc_decode = nlm4svc_decode_void,
|
||||
.pc_encode = nlm4svc_encode_void,
|
||||
.pc_argsize = sizeof(struct nlm_res),
|
||||
.pc_ressize = sizeof(struct nlm_void),
|
||||
.pc_xdrressize = St,
|
||||
},
|
||||
[NLMPROC_LOCK_RES] = {
|
||||
.pc_func = nlm4svc_proc_null,
|
||||
.pc_decode = nlm4svc_decode_void,
|
||||
.pc_encode = nlm4svc_encode_void,
|
||||
.pc_argsize = sizeof(struct nlm_res),
|
||||
.pc_ressize = sizeof(struct nlm_void),
|
||||
.pc_xdrressize = St,
|
||||
},
|
||||
[NLMPROC_CANCEL_RES] = {
|
||||
.pc_func = nlm4svc_proc_null,
|
||||
.pc_decode = nlm4svc_decode_void,
|
||||
.pc_encode = nlm4svc_encode_void,
|
||||
.pc_argsize = sizeof(struct nlm_res),
|
||||
.pc_ressize = sizeof(struct nlm_void),
|
||||
.pc_xdrressize = St,
|
||||
},
|
||||
[NLMPROC_UNLOCK_RES] = {
|
||||
.pc_func = nlm4svc_proc_null,
|
||||
.pc_decode = nlm4svc_decode_void,
|
||||
.pc_encode = nlm4svc_encode_void,
|
||||
.pc_argsize = sizeof(struct nlm_res),
|
||||
.pc_ressize = sizeof(struct nlm_void),
|
||||
.pc_xdrressize = St,
|
||||
},
|
||||
[NLMPROC_GRANTED_RES] = {
|
||||
.pc_func = nlm4svc_proc_granted_res,
|
||||
.pc_decode = nlm4svc_decode_res,
|
||||
.pc_encode = nlm4svc_encode_void,
|
||||
.pc_argsize = sizeof(struct nlm_res),
|
||||
.pc_ressize = sizeof(struct nlm_void),
|
||||
.pc_xdrressize = St,
|
||||
},
|
||||
[NLMPROC_NSM_NOTIFY] = {
|
||||
.pc_func = nlm4svc_proc_sm_notify,
|
||||
.pc_decode = nlm4svc_decode_reboot,
|
||||
.pc_encode = nlm4svc_encode_void,
|
||||
.pc_argsize = sizeof(struct nlm_reboot),
|
||||
.pc_ressize = sizeof(struct nlm_void),
|
||||
.pc_xdrressize = St,
|
||||
},
|
||||
[17] = {
|
||||
.pc_func = nlm4svc_proc_unused,
|
||||
.pc_decode = nlm4svc_decode_void,
|
||||
.pc_encode = nlm4svc_encode_void,
|
||||
.pc_argsize = sizeof(struct nlm_void),
|
||||
.pc_ressize = sizeof(struct nlm_void),
|
||||
.pc_xdrressize = 0,
|
||||
},
|
||||
[18] = {
|
||||
.pc_func = nlm4svc_proc_unused,
|
||||
.pc_decode = nlm4svc_decode_void,
|
||||
.pc_encode = nlm4svc_encode_void,
|
||||
.pc_argsize = sizeof(struct nlm_void),
|
||||
.pc_ressize = sizeof(struct nlm_void),
|
||||
.pc_xdrressize = 0,
|
||||
},
|
||||
[19] = {
|
||||
.pc_func = nlm4svc_proc_unused,
|
||||
.pc_decode = nlm4svc_decode_void,
|
||||
.pc_encode = nlm4svc_encode_void,
|
||||
.pc_argsize = sizeof(struct nlm_void),
|
||||
.pc_ressize = sizeof(struct nlm_void),
|
||||
.pc_xdrressize = 0,
|
||||
},
|
||||
[NLMPROC_SHARE] = {
|
||||
.pc_func = nlm4svc_proc_share,
|
||||
.pc_decode = nlm4svc_decode_shareargs,
|
||||
.pc_encode = nlm4svc_encode_shareres,
|
||||
.pc_argsize = sizeof(struct nlm_args),
|
||||
.pc_ressize = sizeof(struct nlm_res),
|
||||
.pc_xdrressize = Ck+St+1,
|
||||
},
|
||||
[NLMPROC_UNSHARE] = {
|
||||
.pc_func = nlm4svc_proc_unshare,
|
||||
.pc_decode = nlm4svc_decode_shareargs,
|
||||
.pc_encode = nlm4svc_encode_shareres,
|
||||
.pc_argsize = sizeof(struct nlm_args),
|
||||
.pc_ressize = sizeof(struct nlm_res),
|
||||
.pc_xdrressize = Ck+St+1,
|
||||
},
|
||||
[NLMPROC_NM_LOCK] = {
|
||||
.pc_func = nlm4svc_proc_nm_lock,
|
||||
.pc_decode = nlm4svc_decode_lockargs,
|
||||
.pc_encode = nlm4svc_encode_res,
|
||||
.pc_argsize = sizeof(struct nlm_args),
|
||||
.pc_ressize = sizeof(struct nlm_res),
|
||||
.pc_xdrressize = Ck+St,
|
||||
},
|
||||
[NLMPROC_FREE_ALL] = {
|
||||
.pc_func = nlm4svc_proc_free_all,
|
||||
.pc_decode = nlm4svc_decode_notify,
|
||||
.pc_encode = nlm4svc_encode_void,
|
||||
.pc_argsize = sizeof(struct nlm_args),
|
||||
.pc_ressize = sizeof(struct nlm_void),
|
||||
.pc_xdrressize = St,
|
||||
},
|
||||
};
|
||||
|
||||
+199
-51
@@ -529,66 +529,214 @@ nlmsvc_proc_granted_res(struct svc_rqst *rqstp)
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
static __be32
|
||||
nlmsvc_proc_unused(struct svc_rqst *rqstp)
|
||||
{
|
||||
return rpc_proc_unavail;
|
||||
}
|
||||
|
||||
/*
|
||||
* NLM Server procedures.
|
||||
*/
|
||||
|
||||
#define nlmsvc_encode_norep nlmsvc_encode_void
|
||||
#define nlmsvc_decode_norep nlmsvc_decode_void
|
||||
#define nlmsvc_decode_testres nlmsvc_decode_void
|
||||
#define nlmsvc_decode_lockres nlmsvc_decode_void
|
||||
#define nlmsvc_decode_unlockres nlmsvc_decode_void
|
||||
#define nlmsvc_decode_cancelres nlmsvc_decode_void
|
||||
#define nlmsvc_decode_grantedres nlmsvc_decode_void
|
||||
|
||||
#define nlmsvc_proc_none nlmsvc_proc_null
|
||||
#define nlmsvc_proc_test_res nlmsvc_proc_null
|
||||
#define nlmsvc_proc_lock_res nlmsvc_proc_null
|
||||
#define nlmsvc_proc_cancel_res nlmsvc_proc_null
|
||||
#define nlmsvc_proc_unlock_res nlmsvc_proc_null
|
||||
|
||||
struct nlm_void { int dummy; };
|
||||
|
||||
#define PROC(name, xargt, xrest, argt, rest, respsize) \
|
||||
{ .pc_func = nlmsvc_proc_##name, \
|
||||
.pc_decode = nlmsvc_decode_##xargt, \
|
||||
.pc_encode = nlmsvc_encode_##xrest, \
|
||||
.pc_release = NULL, \
|
||||
.pc_argsize = sizeof(struct nlm_##argt), \
|
||||
.pc_ressize = sizeof(struct nlm_##rest), \
|
||||
.pc_xdrressize = respsize, \
|
||||
}
|
||||
|
||||
#define Ck (1+XDR_QUADLEN(NLM_MAXCOOKIELEN)) /* cookie */
|
||||
#define St 1 /* status */
|
||||
#define No (1+1024/4) /* Net Obj */
|
||||
#define Rg 2 /* range - offset + size */
|
||||
|
||||
const struct svc_procedure nlmsvc_procedures[] = {
|
||||
PROC(null, void, void, void, void, 1),
|
||||
PROC(test, testargs, testres, args, res, Ck+St+2+No+Rg),
|
||||
PROC(lock, lockargs, res, args, res, Ck+St),
|
||||
PROC(cancel, cancargs, res, args, res, Ck+St),
|
||||
PROC(unlock, unlockargs, res, args, res, Ck+St),
|
||||
PROC(granted, testargs, res, args, res, Ck+St),
|
||||
PROC(test_msg, testargs, norep, args, void, 1),
|
||||
PROC(lock_msg, lockargs, norep, args, void, 1),
|
||||
PROC(cancel_msg, cancargs, norep, args, void, 1),
|
||||
PROC(unlock_msg, unlockargs, norep, args, void, 1),
|
||||
PROC(granted_msg, testargs, norep, args, void, 1),
|
||||
PROC(test_res, testres, norep, res, void, 1),
|
||||
PROC(lock_res, lockres, norep, res, void, 1),
|
||||
PROC(cancel_res, cancelres, norep, res, void, 1),
|
||||
PROC(unlock_res, unlockres, norep, res, void, 1),
|
||||
PROC(granted_res, res, norep, res, void, 1),
|
||||
/* statd callback */
|
||||
PROC(sm_notify, reboot, void, reboot, void, 1),
|
||||
PROC(none, void, void, void, void, 1),
|
||||
PROC(none, void, void, void, void, 1),
|
||||
PROC(none, void, void, void, void, 1),
|
||||
PROC(share, shareargs, shareres, args, res, Ck+St+1),
|
||||
PROC(unshare, shareargs, shareres, args, res, Ck+St+1),
|
||||
PROC(nm_lock, lockargs, res, args, res, Ck+St),
|
||||
PROC(free_all, notify, void, args, void, 0),
|
||||
|
||||
const struct svc_procedure nlmsvc_procedures[24] = {
|
||||
[NLMPROC_NULL] = {
|
||||
.pc_func = nlmsvc_proc_null,
|
||||
.pc_decode = nlmsvc_decode_void,
|
||||
.pc_encode = nlmsvc_encode_void,
|
||||
.pc_argsize = sizeof(struct nlm_void),
|
||||
.pc_ressize = sizeof(struct nlm_void),
|
||||
.pc_xdrressize = St,
|
||||
},
|
||||
[NLMPROC_TEST] = {
|
||||
.pc_func = nlmsvc_proc_test,
|
||||
.pc_decode = nlmsvc_decode_testargs,
|
||||
.pc_encode = nlmsvc_encode_testres,
|
||||
.pc_argsize = sizeof(struct nlm_args),
|
||||
.pc_ressize = sizeof(struct nlm_res),
|
||||
.pc_xdrressize = Ck+St+2+No+Rg,
|
||||
},
|
||||
[NLMPROC_LOCK] = {
|
||||
.pc_func = nlmsvc_proc_lock,
|
||||
.pc_decode = nlmsvc_decode_lockargs,
|
||||
.pc_encode = nlmsvc_encode_res,
|
||||
.pc_argsize = sizeof(struct nlm_args),
|
||||
.pc_ressize = sizeof(struct nlm_res),
|
||||
.pc_xdrressize = Ck+St,
|
||||
},
|
||||
[NLMPROC_CANCEL] = {
|
||||
.pc_func = nlmsvc_proc_cancel,
|
||||
.pc_decode = nlmsvc_decode_cancargs,
|
||||
.pc_encode = nlmsvc_encode_res,
|
||||
.pc_argsize = sizeof(struct nlm_args),
|
||||
.pc_ressize = sizeof(struct nlm_res),
|
||||
.pc_xdrressize = Ck+St,
|
||||
},
|
||||
[NLMPROC_UNLOCK] = {
|
||||
.pc_func = nlmsvc_proc_unlock,
|
||||
.pc_decode = nlmsvc_decode_unlockargs,
|
||||
.pc_encode = nlmsvc_encode_res,
|
||||
.pc_argsize = sizeof(struct nlm_args),
|
||||
.pc_ressize = sizeof(struct nlm_res),
|
||||
.pc_xdrressize = Ck+St,
|
||||
},
|
||||
[NLMPROC_GRANTED] = {
|
||||
.pc_func = nlmsvc_proc_granted,
|
||||
.pc_decode = nlmsvc_decode_testargs,
|
||||
.pc_encode = nlmsvc_encode_res,
|
||||
.pc_argsize = sizeof(struct nlm_args),
|
||||
.pc_ressize = sizeof(struct nlm_res),
|
||||
.pc_xdrressize = Ck+St,
|
||||
},
|
||||
[NLMPROC_TEST_MSG] = {
|
||||
.pc_func = nlmsvc_proc_test_msg,
|
||||
.pc_decode = nlmsvc_decode_testargs,
|
||||
.pc_encode = nlmsvc_encode_void,
|
||||
.pc_argsize = sizeof(struct nlm_args),
|
||||
.pc_ressize = sizeof(struct nlm_void),
|
||||
.pc_xdrressize = St,
|
||||
},
|
||||
[NLMPROC_LOCK_MSG] = {
|
||||
.pc_func = nlmsvc_proc_lock_msg,
|
||||
.pc_decode = nlmsvc_decode_lockargs,
|
||||
.pc_encode = nlmsvc_encode_void,
|
||||
.pc_argsize = sizeof(struct nlm_args),
|
||||
.pc_ressize = sizeof(struct nlm_void),
|
||||
.pc_xdrressize = St,
|
||||
},
|
||||
[NLMPROC_CANCEL_MSG] = {
|
||||
.pc_func = nlmsvc_proc_cancel_msg,
|
||||
.pc_decode = nlmsvc_decode_cancargs,
|
||||
.pc_encode = nlmsvc_encode_void,
|
||||
.pc_argsize = sizeof(struct nlm_args),
|
||||
.pc_ressize = sizeof(struct nlm_void),
|
||||
.pc_xdrressize = St,
|
||||
},
|
||||
[NLMPROC_UNLOCK_MSG] = {
|
||||
.pc_func = nlmsvc_proc_unlock_msg,
|
||||
.pc_decode = nlmsvc_decode_unlockargs,
|
||||
.pc_encode = nlmsvc_encode_void,
|
||||
.pc_argsize = sizeof(struct nlm_args),
|
||||
.pc_ressize = sizeof(struct nlm_void),
|
||||
.pc_xdrressize = St,
|
||||
},
|
||||
[NLMPROC_GRANTED_MSG] = {
|
||||
.pc_func = nlmsvc_proc_granted_msg,
|
||||
.pc_decode = nlmsvc_decode_testargs,
|
||||
.pc_encode = nlmsvc_encode_void,
|
||||
.pc_argsize = sizeof(struct nlm_args),
|
||||
.pc_ressize = sizeof(struct nlm_void),
|
||||
.pc_xdrressize = St,
|
||||
},
|
||||
[NLMPROC_TEST_RES] = {
|
||||
.pc_func = nlmsvc_proc_null,
|
||||
.pc_decode = nlmsvc_decode_void,
|
||||
.pc_encode = nlmsvc_encode_void,
|
||||
.pc_argsize = sizeof(struct nlm_res),
|
||||
.pc_ressize = sizeof(struct nlm_void),
|
||||
.pc_xdrressize = St,
|
||||
},
|
||||
[NLMPROC_LOCK_RES] = {
|
||||
.pc_func = nlmsvc_proc_null,
|
||||
.pc_decode = nlmsvc_decode_void,
|
||||
.pc_encode = nlmsvc_encode_void,
|
||||
.pc_argsize = sizeof(struct nlm_res),
|
||||
.pc_ressize = sizeof(struct nlm_void),
|
||||
.pc_xdrressize = St,
|
||||
},
|
||||
[NLMPROC_CANCEL_RES] = {
|
||||
.pc_func = nlmsvc_proc_null,
|
||||
.pc_decode = nlmsvc_decode_void,
|
||||
.pc_encode = nlmsvc_encode_void,
|
||||
.pc_argsize = sizeof(struct nlm_res),
|
||||
.pc_ressize = sizeof(struct nlm_void),
|
||||
.pc_xdrressize = St,
|
||||
},
|
||||
[NLMPROC_UNLOCK_RES] = {
|
||||
.pc_func = nlmsvc_proc_null,
|
||||
.pc_decode = nlmsvc_decode_void,
|
||||
.pc_encode = nlmsvc_encode_void,
|
||||
.pc_argsize = sizeof(struct nlm_res),
|
||||
.pc_ressize = sizeof(struct nlm_void),
|
||||
.pc_xdrressize = St,
|
||||
},
|
||||
[NLMPROC_GRANTED_RES] = {
|
||||
.pc_func = nlmsvc_proc_granted_res,
|
||||
.pc_decode = nlmsvc_decode_res,
|
||||
.pc_encode = nlmsvc_encode_void,
|
||||
.pc_argsize = sizeof(struct nlm_res),
|
||||
.pc_ressize = sizeof(struct nlm_void),
|
||||
.pc_xdrressize = St,
|
||||
},
|
||||
[NLMPROC_NSM_NOTIFY] = {
|
||||
.pc_func = nlmsvc_proc_sm_notify,
|
||||
.pc_decode = nlmsvc_decode_reboot,
|
||||
.pc_encode = nlmsvc_encode_void,
|
||||
.pc_argsize = sizeof(struct nlm_reboot),
|
||||
.pc_ressize = sizeof(struct nlm_void),
|
||||
.pc_xdrressize = St,
|
||||
},
|
||||
[17] = {
|
||||
.pc_func = nlmsvc_proc_unused,
|
||||
.pc_decode = nlmsvc_decode_void,
|
||||
.pc_encode = nlmsvc_encode_void,
|
||||
.pc_argsize = sizeof(struct nlm_void),
|
||||
.pc_ressize = sizeof(struct nlm_void),
|
||||
.pc_xdrressize = St,
|
||||
},
|
||||
[18] = {
|
||||
.pc_func = nlmsvc_proc_unused,
|
||||
.pc_decode = nlmsvc_decode_void,
|
||||
.pc_encode = nlmsvc_encode_void,
|
||||
.pc_argsize = sizeof(struct nlm_void),
|
||||
.pc_ressize = sizeof(struct nlm_void),
|
||||
.pc_xdrressize = St,
|
||||
},
|
||||
[19] = {
|
||||
.pc_func = nlmsvc_proc_unused,
|
||||
.pc_decode = nlmsvc_decode_void,
|
||||
.pc_encode = nlmsvc_encode_void,
|
||||
.pc_argsize = sizeof(struct nlm_void),
|
||||
.pc_ressize = sizeof(struct nlm_void),
|
||||
.pc_xdrressize = St,
|
||||
},
|
||||
[NLMPROC_SHARE] = {
|
||||
.pc_func = nlmsvc_proc_share,
|
||||
.pc_decode = nlmsvc_decode_shareargs,
|
||||
.pc_encode = nlmsvc_encode_shareres,
|
||||
.pc_argsize = sizeof(struct nlm_args),
|
||||
.pc_ressize = sizeof(struct nlm_res),
|
||||
.pc_xdrressize = Ck+St+1,
|
||||
},
|
||||
[NLMPROC_UNSHARE] = {
|
||||
.pc_func = nlmsvc_proc_unshare,
|
||||
.pc_decode = nlmsvc_decode_shareargs,
|
||||
.pc_encode = nlmsvc_encode_shareres,
|
||||
.pc_argsize = sizeof(struct nlm_args),
|
||||
.pc_ressize = sizeof(struct nlm_res),
|
||||
.pc_xdrressize = Ck+St+1,
|
||||
},
|
||||
[NLMPROC_NM_LOCK] = {
|
||||
.pc_func = nlmsvc_proc_nm_lock,
|
||||
.pc_decode = nlmsvc_decode_lockargs,
|
||||
.pc_encode = nlmsvc_encode_res,
|
||||
.pc_argsize = sizeof(struct nlm_args),
|
||||
.pc_ressize = sizeof(struct nlm_res),
|
||||
.pc_xdrressize = Ck+St,
|
||||
},
|
||||
[NLMPROC_FREE_ALL] = {
|
||||
.pc_func = nlmsvc_proc_free_all,
|
||||
.pc_decode = nlmsvc_decode_notify,
|
||||
.pc_encode = nlmsvc_encode_void,
|
||||
.pc_argsize = sizeof(struct nlm_args),
|
||||
.pc_ressize = sizeof(struct nlm_void),
|
||||
.pc_xdrressize = 0,
|
||||
},
|
||||
};
|
||||
|
||||
+32
-6
@@ -9,6 +9,7 @@
|
||||
#include <linux/falloc.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/nfs_fs.h>
|
||||
#include <linux/nfs_ssc.h>
|
||||
#include "delegation.h"
|
||||
#include "internal.h"
|
||||
#include "iostat.h"
|
||||
@@ -315,9 +316,8 @@ out:
|
||||
static int read_name_gen = 1;
|
||||
#define SSC_READ_NAME_BODY "ssc_read_%d"
|
||||
|
||||
struct file *
|
||||
nfs42_ssc_open(struct vfsmount *ss_mnt, struct nfs_fh *src_fh,
|
||||
nfs4_stateid *stateid)
|
||||
static struct file *__nfs42_ssc_open(struct vfsmount *ss_mnt,
|
||||
struct nfs_fh *src_fh, nfs4_stateid *stateid)
|
||||
{
|
||||
struct nfs_fattr fattr;
|
||||
struct file *filep, *res;
|
||||
@@ -399,14 +399,40 @@ out_filep:
|
||||
fput(filep);
|
||||
goto out_free_name;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs42_ssc_open);
|
||||
void nfs42_ssc_close(struct file *filep)
|
||||
|
||||
static void __nfs42_ssc_close(struct file *filep)
|
||||
{
|
||||
struct nfs_open_context *ctx = nfs_file_open_context(filep);
|
||||
|
||||
ctx->state->flags = 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs42_ssc_close);
|
||||
|
||||
static const struct nfs4_ssc_client_ops nfs4_ssc_clnt_ops_tbl = {
|
||||
.sco_open = __nfs42_ssc_open,
|
||||
.sco_close = __nfs42_ssc_close,
|
||||
};
|
||||
|
||||
/**
|
||||
* nfs42_ssc_register_ops - Wrapper to register NFS_V4 ops in nfs_common
|
||||
*
|
||||
* Return values:
|
||||
* None
|
||||
*/
|
||||
void nfs42_ssc_register_ops(void)
|
||||
{
|
||||
nfs42_ssc_register(&nfs4_ssc_clnt_ops_tbl);
|
||||
}
|
||||
|
||||
/**
|
||||
* nfs42_ssc_unregister_ops - wrapper to un-register NFS_V4 ops in nfs_common
|
||||
*
|
||||
* Return values:
|
||||
* None.
|
||||
*/
|
||||
void nfs42_ssc_unregister_ops(void)
|
||||
{
|
||||
nfs42_ssc_unregister(&nfs4_ssc_clnt_ops_tbl);
|
||||
}
|
||||
#endif /* CONFIG_NFS_V4_2 */
|
||||
|
||||
const struct file_operations nfs4_file_operations = {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <linux/mount.h>
|
||||
#include <linux/nfs4_mount.h>
|
||||
#include <linux/nfs_fs.h>
|
||||
#include <linux/nfs_ssc.h>
|
||||
#include "delegation.h"
|
||||
#include "internal.h"
|
||||
#include "nfs4_fs.h"
|
||||
@@ -279,6 +280,9 @@ static int __init init_nfs_v4(void)
|
||||
if (err)
|
||||
goto out2;
|
||||
|
||||
#ifdef CONFIG_NFS_V4_2
|
||||
nfs42_ssc_register_ops();
|
||||
#endif
|
||||
register_nfs_version(&nfs_v4);
|
||||
return 0;
|
||||
out2:
|
||||
@@ -297,6 +301,7 @@ static void __exit exit_nfs_v4(void)
|
||||
unregister_nfs_version(&nfs_v4);
|
||||
#ifdef CONFIG_NFS_V4_2
|
||||
nfs4_xattr_cache_exit();
|
||||
nfs42_ssc_unregister_ops();
|
||||
#endif
|
||||
nfs4_unregister_sysctl();
|
||||
nfs_idmap_quit();
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
#include <linux/rcupdate.h>
|
||||
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/nfs_ssc.h>
|
||||
|
||||
#include "nfs4_fs.h"
|
||||
#include "callback.h"
|
||||
@@ -85,6 +86,10 @@ const struct super_operations nfs_sops = {
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(nfs_sops);
|
||||
|
||||
static const struct nfs_ssc_client_ops nfs_ssc_clnt_ops_tbl = {
|
||||
.sco_sb_deactive = nfs_sb_deactive,
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_NFS_V4)
|
||||
static int __init register_nfs4_fs(void)
|
||||
{
|
||||
@@ -106,6 +111,16 @@ static void unregister_nfs4_fs(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
static void nfs_ssc_register_ops(void)
|
||||
{
|
||||
nfs_ssc_register(&nfs_ssc_clnt_ops_tbl);
|
||||
}
|
||||
|
||||
static void nfs_ssc_unregister_ops(void)
|
||||
{
|
||||
nfs_ssc_unregister(&nfs_ssc_clnt_ops_tbl);
|
||||
}
|
||||
|
||||
static struct shrinker acl_shrinker = {
|
||||
.count_objects = nfs_access_cache_count,
|
||||
.scan_objects = nfs_access_cache_scan,
|
||||
@@ -133,6 +148,7 @@ int __init register_nfs_fs(void)
|
||||
ret = register_shrinker(&acl_shrinker);
|
||||
if (ret < 0)
|
||||
goto error_3;
|
||||
nfs_ssc_register_ops();
|
||||
return 0;
|
||||
error_3:
|
||||
nfs_unregister_sysctl();
|
||||
@@ -152,6 +168,7 @@ void __exit unregister_nfs_fs(void)
|
||||
unregister_shrinker(&acl_shrinker);
|
||||
nfs_unregister_sysctl();
|
||||
unregister_nfs4_fs();
|
||||
nfs_ssc_unregister_ops();
|
||||
unregister_filesystem(&nfs_fs_type);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,3 +7,4 @@ obj-$(CONFIG_NFS_ACL_SUPPORT) += nfs_acl.o
|
||||
nfs_acl-objs := nfsacl.o
|
||||
|
||||
obj-$(CONFIG_GRACE_PERIOD) += grace.o
|
||||
obj-$(CONFIG_GRACE_PERIOD) += nfs_ssc.o
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* fs/nfs_common/nfs_ssc_comm.c
|
||||
*
|
||||
* Helper for knfsd's SSC to access ops in NFS client modules
|
||||
*
|
||||
* Author: Dai Ngo <dai.ngo@oracle.com>
|
||||
*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/nfs_ssc.h>
|
||||
#include "../nfs/nfs4_fs.h"
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
struct nfs_ssc_client_ops_tbl nfs_ssc_client_tbl;
|
||||
EXPORT_SYMBOL_GPL(nfs_ssc_client_tbl);
|
||||
|
||||
#ifdef CONFIG_NFS_V4_2
|
||||
/**
|
||||
* nfs42_ssc_register - install the NFS_V4 client ops in the nfs_ssc_client_tbl
|
||||
* @ops: NFS_V4 ops to be installed
|
||||
*
|
||||
* Return values:
|
||||
* None
|
||||
*/
|
||||
void nfs42_ssc_register(const struct nfs4_ssc_client_ops *ops)
|
||||
{
|
||||
nfs_ssc_client_tbl.ssc_nfs4_ops = ops;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs42_ssc_register);
|
||||
|
||||
/**
|
||||
* nfs42_ssc_unregister - uninstall the NFS_V4 client ops from
|
||||
* the nfs_ssc_client_tbl
|
||||
* @ops: ops to be uninstalled
|
||||
*
|
||||
* Return values:
|
||||
* None
|
||||
*/
|
||||
void nfs42_ssc_unregister(const struct nfs4_ssc_client_ops *ops)
|
||||
{
|
||||
if (nfs_ssc_client_tbl.ssc_nfs4_ops != ops)
|
||||
return;
|
||||
|
||||
nfs_ssc_client_tbl.ssc_nfs4_ops = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs42_ssc_unregister);
|
||||
#endif /* CONFIG_NFS_V4_2 */
|
||||
|
||||
#ifdef CONFIG_NFS_V4_2
|
||||
/**
|
||||
* nfs_ssc_register - install the NFS_FS client ops in the nfs_ssc_client_tbl
|
||||
* @ops: NFS_FS ops to be installed
|
||||
*
|
||||
* Return values:
|
||||
* None
|
||||
*/
|
||||
void nfs_ssc_register(const struct nfs_ssc_client_ops *ops)
|
||||
{
|
||||
nfs_ssc_client_tbl.ssc_nfs_ops = ops;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs_ssc_register);
|
||||
|
||||
/**
|
||||
* nfs_ssc_unregister - uninstall the NFS_FS client ops from
|
||||
* the nfs_ssc_client_tbl
|
||||
* @ops: ops to be uninstalled
|
||||
*
|
||||
* Return values:
|
||||
* None
|
||||
*/
|
||||
void nfs_ssc_unregister(const struct nfs_ssc_client_ops *ops)
|
||||
{
|
||||
if (nfs_ssc_client_tbl.ssc_nfs_ops != ops)
|
||||
return;
|
||||
nfs_ssc_client_tbl.ssc_nfs_ops = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs_ssc_unregister);
|
||||
|
||||
#else
|
||||
void nfs_ssc_register(const struct nfs_ssc_client_ops *ops)
|
||||
{
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs_ssc_register);
|
||||
|
||||
void nfs_ssc_unregister(const struct nfs_ssc_client_ops *ops)
|
||||
{
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs_ssc_unregister);
|
||||
#endif /* CONFIG_NFS_V4_2 */
|
||||
+1
-11
@@ -136,7 +136,7 @@ config NFSD_FLEXFILELAYOUT
|
||||
|
||||
config NFSD_V4_2_INTER_SSC
|
||||
bool "NFSv4.2 inter server to server COPY"
|
||||
depends on NFSD_V4 && NFS_V4_1 && NFS_V4_2 && NFS_FS=y
|
||||
depends on NFSD_V4 && NFS_V4_1 && NFS_V4_2
|
||||
help
|
||||
This option enables support for NFSv4.2 inter server to
|
||||
server copy where the destination server calls the NFSv4.2
|
||||
@@ -156,13 +156,3 @@ config NFSD_V4_SECURITY_LABEL
|
||||
|
||||
If you do not wish to enable fine-grained security labels SELinux or
|
||||
Smack policies on NFSv4 files, say N.
|
||||
|
||||
config NFSD_FAULT_INJECTION
|
||||
bool "NFS server manual fault injection"
|
||||
depends on NFSD_V4 && DEBUG_KERNEL && DEBUG_FS && BROKEN
|
||||
help
|
||||
This option enables support for manually injecting faults
|
||||
into the NFS server. This is intended to be used for
|
||||
testing error recovery on the NFS client.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
@@ -13,7 +13,6 @@ nfsd-y += trace.o
|
||||
nfsd-y += nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \
|
||||
export.o auth.o lockd.o nfscache.o nfsxdr.o \
|
||||
stats.o filecache.o
|
||||
nfsd-$(CONFIG_NFSD_FAULT_INJECTION) += fault_inject.o
|
||||
nfsd-$(CONFIG_NFSD_V2_ACL) += nfs2acl.o
|
||||
nfsd-$(CONFIG_NFSD_V3) += nfs3proc.o nfs3xdr.o
|
||||
nfsd-$(CONFIG_NFSD_V3_ACL) += nfs3acl.o
|
||||
|
||||
+1
-1
@@ -1002,7 +1002,7 @@ __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
|
||||
if (nfsd4_spo_must_allow(rqstp))
|
||||
return 0;
|
||||
|
||||
return nfserr_wrongsec;
|
||||
return rqstp->rq_vers < 4 ? nfserr_acces : nfserr_wrongsec;
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+1
-1
@@ -889,7 +889,7 @@ nfsd_file_find_locked(struct inode *inode, unsigned int may_flags,
|
||||
|
||||
hlist_for_each_entry_rcu(nf, &nfsd_file_hashtbl[hashval].nfb_head,
|
||||
nf_node, lockdep_is_held(&nfsd_file_hashtbl[hashval].nfb_lock)) {
|
||||
if ((need & nf->nf_may) != need)
|
||||
if (nf->nf_may != need)
|
||||
continue;
|
||||
if (nf->nf_inode != inode)
|
||||
continue;
|
||||
|
||||
+104
-56
@@ -14,7 +14,6 @@
|
||||
#include "vfs.h"
|
||||
|
||||
#define NFSDDBG_FACILITY NFSDDBG_PROC
|
||||
#define RETURN_STATUS(st) { resp->status = (st); return (st); }
|
||||
|
||||
/*
|
||||
* NULL call.
|
||||
@@ -22,7 +21,7 @@
|
||||
static __be32
|
||||
nfsacld_proc_null(struct svc_rqst *rqstp)
|
||||
{
|
||||
return nfs_ok;
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -35,24 +34,25 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst *rqstp)
|
||||
struct posix_acl *acl;
|
||||
struct inode *inode;
|
||||
svc_fh *fh;
|
||||
__be32 nfserr = 0;
|
||||
|
||||
dprintk("nfsd: GETACL(2acl) %s\n", SVCFH_fmt(&argp->fh));
|
||||
|
||||
fh = fh_copy(&resp->fh, &argp->fh);
|
||||
nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
|
||||
if (nfserr)
|
||||
RETURN_STATUS(nfserr);
|
||||
resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
|
||||
if (resp->status != nfs_ok)
|
||||
goto out;
|
||||
|
||||
inode = d_inode(fh->fh_dentry);
|
||||
|
||||
if (argp->mask & ~NFS_ACL_MASK)
|
||||
RETURN_STATUS(nfserr_inval);
|
||||
if (argp->mask & ~NFS_ACL_MASK) {
|
||||
resp->status = nfserr_inval;
|
||||
goto out;
|
||||
}
|
||||
resp->mask = argp->mask;
|
||||
|
||||
nfserr = fh_getattr(fh, &resp->stat);
|
||||
if (nfserr)
|
||||
RETURN_STATUS(nfserr);
|
||||
resp->status = fh_getattr(fh, &resp->stat);
|
||||
if (resp->status != nfs_ok)
|
||||
goto out;
|
||||
|
||||
if (resp->mask & (NFS_ACL|NFS_ACLCNT)) {
|
||||
acl = get_acl(inode, ACL_TYPE_ACCESS);
|
||||
@@ -61,7 +61,7 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst *rqstp)
|
||||
acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
|
||||
}
|
||||
if (IS_ERR(acl)) {
|
||||
nfserr = nfserrno(PTR_ERR(acl));
|
||||
resp->status = nfserrno(PTR_ERR(acl));
|
||||
goto fail;
|
||||
}
|
||||
resp->acl_access = acl;
|
||||
@@ -71,19 +71,20 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst *rqstp)
|
||||
of a non-directory! */
|
||||
acl = get_acl(inode, ACL_TYPE_DEFAULT);
|
||||
if (IS_ERR(acl)) {
|
||||
nfserr = nfserrno(PTR_ERR(acl));
|
||||
resp->status = nfserrno(PTR_ERR(acl));
|
||||
goto fail;
|
||||
}
|
||||
resp->acl_default = acl;
|
||||
}
|
||||
|
||||
/* resp->acl_{access,default} are released in nfssvc_release_getacl. */
|
||||
RETURN_STATUS(0);
|
||||
out:
|
||||
return rpc_success;
|
||||
|
||||
fail:
|
||||
posix_acl_release(resp->acl_access);
|
||||
posix_acl_release(resp->acl_default);
|
||||
RETURN_STATUS(nfserr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -95,14 +96,13 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp)
|
||||
struct nfsd_attrstat *resp = rqstp->rq_resp;
|
||||
struct inode *inode;
|
||||
svc_fh *fh;
|
||||
__be32 nfserr = 0;
|
||||
int error;
|
||||
|
||||
dprintk("nfsd: SETACL(2acl) %s\n", SVCFH_fmt(&argp->fh));
|
||||
|
||||
fh = fh_copy(&resp->fh, &argp->fh);
|
||||
nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR);
|
||||
if (nfserr)
|
||||
resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR);
|
||||
if (resp->status != nfs_ok)
|
||||
goto out;
|
||||
|
||||
inode = d_inode(fh->fh_dentry);
|
||||
@@ -124,19 +124,20 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst *rqstp)
|
||||
|
||||
fh_drop_write(fh);
|
||||
|
||||
nfserr = fh_getattr(fh, &resp->stat);
|
||||
resp->status = fh_getattr(fh, &resp->stat);
|
||||
|
||||
out:
|
||||
/* argp->acl_{access,default} may have been allocated in
|
||||
nfssvc_decode_setaclargs. */
|
||||
posix_acl_release(argp->acl_access);
|
||||
posix_acl_release(argp->acl_default);
|
||||
return nfserr;
|
||||
return rpc_success;
|
||||
|
||||
out_drop_lock:
|
||||
fh_unlock(fh);
|
||||
fh_drop_write(fh);
|
||||
out_errno:
|
||||
nfserr = nfserrno(error);
|
||||
resp->status = nfserrno(error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -147,15 +148,16 @@ static __be32 nfsacld_proc_getattr(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_fhandle *argp = rqstp->rq_argp;
|
||||
struct nfsd_attrstat *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh));
|
||||
|
||||
fh_copy(&resp->fh, &argp->fh);
|
||||
nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
|
||||
if (nfserr)
|
||||
return nfserr;
|
||||
nfserr = fh_getattr(&resp->fh, &resp->stat);
|
||||
return nfserr;
|
||||
resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
|
||||
if (resp->status != nfs_ok)
|
||||
goto out;
|
||||
resp->status = fh_getattr(&resp->fh, &resp->stat);
|
||||
out:
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -165,7 +167,6 @@ static __be32 nfsacld_proc_access(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_accessargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_accessres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: ACCESS(2acl) %s 0x%x\n",
|
||||
SVCFH_fmt(&argp->fh),
|
||||
@@ -173,16 +174,22 @@ static __be32 nfsacld_proc_access(struct svc_rqst *rqstp)
|
||||
|
||||
fh_copy(&resp->fh, &argp->fh);
|
||||
resp->access = argp->access;
|
||||
nfserr = nfsd_access(rqstp, &resp->fh, &resp->access, NULL);
|
||||
if (nfserr)
|
||||
return nfserr;
|
||||
nfserr = fh_getattr(&resp->fh, &resp->stat);
|
||||
return nfserr;
|
||||
resp->status = nfsd_access(rqstp, &resp->fh, &resp->access, NULL);
|
||||
if (resp->status != nfs_ok)
|
||||
goto out;
|
||||
resp->status = fh_getattr(&resp->fh, &resp->stat);
|
||||
out:
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
* XDR decode functions
|
||||
*/
|
||||
static int nfsaclsvc_decode_voidarg(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int nfsaclsvc_decode_getaclargs(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nfsd3_getaclargs *argp = rqstp->rq_argp;
|
||||
@@ -268,6 +275,10 @@ static int nfsaclsvc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p)
|
||||
int n;
|
||||
int w;
|
||||
|
||||
*p++ = resp->status;
|
||||
if (resp->status != nfs_ok)
|
||||
return xdr_ressize_check(rqstp, p);
|
||||
|
||||
/*
|
||||
* Since this is version 2, the check for nfserr in
|
||||
* nfsd_dispatch actually ensures the following cannot happen.
|
||||
@@ -307,7 +318,12 @@ static int nfsaclsvc_encode_attrstatres(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nfsd_attrstat *resp = rqstp->rq_resp;
|
||||
|
||||
*p++ = resp->status;
|
||||
if (resp->status != nfs_ok)
|
||||
goto out;
|
||||
|
||||
p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat);
|
||||
out:
|
||||
return xdr_ressize_check(rqstp, p);
|
||||
}
|
||||
|
||||
@@ -316,8 +332,13 @@ static int nfsaclsvc_encode_accessres(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nfsd3_accessres *resp = rqstp->rq_resp;
|
||||
|
||||
*p++ = resp->status;
|
||||
if (resp->status != nfs_ok)
|
||||
goto out;
|
||||
|
||||
p = nfs2svc_encode_fattr(rqstp, p, &resp->fh, &resp->stat);
|
||||
*p++ = htonl(resp->access);
|
||||
out:
|
||||
return xdr_ressize_check(rqstp, p);
|
||||
}
|
||||
|
||||
@@ -347,36 +368,63 @@ static void nfsaclsvc_release_access(struct svc_rqst *rqstp)
|
||||
fh_put(&resp->fh);
|
||||
}
|
||||
|
||||
#define nfsaclsvc_decode_voidargs NULL
|
||||
#define nfsaclsvc_release_void NULL
|
||||
#define nfsd3_fhandleargs nfsd_fhandle
|
||||
#define nfsd3_attrstatres nfsd_attrstat
|
||||
#define nfsd3_voidres nfsd3_voidargs
|
||||
struct nfsd3_voidargs { int dummy; };
|
||||
|
||||
#define PROC(name, argt, rest, relt, cache, respsize) \
|
||||
{ \
|
||||
.pc_func = nfsacld_proc_##name, \
|
||||
.pc_decode = nfsaclsvc_decode_##argt##args, \
|
||||
.pc_encode = nfsaclsvc_encode_##rest##res, \
|
||||
.pc_release = nfsaclsvc_release_##relt, \
|
||||
.pc_argsize = sizeof(struct nfsd3_##argt##args), \
|
||||
.pc_ressize = sizeof(struct nfsd3_##rest##res), \
|
||||
.pc_cachetype = cache, \
|
||||
.pc_xdrressize = respsize, \
|
||||
}
|
||||
|
||||
#define ST 1 /* status*/
|
||||
#define AT 21 /* attributes */
|
||||
#define pAT (1+AT) /* post attributes - conditional */
|
||||
#define ACL (1+NFS_ACL_MAX_ENTRIES*3) /* Access Control List */
|
||||
|
||||
static const struct svc_procedure nfsd_acl_procedures2[] = {
|
||||
PROC(null, void, void, void, RC_NOCACHE, ST),
|
||||
PROC(getacl, getacl, getacl, getacl, RC_NOCACHE, ST+1+2*(1+ACL)),
|
||||
PROC(setacl, setacl, attrstat, attrstat, RC_NOCACHE, ST+AT),
|
||||
PROC(getattr, fhandle, attrstat, attrstat, RC_NOCACHE, ST+AT),
|
||||
PROC(access, access, access, access, RC_NOCACHE, ST+AT+1),
|
||||
static const struct svc_procedure nfsd_acl_procedures2[5] = {
|
||||
[ACLPROC2_NULL] = {
|
||||
.pc_func = nfsacld_proc_null,
|
||||
.pc_decode = nfsaclsvc_decode_voidarg,
|
||||
.pc_encode = nfsaclsvc_encode_voidres,
|
||||
.pc_argsize = sizeof(struct nfsd3_voidargs),
|
||||
.pc_ressize = sizeof(struct nfsd3_voidargs),
|
||||
.pc_cachetype = RC_NOCACHE,
|
||||
.pc_xdrressize = ST,
|
||||
},
|
||||
[ACLPROC2_GETACL] = {
|
||||
.pc_func = nfsacld_proc_getacl,
|
||||
.pc_decode = nfsaclsvc_decode_getaclargs,
|
||||
.pc_encode = nfsaclsvc_encode_getaclres,
|
||||
.pc_release = nfsaclsvc_release_getacl,
|
||||
.pc_argsize = sizeof(struct nfsd3_getaclargs),
|
||||
.pc_ressize = sizeof(struct nfsd3_getaclres),
|
||||
.pc_cachetype = RC_NOCACHE,
|
||||
.pc_xdrressize = ST+1+2*(1+ACL),
|
||||
},
|
||||
[ACLPROC2_SETACL] = {
|
||||
.pc_func = nfsacld_proc_setacl,
|
||||
.pc_decode = nfsaclsvc_decode_setaclargs,
|
||||
.pc_encode = nfsaclsvc_encode_attrstatres,
|
||||
.pc_release = nfsaclsvc_release_attrstat,
|
||||
.pc_argsize = sizeof(struct nfsd3_setaclargs),
|
||||
.pc_ressize = sizeof(struct nfsd_attrstat),
|
||||
.pc_cachetype = RC_NOCACHE,
|
||||
.pc_xdrressize = ST+AT,
|
||||
},
|
||||
[ACLPROC2_GETATTR] = {
|
||||
.pc_func = nfsacld_proc_getattr,
|
||||
.pc_decode = nfsaclsvc_decode_fhandleargs,
|
||||
.pc_encode = nfsaclsvc_encode_attrstatres,
|
||||
.pc_release = nfsaclsvc_release_attrstat,
|
||||
.pc_argsize = sizeof(struct nfsd_fhandle),
|
||||
.pc_ressize = sizeof(struct nfsd_attrstat),
|
||||
.pc_cachetype = RC_NOCACHE,
|
||||
.pc_xdrressize = ST+AT,
|
||||
},
|
||||
[ACLPROC2_ACCESS] = {
|
||||
.pc_func = nfsacld_proc_access,
|
||||
.pc_decode = nfsaclsvc_decode_accessargs,
|
||||
.pc_encode = nfsaclsvc_encode_accessres,
|
||||
.pc_release = nfsaclsvc_release_access,
|
||||
.pc_argsize = sizeof(struct nfsd3_accessargs),
|
||||
.pc_ressize = sizeof(struct nfsd3_accessres),
|
||||
.pc_cachetype = RC_NOCACHE,
|
||||
.pc_xdrressize = ST+AT+1,
|
||||
},
|
||||
};
|
||||
|
||||
static unsigned int nfsd_acl_count2[ARRAY_SIZE(nfsd_acl_procedures2)];
|
||||
|
||||
+49
-39
@@ -13,15 +13,13 @@
|
||||
#include "xdr3.h"
|
||||
#include "vfs.h"
|
||||
|
||||
#define RETURN_STATUS(st) { resp->status = (st); return (st); }
|
||||
|
||||
/*
|
||||
* NULL call.
|
||||
*/
|
||||
static __be32
|
||||
nfsd3_proc_null(struct svc_rqst *rqstp)
|
||||
{
|
||||
return nfs_ok;
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -34,17 +32,18 @@ static __be32 nfsd3_proc_getacl(struct svc_rqst *rqstp)
|
||||
struct posix_acl *acl;
|
||||
struct inode *inode;
|
||||
svc_fh *fh;
|
||||
__be32 nfserr = 0;
|
||||
|
||||
fh = fh_copy(&resp->fh, &argp->fh);
|
||||
nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
|
||||
if (nfserr)
|
||||
RETURN_STATUS(nfserr);
|
||||
resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_NOP);
|
||||
if (resp->status != nfs_ok)
|
||||
goto out;
|
||||
|
||||
inode = d_inode(fh->fh_dentry);
|
||||
|
||||
if (argp->mask & ~NFS_ACL_MASK)
|
||||
RETURN_STATUS(nfserr_inval);
|
||||
if (argp->mask & ~NFS_ACL_MASK) {
|
||||
resp->status = nfserr_inval;
|
||||
goto out;
|
||||
}
|
||||
resp->mask = argp->mask;
|
||||
|
||||
if (resp->mask & (NFS_ACL|NFS_ACLCNT)) {
|
||||
@@ -54,7 +53,7 @@ static __be32 nfsd3_proc_getacl(struct svc_rqst *rqstp)
|
||||
acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
|
||||
}
|
||||
if (IS_ERR(acl)) {
|
||||
nfserr = nfserrno(PTR_ERR(acl));
|
||||
resp->status = nfserrno(PTR_ERR(acl));
|
||||
goto fail;
|
||||
}
|
||||
resp->acl_access = acl;
|
||||
@@ -64,19 +63,20 @@ static __be32 nfsd3_proc_getacl(struct svc_rqst *rqstp)
|
||||
of a non-directory! */
|
||||
acl = get_acl(inode, ACL_TYPE_DEFAULT);
|
||||
if (IS_ERR(acl)) {
|
||||
nfserr = nfserrno(PTR_ERR(acl));
|
||||
resp->status = nfserrno(PTR_ERR(acl));
|
||||
goto fail;
|
||||
}
|
||||
resp->acl_default = acl;
|
||||
}
|
||||
|
||||
/* resp->acl_{access,default} are released in nfs3svc_release_getacl. */
|
||||
RETURN_STATUS(0);
|
||||
out:
|
||||
return rpc_success;
|
||||
|
||||
fail:
|
||||
posix_acl_release(resp->acl_access);
|
||||
posix_acl_release(resp->acl_default);
|
||||
RETURN_STATUS(nfserr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -88,12 +88,11 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst *rqstp)
|
||||
struct nfsd3_attrstat *resp = rqstp->rq_resp;
|
||||
struct inode *inode;
|
||||
svc_fh *fh;
|
||||
__be32 nfserr = 0;
|
||||
int error;
|
||||
|
||||
fh = fh_copy(&resp->fh, &argp->fh);
|
||||
nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR);
|
||||
if (nfserr)
|
||||
resp->status = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR);
|
||||
if (resp->status != nfs_ok)
|
||||
goto out;
|
||||
|
||||
inode = d_inode(fh->fh_dentry);
|
||||
@@ -113,13 +112,13 @@ out_drop_lock:
|
||||
fh_unlock(fh);
|
||||
fh_drop_write(fh);
|
||||
out_errno:
|
||||
nfserr = nfserrno(error);
|
||||
resp->status = nfserrno(error);
|
||||
out:
|
||||
/* argp->acl_{access,default} may have been allocated in
|
||||
nfs3svc_decode_setaclargs. */
|
||||
posix_acl_release(argp->acl_access);
|
||||
posix_acl_release(argp->acl_default);
|
||||
RETURN_STATUS(nfserr);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -174,6 +173,7 @@ static int nfs3svc_encode_getaclres(struct svc_rqst *rqstp, __be32 *p)
|
||||
struct nfsd3_getaclres *resp = rqstp->rq_resp;
|
||||
struct dentry *dentry = resp->fh.fh_dentry;
|
||||
|
||||
*p++ = resp->status;
|
||||
p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh);
|
||||
if (resp->status == 0 && dentry && d_really_is_positive(dentry)) {
|
||||
struct inode *inode = d_inode(dentry);
|
||||
@@ -218,8 +218,8 @@ static int nfs3svc_encode_setaclres(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nfsd3_attrstat *resp = rqstp->rq_resp;
|
||||
|
||||
*p++ = resp->status;
|
||||
p = nfs3svc_encode_post_op_attr(rqstp, p, &resp->fh);
|
||||
|
||||
return xdr_ressize_check(rqstp, p);
|
||||
}
|
||||
|
||||
@@ -235,33 +235,43 @@ static void nfs3svc_release_getacl(struct svc_rqst *rqstp)
|
||||
posix_acl_release(resp->acl_default);
|
||||
}
|
||||
|
||||
#define nfs3svc_decode_voidargs NULL
|
||||
#define nfs3svc_release_void NULL
|
||||
#define nfsd3_setaclres nfsd3_attrstat
|
||||
#define nfsd3_voidres nfsd3_voidargs
|
||||
struct nfsd3_voidargs { int dummy; };
|
||||
|
||||
#define PROC(name, argt, rest, relt, cache, respsize) \
|
||||
{ \
|
||||
.pc_func = nfsd3_proc_##name, \
|
||||
.pc_decode = nfs3svc_decode_##argt##args, \
|
||||
.pc_encode = nfs3svc_encode_##rest##res, \
|
||||
.pc_release = nfs3svc_release_##relt, \
|
||||
.pc_argsize = sizeof(struct nfsd3_##argt##args), \
|
||||
.pc_ressize = sizeof(struct nfsd3_##rest##res), \
|
||||
.pc_cachetype = cache, \
|
||||
.pc_xdrressize = respsize, \
|
||||
}
|
||||
|
||||
#define ST 1 /* status*/
|
||||
#define AT 21 /* attributes */
|
||||
#define pAT (1+AT) /* post attributes - conditional */
|
||||
#define ACL (1+NFS_ACL_MAX_ENTRIES*3) /* Access Control List */
|
||||
|
||||
static const struct svc_procedure nfsd_acl_procedures3[] = {
|
||||
PROC(null, void, void, void, RC_NOCACHE, ST),
|
||||
PROC(getacl, getacl, getacl, getacl, RC_NOCACHE, ST+1+2*(1+ACL)),
|
||||
PROC(setacl, setacl, setacl, fhandle, RC_NOCACHE, ST+pAT),
|
||||
static const struct svc_procedure nfsd_acl_procedures3[3] = {
|
||||
[ACLPROC3_NULL] = {
|
||||
.pc_func = nfsd3_proc_null,
|
||||
.pc_decode = nfs3svc_decode_voidarg,
|
||||
.pc_encode = nfs3svc_encode_voidres,
|
||||
.pc_argsize = sizeof(struct nfsd3_voidargs),
|
||||
.pc_ressize = sizeof(struct nfsd3_voidargs),
|
||||
.pc_cachetype = RC_NOCACHE,
|
||||
.pc_xdrressize = ST,
|
||||
},
|
||||
[ACLPROC3_GETACL] = {
|
||||
.pc_func = nfsd3_proc_getacl,
|
||||
.pc_decode = nfs3svc_decode_getaclargs,
|
||||
.pc_encode = nfs3svc_encode_getaclres,
|
||||
.pc_release = nfs3svc_release_getacl,
|
||||
.pc_argsize = sizeof(struct nfsd3_getaclargs),
|
||||
.pc_ressize = sizeof(struct nfsd3_getaclres),
|
||||
.pc_cachetype = RC_NOCACHE,
|
||||
.pc_xdrressize = ST+1+2*(1+ACL),
|
||||
},
|
||||
[ACLPROC3_SETACL] = {
|
||||
.pc_func = nfsd3_proc_setacl,
|
||||
.pc_decode = nfs3svc_decode_setaclargs,
|
||||
.pc_encode = nfs3svc_encode_setaclres,
|
||||
.pc_release = nfs3svc_release_fhandle,
|
||||
.pc_argsize = sizeof(struct nfsd3_setaclargs),
|
||||
.pc_ressize = sizeof(struct nfsd3_attrstat),
|
||||
.pc_cachetype = RC_NOCACHE,
|
||||
.pc_xdrressize = ST+pAT,
|
||||
},
|
||||
};
|
||||
|
||||
static unsigned int nfsd_acl_count3[ARRAY_SIZE(nfsd_acl_procedures3)];
|
||||
|
||||
+115
-121
@@ -15,8 +15,6 @@
|
||||
|
||||
#define NFSDDBG_FACILITY NFSDDBG_PROC
|
||||
|
||||
#define RETURN_STATUS(st) { resp->status = (st); return (st); }
|
||||
|
||||
static int nfs3_ftypes[] = {
|
||||
0, /* NF3NON */
|
||||
S_IFREG, /* NF3REG */
|
||||
@@ -34,7 +32,7 @@ static int nfs3_ftypes[] = {
|
||||
static __be32
|
||||
nfsd3_proc_null(struct svc_rqst *rqstp)
|
||||
{
|
||||
return nfs_ok;
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -45,20 +43,19 @@ nfsd3_proc_getattr(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_fhandle *argp = rqstp->rq_argp;
|
||||
struct nfsd3_attrstat *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: GETATTR(3) %s\n",
|
||||
SVCFH_fmt(&argp->fh));
|
||||
|
||||
fh_copy(&resp->fh, &argp->fh);
|
||||
nfserr = fh_verify(rqstp, &resp->fh, 0,
|
||||
NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
|
||||
if (nfserr)
|
||||
RETURN_STATUS(nfserr);
|
||||
resp->status = fh_verify(rqstp, &resp->fh, 0,
|
||||
NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
|
||||
if (resp->status != nfs_ok)
|
||||
goto out;
|
||||
|
||||
nfserr = fh_getattr(&resp->fh, &resp->stat);
|
||||
|
||||
RETURN_STATUS(nfserr);
|
||||
resp->status = fh_getattr(&resp->fh, &resp->stat);
|
||||
out:
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -69,15 +66,14 @@ nfsd3_proc_setattr(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_sattrargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_attrstat *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: SETATTR(3) %s\n",
|
||||
SVCFH_fmt(&argp->fh));
|
||||
|
||||
fh_copy(&resp->fh, &argp->fh);
|
||||
nfserr = nfsd_setattr(rqstp, &resp->fh, &argp->attrs,
|
||||
argp->check_guard, argp->guardtime);
|
||||
RETURN_STATUS(nfserr);
|
||||
resp->status = nfsd_setattr(rqstp, &resp->fh, &argp->attrs,
|
||||
argp->check_guard, argp->guardtime);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -88,7 +84,6 @@ nfsd3_proc_lookup(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_diropargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_diropres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: LOOKUP(3) %s %.*s\n",
|
||||
SVCFH_fmt(&argp->fh),
|
||||
@@ -98,11 +93,10 @@ nfsd3_proc_lookup(struct svc_rqst *rqstp)
|
||||
fh_copy(&resp->dirfh, &argp->fh);
|
||||
fh_init(&resp->fh, NFS3_FHSIZE);
|
||||
|
||||
nfserr = nfsd_lookup(rqstp, &resp->dirfh,
|
||||
argp->name,
|
||||
argp->len,
|
||||
&resp->fh);
|
||||
RETURN_STATUS(nfserr);
|
||||
resp->status = nfsd_lookup(rqstp, &resp->dirfh,
|
||||
argp->name, argp->len,
|
||||
&resp->fh);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -113,7 +107,6 @@ nfsd3_proc_access(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_accessargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_accessres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: ACCESS(3) %s 0x%x\n",
|
||||
SVCFH_fmt(&argp->fh),
|
||||
@@ -121,8 +114,8 @@ nfsd3_proc_access(struct svc_rqst *rqstp)
|
||||
|
||||
fh_copy(&resp->fh, &argp->fh);
|
||||
resp->access = argp->access;
|
||||
nfserr = nfsd_access(rqstp, &resp->fh, &resp->access, NULL);
|
||||
RETURN_STATUS(nfserr);
|
||||
resp->status = nfsd_access(rqstp, &resp->fh, &resp->access, NULL);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -133,15 +126,14 @@ nfsd3_proc_readlink(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_readlinkargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_readlinkres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: READLINK(3) %s\n", SVCFH_fmt(&argp->fh));
|
||||
|
||||
/* Read the symlink. */
|
||||
fh_copy(&resp->fh, &argp->fh);
|
||||
resp->len = NFS3_MAXPATHLEN;
|
||||
nfserr = nfsd_readlink(rqstp, &resp->fh, argp->buffer, &resp->len);
|
||||
RETURN_STATUS(nfserr);
|
||||
resp->status = nfsd_readlink(rqstp, &resp->fh, argp->buffer, &resp->len);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -152,7 +144,6 @@ nfsd3_proc_read(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_readargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_readres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
u32 max_blocksize = svc_max_payload(rqstp);
|
||||
unsigned long cnt = min(argp->count, max_blocksize);
|
||||
|
||||
@@ -169,12 +160,10 @@ nfsd3_proc_read(struct svc_rqst *rqstp)
|
||||
svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4);
|
||||
|
||||
fh_copy(&resp->fh, &argp->fh);
|
||||
nfserr = nfsd_read(rqstp, &resp->fh,
|
||||
argp->offset,
|
||||
rqstp->rq_vec, argp->vlen,
|
||||
&resp->count,
|
||||
&resp->eof);
|
||||
RETURN_STATUS(nfserr);
|
||||
resp->status = nfsd_read(rqstp, &resp->fh, argp->offset,
|
||||
rqstp->rq_vec, argp->vlen, &resp->count,
|
||||
&resp->eof);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -185,7 +174,6 @@ nfsd3_proc_write(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_writeargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_writeres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
unsigned long cnt = argp->len;
|
||||
unsigned int nvecs;
|
||||
|
||||
@@ -199,13 +187,16 @@ nfsd3_proc_write(struct svc_rqst *rqstp)
|
||||
resp->committed = argp->stable;
|
||||
nvecs = svc_fill_write_vector(rqstp, rqstp->rq_arg.pages,
|
||||
&argp->first, cnt);
|
||||
if (!nvecs)
|
||||
RETURN_STATUS(nfserr_io);
|
||||
nfserr = nfsd_write(rqstp, &resp->fh, argp->offset,
|
||||
rqstp->rq_vec, nvecs, &cnt,
|
||||
resp->committed, resp->verf);
|
||||
if (!nvecs) {
|
||||
resp->status = nfserr_io;
|
||||
goto out;
|
||||
}
|
||||
resp->status = nfsd_write(rqstp, &resp->fh, argp->offset,
|
||||
rqstp->rq_vec, nvecs, &cnt,
|
||||
resp->committed, resp->verf);
|
||||
resp->count = cnt;
|
||||
RETURN_STATUS(nfserr);
|
||||
out:
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -220,7 +211,6 @@ nfsd3_proc_create(struct svc_rqst *rqstp)
|
||||
struct nfsd3_diropres *resp = rqstp->rq_resp;
|
||||
svc_fh *dirfhp, *newfhp = NULL;
|
||||
struct iattr *attr;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: CREATE(3) %s %.*s\n",
|
||||
SVCFH_fmt(&argp->fh),
|
||||
@@ -241,11 +231,10 @@ nfsd3_proc_create(struct svc_rqst *rqstp)
|
||||
}
|
||||
|
||||
/* Now create the file and set attributes */
|
||||
nfserr = do_nfsd_create(rqstp, dirfhp, argp->name, argp->len,
|
||||
attr, newfhp,
|
||||
argp->createmode, (u32 *)argp->verf, NULL, NULL);
|
||||
|
||||
RETURN_STATUS(nfserr);
|
||||
resp->status = do_nfsd_create(rqstp, dirfhp, argp->name, argp->len,
|
||||
attr, newfhp, argp->createmode,
|
||||
(u32 *)argp->verf, NULL, NULL);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -256,7 +245,6 @@ nfsd3_proc_mkdir(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_createargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_diropres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: MKDIR(3) %s %.*s\n",
|
||||
SVCFH_fmt(&argp->fh),
|
||||
@@ -266,10 +254,10 @@ nfsd3_proc_mkdir(struct svc_rqst *rqstp)
|
||||
argp->attrs.ia_valid &= ~ATTR_SIZE;
|
||||
fh_copy(&resp->dirfh, &argp->fh);
|
||||
fh_init(&resp->fh, NFS3_FHSIZE);
|
||||
nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
|
||||
&argp->attrs, S_IFDIR, 0, &resp->fh);
|
||||
resp->status = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
|
||||
&argp->attrs, S_IFDIR, 0, &resp->fh);
|
||||
fh_unlock(&resp->dirfh);
|
||||
RETURN_STATUS(nfserr);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
static __be32
|
||||
@@ -277,18 +265,23 @@ nfsd3_proc_symlink(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_symlinkargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_diropres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
if (argp->tlen == 0)
|
||||
RETURN_STATUS(nfserr_inval);
|
||||
if (argp->tlen > NFS3_MAXPATHLEN)
|
||||
RETURN_STATUS(nfserr_nametoolong);
|
||||
if (argp->tlen == 0) {
|
||||
resp->status = nfserr_inval;
|
||||
goto out;
|
||||
}
|
||||
if (argp->tlen > NFS3_MAXPATHLEN) {
|
||||
resp->status = nfserr_nametoolong;
|
||||
goto out;
|
||||
}
|
||||
|
||||
argp->tname = svc_fill_symlink_pathname(rqstp, &argp->first,
|
||||
page_address(rqstp->rq_arg.pages[0]),
|
||||
argp->tlen);
|
||||
if (IS_ERR(argp->tname))
|
||||
RETURN_STATUS(nfserrno(PTR_ERR(argp->tname)));
|
||||
if (IS_ERR(argp->tname)) {
|
||||
resp->status = nfserrno(PTR_ERR(argp->tname));
|
||||
goto out;
|
||||
}
|
||||
|
||||
dprintk("nfsd: SYMLINK(3) %s %.*s -> %.*s\n",
|
||||
SVCFH_fmt(&argp->ffh),
|
||||
@@ -297,10 +290,11 @@ nfsd3_proc_symlink(struct svc_rqst *rqstp)
|
||||
|
||||
fh_copy(&resp->dirfh, &argp->ffh);
|
||||
fh_init(&resp->fh, NFS3_FHSIZE);
|
||||
nfserr = nfsd_symlink(rqstp, &resp->dirfh, argp->fname, argp->flen,
|
||||
argp->tname, &resp->fh);
|
||||
resp->status = nfsd_symlink(rqstp, &resp->dirfh, argp->fname,
|
||||
argp->flen, argp->tname, &resp->fh);
|
||||
kfree(argp->tname);
|
||||
RETURN_STATUS(nfserr);
|
||||
out:
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -311,7 +305,6 @@ nfsd3_proc_mknod(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_mknodargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_diropres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
int type;
|
||||
dev_t rdev = 0;
|
||||
|
||||
@@ -323,22 +316,28 @@ nfsd3_proc_mknod(struct svc_rqst *rqstp)
|
||||
fh_copy(&resp->dirfh, &argp->fh);
|
||||
fh_init(&resp->fh, NFS3_FHSIZE);
|
||||
|
||||
if (argp->ftype == 0 || argp->ftype >= NF3BAD)
|
||||
RETURN_STATUS(nfserr_inval);
|
||||
if (argp->ftype == 0 || argp->ftype >= NF3BAD) {
|
||||
resp->status = nfserr_inval;
|
||||
goto out;
|
||||
}
|
||||
if (argp->ftype == NF3CHR || argp->ftype == NF3BLK) {
|
||||
rdev = MKDEV(argp->major, argp->minor);
|
||||
if (MAJOR(rdev) != argp->major ||
|
||||
MINOR(rdev) != argp->minor)
|
||||
RETURN_STATUS(nfserr_inval);
|
||||
} else
|
||||
if (argp->ftype != NF3SOCK && argp->ftype != NF3FIFO)
|
||||
RETURN_STATUS(nfserr_inval);
|
||||
MINOR(rdev) != argp->minor) {
|
||||
resp->status = nfserr_inval;
|
||||
goto out;
|
||||
}
|
||||
} else if (argp->ftype != NF3SOCK && argp->ftype != NF3FIFO) {
|
||||
resp->status = nfserr_inval;
|
||||
goto out;
|
||||
}
|
||||
|
||||
type = nfs3_ftypes[argp->ftype];
|
||||
nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
|
||||
&argp->attrs, type, rdev, &resp->fh);
|
||||
resp->status = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
|
||||
&argp->attrs, type, rdev, &resp->fh);
|
||||
fh_unlock(&resp->dirfh);
|
||||
RETURN_STATUS(nfserr);
|
||||
out:
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -349,7 +348,6 @@ nfsd3_proc_remove(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_diropargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_attrstat *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: REMOVE(3) %s %.*s\n",
|
||||
SVCFH_fmt(&argp->fh),
|
||||
@@ -358,9 +356,10 @@ nfsd3_proc_remove(struct svc_rqst *rqstp)
|
||||
|
||||
/* Unlink. -S_IFDIR means file must not be a directory */
|
||||
fh_copy(&resp->fh, &argp->fh);
|
||||
nfserr = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR, argp->name, argp->len);
|
||||
resp->status = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR,
|
||||
argp->name, argp->len);
|
||||
fh_unlock(&resp->fh);
|
||||
RETURN_STATUS(nfserr);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -371,7 +370,6 @@ nfsd3_proc_rmdir(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_diropargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_attrstat *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: RMDIR(3) %s %.*s\n",
|
||||
SVCFH_fmt(&argp->fh),
|
||||
@@ -379,9 +377,10 @@ nfsd3_proc_rmdir(struct svc_rqst *rqstp)
|
||||
argp->name);
|
||||
|
||||
fh_copy(&resp->fh, &argp->fh);
|
||||
nfserr = nfsd_unlink(rqstp, &resp->fh, S_IFDIR, argp->name, argp->len);
|
||||
resp->status = nfsd_unlink(rqstp, &resp->fh, S_IFDIR,
|
||||
argp->name, argp->len);
|
||||
fh_unlock(&resp->fh);
|
||||
RETURN_STATUS(nfserr);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
static __be32
|
||||
@@ -389,7 +388,6 @@ nfsd3_proc_rename(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_renameargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_renameres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: RENAME(3) %s %.*s ->\n",
|
||||
SVCFH_fmt(&argp->ffh),
|
||||
@@ -402,9 +400,9 @@ nfsd3_proc_rename(struct svc_rqst *rqstp)
|
||||
|
||||
fh_copy(&resp->ffh, &argp->ffh);
|
||||
fh_copy(&resp->tfh, &argp->tfh);
|
||||
nfserr = nfsd_rename(rqstp, &resp->ffh, argp->fname, argp->flen,
|
||||
&resp->tfh, argp->tname, argp->tlen);
|
||||
RETURN_STATUS(nfserr);
|
||||
resp->status = nfsd_rename(rqstp, &resp->ffh, argp->fname, argp->flen,
|
||||
&resp->tfh, argp->tname, argp->tlen);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
static __be32
|
||||
@@ -412,7 +410,6 @@ nfsd3_proc_link(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_linkargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_linkres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: LINK(3) %s ->\n",
|
||||
SVCFH_fmt(&argp->ffh));
|
||||
@@ -423,9 +420,9 @@ nfsd3_proc_link(struct svc_rqst *rqstp)
|
||||
|
||||
fh_copy(&resp->fh, &argp->ffh);
|
||||
fh_copy(&resp->tfh, &argp->tfh);
|
||||
nfserr = nfsd_link(rqstp, &resp->tfh, argp->tname, argp->tlen,
|
||||
&resp->fh);
|
||||
RETURN_STATUS(nfserr);
|
||||
resp->status = nfsd_link(rqstp, &resp->tfh, argp->tname, argp->tlen,
|
||||
&resp->fh);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -436,7 +433,6 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_readdirargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_readdirres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
int count = 0;
|
||||
struct page **p;
|
||||
caddr_t page_addr = NULL;
|
||||
@@ -456,8 +452,8 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp)
|
||||
resp->common.err = nfs_ok;
|
||||
resp->buffer = argp->buffer;
|
||||
resp->rqstp = rqstp;
|
||||
nfserr = nfsd_readdir(rqstp, &resp->fh, (loff_t*) &argp->cookie,
|
||||
&resp->common, nfs3svc_encode_entry);
|
||||
resp->status = nfsd_readdir(rqstp, &resp->fh, (loff_t *)&argp->cookie,
|
||||
&resp->common, nfs3svc_encode_entry);
|
||||
memcpy(resp->verf, argp->verf, 8);
|
||||
count = 0;
|
||||
for (p = rqstp->rq_respages + 1; p < rqstp->rq_next_page; p++) {
|
||||
@@ -485,7 +481,7 @@ nfsd3_proc_readdir(struct svc_rqst *rqstp)
|
||||
resp->offset = NULL;
|
||||
}
|
||||
|
||||
RETURN_STATUS(nfserr);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -497,7 +493,6 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_readdirargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_readdirres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
int count = 0;
|
||||
loff_t offset;
|
||||
struct page **p;
|
||||
@@ -520,17 +515,17 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp)
|
||||
resp->rqstp = rqstp;
|
||||
offset = argp->cookie;
|
||||
|
||||
nfserr = fh_verify(rqstp, &resp->fh, S_IFDIR, NFSD_MAY_NOP);
|
||||
if (nfserr)
|
||||
RETURN_STATUS(nfserr);
|
||||
resp->status = fh_verify(rqstp, &resp->fh, S_IFDIR, NFSD_MAY_NOP);
|
||||
if (resp->status != nfs_ok)
|
||||
goto out;
|
||||
|
||||
if (resp->fh.fh_export->ex_flags & NFSEXP_NOREADDIRPLUS)
|
||||
RETURN_STATUS(nfserr_notsupp);
|
||||
if (resp->fh.fh_export->ex_flags & NFSEXP_NOREADDIRPLUS) {
|
||||
resp->status = nfserr_notsupp;
|
||||
goto out;
|
||||
}
|
||||
|
||||
nfserr = nfsd_readdir(rqstp, &resp->fh,
|
||||
&offset,
|
||||
&resp->common,
|
||||
nfs3svc_encode_entry_plus);
|
||||
resp->status = nfsd_readdir(rqstp, &resp->fh, &offset,
|
||||
&resp->common, nfs3svc_encode_entry_plus);
|
||||
memcpy(resp->verf, argp->verf, 8);
|
||||
for (p = rqstp->rq_respages + 1; p < rqstp->rq_next_page; p++) {
|
||||
page_addr = page_address(*p);
|
||||
@@ -555,7 +550,8 @@ nfsd3_proc_readdirplus(struct svc_rqst *rqstp)
|
||||
resp->offset = NULL;
|
||||
}
|
||||
|
||||
RETURN_STATUS(nfserr);
|
||||
out:
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -566,14 +562,13 @@ nfsd3_proc_fsstat(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_fhandle *argp = rqstp->rq_argp;
|
||||
struct nfsd3_fsstatres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: FSSTAT(3) %s\n",
|
||||
SVCFH_fmt(&argp->fh));
|
||||
|
||||
nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats, 0);
|
||||
resp->status = nfsd_statfs(rqstp, &argp->fh, &resp->stats, 0);
|
||||
fh_put(&argp->fh);
|
||||
RETURN_STATUS(nfserr);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -584,7 +579,6 @@ nfsd3_proc_fsinfo(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_fhandle *argp = rqstp->rq_argp;
|
||||
struct nfsd3_fsinfores *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
u32 max_blocksize = svc_max_payload(rqstp);
|
||||
|
||||
dprintk("nfsd: FSINFO(3) %s\n",
|
||||
@@ -600,13 +594,13 @@ nfsd3_proc_fsinfo(struct svc_rqst *rqstp)
|
||||
resp->f_maxfilesize = ~(u32) 0;
|
||||
resp->f_properties = NFS3_FSF_DEFAULT;
|
||||
|
||||
nfserr = fh_verify(rqstp, &argp->fh, 0,
|
||||
NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
|
||||
resp->status = fh_verify(rqstp, &argp->fh, 0,
|
||||
NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
|
||||
|
||||
/* Check special features of the file system. May request
|
||||
* different read/write sizes for file systems known to have
|
||||
* problems with large blocks */
|
||||
if (nfserr == 0) {
|
||||
if (resp->status == nfs_ok) {
|
||||
struct super_block *sb = argp->fh.fh_dentry->d_sb;
|
||||
|
||||
/* Note that we don't care for remote fs's here */
|
||||
@@ -617,7 +611,7 @@ nfsd3_proc_fsinfo(struct svc_rqst *rqstp)
|
||||
}
|
||||
|
||||
fh_put(&argp->fh);
|
||||
RETURN_STATUS(nfserr);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -628,7 +622,6 @@ nfsd3_proc_pathconf(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_fhandle *argp = rqstp->rq_argp;
|
||||
struct nfsd3_pathconfres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: PATHCONF(3) %s\n",
|
||||
SVCFH_fmt(&argp->fh));
|
||||
@@ -641,9 +634,9 @@ nfsd3_proc_pathconf(struct svc_rqst *rqstp)
|
||||
resp->p_case_insensitive = 0;
|
||||
resp->p_case_preserving = 1;
|
||||
|
||||
nfserr = fh_verify(rqstp, &argp->fh, 0, NFSD_MAY_NOP);
|
||||
resp->status = fh_verify(rqstp, &argp->fh, 0, NFSD_MAY_NOP);
|
||||
|
||||
if (nfserr == 0) {
|
||||
if (resp->status == nfs_ok) {
|
||||
struct super_block *sb = argp->fh.fh_dentry->d_sb;
|
||||
|
||||
/* Note that we don't care for remote fs's here */
|
||||
@@ -660,10 +653,9 @@ nfsd3_proc_pathconf(struct svc_rqst *rqstp)
|
||||
}
|
||||
|
||||
fh_put(&argp->fh);
|
||||
RETURN_STATUS(nfserr);
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Commit a file (range) to stable storage.
|
||||
*/
|
||||
@@ -672,21 +664,22 @@ nfsd3_proc_commit(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd3_commitargs *argp = rqstp->rq_argp;
|
||||
struct nfsd3_commitres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: COMMIT(3) %s %u@%Lu\n",
|
||||
SVCFH_fmt(&argp->fh),
|
||||
argp->count,
|
||||
(unsigned long long) argp->offset);
|
||||
|
||||
if (argp->offset > NFS_OFFSET_MAX)
|
||||
RETURN_STATUS(nfserr_inval);
|
||||
if (argp->offset > NFS_OFFSET_MAX) {
|
||||
resp->status = nfserr_inval;
|
||||
goto out;
|
||||
}
|
||||
|
||||
fh_copy(&resp->fh, &argp->fh);
|
||||
nfserr = nfsd_commit(rqstp, &resp->fh, argp->offset, argp->count,
|
||||
resp->verf);
|
||||
|
||||
RETURN_STATUS(nfserr);
|
||||
resp->status = nfsd_commit(rqstp, &resp->fh, argp->offset,
|
||||
argp->count, resp->verf);
|
||||
out:
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
|
||||
@@ -716,6 +709,7 @@ struct nfsd3_voidargs { int dummy; };
|
||||
static const struct svc_procedure nfsd_procedures3[22] = {
|
||||
[NFS3PROC_NULL] = {
|
||||
.pc_func = nfsd3_proc_null,
|
||||
.pc_decode = nfs3svc_decode_voidarg,
|
||||
.pc_encode = nfs3svc_encode_voidres,
|
||||
.pc_argsize = sizeof(struct nfsd3_voidargs),
|
||||
.pc_ressize = sizeof(struct nfsd3_voidres),
|
||||
|
||||
+21
-4
@@ -304,6 +304,12 @@ void fill_post_wcc(struct svc_fh *fhp)
|
||||
/*
|
||||
* XDR decode functions
|
||||
*/
|
||||
int
|
||||
nfs3svc_decode_voidarg(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
nfs3svc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
@@ -635,10 +641,7 @@ nfs3svc_decode_commitargs(struct svc_rqst *rqstp, __be32 *p)
|
||||
/*
|
||||
* XDR encode functions
|
||||
*/
|
||||
/*
|
||||
* There must be an encoding function for void results so svc_process
|
||||
* will work properly.
|
||||
*/
|
||||
|
||||
int
|
||||
nfs3svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
@@ -651,6 +654,7 @@ nfs3svc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nfsd3_attrstat *resp = rqstp->rq_resp;
|
||||
|
||||
*p++ = resp->status;
|
||||
if (resp->status == 0) {
|
||||
lease_get_mtime(d_inode(resp->fh.fh_dentry),
|
||||
&resp->stat.mtime);
|
||||
@@ -665,6 +669,7 @@ nfs3svc_encode_wccstat(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nfsd3_attrstat *resp = rqstp->rq_resp;
|
||||
|
||||
*p++ = resp->status;
|
||||
p = encode_wcc_data(rqstp, p, &resp->fh);
|
||||
return xdr_ressize_check(rqstp, p);
|
||||
}
|
||||
@@ -675,6 +680,7 @@ nfs3svc_encode_diropres(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nfsd3_diropres *resp = rqstp->rq_resp;
|
||||
|
||||
*p++ = resp->status;
|
||||
if (resp->status == 0) {
|
||||
p = encode_fh(p, &resp->fh);
|
||||
p = encode_post_op_attr(rqstp, p, &resp->fh);
|
||||
@@ -689,6 +695,7 @@ nfs3svc_encode_accessres(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nfsd3_accessres *resp = rqstp->rq_resp;
|
||||
|
||||
*p++ = resp->status;
|
||||
p = encode_post_op_attr(rqstp, p, &resp->fh);
|
||||
if (resp->status == 0)
|
||||
*p++ = htonl(resp->access);
|
||||
@@ -701,6 +708,7 @@ nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nfsd3_readlinkres *resp = rqstp->rq_resp;
|
||||
|
||||
*p++ = resp->status;
|
||||
p = encode_post_op_attr(rqstp, p, &resp->fh);
|
||||
if (resp->status == 0) {
|
||||
*p++ = htonl(resp->len);
|
||||
@@ -723,6 +731,7 @@ nfs3svc_encode_readres(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nfsd3_readres *resp = rqstp->rq_resp;
|
||||
|
||||
*p++ = resp->status;
|
||||
p = encode_post_op_attr(rqstp, p, &resp->fh);
|
||||
if (resp->status == 0) {
|
||||
*p++ = htonl(resp->count);
|
||||
@@ -748,6 +757,7 @@ nfs3svc_encode_writeres(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nfsd3_writeres *resp = rqstp->rq_resp;
|
||||
|
||||
*p++ = resp->status;
|
||||
p = encode_wcc_data(rqstp, p, &resp->fh);
|
||||
if (resp->status == 0) {
|
||||
*p++ = htonl(resp->count);
|
||||
@@ -764,6 +774,7 @@ nfs3svc_encode_createres(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nfsd3_diropres *resp = rqstp->rq_resp;
|
||||
|
||||
*p++ = resp->status;
|
||||
if (resp->status == 0) {
|
||||
*p++ = xdr_one;
|
||||
p = encode_fh(p, &resp->fh);
|
||||
@@ -779,6 +790,7 @@ nfs3svc_encode_renameres(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nfsd3_renameres *resp = rqstp->rq_resp;
|
||||
|
||||
*p++ = resp->status;
|
||||
p = encode_wcc_data(rqstp, p, &resp->ffh);
|
||||
p = encode_wcc_data(rqstp, p, &resp->tfh);
|
||||
return xdr_ressize_check(rqstp, p);
|
||||
@@ -790,6 +802,7 @@ nfs3svc_encode_linkres(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nfsd3_linkres *resp = rqstp->rq_resp;
|
||||
|
||||
*p++ = resp->status;
|
||||
p = encode_post_op_attr(rqstp, p, &resp->fh);
|
||||
p = encode_wcc_data(rqstp, p, &resp->tfh);
|
||||
return xdr_ressize_check(rqstp, p);
|
||||
@@ -801,6 +814,7 @@ nfs3svc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nfsd3_readdirres *resp = rqstp->rq_resp;
|
||||
|
||||
*p++ = resp->status;
|
||||
p = encode_post_op_attr(rqstp, p, &resp->fh);
|
||||
|
||||
if (resp->status == 0) {
|
||||
@@ -1053,6 +1067,7 @@ nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, __be32 *p)
|
||||
struct kstatfs *s = &resp->stats;
|
||||
u64 bs = s->f_bsize;
|
||||
|
||||
*p++ = resp->status;
|
||||
*p++ = xdr_zero; /* no post_op_attr */
|
||||
|
||||
if (resp->status == 0) {
|
||||
@@ -1073,6 +1088,7 @@ nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nfsd3_fsinfores *resp = rqstp->rq_resp;
|
||||
|
||||
*p++ = resp->status;
|
||||
*p++ = xdr_zero; /* no post_op_attr */
|
||||
|
||||
if (resp->status == 0) {
|
||||
@@ -1118,6 +1134,7 @@ nfs3svc_encode_commitres(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nfsd3_commitres *resp = rqstp->rq_resp;
|
||||
|
||||
*p++ = resp->status;
|
||||
p = encode_wcc_data(rqstp, p, &resp->fh);
|
||||
/* Write verifier */
|
||||
if (resp->status == 0) {
|
||||
|
||||
+28
-6
@@ -38,6 +38,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/sunrpc/addr.h>
|
||||
#include <linux/nfs_ssc.h>
|
||||
|
||||
#include "idmap.h"
|
||||
#include "cache.h"
|
||||
@@ -1247,7 +1248,7 @@ out_err:
|
||||
static void
|
||||
nfsd4_interssc_disconnect(struct vfsmount *ss_mnt)
|
||||
{
|
||||
nfs_sb_deactive(ss_mnt->mnt_sb);
|
||||
nfs_do_sb_deactive(ss_mnt->mnt_sb);
|
||||
mntput(ss_mnt);
|
||||
}
|
||||
|
||||
@@ -2165,7 +2166,7 @@ nfsd4_removexattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
static __be32
|
||||
nfsd4_proc_null(struct svc_rqst *rqstp)
|
||||
{
|
||||
return nfs_ok;
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
static inline void nfsd4_increment_op_stats(u32 opnum)
|
||||
@@ -2457,15 +2458,14 @@ encode_op:
|
||||
nfsd4_increment_op_stats(op->opnum);
|
||||
}
|
||||
|
||||
cstate->status = status;
|
||||
fh_put(current_fh);
|
||||
fh_put(save_fh);
|
||||
BUG_ON(cstate->replay_owner);
|
||||
out:
|
||||
cstate->status = status;
|
||||
/* Reset deferral mechanism for RPC deferrals */
|
||||
set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags);
|
||||
dprintk("nfsv4 compound returned %d\n", ntohl(status));
|
||||
return status;
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
#define op_encode_hdr_size (2)
|
||||
@@ -2591,6 +2591,20 @@ static inline u32 nfsd4_read_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
||||
return (op_encode_hdr_size + 2 + XDR_QUADLEN(rlen)) * sizeof(__be32);
|
||||
}
|
||||
|
||||
static inline u32 nfsd4_read_plus_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
||||
{
|
||||
u32 maxcount = svc_max_payload(rqstp);
|
||||
u32 rlen = min(op->u.read.rd_length, maxcount);
|
||||
/*
|
||||
* If we detect that the file changed during hole encoding, then we
|
||||
* recover by encoding the remaining reply as data. This means we need
|
||||
* to set aside enough room to encode two data segments.
|
||||
*/
|
||||
u32 seg_len = 2 * (1 + 2 + 1);
|
||||
|
||||
return (op_encode_hdr_size + 2 + seg_len + XDR_QUADLEN(rlen)) * sizeof(__be32);
|
||||
}
|
||||
|
||||
static inline u32 nfsd4_readdir_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
||||
{
|
||||
u32 maxcount = 0, rlen = 0;
|
||||
@@ -3163,6 +3177,13 @@ static const struct nfsd4_operation nfsd4_ops[] = {
|
||||
.op_name = "OP_COPY",
|
||||
.op_rsize_bop = nfsd4_copy_rsize,
|
||||
},
|
||||
[OP_READ_PLUS] = {
|
||||
.op_func = nfsd4_read,
|
||||
.op_release = nfsd4_read_release,
|
||||
.op_name = "OP_READ_PLUS",
|
||||
.op_rsize_bop = nfsd4_read_plus_rsize,
|
||||
.op_get_currentstateid = nfsd4_get_readstateid,
|
||||
},
|
||||
[OP_SEEK] = {
|
||||
.op_func = nfsd4_seek,
|
||||
.op_name = "OP_SEEK",
|
||||
@@ -3231,7 +3252,7 @@ bool nfsd4_spo_must_allow(struct svc_rqst *rqstp)
|
||||
if (!cstate->minorversion)
|
||||
return false;
|
||||
|
||||
if (cstate->spo_must_allowed == true)
|
||||
if (cstate->spo_must_allowed)
|
||||
return true;
|
||||
|
||||
opiter = resp->opcnt;
|
||||
@@ -3279,6 +3300,7 @@ struct nfsd4_voidargs { int dummy; };
|
||||
static const struct svc_procedure nfsd_procedures4[2] = {
|
||||
[NFSPROC4_NULL] = {
|
||||
.pc_func = nfsd4_proc_null,
|
||||
.pc_decode = nfs4svc_decode_voidarg,
|
||||
.pc_encode = nfs4svc_encode_voidres,
|
||||
.pc_argsize = sizeof(struct nfsd4_voidargs),
|
||||
.pc_ressize = sizeof(struct nfsd4_voidres),
|
||||
|
||||
+6
-599
@@ -4513,7 +4513,8 @@ static int nfsd4_cb_recall_done(struct nfsd4_callback *cb,
|
||||
{
|
||||
struct nfs4_delegation *dp = cb_to_delegation(cb);
|
||||
|
||||
if (dp->dl_stid.sc_type == NFS4_CLOSED_DELEG_STID)
|
||||
if (dp->dl_stid.sc_type == NFS4_CLOSED_DELEG_STID ||
|
||||
dp->dl_stid.sc_type == NFS4_REVOKED_DELEG_STID)
|
||||
return 1;
|
||||
|
||||
switch (task->tk_status) {
|
||||
@@ -4597,7 +4598,8 @@ static bool nfsd_breaker_owns_lease(struct file_lock *fl)
|
||||
if (!i_am_nfsd())
|
||||
return NULL;
|
||||
rqst = kthread_data(current);
|
||||
if (!rqst->rq_lease_breaker)
|
||||
/* Note rq_prog == NFS_ACL_PROGRAM is also possible: */
|
||||
if (rqst->rq_prog != NFS_PROGRAM || rqst->rq_vers < 4)
|
||||
return NULL;
|
||||
clp = *(rqst->rq_lease_breaker);
|
||||
return dl->dl_stid.sc_client == clp;
|
||||
@@ -4954,7 +4956,6 @@ static int nfsd4_check_conflicting_opens(struct nfs4_client *clp,
|
||||
writes--;
|
||||
if (fp->fi_fds[O_RDWR])
|
||||
writes--;
|
||||
WARN_ON_ONCE(writes < 0);
|
||||
if (writes > 0)
|
||||
return -EAGAIN;
|
||||
spin_lock(&fp->fi_lock);
|
||||
@@ -5126,7 +5127,7 @@ nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open,
|
||||
|
||||
memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid));
|
||||
|
||||
trace_nfsd_deleg_open(&dp->dl_stid.sc_stateid);
|
||||
trace_nfsd_deleg_read(&dp->dl_stid.sc_stateid);
|
||||
open->op_delegate_type = NFS4_OPEN_DELEGATE_READ;
|
||||
nfs4_put_stid(&dp->dl_stid);
|
||||
return;
|
||||
@@ -5243,7 +5244,7 @@ nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nf
|
||||
nfs4_open_delegation(current_fh, open, stp);
|
||||
nodeleg:
|
||||
status = nfs_ok;
|
||||
trace_nfsd_deleg_none(&stp->st_stid.sc_stateid);
|
||||
trace_nfsd_open(&stp->st_stid.sc_stateid);
|
||||
out:
|
||||
/* 4.1 client trying to upgrade/downgrade delegation? */
|
||||
if (open->op_delegate_type == NFS4_OPEN_DELEGATE_NONE && dp &&
|
||||
@@ -5722,7 +5723,6 @@ nfs4_find_file(struct nfs4_stid *s, int flags)
|
||||
return find_readable_file(s->sc_file);
|
||||
else
|
||||
return find_writeable_file(s->sc_file);
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
@@ -7253,599 +7253,6 @@ nfs4_check_open_reclaim(clientid_t *clid,
|
||||
return nfs_ok;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NFSD_FAULT_INJECTION
|
||||
static inline void
|
||||
put_client(struct nfs4_client *clp)
|
||||
{
|
||||
atomic_dec(&clp->cl_rpc_users);
|
||||
}
|
||||
|
||||
static struct nfs4_client *
|
||||
nfsd_find_client(struct sockaddr_storage *addr, size_t addr_size)
|
||||
{
|
||||
struct nfs4_client *clp;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
|
||||
if (!nfsd_netns_ready(nn))
|
||||
return NULL;
|
||||
|
||||
list_for_each_entry(clp, &nn->client_lru, cl_lru) {
|
||||
if (memcmp(&clp->cl_addr, addr, addr_size) == 0)
|
||||
return clp;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u64
|
||||
nfsd_inject_print_clients(void)
|
||||
{
|
||||
struct nfs4_client *clp;
|
||||
u64 count = 0;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
char buf[INET6_ADDRSTRLEN];
|
||||
|
||||
if (!nfsd_netns_ready(nn))
|
||||
return 0;
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
list_for_each_entry(clp, &nn->client_lru, cl_lru) {
|
||||
rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf));
|
||||
pr_info("NFS Client: %s\n", buf);
|
||||
++count;
|
||||
}
|
||||
spin_unlock(&nn->client_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
u64
|
||||
nfsd_inject_forget_client(struct sockaddr_storage *addr, size_t addr_size)
|
||||
{
|
||||
u64 count = 0;
|
||||
struct nfs4_client *clp;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
|
||||
if (!nfsd_netns_ready(nn))
|
||||
return count;
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
clp = nfsd_find_client(addr, addr_size);
|
||||
if (clp) {
|
||||
if (mark_client_expired_locked(clp) == nfs_ok)
|
||||
++count;
|
||||
else
|
||||
clp = NULL;
|
||||
}
|
||||
spin_unlock(&nn->client_lock);
|
||||
|
||||
if (clp)
|
||||
expire_client(clp);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
u64
|
||||
nfsd_inject_forget_clients(u64 max)
|
||||
{
|
||||
u64 count = 0;
|
||||
struct nfs4_client *clp, *next;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
LIST_HEAD(reaplist);
|
||||
|
||||
if (!nfsd_netns_ready(nn))
|
||||
return count;
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) {
|
||||
if (mark_client_expired_locked(clp) == nfs_ok) {
|
||||
list_add(&clp->cl_lru, &reaplist);
|
||||
if (max != 0 && ++count >= max)
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock(&nn->client_lock);
|
||||
|
||||
list_for_each_entry_safe(clp, next, &reaplist, cl_lru)
|
||||
expire_client(clp);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static void nfsd_print_count(struct nfs4_client *clp, unsigned int count,
|
||||
const char *type)
|
||||
{
|
||||
char buf[INET6_ADDRSTRLEN];
|
||||
rpc_ntop((struct sockaddr *)&clp->cl_addr, buf, sizeof(buf));
|
||||
printk(KERN_INFO "NFS Client: %s has %u %s\n", buf, count, type);
|
||||
}
|
||||
|
||||
static void
|
||||
nfsd_inject_add_lock_to_list(struct nfs4_ol_stateid *lst,
|
||||
struct list_head *collect)
|
||||
{
|
||||
struct nfs4_client *clp = lst->st_stid.sc_client;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
|
||||
if (!collect)
|
||||
return;
|
||||
|
||||
lockdep_assert_held(&nn->client_lock);
|
||||
atomic_inc(&clp->cl_rpc_users);
|
||||
list_add(&lst->st_locks, collect);
|
||||
}
|
||||
|
||||
static u64 nfsd_foreach_client_lock(struct nfs4_client *clp, u64 max,
|
||||
struct list_head *collect,
|
||||
bool (*func)(struct nfs4_ol_stateid *))
|
||||
{
|
||||
struct nfs4_openowner *oop;
|
||||
struct nfs4_ol_stateid *stp, *st_next;
|
||||
struct nfs4_ol_stateid *lst, *lst_next;
|
||||
u64 count = 0;
|
||||
|
||||
spin_lock(&clp->cl_lock);
|
||||
list_for_each_entry(oop, &clp->cl_openowners, oo_perclient) {
|
||||
list_for_each_entry_safe(stp, st_next,
|
||||
&oop->oo_owner.so_stateids, st_perstateowner) {
|
||||
list_for_each_entry_safe(lst, lst_next,
|
||||
&stp->st_locks, st_locks) {
|
||||
if (func) {
|
||||
if (func(lst))
|
||||
nfsd_inject_add_lock_to_list(lst,
|
||||
collect);
|
||||
}
|
||||
++count;
|
||||
/*
|
||||
* Despite the fact that these functions deal
|
||||
* with 64-bit integers for "count", we must
|
||||
* ensure that it doesn't blow up the
|
||||
* clp->cl_rpc_users. Throw a warning if we
|
||||
* start to approach INT_MAX here.
|
||||
*/
|
||||
WARN_ON_ONCE(count == (INT_MAX / 2));
|
||||
if (count == max)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
}
|
||||
out:
|
||||
spin_unlock(&clp->cl_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static u64
|
||||
nfsd_collect_client_locks(struct nfs4_client *clp, struct list_head *collect,
|
||||
u64 max)
|
||||
{
|
||||
return nfsd_foreach_client_lock(clp, max, collect, unhash_lock_stateid);
|
||||
}
|
||||
|
||||
static u64
|
||||
nfsd_print_client_locks(struct nfs4_client *clp)
|
||||
{
|
||||
u64 count = nfsd_foreach_client_lock(clp, 0, NULL, NULL);
|
||||
nfsd_print_count(clp, count, "locked files");
|
||||
return count;
|
||||
}
|
||||
|
||||
u64
|
||||
nfsd_inject_print_locks(void)
|
||||
{
|
||||
struct nfs4_client *clp;
|
||||
u64 count = 0;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
|
||||
if (!nfsd_netns_ready(nn))
|
||||
return 0;
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
list_for_each_entry(clp, &nn->client_lru, cl_lru)
|
||||
count += nfsd_print_client_locks(clp);
|
||||
spin_unlock(&nn->client_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static void
|
||||
nfsd_reap_locks(struct list_head *reaplist)
|
||||
{
|
||||
struct nfs4_client *clp;
|
||||
struct nfs4_ol_stateid *stp, *next;
|
||||
|
||||
list_for_each_entry_safe(stp, next, reaplist, st_locks) {
|
||||
list_del_init(&stp->st_locks);
|
||||
clp = stp->st_stid.sc_client;
|
||||
nfs4_put_stid(&stp->st_stid);
|
||||
put_client(clp);
|
||||
}
|
||||
}
|
||||
|
||||
u64
|
||||
nfsd_inject_forget_client_locks(struct sockaddr_storage *addr, size_t addr_size)
|
||||
{
|
||||
unsigned int count = 0;
|
||||
struct nfs4_client *clp;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
LIST_HEAD(reaplist);
|
||||
|
||||
if (!nfsd_netns_ready(nn))
|
||||
return count;
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
clp = nfsd_find_client(addr, addr_size);
|
||||
if (clp)
|
||||
count = nfsd_collect_client_locks(clp, &reaplist, 0);
|
||||
spin_unlock(&nn->client_lock);
|
||||
nfsd_reap_locks(&reaplist);
|
||||
return count;
|
||||
}
|
||||
|
||||
u64
|
||||
nfsd_inject_forget_locks(u64 max)
|
||||
{
|
||||
u64 count = 0;
|
||||
struct nfs4_client *clp;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
LIST_HEAD(reaplist);
|
||||
|
||||
if (!nfsd_netns_ready(nn))
|
||||
return count;
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
list_for_each_entry(clp, &nn->client_lru, cl_lru) {
|
||||
count += nfsd_collect_client_locks(clp, &reaplist, max - count);
|
||||
if (max != 0 && count >= max)
|
||||
break;
|
||||
}
|
||||
spin_unlock(&nn->client_lock);
|
||||
nfsd_reap_locks(&reaplist);
|
||||
return count;
|
||||
}
|
||||
|
||||
static u64
|
||||
nfsd_foreach_client_openowner(struct nfs4_client *clp, u64 max,
|
||||
struct list_head *collect,
|
||||
void (*func)(struct nfs4_openowner *))
|
||||
{
|
||||
struct nfs4_openowner *oop, *next;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
u64 count = 0;
|
||||
|
||||
lockdep_assert_held(&nn->client_lock);
|
||||
|
||||
spin_lock(&clp->cl_lock);
|
||||
list_for_each_entry_safe(oop, next, &clp->cl_openowners, oo_perclient) {
|
||||
if (func) {
|
||||
func(oop);
|
||||
if (collect) {
|
||||
atomic_inc(&clp->cl_rpc_users);
|
||||
list_add(&oop->oo_perclient, collect);
|
||||
}
|
||||
}
|
||||
++count;
|
||||
/*
|
||||
* Despite the fact that these functions deal with
|
||||
* 64-bit integers for "count", we must ensure that
|
||||
* it doesn't blow up the clp->cl_rpc_users. Throw a
|
||||
* warning if we start to approach INT_MAX here.
|
||||
*/
|
||||
WARN_ON_ONCE(count == (INT_MAX / 2));
|
||||
if (count == max)
|
||||
break;
|
||||
}
|
||||
spin_unlock(&clp->cl_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static u64
|
||||
nfsd_print_client_openowners(struct nfs4_client *clp)
|
||||
{
|
||||
u64 count = nfsd_foreach_client_openowner(clp, 0, NULL, NULL);
|
||||
|
||||
nfsd_print_count(clp, count, "openowners");
|
||||
return count;
|
||||
}
|
||||
|
||||
static u64
|
||||
nfsd_collect_client_openowners(struct nfs4_client *clp,
|
||||
struct list_head *collect, u64 max)
|
||||
{
|
||||
return nfsd_foreach_client_openowner(clp, max, collect,
|
||||
unhash_openowner_locked);
|
||||
}
|
||||
|
||||
u64
|
||||
nfsd_inject_print_openowners(void)
|
||||
{
|
||||
struct nfs4_client *clp;
|
||||
u64 count = 0;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
|
||||
if (!nfsd_netns_ready(nn))
|
||||
return 0;
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
list_for_each_entry(clp, &nn->client_lru, cl_lru)
|
||||
count += nfsd_print_client_openowners(clp);
|
||||
spin_unlock(&nn->client_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static void
|
||||
nfsd_reap_openowners(struct list_head *reaplist)
|
||||
{
|
||||
struct nfs4_client *clp;
|
||||
struct nfs4_openowner *oop, *next;
|
||||
|
||||
list_for_each_entry_safe(oop, next, reaplist, oo_perclient) {
|
||||
list_del_init(&oop->oo_perclient);
|
||||
clp = oop->oo_owner.so_client;
|
||||
release_openowner(oop);
|
||||
put_client(clp);
|
||||
}
|
||||
}
|
||||
|
||||
u64
|
||||
nfsd_inject_forget_client_openowners(struct sockaddr_storage *addr,
|
||||
size_t addr_size)
|
||||
{
|
||||
unsigned int count = 0;
|
||||
struct nfs4_client *clp;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
LIST_HEAD(reaplist);
|
||||
|
||||
if (!nfsd_netns_ready(nn))
|
||||
return count;
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
clp = nfsd_find_client(addr, addr_size);
|
||||
if (clp)
|
||||
count = nfsd_collect_client_openowners(clp, &reaplist, 0);
|
||||
spin_unlock(&nn->client_lock);
|
||||
nfsd_reap_openowners(&reaplist);
|
||||
return count;
|
||||
}
|
||||
|
||||
u64
|
||||
nfsd_inject_forget_openowners(u64 max)
|
||||
{
|
||||
u64 count = 0;
|
||||
struct nfs4_client *clp;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
LIST_HEAD(reaplist);
|
||||
|
||||
if (!nfsd_netns_ready(nn))
|
||||
return count;
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
list_for_each_entry(clp, &nn->client_lru, cl_lru) {
|
||||
count += nfsd_collect_client_openowners(clp, &reaplist,
|
||||
max - count);
|
||||
if (max != 0 && count >= max)
|
||||
break;
|
||||
}
|
||||
spin_unlock(&nn->client_lock);
|
||||
nfsd_reap_openowners(&reaplist);
|
||||
return count;
|
||||
}
|
||||
|
||||
static u64 nfsd_find_all_delegations(struct nfs4_client *clp, u64 max,
|
||||
struct list_head *victims)
|
||||
{
|
||||
struct nfs4_delegation *dp, *next;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
u64 count = 0;
|
||||
|
||||
lockdep_assert_held(&nn->client_lock);
|
||||
|
||||
spin_lock(&state_lock);
|
||||
list_for_each_entry_safe(dp, next, &clp->cl_delegations, dl_perclnt) {
|
||||
if (victims) {
|
||||
/*
|
||||
* It's not safe to mess with delegations that have a
|
||||
* non-zero dl_time. They might have already been broken
|
||||
* and could be processed by the laundromat outside of
|
||||
* the state_lock. Just leave them be.
|
||||
*/
|
||||
if (dp->dl_time != 0)
|
||||
continue;
|
||||
|
||||
atomic_inc(&clp->cl_rpc_users);
|
||||
WARN_ON(!unhash_delegation_locked(dp));
|
||||
list_add(&dp->dl_recall_lru, victims);
|
||||
}
|
||||
++count;
|
||||
/*
|
||||
* Despite the fact that these functions deal with
|
||||
* 64-bit integers for "count", we must ensure that
|
||||
* it doesn't blow up the clp->cl_rpc_users. Throw a
|
||||
* warning if we start to approach INT_MAX here.
|
||||
*/
|
||||
WARN_ON_ONCE(count == (INT_MAX / 2));
|
||||
if (count == max)
|
||||
break;
|
||||
}
|
||||
spin_unlock(&state_lock);
|
||||
return count;
|
||||
}
|
||||
|
||||
static u64
|
||||
nfsd_print_client_delegations(struct nfs4_client *clp)
|
||||
{
|
||||
u64 count = nfsd_find_all_delegations(clp, 0, NULL);
|
||||
|
||||
nfsd_print_count(clp, count, "delegations");
|
||||
return count;
|
||||
}
|
||||
|
||||
u64
|
||||
nfsd_inject_print_delegations(void)
|
||||
{
|
||||
struct nfs4_client *clp;
|
||||
u64 count = 0;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
|
||||
if (!nfsd_netns_ready(nn))
|
||||
return 0;
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
list_for_each_entry(clp, &nn->client_lru, cl_lru)
|
||||
count += nfsd_print_client_delegations(clp);
|
||||
spin_unlock(&nn->client_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static void
|
||||
nfsd_forget_delegations(struct list_head *reaplist)
|
||||
{
|
||||
struct nfs4_client *clp;
|
||||
struct nfs4_delegation *dp, *next;
|
||||
|
||||
list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) {
|
||||
list_del_init(&dp->dl_recall_lru);
|
||||
clp = dp->dl_stid.sc_client;
|
||||
revoke_delegation(dp);
|
||||
put_client(clp);
|
||||
}
|
||||
}
|
||||
|
||||
u64
|
||||
nfsd_inject_forget_client_delegations(struct sockaddr_storage *addr,
|
||||
size_t addr_size)
|
||||
{
|
||||
u64 count = 0;
|
||||
struct nfs4_client *clp;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
LIST_HEAD(reaplist);
|
||||
|
||||
if (!nfsd_netns_ready(nn))
|
||||
return count;
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
clp = nfsd_find_client(addr, addr_size);
|
||||
if (clp)
|
||||
count = nfsd_find_all_delegations(clp, 0, &reaplist);
|
||||
spin_unlock(&nn->client_lock);
|
||||
|
||||
nfsd_forget_delegations(&reaplist);
|
||||
return count;
|
||||
}
|
||||
|
||||
u64
|
||||
nfsd_inject_forget_delegations(u64 max)
|
||||
{
|
||||
u64 count = 0;
|
||||
struct nfs4_client *clp;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
LIST_HEAD(reaplist);
|
||||
|
||||
if (!nfsd_netns_ready(nn))
|
||||
return count;
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
list_for_each_entry(clp, &nn->client_lru, cl_lru) {
|
||||
count += nfsd_find_all_delegations(clp, max - count, &reaplist);
|
||||
if (max != 0 && count >= max)
|
||||
break;
|
||||
}
|
||||
spin_unlock(&nn->client_lock);
|
||||
nfsd_forget_delegations(&reaplist);
|
||||
return count;
|
||||
}
|
||||
|
||||
static void
|
||||
nfsd_recall_delegations(struct list_head *reaplist)
|
||||
{
|
||||
struct nfs4_client *clp;
|
||||
struct nfs4_delegation *dp, *next;
|
||||
|
||||
list_for_each_entry_safe(dp, next, reaplist, dl_recall_lru) {
|
||||
list_del_init(&dp->dl_recall_lru);
|
||||
clp = dp->dl_stid.sc_client;
|
||||
|
||||
trace_nfsd_deleg_recall(&dp->dl_stid.sc_stateid);
|
||||
|
||||
/*
|
||||
* We skipped all entries that had a zero dl_time before,
|
||||
* so we can now reset the dl_time back to 0. If a delegation
|
||||
* break comes in now, then it won't make any difference since
|
||||
* we're recalling it either way.
|
||||
*/
|
||||
spin_lock(&state_lock);
|
||||
dp->dl_time = 0;
|
||||
spin_unlock(&state_lock);
|
||||
nfsd_break_one_deleg(dp);
|
||||
put_client(clp);
|
||||
}
|
||||
}
|
||||
|
||||
u64
|
||||
nfsd_inject_recall_client_delegations(struct sockaddr_storage *addr,
|
||||
size_t addr_size)
|
||||
{
|
||||
u64 count = 0;
|
||||
struct nfs4_client *clp;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
LIST_HEAD(reaplist);
|
||||
|
||||
if (!nfsd_netns_ready(nn))
|
||||
return count;
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
clp = nfsd_find_client(addr, addr_size);
|
||||
if (clp)
|
||||
count = nfsd_find_all_delegations(clp, 0, &reaplist);
|
||||
spin_unlock(&nn->client_lock);
|
||||
|
||||
nfsd_recall_delegations(&reaplist);
|
||||
return count;
|
||||
}
|
||||
|
||||
u64
|
||||
nfsd_inject_recall_delegations(u64 max)
|
||||
{
|
||||
u64 count = 0;
|
||||
struct nfs4_client *clp, *next;
|
||||
struct nfsd_net *nn = net_generic(current->nsproxy->net_ns,
|
||||
nfsd_net_id);
|
||||
LIST_HEAD(reaplist);
|
||||
|
||||
if (!nfsd_netns_ready(nn))
|
||||
return count;
|
||||
|
||||
spin_lock(&nn->client_lock);
|
||||
list_for_each_entry_safe(clp, next, &nn->client_lru, cl_lru) {
|
||||
count += nfsd_find_all_delegations(clp, max - count, &reaplist);
|
||||
if (max != 0 && ++count >= max)
|
||||
break;
|
||||
}
|
||||
spin_unlock(&nn->client_lock);
|
||||
nfsd_recall_delegations(&reaplist);
|
||||
return count;
|
||||
}
|
||||
#endif /* CONFIG_NFSD_FAULT_INJECTION */
|
||||
|
||||
/*
|
||||
* Since the lifetime of a delegation isn't limited to that of an open, a
|
||||
* client may quite reasonably hang on to a delegation as long as it has
|
||||
|
||||
+164
-38
@@ -1855,7 +1855,7 @@ static __be32
|
||||
nfsd4_decode_copy_notify(struct nfsd4_compoundargs *argp,
|
||||
struct nfsd4_copy_notify *cn)
|
||||
{
|
||||
int status;
|
||||
__be32 status;
|
||||
|
||||
status = nfsd4_decode_stateid(argp, &cn->cpn_src_stateid);
|
||||
if (status)
|
||||
@@ -2173,7 +2173,7 @@ static const nfsd4_dec nfsd4_dec_ops[] = {
|
||||
[OP_LAYOUTSTATS] = (nfsd4_dec)nfsd4_decode_notsupp,
|
||||
[OP_OFFLOAD_CANCEL] = (nfsd4_dec)nfsd4_decode_offload_status,
|
||||
[OP_OFFLOAD_STATUS] = (nfsd4_dec)nfsd4_decode_offload_status,
|
||||
[OP_READ_PLUS] = (nfsd4_dec)nfsd4_decode_notsupp,
|
||||
[OP_READ_PLUS] = (nfsd4_dec)nfsd4_decode_read,
|
||||
[OP_SEEK] = (nfsd4_dec)nfsd4_decode_seek,
|
||||
[OP_WRITE_SAME] = (nfsd4_dec)nfsd4_decode_notsupp,
|
||||
[OP_CLONE] = (nfsd4_dec)nfsd4_decode_clone,
|
||||
@@ -2261,7 +2261,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp)
|
||||
*/
|
||||
cachethis |= nfsd4_cache_this_op(op);
|
||||
|
||||
if (op->opnum == OP_READ) {
|
||||
if (op->opnum == OP_READ || op->opnum == OP_READ_PLUS) {
|
||||
readcount++;
|
||||
readbytes += nfsd4_max_reply(argp->rqstp, op);
|
||||
} else
|
||||
@@ -3814,36 +3814,14 @@ static __be32 nfsd4_encode_readv(struct nfsd4_compoundres *resp,
|
||||
{
|
||||
struct xdr_stream *xdr = &resp->xdr;
|
||||
u32 eof;
|
||||
int v;
|
||||
int starting_len = xdr->buf->len - 8;
|
||||
long len;
|
||||
int thislen;
|
||||
__be32 nfserr;
|
||||
__be32 tmp;
|
||||
__be32 *p;
|
||||
int pad;
|
||||
|
||||
/*
|
||||
* svcrdma requires every READ payload to start somewhere
|
||||
* in xdr->pages.
|
||||
*/
|
||||
if (xdr->iov == xdr->buf->head) {
|
||||
xdr->iov = NULL;
|
||||
xdr->end = xdr->p;
|
||||
}
|
||||
|
||||
len = maxcount;
|
||||
v = 0;
|
||||
while (len) {
|
||||
thislen = min_t(long, len, PAGE_SIZE);
|
||||
p = xdr_reserve_space(xdr, thislen);
|
||||
WARN_ON_ONCE(!p);
|
||||
resp->rqstp->rq_vec[v].iov_base = p;
|
||||
resp->rqstp->rq_vec[v].iov_len = thislen;
|
||||
v++;
|
||||
len -= thislen;
|
||||
}
|
||||
read->rd_vlen = v;
|
||||
read->rd_vlen = xdr_reserve_space_vec(xdr, resp->rqstp->rq_vec, maxcount);
|
||||
if (read->rd_vlen < 0)
|
||||
return nfserr_resource;
|
||||
|
||||
nfserr = nfsd_readv(resp->rqstp, read->rd_fhp, file, read->rd_offset,
|
||||
resp->rqstp->rq_vec, read->rd_vlen, &maxcount,
|
||||
@@ -4619,6 +4597,149 @@ nfsd4_encode_offload_status(struct nfsd4_compoundres *resp, __be32 nfserr,
|
||||
return nfserr_resource;
|
||||
p = xdr_encode_hyper(p, os->count);
|
||||
*p++ = cpu_to_be32(0);
|
||||
return nfserr;
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd4_encode_read_plus_data(struct nfsd4_compoundres *resp,
|
||||
struct nfsd4_read *read,
|
||||
unsigned long *maxcount, u32 *eof,
|
||||
loff_t *pos)
|
||||
{
|
||||
struct xdr_stream *xdr = &resp->xdr;
|
||||
struct file *file = read->rd_nf->nf_file;
|
||||
int starting_len = xdr->buf->len;
|
||||
loff_t hole_pos;
|
||||
__be32 nfserr;
|
||||
__be32 *p, tmp;
|
||||
__be64 tmp64;
|
||||
|
||||
hole_pos = pos ? *pos : vfs_llseek(file, read->rd_offset, SEEK_HOLE);
|
||||
if (hole_pos > read->rd_offset)
|
||||
*maxcount = min_t(unsigned long, *maxcount, hole_pos - read->rd_offset);
|
||||
*maxcount = min_t(unsigned long, *maxcount, (xdr->buf->buflen - xdr->buf->len));
|
||||
|
||||
/* Content type, offset, byte count */
|
||||
p = xdr_reserve_space(xdr, 4 + 8 + 4);
|
||||
if (!p)
|
||||
return nfserr_resource;
|
||||
|
||||
read->rd_vlen = xdr_reserve_space_vec(xdr, resp->rqstp->rq_vec, *maxcount);
|
||||
if (read->rd_vlen < 0)
|
||||
return nfserr_resource;
|
||||
|
||||
nfserr = nfsd_readv(resp->rqstp, read->rd_fhp, file, read->rd_offset,
|
||||
resp->rqstp->rq_vec, read->rd_vlen, maxcount, eof);
|
||||
if (nfserr)
|
||||
return nfserr;
|
||||
|
||||
tmp = htonl(NFS4_CONTENT_DATA);
|
||||
write_bytes_to_xdr_buf(xdr->buf, starting_len, &tmp, 4);
|
||||
tmp64 = cpu_to_be64(read->rd_offset);
|
||||
write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp64, 8);
|
||||
tmp = htonl(*maxcount);
|
||||
write_bytes_to_xdr_buf(xdr->buf, starting_len + 12, &tmp, 4);
|
||||
return nfs_ok;
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd4_encode_read_plus_hole(struct nfsd4_compoundres *resp,
|
||||
struct nfsd4_read *read,
|
||||
unsigned long *maxcount, u32 *eof)
|
||||
{
|
||||
struct file *file = read->rd_nf->nf_file;
|
||||
loff_t data_pos = vfs_llseek(file, read->rd_offset, SEEK_DATA);
|
||||
loff_t f_size = i_size_read(file_inode(file));
|
||||
unsigned long count;
|
||||
__be32 *p;
|
||||
|
||||
if (data_pos == -ENXIO)
|
||||
data_pos = f_size;
|
||||
else if (data_pos <= read->rd_offset || (data_pos < f_size && data_pos % PAGE_SIZE))
|
||||
return nfsd4_encode_read_plus_data(resp, read, maxcount, eof, &f_size);
|
||||
count = data_pos - read->rd_offset;
|
||||
|
||||
/* Content type, offset, byte count */
|
||||
p = xdr_reserve_space(&resp->xdr, 4 + 8 + 8);
|
||||
if (!p)
|
||||
return nfserr_resource;
|
||||
|
||||
*p++ = htonl(NFS4_CONTENT_HOLE);
|
||||
p = xdr_encode_hyper(p, read->rd_offset);
|
||||
p = xdr_encode_hyper(p, count);
|
||||
|
||||
*eof = (read->rd_offset + count) >= f_size;
|
||||
*maxcount = min_t(unsigned long, count, *maxcount);
|
||||
return nfs_ok;
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd4_encode_read_plus(struct nfsd4_compoundres *resp, __be32 nfserr,
|
||||
struct nfsd4_read *read)
|
||||
{
|
||||
unsigned long maxcount, count;
|
||||
struct xdr_stream *xdr = &resp->xdr;
|
||||
struct file *file;
|
||||
int starting_len = xdr->buf->len;
|
||||
int last_segment = xdr->buf->len;
|
||||
int segments = 0;
|
||||
__be32 *p, tmp;
|
||||
bool is_data;
|
||||
loff_t pos;
|
||||
u32 eof;
|
||||
|
||||
if (nfserr)
|
||||
return nfserr;
|
||||
file = read->rd_nf->nf_file;
|
||||
|
||||
/* eof flag, segment count */
|
||||
p = xdr_reserve_space(xdr, 4 + 4);
|
||||
if (!p)
|
||||
return nfserr_resource;
|
||||
xdr_commit_encode(xdr);
|
||||
|
||||
maxcount = svc_max_payload(resp->rqstp);
|
||||
maxcount = min_t(unsigned long, maxcount,
|
||||
(xdr->buf->buflen - xdr->buf->len));
|
||||
maxcount = min_t(unsigned long, maxcount, read->rd_length);
|
||||
count = maxcount;
|
||||
|
||||
eof = read->rd_offset >= i_size_read(file_inode(file));
|
||||
if (eof)
|
||||
goto out;
|
||||
|
||||
pos = vfs_llseek(file, read->rd_offset, SEEK_HOLE);
|
||||
is_data = pos > read->rd_offset;
|
||||
|
||||
while (count > 0 && !eof) {
|
||||
maxcount = count;
|
||||
if (is_data)
|
||||
nfserr = nfsd4_encode_read_plus_data(resp, read, &maxcount, &eof,
|
||||
segments == 0 ? &pos : NULL);
|
||||
else
|
||||
nfserr = nfsd4_encode_read_plus_hole(resp, read, &maxcount, &eof);
|
||||
if (nfserr)
|
||||
goto out;
|
||||
count -= maxcount;
|
||||
read->rd_offset += maxcount;
|
||||
is_data = !is_data;
|
||||
last_segment = xdr->buf->len;
|
||||
segments++;
|
||||
}
|
||||
|
||||
out:
|
||||
if (nfserr && segments == 0)
|
||||
xdr_truncate_encode(xdr, starting_len);
|
||||
else {
|
||||
tmp = htonl(eof);
|
||||
write_bytes_to_xdr_buf(xdr->buf, starting_len, &tmp, 4);
|
||||
tmp = htonl(segments);
|
||||
write_bytes_to_xdr_buf(xdr->buf, starting_len + 4, &tmp, 4);
|
||||
if (nfserr) {
|
||||
xdr_truncate_encode(xdr, last_segment);
|
||||
nfserr = nfs_ok;
|
||||
}
|
||||
}
|
||||
|
||||
return nfserr;
|
||||
}
|
||||
@@ -4679,7 +4800,7 @@ nfsd4_encode_noop(struct nfsd4_compoundres *resp, __be32 nfserr, void *p)
|
||||
/*
|
||||
* Encode kmalloc-ed buffer in to XDR stream.
|
||||
*/
|
||||
static int
|
||||
static __be32
|
||||
nfsd4_vbuf_to_stream(struct xdr_stream *xdr, char *buf, u32 buflen)
|
||||
{
|
||||
u32 cplen;
|
||||
@@ -4795,7 +4916,7 @@ nfsd4_encode_listxattrs(struct nfsd4_compoundres *resp, __be32 nfserr,
|
||||
u32 xdrlen, offset;
|
||||
u64 cookie;
|
||||
char *sp;
|
||||
__be32 status;
|
||||
__be32 status, tmp;
|
||||
__be32 *p;
|
||||
u32 nuser;
|
||||
|
||||
@@ -4828,7 +4949,7 @@ nfsd4_encode_listxattrs(struct nfsd4_compoundres *resp, __be32 nfserr,
|
||||
slen = strlen(sp);
|
||||
|
||||
/*
|
||||
* Check if this a user. attribute, skip it if not.
|
||||
* Check if this is a "user." attribute, skip it if not.
|
||||
*/
|
||||
if (strncmp(sp, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN))
|
||||
goto contloop;
|
||||
@@ -4859,7 +4980,7 @@ nfsd4_encode_listxattrs(struct nfsd4_compoundres *resp, __be32 nfserr,
|
||||
goto out;
|
||||
}
|
||||
|
||||
p = xdr_encode_opaque(p, sp, slen);
|
||||
xdr_encode_opaque(p, sp, slen);
|
||||
|
||||
xdrleft -= xdrlen;
|
||||
count++;
|
||||
@@ -4888,8 +5009,8 @@ wreof:
|
||||
cookie = offset + count;
|
||||
|
||||
write_bytes_to_xdr_buf(xdr->buf, cookie_offset, &cookie, 8);
|
||||
count = htonl(count);
|
||||
write_bytes_to_xdr_buf(xdr->buf, count_offset, &count, 4);
|
||||
tmp = cpu_to_be32(count);
|
||||
write_bytes_to_xdr_buf(xdr->buf, count_offset, &tmp, 4);
|
||||
out:
|
||||
if (listxattrs->lsxa_len)
|
||||
kvfree(listxattrs->lsxa_buf);
|
||||
@@ -4996,7 +5117,7 @@ static const nfsd4_enc nfsd4_enc_ops[] = {
|
||||
[OP_LAYOUTSTATS] = (nfsd4_enc)nfsd4_encode_noop,
|
||||
[OP_OFFLOAD_CANCEL] = (nfsd4_enc)nfsd4_encode_noop,
|
||||
[OP_OFFLOAD_STATUS] = (nfsd4_enc)nfsd4_encode_offload_status,
|
||||
[OP_READ_PLUS] = (nfsd4_enc)nfsd4_encode_noop,
|
||||
[OP_READ_PLUS] = (nfsd4_enc)nfsd4_encode_read_plus,
|
||||
[OP_SEEK] = (nfsd4_enc)nfsd4_encode_seek,
|
||||
[OP_WRITE_SAME] = (nfsd4_enc)nfsd4_encode_noop,
|
||||
[OP_CLONE] = (nfsd4_enc)nfsd4_encode_noop,
|
||||
@@ -5156,6 +5277,12 @@ void nfsd4_release_compoundargs(struct svc_rqst *rqstp)
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
nfs4svc_decode_voidarg(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
@@ -5183,15 +5310,14 @@ nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p)
|
||||
int
|
||||
nfs4svc_encode_compoundres(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
/*
|
||||
* All that remains is to write the tag and operation count...
|
||||
*/
|
||||
struct nfsd4_compoundres *resp = rqstp->rq_resp;
|
||||
struct xdr_buf *buf = resp->xdr.buf;
|
||||
|
||||
WARN_ON_ONCE(buf->len != buf->head[0].iov_len + buf->page_len +
|
||||
buf->tail[0].iov_len);
|
||||
|
||||
*p = resp->cstate.status;
|
||||
|
||||
rqstp->rq_next_page = resp->xdr.page_ptr + 1;
|
||||
|
||||
p = resp->tagp;
|
||||
|
||||
+4
-8
@@ -172,14 +172,10 @@ int nfsd_reply_cache_init(struct nfsd_net *nn)
|
||||
if (status)
|
||||
goto out_nomem;
|
||||
|
||||
nn->drc_hashtbl = kcalloc(hashsize,
|
||||
sizeof(*nn->drc_hashtbl), GFP_KERNEL);
|
||||
if (!nn->drc_hashtbl) {
|
||||
nn->drc_hashtbl = vzalloc(array_size(hashsize,
|
||||
sizeof(*nn->drc_hashtbl)));
|
||||
if (!nn->drc_hashtbl)
|
||||
goto out_shrinker;
|
||||
}
|
||||
nn->drc_hashtbl = kvzalloc(array_size(hashsize,
|
||||
sizeof(*nn->drc_hashtbl)), GFP_KERNEL);
|
||||
if (!nn->drc_hashtbl)
|
||||
goto out_shrinker;
|
||||
|
||||
for (i = 0; i < hashsize; i++) {
|
||||
INIT_LIST_HEAD(&nn->drc_hashtbl[i].lru_head);
|
||||
|
||||
@@ -1534,7 +1534,6 @@ static int __init init_nfsd(void)
|
||||
retval = nfsd4_init_pnfs();
|
||||
if (retval)
|
||||
goto out_free_slabs;
|
||||
nfsd_fault_inject_init(); /* nfsd fault injection controls */
|
||||
nfsd_stat_init(); /* Statistics */
|
||||
retval = nfsd_drc_slab_create();
|
||||
if (retval)
|
||||
@@ -1555,7 +1554,6 @@ out_free_lockd:
|
||||
nfsd_drc_slab_free();
|
||||
out_free_stat:
|
||||
nfsd_stat_shutdown();
|
||||
nfsd_fault_inject_cleanup();
|
||||
nfsd4_exit_pnfs();
|
||||
out_free_slabs:
|
||||
nfsd4_free_slabs();
|
||||
@@ -1575,7 +1573,6 @@ static void __exit exit_nfsd(void)
|
||||
nfsd_lockd_shutdown();
|
||||
nfsd4_free_slabs();
|
||||
nfsd4_exit_pnfs();
|
||||
nfsd_fault_inject_cleanup();
|
||||
unregister_filesystem(&nfsd_fs_type);
|
||||
unregister_cld_notifier();
|
||||
unregister_pernet_subsys(&nfsd_net_ops);
|
||||
|
||||
+156
-125
@@ -11,30 +11,14 @@
|
||||
#include "xdr.h"
|
||||
#include "vfs.h"
|
||||
|
||||
typedef struct svc_rqst svc_rqst;
|
||||
typedef struct svc_buf svc_buf;
|
||||
|
||||
#define NFSDDBG_FACILITY NFSDDBG_PROC
|
||||
|
||||
|
||||
static __be32
|
||||
nfsd_proc_null(struct svc_rqst *rqstp)
|
||||
{
|
||||
return nfs_ok;
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd_return_attrs(__be32 err, struct nfsd_attrstat *resp)
|
||||
{
|
||||
if (err) return err;
|
||||
return fh_getattr(&resp->fh, &resp->stat);
|
||||
}
|
||||
static __be32
|
||||
nfsd_return_dirop(__be32 err, struct nfsd_diropres *resp)
|
||||
{
|
||||
if (err) return err;
|
||||
return fh_getattr(&resp->fh, &resp->stat);
|
||||
}
|
||||
/*
|
||||
* Get a file's attributes
|
||||
* N.B. After this call resp->fh needs an fh_put
|
||||
@@ -44,13 +28,17 @@ nfsd_proc_getattr(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_fhandle *argp = rqstp->rq_argp;
|
||||
struct nfsd_attrstat *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: GETATTR %s\n", SVCFH_fmt(&argp->fh));
|
||||
|
||||
fh_copy(&resp->fh, &argp->fh);
|
||||
nfserr = fh_verify(rqstp, &resp->fh, 0,
|
||||
NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
|
||||
return nfsd_return_attrs(nfserr, resp);
|
||||
resp->status = fh_verify(rqstp, &resp->fh, 0,
|
||||
NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
|
||||
if (resp->status != nfs_ok)
|
||||
goto out;
|
||||
resp->status = fh_getattr(&resp->fh, &resp->stat);
|
||||
out:
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -64,7 +52,6 @@ nfsd_proc_setattr(struct svc_rqst *rqstp)
|
||||
struct nfsd_attrstat *resp = rqstp->rq_resp;
|
||||
struct iattr *iap = &argp->attrs;
|
||||
struct svc_fh *fhp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: SETATTR %s, valid=%x, size=%ld\n",
|
||||
SVCFH_fmt(&argp->fh),
|
||||
@@ -96,9 +83,9 @@ nfsd_proc_setattr(struct svc_rqst *rqstp)
|
||||
*/
|
||||
time64_t delta = iap->ia_atime.tv_sec - ktime_get_real_seconds();
|
||||
|
||||
nfserr = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP);
|
||||
if (nfserr)
|
||||
goto done;
|
||||
resp->status = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP);
|
||||
if (resp->status != nfs_ok)
|
||||
goto out;
|
||||
|
||||
if (delta < 0)
|
||||
delta = -delta;
|
||||
@@ -113,9 +100,20 @@ nfsd_proc_setattr(struct svc_rqst *rqstp)
|
||||
}
|
||||
}
|
||||
|
||||
nfserr = nfsd_setattr(rqstp, fhp, iap, 0, (time64_t)0);
|
||||
done:
|
||||
return nfsd_return_attrs(nfserr, resp);
|
||||
resp->status = nfsd_setattr(rqstp, fhp, iap, 0, (time64_t)0);
|
||||
if (resp->status != nfs_ok)
|
||||
goto out;
|
||||
|
||||
resp->status = fh_getattr(&resp->fh, &resp->stat);
|
||||
out:
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/* Obsolete, replaced by MNTPROC_MNT. */
|
||||
static __be32
|
||||
nfsd_proc_root(struct svc_rqst *rqstp)
|
||||
{
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -129,17 +127,20 @@ nfsd_proc_lookup(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_diropargs *argp = rqstp->rq_argp;
|
||||
struct nfsd_diropres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: LOOKUP %s %.*s\n",
|
||||
SVCFH_fmt(&argp->fh), argp->len, argp->name);
|
||||
|
||||
fh_init(&resp->fh, NFS_FHSIZE);
|
||||
nfserr = nfsd_lookup(rqstp, &argp->fh, argp->name, argp->len,
|
||||
&resp->fh);
|
||||
|
||||
resp->status = nfsd_lookup(rqstp, &argp->fh, argp->name, argp->len,
|
||||
&resp->fh);
|
||||
fh_put(&argp->fh);
|
||||
return nfsd_return_dirop(nfserr, resp);
|
||||
if (resp->status != nfs_ok)
|
||||
goto out;
|
||||
|
||||
resp->status = fh_getattr(&resp->fh, &resp->stat);
|
||||
out:
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -150,16 +151,15 @@ nfsd_proc_readlink(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_readlinkargs *argp = rqstp->rq_argp;
|
||||
struct nfsd_readlinkres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: READLINK %s\n", SVCFH_fmt(&argp->fh));
|
||||
|
||||
/* Read the symlink. */
|
||||
resp->len = NFS_MAXPATHLEN;
|
||||
nfserr = nfsd_readlink(rqstp, &argp->fh, argp->buffer, &resp->len);
|
||||
resp->status = nfsd_readlink(rqstp, &argp->fh, argp->buffer, &resp->len);
|
||||
|
||||
fh_put(&argp->fh);
|
||||
return nfserr;
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -171,7 +171,6 @@ nfsd_proc_read(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_readargs *argp = rqstp->rq_argp;
|
||||
struct nfsd_readres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
u32 eof;
|
||||
|
||||
dprintk("nfsd: READ %s %d bytes at %d\n",
|
||||
@@ -193,14 +192,23 @@ nfsd_proc_read(struct svc_rqst *rqstp)
|
||||
svc_reserve_auth(rqstp, (19<<2) + argp->count + 4);
|
||||
|
||||
resp->count = argp->count;
|
||||
nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh),
|
||||
argp->offset,
|
||||
rqstp->rq_vec, argp->vlen,
|
||||
&resp->count,
|
||||
&eof);
|
||||
resp->status = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh),
|
||||
argp->offset,
|
||||
rqstp->rq_vec, argp->vlen,
|
||||
&resp->count,
|
||||
&eof);
|
||||
if (resp->status == nfs_ok)
|
||||
resp->status = fh_getattr(&resp->fh, &resp->stat);
|
||||
else if (resp->status == nfserr_jukebox)
|
||||
return rpc_drop_reply;
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
if (nfserr) return nfserr;
|
||||
return fh_getattr(&resp->fh, &resp->stat);
|
||||
/* Reserved */
|
||||
static __be32
|
||||
nfsd_proc_writecache(struct svc_rqst *rqstp)
|
||||
{
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -212,7 +220,6 @@ nfsd_proc_write(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_writeargs *argp = rqstp->rq_argp;
|
||||
struct nfsd_attrstat *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
unsigned long cnt = argp->len;
|
||||
unsigned int nvecs;
|
||||
|
||||
@@ -222,12 +229,20 @@ nfsd_proc_write(struct svc_rqst *rqstp)
|
||||
|
||||
nvecs = svc_fill_write_vector(rqstp, rqstp->rq_arg.pages,
|
||||
&argp->first, cnt);
|
||||
if (!nvecs)
|
||||
return nfserr_io;
|
||||
nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh),
|
||||
argp->offset, rqstp->rq_vec, nvecs,
|
||||
&cnt, NFS_DATA_SYNC, NULL);
|
||||
return nfsd_return_attrs(nfserr, resp);
|
||||
if (!nvecs) {
|
||||
resp->status = nfserr_io;
|
||||
goto out;
|
||||
}
|
||||
|
||||
resp->status = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh),
|
||||
argp->offset, rqstp->rq_vec, nvecs,
|
||||
&cnt, NFS_DATA_SYNC, NULL);
|
||||
if (resp->status == nfs_ok)
|
||||
resp->status = fh_getattr(&resp->fh, &resp->stat);
|
||||
else if (resp->status == nfserr_jukebox)
|
||||
return rpc_drop_reply;
|
||||
out:
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -247,7 +262,6 @@ nfsd_proc_create(struct svc_rqst *rqstp)
|
||||
struct inode *inode;
|
||||
struct dentry *dchild;
|
||||
int type, mode;
|
||||
__be32 nfserr;
|
||||
int hosterr;
|
||||
dev_t rdev = 0, wanted = new_decode_dev(attr->ia_size);
|
||||
|
||||
@@ -255,40 +269,40 @@ nfsd_proc_create(struct svc_rqst *rqstp)
|
||||
SVCFH_fmt(dirfhp), argp->len, argp->name);
|
||||
|
||||
/* First verify the parent file handle */
|
||||
nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, NFSD_MAY_EXEC);
|
||||
if (nfserr)
|
||||
resp->status = fh_verify(rqstp, dirfhp, S_IFDIR, NFSD_MAY_EXEC);
|
||||
if (resp->status != nfs_ok)
|
||||
goto done; /* must fh_put dirfhp even on error */
|
||||
|
||||
/* Check for NFSD_MAY_WRITE in nfsd_create if necessary */
|
||||
|
||||
nfserr = nfserr_exist;
|
||||
resp->status = nfserr_exist;
|
||||
if (isdotent(argp->name, argp->len))
|
||||
goto done;
|
||||
hosterr = fh_want_write(dirfhp);
|
||||
if (hosterr) {
|
||||
nfserr = nfserrno(hosterr);
|
||||
resp->status = nfserrno(hosterr);
|
||||
goto done;
|
||||
}
|
||||
|
||||
fh_lock_nested(dirfhp, I_MUTEX_PARENT);
|
||||
dchild = lookup_one_len(argp->name, dirfhp->fh_dentry, argp->len);
|
||||
if (IS_ERR(dchild)) {
|
||||
nfserr = nfserrno(PTR_ERR(dchild));
|
||||
resp->status = nfserrno(PTR_ERR(dchild));
|
||||
goto out_unlock;
|
||||
}
|
||||
fh_init(newfhp, NFS_FHSIZE);
|
||||
nfserr = fh_compose(newfhp, dirfhp->fh_export, dchild, dirfhp);
|
||||
if (!nfserr && d_really_is_negative(dchild))
|
||||
nfserr = nfserr_noent;
|
||||
resp->status = fh_compose(newfhp, dirfhp->fh_export, dchild, dirfhp);
|
||||
if (!resp->status && d_really_is_negative(dchild))
|
||||
resp->status = nfserr_noent;
|
||||
dput(dchild);
|
||||
if (nfserr) {
|
||||
if (nfserr != nfserr_noent)
|
||||
if (resp->status) {
|
||||
if (resp->status != nfserr_noent)
|
||||
goto out_unlock;
|
||||
/*
|
||||
* If the new file handle wasn't verified, we can't tell
|
||||
* whether the file exists or not. Time to bail ...
|
||||
*/
|
||||
nfserr = nfserr_acces;
|
||||
resp->status = nfserr_acces;
|
||||
if (!newfhp->fh_dentry) {
|
||||
printk(KERN_WARNING
|
||||
"nfsd_proc_create: file handle not verified\n");
|
||||
@@ -321,11 +335,11 @@ nfsd_proc_create(struct svc_rqst *rqstp)
|
||||
* echo thing > device-special-file-or-pipe
|
||||
* by doing a CREATE with type==0
|
||||
*/
|
||||
nfserr = nfsd_permission(rqstp,
|
||||
resp->status = nfsd_permission(rqstp,
|
||||
newfhp->fh_export,
|
||||
newfhp->fh_dentry,
|
||||
NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS);
|
||||
if (nfserr && nfserr != nfserr_rofs)
|
||||
if (resp->status && resp->status != nfserr_rofs)
|
||||
goto out_unlock;
|
||||
}
|
||||
} else
|
||||
@@ -361,16 +375,17 @@ nfsd_proc_create(struct svc_rqst *rqstp)
|
||||
attr->ia_valid &= ~ATTR_SIZE;
|
||||
|
||||
/* Make sure the type and device matches */
|
||||
nfserr = nfserr_exist;
|
||||
resp->status = nfserr_exist;
|
||||
if (inode && type != (inode->i_mode & S_IFMT))
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
nfserr = 0;
|
||||
resp->status = nfs_ok;
|
||||
if (!inode) {
|
||||
/* File doesn't exist. Create it and set attrs */
|
||||
nfserr = nfsd_create_locked(rqstp, dirfhp, argp->name,
|
||||
argp->len, attr, type, rdev, newfhp);
|
||||
resp->status = nfsd_create_locked(rqstp, dirfhp, argp->name,
|
||||
argp->len, attr, type, rdev,
|
||||
newfhp);
|
||||
} else if (type == S_IFREG) {
|
||||
dprintk("nfsd: existing %s, valid=%x, size=%ld\n",
|
||||
argp->name, attr->ia_valid, (long) attr->ia_size);
|
||||
@@ -380,7 +395,8 @@ nfsd_proc_create(struct svc_rqst *rqstp)
|
||||
*/
|
||||
attr->ia_valid &= ATTR_SIZE;
|
||||
if (attr->ia_valid)
|
||||
nfserr = nfsd_setattr(rqstp, newfhp, attr, 0, (time64_t)0);
|
||||
resp->status = nfsd_setattr(rqstp, newfhp, attr, 0,
|
||||
(time64_t)0);
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
@@ -389,47 +405,52 @@ out_unlock:
|
||||
fh_drop_write(dirfhp);
|
||||
done:
|
||||
fh_put(dirfhp);
|
||||
return nfsd_return_dirop(nfserr, resp);
|
||||
if (resp->status != nfs_ok)
|
||||
goto out;
|
||||
resp->status = fh_getattr(&resp->fh, &resp->stat);
|
||||
out:
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd_proc_remove(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_diropargs *argp = rqstp->rq_argp;
|
||||
__be32 nfserr;
|
||||
struct nfsd_stat *resp = rqstp->rq_resp;
|
||||
|
||||
dprintk("nfsd: REMOVE %s %.*s\n", SVCFH_fmt(&argp->fh),
|
||||
argp->len, argp->name);
|
||||
|
||||
/* Unlink. -SIFDIR means file must not be a directory */
|
||||
nfserr = nfsd_unlink(rqstp, &argp->fh, -S_IFDIR, argp->name, argp->len);
|
||||
resp->status = nfsd_unlink(rqstp, &argp->fh, -S_IFDIR,
|
||||
argp->name, argp->len);
|
||||
fh_put(&argp->fh);
|
||||
return nfserr;
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd_proc_rename(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_renameargs *argp = rqstp->rq_argp;
|
||||
__be32 nfserr;
|
||||
struct nfsd_stat *resp = rqstp->rq_resp;
|
||||
|
||||
dprintk("nfsd: RENAME %s %.*s -> \n",
|
||||
SVCFH_fmt(&argp->ffh), argp->flen, argp->fname);
|
||||
dprintk("nfsd: -> %s %.*s\n",
|
||||
SVCFH_fmt(&argp->tfh), argp->tlen, argp->tname);
|
||||
|
||||
nfserr = nfsd_rename(rqstp, &argp->ffh, argp->fname, argp->flen,
|
||||
&argp->tfh, argp->tname, argp->tlen);
|
||||
resp->status = nfsd_rename(rqstp, &argp->ffh, argp->fname, argp->flen,
|
||||
&argp->tfh, argp->tname, argp->tlen);
|
||||
fh_put(&argp->ffh);
|
||||
fh_put(&argp->tfh);
|
||||
return nfserr;
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd_proc_link(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_linkargs *argp = rqstp->rq_argp;
|
||||
__be32 nfserr;
|
||||
struct nfsd_stat *resp = rqstp->rq_resp;
|
||||
|
||||
dprintk("nfsd: LINK %s ->\n",
|
||||
SVCFH_fmt(&argp->ffh));
|
||||
@@ -438,41 +459,46 @@ nfsd_proc_link(struct svc_rqst *rqstp)
|
||||
argp->tlen,
|
||||
argp->tname);
|
||||
|
||||
nfserr = nfsd_link(rqstp, &argp->tfh, argp->tname, argp->tlen,
|
||||
&argp->ffh);
|
||||
resp->status = nfsd_link(rqstp, &argp->tfh, argp->tname, argp->tlen,
|
||||
&argp->ffh);
|
||||
fh_put(&argp->ffh);
|
||||
fh_put(&argp->tfh);
|
||||
return nfserr;
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd_proc_symlink(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_symlinkargs *argp = rqstp->rq_argp;
|
||||
struct nfsd_stat *resp = rqstp->rq_resp;
|
||||
struct svc_fh newfh;
|
||||
__be32 nfserr;
|
||||
|
||||
if (argp->tlen > NFS_MAXPATHLEN)
|
||||
return nfserr_nametoolong;
|
||||
if (argp->tlen > NFS_MAXPATHLEN) {
|
||||
resp->status = nfserr_nametoolong;
|
||||
goto out;
|
||||
}
|
||||
|
||||
argp->tname = svc_fill_symlink_pathname(rqstp, &argp->first,
|
||||
page_address(rqstp->rq_arg.pages[0]),
|
||||
argp->tlen);
|
||||
if (IS_ERR(argp->tname))
|
||||
return nfserrno(PTR_ERR(argp->tname));
|
||||
if (IS_ERR(argp->tname)) {
|
||||
resp->status = nfserrno(PTR_ERR(argp->tname));
|
||||
goto out;
|
||||
}
|
||||
|
||||
dprintk("nfsd: SYMLINK %s %.*s -> %.*s\n",
|
||||
SVCFH_fmt(&argp->ffh), argp->flen, argp->fname,
|
||||
argp->tlen, argp->tname);
|
||||
|
||||
fh_init(&newfh, NFS_FHSIZE);
|
||||
nfserr = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen,
|
||||
argp->tname, &newfh);
|
||||
resp->status = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen,
|
||||
argp->tname, &newfh);
|
||||
|
||||
kfree(argp->tname);
|
||||
fh_put(&argp->ffh);
|
||||
fh_put(&newfh);
|
||||
return nfserr;
|
||||
out:
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -484,7 +510,6 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_createargs *argp = rqstp->rq_argp;
|
||||
struct nfsd_diropres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: MKDIR %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
|
||||
|
||||
@@ -495,10 +520,15 @@ nfsd_proc_mkdir(struct svc_rqst *rqstp)
|
||||
|
||||
argp->attrs.ia_valid &= ~ATTR_SIZE;
|
||||
fh_init(&resp->fh, NFS_FHSIZE);
|
||||
nfserr = nfsd_create(rqstp, &argp->fh, argp->name, argp->len,
|
||||
&argp->attrs, S_IFDIR, 0, &resp->fh);
|
||||
resp->status = nfsd_create(rqstp, &argp->fh, argp->name, argp->len,
|
||||
&argp->attrs, S_IFDIR, 0, &resp->fh);
|
||||
fh_put(&argp->fh);
|
||||
return nfsd_return_dirop(nfserr, resp);
|
||||
if (resp->status != nfs_ok)
|
||||
goto out;
|
||||
|
||||
resp->status = fh_getattr(&resp->fh, &resp->stat);
|
||||
out:
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -508,13 +538,14 @@ static __be32
|
||||
nfsd_proc_rmdir(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_diropargs *argp = rqstp->rq_argp;
|
||||
__be32 nfserr;
|
||||
struct nfsd_stat *resp = rqstp->rq_resp;
|
||||
|
||||
dprintk("nfsd: RMDIR %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
|
||||
|
||||
nfserr = nfsd_unlink(rqstp, &argp->fh, S_IFDIR, argp->name, argp->len);
|
||||
resp->status = nfsd_unlink(rqstp, &argp->fh, S_IFDIR,
|
||||
argp->name, argp->len);
|
||||
fh_put(&argp->fh);
|
||||
return nfserr;
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -526,7 +557,6 @@ nfsd_proc_readdir(struct svc_rqst *rqstp)
|
||||
struct nfsd_readdirargs *argp = rqstp->rq_argp;
|
||||
struct nfsd_readdirres *resp = rqstp->rq_resp;
|
||||
int count;
|
||||
__be32 nfserr;
|
||||
loff_t offset;
|
||||
|
||||
dprintk("nfsd: READDIR %s %d bytes at %d\n",
|
||||
@@ -547,15 +577,15 @@ nfsd_proc_readdir(struct svc_rqst *rqstp)
|
||||
resp->common.err = nfs_ok;
|
||||
/* Read directory and encode entries on the fly */
|
||||
offset = argp->cookie;
|
||||
nfserr = nfsd_readdir(rqstp, &argp->fh, &offset,
|
||||
&resp->common, nfssvc_encode_entry);
|
||||
resp->status = nfsd_readdir(rqstp, &argp->fh, &offset,
|
||||
&resp->common, nfssvc_encode_entry);
|
||||
|
||||
resp->count = resp->buffer - argp->buffer;
|
||||
if (resp->offset)
|
||||
*resp->offset = htonl(offset);
|
||||
|
||||
fh_put(&argp->fh);
|
||||
return nfserr;
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -566,14 +596,13 @@ nfsd_proc_statfs(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_fhandle *argp = rqstp->rq_argp;
|
||||
struct nfsd_statfsres *resp = rqstp->rq_resp;
|
||||
__be32 nfserr;
|
||||
|
||||
dprintk("nfsd: STATFS %s\n", SVCFH_fmt(&argp->fh));
|
||||
|
||||
nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats,
|
||||
NFSD_MAY_BYPASS_GSS_ON_ROOT);
|
||||
resp->status = nfsd_statfs(rqstp, &argp->fh, &resp->stats,
|
||||
NFSD_MAY_BYPASS_GSS_ON_ROOT);
|
||||
fh_put(&argp->fh);
|
||||
return nfserr;
|
||||
return rpc_success;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -594,13 +623,13 @@ static const struct svc_procedure nfsd_procedures2[18] = {
|
||||
.pc_argsize = sizeof(struct nfsd_void),
|
||||
.pc_ressize = sizeof(struct nfsd_void),
|
||||
.pc_cachetype = RC_NOCACHE,
|
||||
.pc_xdrressize = ST,
|
||||
.pc_xdrressize = 0,
|
||||
},
|
||||
[NFSPROC_GETATTR] = {
|
||||
.pc_func = nfsd_proc_getattr,
|
||||
.pc_decode = nfssvc_decode_fhandle,
|
||||
.pc_encode = nfssvc_encode_attrstat,
|
||||
.pc_release = nfssvc_release_fhandle,
|
||||
.pc_release = nfssvc_release_attrstat,
|
||||
.pc_argsize = sizeof(struct nfsd_fhandle),
|
||||
.pc_ressize = sizeof(struct nfsd_attrstat),
|
||||
.pc_cachetype = RC_NOCACHE,
|
||||
@@ -610,25 +639,26 @@ static const struct svc_procedure nfsd_procedures2[18] = {
|
||||
.pc_func = nfsd_proc_setattr,
|
||||
.pc_decode = nfssvc_decode_sattrargs,
|
||||
.pc_encode = nfssvc_encode_attrstat,
|
||||
.pc_release = nfssvc_release_fhandle,
|
||||
.pc_release = nfssvc_release_attrstat,
|
||||
.pc_argsize = sizeof(struct nfsd_sattrargs),
|
||||
.pc_ressize = sizeof(struct nfsd_attrstat),
|
||||
.pc_cachetype = RC_REPLBUFF,
|
||||
.pc_xdrressize = ST+AT,
|
||||
},
|
||||
[NFSPROC_ROOT] = {
|
||||
.pc_func = nfsd_proc_root,
|
||||
.pc_decode = nfssvc_decode_void,
|
||||
.pc_encode = nfssvc_encode_void,
|
||||
.pc_argsize = sizeof(struct nfsd_void),
|
||||
.pc_ressize = sizeof(struct nfsd_void),
|
||||
.pc_cachetype = RC_NOCACHE,
|
||||
.pc_xdrressize = ST,
|
||||
.pc_xdrressize = 0,
|
||||
},
|
||||
[NFSPROC_LOOKUP] = {
|
||||
.pc_func = nfsd_proc_lookup,
|
||||
.pc_decode = nfssvc_decode_diropargs,
|
||||
.pc_encode = nfssvc_encode_diropres,
|
||||
.pc_release = nfssvc_release_fhandle,
|
||||
.pc_release = nfssvc_release_diropres,
|
||||
.pc_argsize = sizeof(struct nfsd_diropargs),
|
||||
.pc_ressize = sizeof(struct nfsd_diropres),
|
||||
.pc_cachetype = RC_NOCACHE,
|
||||
@@ -647,25 +677,26 @@ static const struct svc_procedure nfsd_procedures2[18] = {
|
||||
.pc_func = nfsd_proc_read,
|
||||
.pc_decode = nfssvc_decode_readargs,
|
||||
.pc_encode = nfssvc_encode_readres,
|
||||
.pc_release = nfssvc_release_fhandle,
|
||||
.pc_release = nfssvc_release_readres,
|
||||
.pc_argsize = sizeof(struct nfsd_readargs),
|
||||
.pc_ressize = sizeof(struct nfsd_readres),
|
||||
.pc_cachetype = RC_NOCACHE,
|
||||
.pc_xdrressize = ST+AT+1+NFSSVC_MAXBLKSIZE_V2/4,
|
||||
},
|
||||
[NFSPROC_WRITECACHE] = {
|
||||
.pc_func = nfsd_proc_writecache,
|
||||
.pc_decode = nfssvc_decode_void,
|
||||
.pc_encode = nfssvc_encode_void,
|
||||
.pc_argsize = sizeof(struct nfsd_void),
|
||||
.pc_ressize = sizeof(struct nfsd_void),
|
||||
.pc_cachetype = RC_NOCACHE,
|
||||
.pc_xdrressize = ST,
|
||||
.pc_xdrressize = 0,
|
||||
},
|
||||
[NFSPROC_WRITE] = {
|
||||
.pc_func = nfsd_proc_write,
|
||||
.pc_decode = nfssvc_decode_writeargs,
|
||||
.pc_encode = nfssvc_encode_attrstat,
|
||||
.pc_release = nfssvc_release_fhandle,
|
||||
.pc_release = nfssvc_release_attrstat,
|
||||
.pc_argsize = sizeof(struct nfsd_writeargs),
|
||||
.pc_ressize = sizeof(struct nfsd_attrstat),
|
||||
.pc_cachetype = RC_REPLBUFF,
|
||||
@@ -675,7 +706,7 @@ static const struct svc_procedure nfsd_procedures2[18] = {
|
||||
.pc_func = nfsd_proc_create,
|
||||
.pc_decode = nfssvc_decode_createargs,
|
||||
.pc_encode = nfssvc_encode_diropres,
|
||||
.pc_release = nfssvc_release_fhandle,
|
||||
.pc_release = nfssvc_release_diropres,
|
||||
.pc_argsize = sizeof(struct nfsd_createargs),
|
||||
.pc_ressize = sizeof(struct nfsd_diropres),
|
||||
.pc_cachetype = RC_REPLBUFF,
|
||||
@@ -684,36 +715,36 @@ static const struct svc_procedure nfsd_procedures2[18] = {
|
||||
[NFSPROC_REMOVE] = {
|
||||
.pc_func = nfsd_proc_remove,
|
||||
.pc_decode = nfssvc_decode_diropargs,
|
||||
.pc_encode = nfssvc_encode_void,
|
||||
.pc_encode = nfssvc_encode_stat,
|
||||
.pc_argsize = sizeof(struct nfsd_diropargs),
|
||||
.pc_ressize = sizeof(struct nfsd_void),
|
||||
.pc_ressize = sizeof(struct nfsd_stat),
|
||||
.pc_cachetype = RC_REPLSTAT,
|
||||
.pc_xdrressize = ST,
|
||||
},
|
||||
[NFSPROC_RENAME] = {
|
||||
.pc_func = nfsd_proc_rename,
|
||||
.pc_decode = nfssvc_decode_renameargs,
|
||||
.pc_encode = nfssvc_encode_void,
|
||||
.pc_encode = nfssvc_encode_stat,
|
||||
.pc_argsize = sizeof(struct nfsd_renameargs),
|
||||
.pc_ressize = sizeof(struct nfsd_void),
|
||||
.pc_ressize = sizeof(struct nfsd_stat),
|
||||
.pc_cachetype = RC_REPLSTAT,
|
||||
.pc_xdrressize = ST,
|
||||
},
|
||||
[NFSPROC_LINK] = {
|
||||
.pc_func = nfsd_proc_link,
|
||||
.pc_decode = nfssvc_decode_linkargs,
|
||||
.pc_encode = nfssvc_encode_void,
|
||||
.pc_encode = nfssvc_encode_stat,
|
||||
.pc_argsize = sizeof(struct nfsd_linkargs),
|
||||
.pc_ressize = sizeof(struct nfsd_void),
|
||||
.pc_ressize = sizeof(struct nfsd_stat),
|
||||
.pc_cachetype = RC_REPLSTAT,
|
||||
.pc_xdrressize = ST,
|
||||
},
|
||||
[NFSPROC_SYMLINK] = {
|
||||
.pc_func = nfsd_proc_symlink,
|
||||
.pc_decode = nfssvc_decode_symlinkargs,
|
||||
.pc_encode = nfssvc_encode_void,
|
||||
.pc_encode = nfssvc_encode_stat,
|
||||
.pc_argsize = sizeof(struct nfsd_symlinkargs),
|
||||
.pc_ressize = sizeof(struct nfsd_void),
|
||||
.pc_ressize = sizeof(struct nfsd_stat),
|
||||
.pc_cachetype = RC_REPLSTAT,
|
||||
.pc_xdrressize = ST,
|
||||
},
|
||||
@@ -721,7 +752,7 @@ static const struct svc_procedure nfsd_procedures2[18] = {
|
||||
.pc_func = nfsd_proc_mkdir,
|
||||
.pc_decode = nfssvc_decode_createargs,
|
||||
.pc_encode = nfssvc_encode_diropres,
|
||||
.pc_release = nfssvc_release_fhandle,
|
||||
.pc_release = nfssvc_release_diropres,
|
||||
.pc_argsize = sizeof(struct nfsd_createargs),
|
||||
.pc_ressize = sizeof(struct nfsd_diropres),
|
||||
.pc_cachetype = RC_REPLBUFF,
|
||||
@@ -730,9 +761,9 @@ static const struct svc_procedure nfsd_procedures2[18] = {
|
||||
[NFSPROC_RMDIR] = {
|
||||
.pc_func = nfsd_proc_rmdir,
|
||||
.pc_decode = nfssvc_decode_diropargs,
|
||||
.pc_encode = nfssvc_encode_void,
|
||||
.pc_encode = nfssvc_encode_stat,
|
||||
.pc_argsize = sizeof(struct nfsd_diropargs),
|
||||
.pc_ressize = sizeof(struct nfsd_void),
|
||||
.pc_ressize = sizeof(struct nfsd_stat),
|
||||
.pc_cachetype = RC_REPLSTAT,
|
||||
.pc_xdrressize = ST,
|
||||
},
|
||||
|
||||
+59
-63
@@ -960,15 +960,6 @@ out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __be32 map_new_errors(u32 vers, __be32 nfserr)
|
||||
{
|
||||
if (nfserr == nfserr_jukebox && vers == 2)
|
||||
return nfserr_dropit;
|
||||
if (nfserr == nfserr_wrongsec && vers < 4)
|
||||
return nfserr_acces;
|
||||
return nfserr;
|
||||
}
|
||||
|
||||
/*
|
||||
* A write procedure can have a large argument, and a read procedure can
|
||||
* have a large reply, but no NFSv2 or NFSv3 procedure has argument and
|
||||
@@ -1000,80 +991,85 @@ static bool nfs_request_too_big(struct svc_rqst *rqstp,
|
||||
return rqstp->rq_arg.len > PAGE_SIZE;
|
||||
}
|
||||
|
||||
int
|
||||
nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
|
||||
/**
|
||||
* nfsd_dispatch - Process an NFS or NFSACL Request
|
||||
* @rqstp: incoming request
|
||||
* @statp: pointer to location of accept_stat field in RPC Reply buffer
|
||||
*
|
||||
* This RPC dispatcher integrates the NFS server's duplicate reply cache.
|
||||
*
|
||||
* Return values:
|
||||
* %0: Processing complete; do not send a Reply
|
||||
* %1: Processing complete; send Reply in rqstp->rq_res
|
||||
*/
|
||||
int nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp)
|
||||
{
|
||||
const struct svc_procedure *proc;
|
||||
__be32 nfserr;
|
||||
__be32 *nfserrp;
|
||||
const struct svc_procedure *proc = rqstp->rq_procinfo;
|
||||
struct kvec *argv = &rqstp->rq_arg.head[0];
|
||||
struct kvec *resv = &rqstp->rq_res.head[0];
|
||||
__be32 *p;
|
||||
|
||||
dprintk("nfsd_dispatch: vers %d proc %d\n",
|
||||
rqstp->rq_vers, rqstp->rq_proc);
|
||||
proc = rqstp->rq_procinfo;
|
||||
|
||||
if (nfs_request_too_big(rqstp, proc)) {
|
||||
dprintk("nfsd: NFSv%d argument too large\n", rqstp->rq_vers);
|
||||
*statp = rpc_garbage_args;
|
||||
return 1;
|
||||
}
|
||||
rqstp->rq_lease_breaker = NULL;
|
||||
if (nfs_request_too_big(rqstp, proc))
|
||||
goto out_too_large;
|
||||
|
||||
/*
|
||||
* Give the xdr decoder a chance to change this if it wants
|
||||
* (necessary in the NFSv4.0 compound case)
|
||||
*/
|
||||
rqstp->rq_cachetype = proc->pc_cachetype;
|
||||
/* Decode arguments */
|
||||
if (proc->pc_decode &&
|
||||
!proc->pc_decode(rqstp, (__be32*)rqstp->rq_arg.head[0].iov_base)) {
|
||||
dprintk("nfsd: failed to decode arguments!\n");
|
||||
*statp = rpc_garbage_args;
|
||||
return 1;
|
||||
}
|
||||
if (!proc->pc_decode(rqstp, argv->iov_base))
|
||||
goto out_decode_err;
|
||||
|
||||
/* Check whether we have this call in the cache. */
|
||||
switch (nfsd_cache_lookup(rqstp)) {
|
||||
case RC_DROPIT:
|
||||
return 0;
|
||||
case RC_DOIT:
|
||||
break;
|
||||
case RC_REPLY:
|
||||
return 1;
|
||||
case RC_DOIT:;
|
||||
/* do it */
|
||||
goto out_cached_reply;
|
||||
case RC_DROPIT:
|
||||
goto out_dropit;
|
||||
}
|
||||
|
||||
/* need to grab the location to store the status, as
|
||||
* nfsv4 does some encoding while processing
|
||||
/*
|
||||
* Need to grab the location to store the status, as
|
||||
* NFSv4 does some encoding while processing
|
||||
*/
|
||||
nfserrp = rqstp->rq_res.head[0].iov_base
|
||||
+ rqstp->rq_res.head[0].iov_len;
|
||||
rqstp->rq_res.head[0].iov_len += sizeof(__be32);
|
||||
p = resv->iov_base + resv->iov_len;
|
||||
resv->iov_len += sizeof(__be32);
|
||||
|
||||
/* Now call the procedure handler, and encode NFS status. */
|
||||
nfserr = proc->pc_func(rqstp);
|
||||
nfserr = map_new_errors(rqstp->rq_vers, nfserr);
|
||||
if (nfserr == nfserr_dropit || test_bit(RQ_DROPME, &rqstp->rq_flags)) {
|
||||
dprintk("nfsd: Dropping request; may be revisited later\n");
|
||||
nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
|
||||
return 0;
|
||||
}
|
||||
*statp = proc->pc_func(rqstp);
|
||||
if (*statp == rpc_drop_reply || test_bit(RQ_DROPME, &rqstp->rq_flags))
|
||||
goto out_update_drop;
|
||||
|
||||
if (rqstp->rq_proc != 0)
|
||||
*nfserrp++ = nfserr;
|
||||
if (!proc->pc_encode(rqstp, p))
|
||||
goto out_encode_err;
|
||||
|
||||
/* Encode result.
|
||||
* For NFSv2, additional info is never returned in case of an error.
|
||||
*/
|
||||
if (!(nfserr && rqstp->rq_vers == 2)) {
|
||||
if (proc->pc_encode && !proc->pc_encode(rqstp, nfserrp)) {
|
||||
/* Failed to encode result. Release cache entry */
|
||||
dprintk("nfsd: failed to encode result!\n");
|
||||
nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
|
||||
*statp = rpc_system_err;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Store reply in cache. */
|
||||
nfsd_cache_update(rqstp, rqstp->rq_cachetype, statp + 1);
|
||||
out_cached_reply:
|
||||
return 1;
|
||||
|
||||
out_too_large:
|
||||
dprintk("nfsd: NFSv%d argument too large\n", rqstp->rq_vers);
|
||||
*statp = rpc_garbage_args;
|
||||
return 1;
|
||||
|
||||
out_decode_err:
|
||||
dprintk("nfsd: failed to decode arguments!\n");
|
||||
*statp = rpc_garbage_args;
|
||||
return 1;
|
||||
|
||||
out_update_drop:
|
||||
dprintk("nfsd: Dropping request; may be revisited later\n");
|
||||
nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
|
||||
out_dropit:
|
||||
return 0;
|
||||
|
||||
out_encode_err:
|
||||
dprintk("nfsd: failed to encode result!\n");
|
||||
nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
|
||||
*statp = rpc_system_err;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
+49
-3
@@ -429,12 +429,25 @@ nfssvc_encode_void(struct svc_rqst *rqstp, __be32 *p)
|
||||
return xdr_ressize_check(rqstp, p);
|
||||
}
|
||||
|
||||
int
|
||||
nfssvc_encode_stat(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nfsd_stat *resp = rqstp->rq_resp;
|
||||
|
||||
*p++ = resp->status;
|
||||
return xdr_ressize_check(rqstp, p);
|
||||
}
|
||||
|
||||
int
|
||||
nfssvc_encode_attrstat(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nfsd_attrstat *resp = rqstp->rq_resp;
|
||||
|
||||
*p++ = resp->status;
|
||||
if (resp->status != nfs_ok)
|
||||
goto out;
|
||||
p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
|
||||
out:
|
||||
return xdr_ressize_check(rqstp, p);
|
||||
}
|
||||
|
||||
@@ -443,8 +456,12 @@ nfssvc_encode_diropres(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nfsd_diropres *resp = rqstp->rq_resp;
|
||||
|
||||
*p++ = resp->status;
|
||||
if (resp->status != nfs_ok)
|
||||
goto out;
|
||||
p = encode_fh(p, &resp->fh);
|
||||
p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
|
||||
out:
|
||||
return xdr_ressize_check(rqstp, p);
|
||||
}
|
||||
|
||||
@@ -453,6 +470,10 @@ nfssvc_encode_readlinkres(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nfsd_readlinkres *resp = rqstp->rq_resp;
|
||||
|
||||
*p++ = resp->status;
|
||||
if (resp->status != nfs_ok)
|
||||
return xdr_ressize_check(rqstp, p);
|
||||
|
||||
*p++ = htonl(resp->len);
|
||||
xdr_ressize_check(rqstp, p);
|
||||
rqstp->rq_res.page_len = resp->len;
|
||||
@@ -470,6 +491,10 @@ nfssvc_encode_readres(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nfsd_readres *resp = rqstp->rq_resp;
|
||||
|
||||
*p++ = resp->status;
|
||||
if (resp->status != nfs_ok)
|
||||
return xdr_ressize_check(rqstp, p);
|
||||
|
||||
p = encode_fattr(rqstp, p, &resp->fh, &resp->stat);
|
||||
*p++ = htonl(resp->count);
|
||||
xdr_ressize_check(rqstp, p);
|
||||
@@ -490,6 +515,10 @@ nfssvc_encode_readdirres(struct svc_rqst *rqstp, __be32 *p)
|
||||
{
|
||||
struct nfsd_readdirres *resp = rqstp->rq_resp;
|
||||
|
||||
*p++ = resp->status;
|
||||
if (resp->status != nfs_ok)
|
||||
return xdr_ressize_check(rqstp, p);
|
||||
|
||||
xdr_ressize_check(rqstp, p);
|
||||
p = resp->buffer;
|
||||
*p++ = 0; /* no more entries */
|
||||
@@ -505,6 +534,10 @@ nfssvc_encode_statfsres(struct svc_rqst *rqstp, __be32 *p)
|
||||
struct nfsd_statfsres *resp = rqstp->rq_resp;
|
||||
struct kstatfs *stat = &resp->stats;
|
||||
|
||||
*p++ = resp->status;
|
||||
if (resp->status != nfs_ok)
|
||||
return xdr_ressize_check(rqstp, p);
|
||||
|
||||
*p++ = htonl(NFSSVC_MAXBLKSIZE_V2); /* max transfer size */
|
||||
*p++ = htonl(stat->f_bsize);
|
||||
*p++ = htonl(stat->f_blocks);
|
||||
@@ -561,10 +594,23 @@ nfssvc_encode_entry(void *ccdv, const char *name,
|
||||
/*
|
||||
* XDR release functions
|
||||
*/
|
||||
void
|
||||
nfssvc_release_fhandle(struct svc_rqst *rqstp)
|
||||
void nfssvc_release_attrstat(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_fhandle *resp = rqstp->rq_resp;
|
||||
struct nfsd_attrstat *resp = rqstp->rq_resp;
|
||||
|
||||
fh_put(&resp->fh);
|
||||
}
|
||||
|
||||
void nfssvc_release_diropres(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_diropres *resp = rqstp->rq_resp;
|
||||
|
||||
fh_put(&resp->fh);
|
||||
}
|
||||
|
||||
void nfssvc_release_readres(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd_readres *resp = rqstp->rq_resp;
|
||||
|
||||
fh_put(&resp->fh);
|
||||
}
|
||||
|
||||
@@ -693,31 +693,4 @@ extern void nfsd4_client_record_remove(struct nfs4_client *clp);
|
||||
extern int nfsd4_client_record_check(struct nfs4_client *clp);
|
||||
extern void nfsd4_record_grace_done(struct nfsd_net *nn);
|
||||
|
||||
/* nfs fault injection functions */
|
||||
#ifdef CONFIG_NFSD_FAULT_INJECTION
|
||||
void nfsd_fault_inject_init(void);
|
||||
void nfsd_fault_inject_cleanup(void);
|
||||
|
||||
u64 nfsd_inject_print_clients(void);
|
||||
u64 nfsd_inject_forget_client(struct sockaddr_storage *, size_t);
|
||||
u64 nfsd_inject_forget_clients(u64);
|
||||
|
||||
u64 nfsd_inject_print_locks(void);
|
||||
u64 nfsd_inject_forget_client_locks(struct sockaddr_storage *, size_t);
|
||||
u64 nfsd_inject_forget_locks(u64);
|
||||
|
||||
u64 nfsd_inject_print_openowners(void);
|
||||
u64 nfsd_inject_forget_client_openowners(struct sockaddr_storage *, size_t);
|
||||
u64 nfsd_inject_forget_openowners(u64);
|
||||
|
||||
u64 nfsd_inject_print_delegations(void);
|
||||
u64 nfsd_inject_forget_client_delegations(struct sockaddr_storage *, size_t);
|
||||
u64 nfsd_inject_forget_delegations(u64);
|
||||
u64 nfsd_inject_recall_client_delegations(struct sockaddr_storage *, size_t);
|
||||
u64 nfsd_inject_recall_delegations(u64);
|
||||
#else /* CONFIG_NFSD_FAULT_INJECTION */
|
||||
static inline void nfsd_fault_inject_init(void) {}
|
||||
static inline void nfsd_fault_inject_cleanup(void) {}
|
||||
#endif /* CONFIG_NFSD_FAULT_INJECTION */
|
||||
|
||||
#endif /* NFSD4_STATE_H */
|
||||
|
||||
+2
-2
@@ -289,8 +289,8 @@ DEFINE_STATEID_EVENT(layout_recall_done);
|
||||
DEFINE_STATEID_EVENT(layout_recall_fail);
|
||||
DEFINE_STATEID_EVENT(layout_recall_release);
|
||||
|
||||
DEFINE_STATEID_EVENT(deleg_open);
|
||||
DEFINE_STATEID_EVENT(deleg_none);
|
||||
DEFINE_STATEID_EVENT(open);
|
||||
DEFINE_STATEID_EVENT(deleg_read);
|
||||
DEFINE_STATEID_EVENT(deleg_break);
|
||||
DEFINE_STATEID_EVENT(deleg_recall);
|
||||
|
||||
|
||||
+4
-2
@@ -2259,7 +2259,8 @@ out:
|
||||
__be32
|
||||
nfsd_removexattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name)
|
||||
{
|
||||
int err, ret;
|
||||
__be32 err;
|
||||
int ret;
|
||||
|
||||
err = fh_verify(rqstp, fhp, 0, NFSD_MAY_WRITE);
|
||||
if (err)
|
||||
@@ -2283,7 +2284,8 @@ __be32
|
||||
nfsd_setxattr(struct svc_rqst *rqstp, struct svc_fh *fhp, char *name,
|
||||
void *buf, u32 len, u32 flags)
|
||||
{
|
||||
int err, ret;
|
||||
__be32 err;
|
||||
int ret;
|
||||
|
||||
err = fh_verify(rqstp, fhp, 0, NFSD_MAY_WRITE);
|
||||
if (err)
|
||||
|
||||
+15
-1
@@ -82,27 +82,37 @@ struct nfsd_readdirargs {
|
||||
__be32 * buffer;
|
||||
};
|
||||
|
||||
struct nfsd_stat {
|
||||
__be32 status;
|
||||
};
|
||||
|
||||
struct nfsd_attrstat {
|
||||
__be32 status;
|
||||
struct svc_fh fh;
|
||||
struct kstat stat;
|
||||
};
|
||||
|
||||
struct nfsd_diropres {
|
||||
__be32 status;
|
||||
struct svc_fh fh;
|
||||
struct kstat stat;
|
||||
};
|
||||
|
||||
struct nfsd_readlinkres {
|
||||
__be32 status;
|
||||
int len;
|
||||
};
|
||||
|
||||
struct nfsd_readres {
|
||||
__be32 status;
|
||||
struct svc_fh fh;
|
||||
unsigned long count;
|
||||
struct kstat stat;
|
||||
};
|
||||
|
||||
struct nfsd_readdirres {
|
||||
__be32 status;
|
||||
|
||||
int count;
|
||||
|
||||
struct readdir_cd common;
|
||||
@@ -112,6 +122,7 @@ struct nfsd_readdirres {
|
||||
};
|
||||
|
||||
struct nfsd_statfsres {
|
||||
__be32 status;
|
||||
struct kstatfs stats;
|
||||
};
|
||||
|
||||
@@ -146,6 +157,7 @@ int nfssvc_decode_linkargs(struct svc_rqst *, __be32 *);
|
||||
int nfssvc_decode_symlinkargs(struct svc_rqst *, __be32 *);
|
||||
int nfssvc_decode_readdirargs(struct svc_rqst *, __be32 *);
|
||||
int nfssvc_encode_void(struct svc_rqst *, __be32 *);
|
||||
int nfssvc_encode_stat(struct svc_rqst *, __be32 *);
|
||||
int nfssvc_encode_attrstat(struct svc_rqst *, __be32 *);
|
||||
int nfssvc_encode_diropres(struct svc_rqst *, __be32 *);
|
||||
int nfssvc_encode_readlinkres(struct svc_rqst *, __be32 *);
|
||||
@@ -156,7 +168,9 @@ int nfssvc_encode_readdirres(struct svc_rqst *, __be32 *);
|
||||
int nfssvc_encode_entry(void *, const char *name,
|
||||
int namlen, loff_t offset, u64 ino, unsigned int);
|
||||
|
||||
void nfssvc_release_fhandle(struct svc_rqst *);
|
||||
void nfssvc_release_attrstat(struct svc_rqst *rqstp);
|
||||
void nfssvc_release_diropres(struct svc_rqst *rqstp);
|
||||
void nfssvc_release_readres(struct svc_rqst *rqstp);
|
||||
|
||||
/* Helper functions for NFSv2 ACL code */
|
||||
__be32 *nfs2svc_encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp, struct kstat *stat);
|
||||
|
||||
@@ -273,6 +273,7 @@ union nfsd3_xdrstore {
|
||||
|
||||
#define NFS3_SVC_XDRSIZE sizeof(union nfsd3_xdrstore)
|
||||
|
||||
int nfs3svc_decode_voidarg(struct svc_rqst *, __be32 *);
|
||||
int nfs3svc_decode_fhandle(struct svc_rqst *, __be32 *);
|
||||
int nfs3svc_decode_sattrargs(struct svc_rqst *, __be32 *);
|
||||
int nfs3svc_decode_diropargs(struct svc_rqst *, __be32 *);
|
||||
|
||||
@@ -781,6 +781,7 @@ set_change_info(struct nfsd4_change_info *cinfo, struct svc_fh *fhp)
|
||||
|
||||
|
||||
bool nfsd4_mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp);
|
||||
int nfs4svc_decode_voidarg(struct svc_rqst *, __be32 *);
|
||||
int nfs4svc_encode_voidres(struct svc_rqst *, __be32 *);
|
||||
int nfs4svc_decode_compoundargs(struct svc_rqst *, __be32 *);
|
||||
int nfs4svc_encode_compoundres(struct svc_rqst *, __be32 *);
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* include/linux/nfs_ssc.h
|
||||
*
|
||||
* Author: Dai Ngo <dai.ngo@oracle.com>
|
||||
*
|
||||
* Copyright (c) 2020, Oracle and/or its affiliates.
|
||||
*/
|
||||
|
||||
#include <linux/nfs_fs.h>
|
||||
|
||||
extern struct nfs_ssc_client_ops_tbl nfs_ssc_client_tbl;
|
||||
|
||||
/*
|
||||
* NFS_V4
|
||||
*/
|
||||
struct nfs4_ssc_client_ops {
|
||||
struct file *(*sco_open)(struct vfsmount *ss_mnt,
|
||||
struct nfs_fh *src_fh, nfs4_stateid *stateid);
|
||||
void (*sco_close)(struct file *filep);
|
||||
};
|
||||
|
||||
/*
|
||||
* NFS_FS
|
||||
*/
|
||||
struct nfs_ssc_client_ops {
|
||||
void (*sco_sb_deactive)(struct super_block *sb);
|
||||
};
|
||||
|
||||
struct nfs_ssc_client_ops_tbl {
|
||||
const struct nfs4_ssc_client_ops *ssc_nfs4_ops;
|
||||
const struct nfs_ssc_client_ops *ssc_nfs_ops;
|
||||
};
|
||||
|
||||
extern void nfs42_ssc_register_ops(void);
|
||||
extern void nfs42_ssc_unregister_ops(void);
|
||||
|
||||
extern void nfs42_ssc_register(const struct nfs4_ssc_client_ops *ops);
|
||||
extern void nfs42_ssc_unregister(const struct nfs4_ssc_client_ops *ops);
|
||||
|
||||
#ifdef CONFIG_NFSD_V4_2_INTER_SSC
|
||||
static inline struct file *nfs42_ssc_open(struct vfsmount *ss_mnt,
|
||||
struct nfs_fh *src_fh, nfs4_stateid *stateid)
|
||||
{
|
||||
if (nfs_ssc_client_tbl.ssc_nfs4_ops)
|
||||
return (*nfs_ssc_client_tbl.ssc_nfs4_ops->sco_open)(ss_mnt, src_fh, stateid);
|
||||
return ERR_PTR(-EIO);
|
||||
}
|
||||
|
||||
static inline void nfs42_ssc_close(struct file *filep)
|
||||
{
|
||||
if (nfs_ssc_client_tbl.ssc_nfs4_ops)
|
||||
(*nfs_ssc_client_tbl.ssc_nfs4_ops->sco_close)(filep);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* NFS_FS
|
||||
*/
|
||||
extern void nfs_ssc_register(const struct nfs_ssc_client_ops *ops);
|
||||
extern void nfs_ssc_unregister(const struct nfs_ssc_client_ops *ops);
|
||||
|
||||
static inline void nfs_do_sb_deactive(struct super_block *sb)
|
||||
{
|
||||
if (nfs_ssc_client_tbl.ssc_nfs_ops)
|
||||
(*nfs_ssc_client_tbl.ssc_nfs_ops->sco_sb_deactive)(sb);
|
||||
}
|
||||
@@ -234,6 +234,8 @@ typedef int (*kxdrdproc_t)(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
|
||||
extern void xdr_init_encode(struct xdr_stream *xdr, struct xdr_buf *buf,
|
||||
__be32 *p, struct rpc_rqst *rqst);
|
||||
extern __be32 *xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes);
|
||||
extern int xdr_reserve_space_vec(struct xdr_stream *xdr, struct kvec *vec,
|
||||
size_t nbytes);
|
||||
extern void xdr_commit_encode(struct xdr_stream *xdr);
|
||||
extern void xdr_truncate_encode(struct xdr_stream *xdr, size_t len);
|
||||
extern int xdr_restrict_buflen(struct xdr_stream *xdr, int newbuflen);
|
||||
|
||||
@@ -9,11 +9,13 @@
|
||||
|
||||
#define NFS_ACL_PROGRAM 100227
|
||||
|
||||
#define ACLPROC2_NULL 0
|
||||
#define ACLPROC2_GETACL 1
|
||||
#define ACLPROC2_SETACL 2
|
||||
#define ACLPROC2_GETATTR 3
|
||||
#define ACLPROC2_ACCESS 4
|
||||
|
||||
#define ACLPROC3_NULL 0
|
||||
#define ACLPROC3_GETACL 1
|
||||
#define ACLPROC3_SETACL 2
|
||||
|
||||
|
||||
+1
-1
@@ -1023,7 +1023,7 @@ p9_fd_create_unix(struct p9_client *client, const char *addr, char *args)
|
||||
|
||||
csocket = NULL;
|
||||
|
||||
if (addr == NULL)
|
||||
if (!addr || !strlen(addr))
|
||||
return -EINVAL;
|
||||
|
||||
if (strlen(addr) >= UNIX_PATH_MAX) {
|
||||
|
||||
+2
-2
@@ -451,13 +451,13 @@ static int xen_9pfs_front_probe(struct xenbus_device *dev,
|
||||
char str[16];
|
||||
|
||||
BUILD_BUG_ON(XEN_9PFS_NUM_RINGS > 9);
|
||||
sprintf(str, "ring-ref%u", i);
|
||||
sprintf(str, "ring-ref%d", i);
|
||||
ret = xenbus_printf(xbt, dev->nodename, str, "%d",
|
||||
priv->rings[i].ref);
|
||||
if (ret)
|
||||
goto error_xenbus;
|
||||
|
||||
sprintf(str, "event-channel-%u", i);
|
||||
sprintf(str, "event-channel-%d", i);
|
||||
ret = xenbus_printf(xbt, dev->nodename, str, "%u",
|
||||
priv->rings[i].evtchn);
|
||||
if (ret)
|
||||
|
||||
@@ -1147,9 +1147,9 @@ static int gss_read_proxy_verf(struct svc_rqst *rqstp,
|
||||
struct gssp_in_token *in_token)
|
||||
{
|
||||
struct kvec *argv = &rqstp->rq_arg.head[0];
|
||||
unsigned int page_base, length;
|
||||
int pages, i, res;
|
||||
size_t inlen;
|
||||
unsigned int length, pgto_offs, pgfrom_offs;
|
||||
int pages, i, res, pgto, pgfrom;
|
||||
size_t inlen, to_offs, from_offs;
|
||||
|
||||
res = gss_read_common_verf(gc, argv, authp, in_handle);
|
||||
if (res)
|
||||
@@ -1177,17 +1177,24 @@ static int gss_read_proxy_verf(struct svc_rqst *rqstp,
|
||||
memcpy(page_address(in_token->pages[0]), argv->iov_base, length);
|
||||
inlen -= length;
|
||||
|
||||
i = 1;
|
||||
page_base = rqstp->rq_arg.page_base;
|
||||
to_offs = length;
|
||||
from_offs = rqstp->rq_arg.page_base;
|
||||
while (inlen) {
|
||||
length = min_t(unsigned int, inlen, PAGE_SIZE);
|
||||
memcpy(page_address(in_token->pages[i]),
|
||||
page_address(rqstp->rq_arg.pages[i]) + page_base,
|
||||
pgto = to_offs >> PAGE_SHIFT;
|
||||
pgfrom = from_offs >> PAGE_SHIFT;
|
||||
pgto_offs = to_offs & ~PAGE_MASK;
|
||||
pgfrom_offs = from_offs & ~PAGE_MASK;
|
||||
|
||||
length = min_t(unsigned int, inlen,
|
||||
min_t(unsigned int, PAGE_SIZE - pgto_offs,
|
||||
PAGE_SIZE - pgfrom_offs));
|
||||
memcpy(page_address(in_token->pages[pgto]) + pgto_offs,
|
||||
page_address(rqstp->rq_arg.pages[pgfrom]) + pgfrom_offs,
|
||||
length);
|
||||
|
||||
to_offs += length;
|
||||
from_offs += length;
|
||||
inlen -= length;
|
||||
page_base = 0;
|
||||
i++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ out_free:
|
||||
* by the backchannel. This function can be called multiple times
|
||||
* when creating new sessions that use the same rpc_xprt. The
|
||||
* preallocated buffers are added to the pool of resources used by
|
||||
* the rpc_xprt. Anyone of these resources may be used used by an
|
||||
* the rpc_xprt. Any one of these resources may be used by an
|
||||
* incoming callback request. It's up to the higher levels in the
|
||||
* stack to enforce that the maximum number of session slots is not
|
||||
* being exceeded.
|
||||
|
||||
+11
-10
@@ -498,16 +498,17 @@ static int cache_clean(void)
|
||||
*/
|
||||
static void do_cache_clean(struct work_struct *work)
|
||||
{
|
||||
int delay = 5;
|
||||
if (cache_clean() == -1)
|
||||
delay = round_jiffies_relative(30*HZ);
|
||||
int delay;
|
||||
|
||||
if (list_empty(&cache_list))
|
||||
delay = 0;
|
||||
return;
|
||||
|
||||
if (delay)
|
||||
queue_delayed_work(system_power_efficient_wq,
|
||||
&cache_cleaner, delay);
|
||||
if (cache_clean() == -1)
|
||||
delay = round_jiffies_relative(30*HZ);
|
||||
else
|
||||
delay = 5;
|
||||
|
||||
queue_delayed_work(system_power_efficient_wq, &cache_cleaner, delay);
|
||||
}
|
||||
|
||||
|
||||
@@ -908,7 +909,7 @@ static ssize_t cache_do_downcall(char *kaddr, const char __user *buf,
|
||||
static ssize_t cache_slow_downcall(const char __user *buf,
|
||||
size_t count, struct cache_detail *cd)
|
||||
{
|
||||
static char write_buf[8192]; /* protected by queue_io_mutex */
|
||||
static char write_buf[32768]; /* protected by queue_io_mutex */
|
||||
ssize_t ret = -EINVAL;
|
||||
|
||||
if (count >= sizeof(write_buf))
|
||||
@@ -1436,10 +1437,10 @@ static int c_show(struct seq_file *m, void *p)
|
||||
cache_get(cp);
|
||||
if (cache_check(cd, cp, NULL))
|
||||
/* cache_check does a cache_put on failure */
|
||||
seq_printf(m, "# ");
|
||||
seq_puts(m, "# ");
|
||||
else {
|
||||
if (cache_is_expired(cd, cp))
|
||||
seq_printf(m, "# ");
|
||||
seq_puts(m, "# ");
|
||||
cache_put(cp, cd);
|
||||
}
|
||||
|
||||
|
||||
+7
-1
@@ -70,7 +70,13 @@ static int proc_do_xprt(struct ctl_table *table, int write,
|
||||
return 0;
|
||||
}
|
||||
len = svc_print_xprts(tmpbuf, sizeof(tmpbuf));
|
||||
return memory_read_from_buffer(buffer, *lenp, ppos, tmpbuf, len);
|
||||
*lenp = memory_read_from_buffer(buffer, *lenp, ppos, tmpbuf, len);
|
||||
|
||||
if (*lenp < 0) {
|
||||
*lenp = 0;
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
|
||||
+46
-1
@@ -792,6 +792,51 @@ __be32 * xdr_reserve_space(struct xdr_stream *xdr, size_t nbytes)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xdr_reserve_space);
|
||||
|
||||
|
||||
/**
|
||||
* xdr_reserve_space_vec - Reserves a large amount of buffer space for sending
|
||||
* @xdr: pointer to xdr_stream
|
||||
* @vec: pointer to a kvec array
|
||||
* @nbytes: number of bytes to reserve
|
||||
*
|
||||
* Reserves enough buffer space to encode 'nbytes' of data and stores the
|
||||
* pointers in 'vec'. The size argument passed to xdr_reserve_space() is
|
||||
* determined based on the number of bytes remaining in the current page to
|
||||
* avoid invalidating iov_base pointers when xdr_commit_encode() is called.
|
||||
*/
|
||||
int xdr_reserve_space_vec(struct xdr_stream *xdr, struct kvec *vec, size_t nbytes)
|
||||
{
|
||||
int thislen;
|
||||
int v = 0;
|
||||
__be32 *p;
|
||||
|
||||
/*
|
||||
* svcrdma requires every READ payload to start somewhere
|
||||
* in xdr->pages.
|
||||
*/
|
||||
if (xdr->iov == xdr->buf->head) {
|
||||
xdr->iov = NULL;
|
||||
xdr->end = xdr->p;
|
||||
}
|
||||
|
||||
while (nbytes) {
|
||||
thislen = xdr->buf->page_len % PAGE_SIZE;
|
||||
thislen = min_t(size_t, nbytes, PAGE_SIZE - thislen);
|
||||
|
||||
p = xdr_reserve_space(xdr, thislen);
|
||||
if (!p)
|
||||
return -EIO;
|
||||
|
||||
vec[v].iov_base = p;
|
||||
vec[v].iov_len = thislen;
|
||||
v++;
|
||||
nbytes -= thislen;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xdr_reserve_space_vec);
|
||||
|
||||
/**
|
||||
* xdr_truncate_encode - truncate an encode buffer
|
||||
* @xdr: pointer to xdr_stream
|
||||
@@ -802,7 +847,7 @@ EXPORT_SYMBOL_GPL(xdr_reserve_space);
|
||||
* head, tail, and page lengths are adjusted to correspond.
|
||||
*
|
||||
* If this means moving xdr->p to a different buffer, we assume that
|
||||
* that the end pointer should be set to the end of the current page,
|
||||
* the end pointer should be set to the end of the current page,
|
||||
* except in the case of the head buffer when we assume the head
|
||||
* buffer's current length represents the end of the available buffer.
|
||||
*
|
||||
|
||||
@@ -137,7 +137,7 @@ static int svc_rdma_rw_ctx_init(struct svcxprt_rdma *rdma,
|
||||
}
|
||||
|
||||
/* A chunk context tracks all I/O for moving one Read or Write
|
||||
* chunk. This is a a set of rdma_rw's that handle data movement
|
||||
* chunk. This is a set of rdma_rw's that handle data movement
|
||||
* for all segments of one chunk.
|
||||
*
|
||||
* These are small, acquired with a single allocator call, and
|
||||
|
||||
@@ -638,10 +638,11 @@ static int svc_rdma_pull_up_reply_msg(struct svcxprt_rdma *rdma,
|
||||
while (remaining) {
|
||||
len = min_t(u32, PAGE_SIZE - pageoff, remaining);
|
||||
|
||||
memcpy(dst, page_address(*ppages), len);
|
||||
memcpy(dst, page_address(*ppages) + pageoff, len);
|
||||
remaining -= len;
|
||||
dst += len;
|
||||
pageoff = 0;
|
||||
ppages++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
#!/bin/bash
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Copyright (c) 2011 Bryan Schumaker <bjschuma@netapp.com>
|
||||
#
|
||||
# Script for easier NFSD fault injection
|
||||
|
||||
# Check that debugfs has been mounted
|
||||
DEBUGFS=`cat /proc/mounts | grep debugfs`
|
||||
if [ "$DEBUGFS" == "" ]; then
|
||||
echo "debugfs does not appear to be mounted!"
|
||||
echo "Please mount debugfs and try again"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check that the fault injection directory exists
|
||||
DEBUGDIR=`echo $DEBUGFS | awk '{print $2}'`/nfsd
|
||||
if [ ! -d "$DEBUGDIR" ]; then
|
||||
echo "$DEBUGDIR does not exist"
|
||||
echo "Check that your .config selects CONFIG_NFSD_FAULT_INJECTION"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
function help()
|
||||
{
|
||||
echo "Usage $0 injection_type [count]"
|
||||
echo ""
|
||||
echo "Injection types are:"
|
||||
ls $DEBUGDIR
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [ $# == 0 ]; then
|
||||
help
|
||||
elif [ ! -f $DEBUGDIR/$1 ]; then
|
||||
help
|
||||
elif [ $# != 2 ]; then
|
||||
COUNT=0
|
||||
else
|
||||
COUNT=$2
|
||||
fi
|
||||
|
||||
BEFORE=`mktemp`
|
||||
AFTER=`mktemp`
|
||||
dmesg > $BEFORE
|
||||
echo $COUNT > $DEBUGDIR/$1
|
||||
dmesg > $AFTER
|
||||
# Capture lines that only exist in the $AFTER file
|
||||
diff $BEFORE $AFTER | grep ">"
|
||||
rm -f $BEFORE $AFTER
|
||||
Reference in New Issue
Block a user