forked from mirrors/linux
		
	afs: Make afs_fs_fetch_data() take a list of pages
Make afs_fs_fetch_data() take a list of pages for bulk data transfer. This will allow afs_readpages() to be made more efficient. Signed-off-by: David Howells <dhowells@redhat.com>
This commit is contained in:
		
							parent
							
								
									c1878f7a89
								
							
						
					
					
						commit
						196ee9cd2d
					
				
					 5 changed files with 145 additions and 55 deletions
				
			
		| 
						 | 
					@ -101,6 +101,21 @@ int afs_release(struct inode *inode, struct file *file)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Dispose of a ref to a read record.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void afs_put_read(struct afs_read *req)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (atomic_dec_and_test(&req->usage)) {
 | 
				
			||||||
 | 
							for (i = 0; i < req->nr_pages; i++)
 | 
				
			||||||
 | 
								if (req->pages[i])
 | 
				
			||||||
 | 
									put_page(req->pages[i]);
 | 
				
			||||||
 | 
							kfree(req);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_AFS_FSCACHE
 | 
					#ifdef CONFIG_AFS_FSCACHE
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * deal with notification that a page was read from the cache
 | 
					 * deal with notification that a page was read from the cache
 | 
				
			||||||
| 
						 | 
					@ -126,9 +141,8 @@ int afs_page_filler(void *data, struct page *page)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct inode *inode = page->mapping->host;
 | 
						struct inode *inode = page->mapping->host;
 | 
				
			||||||
	struct afs_vnode *vnode = AFS_FS_I(inode);
 | 
						struct afs_vnode *vnode = AFS_FS_I(inode);
 | 
				
			||||||
 | 
						struct afs_read *req;
 | 
				
			||||||
	struct key *key = data;
 | 
						struct key *key = data;
 | 
				
			||||||
	size_t len;
 | 
					 | 
				
			||||||
	off_t offset;
 | 
					 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_enter("{%x},{%lu},{%lu}", key_serial(key), inode->i_ino, page->index);
 | 
						_enter("{%x},{%lu},{%lu}", key_serial(key), inode->i_ino, page->index);
 | 
				
			||||||
| 
						 | 
					@ -164,12 +178,23 @@ int afs_page_filler(void *data, struct page *page)
 | 
				
			||||||
		_debug("cache said ENOBUFS");
 | 
							_debug("cache said ENOBUFS");
 | 
				
			||||||
	default:
 | 
						default:
 | 
				
			||||||
	go_on:
 | 
						go_on:
 | 
				
			||||||
		offset = page->index << PAGE_SHIFT;
 | 
							req = kzalloc(sizeof(struct afs_read) + sizeof(struct page *),
 | 
				
			||||||
		len = min_t(size_t, i_size_read(inode) - offset, PAGE_SIZE);
 | 
								      GFP_KERNEL);
 | 
				
			||||||
 | 
							if (!req)
 | 
				
			||||||
 | 
								goto enomem;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							atomic_set(&req->usage, 1);
 | 
				
			||||||
 | 
							req->pos = (loff_t)page->index << PAGE_SHIFT;
 | 
				
			||||||
 | 
							req->len = min_t(size_t, i_size_read(inode) - req->pos,
 | 
				
			||||||
 | 
									 PAGE_SIZE);
 | 
				
			||||||
 | 
							req->nr_pages = 1;
 | 
				
			||||||
 | 
							req->pages[0] = page;
 | 
				
			||||||
 | 
							get_page(page);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* read the contents of the file from the server into the
 | 
							/* read the contents of the file from the server into the
 | 
				
			||||||
		 * page */
 | 
							 * page */
 | 
				
			||||||
		ret = afs_vnode_fetch_data(vnode, key, offset, len, page);
 | 
							ret = afs_vnode_fetch_data(vnode, key, req);
 | 
				
			||||||
 | 
							afs_put_read(req);
 | 
				
			||||||
		if (ret < 0) {
 | 
							if (ret < 0) {
 | 
				
			||||||
			if (ret == -ENOENT) {
 | 
								if (ret == -ENOENT) {
 | 
				
			||||||
				_debug("got NOENT from server"
 | 
									_debug("got NOENT from server"
 | 
				
			||||||
| 
						 | 
					@ -201,6 +226,8 @@ int afs_page_filler(void *data, struct page *page)
 | 
				
			||||||
	_leave(" = 0");
 | 
						_leave(" = 0");
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enomem:
 | 
				
			||||||
 | 
						ret = -ENOMEM;
 | 
				
			||||||
error:
 | 
					error:
 | 
				
			||||||
	SetPageError(page);
 | 
						SetPageError(page);
 | 
				
			||||||
	unlock_page(page);
 | 
						unlock_page(page);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -309,15 +309,19 @@ int afs_fs_fetch_file_status(struct afs_server *server,
 | 
				
			||||||
static int afs_deliver_fs_fetch_data(struct afs_call *call)
 | 
					static int afs_deliver_fs_fetch_data(struct afs_call *call)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct afs_vnode *vnode = call->reply;
 | 
						struct afs_vnode *vnode = call->reply;
 | 
				
			||||||
 | 
						struct afs_read *req = call->reply3;
 | 
				
			||||||
	const __be32 *bp;
 | 
						const __be32 *bp;
 | 
				
			||||||
	struct page *page;
 | 
						unsigned int size;
 | 
				
			||||||
	void *buffer;
 | 
						void *buffer;
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_enter("{%u}", call->unmarshall);
 | 
						_enter("{%u,%zu/%u;%u/%llu}",
 | 
				
			||||||
 | 
						       call->unmarshall, call->offset, call->count,
 | 
				
			||||||
 | 
						       req->remain, req->actual_len);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	switch (call->unmarshall) {
 | 
						switch (call->unmarshall) {
 | 
				
			||||||
	case 0:
 | 
						case 0:
 | 
				
			||||||
 | 
							req->actual_len = 0;
 | 
				
			||||||
		call->offset = 0;
 | 
							call->offset = 0;
 | 
				
			||||||
		call->unmarshall++;
 | 
							call->unmarshall++;
 | 
				
			||||||
		if (call->operation_ID != FSFETCHDATA64) {
 | 
							if (call->operation_ID != FSFETCHDATA64) {
 | 
				
			||||||
| 
						 | 
					@ -334,10 +338,8 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
 | 
				
			||||||
		if (ret < 0)
 | 
							if (ret < 0)
 | 
				
			||||||
			return ret;
 | 
								return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		call->count = ntohl(call->tmp);
 | 
							req->actual_len = ntohl(call->tmp);
 | 
				
			||||||
		_debug("DATA length MSW: %u", call->count);
 | 
							req->actual_len <<= 32;
 | 
				
			||||||
		if (call->count > 0)
 | 
					 | 
				
			||||||
			return -EBADMSG;
 | 
					 | 
				
			||||||
		call->offset = 0;
 | 
							call->offset = 0;
 | 
				
			||||||
		call->unmarshall++;
 | 
							call->unmarshall++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -349,26 +351,52 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
 | 
				
			||||||
		if (ret < 0)
 | 
							if (ret < 0)
 | 
				
			||||||
			return ret;
 | 
								return ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		call->count = ntohl(call->tmp);
 | 
							req->actual_len |= ntohl(call->tmp);
 | 
				
			||||||
		_debug("DATA length: %u", call->count);
 | 
							_debug("DATA length: %llu", req->actual_len);
 | 
				
			||||||
		if (call->count > PAGE_SIZE)
 | 
							/* Check that the server didn't want to send us extra.  We
 | 
				
			||||||
 | 
							 * might want to just discard instead, but that requires
 | 
				
			||||||
 | 
							 * cooperation from AF_RXRPC.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							if (req->actual_len > req->len)
 | 
				
			||||||
			return -EBADMSG;
 | 
								return -EBADMSG;
 | 
				
			||||||
		call->offset = 0;
 | 
					
 | 
				
			||||||
 | 
							req->remain = req->actual_len;
 | 
				
			||||||
 | 
							call->offset = req->pos & (PAGE_SIZE - 1);
 | 
				
			||||||
 | 
							req->index = 0;
 | 
				
			||||||
 | 
							if (req->actual_len == 0)
 | 
				
			||||||
 | 
								goto no_more_data;
 | 
				
			||||||
		call->unmarshall++;
 | 
							call->unmarshall++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						begin_page:
 | 
				
			||||||
 | 
							if (req->remain > PAGE_SIZE - call->offset)
 | 
				
			||||||
 | 
								size = PAGE_SIZE - call->offset;
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								size = req->remain;
 | 
				
			||||||
 | 
							call->count = call->offset + size;
 | 
				
			||||||
 | 
							ASSERTCMP(call->count, <=, PAGE_SIZE);
 | 
				
			||||||
 | 
							req->remain -= size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* extract the returned data */
 | 
							/* extract the returned data */
 | 
				
			||||||
	case 3:
 | 
						case 3:
 | 
				
			||||||
		_debug("extract data");
 | 
							_debug("extract data %u/%llu %zu/%u",
 | 
				
			||||||
		if (call->count > 0) {
 | 
							       req->remain, req->actual_len, call->offset, call->count);
 | 
				
			||||||
			page = call->reply3;
 | 
					
 | 
				
			||||||
			buffer = kmap(page);
 | 
							buffer = kmap(req->pages[req->index]);
 | 
				
			||||||
			ret = afs_extract_data(call, buffer,
 | 
							ret = afs_extract_data(call, buffer, call->count, true);
 | 
				
			||||||
					       call->count, true);
 | 
							kunmap(req->pages[req->index]);
 | 
				
			||||||
			kunmap(page);
 | 
					 | 
				
			||||||
		if (ret < 0)
 | 
							if (ret < 0)
 | 
				
			||||||
			return ret;
 | 
								return ret;
 | 
				
			||||||
 | 
							if (call->offset == PAGE_SIZE) {
 | 
				
			||||||
 | 
								if (req->page_done)
 | 
				
			||||||
 | 
									req->page_done(call, req);
 | 
				
			||||||
 | 
								if (req->remain > 0) {
 | 
				
			||||||
 | 
									req->index++;
 | 
				
			||||||
 | 
									call->offset = 0;
 | 
				
			||||||
 | 
									goto begin_page;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						no_more_data:
 | 
				
			||||||
		call->offset = 0;
 | 
							call->offset = 0;
 | 
				
			||||||
		call->unmarshall++;
 | 
							call->unmarshall++;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -393,17 +421,25 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (call->count < PAGE_SIZE) {
 | 
						if (call->count < PAGE_SIZE) {
 | 
				
			||||||
		_debug("clear");
 | 
							buffer = kmap(req->pages[req->index]);
 | 
				
			||||||
		page = call->reply3;
 | 
					 | 
				
			||||||
		buffer = kmap(page);
 | 
					 | 
				
			||||||
		memset(buffer + call->count, 0, PAGE_SIZE - call->count);
 | 
							memset(buffer + call->count, 0, PAGE_SIZE - call->count);
 | 
				
			||||||
		kunmap(page);
 | 
							kunmap(req->pages[req->index]);
 | 
				
			||||||
 | 
							if (req->page_done)
 | 
				
			||||||
 | 
								req->page_done(call, req);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_leave(" = 0 [done]");
 | 
						_leave(" = 0 [done]");
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void afs_fetch_data_destructor(struct afs_call *call)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct afs_read *req = call->reply3;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						afs_put_read(req);
 | 
				
			||||||
 | 
						afs_flat_call_destructor(call);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * FS.FetchData operation type
 | 
					 * FS.FetchData operation type
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -411,14 +447,14 @@ static const struct afs_call_type afs_RXFSFetchData = {
 | 
				
			||||||
	.name		= "FS.FetchData",
 | 
						.name		= "FS.FetchData",
 | 
				
			||||||
	.deliver	= afs_deliver_fs_fetch_data,
 | 
						.deliver	= afs_deliver_fs_fetch_data,
 | 
				
			||||||
	.abort_to_error	= afs_abort_to_error,
 | 
						.abort_to_error	= afs_abort_to_error,
 | 
				
			||||||
	.destructor	= afs_flat_call_destructor,
 | 
						.destructor	= afs_fetch_data_destructor,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const struct afs_call_type afs_RXFSFetchData64 = {
 | 
					static const struct afs_call_type afs_RXFSFetchData64 = {
 | 
				
			||||||
	.name		= "FS.FetchData64",
 | 
						.name		= "FS.FetchData64",
 | 
				
			||||||
	.deliver	= afs_deliver_fs_fetch_data,
 | 
						.deliver	= afs_deliver_fs_fetch_data,
 | 
				
			||||||
	.abort_to_error	= afs_abort_to_error,
 | 
						.abort_to_error	= afs_abort_to_error,
 | 
				
			||||||
	.destructor	= afs_flat_call_destructor,
 | 
						.destructor	= afs_fetch_data_destructor,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -427,8 +463,7 @@ static const struct afs_call_type afs_RXFSFetchData64 = {
 | 
				
			||||||
static int afs_fs_fetch_data64(struct afs_server *server,
 | 
					static int afs_fs_fetch_data64(struct afs_server *server,
 | 
				
			||||||
			       struct key *key,
 | 
								       struct key *key,
 | 
				
			||||||
			       struct afs_vnode *vnode,
 | 
								       struct afs_vnode *vnode,
 | 
				
			||||||
			       off_t offset, size_t length,
 | 
								       struct afs_read *req,
 | 
				
			||||||
			       struct page *buffer,
 | 
					 | 
				
			||||||
			       const struct afs_wait_mode *wait_mode)
 | 
								       const struct afs_wait_mode *wait_mode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct afs_call *call;
 | 
						struct afs_call *call;
 | 
				
			||||||
| 
						 | 
					@ -436,8 +471,6 @@ static int afs_fs_fetch_data64(struct afs_server *server,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_enter("");
 | 
						_enter("");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ASSERTCMP(length, <, ULONG_MAX);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	call = afs_alloc_flat_call(&afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4);
 | 
						call = afs_alloc_flat_call(&afs_RXFSFetchData64, 32, (21 + 3 + 6) * 4);
 | 
				
			||||||
	if (!call)
 | 
						if (!call)
 | 
				
			||||||
		return -ENOMEM;
 | 
							return -ENOMEM;
 | 
				
			||||||
| 
						 | 
					@ -445,7 +478,7 @@ static int afs_fs_fetch_data64(struct afs_server *server,
 | 
				
			||||||
	call->key = key;
 | 
						call->key = key;
 | 
				
			||||||
	call->reply = vnode;
 | 
						call->reply = vnode;
 | 
				
			||||||
	call->reply2 = NULL; /* volsync */
 | 
						call->reply2 = NULL; /* volsync */
 | 
				
			||||||
	call->reply3 = buffer;
 | 
						call->reply3 = req;
 | 
				
			||||||
	call->service_id = FS_SERVICE;
 | 
						call->service_id = FS_SERVICE;
 | 
				
			||||||
	call->port = htons(AFS_FS_PORT);
 | 
						call->port = htons(AFS_FS_PORT);
 | 
				
			||||||
	call->operation_ID = FSFETCHDATA64;
 | 
						call->operation_ID = FSFETCHDATA64;
 | 
				
			||||||
| 
						 | 
					@ -456,11 +489,12 @@ static int afs_fs_fetch_data64(struct afs_server *server,
 | 
				
			||||||
	bp[1] = htonl(vnode->fid.vid);
 | 
						bp[1] = htonl(vnode->fid.vid);
 | 
				
			||||||
	bp[2] = htonl(vnode->fid.vnode);
 | 
						bp[2] = htonl(vnode->fid.vnode);
 | 
				
			||||||
	bp[3] = htonl(vnode->fid.unique);
 | 
						bp[3] = htonl(vnode->fid.unique);
 | 
				
			||||||
	bp[4] = htonl(upper_32_bits(offset));
 | 
						bp[4] = htonl(upper_32_bits(req->pos));
 | 
				
			||||||
	bp[5] = htonl((u32) offset);
 | 
						bp[5] = htonl(lower_32_bits(req->pos));
 | 
				
			||||||
	bp[6] = 0;
 | 
						bp[6] = 0;
 | 
				
			||||||
	bp[7] = htonl((u32) length);
 | 
						bp[7] = htonl(lower_32_bits(req->len));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						atomic_inc(&req->usage);
 | 
				
			||||||
	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
 | 
						return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -470,16 +504,16 @@ static int afs_fs_fetch_data64(struct afs_server *server,
 | 
				
			||||||
int afs_fs_fetch_data(struct afs_server *server,
 | 
					int afs_fs_fetch_data(struct afs_server *server,
 | 
				
			||||||
		      struct key *key,
 | 
							      struct key *key,
 | 
				
			||||||
		      struct afs_vnode *vnode,
 | 
							      struct afs_vnode *vnode,
 | 
				
			||||||
		      off_t offset, size_t length,
 | 
							      struct afs_read *req,
 | 
				
			||||||
		      struct page *buffer,
 | 
					 | 
				
			||||||
		      const struct afs_wait_mode *wait_mode)
 | 
							      const struct afs_wait_mode *wait_mode)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct afs_call *call;
 | 
						struct afs_call *call;
 | 
				
			||||||
	__be32 *bp;
 | 
						__be32 *bp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (upper_32_bits(offset) || upper_32_bits(offset + length))
 | 
						if (upper_32_bits(req->pos) ||
 | 
				
			||||||
		return afs_fs_fetch_data64(server, key, vnode, offset, length,
 | 
						    upper_32_bits(req->len) ||
 | 
				
			||||||
					   buffer, wait_mode);
 | 
						    upper_32_bits(req->pos + req->len))
 | 
				
			||||||
 | 
							return afs_fs_fetch_data64(server, key, vnode, req, wait_mode);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_enter("");
 | 
						_enter("");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -490,7 +524,7 @@ int afs_fs_fetch_data(struct afs_server *server,
 | 
				
			||||||
	call->key = key;
 | 
						call->key = key;
 | 
				
			||||||
	call->reply = vnode;
 | 
						call->reply = vnode;
 | 
				
			||||||
	call->reply2 = NULL; /* volsync */
 | 
						call->reply2 = NULL; /* volsync */
 | 
				
			||||||
	call->reply3 = buffer;
 | 
						call->reply3 = req;
 | 
				
			||||||
	call->service_id = FS_SERVICE;
 | 
						call->service_id = FS_SERVICE;
 | 
				
			||||||
	call->port = htons(AFS_FS_PORT);
 | 
						call->port = htons(AFS_FS_PORT);
 | 
				
			||||||
	call->operation_ID = FSFETCHDATA;
 | 
						call->operation_ID = FSFETCHDATA;
 | 
				
			||||||
| 
						 | 
					@ -501,9 +535,10 @@ int afs_fs_fetch_data(struct afs_server *server,
 | 
				
			||||||
	bp[1] = htonl(vnode->fid.vid);
 | 
						bp[1] = htonl(vnode->fid.vid);
 | 
				
			||||||
	bp[2] = htonl(vnode->fid.vnode);
 | 
						bp[2] = htonl(vnode->fid.vnode);
 | 
				
			||||||
	bp[3] = htonl(vnode->fid.unique);
 | 
						bp[3] = htonl(vnode->fid.unique);
 | 
				
			||||||
	bp[4] = htonl(offset);
 | 
						bp[4] = htonl(lower_32_bits(req->pos));
 | 
				
			||||||
	bp[5] = htonl(length);
 | 
						bp[5] = htonl(lower_32_bits(req->len));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						atomic_inc(&req->usage);
 | 
				
			||||||
	return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
 | 
						return afs_make_call(&server->addr, call, GFP_NOFS, wait_mode);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -133,6 +133,22 @@ struct afs_call_type {
 | 
				
			||||||
	void (*destructor)(struct afs_call *call);
 | 
						void (*destructor)(struct afs_call *call);
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Record of an outstanding read operation on a vnode.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct afs_read {
 | 
				
			||||||
 | 
						loff_t			pos;		/* Where to start reading */
 | 
				
			||||||
 | 
						loff_t			len;		/* How much to read */
 | 
				
			||||||
 | 
						loff_t			actual_len;	/* How much we're actually getting */
 | 
				
			||||||
 | 
						atomic_t		usage;
 | 
				
			||||||
 | 
						unsigned int		remain;		/* Amount remaining */
 | 
				
			||||||
 | 
						unsigned int		index;		/* Which page we're reading into */
 | 
				
			||||||
 | 
						unsigned int		pg_offset;	/* Offset in page we're at */
 | 
				
			||||||
 | 
						unsigned int		nr_pages;
 | 
				
			||||||
 | 
						void (*page_done)(struct afs_call *, struct afs_read *);
 | 
				
			||||||
 | 
						struct page		*pages[];
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * record of an outstanding writeback on a vnode
 | 
					 * record of an outstanding writeback on a vnode
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					@ -494,6 +510,7 @@ extern const struct file_operations afs_file_operations;
 | 
				
			||||||
extern int afs_open(struct inode *, struct file *);
 | 
					extern int afs_open(struct inode *, struct file *);
 | 
				
			||||||
extern int afs_release(struct inode *, struct file *);
 | 
					extern int afs_release(struct inode *, struct file *);
 | 
				
			||||||
extern int afs_page_filler(void *, struct page *);
 | 
					extern int afs_page_filler(void *, struct page *);
 | 
				
			||||||
 | 
					extern void afs_put_read(struct afs_read *);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * flock.c
 | 
					 * flock.c
 | 
				
			||||||
| 
						 | 
					@ -513,7 +530,7 @@ extern int afs_fs_fetch_file_status(struct afs_server *, struct key *,
 | 
				
			||||||
extern int afs_fs_give_up_callbacks(struct afs_server *,
 | 
					extern int afs_fs_give_up_callbacks(struct afs_server *,
 | 
				
			||||||
				    const struct afs_wait_mode *);
 | 
									    const struct afs_wait_mode *);
 | 
				
			||||||
extern int afs_fs_fetch_data(struct afs_server *, struct key *,
 | 
					extern int afs_fs_fetch_data(struct afs_server *, struct key *,
 | 
				
			||||||
			     struct afs_vnode *, off_t, size_t, struct page *,
 | 
								     struct afs_vnode *, struct afs_read *,
 | 
				
			||||||
			     const struct afs_wait_mode *);
 | 
								     const struct afs_wait_mode *);
 | 
				
			||||||
extern int afs_fs_create(struct afs_server *, struct key *,
 | 
					extern int afs_fs_create(struct afs_server *, struct key *,
 | 
				
			||||||
			 struct afs_vnode *, const char *, umode_t,
 | 
								 struct afs_vnode *, const char *, umode_t,
 | 
				
			||||||
| 
						 | 
					@ -699,7 +716,7 @@ extern void afs_vnode_finalise_status_update(struct afs_vnode *,
 | 
				
			||||||
extern int afs_vnode_fetch_status(struct afs_vnode *, struct afs_vnode *,
 | 
					extern int afs_vnode_fetch_status(struct afs_vnode *, struct afs_vnode *,
 | 
				
			||||||
				  struct key *);
 | 
									  struct key *);
 | 
				
			||||||
extern int afs_vnode_fetch_data(struct afs_vnode *, struct key *,
 | 
					extern int afs_vnode_fetch_data(struct afs_vnode *, struct key *,
 | 
				
			||||||
				off_t, size_t, struct page *);
 | 
									struct afs_read *);
 | 
				
			||||||
extern int afs_vnode_create(struct afs_vnode *, struct key *, const char *,
 | 
					extern int afs_vnode_create(struct afs_vnode *, struct key *, const char *,
 | 
				
			||||||
			    umode_t, struct afs_fid *, struct afs_file_status *,
 | 
								    umode_t, struct afs_fid *, struct afs_file_status *,
 | 
				
			||||||
			    struct afs_callback *, struct afs_server **);
 | 
								    struct afs_callback *, struct afs_server **);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -393,7 +393,7 @@ int afs_vnode_fetch_status(struct afs_vnode *vnode,
 | 
				
			||||||
 * - TODO implement caching
 | 
					 * - TODO implement caching
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
int afs_vnode_fetch_data(struct afs_vnode *vnode, struct key *key,
 | 
					int afs_vnode_fetch_data(struct afs_vnode *vnode, struct key *key,
 | 
				
			||||||
			 off_t offset, size_t length, struct page *page)
 | 
								 struct afs_read *desc)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct afs_server *server;
 | 
						struct afs_server *server;
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
| 
						 | 
					@ -420,8 +420,8 @@ int afs_vnode_fetch_data(struct afs_vnode *vnode, struct key *key,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		_debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
 | 
							_debug("USING SERVER: %08x\n", ntohl(server->addr.s_addr));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		ret = afs_fs_fetch_data(server, key, vnode, offset, length,
 | 
							ret = afs_fs_fetch_data(server, key, vnode, desc,
 | 
				
			||||||
					page, &afs_sync_call);
 | 
										&afs_sync_call);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	} while (!afs_volume_release_fileserver(vnode, server, ret));
 | 
						} while (!afs_volume_release_fileserver(vnode, server, ret));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -86,19 +86,30 @@ void afs_put_writeback(struct afs_writeback *wb)
 | 
				
			||||||
static int afs_fill_page(struct afs_vnode *vnode, struct key *key,
 | 
					static int afs_fill_page(struct afs_vnode *vnode, struct key *key,
 | 
				
			||||||
			 loff_t pos, struct page *page)
 | 
								 loff_t pos, struct page *page)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						struct afs_read *req;
 | 
				
			||||||
	loff_t i_size;
 | 
						loff_t i_size;
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
	int len;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	_enter(",,%llu", (unsigned long long)pos);
 | 
						_enter(",,%llu", (unsigned long long)pos);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						req = kzalloc(sizeof(struct afs_read) + sizeof(struct page *),
 | 
				
			||||||
 | 
							      GFP_KERNEL);
 | 
				
			||||||
 | 
						if (!req)
 | 
				
			||||||
 | 
							return -ENOMEM;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						atomic_set(&req->usage, 1);
 | 
				
			||||||
 | 
						req->pos = pos;
 | 
				
			||||||
 | 
						req->nr_pages = 1;
 | 
				
			||||||
 | 
						req->pages[0] = page;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	i_size = i_size_read(&vnode->vfs_inode);
 | 
						i_size = i_size_read(&vnode->vfs_inode);
 | 
				
			||||||
	if (pos + PAGE_SIZE > i_size)
 | 
						if (pos + PAGE_SIZE > i_size)
 | 
				
			||||||
		len = i_size - pos;
 | 
							req->len = i_size - pos;
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		len = PAGE_SIZE;
 | 
							req->len = PAGE_SIZE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = afs_vnode_fetch_data(vnode, key, pos, len, page);
 | 
						ret = afs_vnode_fetch_data(vnode, key, req);
 | 
				
			||||||
 | 
						afs_put_read(req);
 | 
				
			||||||
	if (ret < 0) {
 | 
						if (ret < 0) {
 | 
				
			||||||
		if (ret == -ENOENT) {
 | 
							if (ret == -ENOENT) {
 | 
				
			||||||
			_debug("got NOENT from server"
 | 
								_debug("got NOENT from server"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue