diff options
Diffstat (limited to 'fs/afs/inode.c')
| -rw-r--r-- | fs/afs/inode.c | 101 | 
1 files changed, 64 insertions, 37 deletions
| diff --git a/fs/afs/inode.c b/fs/afs/inode.c index 16906eb592d9..5964f8aee090 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c @@ -413,9 +413,9 @@ static void afs_get_inode_cache(struct afs_vnode *vnode)  {  #ifdef CONFIG_AFS_FSCACHE  	struct { -		u32 vnode_id; -		u32 unique; -		u32 vnode_id_ext[2];	/* Allow for a 96-bit key */ +		__be32 vnode_id; +		__be32 unique; +		__be32 vnode_id_ext[2];	/* Allow for a 96-bit key */  	} __packed key;  	struct afs_vnode_cache_aux aux; @@ -424,17 +424,18 @@ static void afs_get_inode_cache(struct afs_vnode *vnode)  		return;  	} -	key.vnode_id		= vnode->fid.vnode; -	key.unique		= vnode->fid.unique; -	key.vnode_id_ext[0]	= vnode->fid.vnode >> 32; -	key.vnode_id_ext[1]	= vnode->fid.vnode_hi; -	aux.data_version	= vnode->status.data_version; - -	vnode->cache = fscache_acquire_cookie(vnode->volume->cache, -					      &afs_vnode_cache_index_def, -					      &key, sizeof(key), -					      &aux, sizeof(aux), -					      vnode, vnode->status.size, true); +	key.vnode_id		= htonl(vnode->fid.vnode); +	key.unique		= htonl(vnode->fid.unique); +	key.vnode_id_ext[0]	= htonl(vnode->fid.vnode >> 32); +	key.vnode_id_ext[1]	= htonl(vnode->fid.vnode_hi); +	afs_set_cache_aux(vnode, &aux); + +	vnode->cache = fscache_acquire_cookie( +		vnode->volume->cache, +		vnode->status.type == AFS_FTYPE_FILE ? 0 : FSCACHE_ADV_SINGLE_CHUNK, +		&key, sizeof(key), +		&aux, sizeof(aux), +		vnode->status.size);  #endif  } @@ -563,9 +564,7 @@ static void afs_zap_data(struct afs_vnode *vnode)  {  	_enter("{%llx:%llu}", vnode->fid.vid, vnode->fid.vnode); -#ifdef CONFIG_AFS_FSCACHE -	fscache_invalidate(vnode->cache); -#endif +	afs_invalidate_cache(vnode, 0);  	/* nuke all the non-dirty pages that aren't locked, mapped or being  	 * written back in a regular file and completely discard the pages in a @@ -762,9 +761,8 @@ int afs_drop_inode(struct inode *inode)   */  void afs_evict_inode(struct inode *inode)  { -	struct afs_vnode *vnode; - -	vnode = AFS_FS_I(inode); +	struct afs_vnode_cache_aux aux; +	struct afs_vnode *vnode = AFS_FS_I(inode);  	_enter("{%llx:%llu.%d}",  	       vnode->fid.vid, @@ -776,6 +774,9 @@ void afs_evict_inode(struct inode *inode)  	ASSERTCMP(inode->i_ino, ==, vnode->fid.vnode);  	truncate_inode_pages_final(&inode->i_data); + +	afs_set_cache_aux(vnode, &aux); +	fscache_clear_inode_writeback(afs_vnode_cache(vnode), inode, &aux);  	clear_inode(inode);  	while (!list_empty(&vnode->wb_keys)) { @@ -786,14 +787,9 @@ void afs_evict_inode(struct inode *inode)  	}  #ifdef CONFIG_AFS_FSCACHE -	{ -		struct afs_vnode_cache_aux aux; - -		aux.data_version = vnode->status.data_version; -		fscache_relinquish_cookie(vnode->cache, &aux, -					  test_bit(AFS_VNODE_DELETED, &vnode->flags)); -		vnode->cache = NULL; -	} +	fscache_relinquish_cookie(vnode->cache, +				  test_bit(AFS_VNODE_DELETED, &vnode->flags)); +	vnode->cache = NULL;  #endif  	afs_prune_wb_keys(vnode); @@ -833,6 +829,9 @@ static void afs_setattr_edit_file(struct afs_operation *op)  		if (size < i_size)  			truncate_pagecache(inode, size); +		if (size != i_size) +			fscache_resize_cookie(afs_vnode_cache(vp->vnode), +					      vp->scb.status.size);  	}  } @@ -849,40 +848,67 @@ static const struct afs_operation_ops afs_setattr_operation = {  int afs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,  		struct iattr *attr)  { +	const unsigned int supported = +		ATTR_SIZE | ATTR_MODE | ATTR_UID | ATTR_GID | +		ATTR_MTIME | ATTR_MTIME_SET | ATTR_TIMES_SET | ATTR_TOUCH;  	struct afs_operation *op;  	struct afs_vnode *vnode = AFS_FS_I(d_inode(dentry)); +	struct inode *inode = &vnode->vfs_inode; +	loff_t i_size;  	int ret;  	_enter("{%llx:%llu},{n=%pd},%x",  	       vnode->fid.vid, vnode->fid.vnode, dentry,  	       attr->ia_valid); -	if (!(attr->ia_valid & (ATTR_SIZE | ATTR_MODE | ATTR_UID | ATTR_GID | -				ATTR_MTIME | ATTR_MTIME_SET | ATTR_TIMES_SET | -				ATTR_TOUCH))) { +	if (!(attr->ia_valid & supported)) {  		_leave(" = 0 [unsupported]");  		return 0;  	} +	i_size = i_size_read(inode);  	if (attr->ia_valid & ATTR_SIZE) { -		if (!S_ISREG(vnode->vfs_inode.i_mode)) +		if (!S_ISREG(inode->i_mode))  			return -EISDIR; -		ret = inode_newsize_ok(&vnode->vfs_inode, attr->ia_size); +		ret = inode_newsize_ok(inode, attr->ia_size);  		if (ret)  			return ret; -		if (attr->ia_size == i_size_read(&vnode->vfs_inode)) +		if (attr->ia_size == i_size)  			attr->ia_valid &= ~ATTR_SIZE;  	} -	/* flush any dirty data outstanding on a regular file */ -	if (S_ISREG(vnode->vfs_inode.i_mode)) -		filemap_write_and_wait(vnode->vfs_inode.i_mapping); +	fscache_use_cookie(afs_vnode_cache(vnode), true);  	/* Prevent any new writebacks from starting whilst we do this. */  	down_write(&vnode->validate_lock); +	if ((attr->ia_valid & ATTR_SIZE) && S_ISREG(inode->i_mode)) { +		loff_t size = attr->ia_size; + +		/* Wait for any outstanding writes to the server to complete */ +		loff_t from = min(size, i_size); +		loff_t to = max(size, i_size); +		ret = filemap_fdatawait_range(inode->i_mapping, from, to); +		if (ret < 0) +			goto out_unlock; + +		/* Don't talk to the server if we're just shortening in-memory +		 * writes that haven't gone to the server yet. +		 */ +		if (!(attr->ia_valid & (supported & ~ATTR_SIZE & ~ATTR_MTIME)) && +		    attr->ia_size < i_size && +		    attr->ia_size > vnode->status.size) { +			truncate_pagecache(inode, attr->ia_size); +			fscache_resize_cookie(afs_vnode_cache(vnode), +					      attr->ia_size); +			i_size_write(inode, attr->ia_size); +			ret = 0; +			goto out_unlock; +		} +	} +  	op = afs_alloc_operation(((attr->ia_valid & ATTR_FILE) ?  				  afs_file_key(attr->ia_file) : NULL),  				 vnode->volume); @@ -907,6 +933,7 @@ int afs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,  out_unlock:  	up_write(&vnode->validate_lock); +	fscache_unuse_cookie(afs_vnode_cache(vnode), NULL, NULL);  	_leave(" = %d", ret);  	return ret;  } |