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

📄 file.c

📁 Linux内核自带的cifs模块
💻 C
📖 第 1 页 / 共 5 页
字号:
	inode = file->f_path.dentry->d_inode;	if (inode == NULL) {		cERROR(1, ("inode not valid"));		dump_stack();		rc = -EBADF;		goto reopen_error_exit;	}	cifs_sb = CIFS_SB(inode->i_sb);	pTcon = cifs_sb->tcon;/* can not grab rename sem here because various ops, including   those that already have the rename sem can end up causing writepage   to get called and if the server was down that means we end up here,   and we can never tell if the caller already has the rename_sem */	full_path = build_path_from_dentry(file->f_path.dentry);#endif	if (full_path == NULL) {		rc = -ENOMEM;reopen_error_exit:		up(&pCifsFile->fh_sem);		FreeXid(xid);		return rc;	}	cFYI(1, ("inode = 0x%p file flags 0x%x for %s",		 inode, file->f_flags, full_path));	desiredAccess = cifs_convert_flags(file->f_flags);	if (oplockEnabled)		oplock = REQ_OPLOCK;	else		oplock = FALSE;	/* Can not refresh inode by passing in file_info buf to be returned	   by SMBOpen and then calling get_inode_info with returned buf	   since file might have write behind data that needs to be flushed	   and server version of file size can be stale. If we knew for sure	   that inode was not dirty locally we could do this */	rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess,			 CREATE_NOT_DIR, &netfid, &oplock, NULL,			 cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &				CIFS_MOUNT_MAP_SPECIAL_CHR);	if (rc) {		up(&pCifsFile->fh_sem);		cFYI(1, ("cifs_open returned 0x%x", rc));		cFYI(1, ("oplock: %d", oplock));	} else {		pCifsFile->netfid = netfid;		pCifsFile->invalidHandle = FALSE;		up(&pCifsFile->fh_sem);		pCifsInode = CIFS_I(inode);		if (pCifsInode) {			if (can_flush) {#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15)				filemap_write_and_wait(inode->i_mapping);#else				filemap_fdatawrite(inode->i_mapping);				filemap_fdatawait(inode->i_mapping);#endif			/* temporarily disable caching while we			   go to server to get inode info */				pCifsInode->clientCanCacheAll = FALSE;				pCifsInode->clientCanCacheRead = FALSE;				if (pTcon->unix_ext)					rc = cifs_get_inode_info_unix(&inode,						full_path, inode->i_sb, xid);				else					rc = cifs_get_inode_info(&inode,						full_path, NULL, inode->i_sb,						xid);			} /* else we are writing out data to server already			     and could deadlock if we tried to flush data, and			     since we do not know if we have data that would			     invalidate the current end of file on the server			     we can not go to the server to get the new inod			     info */			if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {				pCifsInode->clientCanCacheAll = TRUE;				pCifsInode->clientCanCacheRead = TRUE;#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)				cFYI(1, ("Exclusive Oplock granted on inode %p",					file->f_dentry->d_inode));#else				cFYI(1, ("Exclusive Oplock granted on inode %p",					 file->f_path.dentry->d_inode));#endif			} else if ((oplock & 0xF) == OPLOCK_READ) {				pCifsInode->clientCanCacheRead = TRUE;				pCifsInode->clientCanCacheAll = FALSE;			} else {				pCifsInode->clientCanCacheRead = FALSE;				pCifsInode->clientCanCacheAll = FALSE;			}			cifs_relock_file(pCifsFile);		}	}	kfree(full_path);	FreeXid(xid);	return rc;}int cifs_close(struct inode *inode, struct file *file){	int rc = 0;	int xid, timeout;	struct cifs_sb_info *cifs_sb;	struct cifsTconInfo *pTcon;	struct cifsFileInfo *pSMBFile =		(struct cifsFileInfo *)file->private_data;	xid = GetXid();	cifs_sb = CIFS_SB(inode->i_sb);	pTcon = cifs_sb->tcon;	if (pSMBFile) {		struct cifsLockInfo *li, *tmp;		pSMBFile->closePend = TRUE;		if (pTcon) {			/* no sense reconnecting to close a file that is			   already closed */			if (pTcon->tidStatus != CifsNeedReconnect) {				timeout = 2;				while ((atomic_read(&pSMBFile->wrtPending) != 0)					&& (timeout <= 2048)) {					/* Give write a better chance to get to					server ahead of the close.  We do not					want to add a wait_q here as it would					increase the memory utilization as					the struct would be in each open file,					but this should give enough time to					clear the socket */#ifdef CONFIG_CIFS_DEBUG2					cFYI(1, ("close delay, write pending"));#endif /* DEBUG2 */					msleep(timeout);					timeout *= 4;				}				if (atomic_read(&pSMBFile->wrtPending))					cERROR(1,						("close with pending writes"));				rc = CIFSSMBClose(xid, pTcon,						  pSMBFile->netfid);			}		}		/* Delete any outstanding lock records.		   We'll lose them when the file is closed anyway. */		mutex_lock(&pSMBFile->lock_mutex);		list_for_each_entry_safe(li, tmp, &pSMBFile->llist, llist) {			list_del(&li->llist);			kfree(li);		}		mutex_unlock(&pSMBFile->lock_mutex);		write_lock(&GlobalSMBSeslock);		list_del(&pSMBFile->flist);		list_del(&pSMBFile->tlist);		write_unlock(&GlobalSMBSeslock);		timeout = 10;		/* We waited above to give the SMBWrite a chance to issue		   on the wire (so we do not get SMBWrite returning EBADF		   if writepages is racing with close.  Note that writepages		   does not specify a file handle, so it is possible for a file		   to be opened twice, and the application close the "wrong"		   file handle - in these cases we delay long enough to allow		   the SMBWrite to get on the wire before the SMB Close.		   We allow total wait here over 45 seconds, more than		   oplock break time, and more than enough to allow any write		   to complete on the server, or to time out on the client */		while ((atomic_read(&pSMBFile->wrtPending) != 0)				&& (timeout <= 50000)) {			cERROR(1, ("writes pending, delay free of handle"));			msleep(timeout);			timeout *= 8;		}		kfree(pSMBFile->search_resume_name);		kfree(file->private_data);		file->private_data = NULL;	} else		rc = -EBADF;	read_lock(&GlobalSMBSeslock);	if (list_empty(&(CIFS_I(inode)->openFileList))) {		cFYI(1, ("closing last open instance for inode %p", inode));		/* if the file is not open we do not know if we can cache info		   on this inode, much less write behind and read ahead */		CIFS_I(inode)->clientCanCacheRead = FALSE;		CIFS_I(inode)->clientCanCacheAll  = FALSE;	}	read_unlock(&GlobalSMBSeslock);	if ((rc == 0) && CIFS_I(inode)->write_behind_rc)		rc = CIFS_I(inode)->write_behind_rc;	FreeXid(xid);	return rc;}int cifs_closedir(struct inode *inode, struct file *file){	int rc = 0;	int xid;	struct cifsFileInfo *pCFileStruct =	    (struct cifsFileInfo *)file->private_data;	char *ptmp;	cFYI(1, ("Closedir inode = 0x%p", inode));	xid = GetXid();	if (pCFileStruct) {		struct cifsTconInfo *pTcon;		struct cifs_sb_info *cifs_sb =#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)			CIFS_SB(file->f_dentry->d_sb);#else			CIFS_SB(file->f_path.dentry->d_sb);#endif		pTcon = cifs_sb->tcon;		cFYI(1, ("Freeing private data in close dir"));		if ((pCFileStruct->srch_inf.endOfSearch == FALSE) &&		   (pCFileStruct->invalidHandle == FALSE)) {			pCFileStruct->invalidHandle = TRUE;			rc = CIFSFindClose(xid, pTcon, pCFileStruct->netfid);			cFYI(1, ("Closing uncompleted readdir with rc %d",				 rc));			/* not much we can do if it fails anyway, ignore rc */			rc = 0;		}		ptmp = pCFileStruct->srch_inf.ntwrk_buf_start;		if (ptmp) {			cFYI(1, ("closedir free smb buf in srch struct"));			pCFileStruct->srch_inf.ntwrk_buf_start = NULL;			if (pCFileStruct->srch_inf.smallBuf)				cifs_small_buf_release(ptmp);			else				cifs_buf_release(ptmp);		}		ptmp = pCFileStruct->search_resume_name;		if (ptmp) {			cFYI(1, ("closedir free resume name"));			pCFileStruct->search_resume_name = NULL;			kfree(ptmp);		}		kfree(file->private_data);		file->private_data = NULL;	}	/* BB can we lock the filestruct while this is going on? */	FreeXid(xid);	return rc;}static int store_file_lock(struct cifsFileInfo *fid, __u64 len,				__u64 offset, __u8 lockType){	struct cifsLockInfo *li =		kmalloc(sizeof(struct cifsLockInfo), GFP_KERNEL);	if (li == NULL)		return -ENOMEM;	li->offset = offset;	li->length = len;	li->type = lockType;	mutex_lock(&fid->lock_mutex);	list_add(&li->llist, &fid->llist);	mutex_unlock(&fid->lock_mutex);	return 0;}int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock){	int rc, xid;	__u32 numLock = 0;	__u32 numUnlock = 0;	__u64 length;	int wait_flag = FALSE;	struct cifs_sb_info *cifs_sb;	struct cifsTconInfo *pTcon;	__u16 netfid;	__u8 lockType = LOCKING_ANDX_LARGE_FILES;	int posix_locking;	length = 1 + pfLock->fl_end - pfLock->fl_start;	rc = -EACCES;	xid = GetXid();	cFYI(1, ("Lock parm: 0x%x flockflags: "		 "0x%x flocktype: 0x%x start: %lld end: %lld",		cmd, pfLock->fl_flags, pfLock->fl_type, pfLock->fl_start,		pfLock->fl_end));	if (pfLock->fl_flags & FL_POSIX)		cFYI(1, ("Posix"));	if (pfLock->fl_flags & FL_FLOCK)		cFYI(1, ("Flock"));	if (pfLock->fl_flags & FL_SLEEP) {		cFYI(1, ("Blocking lock"));		wait_flag = TRUE;	}	if (pfLock->fl_flags & FL_ACCESS)		cFYI(1, ("Process suspended by mandatory locking - "			 "not implemented yet"));	if (pfLock->fl_flags & FL_LEASE)		cFYI(1, ("Lease on file - not implemented yet"));	if (pfLock->fl_flags &	    (~(FL_POSIX | FL_FLOCK | FL_SLEEP | FL_ACCESS | FL_LEASE)))		cFYI(1, ("Unknown lock flags 0x%x", pfLock->fl_flags));	if (pfLock->fl_type == F_WRLCK) {		cFYI(1, ("F_WRLCK "));		numLock = 1;	} else if (pfLock->fl_type == F_UNLCK) {		cFYI(1, ("F_UNLCK"));		numUnlock = 1;		/* Check if unlock includes more than		one lock range */	} else if (pfLock->fl_type == F_RDLCK) {		cFYI(1, ("F_RDLCK"));		lockType |= LOCKING_ANDX_SHARED_LOCK;		numLock = 1;	} else if (pfLock->fl_type == F_EXLCK) {		cFYI(1, ("F_EXLCK"));		numLock = 1;	} else if (pfLock->fl_type == F_SHLCK) {		cFYI(1, ("F_SHLCK"));		lockType |= LOCKING_ANDX_SHARED_LOCK;		numLock = 1;	} else		cFYI(1, ("Unknown type of lock"));#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)	cifs_sb = CIFS_SB(file->f_dentry->d_sb);#else	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);#endif	pTcon = cifs_sb->tcon;	if (file->private_data == NULL) {		FreeXid(xid);		return -EBADF;	}	netfid = ((struct cifsFileInfo *)file->private_data)->netfid;	posix_locking = (cifs_sb->tcon->ses->capabilities & CAP_UNIX) &&			(CIFS_UNIX_FCNTL_CAP & le64_to_cpu(cifs_sb->tcon->fsUnixInfo.Capability));	/* BB add code here to normalize offset and length to	account for negative length which we can not accept over the	wire */	if (IS_GETLK(cmd)) {		if (posix_locking) {			int posix_lock_type;			if (lockType & LOCKING_ANDX_SHARED_LOCK)				posix_lock_type = CIFS_RDLCK;			else				posix_lock_type = CIFS_WRLCK;			rc = CIFSSMBPosixLock(xid, pTcon, netfid, 1 /* get */,					length,	pfLock,					posix_lock_type, wait_flag);			FreeXid(xid);			return rc;		}		/* BB we could chain these into one lock request BB */		rc = CIFSSMBLock(xid, pTcon, netfid, length, pfLock->fl_start,				 0, 1, lockType, 0 /* wait flag */ );		if (rc == 0) {			rc = CIFSSMBLock(xid, pTcon, netfid, length,					 pfLock->fl_start, 1 /* numUnlock */ ,					 0 /* numLock */ , lockType,					 0 /* wait flag */ );			pfLock->fl_type = F_UNLCK;			if (rc != 0)				cERROR(1, ("Error unlocking previously locked "					   "range %d during test of lock", rc));			rc = 0;		} else {			/* if rc == ERR_SHARING_VIOLATION ? */			rc = 0;	/* do not change lock type to unlock				   since range in use */		}		FreeXid(xid);		return rc;	}	if (!numLock && !numUnlock) {		/* if no lock or unlock then nothing		to do since we do not know what it is */		FreeXid(xid);		return -EOPNOTSUPP;	}	if (posix_locking) {		int posix_lock_type;		if (lockType & LOCKING_ANDX_SHARED_LOCK)			posix_lock_type = CIFS_RDLCK;		else			posix_lock_type = CIFS_WRLCK;		if (numUnlock == 1)			posix_lock_type = CIFS_UNLCK;		rc = CIFSSMBPosixLock(xid, pTcon, netfid, 0 /* set */,				      length, pfLock,				      posix_lock_type, wait_flag);	} else {		struct cifsFileInfo *fid =			(struct cifsFileInfo *)file->private_data;		if (numLock) {			rc = CIFSSMBLock(xid, pTcon, netfid, length,					pfLock->fl_start,					0, numLock, lockType, wait_flag);			if (rc == 0) {				/* For Windows locks we must store them. */				rc = store_file_lock(fid, length,						pfLock->fl_start, lockType);			}		} else if (numUnlock) {			/* For each stored lock that this unlock overlaps			   completely, unlock it. */			int stored_rc = 0;			struct cifsLockInfo *li, *tmp;			rc = 0;			mutex_lock(&fid->lock_mutex);			list_for_each_entry_safe(li, tmp, &fid->llist, llist) {				if (pfLock->fl_start <= li->offset &&						(pfLock->fl_start + length) >=						(li->offset + li->length)) {					stored_rc = CIFSSMBLock(xid, pTcon,							netfid,							li->length, li->offset,							1, 0, li->type, FALSE);					if (stored_rc)						rc = stored_rc;					list_del(&li->llist);					kfree(li);				}			}			mutex_unlock(&fid->lock_mutex);		}	}#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,8)	if (pfLock->fl_flags & FL_POSIX)		posix_lock_file_wait(file, pfLock);#endif	FreeXid(xid);	return rc;}ssize_t cifs_user_write(struct file *file, const char __user *write_data,	size_t write_size, loff_t *poffset){

⌨️ 快捷键说明

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