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

📄 file.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
}#endifstruct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode){	struct cifsFileInfo *open_file;	int rc;	/* Having a null inode here (because mapping->host was set to zero by	the VFS or MM) should not happen but we had reports of on oops (due to	it being zero) during stress testcases so we need to check for it */	if (cifs_inode == NULL) {		cERROR(1, ("Null inode passed to cifs_writeable_file"));		dump_stack();		return NULL;	}	read_lock(&GlobalSMBSeslock);refind_writable:	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_WRONLY))) {			atomic_inc(&open_file->wrtPending);			if (!open_file->invalidHandle) {				/* found a good writable file */				read_unlock(&GlobalSMBSeslock);				return open_file;			}			read_unlock(&GlobalSMBSeslock);			/* Had to unlock since following call can block */			rc = cifs_reopen_file(open_file->pfile, FALSE);			if (!rc) {				if (!open_file->closePend)					return open_file;				else { /* start over in case this was deleted */				       /* since the list could be modified */					read_lock(&GlobalSMBSeslock);					atomic_dec(&open_file->wrtPending);					goto refind_writable;				}			}			/* if it fails, try another handle if possible -			(we can not do this if closePending since			loop could be modified - in which case we			have to start at the beginning of the list			again. Note that it would be bad			to hold up writepages here (rather than			in caller) with continuous retries */			cFYI(1, ("wp failed on reopen file"));			read_lock(&GlobalSMBSeslock);			/* can not use this handle, no write			   pending on this one after all */			atomic_dec(&open_file->wrtPending);			if (open_file->closePend) /* list could have changed */				goto refind_writable;			/* else we simply continue to the next entry. Thus			   we do not loop on reopen errors.  If we			   can not reopen the file, for example if we			   reconnected to a server with another client			   racing to delete or lock the file we would not			   make progress if we restarted before the beginning			   of the loop here. */		}	}	read_unlock(&GlobalSMBSeslock);	return NULL;}static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to){	struct address_space *mapping = page->mapping;	loff_t offset = (loff_t)page->index << PAGE_CACHE_SHIFT;	char *write_data;	int rc = -EFAULT;	int bytes_written = 0;	struct cifs_sb_info *cifs_sb;	struct cifsTconInfo *pTcon;	struct inode *inode;	struct cifsFileInfo *open_file;	if (!mapping || !mapping->host)		return -EFAULT;	inode = page->mapping->host;	cifs_sb = CIFS_SB(inode->i_sb);	pTcon = cifs_sb->tcon;	offset += (loff_t)from;	write_data = kmap(page);	write_data += from;	if ((to > PAGE_CACHE_SIZE) || (from > to)) {		kunmap(page);		return -EIO;	}	/* racing with truncate? */	if (offset > mapping->host->i_size) {		kunmap(page);		return 0; /* don't care */	}	/* check to make sure that we are not extending the file */	if (mapping->host->i_size - offset < (loff_t)to)		to = (unsigned)(mapping->host->i_size - offset);	open_file = find_writable_file(CIFS_I(mapping->host));	if (open_file) {		bytes_written = cifs_write(open_file->pfile, write_data,					   to-from, &offset);		atomic_dec(&open_file->wrtPending);		/* Does mm or vfs already set times? */		inode->i_atime = inode->i_mtime = current_fs_time(inode->i_sb);		if ((bytes_written > 0) && (offset)) {			rc = 0;		} else if (bytes_written < 0) {			if (rc != -EBADF)				rc = bytes_written;		}	} else {		cFYI(1, ("No writeable filehandles for inode"));		rc = -EIO;	}	kunmap(page);	return rc;}static int cifs_writepages(struct address_space *mapping,			   struct writeback_control *wbc){	struct backing_dev_info *bdi = mapping->backing_dev_info;	unsigned int bytes_to_write;	unsigned int bytes_written;	struct cifs_sb_info *cifs_sb;	int done = 0;	pgoff_t end;	pgoff_t index;	int range_whole = 0;	struct kvec *iov;	int len;	int n_iov = 0;	pgoff_t next;	int nr_pages;	__u64 offset = 0;	struct cifsFileInfo *open_file;	struct page *page;	struct pagevec pvec;	int rc = 0;	int scanned = 0;	int xid;	cifs_sb = CIFS_SB(mapping->host->i_sb);	/*	 * If wsize is smaller that the page cache size, default to writing	 * one page at a time via cifs_writepage	 */	if (cifs_sb->wsize < PAGE_CACHE_SIZE)		return generic_writepages(mapping, wbc);	if ((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server))		if (cifs_sb->tcon->ses->server->secMode &				(SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))			if (!experimEnabled)				return generic_writepages(mapping, wbc);	iov = kmalloc(32 * sizeof(struct kvec), GFP_KERNEL);	if (iov == NULL)		return generic_writepages(mapping, wbc);	/*	 * BB: Is this meaningful for a non-block-device file system?	 * If it is, we should test it again after we do I/O	 */	if (wbc->nonblocking && bdi_write_congested(bdi)) {		wbc->encountered_congestion = 1;		kfree(iov);		return 0;	}	xid = GetXid();	pagevec_init(&pvec, 0);	if (wbc->range_cyclic) {		index = mapping->writeback_index; /* Start from prev offset */		end = -1;	} else {		index = wbc->range_start >> PAGE_CACHE_SHIFT;		end = wbc->range_end >> PAGE_CACHE_SHIFT;		if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)			range_whole = 1;		scanned = 1;	}retry:	while (!done && (index <= end) &&	       (nr_pages = pagevec_lookup_tag(&pvec, mapping, &index,			PAGECACHE_TAG_DIRTY,			min(end - index, (pgoff_t)PAGEVEC_SIZE - 1) + 1))) {		int first;		unsigned int i;		first = -1;		next = 0;		n_iov = 0;		bytes_to_write = 0;		for (i = 0; i < nr_pages; i++) {			page = pvec.pages[i];			/*			 * At this point we hold neither mapping->tree_lock nor			 * lock on the page itself: the page may be truncated or			 * invalidated (changing page->mapping to NULL), or even			 * swizzled back from swapper_space to tmpfs file			 * mapping			 */			if (first < 0)				lock_page(page);			else if (TestSetPageLocked(page))				break;			if (unlikely(page->mapping != mapping)) {				unlock_page(page);				break;			}			if (!wbc->range_cyclic && page->index > end) {				done = 1;				unlock_page(page);				break;			}			if (next && (page->index != next)) {				/* Not next consecutive page */				unlock_page(page);				break;			}			if (wbc->sync_mode != WB_SYNC_NONE)				wait_on_page_writeback(page);			if (PageWriteback(page) ||					!clear_page_dirty_for_io(page)) {				unlock_page(page);				break;			}			/*			 * This actually clears the dirty bit in the radix tree.			 * See cifs_writepage() for more commentary.			 */			set_page_writeback(page);			if (page_offset(page) >= mapping->host->i_size) {				done = 1;				unlock_page(page);				end_page_writeback(page);				break;			}			/*			 * BB can we get rid of this?  pages are held by pvec			 */			page_cache_get(page);			len = min(mapping->host->i_size - page_offset(page),				  (loff_t)PAGE_CACHE_SIZE);			/* reserve iov[0] for the smb header */			n_iov++;			iov[n_iov].iov_base = kmap(page);			iov[n_iov].iov_len = len;			bytes_to_write += len;			if (first < 0) {				first = i;				offset = page_offset(page);			}			next = page->index + 1;			if (bytes_to_write + PAGE_CACHE_SIZE > cifs_sb->wsize)				break;		}		if (n_iov) {			/* Search for a writable handle every time we call			 * CIFSSMBWrite2.  We can't rely on the last handle			 * we used to still be valid			 */			open_file = find_writable_file(CIFS_I(mapping->host));			if (!open_file) {				cERROR(1, ("No writable handles for inode"));				rc = -EBADF;			} else {				rc = CIFSSMBWrite2(xid, cifs_sb->tcon,						   open_file->netfid,						   bytes_to_write, offset,						   &bytes_written, iov, n_iov,						   CIFS_LONG_OP);				atomic_dec(&open_file->wrtPending);				if (rc || bytes_written < bytes_to_write) {					cERROR(1, ("Write2 ret %d, wrote %d",						  rc, bytes_written));					/* BB what if continued retry is					   requested via mount flags? */					if (rc == -ENOSPC)						set_bit(AS_ENOSPC, &mapping->flags);					else						set_bit(AS_EIO, &mapping->flags);				} else {					cifs_stats_bytes_written(cifs_sb->tcon,								 bytes_written);				}			}			for (i = 0; i < n_iov; i++) {				page = pvec.pages[first + i];				/* Should we also set page error on				success rc but too little data written? */				/* BB investigate retry logic on temporary				server crash cases and how recovery works				when page marked as error */				if (rc)					SetPageError(page);				kunmap(page);				unlock_page(page);				end_page_writeback(page);				page_cache_release(page);			}			if ((wbc->nr_to_write -= n_iov) <= 0)				done = 1;			index = next;		}		pagevec_release(&pvec);	}	if (!scanned && !done) {		/*		 * We hit the last page and there is more work to be done: wrap		 * back to the start of the file		 */		scanned = 1;		index = 0;		goto retry;	}	if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))		mapping->writeback_index = index;	FreeXid(xid);	kfree(iov);	return rc;}static int cifs_writepage(struct page *page, struct writeback_control *wbc){	int rc = -EFAULT;	int xid;	xid = GetXid();/* BB add check for wbc flags */	page_cache_get(page);	if (!PageUptodate(page)) {		cFYI(1, ("ppw - page not up to date"));	}	/*	 * Set the "writeback" flag, and clear "dirty" in the radix tree.	 *	 * A writepage() implementation always needs to do either this,	 * or re-dirty the page with "redirty_page_for_writepage()" in	 * the case of a failure.	 *	 * Just unlocking the page will cause the radix tree tag-bits	 * to fail to update with the state of the page correctly.	 */	set_page_writeback(page);	rc = cifs_partialpagewrite(page, 0, PAGE_CACHE_SIZE);	SetPageUptodate(page); /* BB add check for error and Clearuptodate? */	unlock_page(page);	end_page_writeback(page);	page_cache_release(page);	FreeXid(xid);	return rc;}static int cifs_commit_write(struct file *file, struct page *page,	unsigned offset, unsigned to){	int xid;	int rc = 0;	struct inode *inode = page->mapping->host;	loff_t position = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;	char *page_data;	xid = GetXid();	cFYI(1, ("commit write for page %p up to position %lld for %d",		 page, position, to));	spin_lock(&inode->i_lock);	if (position > inode->i_size) {		i_size_write(inode, position);	}	spin_unlock(&inode->i_lock);	if (!PageUptodate(page)) {		position =  ((loff_t)page->index << PAGE_CACHE_SHIFT) + offset;		/* can not rely on (or let) writepage write this data */		if (to < offset) {			cFYI(1, ("Illegal offsets, can not copy from %d to %d",				offset, to));			FreeXid(xid);			return rc;		}		/* this is probably better than directly calling		   partialpage_write since in this function the file handle is		   known which we might as well	leverage */		/* BB check if anything else missing out of ppw		   such as updating last write time */		page_data = kmap(page);		rc = cifs_write(file, page_data + offset, to-offset,				&position);		if (rc > 0)			rc = 0;		/* else if (rc < 0) should we set writebehind rc? */		kunmap(page);	} else {		set_page_dirty(page);	}	FreeXid(xid);	return rc;}int cifs_fsync(struct file *file, struct dentry *dentry, int datasync){	int xid;	int rc = 0;	struct inode *inode = file->f_path.dentry->d_inode;	xid = GetXid();	cFYI(1, ("Sync file - name: %s datasync: 0x%x",		dentry->d_name.name, datasync));	rc = filemap_write_and_wait(inode->i_mapping);	if (rc == 0) {		rc = CIFS_I(inode)->write_behind_rc;		CIFS_I(inode)->write_behind_rc = 0;	}	FreeXid(xid);	return rc;}/* static void cifs_sync_page(struct page *page){	struct address_space *mapping;	struct inode *inode;	unsigned long index = page->index;	unsigned int rpages = 0;	int rc = 0;	cFYI(1, ("sync page %p",page));	mapping = page->mapping;	if (!mapping)		return 0;	inode = mapping->host;	if (!inode)		return; *//*	fill in rpages then	result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish *//*	cFYI(1, ("rpages is %d for sync page of Index %ld", rpages, index));#if 0	if (rc < 0)		return rc;	return 0;#endif} *//* * As file closes, flush all cached write data for this inode checking * for write behind errors. */int cifs_flush(struct file *file, fl_owner_t id){	struct inode *inode = file->f_path.dentry->d_inode;	int rc = 0;	/* Rather than do the steps manually:	   lock the inode for writing	   loop through pages looking for write behind data (dirty pages)	   coalesce into contiguous 16K (or smaller) chunks to write to server	   send to server (prefer in parallel)	   deal with writebehind errors	   unlock inode for writing	   filemapfdatawrite appears easier for the time being */	rc = filemap_fdatawrite(inode->i_mapping);	/* reset wb rc if we were able to write out dirty pages */	if (!rc) {		rc = CIFS_I(inode)->write_behind_rc;		CIFS_I(inode)->write_behind_rc = 0;	}	cFYI(1, ("Flush inode %p file %p rc %d", inode, file, rc));	return rc;}ssize_t cifs_user_read(struct file *file, char __user *read_data,	size_t read_size, loff_t *poffset){	int rc = -EACCES;	unsigned int bytes_read = 0;	unsigned int total_read = 0;	unsigned int current_read_size;	struct cifs_sb_info *cifs_sb;	struct cifsTconInfo *pTcon;	int xid;	struct cifsFileInfo *open_file;	char *smb_read_data;	char __user *current_offset;	struct smb_com_read_rsp *pSMBr;

⌨️ 快捷键说明

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