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

📄 nfs4state.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	fp = kmem_cache_alloc(file_slab, GFP_KERNEL);	if (fp) {		kref_init(&fp->fi_ref);		INIT_LIST_HEAD(&fp->fi_hash);		INIT_LIST_HEAD(&fp->fi_stateids);		INIT_LIST_HEAD(&fp->fi_delegations);		list_add(&fp->fi_hash, &file_hashtbl[hashval]);		fp->fi_inode = igrab(ino);		fp->fi_id = current_fileid++;		fp->fi_had_conflict = false;		return fp;	}	return NULL;}static voidnfsd4_free_slab(struct kmem_cache **slab){	if (*slab == NULL)		return;	kmem_cache_destroy(*slab);	*slab = NULL;}voidnfsd4_free_slabs(void){	nfsd4_free_slab(&stateowner_slab);	nfsd4_free_slab(&file_slab);	nfsd4_free_slab(&stateid_slab);	nfsd4_free_slab(&deleg_slab);}static intnfsd4_init_slabs(void){	stateowner_slab = kmem_cache_create("nfsd4_stateowners",			sizeof(struct nfs4_stateowner), 0, 0, NULL);	if (stateowner_slab == NULL)		goto out_nomem;	file_slab = kmem_cache_create("nfsd4_files",			sizeof(struct nfs4_file), 0, 0, NULL);	if (file_slab == NULL)		goto out_nomem;	stateid_slab = kmem_cache_create("nfsd4_stateids",			sizeof(struct nfs4_stateid), 0, 0, NULL);	if (stateid_slab == NULL)		goto out_nomem;	deleg_slab = kmem_cache_create("nfsd4_delegations",			sizeof(struct nfs4_delegation), 0, 0, NULL);	if (deleg_slab == NULL)		goto out_nomem;	return 0;out_nomem:	nfsd4_free_slabs();	dprintk("nfsd4: out of memory while initializing nfsv4\n");	return -ENOMEM;}voidnfs4_free_stateowner(struct kref *kref){	struct nfs4_stateowner *sop =		container_of(kref, struct nfs4_stateowner, so_ref);	kfree(sop->so_owner.data);	kmem_cache_free(stateowner_slab, sop);}static inline struct nfs4_stateowner *alloc_stateowner(struct xdr_netobj *owner){	struct nfs4_stateowner *sop;	if ((sop = kmem_cache_alloc(stateowner_slab, GFP_KERNEL))) {		if ((sop->so_owner.data = kmalloc(owner->len, GFP_KERNEL))) {			memcpy(sop->so_owner.data, owner->data, owner->len);			sop->so_owner.len = owner->len;			kref_init(&sop->so_ref);			return sop;		} 		kmem_cache_free(stateowner_slab, sop);	}	return NULL;}static struct nfs4_stateowner *alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfsd4_open *open) {	struct nfs4_stateowner *sop;	struct nfs4_replay *rp;	unsigned int idhashval;	if (!(sop = alloc_stateowner(&open->op_owner)))		return NULL;	idhashval = ownerid_hashval(current_ownerid);	INIT_LIST_HEAD(&sop->so_idhash);	INIT_LIST_HEAD(&sop->so_strhash);	INIT_LIST_HEAD(&sop->so_perclient);	INIT_LIST_HEAD(&sop->so_stateids);	INIT_LIST_HEAD(&sop->so_perstateid);  /* not used */	INIT_LIST_HEAD(&sop->so_close_lru);	sop->so_time = 0;	list_add(&sop->so_idhash, &ownerid_hashtbl[idhashval]);	list_add(&sop->so_strhash, &ownerstr_hashtbl[strhashval]);	list_add(&sop->so_perclient, &clp->cl_openowners);	sop->so_is_open_owner = 1;	sop->so_id = current_ownerid++;	sop->so_client = clp;	sop->so_seqid = open->op_seqid;	sop->so_confirmed = 0;	rp = &sop->so_replay;	rp->rp_status = nfserr_serverfault;	rp->rp_buflen = 0;	rp->rp_buf = rp->rp_ibuf;	return sop;}static voidrelease_stateid_lockowners(struct nfs4_stateid *open_stp){	struct nfs4_stateowner *lock_sop;	while (!list_empty(&open_stp->st_lockowners)) {		lock_sop = list_entry(open_stp->st_lockowners.next,				struct nfs4_stateowner, so_perstateid);		/* list_del(&open_stp->st_lockowners);  */		BUG_ON(lock_sop->so_is_open_owner);		release_stateowner(lock_sop);	}}static voidunhash_stateowner(struct nfs4_stateowner *sop){	struct nfs4_stateid *stp;	list_del(&sop->so_idhash);	list_del(&sop->so_strhash);	if (sop->so_is_open_owner)		list_del(&sop->so_perclient);	list_del(&sop->so_perstateid);	while (!list_empty(&sop->so_stateids)) {		stp = list_entry(sop->so_stateids.next,			struct nfs4_stateid, st_perstateowner);		if (sop->so_is_open_owner)			release_stateid(stp, OPEN_STATE);		else			release_stateid(stp, LOCK_STATE);	}}static voidrelease_stateowner(struct nfs4_stateowner *sop){	unhash_stateowner(sop);	list_del(&sop->so_close_lru);	nfs4_put_stateowner(sop);}static inline voidinit_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) {	struct nfs4_stateowner *sop = open->op_stateowner;	unsigned int hashval = stateid_hashval(sop->so_id, fp->fi_id);	INIT_LIST_HEAD(&stp->st_hash);	INIT_LIST_HEAD(&stp->st_perstateowner);	INIT_LIST_HEAD(&stp->st_lockowners);	INIT_LIST_HEAD(&stp->st_perfile);	list_add(&stp->st_hash, &stateid_hashtbl[hashval]);	list_add(&stp->st_perstateowner, &sop->so_stateids);	list_add(&stp->st_perfile, &fp->fi_stateids);	stp->st_stateowner = sop;	get_nfs4_file(fp);	stp->st_file = fp;	stp->st_stateid.si_boot = boot_time;	stp->st_stateid.si_stateownerid = sop->so_id;	stp->st_stateid.si_fileid = fp->fi_id;	stp->st_stateid.si_generation = 0;	stp->st_access_bmap = 0;	stp->st_deny_bmap = 0;	__set_bit(open->op_share_access, &stp->st_access_bmap);	__set_bit(open->op_share_deny, &stp->st_deny_bmap);	stp->st_openstp = NULL;}static voidrelease_stateid(struct nfs4_stateid *stp, int flags){	struct file *filp = stp->st_vfs_file;	list_del(&stp->st_hash);	list_del(&stp->st_perfile);	list_del(&stp->st_perstateowner);	if (flags & OPEN_STATE) {		release_stateid_lockowners(stp);		stp->st_vfs_file = NULL;		nfsd_close(filp);	} else if (flags & LOCK_STATE)		locks_remove_posix(filp, (fl_owner_t) stp->st_stateowner);	put_nfs4_file(stp->st_file);	kmem_cache_free(stateid_slab, stp);}static voidmove_to_close_lru(struct nfs4_stateowner *sop){	dprintk("NFSD: move_to_close_lru nfs4_stateowner %p\n", sop);	list_move_tail(&sop->so_close_lru, &close_lru);	sop->so_time = get_seconds();}static intsame_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner,							clientid_t *clid){	return (sop->so_owner.len == owner->len) &&		0 == memcmp(sop->so_owner.data, owner->data, owner->len) &&		(sop->so_client->cl_clientid.cl_id == clid->cl_id);}static struct nfs4_stateowner *find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open){	struct nfs4_stateowner *so = NULL;	list_for_each_entry(so, &ownerstr_hashtbl[hashval], so_strhash) {		if (same_owner_str(so, &open->op_owner, &open->op_clientid))			return so;	}	return NULL;}/* search file_hashtbl[] for file */static struct nfs4_file *find_file(struct inode *ino){	unsigned int hashval = file_hashval(ino);	struct nfs4_file *fp;	list_for_each_entry(fp, &file_hashtbl[hashval], fi_hash) {		if (fp->fi_inode == ino) {			get_nfs4_file(fp);			return fp;		}	}	return NULL;}static int access_valid(u32 x){	return (x > 0 && x < 4);}static int deny_valid(u32 x){	return (x >= 0 && x < 5);}static voidset_access(unsigned int *access, unsigned long bmap) {	int i;	*access = 0;	for (i = 1; i < 4; i++) {		if (test_bit(i, &bmap))			*access |= i;	}}static voidset_deny(unsigned int *deny, unsigned long bmap) {	int i;	*deny = 0;	for (i = 0; i < 4; i++) {		if (test_bit(i, &bmap))			*deny |= i ;	}}static inttest_share(struct nfs4_stateid *stp, struct nfsd4_open *open) {	unsigned int access, deny;	set_access(&access, stp->st_access_bmap);	set_deny(&deny, stp->st_deny_bmap);	if ((access & open->op_share_deny) || (deny & open->op_share_access))		return 0;	return 1;}/* * Called to check deny when READ with all zero stateid or * WRITE with all zero or all one stateid */static __be32nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type){	struct inode *ino = current_fh->fh_dentry->d_inode;	struct nfs4_file *fp;	struct nfs4_stateid *stp;	__be32 ret;	dprintk("NFSD: nfs4_share_conflict\n");	fp = find_file(ino);	if (!fp)		return nfs_ok;	ret = nfserr_locked;	/* Search for conflicting share reservations */	list_for_each_entry(stp, &fp->fi_stateids, st_perfile) {		if (test_bit(deny_type, &stp->st_deny_bmap) ||		    test_bit(NFS4_SHARE_DENY_BOTH, &stp->st_deny_bmap))			goto out;	}	ret = nfs_ok;out:	put_nfs4_file(fp);	return ret;}static inline voidnfs4_file_downgrade(struct file *filp, unsigned int share_access){	if (share_access & NFS4_SHARE_ACCESS_WRITE) {		put_write_access(filp->f_path.dentry->d_inode);		filp->f_mode = (filp->f_mode | FMODE_READ) & ~FMODE_WRITE;	}}/* * Recall a delegation */static intdo_recall(void *__dp){	struct nfs4_delegation *dp = __dp;	dp->dl_file->fi_had_conflict = true;	nfsd4_cb_recall(dp);	return 0;}/* * Spawn a thread to perform a recall on the delegation represented * by the lease (file_lock) * * Called from break_lease() with lock_kernel() held. * Note: we assume break_lease will only call this *once* for any given * lease. */staticvoid nfsd_break_deleg_cb(struct file_lock *fl){	struct nfs4_delegation *dp=  (struct nfs4_delegation *)fl->fl_owner;	struct task_struct *t;	dprintk("NFSD nfsd_break_deleg_cb: dp %p fl %p\n",dp,fl);	if (!dp)		return;	/* We're assuming the state code never drops its reference	 * without first removing the lease.  Since we're in this lease	 * callback (and since the lease code is serialized by the kernel	 * lock) we know the server hasn't removed the lease yet, we know	 * it's safe to take a reference: */	atomic_inc(&dp->dl_count);	atomic_inc(&dp->dl_client->cl_count);	spin_lock(&recall_lock);	list_add_tail(&dp->dl_recall_lru, &del_recall_lru);	spin_unlock(&recall_lock);	/* only place dl_time is set. protected by lock_kernel*/	dp->dl_time = get_seconds();	/*	 * We don't want the locks code to timeout the lease for us;	 * we'll remove it ourself if the delegation isn't returned	 * in time.	 */	fl->fl_break_time = 0;	t = kthread_run(do_recall, dp, "%s", "nfs4_cb_recall");	if (IS_ERR(t)) {		struct nfs4_client *clp = dp->dl_client;		printk(KERN_INFO "NFSD: Callback thread failed for "			"for client (clientid %08x/%08x)\n",			clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);		put_nfs4_client(dp->dl_client);		nfs4_put_delegation(dp);	}}/* * The file_lock is being reapd. * * Called by locks_free_lock() with lock_kernel() held. */staticvoid nfsd_release_deleg_cb(struct file_lock *fl){	struct nfs4_delegation *dp = (struct nfs4_delegation *)fl->fl_owner;	dprintk("NFSD nfsd_release_deleg_cb: fl %p dp %p dl_count %d\n", fl,dp, atomic_read(&dp->dl_count));	if (!(fl->fl_flags & FL_LEASE) || !dp)		return;	dp->dl_flock = NULL;}/* * Set the delegation file_lock back pointer. * * Called from setlease() with lock_kernel() held. */staticvoid nfsd_copy_lock_deleg_cb(struct file_lock *new, struct file_lock *fl){	struct nfs4_delegation *dp = (struct nfs4_delegation *)new->fl_owner;	dprintk("NFSD: nfsd_copy_lock_deleg_cb: new fl %p dp %p\n", new, dp);	if (!dp)		return;	dp->dl_flock = new;}/* * Called from setlease() with lock_kernel() held */staticint nfsd_same_client_deleg_cb(struct file_lock *onlist, struct file_lock *try){	struct nfs4_delegation *onlistd =		(struct nfs4_delegation *)onlist->fl_owner;	struct nfs4_delegation *tryd =		(struct nfs4_delegation *)try->fl_owner;	if (onlist->fl_lmops != try->fl_lmops)		return 0;	return onlistd->dl_client == tryd->dl_client;}staticint nfsd_change_deleg_cb(struct file_lock **onlist, int arg){	if (arg & F_UNLCK)		return lease_modify(onlist, arg);	else		return -EAGAIN;}static struct lock_manager_operations nfsd_lease_mng_ops = {	.fl_break = nfsd_break_deleg_cb,	.fl_release_private = nfsd_release_deleg_cb,	.fl_copy_lock = nfsd_copy_lock_deleg_cb,	.fl_mylease = nfsd_same_client_deleg_cb,	.fl_change = nfsd_change_deleg_cb,};__be32nfsd4_process_open1(struct nfsd4_open *open){	clientid_t *clientid = &open->op_clientid;	struct nfs4_client *clp = NULL;	unsigned int strhashval;	struct nfs4_stateowner *sop = NULL;	if (!check_name(open->op_owner))		return nfserr_inval;	if (STALE_CLIENTID(&open->op_clientid))		return nfserr_stale_clientid;	strhashval = ownerstr_hashval(clientid->cl_id, open->op_owner);	sop = find_openstateowner_str(strhashval, open);	open->op_stateowner = sop;	if (!sop) {		/* Make sure the client's lease hasn't expired. */		clp = find_confirmed_client(clientid);		if (clp == NULL)			return nfserr_expired;		goto renew;	}	if (!sop->so_confirmed) {		/* Replace unconfirmed owners without checking for replay. */

⌨️ 快捷键说明

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