📄 nfs4proc.c
字号:
continue; rcu_read_unlock(); update_open_stateid(state, NULL, &stateid, open_mode); goto out_return_state; } rcu_read_unlock();out: return ERR_PTR(ret);out_return_state: atomic_inc(&state->count); return state;}static struct nfs4_state *nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data){ struct inode *inode; struct nfs4_state *state = NULL; struct nfs_delegation *delegation; nfs4_stateid *deleg_stateid = NULL; int ret; if (!data->rpc_done) { state = nfs4_try_open_cached(data); goto out; } ret = -EAGAIN; if (!(data->f_attr.valid & NFS_ATTR_FATTR)) goto err; inode = nfs_fhget(data->dir->d_sb, &data->o_res.fh, &data->f_attr); ret = PTR_ERR(inode); if (IS_ERR(inode)) goto err; ret = -ENOMEM; state = nfs4_get_open_state(inode, data->owner); if (state == NULL) goto err_put_inode; if (data->o_res.delegation_type != 0) { int delegation_flags = 0; rcu_read_lock(); delegation = rcu_dereference(NFS_I(inode)->delegation); if (delegation) delegation_flags = delegation->flags; rcu_read_unlock(); if (!(delegation_flags & NFS_DELEGATION_NEED_RECLAIM)) nfs_inode_set_delegation(state->inode, data->owner->so_cred, &data->o_res); else nfs_inode_reclaim_delegation(state->inode, data->owner->so_cred, &data->o_res); } rcu_read_lock(); delegation = rcu_dereference(NFS_I(inode)->delegation); if (delegation != NULL) deleg_stateid = &delegation->stateid; update_open_stateid(state, &data->o_res.stateid, deleg_stateid, data->o_arg.open_flags); rcu_read_unlock(); iput(inode);out: return state;err_put_inode: iput(inode);err: return ERR_PTR(ret);}static struct nfs_open_context *nfs4_state_find_open_context(struct nfs4_state *state){ struct nfs_inode *nfsi = NFS_I(state->inode); struct nfs_open_context *ctx; spin_lock(&state->inode->i_lock); list_for_each_entry(ctx, &nfsi->open_files, list) { if (ctx->state != state) continue; get_nfs_open_context(ctx); spin_unlock(&state->inode->i_lock); return ctx; } spin_unlock(&state->inode->i_lock); return ERR_PTR(-ENOENT);}static struct nfs4_opendata *nfs4_open_recoverdata_alloc(struct nfs_open_context *ctx, struct nfs4_state *state){ struct nfs4_opendata *opendata; opendata = nfs4_opendata_alloc(&ctx->path, state->owner, 0, NULL); if (opendata == NULL) return ERR_PTR(-ENOMEM); opendata->state = state; atomic_inc(&state->count); return opendata;}static int nfs4_open_recover_helper(struct nfs4_opendata *opendata, mode_t openflags, struct nfs4_state **res){ struct nfs4_state *newstate; int ret; opendata->o_arg.open_flags = openflags; memset(&opendata->o_res, 0, sizeof(opendata->o_res)); memset(&opendata->c_res, 0, sizeof(opendata->c_res)); nfs4_init_opendata_res(opendata); ret = _nfs4_proc_open(opendata); if (ret != 0) return ret; newstate = nfs4_opendata_to_nfs4_state(opendata); if (IS_ERR(newstate)) return PTR_ERR(newstate); nfs4_close_state(&opendata->path, newstate, openflags); *res = newstate; return 0;}static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *state){ struct nfs4_state *newstate; int ret; /* memory barrier prior to reading state->n_* */ clear_bit(NFS_DELEGATED_STATE, &state->flags); smp_rmb(); if (state->n_rdwr != 0) { ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &newstate); if (ret != 0) return ret; if (newstate != state) return -ESTALE; } if (state->n_wronly != 0) { ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &newstate); if (ret != 0) return ret; if (newstate != state) return -ESTALE; } if (state->n_rdonly != 0) { ret = nfs4_open_recover_helper(opendata, FMODE_READ, &newstate); if (ret != 0) return ret; if (newstate != state) return -ESTALE; } /* * We may have performed cached opens for all three recoveries. * Check if we need to update the current stateid. */ if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0 && memcmp(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data)) != 0) { write_seqlock(&state->seqlock); if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) memcpy(state->stateid.data, state->open_stateid.data, sizeof(state->stateid.data)); write_sequnlock(&state->seqlock); } return 0;}/* * OPEN_RECLAIM: * reclaim state on the server after a reboot. */static int _nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state *state){ struct nfs_delegation *delegation; struct nfs4_opendata *opendata; int delegation_type = 0; int status; opendata = nfs4_open_recoverdata_alloc(ctx, state); if (IS_ERR(opendata)) return PTR_ERR(opendata); opendata->o_arg.claim = NFS4_OPEN_CLAIM_PREVIOUS; opendata->o_arg.fh = NFS_FH(state->inode); rcu_read_lock(); delegation = rcu_dereference(NFS_I(state->inode)->delegation); if (delegation != NULL && (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) != 0) delegation_type = delegation->type; rcu_read_unlock(); opendata->o_arg.u.delegation_type = delegation_type; status = nfs4_open_recover(opendata, state); nfs4_opendata_put(opendata); return status;}static int nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state *state){ struct nfs_server *server = NFS_SERVER(state->inode); struct nfs4_exception exception = { }; int err; do { err = _nfs4_do_open_reclaim(ctx, state); if (err != -NFS4ERR_DELAY) break; nfs4_handle_exception(server, err, &exception); } while (exception.retry); return err;}static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state){ struct nfs_open_context *ctx; int ret; ctx = nfs4_state_find_open_context(state); if (IS_ERR(ctx)) return PTR_ERR(ctx); ret = nfs4_do_open_reclaim(ctx, state); put_nfs_open_context(ctx); return ret;}static int _nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid){ struct nfs4_opendata *opendata; int ret; opendata = nfs4_open_recoverdata_alloc(ctx, state); if (IS_ERR(opendata)) return PTR_ERR(opendata); opendata->o_arg.claim = NFS4_OPEN_CLAIM_DELEGATE_CUR; memcpy(opendata->o_arg.u.delegation.data, stateid->data, sizeof(opendata->o_arg.u.delegation.data)); ret = nfs4_open_recover(opendata, state); nfs4_opendata_put(opendata); return ret;}int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid){ struct nfs4_exception exception = { }; struct nfs_server *server = NFS_SERVER(state->inode); int err; do { err = _nfs4_open_delegation_recall(ctx, state, stateid); switch (err) { case 0: return err; case -NFS4ERR_STALE_CLIENTID: case -NFS4ERR_STALE_STATEID: case -NFS4ERR_EXPIRED: /* Don't recall a delegation if it was lost */ nfs4_schedule_state_recovery(server->nfs_client); return err; } err = nfs4_handle_exception(server, err, &exception); } while (exception.retry); return err;}static void nfs4_open_confirm_prepare(struct rpc_task *task, void *calldata){ struct nfs4_opendata *data = calldata; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_CONFIRM], .rpc_argp = &data->c_arg, .rpc_resp = &data->c_res, .rpc_cred = data->owner->so_cred, }; data->timestamp = jiffies; rpc_call_setup(task, &msg, 0);}static void nfs4_open_confirm_done(struct rpc_task *task, void *calldata){ struct nfs4_opendata *data = calldata; data->rpc_status = task->tk_status; if (RPC_ASSASSINATED(task)) return; if (data->rpc_status == 0) { memcpy(data->o_res.stateid.data, data->c_res.stateid.data, sizeof(data->o_res.stateid.data)); nfs_confirm_seqid(&data->owner->so_seqid, 0); renew_lease(data->o_res.server, data->timestamp); data->rpc_done = 1; } nfs_increment_open_seqid(data->rpc_status, data->c_arg.seqid);}static void nfs4_open_confirm_release(void *calldata){ struct nfs4_opendata *data = calldata; struct nfs4_state *state = NULL; /* If this request hasn't been cancelled, do nothing */ if (data->cancelled == 0) goto out_free; /* In case of error, no cleanup! */ if (!data->rpc_done) goto out_free; state = nfs4_opendata_to_nfs4_state(data); if (!IS_ERR(state)) nfs4_close_state(&data->path, state, data->o_arg.open_flags);out_free: nfs4_opendata_put(data);}static const struct rpc_call_ops nfs4_open_confirm_ops = { .rpc_call_prepare = nfs4_open_confirm_prepare, .rpc_call_done = nfs4_open_confirm_done, .rpc_release = nfs4_open_confirm_release,};/* * Note: On error, nfs4_proc_open_confirm will free the struct nfs4_opendata */static int _nfs4_proc_open_confirm(struct nfs4_opendata *data){ struct nfs_server *server = NFS_SERVER(data->dir->d_inode); struct rpc_task *task; int status; kref_get(&data->kref); data->rpc_done = 0; data->rpc_status = 0; task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_confirm_ops, data); if (IS_ERR(task)) return PTR_ERR(task); status = nfs4_wait_for_completion_rpc_task(task); if (status != 0) { data->cancelled = 1; smp_wmb(); } else status = data->rpc_status; rpc_put_task(task); return status;}static void nfs4_open_prepare(struct rpc_task *task, void *calldata){ struct nfs4_opendata *data = calldata; struct nfs4_state_owner *sp = data->owner; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN], .rpc_argp = &data->o_arg, .rpc_resp = &data->o_res, .rpc_cred = sp->so_cred, }; if (nfs_wait_on_sequence(data->o_arg.seqid, task) != 0) return; /* * Check if we still need to send an OPEN call, or if we can use * a delegation instead. */ if (data->state != NULL) { struct nfs_delegation *delegation; if (can_open_cached(data->state, data->o_arg.open_flags & (FMODE_READ|FMODE_WRITE|O_EXCL))) goto out_no_action; rcu_read_lock(); delegation = rcu_dereference(NFS_I(data->state->inode)->delegation); if (delegation != NULL && (delegation->flags & NFS_DELEGATION_NEED_RECLAIM) == 0) { rcu_read_unlock(); goto out_no_action; } rcu_read_unlock(); } /* Update sequence id. */ data->o_arg.id = sp->so_owner_id.id; data->o_arg.clientid = sp->so_client->cl_clientid; if (data->o_arg.claim == NFS4_OPEN_CLAIM_PREVIOUS) { msg.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_NOATTR]; nfs_copy_fh(&data->o_res.fh, data->o_arg.fh); } data->timestamp = jiffies; rpc_call_setup(task, &msg, 0); return;out_no_action: task->tk_action = NULL;}static void nfs4_open_done(struct rpc_task *task, void *calldata){ struct nfs4_opendata *data = calldata; data->rpc_status = task->tk_status; if (RPC_ASSASSINATED(task)) return; if (task->tk_status == 0) { switch (data->o_res.f_attr->mode & S_IFMT) { case S_IFREG: break; case S_IFLNK: data->rpc_status = -ELOOP; break; case S_IFDIR: data->rpc_status = -EISDIR; break; default: data->rpc_status = -ENOTDIR; } renew_lease(data->o_res.server, data->timestamp); if (!(data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM)) nfs_confirm_seqid(&data->owner->so_seqid, 0); } nfs_increment_open_seqid(data->rpc_status, data->o_arg.seqid); data->rpc_done = 1;}static void nfs4_open_release(void *calldata){ struct nfs4_opendata *data = calldata; struct nfs4_state *state = NULL; /* If this request hasn't been cancelled, do nothing */ if (data->cancelled == 0) goto out_free; /* In case of error, no cleanup! */ if (data->rpc_status != 0 || !data->rpc_done) goto out_free; /* In case we need an open_confirm, no cleanup! */ if (data->o_res.rflags & NFS4_OPEN_RESULT_CONFIRM) goto out_free; state = nfs4_opendata_to_nfs4_state(data); if (!IS_ERR(state)) nfs4_close_state(&data->path, state, data->o_arg.open_flags);out_free: nfs4_opendata_put(data);}static const struct rpc_call_ops nfs4_open_ops = { .rpc_call_prepare = nfs4_open_prepare, .rpc_call_done = nfs4_open_done, .rpc_release = nfs4_open_release,};/* * Note: On error, nfs4_proc_open will free the struct nfs4_opendata */static int _nfs4_proc_open(struct nfs4_opendata *data){ struct inode *dir = data->dir->d_inode; struct nfs_server *server = NFS_SERVER(dir); struct nfs_openargs *o_arg = &data->o_arg; struct nfs_openres *o_res = &data->o_res; struct rpc_task *task; int status; kref_get(&data->kref); data->rpc_done = 0; data->rpc_status = 0; data->cancelled = 0; task = rpc_run_task(server->client, RPC_TASK_ASYNC, &nfs4_open_ops, data); if (IS_ERR(task)) return PTR_ERR(task); status = nfs4_wait_for_completion_rpc_task(task); if (status != 0) { data->cancelled = 1; smp_wmb(); } else status = data->rpc_status; rpc_put_task(task); if (status != 0 || !data->rpc_done) return status; if (o_res->fh.size == 0) _nfs4_proc_lookup(dir, o_arg->name, &o_res->fh, o_res->f_attr); if (o_arg->open_flags & O_CREAT) { update_changeattr(dir, &o_res->cinfo);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -