Skip to content

Commit 6ae3733

Browse files
committed
NFSv4.1: Ask for no delegation on OPEN if using O_DIRECT
If we're using NFSv4.1, then we have the ability to let the server know whether or not we believe that returning a delegation as part of our OPEN request would be useful. The feature needs to be used with care, since the client sending the request doesn't necessarily know how other clients are using that file, and how they may be affected by the delegation. For this reason, our initial use of the feature will be to let the server know when the client believes that handing out a delegation would not be useful. The first application for this function is when opening the file using O_DIRECT. Signed-off-by: Trond Myklebust <[email protected]>
1 parent 0e3b137 commit 6ae3733

File tree

3 files changed

+85
-26
lines changed

3 files changed

+85
-26
lines changed

fs/nfs/nfs4proc.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -940,6 +940,31 @@ static bool nfs4_clear_cap_atomic_open_v1(struct nfs_server *server,
940940
return true;
941941
}
942942

943+
static u32
944+
nfs4_map_atomic_open_share(struct nfs_server *server,
945+
fmode_t fmode, int openflags)
946+
{
947+
u32 res = 0;
948+
949+
switch (fmode & (FMODE_READ | FMODE_WRITE)) {
950+
case FMODE_READ:
951+
res = NFS4_SHARE_ACCESS_READ;
952+
break;
953+
case FMODE_WRITE:
954+
res = NFS4_SHARE_ACCESS_WRITE;
955+
break;
956+
case FMODE_READ|FMODE_WRITE:
957+
res = NFS4_SHARE_ACCESS_BOTH;
958+
}
959+
if (!(server->caps & NFS_CAP_ATOMIC_OPEN_V1))
960+
goto out;
961+
/* Want no delegation if we're using O_DIRECT */
962+
if (openflags & O_DIRECT)
963+
res |= NFS4_SHARE_WANT_NO_DELEG;
964+
out:
965+
return res;
966+
}
967+
943968
static enum open_claim_type4
944969
nfs4_map_atomic_open_claim(struct nfs_server *server,
945970
enum open_claim_type4 claim)
@@ -1002,6 +1027,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
10021027
atomic_inc(&sp->so_count);
10031028
p->o_arg.open_flags = flags;
10041029
p->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE);
1030+
p->o_arg.share_access = nfs4_map_atomic_open_share(server,
1031+
fmode, flags);
10051032
/* don't put an ACCESS op in OPEN compound if O_EXCL, because ACCESS
10061033
* will return permission denied for all bits until close */
10071034
if (!(flags & O_EXCL)) {
@@ -2695,6 +2722,9 @@ static void nfs4_close_prepare(struct rpc_task *task, void *data)
26952722
goto out_wait;
26962723
}
26972724
}
2725+
calldata->arg.share_access =
2726+
nfs4_map_atomic_open_share(NFS_SERVER(inode),
2727+
calldata->arg.fmode, 0);
26982728

26992729
nfs_fattr_init(calldata->res.fattr);
27002730
calldata->timestamp = jiffies;

fs/nfs/nfs4xdr.c

Lines changed: 53 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1351,24 +1351,12 @@ static void encode_lookup(struct xdr_stream *xdr, const struct qstr *name, struc
13511351
encode_string(xdr, name->len, name->name);
13521352
}
13531353

1354-
static void encode_share_access(struct xdr_stream *xdr, fmode_t fmode)
1354+
static void encode_share_access(struct xdr_stream *xdr, u32 share_access)
13551355
{
13561356
__be32 *p;
13571357

13581358
p = reserve_space(xdr, 8);
1359-
switch (fmode & (FMODE_READ|FMODE_WRITE)) {
1360-
case FMODE_READ:
1361-
*p++ = cpu_to_be32(NFS4_SHARE_ACCESS_READ);
1362-
break;
1363-
case FMODE_WRITE:
1364-
*p++ = cpu_to_be32(NFS4_SHARE_ACCESS_WRITE);
1365-
break;
1366-
case FMODE_READ|FMODE_WRITE:
1367-
*p++ = cpu_to_be32(NFS4_SHARE_ACCESS_BOTH);
1368-
break;
1369-
default:
1370-
*p++ = cpu_to_be32(0);
1371-
}
1359+
*p++ = cpu_to_be32(share_access);
13721360
*p = cpu_to_be32(0); /* for linux, share_deny = 0 always */
13731361
}
13741362

@@ -1380,7 +1368,7 @@ static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_opena
13801368
* owner 4 = 32
13811369
*/
13821370
encode_nfs4_seqid(xdr, arg->seqid);
1383-
encode_share_access(xdr, arg->fmode);
1371+
encode_share_access(xdr, arg->share_access);
13841372
p = reserve_space(xdr, 36);
13851373
p = xdr_encode_hyper(p, arg->clientid);
13861374
*p++ = cpu_to_be32(24);
@@ -1535,7 +1523,7 @@ static void encode_open_downgrade(struct xdr_stream *xdr, const struct nfs_close
15351523
encode_op_hdr(xdr, OP_OPEN_DOWNGRADE, decode_open_downgrade_maxsz, hdr);
15361524
encode_nfs4_stateid(xdr, &arg->stateid);
15371525
encode_nfs4_seqid(xdr, arg->seqid);
1538-
encode_share_access(xdr, arg->fmode);
1526+
encode_share_access(xdr, arg->share_access);
15391527
}
15401528

15411529
static void
@@ -4935,20 +4923,13 @@ static int decode_space_limit(struct xdr_stream *xdr, u64 *maxsize)
49354923
return -EIO;
49364924
}
49374925

4938-
static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res)
4926+
static int decode_rw_delegation(struct xdr_stream *xdr,
4927+
uint32_t delegation_type,
4928+
struct nfs_openres *res)
49394929
{
49404930
__be32 *p;
4941-
uint32_t delegation_type;
49424931
int status;
49434932

4944-
p = xdr_inline_decode(xdr, 4);
4945-
if (unlikely(!p))
4946-
goto out_overflow;
4947-
delegation_type = be32_to_cpup(p);
4948-
if (delegation_type == NFS4_OPEN_DELEGATE_NONE) {
4949-
res->delegation_type = 0;
4950-
return 0;
4951-
}
49524933
status = decode_stateid(xdr, &res->delegation);
49534934
if (unlikely(status))
49544935
return status;
@@ -4972,6 +4953,52 @@ static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res)
49724953
return -EIO;
49734954
}
49744955

4956+
static int decode_no_delegation(struct xdr_stream *xdr, struct nfs_openres *res)
4957+
{
4958+
__be32 *p;
4959+
uint32_t why_no_delegation;
4960+
4961+
p = xdr_inline_decode(xdr, 4);
4962+
if (unlikely(!p))
4963+
goto out_overflow;
4964+
why_no_delegation = be32_to_cpup(p);
4965+
switch (why_no_delegation) {
4966+
case WND4_CONTENTION:
4967+
case WND4_RESOURCE:
4968+
xdr_inline_decode(xdr, 4);
4969+
/* Ignore for now */
4970+
}
4971+
return 0;
4972+
out_overflow:
4973+
print_overflow_msg(__func__, xdr);
4974+
return -EIO;
4975+
}
4976+
4977+
static int decode_delegation(struct xdr_stream *xdr, struct nfs_openres *res)
4978+
{
4979+
__be32 *p;
4980+
uint32_t delegation_type;
4981+
4982+
p = xdr_inline_decode(xdr, 4);
4983+
if (unlikely(!p))
4984+
goto out_overflow;
4985+
delegation_type = be32_to_cpup(p);
4986+
res->delegation_type = 0;
4987+
switch (delegation_type) {
4988+
case NFS4_OPEN_DELEGATE_NONE:
4989+
return 0;
4990+
case NFS4_OPEN_DELEGATE_READ:
4991+
case NFS4_OPEN_DELEGATE_WRITE:
4992+
return decode_rw_delegation(xdr, delegation_type, res);
4993+
case NFS4_OPEN_DELEGATE_NONE_EXT:
4994+
return decode_no_delegation(xdr, res);
4995+
}
4996+
return -EIO;
4997+
out_overflow:
4998+
print_overflow_msg(__func__, xdr);
4999+
return -EIO;
5000+
}
5001+
49755002
static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
49765003
{
49775004
__be32 *p;

include/linux/nfs_xdr.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,7 @@ struct nfs_openargs {
326326
struct nfs_seqid * seqid;
327327
int open_flags;
328328
fmode_t fmode;
329+
u32 share_access;
329330
u32 access;
330331
__u64 clientid;
331332
struct stateowner_id id;
@@ -393,6 +394,7 @@ struct nfs_closeargs {
393394
nfs4_stateid stateid;
394395
struct nfs_seqid * seqid;
395396
fmode_t fmode;
397+
u32 share_access;
396398
const u32 * bitmask;
397399
};
398400

0 commit comments

Comments
 (0)