NFSv4.1: Enable open-by-filehandle
Sometimes, we actually _want_ to do open-by-filehandle, for instance when recovering opens after a network partition, or when called from nfs4_file_open. Enable that functionality using a new capability NFS_CAP_ATOMIC_OPEN_V1, and which is only enabled for NFSv4.1 servers that support it. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
This commit is contained in:
parent
d9fc6619ca
commit
49f9a0fafd
|
@ -1486,6 +1486,8 @@ static int nfs4_lookup_revalidate(struct dentry *dentry, unsigned int flags)
|
||||||
goto no_open;
|
goto no_open;
|
||||||
if (d_mountpoint(dentry))
|
if (d_mountpoint(dentry))
|
||||||
goto no_open;
|
goto no_open;
|
||||||
|
if (NFS_SB(dentry->d_sb)->caps & NFS_CAP_ATOMIC_OPEN_V1)
|
||||||
|
goto no_open;
|
||||||
|
|
||||||
inode = dentry->d_inode;
|
inode = dentry->d_inode;
|
||||||
parent = dget_parent(dentry);
|
parent = dget_parent(dentry);
|
||||||
|
|
|
@ -767,6 +767,35 @@ struct nfs4_opendata {
|
||||||
int cancelled;
|
int cancelled;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static bool nfs4_clear_cap_atomic_open_v1(struct nfs_server *server,
|
||||||
|
int err, struct nfs4_exception *exception)
|
||||||
|
{
|
||||||
|
if (err != -EINVAL)
|
||||||
|
return false;
|
||||||
|
if (!(server->caps & NFS_CAP_ATOMIC_OPEN_V1))
|
||||||
|
return false;
|
||||||
|
server->caps &= ~NFS_CAP_ATOMIC_OPEN_V1;
|
||||||
|
exception->retry = 1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum open_claim_type4
|
||||||
|
nfs4_map_atomic_open_claim(struct nfs_server *server,
|
||||||
|
enum open_claim_type4 claim)
|
||||||
|
{
|
||||||
|
if (server->caps & NFS_CAP_ATOMIC_OPEN_V1)
|
||||||
|
return claim;
|
||||||
|
switch (claim) {
|
||||||
|
default:
|
||||||
|
return claim;
|
||||||
|
case NFS4_OPEN_CLAIM_FH:
|
||||||
|
return NFS4_OPEN_CLAIM_NULL;
|
||||||
|
case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
|
||||||
|
return NFS4_OPEN_CLAIM_DELEGATE_CUR;
|
||||||
|
case NFS4_OPEN_CLAIM_DELEG_PREV_FH:
|
||||||
|
return NFS4_OPEN_CLAIM_DELEGATE_PREV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void nfs4_init_opendata_res(struct nfs4_opendata *p)
|
static void nfs4_init_opendata_res(struct nfs4_opendata *p)
|
||||||
{
|
{
|
||||||
|
@ -818,8 +847,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,
|
||||||
p->o_arg.server = server;
|
p->o_arg.server = server;
|
||||||
p->o_arg.bitmask = server->attr_bitmask;
|
p->o_arg.bitmask = server->attr_bitmask;
|
||||||
p->o_arg.open_bitmap = &nfs4_fattr_bitmap[0];
|
p->o_arg.open_bitmap = &nfs4_fattr_bitmap[0];
|
||||||
p->o_arg.claim = claim;
|
p->o_arg.claim = nfs4_map_atomic_open_claim(server, claim);
|
||||||
switch (claim) {
|
switch (p->o_arg.claim) {
|
||||||
case NFS4_OPEN_CLAIM_NULL:
|
case NFS4_OPEN_CLAIM_NULL:
|
||||||
case NFS4_OPEN_CLAIM_DELEGATE_CUR:
|
case NFS4_OPEN_CLAIM_DELEGATE_CUR:
|
||||||
case NFS4_OPEN_CLAIM_DELEGATE_PREV:
|
case NFS4_OPEN_CLAIM_DELEGATE_PREV:
|
||||||
|
@ -1326,6 +1355,8 @@ static int nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state
|
||||||
int err;
|
int err;
|
||||||
do {
|
do {
|
||||||
err = _nfs4_do_open_reclaim(ctx, state);
|
err = _nfs4_do_open_reclaim(ctx, state);
|
||||||
|
if (nfs4_clear_cap_atomic_open_v1(server, err, &exception))
|
||||||
|
continue;
|
||||||
if (err != -NFS4ERR_DELAY)
|
if (err != -NFS4ERR_DELAY)
|
||||||
break;
|
break;
|
||||||
nfs4_handle_exception(server, err, &exception);
|
nfs4_handle_exception(server, err, &exception);
|
||||||
|
@ -1741,7 +1772,7 @@ static int _nfs4_open_expired(struct nfs_open_context *ctx, struct nfs4_state *s
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
opendata = nfs4_open_recoverdata_alloc(ctx, state,
|
opendata = nfs4_open_recoverdata_alloc(ctx, state,
|
||||||
NFS4_OPEN_CLAIM_NULL);
|
NFS4_OPEN_CLAIM_FH);
|
||||||
if (IS_ERR(opendata))
|
if (IS_ERR(opendata))
|
||||||
return PTR_ERR(opendata);
|
return PTR_ERR(opendata);
|
||||||
ret = nfs4_open_recover(opendata, state);
|
ret = nfs4_open_recover(opendata, state);
|
||||||
|
@ -1759,6 +1790,8 @@ static int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state
|
||||||
|
|
||||||
do {
|
do {
|
||||||
err = _nfs4_open_expired(ctx, state);
|
err = _nfs4_open_expired(ctx, state);
|
||||||
|
if (nfs4_clear_cap_atomic_open_v1(server, err, &exception))
|
||||||
|
continue;
|
||||||
switch (err) {
|
switch (err) {
|
||||||
default:
|
default:
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -1926,6 +1959,7 @@ static int _nfs4_do_open(struct inode *dir,
|
||||||
struct nfs4_state *state = NULL;
|
struct nfs4_state *state = NULL;
|
||||||
struct nfs_server *server = NFS_SERVER(dir);
|
struct nfs_server *server = NFS_SERVER(dir);
|
||||||
struct nfs4_opendata *opendata;
|
struct nfs4_opendata *opendata;
|
||||||
|
enum open_claim_type4 claim = NFS4_OPEN_CLAIM_NULL;
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
/* Protect against reboot recovery conflicts */
|
/* Protect against reboot recovery conflicts */
|
||||||
|
@ -1941,9 +1975,10 @@ static int _nfs4_do_open(struct inode *dir,
|
||||||
if (dentry->d_inode != NULL)
|
if (dentry->d_inode != NULL)
|
||||||
nfs4_return_incompatible_delegation(dentry->d_inode, fmode);
|
nfs4_return_incompatible_delegation(dentry->d_inode, fmode);
|
||||||
status = -ENOMEM;
|
status = -ENOMEM;
|
||||||
|
if (dentry->d_inode)
|
||||||
|
claim = NFS4_OPEN_CLAIM_FH;
|
||||||
opendata = nfs4_opendata_alloc(dentry, sp, fmode, flags, sattr,
|
opendata = nfs4_opendata_alloc(dentry, sp, fmode, flags, sattr,
|
||||||
NFS4_OPEN_CLAIM_NULL,
|
claim, GFP_KERNEL);
|
||||||
GFP_KERNEL);
|
|
||||||
if (opendata == NULL)
|
if (opendata == NULL)
|
||||||
goto err_put_state_owner;
|
goto err_put_state_owner;
|
||||||
|
|
||||||
|
@ -2001,6 +2036,7 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
|
||||||
struct rpc_cred *cred,
|
struct rpc_cred *cred,
|
||||||
struct nfs4_threshold **ctx_th)
|
struct nfs4_threshold **ctx_th)
|
||||||
{
|
{
|
||||||
|
struct nfs_server *server = NFS_SERVER(dir);
|
||||||
struct nfs4_exception exception = { };
|
struct nfs4_exception exception = { };
|
||||||
struct nfs4_state *res;
|
struct nfs4_state *res;
|
||||||
int status;
|
int status;
|
||||||
|
@ -2044,7 +2080,9 @@ static struct nfs4_state *nfs4_do_open(struct inode *dir,
|
||||||
exception.retry = 1;
|
exception.retry = 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
res = ERR_PTR(nfs4_handle_exception(NFS_SERVER(dir),
|
if (nfs4_clear_cap_atomic_open_v1(server, status, &exception))
|
||||||
|
continue;
|
||||||
|
res = ERR_PTR(nfs4_handle_exception(server,
|
||||||
status, &exception));
|
status, &exception));
|
||||||
} while (exception.retry);
|
} while (exception.retry);
|
||||||
return res;
|
return res;
|
||||||
|
@ -6858,7 +6896,8 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
|
||||||
| NFS_CAP_ATOMIC_OPEN
|
| NFS_CAP_ATOMIC_OPEN
|
||||||
| NFS_CAP_CHANGE_ATTR
|
| NFS_CAP_CHANGE_ATTR
|
||||||
| NFS_CAP_POSIX_LOCK
|
| NFS_CAP_POSIX_LOCK
|
||||||
| NFS_CAP_STATEID_NFSV41,
|
| NFS_CAP_STATEID_NFSV41
|
||||||
|
| NFS_CAP_ATOMIC_OPEN_V1,
|
||||||
.call_sync = nfs4_call_sync_sequence,
|
.call_sync = nfs4_call_sync_sequence,
|
||||||
.match_stateid = nfs41_match_stateid,
|
.match_stateid = nfs41_match_stateid,
|
||||||
.find_root_sec = nfs41_find_root_sec,
|
.find_root_sec = nfs41_find_root_sec,
|
||||||
|
|
|
@ -198,5 +198,6 @@ struct nfs_server {
|
||||||
#define NFS_CAP_POSIX_LOCK (1U << 14)
|
#define NFS_CAP_POSIX_LOCK (1U << 14)
|
||||||
#define NFS_CAP_UIDGID_NOMAP (1U << 15)
|
#define NFS_CAP_UIDGID_NOMAP (1U << 15)
|
||||||
#define NFS_CAP_STATEID_NFSV41 (1U << 16)
|
#define NFS_CAP_STATEID_NFSV41 (1U << 16)
|
||||||
|
#define NFS_CAP_ATOMIC_OPEN_V1 (1U << 17)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue
Block a user