Skip to content

Commit ce0887a

Browse files
olgakorn1J. Bruce Fields
authored andcommitted
NFSD add nfs4 inter ssc to nfsd4_copy
Given a universal address, mount the source server from the destination server. Use an internal mount. Call the NFS client nfs42_ssc_open to obtain the NFS struct file suitable for nfsd_copy_range. Ability to do "inter" server-to-server depends on the an nfsd kernel parameter "inter_copy_offload_enable". Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
1 parent b9e8638 commit ce0887a

File tree

5 files changed

+295
-27
lines changed

5 files changed

+295
-27
lines changed

fs/nfsd/nfs4proc.c

Lines changed: 271 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1144,6 +1144,208 @@ void nfsd4_shutdown_copy(struct nfs4_client *clp)
11441144
while ((copy = nfsd4_get_copy(clp)) != NULL)
11451145
nfsd4_stop_copy(copy);
11461146
}
1147+
#ifdef CONFIG_NFSD_V4_2_INTER_SSC
1148+
1149+
extern struct file *nfs42_ssc_open(struct vfsmount *ss_mnt,
1150+
struct nfs_fh *src_fh,
1151+
nfs4_stateid *stateid);
1152+
extern void nfs42_ssc_close(struct file *filep);
1153+
1154+
extern void nfs_sb_deactive(struct super_block *sb);
1155+
1156+
#define NFSD42_INTERSSC_MOUNTOPS "vers=4.2,addr=%s,sec=sys"
1157+
1158+
/**
1159+
* Support one copy source server for now.
1160+
*/
1161+
static __be32
1162+
nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp,
1163+
struct vfsmount **mount)
1164+
{
1165+
struct file_system_type *type;
1166+
struct vfsmount *ss_mnt;
1167+
struct nfs42_netaddr *naddr;
1168+
struct sockaddr_storage tmp_addr;
1169+
size_t tmp_addrlen, match_netid_len = 3;
1170+
char *startsep = "", *endsep = "", *match_netid = "tcp";
1171+
char *ipaddr, *dev_name, *raw_data;
1172+
int len, raw_len, status = -EINVAL;
1173+
1174+
naddr = &nss->u.nl4_addr;
1175+
tmp_addrlen = rpc_uaddr2sockaddr(SVC_NET(rqstp), naddr->addr,
1176+
naddr->addr_len,
1177+
(struct sockaddr *)&tmp_addr,
1178+
sizeof(tmp_addr));
1179+
if (tmp_addrlen == 0)
1180+
goto out_err;
1181+
1182+
if (tmp_addr.ss_family == AF_INET6) {
1183+
startsep = "[";
1184+
endsep = "]";
1185+
match_netid = "tcp6";
1186+
match_netid_len = 4;
1187+
}
1188+
1189+
if (naddr->netid_len != match_netid_len ||
1190+
strncmp(naddr->netid, match_netid, naddr->netid_len))
1191+
goto out_err;
1192+
1193+
/* Construct the raw data for the vfs_kern_mount call */
1194+
len = RPC_MAX_ADDRBUFLEN + 1;
1195+
ipaddr = kzalloc(len, GFP_KERNEL);
1196+
if (!ipaddr)
1197+
goto out_err;
1198+
1199+
rpc_ntop((struct sockaddr *)&tmp_addr, ipaddr, len);
1200+
1201+
/* 2 for ipv6 endsep and startsep. 3 for ":/" and trailing '/0'*/
1202+
1203+
raw_len = strlen(NFSD42_INTERSSC_MOUNTOPS) + strlen(ipaddr);
1204+
raw_data = kzalloc(raw_len, GFP_KERNEL);
1205+
if (!raw_data)
1206+
goto out_free_ipaddr;
1207+
1208+
snprintf(raw_data, raw_len, NFSD42_INTERSSC_MOUNTOPS, ipaddr);
1209+
1210+
status = -ENODEV;
1211+
type = get_fs_type("nfs");
1212+
if (!type)
1213+
goto out_free_rawdata;
1214+
1215+
/* Set the server:<export> for the vfs_kern_mount call */
1216+
dev_name = kzalloc(len + 5, GFP_KERNEL);
1217+
if (!dev_name)
1218+
goto out_free_rawdata;
1219+
snprintf(dev_name, len + 5, "%s%s%s:/", startsep, ipaddr, endsep);
1220+
1221+
/* Use an 'internal' mount: SB_KERNMOUNT -> MNT_INTERNAL */
1222+
ss_mnt = vfs_kern_mount(type, SB_KERNMOUNT, dev_name, raw_data);
1223+
module_put(type->owner);
1224+
if (IS_ERR(ss_mnt))
1225+
goto out_free_devname;
1226+
1227+
status = 0;
1228+
*mount = ss_mnt;
1229+
1230+
out_free_devname:
1231+
kfree(dev_name);
1232+
out_free_rawdata:
1233+
kfree(raw_data);
1234+
out_free_ipaddr:
1235+
kfree(ipaddr);
1236+
out_err:
1237+
return status;
1238+
}
1239+
1240+
static void
1241+
nfsd4_interssc_disconnect(struct vfsmount *ss_mnt)
1242+
{
1243+
nfs_sb_deactive(ss_mnt->mnt_sb);
1244+
mntput(ss_mnt);
1245+
}
1246+
1247+
/**
1248+
* nfsd4_setup_inter_ssc
1249+
*
1250+
* Verify COPY destination stateid.
1251+
* Connect to the source server with NFSv4.1.
1252+
* Create the source struct file for nfsd_copy_range.
1253+
* Called with COPY cstate:
1254+
* SAVED_FH: source filehandle
1255+
* CURRENT_FH: destination filehandle
1256+
*
1257+
* Returns errno (not nfserrxxx)
1258+
*/
1259+
static __be32
1260+
nfsd4_setup_inter_ssc(struct svc_rqst *rqstp,
1261+
struct nfsd4_compound_state *cstate,
1262+
struct nfsd4_copy *copy, struct vfsmount **mount)
1263+
{
1264+
struct svc_fh *s_fh = NULL;
1265+
stateid_t *s_stid = &copy->cp_src_stateid;
1266+
__be32 status = -EINVAL;
1267+
1268+
/* Verify the destination stateid and set dst struct file*/
1269+
status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
1270+
&copy->cp_dst_stateid,
1271+
WR_STATE, &copy->nf_dst, NULL);
1272+
if (status)
1273+
goto out;
1274+
1275+
status = nfsd4_interssc_connect(&copy->cp_src, rqstp, mount);
1276+
if (status)
1277+
goto out;
1278+
1279+
s_fh = &cstate->save_fh;
1280+
1281+
copy->c_fh.size = s_fh->fh_handle.fh_size;
1282+
memcpy(copy->c_fh.data, &s_fh->fh_handle.fh_base, copy->c_fh.size);
1283+
copy->stateid.seqid = s_stid->si_generation;
1284+
memcpy(copy->stateid.other, (void *)&s_stid->si_opaque,
1285+
sizeof(stateid_opaque_t));
1286+
1287+
status = 0;
1288+
out:
1289+
return status;
1290+
}
1291+
1292+
static void
1293+
nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct nfsd_file *src,
1294+
struct nfsd_file *dst)
1295+
{
1296+
nfs42_ssc_close(src->nf_file);
1297+
nfsd_file_put(src);
1298+
nfsd_file_put(dst);
1299+
mntput(ss_mnt);
1300+
}
1301+
1302+
#else /* CONFIG_NFSD_V4_2_INTER_SSC */
1303+
1304+
static __be32
1305+
nfsd4_setup_inter_ssc(struct svc_rqst *rqstp,
1306+
struct nfsd4_compound_state *cstate,
1307+
struct nfsd4_copy *copy,
1308+
struct vfsmount **mount)
1309+
{
1310+
*mount = NULL;
1311+
return -EINVAL;
1312+
}
1313+
1314+
static void
1315+
nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct nfsd_file *src,
1316+
struct nfsd_file *dst)
1317+
{
1318+
}
1319+
1320+
static void
1321+
nfsd4_interssc_disconnect(struct vfsmount *ss_mnt)
1322+
{
1323+
}
1324+
1325+
static struct file *nfs42_ssc_open(struct vfsmount *ss_mnt,
1326+
struct nfs_fh *src_fh,
1327+
nfs4_stateid *stateid)
1328+
{
1329+
return NULL;
1330+
}
1331+
#endif /* CONFIG_NFSD_V4_2_INTER_SSC */
1332+
1333+
static __be32
1334+
nfsd4_setup_intra_ssc(struct svc_rqst *rqstp,
1335+
struct nfsd4_compound_state *cstate,
1336+
struct nfsd4_copy *copy)
1337+
{
1338+
return nfsd4_verify_copy(rqstp, cstate, &copy->cp_src_stateid,
1339+
&copy->nf_src, &copy->cp_dst_stateid,
1340+
&copy->nf_dst);
1341+
}
1342+
1343+
static void
1344+
nfsd4_cleanup_intra_ssc(struct nfsd_file *src, struct nfsd_file *dst)
1345+
{
1346+
nfsd_file_put(src);
1347+
nfsd_file_put(dst);
1348+
}
11471349

