📄 nfs4proc.c
字号:
}; struct nfs_openargs o_arg = { .fh = NFS_FH(dir), .open_flags = flags, .name = name, .server = server, .bitmask = server->attr_bitmask, .claim = NFS4_OPEN_CLAIM_NULL, }; struct nfs_openres o_res = { .f_attr = &f_attr, .server = server, }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN], .rpc_argp = &o_arg, .rpc_resp = &o_res, .rpc_cred = cred, }; /* Protect against reboot recovery conflicts */ down_read(&clp->cl_sem); status = -ENOMEM; if (!(sp = nfs4_get_state_owner(server, cred))) { dprintk("nfs4_do_open: nfs4_get_state_owner failed!\n"); goto out_err; } if (flags & O_EXCL) { u32 *p = (u32 *) o_arg.u.verifier.data; p[0] = jiffies; p[1] = current->pid; } else o_arg.u.attrs = sattr; /* Serialization for the sequence id */ down(&sp->so_sema); o_arg.seqid = sp->so_seqid; o_arg.id = sp->so_id; o_arg.clientid = clp->cl_clientid, status = rpc_call_sync(server->client, &msg, RPC_TASK_NOINTR); nfs4_increment_seqid(status, sp); if (status) goto out_err; update_changeattr(dir, &o_res.cinfo); if(o_res.rflags & NFS4_OPEN_RESULT_CONFIRM) { status = _nfs4_proc_open_confirm(server->client, &o_res.fh, sp, &o_res.stateid); if (status != 0) goto out_err; } if (!(f_attr.valid & NFS_ATTR_FATTR)) { status = server->rpc_ops->getattr(server, &o_res.fh, &f_attr); if (status < 0) goto out_err; } status = -ENOMEM; inode = nfs_fhget(dir->i_sb, &o_res.fh, &f_attr); if (!inode) goto out_err; state = nfs4_get_open_state(inode, sp); if (!state) goto out_err; memcpy(&state->stateid, &o_res.stateid, sizeof(state->stateid)); spin_lock(&inode->i_lock); if (flags & FMODE_READ) state->nreaders++; if (flags & FMODE_WRITE) state->nwriters++; state->state |= flags & (FMODE_READ|FMODE_WRITE); spin_unlock(&inode->i_lock); if (o_res.delegation_type != 0) nfs_inode_set_delegation(inode, cred, &o_res); up(&sp->so_sema); nfs4_put_state_owner(sp); up_read(&clp->cl_sem); *res = state; return 0;out_err: if (sp != NULL) { if (state != NULL) nfs4_put_open_state(state); up(&sp->so_sema); nfs4_put_state_owner(sp); } /* Note: clp->cl_sem must be released before nfs4_put_open_state()! */ up_read(&clp->cl_sem); if (inode != NULL) iput(inode); *res = NULL; return status;}struct nfs4_state *nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *sattr, struct rpc_cred *cred){ struct nfs4_exception exception = { }; struct nfs4_state *res; int status; do { status = _nfs4_do_open(dir, name, flags, sattr, cred, &res); if (status == 0) break; /* NOTE: BAD_SEQID means the server and client disagree about the * book-keeping w.r.t. state-changing operations * (OPEN/CLOSE/LOCK/LOCKU...) * It is actually a sign of a bug on the client or on the server. * * If we receive a BAD_SEQID error in the particular case of * doing an OPEN, we assume that nfs4_increment_seqid() will * have unhashed the old state_owner for us, and that we can * therefore safely retry using a new one. We should still warn * the user though... */ if (status == -NFS4ERR_BAD_SEQID) { printk(KERN_WARNING "NFS: v4 server returned a bad sequence-id error!\n"); exception.retry = 1; continue; } res = ERR_PTR(nfs4_handle_exception(NFS_SERVER(dir), status, &exception)); } while (exception.retry); return res;}static int _nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, struct nfs_fh *fhandle, struct iattr *sattr, struct nfs4_state *state){ struct nfs_setattrargs arg = { .fh = fhandle, .iap = sattr, .server = server, .bitmask = server->attr_bitmask, }; struct nfs_setattrres res = { .fattr = fattr, .server = server, }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SETATTR], .rpc_argp = &arg, .rpc_resp = &res, }; fattr->valid = 0; if (sattr->ia_valid & ATTR_SIZE) nfs4_copy_stateid(&arg.stateid, state, NULL); else memcpy(&arg.stateid, &zero_stateid, sizeof(arg.stateid)); return rpc_call_sync(server->client, &msg, 0);}int nfs4_do_setattr(struct nfs_server *server, struct nfs_fattr *fattr, struct nfs_fh *fhandle, struct iattr *sattr, struct nfs4_state *state){ struct nfs4_exception exception = { }; int err; do { err = nfs4_handle_exception(server, _nfs4_do_setattr(server, fattr, fhandle, sattr, state), &exception); } while (exception.retry); return err;}/* * It is possible for data to be read/written from a mem-mapped file * after the sys_close call (which hits the vfs layer as a flush). * This means that we can't safely call nfsv4 close on a file until * the inode is cleared. This in turn means that we are not good * NFSv4 citizens - we do not indicate to the server to update the file's * share state even when we are done with one of the three share * stateid's in the inode. * * NOTE: Caller must be holding the sp->so_owner semaphore! */static int _nfs4_do_close(struct inode *inode, struct nfs4_state *state) { struct nfs4_state_owner *sp = state->owner; int status = 0; struct nfs_closeargs arg = { .fh = NFS_FH(inode), }; struct nfs_closeres res; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CLOSE], .rpc_argp = &arg, .rpc_resp = &res, }; if (test_bit(NFS_DELEGATED_STATE, &state->flags)) return 0; memcpy(&arg.stateid, &state->stateid, sizeof(arg.stateid)); /* Serialization for the sequence id */ arg.seqid = sp->so_seqid, status = rpc_call_sync(NFS_SERVER(inode)->client, &msg, RPC_TASK_NOINTR); /* hmm. we are done with the inode, and in the process of freeing * the state_owner. we keep this around to process errors */ nfs4_increment_seqid(status, sp); if (!status) memcpy(&state->stateid, &res.stateid, sizeof(state->stateid)); return status;}int nfs4_do_close(struct inode *inode, struct nfs4_state *state) { struct nfs_server *server = NFS_SERVER(state->inode); struct nfs4_exception exception = { }; int err; do { err = _nfs4_do_close(inode, state); switch (err) { case -NFS4ERR_STALE_STATEID: case -NFS4ERR_EXPIRED: nfs4_schedule_state_recovery(server->nfs4_state); err = 0; default: state->state = 0; } err = nfs4_handle_exception(server, err, &exception); } while (exception.retry); return err;}static int _nfs4_do_downgrade(struct inode *inode, struct nfs4_state *state, mode_t mode) { struct nfs4_state_owner *sp = state->owner; int status = 0; struct nfs_closeargs arg = { .fh = NFS_FH(inode), .seqid = sp->so_seqid, .open_flags = mode, }; struct nfs_closeres res; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_OPEN_DOWNGRADE], .rpc_argp = &arg, .rpc_resp = &res, }; if (test_bit(NFS_DELEGATED_STATE, &state->flags)) return 0; memcpy(&arg.stateid, &state->stateid, sizeof(arg.stateid)); status = rpc_call_sync(NFS_SERVER(inode)->client, &msg, RPC_TASK_NOINTR); nfs4_increment_seqid(status, sp); if (!status) memcpy(&state->stateid, &res.stateid, sizeof(state->stateid)); return status;}int nfs4_do_downgrade(struct inode *inode, struct nfs4_state *state, mode_t mode) { struct nfs_server *server = NFS_SERVER(state->inode); struct nfs4_exception exception = { }; int err; do { err = _nfs4_do_downgrade(inode, state, mode); switch (err) { case -NFS4ERR_STALE_STATEID: case -NFS4ERR_EXPIRED: nfs4_schedule_state_recovery(server->nfs4_state); err = 0; default: state->state = mode; } err = nfs4_handle_exception(server, err, &exception); } while (exception.retry); return err;}struct inode *nfs4_atomic_open(struct inode *dir, struct dentry *dentry, struct nameidata *nd){ struct iattr attr; struct rpc_cred *cred; struct nfs4_state *state; if (nd->flags & LOOKUP_CREATE) { attr.ia_mode = nd->intent.open.create_mode; attr.ia_valid = ATTR_MODE; if (!IS_POSIXACL(dir)) attr.ia_mode &= ~current->fs->umask; } else { attr.ia_valid = 0; BUG_ON(nd->intent.open.flags & O_CREAT); } cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0); state = nfs4_do_open(dir, &dentry->d_name, nd->intent.open.flags, &attr, cred); put_rpccred(cred); if (IS_ERR(state)) return (struct inode *)state; return state->inode;}intnfs4_open_revalidate(struct inode *dir, struct dentry *dentry, int openflags){ struct rpc_cred *cred; struct nfs4_state *state; struct inode *inode; cred = rpcauth_lookupcred(NFS_SERVER(dir)->client->cl_auth, 0); state = nfs4_open_delegated(dentry->d_inode, openflags, cred); if (IS_ERR(state)) state = nfs4_do_open(dir, &dentry->d_name, openflags, NULL, cred); put_rpccred(cred); if (state == ERR_PTR(-ENOENT) && dentry->d_inode == 0) return 1; if (IS_ERR(state)) return 0; inode = state->inode; if (inode == dentry->d_inode) { iput(inode); return 1; } d_drop(dentry); nfs4_close_state(state, openflags); iput(inode); return 0;}static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle){ struct nfs4_server_caps_res res = {}; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SERVER_CAPS], .rpc_argp = fhandle, .rpc_resp = &res, }; int status; status = rpc_call_sync(server->client, &msg, 0); if (status == 0) { memcpy(server->attr_bitmask, res.attr_bitmask, sizeof(server->attr_bitmask)); if (res.attr_bitmask[0] & FATTR4_WORD0_ACL) server->caps |= NFS_CAP_ACLS; if (res.has_links != 0) server->caps |= NFS_CAP_HARDLINKS; if (res.has_symlinks != 0) server->caps |= NFS_CAP_SYMLINKS; server->acl_bitmask = res.acl_bitmask; } return status;}static int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle){ struct nfs4_exception exception = { }; int err; do { err = nfs4_handle_exception(server, _nfs4_server_capabilities(server, fhandle), &exception); } while (exception.retry); return err;}static int _nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *info){ struct nfs_fattr * fattr = info->fattr; struct nfs4_lookup_root_arg args = { .bitmask = nfs4_fattr_bitmap, }; struct nfs4_lookup_res res = { .server = server, .fattr = fattr, .fh = fhandle, }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP_ROOT], .rpc_argp = &args, .rpc_resp = &res, }; fattr->valid = 0; return rpc_call_sync(server->client, &msg, 0);}static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *info){ struct nfs4_exception exception = { }; int err; do { err = nfs4_handle_exception(server, _nfs4_lookup_root(server, fhandle, info), &exception); } while (exception.retry); return err;}static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *info){ struct nfs_fattr * fattr = info->fattr; unsigned char * p; struct qstr q; struct nfs4_lookup_arg args = { .dir_fh = fhandle, .name = &q, .bitmask = nfs4_fattr_bitmap, }; struct nfs4_lookup_res res = { .server = server, .fattr = fattr, .fh = fhandle, }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP], .rpc_argp = &args, .rpc_resp = &res, }; int status; /* * Now we do a separate LOOKUP for each component of the mount path. * The LOOKUPs are done separately so that we can conveniently * catch an ERR_WRONGSEC if it occurs along the way... */ status = nfs4_lookup_root(server, fhandle, info); if (status) goto out; p = server->mnt_path; for (;;) { struct nfs4_exception exception = { }; while (*p == '/') p++; if (!*p) break; q.name = p; while (*p && (*p != '/')) p++; q.len = p - q.name; do { fattr->valid = 0; status = nfs4_handle_exception(server, rpc_call_sync(server->client, &msg, 0), &exception); } while (exception.retry); if (status == 0) continue; if (status == -ENOENT) { printk(KERN_NOTICE "NFS: mount path %s does not exist!\n", server->mnt_path); printk(KERN_NOTICE "NFS: suggestion: try mounting '/' instead.\n"); } break; } if (status == 0) status = nfs4_server_capabilities(server, fhandle); if (status == 0) status = nfs4_do_fsinfo(server, fhandle, info);out: return status;}static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr){ struct nfs4_getattr_arg args = { .fh = fhandle, .bitmask = server->attr_bitmask, }; struct nfs4_getattr_res res = { .fattr = fattr, .server = server, }; struct rpc_message msg = { .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_GETATTR], .rpc_argp = &args, .rpc_resp = &res, }; fattr->valid = 0; return rpc_call_sync(server->client, &msg, 0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -