Merge tag 'nfsd-4.8' of git://linux-nfs.org/~bfields/linux
Pull nfsd updates from Bruce Fields: "Highlights: - Trond made a change to the server's tcp logic that allows a fast client to better take advantage of high bandwidth networks, but may increase the risk that a single client could starve other clients; a new sunrpc.svc_rpc_per_connection_limit parameter should help mitigate this in the (hopefully unlikely) event this becomes a problem in practice. - Tom Haynes added a minimal flex-layout pnfs server, which is of no use in production for now--don't build it unless you're doing client testing or further server development" * tag 'nfsd-4.8' of git://linux-nfs.org/~bfields/linux: (32 commits) nfsd: remove some dead code in nfsd_create_locked() nfsd: drop unnecessary MAY_EXEC check from create nfsd: clean up bad-type check in nfsd_create_locked nfsd: remove unnecessary positive-dentry check nfsd: reorganize nfsd_create nfsd: check d_can_lookup in fh_verify of directories nfsd: remove redundant zero-length check from create nfsd: Make creates return EEXIST instead of EACCES SUNRPC: Detect immediate closure of accepted sockets SUNRPC: accept() may return sockets that are still in SYN_RECV nfsd: allow nfsd to advertise multiple layout types nfsd: Close race between nfsd4_release_lockowner and nfsd4_lock nfsd/blocklayout: Make sure calculate signature/designator length aligned xfs: abstract block export operations from nfsd layouts SUNRPC: Remove unused callback xpo_adjust_wspace() SUNRPC: Change TCP socket space reservation SUNRPC: Add a server side per-connection limit SUNRPC: Micro optimisation for svc_data_ready SUNRPC: Call the default socket callbacks instead of open coding SUNRPC: lock the socket while detaching it ...
This commit is contained in:
@@ -90,6 +90,7 @@ config NFSD_BLOCKLAYOUT
|
||||
bool "NFSv4.1 server support for pNFS block layouts"
|
||||
depends on NFSD_V4 && BLOCK
|
||||
select NFSD_PNFS
|
||||
select EXPORTFS_BLOCK_OPS
|
||||
help
|
||||
This option enables support for the exporting pNFS block layouts
|
||||
in the kernel's NFS server. The pNFS block layout enables NFS
|
||||
@@ -102,6 +103,7 @@ config NFSD_SCSILAYOUT
|
||||
bool "NFSv4.1 server support for pNFS SCSI layouts"
|
||||
depends on NFSD_V4 && BLOCK
|
||||
select NFSD_PNFS
|
||||
select EXPORTFS_BLOCK_OPS
|
||||
help
|
||||
This option enables support for the exporting pNFS SCSI layouts
|
||||
in the kernel's NFS server. The pNFS SCSI layout enables NFS
|
||||
@@ -111,6 +113,23 @@ config NFSD_SCSILAYOUT
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config NFSD_FLEXFILELAYOUT
|
||||
bool "NFSv4.1 server support for pNFS Flex File layouts"
|
||||
depends on NFSD_V4
|
||||
select NFSD_PNFS
|
||||
help
|
||||
This option enables support for the exporting pNFS Flex File
|
||||
layouts in the kernel's NFS server. The pNFS Flex File layout
|
||||
enables NFS clients to directly perform I/O to NFSv3 devices
|
||||
accesible to both the server and the clients. See
|
||||
draft-ietf-nfsv4-flex-files for more details.
|
||||
|
||||
Warning, this server implements the bare minimum functionality
|
||||
to be a flex file server - it is for testing the client,
|
||||
not for use in production.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config NFSD_V4_SECURITY_LABEL
|
||||
bool "Provide Security Label support for NFSv4 server"
|
||||
depends on NFSD_V4 && SECURITY
|
||||
|
@@ -20,3 +20,4 @@ nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \
|
||||
nfsd-$(CONFIG_NFSD_PNFS) += nfs4layouts.o
|
||||
nfsd-$(CONFIG_NFSD_BLOCKLAYOUT) += blocklayout.o blocklayoutxdr.o
|
||||
nfsd-$(CONFIG_NFSD_SCSILAYOUT) += blocklayout.o blocklayoutxdr.o
|
||||
nfsd-$(CONFIG_NFSD_FLEXFILELAYOUT) += flexfilelayout.o flexfilelayoutxdr.o
|
||||
|
@@ -163,6 +163,7 @@ nfsd4_block_get_device_info_simple(struct super_block *sb,
|
||||
|
||||
static __be32
|
||||
nfsd4_block_proc_getdeviceinfo(struct super_block *sb,
|
||||
struct svc_rqst *rqstp,
|
||||
struct nfs4_client *clp,
|
||||
struct nfsd4_getdeviceinfo *gdp)
|
||||
{
|
||||
@@ -355,6 +356,7 @@ nfsd4_block_get_device_info_scsi(struct super_block *sb,
|
||||
|
||||
static __be32
|
||||
nfsd4_scsi_proc_getdeviceinfo(struct super_block *sb,
|
||||
struct svc_rqst *rqstp,
|
||||
struct nfs4_client *clp,
|
||||
struct nfsd4_getdeviceinfo *gdp)
|
||||
{
|
||||
|
@@ -44,7 +44,7 @@ nfsd4_block_encode_volume(struct xdr_stream *xdr, struct pnfs_block_volume *b)
|
||||
|
||||
switch (b->type) {
|
||||
case PNFS_BLOCK_VOLUME_SIMPLE:
|
||||
len = 4 + 4 + 8 + 4 + b->simple.sig_len;
|
||||
len = 4 + 4 + 8 + 4 + (XDR_QUADLEN(b->simple.sig_len) << 2);
|
||||
p = xdr_reserve_space(xdr, len);
|
||||
if (!p)
|
||||
return -ETOOSMALL;
|
||||
@@ -55,7 +55,7 @@ nfsd4_block_encode_volume(struct xdr_stream *xdr, struct pnfs_block_volume *b)
|
||||
p = xdr_encode_opaque(p, b->simple.sig, b->simple.sig_len);
|
||||
break;
|
||||
case PNFS_BLOCK_VOLUME_SCSI:
|
||||
len = 4 + 4 + 4 + 4 + b->scsi.designator_len + 8;
|
||||
len = 4 + 4 + 4 + 4 + (XDR_QUADLEN(b->scsi.designator_len) << 2) + 8;
|
||||
p = xdr_reserve_space(xdr, len);
|
||||
if (!p)
|
||||
return -ETOOSMALL;
|
||||
|
@@ -706,7 +706,7 @@ static void svc_export_init(struct cache_head *cnew, struct cache_head *citem)
|
||||
new->ex_fslocs.locations = NULL;
|
||||
new->ex_fslocs.locations_count = 0;
|
||||
new->ex_fslocs.migrated = 0;
|
||||
new->ex_layout_type = 0;
|
||||
new->ex_layout_types = 0;
|
||||
new->ex_uuid = NULL;
|
||||
new->cd = item->cd;
|
||||
}
|
||||
@@ -731,7 +731,7 @@ static void export_update(struct cache_head *cnew, struct cache_head *citem)
|
||||
item->ex_fslocs.locations_count = 0;
|
||||
new->ex_fslocs.migrated = item->ex_fslocs.migrated;
|
||||
item->ex_fslocs.migrated = 0;
|
||||
new->ex_layout_type = item->ex_layout_type;
|
||||
new->ex_layout_types = item->ex_layout_types;
|
||||
new->ex_nflavors = item->ex_nflavors;
|
||||
for (i = 0; i < MAX_SECINFO_LIST; i++) {
|
||||
new->ex_flavors[i] = item->ex_flavors[i];
|
||||
@@ -954,6 +954,16 @@ __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
|
||||
rqstp->rq_cred.cr_flavor == RPC_AUTH_UNIX)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* If the compound op contains a spo_must_allowed op,
|
||||
* it will be sent with integrity/protection which
|
||||
* will have to be expressly allowed on mounts that
|
||||
* don't support it
|
||||
*/
|
||||
|
||||
if (nfsd4_spo_must_allow(rqstp))
|
||||
return 0;
|
||||
|
||||
return nfserr_wrongsec;
|
||||
}
|
||||
|
||||
|
@@ -57,7 +57,7 @@ struct svc_export {
|
||||
struct nfsd4_fs_locations ex_fslocs;
|
||||
uint32_t ex_nflavors;
|
||||
struct exp_flavor_info ex_flavors[MAX_SECINFO_LIST];
|
||||
enum pnfs_layouttype ex_layout_type;
|
||||
u32 ex_layout_types;
|
||||
struct nfsd4_deviceid_map *ex_devid_map;
|
||||
struct cache_detail *cd;
|
||||
};
|
||||
|
133
fs/nfsd/flexfilelayout.c
Normal file
133
fs/nfsd/flexfilelayout.c
Normal file
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Tom Haynes <loghyr@primarydata.com>
|
||||
*
|
||||
* The following implements a super-simple flex-file server
|
||||
* where the NFSv4.1 mds is also the ds. And the storage is
|
||||
* the same. I.e., writing to the mds via a NFSv4.1 WRITE
|
||||
* goes to the same location as the NFSv3 WRITE.
|
||||
*/
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <linux/nfsd/debug.h>
|
||||
|
||||
#include <linux/sunrpc/addr.h>
|
||||
|
||||
#include "flexfilelayoutxdr.h"
|
||||
#include "pnfs.h"
|
||||
|
||||
#define NFSDDBG_FACILITY NFSDDBG_PNFS
|
||||
|
||||
static __be32
|
||||
nfsd4_ff_proc_layoutget(struct inode *inode, const struct svc_fh *fhp,
|
||||
struct nfsd4_layoutget *args)
|
||||
{
|
||||
struct nfsd4_layout_seg *seg = &args->lg_seg;
|
||||
u32 device_generation = 0;
|
||||
int error;
|
||||
uid_t u;
|
||||
|
||||
struct pnfs_ff_layout *fl;
|
||||
|
||||
/*
|
||||
* The super simple flex file server has 1 mirror, 1 data server,
|
||||
* and 1 file handle. So instead of 4 allocs, do 1 for now.
|
||||
* Zero it out for the stateid - don't want junk in there!
|
||||
*/
|
||||
error = -ENOMEM;
|
||||
fl = kzalloc(sizeof(*fl), GFP_KERNEL);
|
||||
if (!fl)
|
||||
goto out_error;
|
||||
args->lg_content = fl;
|
||||
|
||||
/*
|
||||
* Avoid layout commit, try to force the I/O to the DS,
|
||||
* and for fun, cause all IOMODE_RW layout segments to
|
||||
* effectively be WRITE only.
|
||||
*/
|
||||
fl->flags = FF_FLAGS_NO_LAYOUTCOMMIT | FF_FLAGS_NO_IO_THRU_MDS |
|
||||
FF_FLAGS_NO_READ_IO;
|
||||
|
||||
/* Do not allow a IOMODE_READ segment to have write pemissions */
|
||||
if (seg->iomode == IOMODE_READ) {
|
||||
u = from_kuid(&init_user_ns, inode->i_uid) + 1;
|
||||
fl->uid = make_kuid(&init_user_ns, u);
|
||||
} else
|
||||
fl->uid = inode->i_uid;
|
||||
fl->gid = inode->i_gid;
|
||||
|
||||
error = nfsd4_set_deviceid(&fl->deviceid, fhp, device_generation);
|
||||
if (error)
|
||||
goto out_error;
|
||||
|
||||
fl->fh.size = fhp->fh_handle.fh_size;
|
||||
memcpy(fl->fh.data, &fhp->fh_handle.fh_base, fl->fh.size);
|
||||
|
||||
/* Give whole file layout segments */
|
||||
seg->offset = 0;
|
||||
seg->length = NFS4_MAX_UINT64;
|
||||
|
||||
dprintk("GET: 0x%llx:0x%llx %d\n", seg->offset, seg->length,
|
||||
seg->iomode);
|
||||
return 0;
|
||||
|
||||
out_error:
|
||||
seg->length = 0;
|
||||
return nfserrno(error);
|
||||
}
|
||||
|
||||
static __be32
|
||||
nfsd4_ff_proc_getdeviceinfo(struct super_block *sb, struct svc_rqst *rqstp,
|
||||
struct nfs4_client *clp, struct nfsd4_getdeviceinfo *gdp)
|
||||
{
|
||||
struct pnfs_ff_device_addr *da;
|
||||
|
||||
u16 port;
|
||||
char addr[INET6_ADDRSTRLEN];
|
||||
|
||||
da = kzalloc(sizeof(struct pnfs_ff_device_addr), GFP_KERNEL);
|
||||
if (!da)
|
||||
return nfserrno(-ENOMEM);
|
||||
|
||||
gdp->gd_device = da;
|
||||
|
||||
da->version = 3;
|
||||
da->minor_version = 0;
|
||||
|
||||
da->rsize = svc_max_payload(rqstp);
|
||||
da->wsize = da->rsize;
|
||||
|
||||
rpc_ntop((struct sockaddr *)&rqstp->rq_daddr,
|
||||
addr, INET6_ADDRSTRLEN);
|
||||
if (rqstp->rq_daddr.ss_family == AF_INET) {
|
||||
struct sockaddr_in *sin;
|
||||
|
||||
sin = (struct sockaddr_in *)&rqstp->rq_daddr;
|
||||
port = ntohs(sin->sin_port);
|
||||
snprintf(da->netaddr.netid, FF_NETID_LEN + 1, "tcp");
|
||||
da->netaddr.netid_len = 3;
|
||||
} else {
|
||||
struct sockaddr_in6 *sin6;
|
||||
|
||||
sin6 = (struct sockaddr_in6 *)&rqstp->rq_daddr;
|
||||
port = ntohs(sin6->sin6_port);
|
||||
snprintf(da->netaddr.netid, FF_NETID_LEN + 1, "tcp6");
|
||||
da->netaddr.netid_len = 4;
|
||||
}
|
||||
|
||||
da->netaddr.addr_len =
|
||||
snprintf(da->netaddr.addr, FF_ADDR_LEN + 1,
|
||||
"%s.%hhu.%hhu", addr, port >> 8, port & 0xff);
|
||||
|
||||
da->tightly_coupled = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct nfsd4_layout_ops ff_layout_ops = {
|
||||
.notify_types =
|
||||
NOTIFY_DEVICEID4_DELETE | NOTIFY_DEVICEID4_CHANGE,
|
||||
.proc_getdeviceinfo = nfsd4_ff_proc_getdeviceinfo,
|
||||
.encode_getdeviceinfo = nfsd4_ff_encode_getdeviceinfo,
|
||||
.proc_layoutget = nfsd4_ff_proc_layoutget,
|
||||
.encode_layoutget = nfsd4_ff_encode_layoutget,
|
||||
};
|
115
fs/nfsd/flexfilelayoutxdr.c
Normal file
115
fs/nfsd/flexfilelayoutxdr.c
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Tom Haynes <loghyr@primarydata.com>
|
||||
*/
|
||||
#include <linux/sunrpc/svc.h>
|
||||
#include <linux/nfs4.h>
|
||||
|
||||
#include "nfsd.h"
|
||||
#include "flexfilelayoutxdr.h"
|
||||
|
||||
#define NFSDDBG_FACILITY NFSDDBG_PNFS
|
||||
|
||||
struct ff_idmap {
|
||||
char buf[11];
|
||||
int len;
|
||||
};
|
||||
|
||||
__be32
|
||||
nfsd4_ff_encode_layoutget(struct xdr_stream *xdr,
|
||||
struct nfsd4_layoutget *lgp)
|
||||
{
|
||||
struct pnfs_ff_layout *fl = lgp->lg_content;
|
||||
int len, mirror_len, ds_len, fh_len;
|
||||
__be32 *p;
|
||||
|
||||
/*
|
||||
* Unlike nfsd4_encode_user, we know these will
|
||||
* always be stringified.
|
||||
*/
|
||||
struct ff_idmap uid;
|
||||
struct ff_idmap gid;
|
||||
|
||||
fh_len = 4 + fl->fh.size;
|
||||
|
||||
uid.len = sprintf(uid.buf, "%u", from_kuid(&init_user_ns, fl->uid));
|
||||
gid.len = sprintf(gid.buf, "%u", from_kgid(&init_user_ns, fl->gid));
|
||||
|
||||
/* 8 + len for recording the length, name, and padding */
|
||||
ds_len = 20 + sizeof(stateid_opaque_t) + 4 + fh_len +
|
||||
8 + uid.len + 8 + gid.len;
|
||||
|
||||
mirror_len = 4 + ds_len;
|
||||
|
||||
/* The layout segment */
|
||||
len = 20 + mirror_len;
|
||||
|
||||
p = xdr_reserve_space(xdr, sizeof(__be32) + len);
|
||||
if (!p)
|
||||
return nfserr_toosmall;
|
||||
|
||||
*p++ = cpu_to_be32(len);
|
||||
p = xdr_encode_hyper(p, 0); /* stripe unit of 1 */
|
||||
|
||||
*p++ = cpu_to_be32(1); /* single mirror */
|
||||
*p++ = cpu_to_be32(1); /* single data server */
|
||||
|
||||
p = xdr_encode_opaque_fixed(p, &fl->deviceid,
|
||||
sizeof(struct nfsd4_deviceid));
|
||||
|
||||
*p++ = cpu_to_be32(1); /* efficiency */
|
||||
|
||||
*p++ = cpu_to_be32(fl->stateid.si_generation);
|
||||
p = xdr_encode_opaque_fixed(p, &fl->stateid.si_opaque,
|
||||
sizeof(stateid_opaque_t));
|
||||
|
||||
*p++ = cpu_to_be32(1); /* single file handle */
|
||||
p = xdr_encode_opaque(p, fl->fh.data, fl->fh.size);
|
||||
|
||||
p = xdr_encode_opaque(p, uid.buf, uid.len);
|
||||
p = xdr_encode_opaque(p, gid.buf, gid.len);
|
||||
|
||||
*p++ = cpu_to_be32(fl->flags);
|
||||
*p++ = cpu_to_be32(0); /* No stats collect hint */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
__be32
|
||||
nfsd4_ff_encode_getdeviceinfo(struct xdr_stream *xdr,
|
||||
struct nfsd4_getdeviceinfo *gdp)
|
||||
{
|
||||
struct pnfs_ff_device_addr *da = gdp->gd_device;
|
||||
int len;
|
||||
int ver_len;
|
||||
int addr_len;
|
||||
__be32 *p;
|
||||
|
||||
/* len + padding for two strings */
|
||||
addr_len = 16 + da->netaddr.netid_len + da->netaddr.addr_len;
|
||||
ver_len = 20;
|
||||
|
||||
len = 4 + ver_len + 4 + addr_len;
|
||||
|
||||
p = xdr_reserve_space(xdr, len + sizeof(__be32));
|
||||
if (!p)
|
||||
return nfserr_resource;
|
||||
|
||||
/*
|
||||
* Fill in the overall length and number of volumes at the beginning
|
||||
* of the layout.
|
||||
*/
|
||||
*p++ = cpu_to_be32(len);
|
||||
*p++ = cpu_to_be32(1); /* 1 netaddr */
|
||||
p = xdr_encode_opaque(p, da->netaddr.netid, da->netaddr.netid_len);
|
||||
p = xdr_encode_opaque(p, da->netaddr.addr, da->netaddr.addr_len);
|
||||
|
||||
*p++ = cpu_to_be32(1); /* 1 versions */
|
||||
|
||||
*p++ = cpu_to_be32(da->version);
|
||||
*p++ = cpu_to_be32(da->minor_version);
|
||||
*p++ = cpu_to_be32(da->rsize);
|
||||
*p++ = cpu_to_be32(da->wsize);
|
||||
*p++ = cpu_to_be32(da->tightly_coupled);
|
||||
|
||||
return 0;
|
||||
}
|
49
fs/nfsd/flexfilelayoutxdr.h
Normal file
49
fs/nfsd/flexfilelayoutxdr.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) 2016 Tom Haynes <loghyr@primarydata.com>
|
||||
*/
|
||||
#ifndef _NFSD_FLEXFILELAYOUTXDR_H
|
||||
#define _NFSD_FLEXFILELAYOUTXDR_H 1
|
||||
|
||||
#include <linux/inet.h>
|
||||
#include "xdr4.h"
|
||||
|
||||
#define FF_FLAGS_NO_LAYOUTCOMMIT 1
|
||||
#define FF_FLAGS_NO_IO_THRU_MDS 2
|
||||
#define FF_FLAGS_NO_READ_IO 4
|
||||
|
||||
struct xdr_stream;
|
||||
|
||||
#define FF_NETID_LEN (4)
|
||||
#define FF_ADDR_LEN (INET6_ADDRSTRLEN + 8)
|
||||
struct pnfs_ff_netaddr {
|
||||
char netid[FF_NETID_LEN + 1];
|
||||
char addr[FF_ADDR_LEN + 1];
|
||||
u32 netid_len;
|
||||
u32 addr_len;
|
||||
};
|
||||
|
||||
struct pnfs_ff_device_addr {
|
||||
struct pnfs_ff_netaddr netaddr;
|
||||
u32 version;
|
||||
u32 minor_version;
|
||||
u32 rsize;
|
||||
u32 wsize;
|
||||
bool tightly_coupled;
|
||||
};
|
||||
|
||||
struct pnfs_ff_layout {
|
||||
u32 flags;
|
||||
u32 stats_collect_hint;
|
||||
kuid_t uid;
|
||||
kgid_t gid;
|
||||
struct nfsd4_deviceid deviceid;
|
||||
stateid_t stateid;
|
||||
struct nfs_fh fh;
|
||||
};
|
||||
|
||||
__be32 nfsd4_ff_encode_getdeviceinfo(struct xdr_stream *xdr,
|
||||
struct nfsd4_getdeviceinfo *gdp);
|
||||
__be32 nfsd4_ff_encode_layoutget(struct xdr_stream *xdr,
|
||||
struct nfsd4_layoutget *lgp);
|
||||
|
||||
#endif /* _NFSD_FLEXFILELAYOUTXDR_H */
|
@@ -27,6 +27,9 @@ static const struct nfsd4_callback_ops nfsd4_cb_layout_ops;
|
||||
static const struct lock_manager_operations nfsd4_layouts_lm_ops;
|
||||
|
||||
const struct nfsd4_layout_ops *nfsd4_layout_ops[LAYOUT_TYPE_MAX] = {
|
||||
#ifdef CONFIG_NFSD_FLEXFILELAYOUT
|
||||
[LAYOUT_FLEX_FILES] = &ff_layout_ops,
|
||||
#endif
|
||||
#ifdef CONFIG_NFSD_BLOCKLAYOUT
|
||||
[LAYOUT_BLOCK_VOLUME] = &bl_layout_ops,
|
||||
#endif
|
||||
@@ -122,28 +125,35 @@ nfsd4_set_deviceid(struct nfsd4_deviceid *id, const struct svc_fh *fhp,
|
||||
|
||||
void nfsd4_setup_layout_type(struct svc_export *exp)
|
||||
{
|
||||
#if defined(CONFIG_NFSD_BLOCKLAYOUT) || defined(CONFIG_NFSD_SCSILAYOUT)
|
||||
struct super_block *sb = exp->ex_path.mnt->mnt_sb;
|
||||
#endif
|
||||
|
||||
if (!(exp->ex_flags & NFSEXP_PNFS))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Check if the file system supports exporting a block-like layout.
|
||||
* If flex file is configured, use it by default. Otherwise
|
||||
* check if the file system supports exporting a block-like layout.
|
||||
* If the block device supports reservations prefer the SCSI layout,
|
||||
* otherwise advertise the block layout.
|
||||
*/
|
||||
#ifdef CONFIG_NFSD_FLEXFILELAYOUT
|
||||
exp->ex_layout_types |= 1 << LAYOUT_FLEX_FILES;
|
||||
#endif
|
||||
#ifdef CONFIG_NFSD_BLOCKLAYOUT
|
||||
/* overwrite flex file layout selection if needed */
|
||||
if (sb->s_export_op->get_uuid &&
|
||||
sb->s_export_op->map_blocks &&
|
||||
sb->s_export_op->commit_blocks)
|
||||
exp->ex_layout_type = LAYOUT_BLOCK_VOLUME;
|
||||
exp->ex_layout_types |= 1 << LAYOUT_BLOCK_VOLUME;
|
||||
#endif
|
||||
#ifdef CONFIG_NFSD_SCSILAYOUT
|
||||
/* overwrite block layout selection if needed */
|
||||
if (sb->s_export_op->map_blocks &&
|
||||
sb->s_export_op->commit_blocks &&
|
||||
sb->s_bdev && sb->s_bdev->bd_disk->fops->pr_ops)
|
||||
exp->ex_layout_type = LAYOUT_SCSI;
|
||||
exp->ex_layout_types |= 1 << LAYOUT_SCSI;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@@ -605,8 +605,7 @@ nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
|
||||
fh_init(&resfh, NFS4_FHSIZE);
|
||||
|
||||
status = fh_verify(rqstp, &cstate->current_fh, S_IFDIR,
|
||||
NFSD_MAY_CREATE);
|
||||
status = fh_verify(rqstp, &cstate->current_fh, S_IFDIR, NFSD_MAY_NOP);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
@@ -1219,12 +1218,12 @@ nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
|
||||
static const struct nfsd4_layout_ops *
|
||||
nfsd4_layout_verify(struct svc_export *exp, unsigned int layout_type)
|
||||
{
|
||||
if (!exp->ex_layout_type) {
|
||||
if (!exp->ex_layout_types) {
|
||||
dprintk("%s: export does not support pNFS\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (exp->ex_layout_type != layout_type) {
|
||||
if (!(exp->ex_layout_types & (1 << layout_type))) {
|
||||
dprintk("%s: layout type %d not supported\n",
|
||||
__func__, layout_type);
|
||||
return NULL;
|
||||
@@ -1270,7 +1269,7 @@ nfsd4_getdeviceinfo(struct svc_rqst *rqstp,
|
||||
nfserr = nfs_ok;
|
||||
if (gdp->gd_maxcount != 0) {
|
||||
nfserr = ops->proc_getdeviceinfo(exp->ex_path.mnt->mnt_sb,
|
||||
cstate->session->se_client, gdp);
|
||||
rqstp, cstate->session->se_client, gdp);
|
||||
}
|
||||
|
||||
gdp->gd_notify_types &= ops->notify_types;
|
||||
@@ -2335,6 +2334,45 @@ static struct nfsd4_operation nfsd4_ops[] = {
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* nfsd4_spo_must_allow - Determine if the compound op contains an
|
||||
* operation that is allowed to be sent with machine credentials
|
||||
*
|
||||
* @rqstp: a pointer to the struct svc_rqst
|
||||
*
|
||||
* Checks to see if the compound contains a spo_must_allow op
|
||||
* and confirms that it was sent with the proper machine creds.
|
||||
*/
|
||||
|
||||
bool nfsd4_spo_must_allow(struct svc_rqst *rqstp)
|
||||
{
|
||||
struct nfsd4_compoundres *resp = rqstp->rq_resp;
|
||||
struct nfsd4_compoundargs *argp = rqstp->rq_argp;
|
||||
struct nfsd4_op *this = &argp->ops[resp->opcnt - 1];
|
||||
struct nfsd4_compound_state *cstate = &resp->cstate;
|
||||
struct nfs4_op_map *allow = &cstate->clp->cl_spo_must_allow;
|
||||
u32 opiter;
|
||||
|
||||
if (!cstate->minorversion)
|
||||
return false;
|
||||
|
||||
if (cstate->spo_must_allowed == true)
|
||||
return true;
|
||||
|
||||
opiter = resp->opcnt;
|
||||
while (opiter < argp->opcnt) {
|
||||
this = &argp->ops[opiter++];
|
||||
if (test_bit(this->opnum, allow->u.longs) &&
|
||||
cstate->clp->cl_mach_cred &&
|
||||
nfsd4_mach_creds_match(cstate->clp, rqstp)) {
|
||||
cstate->spo_must_allowed = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
cstate->spo_must_allowed = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
int nfsd4_max_reply(struct svc_rqst *rqstp, struct nfsd4_op *op)
|
||||
{
|
||||
struct nfsd4_operation *opdesc;
|
||||
|
@@ -1200,27 +1200,6 @@ free_ol_stateid_reaplist(struct list_head *reaplist)
|
||||
}
|
||||
}
|
||||
|
||||
static void release_lockowner(struct nfs4_lockowner *lo)
|
||||
{
|
||||
struct nfs4_client *clp = lo->lo_owner.so_client;
|
||||
struct nfs4_ol_stateid *stp;
|
||||
struct list_head reaplist;
|
||||
|
||||
INIT_LIST_HEAD(&reaplist);
|
||||
|
||||
spin_lock(&clp->cl_lock);
|
||||
unhash_lockowner_locked(lo);
|
||||
while (!list_empty(&lo->lo_owner.so_stateids)) {
|
||||
stp = list_first_entry(&lo->lo_owner.so_stateids,
|
||||
struct nfs4_ol_stateid, st_perstateowner);
|
||||
WARN_ON(!unhash_lock_stateid(stp));
|
||||
put_ol_stateid_locked(stp, &reaplist);
|
||||
}
|
||||
spin_unlock(&clp->cl_lock);
|
||||
free_ol_stateid_reaplist(&reaplist);
|
||||
nfs4_put_stateowner(&lo->lo_owner);
|
||||
}
|
||||
|
||||
static void release_open_stateid_locks(struct nfs4_ol_stateid *open_stp,
|
||||
struct list_head *reaplist)
|
||||
{
|
||||
@@ -1972,7 +1951,7 @@ static bool svc_rqst_integrity_protected(struct svc_rqst *rqstp)
|
||||
service == RPC_GSS_SVC_PRIVACY;
|
||||
}
|
||||
|
||||
static bool mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp)
|
||||
bool nfsd4_mach_creds_match(struct nfs4_client *cl, struct svc_rqst *rqstp)
|
||||
{
|
||||
struct svc_cred *cr = &rqstp->rq_cred;
|
||||
|
||||
@@ -2388,6 +2367,22 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
|
||||
|
||||
switch (exid->spa_how) {
|
||||
case SP4_MACH_CRED:
|
||||
exid->spo_must_enforce[0] = 0;
|
||||
exid->spo_must_enforce[1] = (
|
||||
1 << (OP_BIND_CONN_TO_SESSION - 32) |
|
||||
1 << (OP_EXCHANGE_ID - 32) |
|
||||
1 << (OP_CREATE_SESSION - 32) |
|
||||
1 << (OP_DESTROY_SESSION - 32) |
|
||||
1 << (OP_DESTROY_CLIENTID - 32));
|
||||
|
||||
exid->spo_must_allow[0] &= (1 << (OP_CLOSE) |
|
||||
1 << (OP_OPEN_DOWNGRADE) |
|
||||
1 << (OP_LOCKU) |
|
||||
1 << (OP_DELEGRETURN));
|
||||
|
||||
exid->spo_must_allow[1] &= (
|
||||
1 << (OP_TEST_STATEID - 32) |
|
||||
1 << (OP_FREE_STATEID - 32));
|
||||
if (!svc_rqst_integrity_protected(rqstp)) {
|
||||
status = nfserr_inval;
|
||||
goto out_nolock;
|
||||
@@ -2424,7 +2419,7 @@ nfsd4_exchange_id(struct svc_rqst *rqstp,
|
||||
status = nfserr_inval;
|
||||
goto out;
|
||||
}
|
||||
if (!mach_creds_match(conf, rqstp)) {
|
||||
if (!nfsd4_mach_creds_match(conf, rqstp)) {
|
||||
status = nfserr_wrong_cred;
|
||||
goto out;
|
||||
}
|
||||
@@ -2473,6 +2468,8 @@ out_new:
|
||||
goto out;
|
||||
}
|
||||
new->cl_minorversion = cstate->minorversion;
|
||||
new->cl_spo_must_allow.u.words[0] = exid->spo_must_allow[0];
|
||||
new->cl_spo_must_allow.u.words[1] = exid->spo_must_allow[1];
|
||||
|
||||
gen_clid(new, nn);
|
||||
add_to_unconfirmed(new);
|
||||
@@ -2676,7 +2673,7 @@ nfsd4_create_session(struct svc_rqst *rqstp,
|
||||
|
||||
if (conf) {
|
||||
status = nfserr_wrong_cred;
|
||||
if (!mach_creds_match(conf, rqstp))
|
||||
if (!nfsd4_mach_creds_match(conf, rqstp))
|
||||
goto out_free_conn;
|
||||
cs_slot = &conf->cl_cs_slot;
|
||||
status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
|
||||
@@ -2692,7 +2689,7 @@ nfsd4_create_session(struct svc_rqst *rqstp,
|
||||
goto out_free_conn;
|
||||
}
|
||||
status = nfserr_wrong_cred;
|
||||
if (!mach_creds_match(unconf, rqstp))
|
||||
if (!nfsd4_mach_creds_match(unconf, rqstp))
|
||||
goto out_free_conn;
|
||||
cs_slot = &unconf->cl_cs_slot;
|
||||
status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
|
||||
@@ -2801,7 +2798,7 @@ __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,
|
||||
if (!session)
|
||||
goto out_no_session;
|
||||
status = nfserr_wrong_cred;
|
||||
if (!mach_creds_match(session->se_client, rqstp))
|
||||
if (!nfsd4_mach_creds_match(session->se_client, rqstp))
|
||||
goto out;
|
||||
status = nfsd4_map_bcts_dir(&bcts->dir);
|
||||
if (status)
|
||||
@@ -2848,7 +2845,7 @@ nfsd4_destroy_session(struct svc_rqst *r,
|
||||
if (!ses)
|
||||
goto out_client_lock;
|
||||
status = nfserr_wrong_cred;
|
||||
if (!mach_creds_match(ses->se_client, r))
|
||||
if (!nfsd4_mach_creds_match(ses->se_client, r))
|
||||
goto out_put_session;
|
||||
status = mark_session_dead_locked(ses, 1 + ref_held_by_me);
|
||||
if (status)
|
||||
@@ -3087,7 +3084,7 @@ nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta
|
||||
status = nfserr_stale_clientid;
|
||||
goto out;
|
||||
}
|
||||
if (!mach_creds_match(clp, rqstp)) {
|
||||
if (!nfsd4_mach_creds_match(clp, rqstp)) {
|
||||
clp = NULL;
|
||||
status = nfserr_wrong_cred;
|
||||
goto out;
|
||||
@@ -3112,7 +3109,7 @@ nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta
|
||||
* We don't take advantage of the rca_one_fs case.
|
||||
* That's OK, it's optional, we can safely ignore it.
|
||||
*/
|
||||
return nfs_ok;
|
||||
return nfs_ok;
|
||||
}
|
||||
|
||||
status = nfserr_complete_already;
|
||||
@@ -5945,6 +5942,7 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
|
||||
__be32 status;
|
||||
struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
|
||||
struct nfs4_client *clp;
|
||||
LIST_HEAD (reaplist);
|
||||
|
||||
dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
|
||||
clid->cl_boot, clid->cl_id);
|
||||
@@ -5975,9 +5973,23 @@ nfsd4_release_lockowner(struct svc_rqst *rqstp,
|
||||
nfs4_get_stateowner(sop);
|
||||
break;
|
||||
}
|
||||
if (!lo) {
|
||||
spin_unlock(&clp->cl_lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
unhash_lockowner_locked(lo);
|
||||
while (!list_empty(&lo->lo_owner.so_stateids)) {
|
||||
stp = list_first_entry(&lo->lo_owner.so_stateids,
|
||||
struct nfs4_ol_stateid,
|
||||
st_perstateowner);
|
||||
WARN_ON(!unhash_lock_stateid(stp));
|
||||
put_ol_stateid_locked(stp, &reaplist);
|
||||
}
|
||||
spin_unlock(&clp->cl_lock);
|
||||
if (lo)
|
||||
release_lockowner(lo);
|
||||
free_ol_stateid_reaplist(&reaplist);
|
||||
nfs4_put_stateowner(&lo->lo_owner);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@@ -1299,16 +1299,14 @@ nfsd4_decode_exchange_id(struct nfsd4_compoundargs *argp,
|
||||
break;
|
||||
case SP4_MACH_CRED:
|
||||
/* spo_must_enforce */
|
||||
READ_BUF(4);
|
||||
dummy = be32_to_cpup(p++);
|
||||
READ_BUF(dummy * 4);
|
||||
p += dummy;
|
||||
|
||||
status = nfsd4_decode_bitmap(argp,
|
||||
exid->spo_must_enforce);
|
||||
if (status)
|
||||
goto out;
|
||||
/* spo_must_allow */
|
||||
READ_BUF(4);
|
||||
dummy = be32_to_cpup(p++);
|
||||
READ_BUF(dummy * 4);
|
||||
p += dummy;
|
||||
status = nfsd4_decode_bitmap(argp, exid->spo_must_allow);
|
||||
if (status)
|
||||
goto out;
|
||||
break;
|
||||
case SP4_SSV:
|
||||
/* ssp_ops */
|
||||
@@ -2164,22 +2162,20 @@ nfsd4_encode_aclname(struct xdr_stream *xdr, struct svc_rqst *rqstp,
|
||||
}
|
||||
|
||||
static inline __be32
|
||||
nfsd4_encode_layout_type(struct xdr_stream *xdr, enum pnfs_layouttype layout_type)
|
||||
nfsd4_encode_layout_types(struct xdr_stream *xdr, u32 layout_types)
|
||||
{
|
||||
__be32 *p;
|
||||
__be32 *p;
|
||||
unsigned long i = hweight_long(layout_types);
|
||||
|
||||
if (layout_type) {
|
||||
p = xdr_reserve_space(xdr, 8);
|
||||
if (!p)
|
||||
return nfserr_resource;
|
||||
*p++ = cpu_to_be32(1);
|
||||
*p++ = cpu_to_be32(layout_type);
|
||||
} else {
|
||||
p = xdr_reserve_space(xdr, 4);
|
||||
if (!p)
|
||||
return nfserr_resource;
|
||||
*p++ = cpu_to_be32(0);
|
||||
}
|
||||
p = xdr_reserve_space(xdr, 4 + 4 * i);
|
||||
if (!p)
|
||||
return nfserr_resource;
|
||||
|
||||
*p++ = cpu_to_be32(i);
|
||||
|
||||
for (i = LAYOUT_NFSV4_1_FILES; i < LAYOUT_TYPE_MAX; ++i)
|
||||
if (layout_types & (1 << i))
|
||||
*p++ = cpu_to_be32(i);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -2754,13 +2750,13 @@ out_acl:
|
||||
}
|
||||
#ifdef CONFIG_NFSD_PNFS
|
||||
if (bmval1 & FATTR4_WORD1_FS_LAYOUT_TYPES) {
|
||||
status = nfsd4_encode_layout_type(xdr, exp->ex_layout_type);
|
||||
status = nfsd4_encode_layout_types(xdr, exp->ex_layout_types);
|
||||
if (status)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (bmval2 & FATTR4_WORD2_LAYOUT_TYPES) {
|
||||
status = nfsd4_encode_layout_type(xdr, exp->ex_layout_type);
|
||||
status = nfsd4_encode_layout_types(xdr, exp->ex_layout_types);
|
||||
if (status)
|
||||
goto out;
|
||||
}
|
||||
@@ -3867,14 +3863,6 @@ nfsd4_encode_write(struct nfsd4_compoundres *resp, __be32 nfserr, struct nfsd4_w
|
||||
return nfserr;
|
||||
}
|
||||
|
||||
static const u32 nfs4_minimal_spo_must_enforce[2] = {
|
||||
[1] = 1 << (OP_BIND_CONN_TO_SESSION - 32) |
|
||||
1 << (OP_EXCHANGE_ID - 32) |
|
||||
1 << (OP_CREATE_SESSION - 32) |
|
||||
1 << (OP_DESTROY_SESSION - 32) |
|
||||
1 << (OP_DESTROY_CLIENTID - 32)
|
||||
};
|
||||
|
||||
static __be32
|
||||
nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr,
|
||||
struct nfsd4_exchange_id *exid)
|
||||
@@ -3885,6 +3873,7 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr,
|
||||
char *server_scope;
|
||||
int major_id_sz;
|
||||
int server_scope_sz;
|
||||
int status = 0;
|
||||
uint64_t minor_id = 0;
|
||||
|
||||
if (nfserr)
|
||||
@@ -3913,18 +3902,20 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr,
|
||||
case SP4_NONE:
|
||||
break;
|
||||
case SP4_MACH_CRED:
|
||||
/* spo_must_enforce, spo_must_allow */
|
||||
p = xdr_reserve_space(xdr, 16);
|
||||
if (!p)
|
||||
return nfserr_resource;
|
||||
|
||||
/* spo_must_enforce bitmap: */
|
||||
*p++ = cpu_to_be32(2);
|
||||
*p++ = cpu_to_be32(nfs4_minimal_spo_must_enforce[0]);
|
||||
*p++ = cpu_to_be32(nfs4_minimal_spo_must_enforce[1]);
|
||||
/* empty spo_must_allow bitmap: */
|
||||
*p++ = cpu_to_be32(0);
|
||||
|
||||
status = nfsd4_encode_bitmap(xdr,
|
||||
exid->spo_must_enforce[0],
|
||||
exid->spo_must_enforce[1],
|
||||
exid->spo_must_enforce[2]);
|
||||
if (status)
|
||||
goto out;
|
||||
/* spo_must_allow bitmap: */
|
||||
status = nfsd4_encode_bitmap(xdr,
|
||||
exid->spo_must_allow[0],
|
||||
exid->spo_must_allow[1],
|
||||
exid->spo_must_allow[2]);
|
||||
if (status)
|
||||
goto out;
|
||||
break;
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
@@ -3951,6 +3942,8 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr,
|
||||
/* Implementation id */
|
||||
*p++ = cpu_to_be32(0); /* zero length nfs_impl_id4 array */
|
||||
return 0;
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
static __be32
|
||||
|
@@ -124,6 +124,7 @@ void nfs4_state_shutdown_net(struct net *net);
|
||||
void nfs4_reset_lease(time_t leasetime);
|
||||
int nfs4_reset_recoverydir(char *recdir);
|
||||
char * nfs4_recoverydir(void);
|
||||
bool nfsd4_spo_must_allow(struct svc_rqst *rqstp);
|
||||
#else
|
||||
static inline int nfsd4_init_slabs(void) { return 0; }
|
||||
static inline void nfsd4_free_slabs(void) { }
|
||||
@@ -134,6 +135,10 @@ static inline void nfs4_state_shutdown_net(struct net *net) { }
|
||||
static inline void nfs4_reset_lease(time_t leasetime) { }
|
||||
static inline int nfs4_reset_recoverydir(char *recdir) { return 0; }
|
||||
static inline char * nfs4_recoverydir(void) {return NULL; }
|
||||
static inline bool nfsd4_spo_must_allow(struct svc_rqst *rqstp)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@@ -59,14 +59,20 @@ static int nfsd_acceptable(void *expv, struct dentry *dentry)
|
||||
* the write call).
|
||||
*/
|
||||
static inline __be32
|
||||
nfsd_mode_check(struct svc_rqst *rqstp, umode_t mode, umode_t requested)
|
||||
nfsd_mode_check(struct svc_rqst *rqstp, struct dentry *dentry,
|
||||
umode_t requested)
|
||||
{
|
||||
mode &= S_IFMT;
|
||||
umode_t mode = d_inode(dentry)->i_mode & S_IFMT;
|
||||
|
||||
if (requested == 0) /* the caller doesn't care */
|
||||
return nfs_ok;
|
||||
if (mode == requested)
|
||||
if (mode == requested) {
|
||||
if (mode == S_IFDIR && !d_can_lookup(dentry)) {
|
||||
WARN_ON_ONCE(1);
|
||||
return nfserr_notdir;
|
||||
}
|
||||
return nfs_ok;
|
||||
}
|
||||
/*
|
||||
* v4 has an error more specific than err_notdir which we should
|
||||
* return in preference to err_notdir:
|
||||
@@ -298,7 +304,7 @@ out:
|
||||
* that it expects something not of the given type.
|
||||
*
|
||||
* @access is formed from the NFSD_MAY_* constants defined in
|
||||
* include/linux/nfsd/nfsd.h.
|
||||
* fs/nfsd/vfs.h.
|
||||
*/
|
||||
__be32
|
||||
fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
|
||||
@@ -340,7 +346,7 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type, int access)
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
error = nfsd_mode_check(rqstp, d_inode(dentry)->i_mode, type);
|
||||
error = nfsd_mode_check(rqstp, dentry, type);
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
@@ -533,7 +539,7 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
|
||||
* the reference filehandle (if it is in the same export)
|
||||
* or the export options.
|
||||
*/
|
||||
set_version_and_fsid_type(fhp, exp, ref_fh);
|
||||
set_version_and_fsid_type(fhp, exp, ref_fh);
|
||||
|
||||
if (ref_fh == fhp)
|
||||
fh_put(ref_fh);
|
||||
|
@@ -251,9 +251,6 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
|
||||
|
||||
/* Check for NFSD_MAY_WRITE in nfsd_create if necessary */
|
||||
|
||||
nfserr = nfserr_acces;
|
||||
if (!argp->len)
|
||||
goto done;
|
||||
nfserr = nfserr_exist;
|
||||
if (isdotent(argp->name, argp->len))
|
||||
goto done;
|
||||
@@ -362,8 +359,8 @@ nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
|
||||
nfserr = 0;
|
||||
if (!inode) {
|
||||
/* File doesn't exist. Create it and set attrs */
|
||||
nfserr = nfsd_create(rqstp, dirfhp, argp->name, argp->len,
|
||||
attr, type, rdev, newfhp);
|
||||
nfserr = 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);
|
||||
|
@@ -240,7 +240,7 @@ nfssvc_decode_diropargs(struct svc_rqst *rqstp, __be32 *p,
|
||||
|| !(p = decode_filename(p, &args->name, &args->len)))
|
||||
return 0;
|
||||
|
||||
return xdr_argsize_check(rqstp, p);
|
||||
return xdr_argsize_check(rqstp, p);
|
||||
}
|
||||
|
||||
int
|
||||
|
@@ -21,6 +21,7 @@ struct nfsd4_layout_ops {
|
||||
u32 notify_types;
|
||||
|
||||
__be32 (*proc_getdeviceinfo)(struct super_block *sb,
|
||||
struct svc_rqst *rqstp,
|
||||
struct nfs4_client *clp,
|
||||
struct nfsd4_getdeviceinfo *gdevp);
|
||||
__be32 (*encode_getdeviceinfo)(struct xdr_stream *xdr,
|
||||
@@ -44,6 +45,9 @@ extern const struct nfsd4_layout_ops bl_layout_ops;
|
||||
#ifdef CONFIG_NFSD_SCSILAYOUT
|
||||
extern const struct nfsd4_layout_ops scsi_layout_ops;
|
||||
#endif
|
||||
#ifdef CONFIG_NFSD_FLEXFILELAYOUT
|
||||
extern const struct nfsd4_layout_ops ff_layout_ops;
|
||||
#endif
|
||||
|
||||
__be32 nfsd4_preprocess_layout_stateid(struct svc_rqst *rqstp,
|
||||
struct nfsd4_compound_state *cstate, stateid_t *stateid,
|
||||
|
@@ -345,6 +345,7 @@ struct nfs4_client {
|
||||
u32 cl_exchange_flags;
|
||||
/* number of rpc's in progress over an associated session: */
|
||||
atomic_t cl_refcount;
|
||||
struct nfs4_op_map cl_spo_must_allow;
|
||||
|
||||
/* for nfs41 callbacks */
|
||||
/* We currently support a single back channel with a single slot */
|
||||
|
142
fs/nfsd/vfs.c
142
fs/nfsd/vfs.c
@@ -1135,96 +1135,37 @@ nfsd_check_ignore_resizing(struct iattr *iap)
|
||||
iap->ia_valid &= ~ATTR_SIZE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a file (regular, directory, device, fifo); UNIX sockets
|
||||
* not yet implemented.
|
||||
* If the response fh has been verified, the parent directory should
|
||||
* already be locked. Note that the parent directory is left locked.
|
||||
*
|
||||
* N.B. Every call to nfsd_create needs an fh_put for _both_ fhp and resfhp
|
||||
*/
|
||||
/* The parent directory should already be locked: */
|
||||
__be32
|
||||
nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||
nfsd_create_locked(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||
char *fname, int flen, struct iattr *iap,
|
||||
int type, dev_t rdev, struct svc_fh *resfhp)
|
||||
{
|
||||
struct dentry *dentry, *dchild = NULL;
|
||||
struct dentry *dentry, *dchild;
|
||||
struct inode *dirp;
|
||||
__be32 err;
|
||||
__be32 err2;
|
||||
int host_err;
|
||||
|
||||
err = nfserr_perm;
|
||||
if (!flen)
|
||||
goto out;
|
||||
err = nfserr_exist;
|
||||
if (isdotent(fname, flen))
|
||||
goto out;
|
||||
|
||||
err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
dentry = fhp->fh_dentry;
|
||||
dirp = d_inode(dentry);
|
||||
|
||||
err = nfserr_notdir;
|
||||
if (!dirp->i_op->lookup)
|
||||
goto out;
|
||||
/*
|
||||
* Check whether the response file handle has been verified yet.
|
||||
* If it has, the parent directory should already be locked.
|
||||
*/
|
||||
if (!resfhp->fh_dentry) {
|
||||
host_err = fh_want_write(fhp);
|
||||
if (host_err)
|
||||
goto out_nfserr;
|
||||
|
||||
/* called from nfsd_proc_mkdir, or possibly nfsd3_proc_create */
|
||||
fh_lock_nested(fhp, I_MUTEX_PARENT);
|
||||
dchild = lookup_one_len(fname, dentry, flen);
|
||||
host_err = PTR_ERR(dchild);
|
||||
if (IS_ERR(dchild))
|
||||
goto out_nfserr;
|
||||
err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);
|
||||
if (err)
|
||||
goto out;
|
||||
} else {
|
||||
/* called from nfsd_proc_create */
|
||||
dchild = dget(resfhp->fh_dentry);
|
||||
if (!fhp->fh_locked) {
|
||||
/* not actually possible */
|
||||
printk(KERN_ERR
|
||||
"nfsd_create: parent %pd2 not locked!\n",
|
||||
dchild = dget(resfhp->fh_dentry);
|
||||
if (!fhp->fh_locked) {
|
||||
WARN_ONCE(1, "nfsd_create: parent %pd2 not locked!\n",
|
||||
dentry);
|
||||
err = nfserr_io;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Make sure the child dentry is still negative ...
|
||||
*/
|
||||
err = nfserr_exist;
|
||||
if (d_really_is_positive(dchild)) {
|
||||
dprintk("nfsd_create: dentry %pd/%pd not negative!\n",
|
||||
dentry, dchild);
|
||||
goto out;
|
||||
err = nfserr_io;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = nfsd_permission(rqstp, fhp->fh_export, dentry, NFSD_MAY_CREATE);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (!(iap->ia_valid & ATTR_MODE))
|
||||
iap->ia_mode = 0;
|
||||
iap->ia_mode = (iap->ia_mode & S_IALLUGO) | type;
|
||||
|
||||
err = nfserr_inval;
|
||||
if (!S_ISREG(type) && !S_ISDIR(type) && !special_file(type)) {
|
||||
printk(KERN_WARNING "nfsd: bad file type %o in nfsd_create\n",
|
||||
type);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the dir op function pointer.
|
||||
*/
|
||||
err = 0;
|
||||
host_err = 0;
|
||||
switch (type) {
|
||||
@@ -1242,6 +1183,10 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||
case S_IFSOCK:
|
||||
host_err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev);
|
||||
break;
|
||||
default:
|
||||
printk(KERN_WARNING "nfsd: bad file type %o in nfsd_create\n",
|
||||
type);
|
||||
host_err = -EINVAL;
|
||||
}
|
||||
if (host_err < 0)
|
||||
goto out_nfserr;
|
||||
@@ -1251,7 +1196,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||
/*
|
||||
* nfsd_create_setattr already committed the child. Transactional
|
||||
* filesystems had a chance to commit changes for both parent and
|
||||
* child * simultaneously making the following commit_metadata a
|
||||
* child simultaneously making the following commit_metadata a
|
||||
* noop.
|
||||
*/
|
||||
err2 = nfserrno(commit_metadata(fhp));
|
||||
@@ -1263,8 +1208,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||
if (!err)
|
||||
err = fh_update(resfhp);
|
||||
out:
|
||||
if (dchild && !IS_ERR(dchild))
|
||||
dput(dchild);
|
||||
dput(dchild);
|
||||
return err;
|
||||
|
||||
out_nfserr:
|
||||
@@ -1272,6 +1216,50 @@ out_nfserr:
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a filesystem object (regular, directory, special).
|
||||
* Note that the parent directory is left locked.
|
||||
*
|
||||
* N.B. Every call to nfsd_create needs an fh_put for _both_ fhp and resfhp
|
||||
*/
|
||||
__be32
|
||||
nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||
char *fname, int flen, struct iattr *iap,
|
||||
int type, dev_t rdev, struct svc_fh *resfhp)
|
||||
{
|
||||
struct dentry *dentry, *dchild = NULL;
|
||||
struct inode *dirp;
|
||||
__be32 err;
|
||||
int host_err;
|
||||
|
||||
if (isdotent(fname, flen))
|
||||
return nfserr_exist;
|
||||
|
||||
err = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_NOP);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
dentry = fhp->fh_dentry;
|
||||
dirp = d_inode(dentry);
|
||||
|
||||
host_err = fh_want_write(fhp);
|
||||
if (host_err)
|
||||
return nfserrno(host_err);
|
||||
|
||||
fh_lock_nested(fhp, I_MUTEX_PARENT);
|
||||
dchild = lookup_one_len(fname, dentry, flen);
|
||||
host_err = PTR_ERR(dchild);
|
||||
if (IS_ERR(dchild))
|
||||
return nfserrno(host_err);
|
||||
err = fh_compose(resfhp, fhp->fh_export, dchild, fhp);
|
||||
if (err) {
|
||||
dput(dchild);
|
||||
return err;
|
||||
}
|
||||
return nfsd_create_locked(rqstp, fhp, fname, flen, iap, type,
|
||||
rdev, resfhp);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NFSD_V3
|
||||
|
||||
/*
|
||||
@@ -1304,12 +1292,6 @@ do_nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
|
||||
dentry = fhp->fh_dentry;
|
||||
dirp = d_inode(dentry);
|
||||
|
||||
/* Get all the sanity checks out of the way before
|
||||
* we lock the parent. */
|
||||
err = nfserr_notdir;
|
||||
if (!dirp->i_op->lookup)
|
||||
goto out;
|
||||
|
||||
host_err = fh_want_write(fhp);
|
||||
if (host_err)
|
||||
goto out_nfserr;
|
||||
|
@@ -59,6 +59,9 @@ __be32 nfsd4_vfs_fallocate(struct svc_rqst *, struct svc_fh *,
|
||||
__be32 nfsd4_clone_file_range(struct file *, u64, struct file *,
|
||||
u64, u64);
|
||||
#endif /* CONFIG_NFSD_V4 */
|
||||
__be32 nfsd_create_locked(struct svc_rqst *, struct svc_fh *,
|
||||
char *name, int len, struct iattr *attrs,
|
||||
int type, dev_t rdev, struct svc_fh *res);
|
||||
__be32 nfsd_create(struct svc_rqst *, struct svc_fh *,
|
||||
char *name, int len, struct iattr *attrs,
|
||||
int type, dev_t rdev, struct svc_fh *res);
|
||||
|
@@ -59,6 +59,7 @@ struct nfsd4_compound_state {
|
||||
struct nfsd4_session *session;
|
||||
struct nfsd4_slot *slot;
|
||||
int data_offset;
|
||||
bool spo_must_allowed;
|
||||
size_t iovlen;
|
||||
u32 minorversion;
|
||||
__be32 status;
|
||||
@@ -403,6 +404,8 @@ struct nfsd4_exchange_id {
|
||||
clientid_t clientid;
|
||||
u32 seqid;
|
||||
int spa_how;
|
||||
u32 spo_must_enforce[3];
|
||||
u32 spo_must_allow[3];
|
||||
};
|
||||
|
||||
struct nfsd4_sequence {
|
||||
@@ -654,6 +657,8 @@ 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_encode_voidres(struct svc_rqst *, __be32 *, void *);
|
||||
int nfs4svc_decode_compoundargs(struct svc_rqst *, __be32 *,
|
||||
struct nfsd4_compoundargs *);
|
||||
|
Reference in New Issue
Block a user