11481350
static void nfsd4_cb_offload_release(struct nfsd4_callback *cb)
11491351
{
@@ -1209,12 +1411,16 @@ static __be32 nfsd4_do_copy(struct nfsd4_copy *copy, bool sync)
12091411
status = nfs_ok;
12101412
}
12111413

1212-
nfsd_file_put(copy->nf_src);
1213-
nfsd_file_put(copy->nf_dst);
1414+
if (!copy->cp_intra) /* Inter server SSC */
1415+
nfsd4_cleanup_inter_ssc(copy->ss_mnt, copy->nf_src,
1416+
copy->nf_dst);
1417+
else
1418+
nfsd4_cleanup_intra_ssc(copy->nf_src, copy->nf_dst);
1419+
12141420
return status;
12151421
}
12161422

1217-
static void dup_copy_fields(struct nfsd4_copy *src, struct nfsd4_copy *dst)
1423+
static int dup_copy_fields(struct nfsd4_copy *src, struct nfsd4_copy *dst)
12181424
{
12191425
dst->cp_src_pos = src->cp_src_pos;
12201426
dst->cp_dst_pos = src->cp_dst_pos;
@@ -1224,8 +1430,17 @@ static void dup_copy_fields(struct nfsd4_copy *src, struct nfsd4_copy *dst)
12241430
memcpy(&dst->fh, &src->fh, sizeof(src->fh));
12251431
dst->cp_clp = src->cp_clp;
12261432
dst->nf_dst = nfsd_file_get(src->nf_dst);
1227-
dst->nf_src = nfsd_file_get(src->nf_src);
1433+
dst->cp_intra = src->cp_intra;
1434+
if (src->cp_intra) /* for inter, file_src doesn't exist yet */
1435+
dst->nf_src = nfsd_file_get(src->nf_src);
1436+
12281437
memcpy(&dst->cp_stateid, &src->cp_stateid, sizeof(src->cp_stateid));
1438+
memcpy(&dst->cp_src, &src->cp_src, sizeof(struct nl4_server));
1439+
memcpy(&dst->stateid, &src->stateid, sizeof(src->stateid));
1440+
memcpy(&dst->c_fh, &src->c_fh, sizeof(src->c_fh));
1441+
dst->ss_mnt = src->ss_mnt;
1442+
1443+
return 0;
12291444
}
12301445

12311446
static void cleanup_async_copy(struct nfsd4_copy *copy)
@@ -1244,7 +1459,25 @@ static int nfsd4_do_async_copy(void *data)
12441459
struct nfsd4_copy *copy = (struct nfsd4_copy *)data;
12451460
struct nfsd4_copy *cb_copy;
12461461

1462+
if (!copy->cp_intra) { /* Inter server SSC */
1463+
copy->nf_src = kzalloc(sizeof(struct nfsd_file), GFP_KERNEL);
1464+
if (!copy->nf_src) {
1465+
copy->nfserr = nfserr_serverfault;
1466+
nfsd4_interssc_disconnect(copy->ss_mnt);
1467+
goto do_callback;
1468+
}
1469+
copy->nf_src->nf_file = nfs42_ssc_open(copy->ss_mnt, &copy->c_fh,
1470+
&copy->stateid);
1471+
if (IS_ERR(copy->nf_src->nf_file)) {
1472+
kfree(copy->nf_src);
1473+
copy->nfserr = nfserr_offload_denied;
1474+
nfsd4_interssc_disconnect(copy->ss_mnt);
1475+
goto do_callback;
1476+
}
1477+
}
1478+
12471479
copy->nfserr = nfsd4_do_copy(copy, 0);
1480+
do_callback:
12481481
cb_copy = kzalloc(sizeof(struct nfsd4_copy), GFP_KERNEL);
12491482
if (!cb_copy)
12501483
goto out;
@@ -1256,6 +1489,8 @@ static int nfsd4_do_async_copy(void *data)
12561489
&nfsd4_cb_offload_ops, NFSPROC4_CLNT_CB_OFFLOAD);
12571490
nfsd4_run_cb(&cb_copy->cp_cb);
12581491
out:
1492+
if (!copy->cp_intra)
1493+
kfree(copy->nf_src);
12591494
cleanup_async_copy(copy);
12601495
return 0;
12611496
}
@@ -1268,11 +1503,20 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
12681503
__be32 status;
12691504
struct nfsd4_copy *async_copy = NULL;
12701505

