NFS: Use the 64-bit server readdir cookies when possible
When we're running as a 64-bit architecture and are not running in 32-bit compatibility mode, it is better to use the 64-bit readdir cookies that supplied by the server. Doing so improves the accuracy of telldir()/seekdir(), particularly when the directory is changing, for instance, when doing 'rm -rf'. We still fall back to using the 32-bit offsets on 32-bit architectures and when in compatibility mode. Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
This commit is contained in:
		
							parent
							
								
									fb33c6510d
								
							
						
					
					
						commit
						59e356a967
					
				
							
								
								
									
										61
									
								
								fs/nfs/dir.c
									
									
									
									
									
								
							
							
						
						
									
										61
									
								
								fs/nfs/dir.c
									
									
									
									
									
								
							| @ -144,7 +144,6 @@ struct nfs_cache_array { | ||||
| 	struct nfs_cache_array_entry array[0]; | ||||
| }; | ||||
| 
 | ||||
| typedef int (*decode_dirent_t)(struct xdr_stream *, struct nfs_entry *, bool); | ||||
| typedef struct { | ||||
| 	struct file	*file; | ||||
| 	struct page	*page; | ||||
| @ -153,7 +152,7 @@ typedef struct { | ||||
| 	u64		*dir_cookie; | ||||
| 	u64		last_cookie; | ||||
| 	loff_t		current_index; | ||||
| 	decode_dirent_t	decode; | ||||
| 	loff_t		prev_index; | ||||
| 
 | ||||
| 	unsigned long	dir_verifier; | ||||
| 	unsigned long	timestamp; | ||||
| @ -240,6 +239,25 @@ out: | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static inline | ||||
| int is_32bit_api(void) | ||||
| { | ||||
| #ifdef CONFIG_COMPAT | ||||
| 	return in_compat_syscall(); | ||||
| #else | ||||
| 	return (BITS_PER_LONG == 32); | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| static | ||||
| bool nfs_readdir_use_cookie(const struct file *filp) | ||||
| { | ||||
| 	if ((filp->f_mode & FMODE_32BITHASH) || | ||||
| 	    (!(filp->f_mode & FMODE_64BITHASH) && is_32bit_api())) | ||||
| 		return false; | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| static | ||||
| int nfs_readdir_search_for_pos(struct nfs_cache_array *array, nfs_readdir_descriptor_t *desc) | ||||
| { | ||||
| @ -289,7 +307,7 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des | ||||
| 			    !nfs_readdir_inode_mapping_valid(nfsi)) { | ||||
| 				ctx->duped = 0; | ||||
| 				ctx->attr_gencount = nfsi->attr_gencount; | ||||
| 			} else if (new_pos < desc->ctx->pos) { | ||||
| 			} else if (new_pos < desc->prev_index) { | ||||
| 				if (ctx->duped > 0 | ||||
| 				    && ctx->dup_cookie == *desc->dir_cookie) { | ||||
| 					if (printk_ratelimit()) { | ||||
| @ -305,7 +323,11 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des | ||||
| 				ctx->dup_cookie = *desc->dir_cookie; | ||||
| 				ctx->duped = -1; | ||||
| 			} | ||||
| 			desc->ctx->pos = new_pos; | ||||
| 			if (nfs_readdir_use_cookie(desc->file)) | ||||
| 				desc->ctx->pos = *desc->dir_cookie; | ||||
| 			else | ||||
| 				desc->ctx->pos = new_pos; | ||||
| 			desc->prev_index = new_pos; | ||||
| 			desc->cache_entry_index = i; | ||||
| 			return 0; | ||||
| 		} | ||||
| @ -376,9 +398,10 @@ error: | ||||
| static int xdr_decode(nfs_readdir_descriptor_t *desc, | ||||
| 		      struct nfs_entry *entry, struct xdr_stream *xdr) | ||||
| { | ||||
| 	struct inode *inode = file_inode(desc->file); | ||||
| 	int error; | ||||
| 
 | ||||
| 	error = desc->decode(xdr, entry, desc->plus); | ||||
| 	error = NFS_PROTO(inode)->decode_dirent(xdr, entry, desc->plus); | ||||
| 	if (error) | ||||
| 		return error; | ||||
| 	entry->fattr->time_start = desc->timestamp; | ||||
| @ -756,6 +779,7 @@ int readdir_search_pagecache(nfs_readdir_descriptor_t *desc) | ||||
| 
 | ||||
| 	if (desc->page_index == 0) { | ||||
| 		desc->current_index = 0; | ||||
| 		desc->prev_index = 0; | ||||
| 		desc->last_cookie = 0; | ||||
| 	} | ||||
| 	do { | ||||
| @ -786,11 +810,14 @@ int nfs_do_filldir(nfs_readdir_descriptor_t *desc) | ||||
| 			desc->eof = true; | ||||
| 			break; | ||||
| 		} | ||||
| 		desc->ctx->pos++; | ||||
| 		if (i < (array->size-1)) | ||||
| 			*desc->dir_cookie = array->array[i+1].cookie; | ||||
| 		else | ||||
| 			*desc->dir_cookie = array->last_cookie; | ||||
| 		if (nfs_readdir_use_cookie(file)) | ||||
| 			desc->ctx->pos = *desc->dir_cookie; | ||||
| 		else | ||||
| 			desc->ctx->pos++; | ||||
| 		if (ctx->duped != 0) | ||||
| 			ctx->duped = 1; | ||||
| 	} | ||||
| @ -860,9 +887,14 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx) | ||||
| { | ||||
| 	struct dentry	*dentry = file_dentry(file); | ||||
| 	struct inode	*inode = d_inode(dentry); | ||||
| 	nfs_readdir_descriptor_t my_desc, | ||||
| 			*desc = &my_desc; | ||||
| 	struct nfs_open_dir_context *dir_ctx = file->private_data; | ||||
| 	nfs_readdir_descriptor_t my_desc = { | ||||
| 		.file = file, | ||||
| 		.ctx = ctx, | ||||
| 		.dir_cookie = &dir_ctx->dir_cookie, | ||||
| 		.plus = nfs_use_readdirplus(inode, ctx), | ||||
| 	}, | ||||
| 			*desc = &my_desc; | ||||
| 	int res = 0; | ||||
| 
 | ||||
| 	dfprintk(FILE, "NFS: readdir(%pD2) starting at cookie %llu\n", | ||||
| @ -875,14 +907,6 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx) | ||||
| 	 * to either find the entry with the appropriate number or | ||||
| 	 * revalidate the cookie. | ||||
| 	 */ | ||||
| 	memset(desc, 0, sizeof(*desc)); | ||||
| 
 | ||||
| 	desc->file = file; | ||||
| 	desc->ctx = ctx; | ||||
| 	desc->dir_cookie = &dir_ctx->dir_cookie; | ||||
| 	desc->decode = NFS_PROTO(inode)->decode_dirent; | ||||
| 	desc->plus = nfs_use_readdirplus(inode, ctx); | ||||
| 
 | ||||
| 	if (ctx->pos == 0 || nfs_attribute_cache_expired(inode)) | ||||
| 		res = nfs_revalidate_mapping(inode, file->f_mapping); | ||||
| 	if (res < 0) | ||||
| @ -954,7 +978,10 @@ static loff_t nfs_llseek_dir(struct file *filp, loff_t offset, int whence) | ||||
| 	} | ||||
| 	if (offset != filp->f_pos) { | ||||
| 		filp->f_pos = offset; | ||||
| 		dir_ctx->dir_cookie = 0; | ||||
| 		if (nfs_readdir_use_cookie(filp)) | ||||
| 			dir_ctx->dir_cookie = offset; | ||||
| 		else | ||||
| 			dir_ctx->dir_cookie = 0; | ||||
| 		dir_ctx->duped = 0; | ||||
| 	} | ||||
| 	inode_unlock(inode); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user