Skip to content

Commit 9b9960a

Browse files
Tom HaynesJ. Bruce Fields
authored andcommitted
nfsd: Add a super simple flex file server
Have a simple flex file server where the mds (NFSv4.1 or NFSv4.2) is also the ds (NFSv3). I.e., the metadata and the data file are the exact same file. This will allow testing of the flex file client. Simply add the "pnfs" export option to your export in /etc/exports and mount from a client that supports flex files. Signed-off-by: Tom Haynes <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Signed-off-by: J. Bruce Fields <[email protected]>
1 parent d7c920d commit 9b9960a

File tree

7 files changed

+329
-1
lines changed

7 files changed

+329
-1
lines changed

fs/nfsd/Kconfig

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,23 @@ config NFSD_SCSILAYOUT
111111

112112
If unsure, say N.
113113

114+
config NFSD_FLEXFILELAYOUT
115+
bool "NFSv4.1 server support for pNFS Flex File layouts"
116+
depends on NFSD_V4
117+
select NFSD_PNFS
118+
help
119+
This option enables support for the exporting pNFS Flex File
120+
layouts in the kernel's NFS server. The pNFS Flex File layout
121+
enables NFS clients to directly perform I/O to NFSv3 devices
122+
accesible to both the server and the clients. See
123+
draft-ietf-nfsv4-flex-files for more details.
124+
125+
Warning, this server implements the bare minimum functionality
126+
to be a flex file server - it is for testing the client,
127+
not for use in production.
128+
129+
If unsure, say N.
130+
114131
config NFSD_V4_SECURITY_LABEL
115132
bool "Provide Security Label support for NFSv4 server"
116133
depends on NFSD_V4 && SECURITY

fs/nfsd/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,4 @@ nfsd-$(CONFIG_NFSD_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4idmap.o \
2020
nfsd-$(CONFIG_NFSD_PNFS) += nfs4layouts.o
2121
nfsd-$(CONFIG_NFSD_BLOCKLAYOUT) += blocklayout.o blocklayoutxdr.o
2222
nfsd-$(CONFIG_NFSD_SCSILAYOUT) += blocklayout.o blocklayoutxdr.o
23+
nfsd-$(CONFIG_NFSD_FLEXFILELAYOUT) += flexfilelayout.o flexfilelayoutxdr.o

fs/nfsd/flexfilelayout.c

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/*
2+
* Copyright (c) 2016 Tom Haynes <[email protected]>
3+
*
4+
* The following implements a super-simple flex-file server
5+
* where the NFSv4.1 mds is also the ds. And the storage is
6+
* the same. I.e., writing to the mds via a NFSv4.1 WRITE
7+
* goes to the same location as the NFSv3 WRITE.
8+
*/
9+
#include <linux/slab.h>
10+
11+
#include <linux/nfsd/debug.h>
12+
13+
#include <linux/sunrpc/addr.h>
14+
15+
#include "flexfilelayoutxdr.h"
16+
#include "pnfs.h"
17+
18+
#define NFSDDBG_FACILITY NFSDDBG_PNFS
19+
20+
static __be32
21+
nfsd4_ff_proc_layoutget(struct inode *inode, const struct svc_fh *fhp,
22+
struct nfsd4_layoutget *args)
23+
{
24+
struct nfsd4_layout_seg *seg = &args->lg_seg;
25+
u32 device_generation = 0;
26+
int error;
27+
uid_t u;
28+
29+
struct pnfs_ff_layout *fl;
30+
31+
/*
32+
* The super simple flex file server has 1 mirror, 1 data server,
33+
* and 1 file handle. So instead of 4 allocs, do 1 for now.
34+
* Zero it out for the stateid - don't want junk in there!
35+
*/
36+
error = -ENOMEM;
37+
fl = kzalloc(sizeof(*fl), GFP_KERNEL);
38+
if (!fl)
39+
goto out_error;
40+
args->lg_content = fl;
41+
42+
/*
43+
* Avoid layout commit, try to force the I/O to the DS,
44+
* and for fun, cause all IOMODE_RW layout segments to
45+
* effectively be WRITE only.
46+
*/
47+
fl->flags = FF_FLAGS_NO_LAYOUTCOMMIT | FF_FLAGS_NO_IO_THRU_MDS |
48+
FF_FLAGS_NO_READ_IO;
49+
50+
/* Do not allow a IOMODE_READ segment to have write pemissions */
51+
if (seg->iomode == IOMODE_READ) {
52+
u = from_kuid(&init_user_ns, inode->i_uid) + 1;
53+
fl->uid = make_kuid(&init_user_ns, u);
54+
} else
55+
fl->uid = inode->i_uid;
56+
fl->gid = inode->i_gid;
57+
58+
error = nfsd4_set_deviceid(&fl->deviceid, fhp, device_generation);
59+
if (error)
60+
goto out_error;
61+
62+
fl->fh.size = fhp->fh_handle.fh_size;
63+
memcpy(fl->fh.data, &fhp->fh_handle.fh_base, fl->fh.size);
64+
65+
/* Give whole file layout segments */
66+
seg->offset = 0;
67+
seg->length = NFS4_MAX_UINT64;
68+
69+
dprintk("GET: 0x%llx:0x%llx %d\n", seg->offset, seg->length,
70+
seg->iomode);
71+
return 0;
72+
73+
out_error:
74+
seg->length = 0;
75+
return nfserrno(error);
76+
}
77+
78+
static __be32
79+
nfsd4_ff_proc_getdeviceinfo(struct super_block *sb, struct svc_rqst *rqstp,
80+
struct nfs4_client *clp, struct nfsd4_getdeviceinfo *gdp)
81+
{
82+
struct pnfs_ff_device_addr *da;
83+
84+
u16 port;
85+
char addr[INET6_ADDRSTRLEN];
86+
87+
da = kzalloc(sizeof(struct pnfs_ff_device_addr), GFP_KERNEL);
88+
if (!da)
89+
return nfserrno(-ENOMEM);
90+
91+
gdp->gd_device = da;
92+
93+
da->version = 3;
94+
da->minor_version = 0;
95+
96+
da->rsize = svc_max_payload(rqstp);
97+
da->wsize = da->rsize;
98+
99+
rpc_ntop((struct sockaddr *)&rqstp->rq_daddr,
100+
addr, INET6_ADDRSTRLEN);
101+
if (rqstp->rq_daddr.ss_family == AF_INET) {
102+
struct sockaddr_in *sin;
103+
104+
sin = (struct sockaddr_in *)&rqstp->rq_daddr;
105+
port = ntohs(sin->sin_port);
106+
snprintf(da->netaddr.netid, FF_NETID_LEN + 1, "tcp");
107+
da->netaddr.netid_len = 3;
108+
} else {
109+
struct sockaddr_in6 *sin6;
110+
111+
sin6 = (struct sockaddr_in6 *)&rqstp->rq_daddr;
112+
port = ntohs(sin6->sin6_port);
113+
snprintf(da->netaddr.netid, FF_NETID_LEN + 1, "tcp6");
114+
da->netaddr.netid_len = 4;
115+
}
116+
117+
da->netaddr.addr_len =
118+
snprintf(da->netaddr.addr, FF_ADDR_LEN + 1,
119+
"%s.%hhu.%hhu", addr, port >> 8, port & 0xff);
120+
121+
da->tightly_coupled = false;
122+
123+
return 0;
124+
}
125+
126+
const struct nfsd4_layout_ops ff_layout_ops = {
127+
.notify_types =
128+
NOTIFY_DEVICEID4_DELETE | NOTIFY_DEVICEID4_CHANGE,
129+
.proc_getdeviceinfo = nfsd4_ff_proc_getdeviceinfo,
130+
.encode_getdeviceinfo = nfsd4_ff_encode_getdeviceinfo,
131+
.proc_layoutget = nfsd4_ff_proc_layoutget,
132+
.encode_layoutget = nfsd4_ff_encode_layoutget,
133+
};

fs/nfsd/flexfilelayoutxdr.c

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/*
2+
* Copyright (c) 2016 Tom Haynes <[email protected]>
3+
*/
4+
#include <linux/sunrpc/svc.h>
5+
#include <linux/nfs4.h>
6+
7+
#include "nfsd.h"
8+
#include "flexfilelayoutxdr.h"
9+
10+
#define NFSDDBG_FACILITY NFSDDBG_PNFS
11+
12+
struct ff_idmap {
13+
char buf[11];
14+
int len;
15+
};
16+
17+
__be32
18+
nfsd4_ff_encode_layoutget(struct xdr_stream *xdr,
19+
struct nfsd4_layoutget *lgp)
20+
{
21+
struct pnfs_ff_layout *fl = lgp->lg_content;
22+
int len, mirror_len, ds_len, fh_len;
23+
__be32 *p;
24+
25+
/*
26+
* Unlike nfsd4_encode_user, we know these will
27+
* always be stringified.
28+
*/
29+
struct ff_idmap uid;
30+
struct ff_idmap gid;
31+
32+
fh_len = 4 + fl->fh.size;
33+
34+
uid.len = sprintf(uid.buf, "%u", from_kuid(&init_user_ns, fl->uid));
35+
gid.len = sprintf(gid.buf, "%u", from_kgid(&init_user_ns, fl->gid));
36+
37+
/* 8 + len for recording the length, name, and padding */
38+
ds_len = 20 + sizeof(stateid_opaque_t) + 4 + fh_len +
39+
8 + uid.len + 8 + gid.len;
40+
41+
mirror_len = 4 + ds_len;
42+
43+
/* The layout segment */
44+
len = 20 + mirror_len;
45+
46+
p = xdr_reserve_space(xdr, sizeof(__be32) + len);
47+
if (!p)
48+
return nfserr_toosmall;
49+
50+
*p++ = cpu_to_be32(len);
51+
p = xdr_encode_hyper(p, 0); /* stripe unit of 1 */
52+
53+
*p++ = cpu_to_be32(1); /* single mirror */
54+
*p++ = cpu_to_be32(1); /* single data server */
55+
56+
p = xdr_encode_opaque_fixed(p, &fl->deviceid,
57+
sizeof(struct nfsd4_deviceid));
58+
59+
*p++ = cpu_to_be32(1); /* efficiency */
60+
61+
*p++ = cpu_to_be32(fl->stateid.si_generation);
62+
p = xdr_encode_opaque_fixed(p, &fl->stateid.si_opaque,
63+
sizeof(stateid_opaque_t));
64+
65+
*p++ = cpu_to_be32(1); /* single file handle */
66+
p = xdr_encode_opaque(p, fl->fh.data, fl->fh.size);
67+
68+
p = xdr_encode_opaque(p, uid.buf, uid.len);
69+
p = xdr_encode_opaque(p, gid.buf, gid.len);
70+
71+
*p++ = cpu_to_be32(fl->flags);
72+
*p++ = cpu_to_be32(0); /* No stats collect hint */
73+
74+
return 0;
75+
}
76+
77+
__be32
78+
nfsd4_ff_encode_getdeviceinfo(struct xdr_stream *xdr,
79+
struct nfsd4_getdeviceinfo *gdp)
80+
{
81+
struct pnfs_ff_device_addr *da = gdp->gd_device;
82+
int len;
83+
int ver_len;
84+
int addr_len;
85+
__be32 *p;
86+
87+
/* len + padding for two strings */
88+
addr_len = 16 + da->netaddr.netid_len + da->netaddr.addr_len;
89+
ver_len = 20;
90+
91+
len = 4 + ver_len + 4 + addr_len;
92+
93+
p = xdr_reserve_space(xdr, len + sizeof(__be32));
94+
if (!p)
95+
return nfserr_resource;
96+
97+
/*
98+
* Fill in the overall length and number of volumes at the beginning
99+
* of the layout.
100+
*/
101+
*p++ = cpu_to_be32(len);
102+
*p++ = cpu_to_be32(1); /* 1 netaddr */
103+
p = xdr_encode_opaque(p, da->netaddr.netid, da->netaddr.netid_len);
104+
p = xdr_encode_opaque(p, da->netaddr.addr, da->netaddr.addr_len);
105+
106+
*p++ = cpu_to_be32(1); /* 1 versions */
107+
108+
*p++ = cpu_to_be32(da->version);
109+
*p++ = cpu_to_be32(da->minor_version);
110+
*p++ = cpu_to_be32(da->rsize);
111+
*p++ = cpu_to_be32(da->wsize);
112+
*p++ = cpu_to_be32(da->tightly_coupled);
113+
114+
return 0;
115+
}

fs/nfsd/flexfilelayoutxdr.h

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*
2+
* Copyright (c) 2016 Tom Haynes <[email protected]>
3+
*/
4+
#ifndef _NFSD_FLEXFILELAYOUTXDR_H
5+
#define _NFSD_FLEXFILELAYOUTXDR_H 1
6+
7+
#include <linux/inet.h>
8+
#include "xdr4.h"
9+
10+
#define FF_FLAGS_NO_LAYOUTCOMMIT 1
11+
#define FF_FLAGS_NO_IO_THRU_MDS 2
12+
#define FF_FLAGS_NO_READ_IO 4
13+
14+
struct xdr_stream;
15+
16+
#define FF_NETID_LEN (4)
17+
#define FF_ADDR_LEN (INET6_ADDRSTRLEN + 8)
18+
struct pnfs_ff_netaddr {
19+
char netid[FF_NETID_LEN + 1];
20+
char addr[FF_ADDR_LEN + 1];
21+
u32 netid_len;
22+
u32 addr_len;
23+
};
24+
25+
struct pnfs_ff_device_addr {
26+
struct pnfs_ff_netaddr netaddr;
27+
u32 version;
28+
u32 minor_version;
29+
u32 rsize;
30+
u32 wsize;
31+
bool tightly_coupled;
32+
};
33+
34+
struct pnfs_ff_layout {
35+
u32 flags;
36+
u32 stats_collect_hint;
37+
kuid_t uid;
38+
kgid_t gid;
39+
struct nfsd4_deviceid deviceid;
40+
stateid_t stateid;
41+
struct nfs_fh fh;
42+
};
43+
44+
__be32 nfsd4_ff_encode_getdeviceinfo(struct xdr_stream *xdr,
45+
struct nfsd4_getdeviceinfo *gdp);
46+
__be32 nfsd4_ff_encode_layoutget(struct xdr_stream *xdr,
47+
struct nfsd4_layoutget *lgp);
48+
49+
#endif /* _NFSD_FLEXFILELAYOUTXDR_H */

fs/nfsd/nfs4layouts.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ static const struct nfsd4_callback_ops nfsd4_cb_layout_ops;
2727
static const struct lock_manager_operations nfsd4_layouts_lm_ops;
2828

2929
const struct nfsd4_layout_ops *nfsd4_layout_ops[LAYOUT_TYPE_MAX] = {
30+
#ifdef CONFIG_NFSD_FLEXFILELAYOUT
31+
[LAYOUT_FLEX_FILES] = &ff_layout_ops,
32+
#endif
3033
#ifdef CONFIG_NFSD_BLOCKLAYOUT
3134
[LAYOUT_BLOCK_VOLUME] = &bl_layout_ops,
3235
#endif
@@ -122,17 +125,24 @@ nfsd4_set_deviceid(struct nfsd4_deviceid *id, const struct svc_fh *fhp,
122125

123126
void nfsd4_setup_layout_type(struct svc_export *exp)
124127
{
128+
#if defined(CONFIG_NFSD_BLOCKLAYOUT) || defined(CONFIG_NFSD_SCSILAYOUT)
125129
struct super_block *sb = exp->ex_path.mnt->mnt_sb;
130+
#endif
126131

127132
if (!(exp->ex_flags & NFSEXP_PNFS))
128133
return;
129134

130135
/*
131-
* Check if the file system supports exporting a block-like layout.
136+
* If flex file is configured, use it by default. Otherwise
137+
* check if the file system supports exporting a block-like layout.
132138
* If the block device supports reservations prefer the SCSI layout,
133139
* otherwise advertise the block layout.
134140
*/
141+
#ifdef CONFIG_NFSD_FLEXFILELAYOUT
142+
exp->ex_layout_type = LAYOUT_FLEX_FILES;
143+
#endif
135144
#ifdef CONFIG_NFSD_BLOCKLAYOUT
145+
/* overwrite flex file layout selection if needed */
136146
if (sb->s_export_op->get_uuid &&
137147
sb->s_export_op->map_blocks &&
138148
sb->s_export_op->commit_blocks)

fs/nfsd/pnfs.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ extern const struct nfsd4_layout_ops bl_layout_ops;
4545
#ifdef CONFIG_NFSD_SCSILAYOUT
4646
extern const struct nfsd4_layout_ops scsi_layout_ops;
4747
#endif
48+
#ifdef CONFIG_NFSD_FLEXFILELAYOUT
49+
extern const struct nfsd4_layout_ops ff_layout_ops;
50+
#endif
4851

4952
__be32 nfsd4_preprocess_layout_stateid(struct svc_rqst *rqstp,
5053
struct nfsd4_compound_state *cstate, stateid_t *stateid,

0 commit comments

Comments
 (0)