1271-
status = nfsd4_verify_copy(rqstp, cstate, &copy->cp_src_stateid,
1272-
&copy->nf_src, &copy->cp_dst_stateid,
1273-
&copy->nf_dst);
1274-
if (status)
1275-
goto out;
1506+
if (!copy->cp_intra) { /* Inter server SSC */
1507+
if (!inter_copy_offload_enable || copy->cp_synchronous) {
1508+
status = nfserr_notsupp;
1509+
goto out;
1510+
}
1511+
status = nfsd4_setup_inter_ssc(rqstp, cstate, copy,
1512+
&copy->ss_mnt);
1513+
if (status)
1514+
return nfserr_offload_denied;
1515+
} else {
1516+
status = nfsd4_setup_intra_ssc(rqstp, cstate, copy);
1517+
if (status)
1518+
return status;
1519+
}
12761520

12771521
copy->cp_clp = cstate->clp;
12781522
memcpy(&copy->fh, &cstate->current_fh.fh_handle,
@@ -1283,15 +1527,15 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
12831527
status = nfserrno(-ENOMEM);
12841528
async_copy = kzalloc(sizeof(struct nfsd4_copy), GFP_KERNEL);
12851529
if (!async_copy)
1286-
goto out;
1287-
if (!nfs4_init_copy_state(nn, copy)) {
1288-
kfree(async_copy);
1289-
goto out;
1290-
}
1530+
goto out_err;
1531+
if (!nfs4_init_copy_state(nn, copy))
1532+
goto out_err;
12911533
refcount_set(&async_copy->refcount, 1);
12921534
memcpy(&copy->cp_res.cb_stateid, &copy->cp_stateid,
12931535
sizeof(copy->cp_stateid));
1294-
dup_copy_fields(copy, async_copy);
1536+
status = dup_copy_fields(copy, async_copy);
1537+
if (status)
1538+
goto out_err;
12951539
async_copy->copy_task = kthread_create(nfsd4_do_async_copy,
12961540
async_copy, "%s", "copy thread");
12971541
if (IS_ERR(async_copy->copy_task))
@@ -1302,13 +1546,17 @@ nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
13021546
spin_unlock(&async_copy->cp_clp->async_lock);
13031547
wake_up_process(async_copy->copy_task);
13041548
status = nfs_ok;
1305-
} else
1549+
} else {
13061550
status = nfsd4_do_copy(copy, 1);
1551+
}
13071552
out:
13081553
return status;
13091554
out_err:
13101555
if (async_copy)
13111556
cleanup_async_copy(async_copy);
1557+
status = nfserrno(-ENOMEM);
1558+
if (!copy->cp_intra)
1559+
nfsd4_interssc_disconnect(copy->ss_mnt);
13121560
goto out;
13131561
}
13141562

@@ -1319,7 +1567,7 @@ find_async_copy(struct nfs4_client *clp, stateid_t *stateid)
13191567

13201568
spin_lock(&clp->async_lock);
13211569
list_for_each_entry(copy, &clp->async_copies, copies) {
1322-
if (memcmp(&copy->cp_stateid, stateid, NFS4_STATEID_SIZE))
1570+
if (memcmp(&copy->cp_stateid.stid, stateid, NFS4_STATEID_SIZE))
13231571
continue;
13241572
refcount_inc(&copy->refcount);
13251573
spin_unlock(&clp->async_lock);
@@ -1335,17 +1583,18 @@ nfsd4_offload_cancel(struct svc_rqst *rqstp,
13351583
union nfsd4_op_u *u)
13361584
{
13371585
struct nfsd4_offload_status *os = &u->offload_status;
1338-
__be32 status = 0;
13391586
struct nfsd4_copy *copy;
13401587
struct nfs4_client *clp = cstate->clp;
13411588

13421589
copy = find_async_copy(clp, &os->stateid);
1343-
if (copy)
1590+
if (!copy) {
1591+
struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
1592+
1593+
return manage_cpntf_state(nn, &os->stateid, clp, NULL);
1594+
} else
13441595
nfsd4_stop_copy(copy);
1345-
else
1346-
status = nfserr_bad_stateid;
13471596

1348-
return status;
1597+
return nfs_ok;
13491598
}
13501599

13511600
static __be32

0 commit comments

Comments
 (0)