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

📄 misc.c

📁 Linux内核自带的cifs模块
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *   fs/cifs/misc.c * *   Copyright (C) International Business Machines  Corp., 2002,2007 *   Author(s): Steve French (sfrench@us.ibm.com) * *   This library is free software; you can redistribute it and/or modify *   it under the terms of the GNU Lesser General Public License as published *   by the Free Software Foundation; either version 2.1 of the License, or *   (at your option) any later version. * *   This library is distributed in the hope that it will be useful, *   but WITHOUT ANY WARRANTY; without even the implied warranty of *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See *   the GNU Lesser General Public License for more details. * *   You should have received a copy of the GNU Lesser General Public License *   along with this library; if not, write to the Free Software *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <linux/slab.h>#include <linux/ctype.h>#include <linux/version.h>#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)#include <linux/mempool.h>#endif#include "cifspdu.h"#include "cifsglob.h"#include "cifsproto.h"#include "cifs_debug.h"#include "smberr.h"#include "nterr.h"#include "cifs_unicode.h"#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)extern mempool_t *cifs_sm_req_poolp;extern mempool_t *cifs_req_poolp;#elseextern kmem_cache_t *cifs_sm_req_cachep;extern kmem_cache_t *cifs_req_cachep;#endifextern struct task_struct *oplockThread;/* The xid serves as a useful identifier for each incoming vfs request,   in a similar way to the mid which is useful to track each sent smb,   and CurrentXid can also provide a running counter (although it   will eventually wrap past zero) of the total vfs operations handled   since the cifs fs was mounted */unsigned int_GetXid(void){	unsigned int xid;	spin_lock(&GlobalMid_Lock);	GlobalTotalActiveXid++;	/* keep high water mark for number of simultaneous ops in filesystem */	if (GlobalTotalActiveXid > GlobalMaxActiveXid)		GlobalMaxActiveXid = GlobalTotalActiveXid;	if (GlobalTotalActiveXid > 65000)		cFYI(1, ("warning: more than 65000 requests active"));	xid = GlobalCurrentXid++;	spin_unlock(&GlobalMid_Lock);	return xid;}void_FreeXid(unsigned int xid){	spin_lock(&GlobalMid_Lock);	/* if (GlobalTotalActiveXid == 0)		BUG(); */	GlobalTotalActiveXid--;	spin_unlock(&GlobalMid_Lock);}struct cifsSesInfo *sesInfoAlloc(void){	struct cifsSesInfo *ret_buf;	ret_buf = kzalloc(sizeof (struct cifsSesInfo), GFP_KERNEL);	if (ret_buf) {		write_lock(&GlobalSMBSeslock);		atomic_inc(&sesInfoAllocCount);		ret_buf->status = CifsNew;		list_add(&ret_buf->cifsSessionList, &GlobalSMBSessionList);		init_MUTEX(&ret_buf->sesSem);		write_unlock(&GlobalSMBSeslock);	}	return ret_buf;}voidsesInfoFree(struct cifsSesInfo *buf_to_free){	if (buf_to_free == NULL) {		cFYI(1, ("Null buffer passed to sesInfoFree"));		return;	}	write_lock(&GlobalSMBSeslock);	atomic_dec(&sesInfoAllocCount);	list_del(&buf_to_free->cifsSessionList);	write_unlock(&GlobalSMBSeslock);	kfree(buf_to_free->serverOS);	kfree(buf_to_free->serverDomain);	kfree(buf_to_free->serverNOS);	kfree(buf_to_free->password);	kfree(buf_to_free->domainName);	kfree(buf_to_free);}struct cifsTconInfo *tconInfoAlloc(void){	struct cifsTconInfo *ret_buf;	ret_buf = kzalloc(sizeof (struct cifsTconInfo), GFP_KERNEL);	if (ret_buf) {		write_lock(&GlobalSMBSeslock);		atomic_inc(&tconInfoAllocCount);		list_add(&ret_buf->cifsConnectionList,			 &GlobalTreeConnectionList);		ret_buf->tidStatus = CifsNew;		INIT_LIST_HEAD(&ret_buf->openFileList);		init_MUTEX(&ret_buf->tconSem);#ifdef CONFIG_CIFS_STATS		spin_lock_init(&ret_buf->stat_lock);#endif		write_unlock(&GlobalSMBSeslock);	}	return ret_buf;}voidtconInfoFree(struct cifsTconInfo *buf_to_free){	if (buf_to_free == NULL) {		cFYI(1, ("Null buffer passed to tconInfoFree"));		return;	}	write_lock(&GlobalSMBSeslock);	atomic_dec(&tconInfoAllocCount);	list_del(&buf_to_free->cifsConnectionList);	write_unlock(&GlobalSMBSeslock);	kfree(buf_to_free->nativeFileSystem);	kfree(buf_to_free);}struct smb_hdr *cifs_buf_get(void){	struct smb_hdr *ret_buf = NULL;/* We could use negotiated size instead of max_msgsize -   but it may be more efficient to always alloc same size   albeit slightly larger than necessary and maxbuffersize   defaults to this and can not be bigger */#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)	ret_buf = (struct smb_hdr *) mempool_alloc(cifs_req_poolp,						   GFP_KERNEL | GFP_NOFS);#else	ret_buf = (struct smb_hdr *) kmem_cache_alloc(cifs_req_cachep, 						   SLAB_KERNEL);#endif	/* clear the first few header bytes */	/* for most paths, more is cleared in header_assemble */	if (ret_buf) {		memset(ret_buf, 0, sizeof(struct smb_hdr) + 3);		atomic_inc(&bufAllocCount);#ifdef CONFIG_CIFS_STATS2		atomic_inc(&totBufAllocCount);#endif /* CONFIG_CIFS_STATS2 */	}	return ret_buf;}voidcifs_buf_release(void *buf_to_free){	if (buf_to_free == NULL) {		/* cFYI(1, ("Null buffer passed to cifs_buf_release"));*/		return;	}#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)	mempool_free(buf_to_free, cifs_req_poolp);#else	kmem_cache_free(cifs_req_cachep, buf_to_free);#endif	atomic_dec(&bufAllocCount);	return;}struct smb_hdr *cifs_small_buf_get(void){	struct smb_hdr *ret_buf = NULL;/* We could use negotiated size instead of max_msgsize -   but it may be more efficient to always alloc same size   albeit slightly larger than necessary and maxbuffersize   defaults to this and can not be bigger */#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)	ret_buf = (struct smb_hdr *) mempool_alloc(cifs_sm_req_poolp,						   GFP_KERNEL | GFP_NOFS);#else	ret_buf = (struct smb_hdr *) kmem_cache_alloc(cifs_sm_req_cachep,						   SLAB_KERNEL);#endif	if (ret_buf) {	/* No need to clear memory here, cleared in header assemble */	/*	memset(ret_buf, 0, sizeof(struct smb_hdr) + 27);*/		atomic_inc(&smBufAllocCount);#ifdef CONFIG_CIFS_STATS2		atomic_inc(&totSmBufAllocCount);#endif /* CONFIG_CIFS_STATS2 */	}	return ret_buf;}voidcifs_small_buf_release(void *buf_to_free){	if (buf_to_free == NULL) {		cFYI(1, ("Null buffer passed to cifs_small_buf_release"));		return;	}#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0)	mempool_free(buf_to_free, cifs_sm_req_poolp);#else	kmem_cache_free(cifs_sm_req_cachep, buf_to_free);#endif	atomic_dec(&smBufAllocCount);	return;}/*	Find a free multiplex id (SMB mid). Otherwise there could be	mid collisions which might cause problems, demultiplexing the	wrong response to this request. Multiplex ids could collide if	one of a series requests takes much longer than the others, or	if a very large number of long lived requests (byte range	locks or FindNotify requests) are pending.  No more than	64K-1 requests can be outstanding at one time.  If no	mids are available, return zero.  A future optimization	could make the combination of mids and uid the key we use	to demultiplex on (rather than mid alone).	In addition to the above check, the cifs demultiplex	code already used the command code as a secondary	check of the frame and if signing is negotiated the	response would be discarded if the mid were the same	but the signature was wrong.  Since the mid is not put in the	pending queue until later (when it is about to be dispatched)	we do have to limit the number of outstanding requests	to somewhat less than 64K-1 although it is hard to imagine	so many threads being in the vfs at one time.*/__u16 GetNextMid(struct TCP_Server_Info *server){	__u16 mid = 0;	__u16 last_mid;	int   collision;	if (server == NULL)		return mid;	spin_lock(&GlobalMid_Lock);	last_mid = server->CurrentMid; /* we do not want to loop forever */	server->CurrentMid++;	/* This nested loop looks more expensive than it is.	In practice the list of pending requests is short,	fewer than 50, and the mids are likely to be unique	on the first pass through the loop unless some request	takes longer than the 64 thousand requests before it	(and it would also have to have been a request that	 did not time out) */	while (server->CurrentMid != last_mid) {		struct list_head *tmp;		struct mid_q_entry *mid_entry;		collision = 0;		if (server->CurrentMid == 0)			server->CurrentMid++;		list_for_each(tmp, &server->pending_mid_q) {			mid_entry = list_entry(tmp, struct mid_q_entry, qhead);			if ((mid_entry->mid == server->CurrentMid) &&			    (mid_entry->midState == MID_REQUEST_SUBMITTED)) {				/* This mid is in use, try a different one */				collision = 1;				break;			}		}		if (collision == 0) {			mid = server->CurrentMid;			break;		}		server->CurrentMid++;	}	spin_unlock(&GlobalMid_Lock);	return mid;}/* NB: MID can not be set if treeCon not passed in, in that   case it is responsbility of caller to set the mid */voidheader_assemble(struct smb_hdr *buffer, char smb_command /* command */ ,		const struct cifsTconInfo *treeCon, int word_count		/* length of fixed section (word count) in two byte units  */){	struct list_head *temp_item;	struct cifsSesInfo *ses;	char *temp = (char *) buffer;	memset(temp, 0, 256); /* bigger than MAX_CIFS_HDR_SIZE */	buffer->smb_buf_length =	    (2 * word_count) + sizeof (struct smb_hdr) -	    4 /*  RFC 1001 length field does not count */  +	    2 /* for bcc field itself */ ;	/* Note that this is the only network field that has to be converted	   to big endian and it is done just before we send it */	buffer->Protocol[0] = 0xFF;	buffer->Protocol[1] = 'S';	buffer->Protocol[2] = 'M';	buffer->Protocol[3] = 'B';	buffer->Command = smb_command;	buffer->Flags = 0x00;	/* case sensitive */	buffer->Flags2 = SMBFLG2_KNOWS_LONG_NAMES;	buffer->Pid = cpu_to_le16((__u16)current->tgid);	buffer->PidHigh = cpu_to_le16((__u16)(current->tgid >> 16));	spin_lock(&GlobalMid_Lock);	spin_unlock(&GlobalMid_Lock);	if (treeCon) {		buffer->Tid = treeCon->tid;		if (treeCon->ses) {			if (treeCon->ses->capabilities & CAP_UNICODE)				buffer->Flags2 |= SMBFLG2_UNICODE;			if (treeCon->ses->capabilities & CAP_STATUS32) {				buffer->Flags2 |= SMBFLG2_ERR_STATUS;			}			/* Uid is not converted */			buffer->Uid = treeCon->ses->Suid;			buffer->Mid = GetNextMid(treeCon->ses->server);			if (multiuser_mount != 0) {		/* For the multiuser case, there are few obvious technically  */		/* possible mechanisms to match the local linux user (uid)    */		/* to a valid remote smb user (smb_uid):		      */		/* 	1) Query Winbind (or other local pam/nss daemon       */		/* 	  for userid/password/logon_domain or credential      */		/*      2) Query Winbind for uid to sid to username mapping   */		/* 	   and see if we have a matching password for existing*/		/*         session for that user perhas getting password by   */		/*         adding a new pam_cifs module that stores passwords */		/*         so that the cifs vfs can get at that for all logged*/		/*	   on users					      */		/*	3) (Which is the mechanism we have chosen)	      */		/*	   Search through sessions to the same server for a   */		/*	   a match on the uid that was passed in on mount     */		/*         with the current processes uid (or euid?) and use  */		/* 	   that smb uid.   If no existing smb session for     */		/* 	   that uid found, use the default smb session ie     */		/*         the smb session for the volume mounted which is    */		/* 	   the same as would be used if the multiuser mount   */		/* 	   flag were disabled.  */		/*  BB Add support for establishing new tCon and SMB Session  */		/*      with userid/password pairs found on the smb session   */		/*	for other target tcp/ip addresses 		BB    */				if (current->fsuid != treeCon->ses->linux_uid) {					cFYI(1, ("Multiuser mode and UID "						 "did not match tcon uid"));					read_lock(&GlobalSMBSeslock);					list_for_each(temp_item, &GlobalSMBSessionList) {						ses = list_entry(temp_item, struct cifsSesInfo, cifsSessionList);						if (ses->linux_uid == current->fsuid) {							if (ses->server == treeCon->ses->server) {								cFYI(1, ("found matching uid substitute right smb_uid"));								buffer->Uid = ses->Suid;								break;							} else {				/* BB eventually call cifs_setup_session here */								cFYI(1, ("local UID found but no smb sess with this server exists"));							}						}					}					read_unlock(&GlobalSMBSeslock);				}			}		}		if (treeCon->Flags & SMB_SHARE_IS_IN_DFS)			buffer->Flags2 |= SMBFLG2_DFS;		if (treeCon->nocase)

⌨️ 快捷键说明

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