aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4proc.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd/nfs4proc.c')
-rw-r--r--fs/nfsd/nfs4proc.c310
1 files changed, 310 insertions, 0 deletions
diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
index ac71d13c69ef..d30bea8d0277 100644
--- a/fs/nfsd/nfs4proc.c
+++ b/fs/nfsd/nfs4proc.c
@@ -43,6 +43,8 @@
43#include "current_stateid.h" 43#include "current_stateid.h"
44#include "netns.h" 44#include "netns.h"
45#include "acl.h" 45#include "acl.h"
46#include "pnfs.h"
47#include "trace.h"
46 48
47#ifdef CONFIG_NFSD_V4_SECURITY_LABEL 49#ifdef CONFIG_NFSD_V4_SECURITY_LABEL
48#include <linux/security.h> 50#include <linux/security.h>
@@ -1178,6 +1180,259 @@ nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
1178 return status == nfserr_same ? nfs_ok : status; 1180 return status == nfserr_same ? nfs_ok : status;
1179} 1181}
1180 1182
1183#ifdef CONFIG_NFSD_PNFS
1184static const struct nfsd4_layout_ops *
1185nfsd4_layout_verify(struct svc_export *exp, unsigned int layout_type)
1186{
1187 if (!exp->ex_layout_type) {
1188 dprintk("%s: export does not support pNFS\n", __func__);
1189 return NULL;
1190 }
1191
1192 if (exp->ex_layout_type != layout_type) {
1193 dprintk("%s: layout type %d not supported\n",
1194 __func__, layout_type);
1195 return NULL;
1196 }
1197
1198 return nfsd4_layout_ops[layout_type];
1199}
1200
1201static __be32
1202nfsd4_getdeviceinfo(struct svc_rqst *rqstp,
1203 struct nfsd4_compound_state *cstate,
1204 struct nfsd4_getdeviceinfo *gdp)
1205{
1206 const struct nfsd4_layout_ops *ops;
1207 struct nfsd4_deviceid_map *map;
1208 struct svc_export *exp;
1209 __be32 nfserr;
1210
1211 dprintk("%s: layout_type %u dev_id [0x%llx:0x%x] maxcnt %u\n",
1212 __func__,
1213 gdp->gd_layout_type,
1214 gdp->gd_devid.fsid_idx, gdp->gd_devid.generation,
1215 gdp->gd_maxcount);
1216
1217 map = nfsd4_find_devid_map(gdp->gd_devid.fsid_idx);
1218 if (!map) {
1219 dprintk("%s: couldn't find device ID to export mapping!\n",
1220 __func__);
1221 return nfserr_noent;
1222 }
1223
1224 exp = rqst_exp_find(rqstp, map->fsid_type, map->fsid);
1225 if (IS_ERR(exp)) {
1226 dprintk("%s: could not find device id\n", __func__);
1227 return nfserr_noent;
1228 }
1229
1230 nfserr = nfserr_layoutunavailable;
1231 ops = nfsd4_layout_verify(exp, gdp->gd_layout_type);
1232 if (!ops)
1233 goto out;
1234
1235 nfserr = nfs_ok;
1236 if (gdp->gd_maxcount != 0)
1237 nfserr = ops->proc_getdeviceinfo(exp->ex_path.mnt->mnt_sb, gdp);
1238
1239 gdp->gd_notify_types &= ops->notify_types;
1240 exp_put(exp);
1241out:
1242 return nfserr;
1243}
1244
1245static __be32
1246nfsd4_layoutget(struct svc_rqst *rqstp,
1247 struct nfsd4_compound_state *cstate,
1248 struct nfsd4_layoutget *lgp)
1249{
1250 struct svc_fh *current_fh = &cstate->current_fh;
1251 const struct nfsd4_layout_ops *ops;
1252 struct nfs4_layout_stateid *ls;
1253 __be32 nfserr;
1254 int accmode;
1255
1256 switch (lgp->lg_seg.iomode) {
1257 case IOMODE_READ:
1258 accmode = NFSD_MAY_READ;
1259 break;
1260 case IOMODE_RW:
1261 accmode = NFSD_MAY_READ | NFSD_MAY_WRITE;
1262 break;
1263 default:
1264 dprintk("%s: invalid iomode %d\n",
1265 __func__, lgp->lg_seg.iomode);
1266 nfserr = nfserr_badiomode;
1267 goto out;
1268 }
1269
1270 nfserr = fh_verify(rqstp, current_fh, 0, accmode);
1271 if (nfserr)
1272 goto out;
1273
1274 nfserr = nfserr_layoutunavailable;
1275 ops = nfsd4_layout_verify(current_fh->fh_export, lgp->lg_layout_type);
1276 if (!ops)
1277 goto out;
1278
1279 /*
1280 * Verify minlength and range as per RFC5661:
1281 * o If loga_length is less than loga_minlength,
1282 * the metadata server MUST return NFS4ERR_INVAL.
1283 * o If the sum of loga_offset and loga_minlength exceeds
1284 * NFS4_UINT64_MAX, and loga_minlength is not
1285 * NFS4_UINT64_MAX, the error NFS4ERR_INVAL MUST result.
1286 * o If the sum of loga_offset and loga_length exceeds
1287 * NFS4_UINT64_MAX, and loga_length is not NFS4_UINT64_MAX,
1288 * the error NFS4ERR_INVAL MUST result.
1289 */
1290 nfserr = nfserr_inval;
1291 if (lgp->lg_seg.length < lgp->lg_minlength ||
1292 (lgp->lg_minlength != NFS4_MAX_UINT64 &&
1293 lgp->lg_minlength > NFS4_MAX_UINT64 - lgp->lg_seg.offset) ||
1294 (lgp->lg_seg.length != NFS4_MAX_UINT64 &&
1295 lgp->lg_seg.length > NFS4_MAX_UINT64 - lgp->lg_seg.offset))
1296 goto out;
1297 if (lgp->lg_seg.length == 0)
1298 goto out;
1299
1300 nfserr = nfsd4_preprocess_layout_stateid(rqstp, cstate, &lgp->lg_sid,
1301 true, lgp->lg_layout_type, &ls);
1302 if (nfserr) {
1303 trace_layout_get_lookup_fail(&lgp->lg_sid);
1304 goto out;
1305 }
1306
1307 nfserr = nfserr_recallconflict;
1308 if (atomic_read(&ls->ls_stid.sc_file->fi_lo_recalls))
1309 goto out_put_stid;
1310
1311 nfserr = ops->proc_layoutget(current_fh->fh_dentry->d_inode,
1312 current_fh, lgp);
1313 if (nfserr)
1314 goto out_put_stid;
1315
1316 nfserr = nfsd4_insert_layout(lgp, ls);
1317
1318out_put_stid:
1319 nfs4_put_stid(&ls->ls_stid);
1320out:
1321 return nfserr;
1322}
1323
1324static __be32
1325nfsd4_layoutcommit(struct svc_rqst *rqstp,
1326 struct nfsd4_compound_state *cstate,
1327 struct nfsd4_layoutcommit *lcp)
1328{
1329 const struct nfsd4_layout_seg *seg = &lcp->lc_seg;
1330 struct svc_fh *current_fh = &cstate->current_fh;
1331 const struct nfsd4_layout_ops *ops;
1332 loff_t new_size = lcp->lc_last_wr + 1;
1333 struct inode *inode;
1334 struct nfs4_layout_stateid *ls;
1335 __be32 nfserr;
1336
1337 nfserr = fh_verify(rqstp, current_fh, 0, NFSD_MAY_WRITE);
1338 if (nfserr)
1339 goto out;
1340
1341 nfserr = nfserr_layoutunavailable;
1342 ops = nfsd4_layout_verify(current_fh->fh_export, lcp->lc_layout_type);
1343 if (!ops)
1344 goto out;
1345 inode = current_fh->fh_dentry->d_inode;
1346
1347 nfserr = nfserr_inval;
1348 if (new_size <= seg->offset) {
1349 dprintk("pnfsd: last write before layout segment\n");
1350 goto out;
1351 }
1352 if (new_size > seg->offset + seg->length) {
1353 dprintk("pnfsd: last write beyond layout segment\n");
1354 goto out;
1355 }
1356 if (!lcp->lc_newoffset && new_size > i_size_read(inode)) {
1357 dprintk("pnfsd: layoutcommit beyond EOF\n");
1358 goto out;
1359 }
1360
1361 nfserr = nfsd4_preprocess_layout_stateid(rqstp, cstate, &lcp->lc_sid,
1362 false, lcp->lc_layout_type,
1363 &ls);
1364 if (nfserr) {
1365 trace_layout_commit_lookup_fail(&lcp->lc_sid);
1366 /* fixup error code as per RFC5661 */
1367 if (nfserr == nfserr_bad_stateid)
1368 nfserr = nfserr_badlayout;
1369 goto out;
1370 }
1371
1372 nfserr = ops->proc_layoutcommit(inode, lcp);
1373 if (nfserr)
1374 goto out_put_stid;
1375
1376 if (new_size > i_size_read(inode)) {
1377 lcp->lc_size_chg = 1;
1378 lcp->lc_newsize = new_size;
1379 } else {
1380 lcp->lc_size_chg = 0;
1381 }
1382
1383out_put_stid:
1384 nfs4_put_stid(&ls->ls_stid);
1385out:
1386 return nfserr;
1387}
1388
1389static __be32
1390nfsd4_layoutreturn(struct svc_rqst *rqstp,
1391 struct nfsd4_compound_state *cstate,
1392 struct nfsd4_layoutreturn *lrp)
1393{
1394 struct svc_fh *current_fh = &cstate->current_fh;
1395 __be32 nfserr;
1396
1397 nfserr = fh_verify(rqstp, current_fh, 0, NFSD_MAY_NOP);
1398 if (nfserr)
1399 goto out;
1400
1401 nfserr = nfserr_layoutunavailable;
1402 if (!nfsd4_layout_verify(current_fh->fh_export, lrp->lr_layout_type))
1403 goto out;
1404
1405 switch (lrp->lr_seg.iomode) {
1406 case IOMODE_READ:
1407 case IOMODE_RW:
1408 case IOMODE_ANY:
1409 break;
1410 default:
1411 dprintk("%s: invalid iomode %d\n", __func__,
1412 lrp->lr_seg.iomode);
1413 nfserr = nfserr_inval;
1414 goto out;
1415 }
1416
1417 switch (lrp->lr_return_type) {
1418 case RETURN_FILE:
1419 nfserr = nfsd4_return_file_layouts(rqstp, cstate, lrp);
1420 break;
1421 case RETURN_FSID:
1422 case RETURN_ALL:
1423 nfserr = nfsd4_return_client_layouts(rqstp, cstate, lrp);
1424 break;
1425 default:
1426 dprintk("%s: invalid return_type %d\n", __func__,
1427 lrp->lr_return_type);
1428 nfserr = nfserr_inval;
1429 break;
1430 }
1431out:
1432 return nfserr;
1433}
1434#endif /* CONFIG_NFSD_PNFS */
1435
1181/* 1436/*
1182 * NULL call. 1437 * NULL call.
1183 */ 1438 */
@@ -1679,6 +1934,36 @@ static inline u32 nfsd4_create_session_rsize(struct svc_rqst *rqstp, struct nfsd
1679 op_encode_channel_attrs_maxsz) * sizeof(__be32); 1934 op_encode_channel_attrs_maxsz) * sizeof(__be32);
1680} 1935}
1681 1936
1937#ifdef CONFIG_NFSD_PNFS
1938/*
1939 * At this stage we don't really know what layout driver will handle the request,
1940 * so we need to define an arbitrary upper bound here.
1941 */
1942#define MAX_LAYOUT_SIZE 128
1943static inline u32 nfsd4_layoutget_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
1944{
1945 return (op_encode_hdr_size +
1946 1 /* logr_return_on_close */ +
1947 op_encode_stateid_maxsz +
1948 1 /* nr of layouts */ +
1949 MAX_LAYOUT_SIZE) * sizeof(__be32);
1950}
1951
1952static inline u32 nfsd4_layoutcommit_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
1953{
1954 return (op_encode_hdr_size +
1955 1 /* locr_newsize */ +
1956 2 /* ns_size */) * sizeof(__be32);
1957}
1958
1959static inline u32 nfsd4_layoutreturn_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
1960{
1961 return (op_encode_hdr_size +
1962 1 /* lrs_stateid */ +
1963 op_encode_stateid_maxsz) * sizeof(__be32);
1964}
1965#endif /* CONFIG_NFSD_PNFS */
1966
1682static struct nfsd4_operation nfsd4_ops[] = { 1967static struct nfsd4_operation nfsd4_ops[] = {
1683 [OP_ACCESS] = { 1968 [OP_ACCESS] = {
1684 .op_func = (nfsd4op_func)nfsd4_access, 1969 .op_func = (nfsd4op_func)nfsd4_access,
@@ -1966,6 +2251,31 @@ static struct nfsd4_operation nfsd4_ops[] = {
1966 .op_get_currentstateid = (stateid_getter)nfsd4_get_freestateid, 2251 .op_get_currentstateid = (stateid_getter)nfsd4_get_freestateid,
1967 .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize, 2252 .op_rsize_bop = (nfsd4op_rsize)nfsd4_only_status_rsize,
1968 }, 2253 },
2254#ifdef CONFIG_NFSD_PNFS
2255 [OP_GETDEVICEINFO] = {
2256 .op_func = (nfsd4op_func)nfsd4_getdeviceinfo,
2257 .op_flags = ALLOWED_WITHOUT_FH,
2258 .op_name = "OP_GETDEVICEINFO",
2259 },
2260 [OP_LAYOUTGET] = {
2261 .op_func = (nfsd4op_func)nfsd4_layoutget,
2262 .op_flags = OP_MODIFIES_SOMETHING,
2263 .op_name = "OP_LAYOUTGET",
2264 .op_rsize_bop = (nfsd4op_rsize)nfsd4_layoutget_rsize,
2265 },
2266 [OP_LAYOUTCOMMIT] = {
2267 .op_func = (nfsd4op_func)nfsd4_layoutcommit,
2268 .op_flags = OP_MODIFIES_SOMETHING,
2269 .op_name = "OP_LAYOUTCOMMIT",
2270 .op_rsize_bop = (nfsd4op_rsize)nfsd4_layoutcommit_rsize,
2271 },
2272 [OP_LAYOUTRETURN] = {
2273 .op_func = (nfsd4op_func)nfsd4_layoutreturn,
2274 .op_flags = OP_MODIFIES_SOMETHING,
2275 .op_name = "OP_LAYOUTRETURN",
2276 .op_rsize_bop = (nfsd4op_rsize)nfsd4_layoutreturn_rsize,
2277 },
2278#endif /* CONFIG_NFSD_PNFS */
1969 2279
1970 /* NFSv4.2 operations */ 2280 /* NFSv4.2 operations */
1971 [OP_ALLOCATE] = { 2281 [OP_ALLOCATE] = {