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

📄 file.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		   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 =			CIFS_SB(file->f_path.dentry->d_sb);		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"));	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);	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 (pfLock->fl_flags & FL_POSIX)		posix_lock_file_wait(file, pfLock);	FreeXid(xid);	return rc;}ssize_t cifs_user_write(struct file *file, const char __user *write_data,	size_t write_size, loff_t *poffset){	int rc = 0;	unsigned int bytes_written = 0;	unsigned int total_written;	struct cifs_sb_info *cifs_sb;	struct cifsTconInfo *pTcon;	int xid, long_op;	struct cifsFileInfo *open_file;	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);	pTcon = cifs_sb->tcon;	/* cFYI(1,	   (" write %d bytes to offset %lld of %s", write_size,	   *poffset, file->f_path.dentry->d_name.name)); */	if (file->private_data == NULL)		return -EBADF;	open_file = (struct cifsFileInfo *) file->private_data;	xid = GetXid();	if (*poffset > file->f_path.dentry->d_inode->i_size)		long_op = CIFS_VLONG_OP; /* writes past EOF take long time */	else		long_op = CIFS_LONG_OP;	for (total_written = 0; write_size > total_written;	     total_written += bytes_written) {		rc = -EAGAIN;		while (rc == -EAGAIN) {			if (file->private_data == NULL) {				/* file has been closed on us */				FreeXid(xid);			/* if we have gotten here we have written some data			   and blocked, and the file has been freed on us while			   we blocked so return what we managed to write */				return total_written;			}			if (open_file->closePend) {				FreeXid(xid);				if (total_written)					return total_written;				else					return -EBADF;			}			if (open_file->invalidHandle) {				/* we could deadlock if we called				   filemap_fdatawait from here so tell				   reopen_file not to flush data to server				   now */				rc = cifs_reopen_file(file, FALSE);				if (rc != 0)					break;			}			rc = CIFSSMBWrite(xid, pTcon,				open_file->netfid,				min_t(const int, cifs_sb->wsize,				      write_size - total_written),				*poffset, &bytes_written,				NULL, write_data + total_written, long_op);		}		if (rc || (bytes_written == 0)) {			if (total_written)				break;			else {				FreeXid(xid);				return rc;			}		} else			*poffset += bytes_written;		long_op = CIFS_STD_OP; /* subsequent writes fast -				    15 seconds is plenty */	}	cifs_stats_bytes_written(pTcon, total_written);	/* since the write may have blocked check these pointers again */	if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {		struct inode *inode = file->f_path.dentry->d_inode;/* Do not update local mtime - server will set its actual value on write *		inode->i_ctime = inode->i_mtime = * 			current_fs_time(inode->i_sb);*/		if (total_written > 0) {			spin_lock(&inode->i_lock);			if (*poffset > file->f_path.dentry->d_inode->i_size)				i_size_write(file->f_path.dentry->d_inode,					*poffset);			spin_unlock(&inode->i_lock);		}		mark_inode_dirty_sync(file->f_path.dentry->d_inode);	}	FreeXid(xid);	return total_written;}static ssize_t cifs_write(struct file *file, const char *write_data,	size_t write_size, loff_t *poffset){	int rc = 0;	unsigned int bytes_written = 0;	unsigned int total_written;	struct cifs_sb_info *cifs_sb;	struct cifsTconInfo *pTcon;	int xid, long_op;	struct cifsFileInfo *open_file;	cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);	pTcon = cifs_sb->tcon;	cFYI(1, ("write %zd bytes to offset %lld of %s", write_size,	   *poffset, file->f_path.dentry->d_name.name));	if (file->private_data == NULL)		return -EBADF;	open_file = (struct cifsFileInfo *)file->private_data;	xid = GetXid();	if (*poffset > file->f_path.dentry->d_inode->i_size)		long_op = CIFS_VLONG_OP; /* writes past EOF can be slow */	else		long_op = CIFS_LONG_OP;	for (total_written = 0; write_size > total_written;	     total_written += bytes_written) {		rc = -EAGAIN;		while (rc == -EAGAIN) {			if (file->private_data == NULL) {				/* file has been closed on us */				FreeXid(xid);			/* if we have gotten here we have written some data			   and blocked, and the file has been freed on us			   while we blocked so return what we managed to			   write */				return total_written;			}			if (open_file->closePend) {				FreeXid(xid);				if (total_written)					return total_written;				else					return -EBADF;			}			if (open_file->invalidHandle) {				/* we could deadlock if we called				   filemap_fdatawait from here so tell				   reopen_file not to flush data to				   server now */				rc = cifs_reopen_file(file, FALSE);				if (rc != 0)					break;			}			if (experimEnabled || (pTcon->ses->server &&				((pTcon->ses->server->secMode &				(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))				== 0))) {				struct kvec iov[2];				unsigned int len;				len = min((size_t)cifs_sb->wsize,					  write_size - total_written);				/* iov[0] is reserved for smb header */				iov[1].iov_base = (char *)write_data +						  total_written;				iov[1].iov_len = len;				rc = CIFSSMBWrite2(xid, pTcon,						open_file->netfid, len,						*poffset, &bytes_written,						iov, 1, long_op);			} else				rc = CIFSSMBWrite(xid, pTcon,					 open_file->netfid,					 min_t(const int, cifs_sb->wsize,					       write_size - total_written),					 *poffset, &bytes_written,					 write_data + total_written,					 NULL, long_op);		}		if (rc || (bytes_written == 0)) {			if (total_written)				break;			else {				FreeXid(xid);				return rc;			}		} else			*poffset += bytes_written;		long_op = CIFS_STD_OP; /* subsequent writes fast -				    15 seconds is plenty */	}	cifs_stats_bytes_written(pTcon, total_written);	/* since the write may have blocked check these pointers again */	if ((file->f_path.dentry) && (file->f_path.dentry->d_inode)) {/*BB We could make this contingent on superblock ATIME flag too *//*		file->f_path.dentry->d_inode->i_ctime =		file->f_path.dentry->d_inode->i_mtime = CURRENT_TIME;*/		if (total_written > 0) {			spin_lock(&file->f_path.dentry->d_inode->i_lock);			if (*poffset > file->f_path.dentry->d_inode->i_size)				i_size_write(file->f_path.dentry->d_inode,					     *poffset);			spin_unlock(&file->f_path.dentry->d_inode->i_lock);		}		mark_inode_dirty_sync(file->f_path.dentry->d_inode);	}	FreeXid(xid);	return total_written;}#ifdef CONFIG_CIFS_EXPERIMENTALstruct cifsFileInfo *find_readable_file(struct cifsInodeInfo *cifs_inode){	struct cifsFileInfo *open_file = NULL;	read_lock(&GlobalSMBSeslock);	/* we could simply get the first_list_entry since write-only entries	   are always at the end of the list but since the first entry might	   have a close pending, we go through the whole list */	list_for_each_entry(open_file, &cifs_inode->openFileList, flist) {		if (open_file->closePend)			continue;		if (open_file->pfile && ((open_file->pfile->f_flags & O_RDWR) ||		    (open_file->pfile->f_flags & O_RDONLY))) {			if (!open_file->invalidHandle) {				/* found a good file */				/* lock it so it will not be closed on us */				atomic_inc(&open_file->wrtPending);				read_unlock(&GlobalSMBSeslock);				return open_file;			} /* else might as well continue, and look for			     another, or simply have the caller reopen it			     again rather than trying to fix this handle */		} else /* write only file */			break; /* write only files are last so must be done */	}	read_unlock(&GlobalSMBSeslock);	return NULL;

⌨️ 快捷键说明

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