⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nfs4state.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  fs/nfs/nfs4state.c * *  Client-side XDR for NFSv4. * *  Copyright (c) 2002 The Regents of the University of Michigan. *  All rights reserved. * *  Kendrick Smith <kmsmith@umich.edu> * *  Redistribution and use in source and binary forms, with or without *  modification, are permitted provided that the following conditions *  are met: * *  1. Redistributions of source code must retain the above copyright *     notice, this list of conditions and the following disclaimer. *  2. Redistributions in binary form must reproduce the above copyright *     notice, this list of conditions and the following disclaimer in the *     documentation and/or other materials provided with the distribution. *  3. Neither the name of the University nor the names of its *     contributors may be used to endorse or promote products derived *     from this software without specific prior written permission. * *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Implementation of the NFSv4 state model.  For the time being, * this is minimal, but will be made much more complex in a * subsequent patch. */#include <linux/kernel.h>#include <linux/slab.h>#include <linux/smp_lock.h>#include <linux/nfs_fs.h>#include <linux/nfs_idmap.h>#include <linux/kthread.h>#include <linux/module.h>#include <linux/random.h>#include <linux/workqueue.h>#include <linux/bitops.h>#include "nfs4_fs.h"#include "callback.h"#include "delegation.h"#include "internal.h"#define OPENOWNER_POOL_SIZE	8const nfs4_stateid zero_stateid;static LIST_HEAD(nfs4_clientid_list);static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred){	int status = nfs4_proc_setclientid(clp, NFS4_CALLBACK,			nfs_callback_tcpport, cred);	if (status == 0)		status = nfs4_proc_setclientid_confirm(clp, cred);	if (status == 0)		nfs4_schedule_state_renewal(clp);	return status;}struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp){	struct nfs4_state_owner *sp;	struct rb_node *pos;	struct rpc_cred *cred = NULL;	for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) {		sp = rb_entry(pos, struct nfs4_state_owner, so_client_node);		if (list_empty(&sp->so_states))			continue;		cred = get_rpccred(sp->so_cred);		break;	}	return cred;}static struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp){	struct nfs4_state_owner *sp;	struct rb_node *pos;	pos = rb_first(&clp->cl_state_owners);	if (pos != NULL) {		sp = rb_entry(pos, struct nfs4_state_owner, so_client_node);		return get_rpccred(sp->so_cred);	}	return NULL;}static void nfs_alloc_unique_id(struct rb_root *root, struct nfs_unique_id *new,		__u64 minval, int maxbits){	struct rb_node **p, *parent;	struct nfs_unique_id *pos;	__u64 mask = ~0ULL;	if (maxbits < 64)		mask = (1ULL << maxbits) - 1ULL;	/* Ensure distribution is more or less flat */	get_random_bytes(&new->id, sizeof(new->id));	new->id &= mask;	if (new->id < minval)		new->id += minval;retry:	p = &root->rb_node;	parent = NULL;	while (*p != NULL) {		parent = *p;		pos = rb_entry(parent, struct nfs_unique_id, rb_node);		if (new->id < pos->id)			p = &(*p)->rb_left;		else if (new->id > pos->id)			p = &(*p)->rb_right;		else			goto id_exists;	}	rb_link_node(&new->rb_node, parent, p);	rb_insert_color(&new->rb_node, root);	return;id_exists:	for (;;) {		new->id++;		if (new->id < minval || (new->id & mask) != new->id) {			new->id = minval;			break;		}		parent = rb_next(parent);		if (parent == NULL)			break;		pos = rb_entry(parent, struct nfs_unique_id, rb_node);		if (new->id < pos->id)			break;	}	goto retry;}static void nfs_free_unique_id(struct rb_root *root, struct nfs_unique_id *id){	rb_erase(&id->rb_node, root);}static struct nfs4_state_owner *nfs4_find_state_owner(struct nfs_server *server, struct rpc_cred *cred){	struct nfs_client *clp = server->nfs_client;	struct rb_node **p = &clp->cl_state_owners.rb_node,		       *parent = NULL;	struct nfs4_state_owner *sp, *res = NULL;	while (*p != NULL) {		parent = *p;		sp = rb_entry(parent, struct nfs4_state_owner, so_client_node);		if (server < sp->so_server) {			p = &parent->rb_left;			continue;		}		if (server > sp->so_server) {			p = &parent->rb_right;			continue;		}		if (cred < sp->so_cred)			p = &parent->rb_left;		else if (cred > sp->so_cred)			p = &parent->rb_right;		else {			atomic_inc(&sp->so_count);			res = sp;			break;		}	}	return res;}static struct nfs4_state_owner *nfs4_insert_state_owner(struct nfs_client *clp, struct nfs4_state_owner *new){	struct rb_node **p = &clp->cl_state_owners.rb_node,		       *parent = NULL;	struct nfs4_state_owner *sp;	while (*p != NULL) {		parent = *p;		sp = rb_entry(parent, struct nfs4_state_owner, so_client_node);		if (new->so_server < sp->so_server) {			p = &parent->rb_left;			continue;		}		if (new->so_server > sp->so_server) {			p = &parent->rb_right;			continue;		}		if (new->so_cred < sp->so_cred)			p = &parent->rb_left;		else if (new->so_cred > sp->so_cred)			p = &parent->rb_right;		else {			atomic_inc(&sp->so_count);			return sp;		}	}	nfs_alloc_unique_id(&clp->cl_openowner_id, &new->so_owner_id, 1, 64);	rb_link_node(&new->so_client_node, parent, p);	rb_insert_color(&new->so_client_node, &clp->cl_state_owners);	return new;}static voidnfs4_remove_state_owner(struct nfs_client *clp, struct nfs4_state_owner *sp){	if (!RB_EMPTY_NODE(&sp->so_client_node))		rb_erase(&sp->so_client_node, &clp->cl_state_owners);	nfs_free_unique_id(&clp->cl_openowner_id, &sp->so_owner_id);}/* * nfs4_alloc_state_owner(): this is called on the OPEN or CREATE path to * create a new state_owner. * */static struct nfs4_state_owner *nfs4_alloc_state_owner(void){	struct nfs4_state_owner *sp;	sp = kzalloc(sizeof(*sp),GFP_KERNEL);	if (!sp)		return NULL;	spin_lock_init(&sp->so_lock);	INIT_LIST_HEAD(&sp->so_states);	INIT_LIST_HEAD(&sp->so_delegations);	rpc_init_wait_queue(&sp->so_sequence.wait, "Seqid_waitqueue");	sp->so_seqid.sequence = &sp->so_sequence;	spin_lock_init(&sp->so_sequence.lock);	INIT_LIST_HEAD(&sp->so_sequence.list);	atomic_set(&sp->so_count, 1);	return sp;}voidnfs4_drop_state_owner(struct nfs4_state_owner *sp){	if (!RB_EMPTY_NODE(&sp->so_client_node)) {		struct nfs_client *clp = sp->so_client;		spin_lock(&clp->cl_lock);		rb_erase(&sp->so_client_node, &clp->cl_state_owners);		RB_CLEAR_NODE(&sp->so_client_node);		spin_unlock(&clp->cl_lock);	}}/* * Note: must be called with clp->cl_sem held in order to prevent races *       with reboot recovery! */struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct rpc_cred *cred){	struct nfs_client *clp = server->nfs_client;	struct nfs4_state_owner *sp, *new;	spin_lock(&clp->cl_lock);	sp = nfs4_find_state_owner(server, cred);	spin_unlock(&clp->cl_lock);	if (sp != NULL)		return sp;	new = nfs4_alloc_state_owner();	if (new == NULL)		return NULL;	new->so_client = clp;	new->so_server = server;	new->so_cred = cred;	spin_lock(&clp->cl_lock);	sp = nfs4_insert_state_owner(clp, new);	spin_unlock(&clp->cl_lock);	if (sp == new)		get_rpccred(cred);	else		kfree(new);	return sp;}/* * Must be called with clp->cl_sem held in order to avoid races * with state recovery... */void nfs4_put_state_owner(struct nfs4_state_owner *sp){	struct nfs_client *clp = sp->so_client;	struct rpc_cred *cred = sp->so_cred;	if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock))		return;	nfs4_remove_state_owner(clp, sp);	spin_unlock(&clp->cl_lock);	put_rpccred(cred);	kfree(sp);}static struct nfs4_state *nfs4_alloc_open_state(void){	struct nfs4_state *state;	state = kzalloc(sizeof(*state), GFP_KERNEL);	if (!state)		return NULL;	atomic_set(&state->count, 1);	INIT_LIST_HEAD(&state->lock_states);	spin_lock_init(&state->state_lock);	seqlock_init(&state->seqlock);	return state;}voidnfs4_state_set_mode_locked(struct nfs4_state *state, mode_t mode){	if (state->state == mode)		return;	/* NB! List reordering - see the reclaim code for why.  */	if ((mode & FMODE_WRITE) != (state->state & FMODE_WRITE)) {		if (mode & FMODE_WRITE)			list_move(&state->open_states, &state->owner->so_states);		else			list_move_tail(&state->open_states, &state->owner->so_states);	}	state->state = mode;}static struct nfs4_state *__nfs4_find_state_byowner(struct inode *inode, struct nfs4_state_owner *owner){	struct nfs_inode *nfsi = NFS_I(inode);	struct nfs4_state *state;	list_for_each_entry(state, &nfsi->open_states, inode_states) {		if (state->owner != owner)			continue;		if (atomic_inc_not_zero(&state->count))			return state;	}	return NULL;}static voidnfs4_free_open_state(struct nfs4_state *state){	kfree(state);}struct nfs4_state *nfs4_get_open_state(struct inode *inode, struct nfs4_state_owner *owner){	struct nfs4_state *state, *new;	struct nfs_inode *nfsi = NFS_I(inode);	spin_lock(&inode->i_lock);	state = __nfs4_find_state_byowner(inode, owner);	spin_unlock(&inode->i_lock);	if (state)		goto out;	new = nfs4_alloc_open_state();	spin_lock(&owner->so_lock);	spin_lock(&inode->i_lock);	state = __nfs4_find_state_byowner(inode, owner);	if (state == NULL && new != NULL) {		state = new;		state->owner = owner;		atomic_inc(&owner->so_count);		list_add(&state->inode_states, &nfsi->open_states);		state->inode = igrab(inode);		spin_unlock(&inode->i_lock);		/* Note: The reclaim code dictates that we add stateless		 * and read-only stateids to the end of the list */		list_add_tail(&state->open_states, &owner->so_states);		spin_unlock(&owner->so_lock);	} else {		spin_unlock(&inode->i_lock);		spin_unlock(&owner->so_lock);		if (new)			nfs4_free_open_state(new);	}out:	return state;}/* * Beware! Caller must be holding exactly one * reference to clp->cl_sem! */void nfs4_put_open_state(struct nfs4_state *state){	struct inode *inode = state->inode;	struct nfs4_state_owner *owner = state->owner;	if (!atomic_dec_and_lock(&state->count, &owner->so_lock))		return;	spin_lock(&inode->i_lock);	list_del(&state->inode_states);	list_del(&state->open_states);	spin_unlock(&inode->i_lock);	spin_unlock(&owner->so_lock);	iput(inode);	nfs4_free_open_state(state);	nfs4_put_state_owner(owner);}/* * Close the current file. */static void __nfs4_close(struct path *path, struct nfs4_state *state, mode_t mode, int wait){	struct nfs4_state_owner *owner = state->owner;	int call_close = 0;	int newstate;	atomic_inc(&owner->so_count);	/* Protect against nfs4_find_state() */	spin_lock(&owner->so_lock);	switch (mode & (FMODE_READ | FMODE_WRITE)) {		case FMODE_READ:			state->n_rdonly--;			break;		case FMODE_WRITE:			state->n_wronly--;			break;		case FMODE_READ|FMODE_WRITE:			state->n_rdwr--;	}	newstate = FMODE_READ|FMODE_WRITE;	if (state->n_rdwr == 0) {		if (state->n_rdonly == 0) {			newstate &= ~FMODE_READ;			call_close |= test_bit(NFS_O_RDONLY_STATE, &state->flags);			call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags);		}		if (state->n_wronly == 0) {			newstate &= ~FMODE_WRITE;			call_close |= test_bit(NFS_O_WRONLY_STATE, &state->flags);			call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags);		}		if (newstate == 0)			clear_bit(NFS_DELEGATED_STATE, &state->flags);	}	nfs4_state_set_mode_locked(state, newstate);	spin_unlock(&owner->so_lock);	if (!call_close) {		nfs4_put_open_state(state);		nfs4_put_state_owner(owner);	} else		nfs4_do_close(path, state, wait);}void nfs4_close_state(struct path *path, struct nfs4_state *state, mode_t mode){	__nfs4_close(path, state, mode, 0);}void nfs4_close_sync(struct path *path, struct nfs4_state *state, mode_t mode){	__nfs4_close(path, state, mode, 1);}/* * Search the state->lock_states for an existing lock_owner * that is compatible with current->files */static struct nfs4_lock_state *__nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner){	struct nfs4_lock_state *pos;	list_for_each_entry(pos, &state->lock_states, ls_locks) {		if (pos->ls_owner != fl_owner)			continue;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -