BUG_ON(readdir->count < 80);
if (cookie > 2) {
- readdir->cookie = (cookie > 2) ? cookie : 0;
+ readdir->cookie = cookie;
memcpy(&readdir->verifier, verifier, sizeof(readdir->verifier));
return;
}
int err;
do {
err = _nfs4_open_reclaim(sp, state);
- switch (err) {
- case 0:
- case -NFS4ERR_STALE_CLIENTID:
- case -NFS4ERR_STALE_STATEID:
- case -NFS4ERR_EXPIRED:
- return err;
- }
- err = nfs4_handle_exception(server, err, &exception);
+ if (err != -NFS4ERR_DELAY)
+ break;
+ nfs4_handle_exception(server, err, &exception);
} while (exception.retry);
return err;
}
goto out_nodeleg;
}
+static inline int nfs4_do_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state, struct dentry *dentry)
+{
+ struct nfs_server *server = NFS_SERVER(dentry->d_inode);
+ struct nfs4_exception exception = { };
+ int err;
+
+ do {
+ err = _nfs4_open_expired(sp, state, dentry);
+ if (err == -NFS4ERR_DELAY)
+ nfs4_handle_exception(server, err, &exception);
+ } while (exception.retry);
+ return err;
+}
+
static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state)
{
struct nfs_inode *nfsi = NFS_I(state->inode);
continue;
get_nfs_open_context(ctx);
spin_unlock(&state->inode->i_lock);
- status = _nfs4_open_expired(sp, state, ctx->dentry);
+ status = nfs4_do_open_expired(sp, state, ctx->dentry);
put_nfs_open_context(ctx);
return status;
}
.rpc_argp = &arg,
.rpc_resp = &res,
};
+ int status;
fattr->valid = 0;
- if (state != NULL)
+ if (state != NULL) {
msg.rpc_cred = state->owner->so_cred;
- if (sattr->ia_valid & ATTR_SIZE)
- nfs4_copy_stateid(&arg.stateid, state, NULL);
- else
+ nfs4_copy_stateid(&arg.stateid, state, current->files);
+ } else
memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid));
- return rpc_call_sync(server->client, &msg, 0);
+ status = rpc_call_sync(server->client, &msg, 0);
+ return status;
}
static int nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr,
nfs4_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
struct iattr *sattr)
{
- struct inode * inode = dentry->d_inode;
- int size_change = sattr->ia_valid & ATTR_SIZE;
- struct nfs4_state *state = NULL;
- int need_iput = 0;
+ struct rpc_cred *cred;
+ struct inode *inode = dentry->d_inode;
+ struct nfs4_state *state;
int status;
fattr->valid = 0;
- if (size_change) {
- struct rpc_cred *cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0);
- if (IS_ERR(cred))
- return PTR_ERR(cred);
+ cred = rpcauth_lookupcred(NFS_SERVER(inode)->client->cl_auth, 0);
+ if (IS_ERR(cred))
+ return PTR_ERR(cred);
+ /* Search for an existing WRITE delegation first */
+ state = nfs4_open_delegated(inode, FMODE_WRITE, cred);
+ if (!IS_ERR(state)) {
+ /* NB: nfs4_open_delegated() bumps the inode->i_count */
+ iput(inode);
+ } else {
+ /* Search for an existing open(O_WRITE) stateid */
state = nfs4_find_state(inode, cred, FMODE_WRITE);
- if (state == NULL) {
- state = nfs4_open_delegated(dentry->d_inode,
- FMODE_WRITE, cred);
- if (IS_ERR(state))
- state = nfs4_do_open(dentry->d_parent->d_inode,
- dentry, FMODE_WRITE,
- NULL, cred);
- need_iput = 1;
- }
- put_rpccred(cred);
- if (IS_ERR(state))
- return PTR_ERR(state);
-
- if (state->inode != inode) {
- printk(KERN_WARNING "nfs: raced in setattr (%p != %p), returning -EIO\n", inode, state->inode);
- status = -EIO;
- goto out;
- }
}
+
status = nfs4_do_setattr(NFS_SERVER(inode), fattr,
NFS_FH(inode), sattr, state);
-out:
- if (state) {
- inode = state->inode;
+ if (status == 0)
+ nfs_setattr_update_inode(inode, sattr);
+ if (state != NULL)
nfs4_close_state(state, FMODE_WRITE);
- if (need_iput)
- iput(inode);
- }
+ put_rpccred(cred);
return status;
}
struct nfs_fattr fattr;
status = nfs4_do_setattr(NFS_SERVER(dir), &fattr,
NFS_FH(state->inode), sattr, state);
- if (status == 0)
+ if (status == 0) {
+ nfs_setattr_update_inode(state->inode, sattr);
goto out;
+ }
} else if (flags != 0)
goto out;
nfs4_close_state(state, flags);
};
int status;
+ dprintk("%s: dentry = %s/%s, cookie = %Lu\n", __FUNCTION__,
+ dentry->d_parent->d_name.name,
+ dentry->d_name.name,
+ (unsigned long long)cookie);
lock_kernel();
nfs4_setup_readdir(cookie, NFS_COOKIEVERF(dir), dentry, &args);
res.pgbase = args.pgbase;
if (status == 0)
memcpy(NFS_COOKIEVERF(dir), res.verifier.data, NFS4_VERIFIER_SIZE);
unlock_kernel();
+ dprintk("%s: returns %d\n", __FUNCTION__, status);
return status;
}
struct nfs4_cached_acl {
int cached;
size_t len;
- char data[];
+ char data[0];
};
static void nfs4_set_cached_acl(struct inode *inode, struct nfs4_cached_acl *acl)
down_read(&clp->cl_sem);
nlo.clientid = clp->cl_clientid;
down(&state->lock_sema);
- lsp = nfs4_find_lock_state(state, request->fl_owner);
- if (lsp)
- nlo.id = lsp->ls_id;
- else {
- spin_lock(&clp->cl_lock);
- nlo.id = nfs4_alloc_lockowner_id(clp);
- spin_unlock(&clp->cl_lock);
- }
+ status = nfs4_set_lock_state(state, request);
+ if (status != 0)
+ goto out;
+ lsp = request->fl_u.nfs4_fl.owner;
+ nlo.id = lsp->ls_id;
arg.u.lockt = &nlo;
status = rpc_call_sync(server->client, &msg, 0);
if (!status) {
request->fl_pid = 0;
status = 0;
}
- if (lsp)
- nfs4_put_lock_state(lsp);
+out:
up(&state->lock_sema);
up_read(&clp->cl_sem);
return status;
};
struct nfs4_lock_state *lsp;
struct nfs_locku_opargs luargs;
- int status = 0;
+ int status;
down_read(&clp->cl_sem);
down(&state->lock_sema);
- lsp = nfs4_find_lock_state(state, request->fl_owner);
- if (!lsp)
+ status = nfs4_set_lock_state(state, request);
+ if (status != 0)
goto out;
+ lsp = request->fl_u.nfs4_fl.owner;
/* We might have lost the locks! */
- if ((lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) {
- luargs.seqid = lsp->ls_seqid;
- memcpy(&luargs.stateid, &lsp->ls_stateid, sizeof(luargs.stateid));
- arg.u.locku = &luargs;
- status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR);
- nfs4_increment_lock_seqid(status, lsp);
- }
+ if ((lsp->ls_flags & NFS_LOCK_INITIALIZED) == 0)
+ goto out;
+ luargs.seqid = lsp->ls_seqid;
+ memcpy(&luargs.stateid, &lsp->ls_stateid, sizeof(luargs.stateid));
+ arg.u.locku = &luargs;
+ status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR);
+ nfs4_increment_lock_seqid(status, lsp);
- if (status == 0) {
+ if (status == 0)
memcpy(&lsp->ls_stateid, &res.u.stateid,
sizeof(lsp->ls_stateid));
- nfs4_notify_unlck(state, request, lsp);
- }
- nfs4_put_lock_state(lsp);
out:
up(&state->lock_sema);
if (status == 0)
{
struct inode *inode = state->inode;
struct nfs_server *server = NFS_SERVER(inode);
- struct nfs4_lock_state *lsp;
+ struct nfs4_lock_state *lsp = request->fl_u.nfs4_fl.owner;
struct nfs_lockargs arg = {
.fh = NFS_FH(inode),
.type = nfs4_lck_type(cmd, request),
};
int status;
- lsp = nfs4_get_lock_state(state, request->fl_owner);
- if (lsp == NULL)
- return -ENOMEM;
if (!(lsp->ls_flags & NFS_LOCK_INITIALIZED)) {
struct nfs4_state_owner *owner = state->owner;
struct nfs_open_to_lock otl = {
* seqid mutating errors */
nfs4_increment_seqid(status, owner);
up(&owner->so_sema);
+ if (status == 0) {
+ lsp->ls_flags |= NFS_LOCK_INITIALIZED;
+ lsp->ls_seqid++;
+ }
} else {
struct nfs_exist_lock el = {
.seqid = lsp->ls_seqid,
};
memcpy(&el.stateid, &lsp->ls_stateid, sizeof(el.stateid));
largs.u.exist_lock = ⪙
- largs.new_lock_owner = 0;
arg.u.lock = &largs;
status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR);
+ /* increment seqid on success, and * seqid mutating errors*/
+ nfs4_increment_lock_seqid(status, lsp);
}
- /* increment seqid on success, and * seqid mutating errors*/
- nfs4_increment_lock_seqid(status, lsp);
/* save the returned stateid. */
- if (status == 0) {
+ if (status == 0)
memcpy(&lsp->ls_stateid, &res.u.stateid, sizeof(nfs4_stateid));
- lsp->ls_flags |= NFS_LOCK_INITIALIZED;
- if (!reclaim)
- nfs4_notify_setlk(state, request, lsp);
- } else if (status == -NFS4ERR_DENIED)
+ else if (status == -NFS4ERR_DENIED)
status = -EAGAIN;
- nfs4_put_lock_state(lsp);
return status;
}
static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request)
{
- return _nfs4_do_setlk(state, F_SETLK, request, 1);
+ struct nfs_server *server = NFS_SERVER(state->inode);
+ struct nfs4_exception exception = { };
+ int err;
+
+ do {
+ err = _nfs4_do_setlk(state, F_SETLK, request, 1);
+ if (err != -NFS4ERR_DELAY)
+ break;
+ nfs4_handle_exception(server, err, &exception);
+ } while (exception.retry);
+ return err;
}
static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request)
{
- return _nfs4_do_setlk(state, F_SETLK, request, 0);
+ struct nfs_server *server = NFS_SERVER(state->inode);
+ struct nfs4_exception exception = { };
+ int err;
+
+ do {
+ err = _nfs4_do_setlk(state, F_SETLK, request, 0);
+ if (err != -NFS4ERR_DELAY)
+ break;
+ nfs4_handle_exception(server, err, &exception);
+ } while (exception.retry);
+ return err;
}
static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
down_read(&clp->cl_sem);
down(&state->lock_sema);
- status = _nfs4_do_setlk(state, cmd, request, 0);
+ status = nfs4_set_lock_state(state, request);
+ if (status == 0)
+ status = _nfs4_do_setlk(state, cmd, request, 0);
up(&state->lock_sema);
if (status == 0) {
/* Note: we always want to sleep here! */
if (signalled())
break;
} while(status < 0);
-
return status;
}