diff options
Diffstat (limited to 'fs/afs')
| -rw-r--r-- | fs/afs/Kconfig | 7 | ||||
| -rw-r--r-- | fs/afs/afs.h | 11 | ||||
| -rw-r--r-- | fs/afs/afs_vl.h | 2 | ||||
| -rw-r--r-- | fs/afs/cache.c | 12 | ||||
| -rw-r--r-- | fs/afs/callback.c | 4 | ||||
| -rw-r--r-- | fs/afs/cell.c | 4 | ||||
| -rw-r--r-- | fs/afs/cmservice.c | 31 | ||||
| -rw-r--r-- | fs/afs/dir.c | 181 | ||||
| -rw-r--r-- | fs/afs/file.c | 20 | ||||
| -rw-r--r-- | fs/afs/flock.c | 15 | ||||
| -rw-r--r-- | fs/afs/fsclient.c | 27 | ||||
| -rw-r--r-- | fs/afs/inode.c | 29 | ||||
| -rw-r--r-- | fs/afs/internal.h | 12 | ||||
| -rw-r--r-- | fs/afs/main.c | 17 | ||||
| -rw-r--r-- | fs/afs/mntpt.c | 71 | ||||
| -rw-r--r-- | fs/afs/proc.c | 130 | ||||
| -rw-r--r-- | fs/afs/rxrpc.c | 89 | ||||
| -rw-r--r-- | fs/afs/security.c | 5 | ||||
| -rw-r--r-- | fs/afs/server.c | 13 | ||||
| -rw-r--r-- | fs/afs/super.c | 104 | ||||
| -rw-r--r-- | fs/afs/vlocation.c | 21 | ||||
| -rw-r--r-- | fs/afs/volume.c | 2 | ||||
| -rw-r--r-- | fs/afs/write.c | 59 | 
23 files changed, 374 insertions, 492 deletions
diff --git a/fs/afs/Kconfig b/fs/afs/Kconfig index 8f975f25b48..ebba3b18e5d 100644 --- a/fs/afs/Kconfig +++ b/fs/afs/Kconfig @@ -1,6 +1,6 @@  config AFS_FS -	tristate "Andrew File System support (AFS) (EXPERIMENTAL)" -	depends on INET && EXPERIMENTAL +	tristate "Andrew File System support (AFS)" +	depends on INET  	select AF_RXRPC  	select DNS_RESOLVER  	help @@ -22,8 +22,7 @@ config AFS_DEBUG  	  If unsure, say N.  config AFS_FSCACHE -	bool "Provide AFS client caching support (EXPERIMENTAL)" -	depends on EXPERIMENTAL +	bool "Provide AFS client caching support"  	depends on AFS_FS=m && FSCACHE || AFS_FS=y && FSCACHE=y  	help  	  Say Y here if you want AFS data to be cached locally on disk through diff --git a/fs/afs/afs.h b/fs/afs/afs.h index c548aa346f0..3c462ff6db6 100644 --- a/fs/afs/afs.h +++ b/fs/afs/afs.h @@ -119,8 +119,8 @@ struct afs_file_status {  	u64			size;		/* file size */  	afs_dataversion_t	data_version;	/* current data version */  	u32			author;		/* author ID */ -	u32			owner;		/* owner ID */ -	u32			group;		/* group ID */ +	kuid_t			owner;		/* owner ID */ +	kgid_t			group;		/* group ID */  	afs_access_t		caller_access;	/* access rights for authenticated caller */  	afs_access_t		anon_access;	/* access rights for unauthenticated caller */  	umode_t			mode;		/* UNIX mode */ @@ -133,13 +133,6 @@ struct afs_file_status {  /*   * AFS file status change request   */ -struct afs_store_status { -	u32			mask;		/* which bits of the struct are set */ -	u32			mtime_client;	/* last time client changed data */ -	u32			owner;		/* owner ID */ -	u32			group;		/* group ID */ -	umode_t			mode;		/* UNIX mode */ -};  #define AFS_SET_MTIME		0x01		/* set the mtime */  #define AFS_SET_OWNER		0x02		/* set the owner ID */ diff --git a/fs/afs/afs_vl.h b/fs/afs/afs_vl.h index 8bbefe009ed..800f607ffaf 100644 --- a/fs/afs/afs_vl.h +++ b/fs/afs/afs_vl.h @@ -49,7 +49,7 @@ enum AFSVL_Errors {  	AFSVL_BADVOLOPER 	= 363542,	/* Bad volume operation code */  	AFSVL_BADRELLOCKTYPE 	= 363543,	/* Bad release lock type */  	AFSVL_RERELEASE 	= 363544,	/* Status report: last release was aborted */ -	AFSVL_BADSERVERFLAG 	= 363545,	/* Invalid replication site server °ag */ +	AFSVL_BADSERVERFLAG 	= 363545,	/* Invalid replication site server flag */  	AFSVL_PERM 		= 363546,	/* No permission access */  	AFSVL_NOMEM 		= 363547,	/* malloc/realloc failed to alloc enough memory */  }; diff --git a/fs/afs/cache.c b/fs/afs/cache.c index 0fb315dd4d2..577763c3d88 100644 --- a/fs/afs/cache.c +++ b/fs/afs/cache.c @@ -98,7 +98,7 @@ static uint16_t afs_cell_cache_get_key(const void *cookie_netfs_data,  }  /* - * provide new auxilliary cache data + * provide new auxiliary cache data   */  static uint16_t afs_cell_cache_get_aux(const void *cookie_netfs_data,  				       void *buffer, uint16_t bufmax) @@ -117,7 +117,7 @@ static uint16_t afs_cell_cache_get_aux(const void *cookie_netfs_data,  }  /* - * check that the auxilliary data indicates that the entry is still valid + * check that the auxiliary data indicates that the entry is still valid   */  static enum fscache_checkaux afs_cell_cache_check_aux(void *cookie_netfs_data,  						      const void *buffer, @@ -150,7 +150,7 @@ static uint16_t afs_vlocation_cache_get_key(const void *cookie_netfs_data,  }  /* - * provide new auxilliary cache data + * provide new auxiliary cache data   */  static uint16_t afs_vlocation_cache_get_aux(const void *cookie_netfs_data,  					    void *buffer, uint16_t bufmax) @@ -172,7 +172,7 @@ static uint16_t afs_vlocation_cache_get_aux(const void *cookie_netfs_data,  }  /* - * check that the auxilliary data indicates that the entry is still valid + * check that the auxiliary data indicates that the entry is still valid   */  static  enum fscache_checkaux afs_vlocation_cache_check_aux(void *cookie_netfs_data, @@ -283,7 +283,7 @@ static void afs_vnode_cache_get_attr(const void *cookie_netfs_data,  }  /* - * provide new auxilliary cache data + * provide new auxiliary cache data   */  static uint16_t afs_vnode_cache_get_aux(const void *cookie_netfs_data,  					void *buffer, uint16_t bufmax) @@ -309,7 +309,7 @@ static uint16_t afs_vnode_cache_get_aux(const void *cookie_netfs_data,  }  /* - * check that the auxilliary data indicates that the entry is still valid + * check that the auxiliary data indicates that the entry is still valid   */  static enum fscache_checkaux afs_vnode_cache_check_aux(void *cookie_netfs_data,  						       const void *buffer, diff --git a/fs/afs/callback.c b/fs/afs/callback.c index 587ef5123cd..7ef637d7f3a 100644 --- a/fs/afs/callback.c +++ b/fs/afs/callback.c @@ -351,9 +351,7 @@ void afs_dispatch_give_up_callbacks(struct work_struct *work)   */  void afs_flush_callback_breaks(struct afs_server *server)  { -	cancel_delayed_work(&server->cb_break_work); -	queue_delayed_work(afs_callback_update_worker, -			   &server->cb_break_work, 0); +	mod_delayed_work(afs_callback_update_worker, &server->cb_break_work, 0);  }  #if 0 diff --git a/fs/afs/cell.c b/fs/afs/cell.c index 0d5eeadf612..ca0a3cf9379 100644 --- a/fs/afs/cell.c +++ b/fs/afs/cell.c @@ -179,7 +179,7 @@ struct afs_cell *afs_cell_create(const char *name, unsigned namesz,  	/* put it up for caching (this never returns an error) */  	cell->cache = fscache_acquire_cookie(afs_cache_netfs.primary_index,  					     &afs_cell_cache_index_def, -					     cell); +					     cell, true);  #endif  	/* add to the cell lists */ @@ -293,7 +293,7 @@ struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz,  		if (!cell) {  			/* this should not happen unless user tries to mount  			 * when root cell is not set. Return an impossibly -			 * bizzare errno to alert the user. Things like +			 * bizarre errno to alert the user. Things like  			 * ENOENT might be "more appropriate" but they happen  			 * for other reasons.  			 */ diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c index a3bcec75c54..4b0eff6da67 100644 --- a/fs/afs/cmservice.c +++ b/fs/afs/cmservice.c @@ -130,6 +130,15 @@ static void afs_cm_destructor(struct afs_call *call)  {  	_enter(""); +	/* Break the callbacks here so that we do it after the final ACK is +	 * received.  The step number here must match the final number in +	 * afs_deliver_cb_callback(). +	 */ +	if (call->unmarshall == 6) { +		ASSERT(call->server && call->count && call->request); +		afs_break_callbacks(call->server, call->count, call->request); +	} +  	afs_put_server(call->server);  	call->server = NULL;  	kfree(call->buffer); @@ -272,6 +281,16 @@ static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb,  		_debug("trailer");  		if (skb->len != 0)  			return -EBADMSG; + +		/* Record that the message was unmarshalled successfully so +		 * that the call destructor can know do the callback breaking +		 * work, even if the final ACK isn't received. +		 * +		 * If the step number changes, then afs_cm_destructor() must be +		 * updated also. +		 */ +		call->unmarshall++; +	case 6:  		break;  	} @@ -289,7 +308,7 @@ static int afs_deliver_cb_callback(struct afs_call *call, struct sk_buff *skb,  	call->server = server;  	INIT_WORK(&call->work, SRXAFSCB_CallBack); -	schedule_work(&call->work); +	queue_work(afs_wq, &call->work);  	return 0;  } @@ -336,7 +355,7 @@ static int afs_deliver_cb_init_call_back_state(struct afs_call *call,  	call->server = server;  	INIT_WORK(&call->work, SRXAFSCB_InitCallBackState); -	schedule_work(&call->work); +	queue_work(afs_wq, &call->work);  	return 0;  } @@ -367,7 +386,7 @@ static int afs_deliver_cb_init_call_back_state3(struct afs_call *call,  	call->server = server;  	INIT_WORK(&call->work, SRXAFSCB_InitCallBackState); -	schedule_work(&call->work); +	queue_work(afs_wq, &call->work);  	return 0;  } @@ -400,7 +419,7 @@ static int afs_deliver_cb_probe(struct afs_call *call, struct sk_buff *skb,  	call->state = AFS_CALL_REPLYING;  	INIT_WORK(&call->work, SRXAFSCB_Probe); -	schedule_work(&call->work); +	queue_work(afs_wq, &call->work);  	return 0;  } @@ -496,7 +515,7 @@ static int afs_deliver_cb_probe_uuid(struct afs_call *call, struct sk_buff *skb,  	call->state = AFS_CALL_REPLYING;  	INIT_WORK(&call->work, SRXAFSCB_ProbeUuid); -	schedule_work(&call->work); +	queue_work(afs_wq, &call->work);  	return 0;  } @@ -580,6 +599,6 @@ static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *call,  	call->state = AFS_CALL_REPLYING;  	INIT_WORK(&call->work, SRXAFSCB_TellMeAboutYourself); -	schedule_work(&call->work); +	queue_work(afs_wq, &call->work);  	return 0;  } diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 5439e1bc9a8..529300327f4 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -13,23 +13,24 @@  #include <linux/module.h>  #include <linux/init.h>  #include <linux/fs.h> +#include <linux/namei.h>  #include <linux/pagemap.h>  #include <linux/ctype.h>  #include <linux/sched.h>  #include "internal.h"  static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, -				 struct nameidata *nd); +				 unsigned int flags);  static int afs_dir_open(struct inode *inode, struct file *file); -static int afs_readdir(struct file *file, void *dirent, filldir_t filldir); -static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd); -static int afs_d_delete(struct dentry *dentry); +static int afs_readdir(struct file *file, struct dir_context *ctx); +static int afs_d_revalidate(struct dentry *dentry, unsigned int flags); +static int afs_d_delete(const struct dentry *dentry);  static void afs_d_release(struct dentry *dentry);  static int afs_lookup_filldir(void *_cookie, const char *name, int nlen,  				  loff_t fpos, u64 ino, unsigned dtype); -static int afs_create(struct inode *dir, struct dentry *dentry, int mode, -		      struct nameidata *nd); -static int afs_mkdir(struct inode *dir, struct dentry *dentry, int mode); +static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, +		      bool excl); +static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode);  static int afs_rmdir(struct inode *dir, struct dentry *dentry);  static int afs_unlink(struct inode *dir, struct dentry *dentry);  static int afs_link(struct dentry *from, struct inode *dir, @@ -42,7 +43,7 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,  const struct file_operations afs_dir_file_operations = {  	.open		= afs_dir_open,  	.release	= afs_release, -	.readdir	= afs_readdir, +	.iterate	= afs_readdir,  	.lock		= afs_lock,  	.llseek		= generic_file_llseek,  }; @@ -61,10 +62,11 @@ const struct inode_operations afs_dir_inode_operations = {  	.setattr	= afs_setattr,  }; -static const struct dentry_operations afs_fs_dentry_operations = { +const struct dentry_operations afs_fs_dentry_operations = {  	.d_revalidate	= afs_d_revalidate,  	.d_delete	= afs_d_delete,  	.d_release	= afs_d_release, +	.d_automount	= afs_d_automount,  };  #define AFS_DIR_HASHTBL_SIZE	128 @@ -117,9 +119,9 @@ struct afs_dir_page {  };  struct afs_lookup_cookie { +	struct dir_context ctx;  	struct afs_fid	fid; -	const char	*name; -	size_t		nlen; +	struct qstr name;  	int		found;  }; @@ -226,20 +228,18 @@ static int afs_dir_open(struct inode *inode, struct file *file)  /*   * deal with one block in an AFS directory   */ -static int afs_dir_iterate_block(unsigned *fpos, +static int afs_dir_iterate_block(struct dir_context *ctx,  				 union afs_dir_block *block, -				 unsigned blkoff, -				 void *cookie, -				 filldir_t filldir) +				 unsigned blkoff)  {  	union afs_dirent *dire;  	unsigned offset, next, curr;  	size_t nlen; -	int tmp, ret; +	int tmp; -	_enter("%u,%x,%p,,",*fpos,blkoff,block); +	_enter("%u,%x,%p,,",(unsigned)ctx->pos,blkoff,block); -	curr = (*fpos - blkoff) / sizeof(union afs_dirent); +	curr = (ctx->pos - blkoff) / sizeof(union afs_dirent);  	/* walk through the block, an entry at a time */  	for (offset = AFS_DIRENT_PER_BLOCK - block->pagehdr.nentries; @@ -254,7 +254,7 @@ static int afs_dir_iterate_block(unsigned *fpos,  			_debug("ENT[%Zu.%u]: unused",  			       blkoff / sizeof(union afs_dir_block), offset);  			if (offset >= curr) -				*fpos = blkoff + +				ctx->pos = blkoff +  					next * sizeof(union afs_dirent);  			continue;  		} @@ -300,19 +300,15 @@ static int afs_dir_iterate_block(unsigned *fpos,  			continue;  		/* found the next entry */ -		ret = filldir(cookie, -			      dire->u.name, -			      nlen, -			      blkoff + offset * sizeof(union afs_dirent), +		if (!dir_emit(ctx, dire->u.name, nlen,  			      ntohl(dire->u.vnode), -			      filldir == afs_lookup_filldir ? -			      ntohl(dire->u.unique) : DT_UNKNOWN); -		if (ret < 0) { +			      ctx->actor == afs_lookup_filldir ? +			      ntohl(dire->u.unique) : DT_UNKNOWN)) {  			_leave(" = 0 [full]");  			return 0;  		} -		*fpos = blkoff + next * sizeof(union afs_dirent); +		ctx->pos = blkoff + next * sizeof(union afs_dirent);  	}  	_leave(" = 1 [more]"); @@ -322,8 +318,8 @@ static int afs_dir_iterate_block(unsigned *fpos,  /*   * iterate through the data blob that lists the contents of an AFS directory   */ -static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie, -			   filldir_t filldir, struct key *key) +static int afs_dir_iterate(struct inode *dir, struct dir_context *ctx, +			   struct key *key)  {  	union afs_dir_block *dblock;  	struct afs_dir_page *dbuf; @@ -331,7 +327,7 @@ static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie,  	unsigned blkoff, limit;  	int ret; -	_enter("{%lu},%u,,", dir->i_ino, *fpos); +	_enter("{%lu},%u,,", dir->i_ino, (unsigned)ctx->pos);  	if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dir)->flags)) {  		_leave(" = -ESTALE"); @@ -339,13 +335,13 @@ static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie,  	}  	/* round the file position up to the next entry boundary */ -	*fpos += sizeof(union afs_dirent) - 1; -	*fpos &= ~(sizeof(union afs_dirent) - 1); +	ctx->pos += sizeof(union afs_dirent) - 1; +	ctx->pos &= ~(sizeof(union afs_dirent) - 1);  	/* walk through the blocks in sequence */  	ret = 0; -	while (*fpos < dir->i_size) { -		blkoff = *fpos & ~(sizeof(union afs_dir_block) - 1); +	while (ctx->pos < dir->i_size) { +		blkoff = ctx->pos & ~(sizeof(union afs_dir_block) - 1);  		/* fetch the appropriate page from the directory */  		page = afs_dir_get_page(dir, blkoff / PAGE_SIZE, key); @@ -362,8 +358,7 @@ static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie,  		do {  			dblock = &dbuf->blocks[(blkoff % PAGE_SIZE) /  					       sizeof(union afs_dir_block)]; -			ret = afs_dir_iterate_block(fpos, dblock, blkoff, -						    cookie, filldir); +			ret = afs_dir_iterate_block(ctx, dblock, blkoff);  			if (ret != 1) {  				afs_dir_put_page(page);  				goto out; @@ -371,7 +366,7 @@ static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie,  			blkoff += sizeof(union afs_dir_block); -		} while (*fpos < dir->i_size && blkoff < limit); +		} while (ctx->pos < dir->i_size && blkoff < limit);  		afs_dir_put_page(page);  		ret = 0; @@ -385,23 +380,10 @@ out:  /*   * read an AFS directory   */ -static int afs_readdir(struct file *file, void *cookie, filldir_t filldir) +static int afs_readdir(struct file *file, struct dir_context *ctx)  { -	unsigned fpos; -	int ret; - -	_enter("{%Ld,{%lu}}", -	       file->f_pos, file->f_path.dentry->d_inode->i_ino); - -	ASSERT(file->private_data != NULL); - -	fpos = file->f_pos; -	ret = afs_dir_iterate(file->f_path.dentry->d_inode, &fpos, -			      cookie, filldir, file->private_data); -	file->f_pos = fpos; - -	_leave(" = %d", ret); -	return ret; +	return afs_dir_iterate(file_inode(file),  +			      ctx, file->private_data);  }  /* @@ -414,15 +396,16 @@ static int afs_lookup_filldir(void *_cookie, const char *name, int nlen,  {  	struct afs_lookup_cookie *cookie = _cookie; -	_enter("{%s,%Zu},%s,%u,,%llu,%u", -	       cookie->name, cookie->nlen, name, nlen, +	_enter("{%s,%u},%s,%u,,%llu,%u", +	       cookie->name.name, cookie->name.len, name, nlen,  	       (unsigned long long) ino, dtype);  	/* insanity checks first */  	BUILD_BUG_ON(sizeof(union afs_dir_block) != 2048);  	BUILD_BUG_ON(sizeof(union afs_dirent) != 32); -	if (cookie->nlen != nlen || memcmp(cookie->name, name, nlen) != 0) { +	if (cookie->name.len != nlen || +	    memcmp(cookie->name.name, name, nlen) != 0) {  		_leave(" = 0 [no]");  		return 0;  	} @@ -442,24 +425,18 @@ static int afs_lookup_filldir(void *_cookie, const char *name, int nlen,  static int afs_do_lookup(struct inode *dir, struct dentry *dentry,  			 struct afs_fid *fid, struct key *key)  { -	struct afs_lookup_cookie cookie; -	struct afs_super_info *as; -	unsigned fpos; +	struct afs_super_info *as = dir->i_sb->s_fs_info; +	struct afs_lookup_cookie cookie = { +		.ctx.actor = afs_lookup_filldir, +		.name = dentry->d_name, +		.fid.vid = as->volume->vid +	};  	int ret;  	_enter("{%lu},%p{%s},", dir->i_ino, dentry, dentry->d_name.name); -	as = dir->i_sb->s_fs_info; -  	/* search the directory */ -	cookie.name	= dentry->d_name.name; -	cookie.nlen	= dentry->d_name.len; -	cookie.fid.vid	= as->volume->vid; -	cookie.found	= 0; - -	fpos = 0; -	ret = afs_dir_iterate(dir, &fpos, &cookie, afs_lookup_filldir, -			      key); +	ret = afs_dir_iterate(dir, &cookie.ctx, key);  	if (ret < 0) {  		_leave(" = %d [iter]", ret);  		return ret; @@ -514,7 +491,7 @@ out:   * look up an entry in a directory   */  static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, -				 struct nameidata *nd) +				 unsigned int flags)  {  	struct afs_vnode *vnode;  	struct afs_fid fid; @@ -581,14 +558,12 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,  	}  success: -	dentry->d_op = &afs_fs_dentry_operations; -  	d_add(dentry, inode); -	_leave(" = 0 { vn=%u u=%u } -> { ino=%lu v=%llu }", +	_leave(" = 0 { vn=%u u=%u } -> { ino=%lu v=%u }",  	       fid.vnode,  	       fid.unique,  	       dentry->d_inode->i_ino, -	       (unsigned long long)dentry->d_inode->i_version); +	       dentry->d_inode->i_generation);  	return NULL;  } @@ -598,7 +573,7 @@ success:   * - NOTE! the hit can be a negative hit too, so we can't assume we have an   *   inode   */ -static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd) +static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)  {  	struct afs_vnode *vnode, *dir;  	struct afs_fid uninitialized_var(fid); @@ -607,6 +582,9 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd)  	void *dir_version;  	int ret; +	if (flags & LOOKUP_RCU) +		return -ECHILD; +  	vnode = AFS_FS_I(dentry->d_inode);  	if (dentry->d_inode) @@ -622,9 +600,6 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd)  	/* lock down the parent dentry so we can peer at it */  	parent = dget_parent(dentry); -	if (!parent->d_inode) -		goto out_bad; -  	dir = AFS_FS_I(parent->d_inode);  	/* validate the parent directory */ @@ -668,10 +643,10 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd)  		 * been deleted and replaced, and the original vnode ID has  		 * been reused */  		if (fid.unique != vnode->fid.unique) { -			_debug("%s: file deleted (uq %u -> %u I:%llu)", +			_debug("%s: file deleted (uq %u -> %u I:%u)",  			       dentry->d_name.name, fid.unique,  			       vnode->fid.unique, -			       (unsigned long long)dentry->d_inode->i_version); +			       dentry->d_inode->i_generation);  			spin_lock(&vnode->lock);  			set_bit(AFS_VNODE_DELETED, &vnode->flags);  			spin_unlock(&vnode->lock); @@ -707,16 +682,12 @@ not_found:  	spin_unlock(&dentry->d_lock);  out_bad: -	if (dentry->d_inode) { -		/* don't unhash if we have submounts */ -		if (have_submounts(dentry)) -			goto out_skip; -	} +	/* don't unhash if we have submounts */ +	if (check_submounts_and_drop(dentry) != 0) +		goto out_skip;  	_debug("dropping dentry %s/%s",  	       parent->d_name.name, dentry->d_name.name); -	shrink_dcache_parent(dentry); -	d_drop(dentry);  	dput(parent);  	key_put(key); @@ -730,7 +701,7 @@ out_bad:   * - called from dput() when d_count is going to 0.   * - return 1 to request dentry be unhashed, 0 otherwise   */ -static int afs_d_delete(struct dentry *dentry) +static int afs_d_delete(const struct dentry *dentry)  {  	_enter("%s", dentry->d_name.name); @@ -761,7 +732,7 @@ static void afs_d_release(struct dentry *dentry)  /*   * create a directory on an AFS filesystem   */ -static int afs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)  {  	struct afs_file_status status;  	struct afs_callback cb; @@ -774,13 +745,9 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, int mode)  	dvnode = AFS_FS_I(dir); -	_enter("{%x:%u},{%s},%o", +	_enter("{%x:%u},{%s},%ho",  	       dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode); -	ret = -ENAMETOOLONG; -	if (dentry->d_name.len >= AFSNAMEMAX) -		goto error; -  	key = afs_request_key(dvnode->volume->cell);  	if (IS_ERR(key)) {  		ret = PTR_ERR(key); @@ -842,10 +809,6 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry)  	_enter("{%x:%u},{%s}",  	       dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name); -	ret = -ENAMETOOLONG; -	if (dentry->d_name.len >= AFSNAMEMAX) -		goto error; -  	key = afs_request_key(dvnode->volume->cell);  	if (IS_ERR(key)) {  		ret = PTR_ERR(key); @@ -945,8 +908,8 @@ error:  /*   * create a regular file on an AFS filesystem   */ -static int afs_create(struct inode *dir, struct dentry *dentry, int mode, -		      struct nameidata *nd) +static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode, +		      bool excl)  {  	struct afs_file_status status;  	struct afs_callback cb; @@ -959,13 +922,9 @@ static int afs_create(struct inode *dir, struct dentry *dentry, int mode,  	dvnode = AFS_FS_I(dir); -	_enter("{%x:%u},{%s},%o,", +	_enter("{%x:%u},{%s},%ho,",  	       dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode); -	ret = -ENAMETOOLONG; -	if (dentry->d_name.len >= AFSNAMEMAX) -		goto error; -  	key = afs_request_key(dvnode->volume->cell);  	if (IS_ERR(key)) {  		ret = PTR_ERR(key); @@ -1031,10 +990,6 @@ static int afs_link(struct dentry *from, struct inode *dir,  	       dvnode->fid.vid, dvnode->fid.vnode,  	       dentry->d_name.name); -	ret = -ENAMETOOLONG; -	if (dentry->d_name.len >= AFSNAMEMAX) -		goto error; -  	key = afs_request_key(dvnode->volume->cell);  	if (IS_ERR(key)) {  		ret = PTR_ERR(key); @@ -1079,10 +1034,6 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry,  	       dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name,  	       content); -	ret = -ENAMETOOLONG; -	if (dentry->d_name.len >= AFSNAMEMAX) -		goto error; -  	ret = -EINVAL;  	if (strlen(content) >= AFSPATHMAX)  		goto error; @@ -1153,10 +1104,6 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,  	       new_dvnode->fid.vid, new_dvnode->fid.vnode,  	       new_dentry->d_name.name); -	ret = -ENAMETOOLONG; -	if (new_dentry->d_name.len >= AFSNAMEMAX) -		goto error; -  	key = afs_request_key(orig_dvnode->volume->cell);  	if (IS_ERR(key)) {  		ret = PTR_ERR(key); diff --git a/fs/afs/file.c b/fs/afs/file.c index 14d89fa58fe..932ce07948b 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c @@ -19,7 +19,8 @@  #include "internal.h"  static int afs_readpage(struct file *file, struct page *page); -static void afs_invalidatepage(struct page *page, unsigned long offset); +static void afs_invalidatepage(struct page *page, unsigned int offset, +			       unsigned int length);  static int afs_releasepage(struct page *page, gfp_t gfp_flags);  static int afs_launder_page(struct page *page); @@ -30,10 +31,10 @@ const struct file_operations afs_file_operations = {  	.open		= afs_open,  	.release	= afs_release,  	.llseek		= generic_file_llseek, -	.read		= do_sync_read, -	.write		= do_sync_write, -	.aio_read	= generic_file_aio_read, -	.aio_write	= afs_file_write, +	.read		= new_sync_read, +	.write		= new_sync_write, +	.read_iter	= generic_file_read_iter, +	.write_iter	= afs_file_write,  	.mmap		= generic_file_readonly_mmap,  	.splice_read	= generic_file_splice_read,  	.fsync		= afs_fsync, @@ -251,7 +252,7 @@ static int afs_readpages(struct file *file, struct address_space *mapping,  	ASSERT(key != NULL);  	vnode = AFS_FS_I(mapping->host); -	if (vnode->flags & AFS_VNODE_DELETED) { +	if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {  		_leave(" = -ESTALE");  		return -ESTALE;  	} @@ -310,16 +311,17 @@ static int afs_launder_page(struct page *page)   * - release a page and clean up its private data if offset is 0 (indicating   *   the entire page)   */ -static void afs_invalidatepage(struct page *page, unsigned long offset) +static void afs_invalidatepage(struct page *page, unsigned int offset, +			       unsigned int length)  {  	struct afs_writeback *wb = (struct afs_writeback *) page_private(page); -	_enter("{%lu},%lu", page->index, offset); +	_enter("{%lu},%u,%u", page->index, offset, length);  	BUG_ON(!PageLocked(page));  	/* we clean up only if the entire page is being invalidated */ -	if (offset == 0) { +	if (offset == 0 && length == PAGE_CACHE_SIZE) {  #ifdef CONFIG_AFS_FSCACHE  		if (PageFsCache(page)) {  			struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); diff --git a/fs/afs/flock.c b/fs/afs/flock.c index 757d664575d..4baf1d2b39e 100644 --- a/fs/afs/flock.c +++ b/fs/afs/flock.c @@ -252,7 +252,8 @@ static void afs_defer_unlock(struct afs_vnode *vnode, struct key *key)   */  static int afs_do_setlk(struct file *file, struct file_lock *fl)  { -	struct afs_vnode *vnode = AFS_FS_I(file->f_mapping->host); +	struct inode *inode = file_inode(file); +	struct afs_vnode *vnode = AFS_FS_I(inode);  	afs_lock_type_t type;  	struct key *key = file->private_data;  	int ret; @@ -273,7 +274,7 @@ static int afs_do_setlk(struct file *file, struct file_lock *fl)  	type = (fl->fl_type == F_RDLCK) ? AFS_LOCK_READ : AFS_LOCK_WRITE; -	lock_flocks(); +	spin_lock(&inode->i_lock);  	/* make sure we've got a callback on this file and that our view of the  	 * data version is up to date */ @@ -420,7 +421,7 @@ given_lock:  	afs_vnode_fetch_status(vnode, NULL, key);  error: -	unlock_flocks(); +	spin_unlock(&inode->i_lock);  	_leave(" = %d", ret);  	return ret; @@ -514,7 +515,7 @@ error:   */  int afs_lock(struct file *file, int cmd, struct file_lock *fl)  { -	struct afs_vnode *vnode = AFS_FS_I(file->f_dentry->d_inode); +	struct afs_vnode *vnode = AFS_FS_I(file_inode(file));  	_enter("{%x:%u},%d,{t=%x,fl=%x,r=%Ld:%Ld}",  	       vnode->fid.vid, vnode->fid.vnode, cmd, @@ -537,7 +538,7 @@ int afs_lock(struct file *file, int cmd, struct file_lock *fl)   */  int afs_flock(struct file *file, int cmd, struct file_lock *fl)  { -	struct afs_vnode *vnode = AFS_FS_I(file->f_dentry->d_inode); +	struct afs_vnode *vnode = AFS_FS_I(file_inode(file));  	_enter("{%x:%u},%d,{t=%x,fl=%x}",  	       vnode->fid.vid, vnode->fid.vnode, cmd, @@ -554,10 +555,6 @@ int afs_flock(struct file *file, int cmd, struct file_lock *fl)  		return -ENOLCK;  	/* we're simulating flock() locks using posix locks on the server */ -	fl->fl_owner = (fl_owner_t) file; -	fl->fl_start = 0; -	fl->fl_end = OFFSET_MAX; -  	if (fl->fl_type == F_UNLCK)  		return afs_do_unlk(file, fl);  	return afs_do_setlk(file, fl); diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index 4bd0218473a..c2e930ec288 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c @@ -42,6 +42,8 @@ static void xdr_decode_AFSFetchStatus(const __be32 **_bp,  	umode_t mode;  	u64 data_version, size;  	u32 changed = 0; /* becomes non-zero if ctime-type changes seen */ +	kuid_t owner; +	kgid_t group;  #define EXTRACT(DST)				\  	do {					\ @@ -56,7 +58,9 @@ static void xdr_decode_AFSFetchStatus(const __be32 **_bp,  	size = ntohl(*bp++);  	data_version = ntohl(*bp++);  	EXTRACT(status->author); -	EXTRACT(status->owner); +	owner = make_kuid(&init_user_ns, ntohl(*bp++)); +	changed |= !uid_eq(owner, status->owner); +	status->owner = owner;  	EXTRACT(status->caller_access); /* call ticket dependent */  	EXTRACT(status->anon_access);  	EXTRACT(status->mode); @@ -65,7 +69,9 @@ static void xdr_decode_AFSFetchStatus(const __be32 **_bp,  	bp++; /* seg size */  	status->mtime_client = ntohl(*bp++);  	status->mtime_server = ntohl(*bp++); -	EXTRACT(status->group); +	group = make_kgid(&init_user_ns, ntohl(*bp++)); +	changed |= !gid_eq(group, status->group); +	status->group = group;  	bp++; /* sync counter */  	data_version |= (u64) ntohl(*bp++) << 32;  	EXTRACT(status->lock_count); @@ -89,8 +95,8 @@ static void xdr_decode_AFSFetchStatus(const __be32 **_bp,  			i_size_write(&vnode->vfs_inode, size);  			vnode->vfs_inode.i_uid = status->owner;  			vnode->vfs_inode.i_gid = status->group; -			vnode->vfs_inode.i_version = vnode->fid.unique; -			vnode->vfs_inode.i_nlink = status->nlink; +			vnode->vfs_inode.i_generation = vnode->fid.unique; +			set_nlink(&vnode->vfs_inode, status->nlink);  			mode = vnode->vfs_inode.i_mode;  			mode &= ~S_IALLUGO; @@ -102,6 +108,7 @@ static void xdr_decode_AFSFetchStatus(const __be32 **_bp,  		vnode->vfs_inode.i_ctime.tv_sec	= status->mtime_server;  		vnode->vfs_inode.i_mtime	= vnode->vfs_inode.i_ctime;  		vnode->vfs_inode.i_atime	= vnode->vfs_inode.i_ctime; +		vnode->vfs_inode.i_version	= data_version;  	}  	expected_version = status->data_version; @@ -180,12 +187,12 @@ static void xdr_encode_AFS_StoreStatus(__be32 **_bp, struct iattr *attr)  	if (attr->ia_valid & ATTR_UID) {  		mask |= AFS_SET_OWNER; -		owner = attr->ia_uid; +		owner = from_kuid(&init_user_ns, attr->ia_uid);  	}  	if (attr->ia_valid & ATTR_GID) {  		mask |= AFS_SET_GROUP; -		group = attr->ia_gid; +		group = from_kgid(&init_user_ns, attr->ia_gid);  	}  	if (attr->ia_valid & ATTR_MODE) { @@ -364,10 +371,10 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call,  		_debug("extract data");  		if (call->count > 0) {  			page = call->reply3; -			buffer = kmap_atomic(page, KM_USER0); +			buffer = kmap_atomic(page);  			ret = afs_extract_data(call, skb, last, buffer,  					       call->count); -			kunmap_atomic(buffer, KM_USER0); +			kunmap_atomic(buffer);  			switch (ret) {  			case 0:		break;  			case -EAGAIN:	return 0; @@ -410,9 +417,9 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call,  	if (call->count < PAGE_SIZE) {  		_debug("clear");  		page = call->reply3; -		buffer = kmap_atomic(page, KM_USER0); +		buffer = kmap_atomic(page);  		memset(buffer + call->count, 0, PAGE_SIZE - call->count); -		kunmap_atomic(buffer, KM_USER0); +		kunmap_atomic(buffer);  	}  	_leave(" = 0 [done]"); diff --git a/fs/afs/inode.c b/fs/afs/inode.c index 0747339011c..29467128844 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c @@ -67,15 +67,16 @@ static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key)  		fscache_attr_changed(vnode->cache);  #endif -	inode->i_nlink		= vnode->status.nlink; +	set_nlink(inode, vnode->status.nlink);  	inode->i_uid		= vnode->status.owner; -	inode->i_gid		= 0; +	inode->i_gid		= GLOBAL_ROOT_GID;  	inode->i_size		= vnode->status.size;  	inode->i_ctime.tv_sec	= vnode->status.mtime_server;  	inode->i_ctime.tv_nsec	= 0;  	inode->i_atime		= inode->i_mtime = inode->i_ctime;  	inode->i_blocks		= 0; -	inode->i_version	= vnode->fid.unique; +	inode->i_generation	= vnode->fid.unique; +	inode->i_version	= vnode->status.data_version;  	inode->i_mapping->a_ops	= &afs_fs_aops;  	/* check to see whether a symbolic link is really a mountpoint */ @@ -100,7 +101,7 @@ static int afs_iget5_test(struct inode *inode, void *opaque)  	struct afs_iget_data *data = opaque;  	return inode->i_ino == data->fid.vnode && -		inode->i_version == data->fid.unique; +		inode->i_generation == data->fid.unique;  }  /* @@ -122,7 +123,7 @@ static int afs_iget5_set(struct inode *inode, void *opaque)  	struct afs_vnode *vnode = AFS_FS_I(inode);  	inode->i_ino = data->fid.vnode; -	inode->i_version = data->fid.unique; +	inode->i_generation = data->fid.unique;  	vnode->fid = data->fid;  	vnode->volume = data->volume; @@ -173,9 +174,9 @@ struct inode *afs_iget_autocell(struct inode *dir, const char *dev_name,  	inode->i_size		= 0;  	inode->i_mode		= S_IFDIR | S_IRUGO | S_IXUGO;  	inode->i_op		= &afs_autocell_inode_operations; -	inode->i_nlink		= 2; -	inode->i_uid		= 0; -	inode->i_gid		= 0; +	set_nlink(inode, 2); +	inode->i_uid		= GLOBAL_ROOT_UID; +	inode->i_gid		= GLOBAL_ROOT_GID;  	inode->i_ctime.tv_sec	= get_seconds();  	inode->i_ctime.tv_nsec	= 0;  	inode->i_atime		= inode->i_mtime = inode->i_ctime; @@ -184,7 +185,8 @@ struct inode *afs_iget_autocell(struct inode *dir, const char *dev_name,  	inode->i_generation	= 0;  	set_bit(AFS_VNODE_PSEUDODIR, &vnode->flags); -	inode->i_flags |= S_NOATIME; +	set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags); +	inode->i_flags |= S_AUTOMOUNT | S_NOATIME;  	unlock_new_inode(inode);  	_leave(" = %p", inode);  	return inode; @@ -257,7 +259,7 @@ struct inode *afs_iget(struct super_block *sb, struct key *key,  #ifdef CONFIG_AFS_FSCACHE  	vnode->cache = fscache_acquire_cookie(vnode->volume->cache,  					      &afs_vnode_cache_index_def, -					      vnode); +					      vnode, true);  #endif  	ret = afs_inode_map_status(vnode, key); @@ -379,8 +381,7 @@ int afs_getattr(struct vfsmount *mnt, struct dentry *dentry,  	inode = dentry->d_inode; -	_enter("{ ino=%lu v=%llu }", inode->i_ino, -		(unsigned long long)inode->i_version); +	_enter("{ ino=%lu v=%u }", inode->i_ino, inode->i_generation);  	generic_fillattr(inode, stat);  	return 0; @@ -421,8 +422,8 @@ void afs_evict_inode(struct inode *inode)  	ASSERTCMP(inode->i_ino, ==, vnode->fid.vnode); -	truncate_inode_pages(&inode->i_data, 0); -	end_writeback(inode); +	truncate_inode_pages_final(&inode->i_data); +	clear_inode(inode);  	afs_give_up_callback(vnode); diff --git a/fs/afs/internal.h b/fs/afs/internal.h index cca8eef736f..71d5982312f 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -75,6 +75,7 @@ struct afs_call {  	const struct afs_call_type *type;	/* type of call */  	const struct afs_wait_mode *wait_mode;	/* completion wait mode */  	wait_queue_head_t	waitq;		/* processes awaiting completion */ +	void (*async_workfn)(struct afs_call *call); /* asynchronous work function */  	struct work_struct	async_work;	/* asynchronous work processor */  	struct work_struct	work;		/* actual work processor */  	struct sk_buff_head	rx_queue;	/* received packets */ @@ -109,7 +110,7 @@ struct afs_call {  	unsigned		reply_size;	/* current size of reply */  	unsigned		first_offset;	/* offset into mapping[first] */  	unsigned		last_to;	/* amount of mapping[last] */ -	unsigned short		offset;		/* offset into received data store */ +	unsigned		offset;		/* offset into received data store */  	unsigned char		unmarshall;	/* unmarshalling phase */  	bool			incoming;	/* T if incoming call */  	bool			send_pages;	/* T if data from mapping should be sent */ @@ -195,7 +196,6 @@ struct afs_cell {  	struct list_head	link;		/* main cell list link */  	struct key		*anonymous_key;	/* anonymous user key for this cell */  	struct list_head	proc_link;	/* /proc cell list link */ -	struct proc_dir_entry	*proc_dir;	/* /proc dir for this cell */  #ifdef CONFIG_AFS_FSCACHE  	struct fscache_cookie	*cache;		/* caching cookie */  #endif @@ -486,6 +486,7 @@ extern bool afs_cm_incoming_call(struct afs_call *);   * dir.c   */  extern const struct inode_operations afs_dir_inode_operations; +extern const struct dentry_operations afs_fs_dentry_operations;  extern const struct file_operations afs_dir_file_operations;  /* @@ -576,6 +577,7 @@ extern int afs_drop_inode(struct inode *);  /*   * main.c   */ +extern struct workqueue_struct *afs_wq;  extern struct afs_uuid afs_uuid;  /* @@ -590,6 +592,7 @@ extern const struct inode_operations afs_mntpt_inode_operations;  extern const struct inode_operations afs_autocell_inode_operations;  extern const struct file_operations afs_mntpt_file_operations; +extern struct vfsmount *afs_d_automount(struct path *);  extern int afs_mntpt_check_symlink(struct afs_vnode *, struct key *);  extern void afs_mntpt_kill_timer(void); @@ -744,10 +747,9 @@ extern int afs_write_end(struct file *file, struct address_space *mapping,  extern int afs_writepage(struct page *, struct writeback_control *);  extern int afs_writepages(struct address_space *, struct writeback_control *);  extern void afs_pages_written_back(struct afs_vnode *, struct afs_call *); -extern ssize_t afs_file_write(struct kiocb *, const struct iovec *, -			      unsigned long, loff_t); +extern ssize_t afs_file_write(struct kiocb *, struct iov_iter *);  extern int afs_writeback_all(struct afs_vnode *); -extern int afs_fsync(struct file *, int); +extern int afs_fsync(struct file *, loff_t, loff_t, int);  /*****************************************************************************/ diff --git a/fs/afs/main.c b/fs/afs/main.c index cfd1cbe25b2..35de0c04729 100644 --- a/fs/afs/main.c +++ b/fs/afs/main.c @@ -30,6 +30,7 @@ module_param(rootcell, charp, 0);  MODULE_PARM_DESC(rootcell, "root AFS cell name and VL server IP addr list");  struct afs_uuid afs_uuid; +struct workqueue_struct *afs_wq;  /*   * get a client UUID @@ -54,13 +55,13 @@ static int __init afs_get_client_UUID(void)  	afs_uuid.time_low = uuidtime;  	afs_uuid.time_mid = uuidtime >> 32;  	afs_uuid.time_hi_and_version = (uuidtime >> 48) & AFS_UUID_TIMEHI_MASK; -	afs_uuid.time_hi_and_version = AFS_UUID_VERSION_TIME; +	afs_uuid.time_hi_and_version |= AFS_UUID_VERSION_TIME;  	get_random_bytes(&clockseq, 2);  	afs_uuid.clock_seq_low = clockseq;  	afs_uuid.clock_seq_hi_and_reserved =  		(clockseq >> 8) & AFS_UUID_CLOCKHI_MASK; -	afs_uuid.clock_seq_hi_and_reserved = AFS_UUID_VARIANT_STD; +	afs_uuid.clock_seq_hi_and_reserved |= AFS_UUID_VARIANT_STD;  	_debug("AFS UUID: %08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",  	       afs_uuid.time_low, @@ -87,10 +88,16 @@ static int __init afs_init(void)  	if (ret < 0)  		return ret; +	/* create workqueue */ +	ret = -ENOMEM; +	afs_wq = alloc_workqueue("afs", 0, 0); +	if (!afs_wq) +		return ret; +  	/* register the /proc stuff */  	ret = afs_proc_init();  	if (ret < 0) -		return ret; +		goto error_proc;  #ifdef CONFIG_AFS_FSCACHE  	/* we want to be able to cache */ @@ -140,6 +147,8 @@ error_cell_init:  error_cache:  #endif  	afs_proc_cleanup(); +error_proc: +	destroy_workqueue(afs_wq);  	rcu_barrier();  	printk(KERN_ERR "kAFS: failed to register: %d\n", ret);  	return ret; @@ -163,7 +172,7 @@ static void __exit afs_exit(void)  	afs_purge_servers();  	afs_callback_update_kill();  	afs_vlocation_purge(); -	flush_scheduled_work(); +	destroy_workqueue(afs_wq);  	afs_cell_purge();  #ifdef CONFIG_AFS_FSCACHE  	fscache_unregister_netfs(&afs_cache_netfs); diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c index 6153417caf5..9682c33d5da 100644 --- a/fs/afs/mntpt.c +++ b/fs/afs/mntpt.c @@ -22,9 +22,8 @@  static struct dentry *afs_mntpt_lookup(struct inode *dir,  				       struct dentry *dentry, -				       struct nameidata *nd); +				       unsigned int flags);  static int afs_mntpt_open(struct inode *inode, struct file *file); -static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd);  static void afs_mntpt_expiry_timed_out(struct work_struct *work);  const struct file_operations afs_mntpt_file_operations = { @@ -34,13 +33,11 @@ const struct file_operations afs_mntpt_file_operations = {  const struct inode_operations afs_mntpt_inode_operations = {  	.lookup		= afs_mntpt_lookup, -	.follow_link	= afs_mntpt_follow_link,  	.readlink	= page_readlink,  	.getattr	= afs_getattr,  };  const struct inode_operations afs_autocell_inode_operations = { -	.follow_link	= afs_mntpt_follow_link,  	.getattr	= afs_getattr,  }; @@ -88,6 +85,7 @@ int afs_mntpt_check_symlink(struct afs_vnode *vnode, struct key *key)  		_debug("symlink is a mountpoint");  		spin_lock(&vnode->lock);  		set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags); +		vnode->vfs_inode.i_flags |= S_AUTOMOUNT;  		spin_unlock(&vnode->lock);  	} @@ -106,7 +104,7 @@ out:   */  static struct dentry *afs_mntpt_lookup(struct inode *dir,  				       struct dentry *dentry, -				       struct nameidata *nd) +				       unsigned int flags)  {  	_enter("%p,%p{%p{%s},%s}",  	       dir, @@ -202,9 +200,9 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)  		if (PageError(page))  			goto error; -		buf = kmap_atomic(page, KM_USER0); +		buf = kmap_atomic(page);  		memcpy(devname, buf, size); -		kunmap_atomic(buf, KM_USER0); +		kunmap_atomic(buf);  		page_cache_release(page);  		page = NULL;  	} @@ -238,52 +236,24 @@ error_no_devname:  }  /* - * follow a link from a mountpoint directory, thus causing it to be mounted + * handle an automount point   */ -static void *afs_mntpt_follow_link(struct dentry *dentry, struct nameidata *nd) +struct vfsmount *afs_d_automount(struct path *path)  {  	struct vfsmount *newmnt; -	int err; -	_enter("%p{%s},{%s:%p{%s},}", -	       dentry, -	       dentry->d_name.name, -	       nd->path.mnt->mnt_devname, -	       dentry, -	       nd->path.dentry->d_name.name); - -	dput(nd->path.dentry); -	nd->path.dentry = dget(dentry); +	_enter("{%s}", path->dentry->d_name.name); -	newmnt = afs_mntpt_do_automount(nd->path.dentry); -	if (IS_ERR(newmnt)) { -		path_put(&nd->path); -		return (void *)newmnt; -	} - -	mntget(newmnt); -	err = do_add_mount(newmnt, &nd->path, MNT_SHRINKABLE, &afs_vfsmounts); -	switch (err) { -	case 0: -		path_put(&nd->path); -		nd->path.mnt = newmnt; -		nd->path.dentry = dget(newmnt->mnt_root); -		schedule_delayed_work(&afs_mntpt_expiry_timer, -				      afs_mntpt_expiry_timeout * HZ); -		break; -	case -EBUSY: -		/* someone else made a mount here whilst we were busy */ -		while (d_mountpoint(nd->path.dentry) && -		       follow_down(&nd->path)) -			; -		err = 0; -	default: -		mntput(newmnt); -		break; -	} +	newmnt = afs_mntpt_do_automount(path->dentry); +	if (IS_ERR(newmnt)) +		return newmnt; -	_leave(" = %d", err); -	return ERR_PTR(err); +	mntget(newmnt); /* prevent immediate expiration */ +	mnt_set_expiry(newmnt, &afs_vfsmounts); +	queue_delayed_work(afs_wq, &afs_mntpt_expiry_timer, +			   afs_mntpt_expiry_timeout * HZ); +	_leave(" = %p", newmnt); +	return newmnt;  }  /* @@ -295,8 +265,8 @@ static void afs_mntpt_expiry_timed_out(struct work_struct *work)  	if (!list_empty(&afs_vfsmounts)) {  		mark_mounts_for_expiry(&afs_vfsmounts); -		schedule_delayed_work(&afs_mntpt_expiry_timer, -				      afs_mntpt_expiry_timeout * HZ); +		queue_delayed_work(afs_wq, &afs_mntpt_expiry_timer, +				   afs_mntpt_expiry_timeout * HZ);  	}  	_leave(""); @@ -310,6 +280,5 @@ void afs_mntpt_kill_timer(void)  	_enter("");  	ASSERT(list_empty(&afs_vfsmounts)); -	cancel_delayed_work(&afs_mntpt_expiry_timer); -	flush_scheduled_work(); +	cancel_delayed_work_sync(&afs_mntpt_expiry_timer);  } diff --git a/fs/afs/proc.c b/fs/afs/proc.c index 096b23f821a..24a905b076f 100644 --- a/fs/afs/proc.c +++ b/fs/afs/proc.c @@ -41,11 +41,8 @@ static const struct file_operations afs_proc_cells_fops = {  	.write		= afs_proc_cells_write,  	.llseek		= seq_lseek,  	.release	= seq_release, -	.owner		= THIS_MODULE,  }; -static int afs_proc_rootcell_open(struct inode *inode, struct file *file); -static int afs_proc_rootcell_release(struct inode *inode, struct file *file);  static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf,  				      size_t size, loff_t *_pos);  static ssize_t afs_proc_rootcell_write(struct file *file, @@ -53,17 +50,12 @@ static ssize_t afs_proc_rootcell_write(struct file *file,  				       size_t size, loff_t *_pos);  static const struct file_operations afs_proc_rootcell_fops = { -	.open		= afs_proc_rootcell_open,  	.read		= afs_proc_rootcell_read,  	.write		= afs_proc_rootcell_write,  	.llseek		= no_llseek, -	.release	= afs_proc_rootcell_release, -	.owner		= THIS_MODULE,  };  static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file); -static int afs_proc_cell_volumes_release(struct inode *inode, -					 struct file *file);  static void *afs_proc_cell_volumes_start(struct seq_file *p, loff_t *pos);  static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v,  					loff_t *pos); @@ -81,14 +73,11 @@ static const struct file_operations afs_proc_cell_volumes_fops = {  	.open		= afs_proc_cell_volumes_open,  	.read		= seq_read,  	.llseek		= seq_lseek, -	.release	= afs_proc_cell_volumes_release, -	.owner		= THIS_MODULE, +	.release	= seq_release,  };  static int afs_proc_cell_vlservers_open(struct inode *inode,  					struct file *file); -static int afs_proc_cell_vlservers_release(struct inode *inode, -					   struct file *file);  static void *afs_proc_cell_vlservers_start(struct seq_file *p, loff_t *pos);  static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v,  					  loff_t *pos); @@ -106,13 +95,10 @@ static const struct file_operations afs_proc_cell_vlservers_fops = {  	.open		= afs_proc_cell_vlservers_open,  	.read		= seq_read,  	.llseek		= seq_lseek, -	.release	= afs_proc_cell_vlservers_release, -	.owner		= THIS_MODULE, +	.release	= seq_release,  };  static int afs_proc_cell_servers_open(struct inode *inode, struct file *file); -static int afs_proc_cell_servers_release(struct inode *inode, -					 struct file *file);  static void *afs_proc_cell_servers_start(struct seq_file *p, loff_t *pos);  static void *afs_proc_cell_servers_next(struct seq_file *p, void *v,  					loff_t *pos); @@ -130,8 +116,7 @@ static const struct file_operations afs_proc_cell_servers_fops = {  	.open		= afs_proc_cell_servers_open,  	.read		= seq_read,  	.llseek		= seq_lseek, -	.release	= afs_proc_cell_servers_release, -	.owner		= THIS_MODULE, +	.release	= seq_release,  };  /* @@ -139,29 +124,21 @@ static const struct file_operations afs_proc_cell_servers_fops = {   */  int afs_proc_init(void)  { -	struct proc_dir_entry *p; -  	_enter("");  	proc_afs = proc_mkdir("fs/afs", NULL);  	if (!proc_afs)  		goto error_dir; -	p = proc_create("cells", 0, proc_afs, &afs_proc_cells_fops); -	if (!p) -		goto error_cells; - -	p = proc_create("rootcell", 0, proc_afs, &afs_proc_rootcell_fops); -	if (!p) -		goto error_rootcell; +	if (!proc_create("cells", 0644, proc_afs, &afs_proc_cells_fops) || +	    !proc_create("rootcell", 0644, proc_afs, &afs_proc_rootcell_fops)) +		goto error_tree;  	_leave(" = 0");  	return 0; -error_rootcell: - 	remove_proc_entry("cells", proc_afs); -error_cells: -	remove_proc_entry("fs/afs", NULL); +error_tree: +	remove_proc_subtree("fs/afs", NULL);  error_dir:  	_leave(" = -ENOMEM");  	return -ENOMEM; @@ -172,9 +149,7 @@ error_dir:   */  void afs_proc_cleanup(void)  { -	remove_proc_entry("rootcell", proc_afs); -	remove_proc_entry("cells", proc_afs); -	remove_proc_entry("fs/afs", NULL); +	remove_proc_subtree("fs/afs", NULL);  }  /* @@ -190,7 +165,7 @@ static int afs_proc_cells_open(struct inode *inode, struct file *file)  		return ret;  	m = file->private_data; -	m->private = PDE(inode)->data; +	m->private = PDE_DATA(inode);  	return 0;  } @@ -319,19 +294,6 @@ inval:  	goto done;  } -/* - * Stubs for /proc/fs/afs/rootcell - */ -static int afs_proc_rootcell_open(struct inode *inode, struct file *file) -{ -	return 0; -} - -static int afs_proc_rootcell_release(struct inode *inode, struct file *file) -{ -	return 0; -} -  static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf,  				      size_t size, loff_t *_pos)  { @@ -387,38 +349,27 @@ nomem:   */  int afs_proc_cell_setup(struct afs_cell *cell)  { -	struct proc_dir_entry *p; +	struct proc_dir_entry *dir;  	_enter("%p{%s}", cell, cell->name); -	cell->proc_dir = proc_mkdir(cell->name, proc_afs); -	if (!cell->proc_dir) +	dir = proc_mkdir(cell->name, proc_afs); +	if (!dir)  		goto error_dir; -	p = proc_create_data("servers", 0, cell->proc_dir, -			     &afs_proc_cell_servers_fops, cell); -	if (!p) -		goto error_servers; - -	p = proc_create_data("vlservers", 0, cell->proc_dir, -			     &afs_proc_cell_vlservers_fops, cell); -	if (!p) -		goto error_vlservers; - -	p = proc_create_data("volumes", 0, cell->proc_dir, -			     &afs_proc_cell_volumes_fops, cell); -	if (!p) -		goto error_volumes; +	if (!proc_create_data("servers", 0, dir, +			     &afs_proc_cell_servers_fops, cell) || +	    !proc_create_data("vlservers", 0, dir, +			     &afs_proc_cell_vlservers_fops, cell) || +	    !proc_create_data("volumes", 0, dir, +			     &afs_proc_cell_volumes_fops, cell)) +		goto error_tree;  	_leave(" = 0");  	return 0; -error_volumes: -	remove_proc_entry("vlservers", cell->proc_dir); -error_vlservers: -	remove_proc_entry("servers", cell->proc_dir); -error_servers: -	remove_proc_entry(cell->name, proc_afs); +error_tree: +	remove_proc_subtree(cell->name, proc_afs);  error_dir:  	_leave(" = -ENOMEM");  	return -ENOMEM; @@ -431,10 +382,7 @@ void afs_proc_cell_remove(struct afs_cell *cell)  {  	_enter(""); -	remove_proc_entry("volumes", cell->proc_dir); -	remove_proc_entry("vlservers", cell->proc_dir); -	remove_proc_entry("servers", cell->proc_dir); -	remove_proc_entry(cell->name, proc_afs); +	remove_proc_subtree(cell->name, proc_afs);  	_leave("");  } @@ -448,7 +396,7 @@ static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file)  	struct seq_file *m;  	int ret; -	cell = PDE(inode)->data; +	cell = PDE_DATA(inode);  	if (!cell)  		return -ENOENT; @@ -463,14 +411,6 @@ static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file)  }  /* - * close the file and release the ref to the cell - */ -static int afs_proc_cell_volumes_release(struct inode *inode, struct file *file) -{ -	return seq_release(inode, file); -} - -/*   * set up the iterator to start reading from the cells list and return the   * first item   */ @@ -554,7 +494,7 @@ static int afs_proc_cell_vlservers_open(struct inode *inode, struct file *file)  	struct seq_file *m;  	int ret; -	cell = PDE(inode)->data; +	cell = PDE_DATA(inode);  	if (!cell)  		return -ENOENT; @@ -569,15 +509,6 @@ static int afs_proc_cell_vlservers_open(struct inode *inode, struct file *file)  }  /* - * close the file and release the ref to the cell - */ -static int afs_proc_cell_vlservers_release(struct inode *inode, -					   struct file *file) -{ -	return seq_release(inode, file); -} - -/*   * set up the iterator to start reading from the cells list and return the   * first item   */ @@ -659,7 +590,7 @@ static int afs_proc_cell_servers_open(struct inode *inode, struct file *file)  	struct seq_file *m;  	int ret; -	cell = PDE(inode)->data; +	cell = PDE_DATA(inode);  	if (!cell)  		return -ENOENT; @@ -673,15 +604,6 @@ static int afs_proc_cell_servers_open(struct inode *inode, struct file *file)  }  /* - * close the file and release the ref to the cell - */ -static int afs_proc_cell_servers_release(struct inode *inode, -					 struct file *file) -{ -	return seq_release(inode, file); -} - -/*   * set up the iterator to start reading from the cells list and return the   * first item   */ diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index 654d8fdbf01..03a3beb1700 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c @@ -25,7 +25,7 @@ static void afs_wake_up_call_waiter(struct afs_call *);  static int afs_wait_for_call_to_complete(struct afs_call *);  static void afs_wake_up_async_call(struct afs_call *);  static int afs_dont_wait_for_call_to_complete(struct afs_call *); -static void afs_process_async_call(struct work_struct *); +static void afs_process_async_call(struct afs_call *);  static void afs_rx_interceptor(struct sock *, unsigned long, struct sk_buff *);  static int afs_deliver_cm_op_id(struct afs_call *, struct sk_buff *, bool); @@ -58,6 +58,13 @@ static void afs_collect_incoming_call(struct work_struct *);  static struct sk_buff_head afs_incoming_calls;  static DECLARE_WORK(afs_collect_incoming_call_work, afs_collect_incoming_call); +static void afs_async_workfn(struct work_struct *work) +{ +	struct afs_call *call = container_of(work, struct afs_call, async_work); + +	call->async_workfn(call); +} +  /*   * open an RxRPC socket and bind it to be a server for callback notifications   * - the socket is left in blocking mode and non-blocking ops use MSG_DONTWAIT @@ -184,6 +191,28 @@ static void afs_free_call(struct afs_call *call)  }  /* + * End a call but do not free it + */ +static void afs_end_call_nofree(struct afs_call *call) +{ +	if (call->rxcall) { +		rxrpc_kernel_end_call(call->rxcall); +		call->rxcall = NULL; +	} +	if (call->type->destructor) +		call->type->destructor(call); +} + +/* + * End a call and free it + */ +static void afs_end_call(struct afs_call *call) +{ +	afs_end_call_nofree(call); +	afs_free_call(call); +} + +/*   * allocate a call with flat request and reply buffers   */  struct afs_call *afs_alloc_flat_call(const struct afs_call_type *type, @@ -314,6 +343,7 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp,  	struct msghdr msg;  	struct kvec iov[1];  	int ret; +	struct sk_buff *skb;  	_enter("%x,{%d},", addr->s_addr, ntohs(call->port)); @@ -325,7 +355,8 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp,  	       atomic_read(&afs_outstanding_calls));  	call->wait_mode = wait_mode; -	INIT_WORK(&call->async_work, afs_process_async_call); +	call->async_workfn = afs_process_async_call; +	INIT_WORK(&call->async_work, afs_async_workfn);  	memset(&srx, 0, sizeof(srx));  	srx.srx_family = AF_RXRPC; @@ -380,11 +411,10 @@ int afs_make_call(struct in_addr *addr, struct afs_call *call, gfp_t gfp,  error_do_abort:  	rxrpc_kernel_abort_call(rxcall, RX_USER_ABORT); -	rxrpc_kernel_end_call(rxcall); -	call->rxcall = NULL; +	while ((skb = skb_dequeue(&call->rx_queue))) +		afs_free_skb(skb);  error_kill_call: -	call->type->destructor(call); -	afs_free_call(call); +	afs_end_call(call);  	_leave(" = %d", ret);  	return ret;  } @@ -410,7 +440,7 @@ static void afs_rx_interceptor(struct sock *sk, unsigned long user_call_ID,  	if (!call) {  		/* its an incoming call for our callback service */  		skb_queue_tail(&afs_incoming_calls, skb); -		schedule_work(&afs_collect_incoming_call_work); +		queue_work(afs_wq, &afs_collect_incoming_call_work);  	} else {  		/* route the messages directly to the appropriate call */  		skb_queue_tail(&call->rx_queue, skb); @@ -506,12 +536,8 @@ static void afs_deliver_to_call(struct afs_call *call)  	if (call->state >= AFS_CALL_COMPLETE) {  		while ((skb = skb_dequeue(&call->rx_queue)))  			afs_free_skb(skb); -		if (call->incoming) { -			rxrpc_kernel_end_call(call->rxcall); -			call->rxcall = NULL; -			call->type->destructor(call); -			afs_free_call(call); -		} +		if (call->incoming) +			afs_end_call(call);  	}  	_leave(""); @@ -561,10 +587,7 @@ static int afs_wait_for_call_to_complete(struct afs_call *call)  	}  	_debug("call complete"); -	rxrpc_kernel_end_call(call->rxcall); -	call->rxcall = NULL; -	call->type->destructor(call); -	afs_free_call(call); +	afs_end_call(call);  	_leave(" = %d", ret);  	return ret;  } @@ -600,11 +623,8 @@ static int afs_dont_wait_for_call_to_complete(struct afs_call *call)  /*   * delete an asynchronous call   */ -static void afs_delete_async_call(struct work_struct *work) +static void afs_delete_async_call(struct afs_call *call)  { -	struct afs_call *call = -		container_of(work, struct afs_call, async_work); -  	_enter("");  	afs_free_call(call); @@ -617,11 +637,8 @@ static void afs_delete_async_call(struct work_struct *work)   * - on a multiple-thread workqueue this work item may try to run on several   *   CPUs at the same time   */ -static void afs_process_async_call(struct work_struct *work) +static void afs_process_async_call(struct afs_call *call)  { -	struct afs_call *call = -		container_of(work, struct afs_call, async_work); -  	_enter("");  	if (!skb_queue_empty(&call->rx_queue)) @@ -634,14 +651,11 @@ static void afs_process_async_call(struct work_struct *work)  		call->reply = NULL;  		/* kill the call */ -		rxrpc_kernel_end_call(call->rxcall); -		call->rxcall = NULL; -		if (call->type->destructor) -			call->type->destructor(call); +		afs_end_call_nofree(call);  		/* we can't just delete the call because the work item may be  		 * queued */ -		PREPARE_WORK(&call->async_work, afs_delete_async_call); +		call->async_workfn = afs_delete_async_call;  		queue_work(afs_async_calls, &call->async_work);  	} @@ -682,7 +696,8 @@ static void afs_collect_incoming_call(struct work_struct *work)  				return;  			} -			INIT_WORK(&call->async_work, afs_process_async_call); +			call->async_workfn = afs_process_async_call; +			INIT_WORK(&call->async_work, afs_async_workfn);  			call->wait_mode = &afs_async_incoming_call;  			call->type = &afs_RXCMxxxx;  			init_waitqueue_head(&call->waitq); @@ -779,10 +794,7 @@ void afs_send_empty_reply(struct afs_call *call)  		_debug("oom");  		rxrpc_kernel_abort_call(call->rxcall, RX_USER_ABORT);  	default: -		rxrpc_kernel_end_call(call->rxcall); -		call->rxcall = NULL; -		call->type->destructor(call); -		afs_free_call(call); +		afs_end_call(call);  		_leave(" [error]");  		return;  	} @@ -812,17 +824,16 @@ void afs_send_simple_reply(struct afs_call *call, const void *buf, size_t len)  	call->state = AFS_CALL_AWAIT_ACK;  	n = rxrpc_kernel_send_data(call->rxcall, &msg, len);  	if (n >= 0) { +		/* Success */  		_leave(" [replied]");  		return;  	} +  	if (n == -ENOMEM) {  		_debug("oom");  		rxrpc_kernel_abort_call(call->rxcall, RX_USER_ABORT);  	} -	rxrpc_kernel_end_call(call->rxcall); -	call->rxcall = NULL; -	call->type->destructor(call); -	afs_free_call(call); +	afs_end_call(call);  	_leave(" [error]");  } diff --git a/fs/afs/security.c b/fs/afs/security.c index bb4ed144d0e..8d010422dc8 100644 --- a/fs/afs/security.c +++ b/fs/afs/security.c @@ -292,6 +292,9 @@ int afs_permission(struct inode *inode, int mask)  	struct key *key;  	int ret; +	if (mask & MAY_NOT_BLOCK) +		return -ECHILD; +  	_enter("{{%x:%u},%lx},%x,",  	       vnode->fid.vid, vnode->fid.vnode, vnode->flags, mask); @@ -347,7 +350,7 @@ int afs_permission(struct inode *inode, int mask)  	}  	key_put(key); -	ret = generic_permission(inode, mask, NULL); +	ret = generic_permission(inode, mask);  	_leave(" = %d", ret);  	return ret; diff --git a/fs/afs/server.c b/fs/afs/server.c index 9fdc7fe3a7b..f342acf3547 100644 --- a/fs/afs/server.c +++ b/fs/afs/server.c @@ -238,8 +238,8 @@ void afs_put_server(struct afs_server *server)  	if (atomic_read(&server->usage) == 0) {  		list_move_tail(&server->grave, &afs_server_graveyard);  		server->time_of_death = get_seconds(); -		schedule_delayed_work(&afs_server_reaper, -				      afs_server_timeout * HZ); +		queue_delayed_work(afs_wq, &afs_server_reaper, +				   afs_server_timeout * HZ);  	}  	spin_unlock(&afs_server_graveyard_lock);  	_leave(" [dead]"); @@ -285,11 +285,7 @@ static void afs_reap_server(struct work_struct *work)  		expiry = server->time_of_death + afs_server_timeout;  		if (expiry > now) {  			delay = (expiry - now) * HZ; -			if (!schedule_delayed_work(&afs_server_reaper, delay)) { -				cancel_delayed_work(&afs_server_reaper); -				schedule_delayed_work(&afs_server_reaper, -						      delay); -			} +			mod_delayed_work(afs_wq, &afs_server_reaper, delay);  			break;  		} @@ -322,6 +318,5 @@ static void afs_reap_server(struct work_struct *work)  void __exit afs_purge_servers(void)  {  	afs_server_timeout = 0; -	cancel_delayed_work(&afs_server_reaper); -	schedule_delayed_work(&afs_server_reaper, 0); +	mod_delayed_work(afs_wq, &afs_server_reaper, 0);  } diff --git a/fs/afs/super.c b/fs/afs/super.c index 27201cffece..c4861557e38 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c @@ -24,6 +24,8 @@  #include <linux/parser.h>  #include <linux/statfs.h>  #include <linux/sched.h> +#include <linux/nsproxy.h> +#include <net/net_namespace.h>  #include "internal.h"  #define AFS_FS_MAGIC 0x6B414653 /* 'kAFS' */ @@ -31,8 +33,8 @@  static void afs_i_init_once(void *foo);  static struct dentry *afs_mount(struct file_system_type *fs_type,  		      int flags, const char *dev_name, void *data); +static void afs_kill_super(struct super_block *sb);  static struct inode *afs_alloc_inode(struct super_block *sb); -static void afs_put_super(struct super_block *sb);  static void afs_destroy_inode(struct inode *inode);  static int afs_statfs(struct dentry *dentry, struct kstatfs *buf); @@ -40,9 +42,10 @@ struct file_system_type afs_fs_type = {  	.owner		= THIS_MODULE,  	.name		= "afs",  	.mount		= afs_mount, -	.kill_sb	= kill_anon_super, +	.kill_sb	= afs_kill_super,  	.fs_flags	= 0,  }; +MODULE_ALIAS_FS("afs");  static const struct super_operations afs_super_ops = {  	.statfs		= afs_statfs, @@ -50,7 +53,6 @@ static const struct super_operations afs_super_ops = {  	.drop_inode	= afs_drop_inode,  	.destroy_inode	= afs_destroy_inode,  	.evict_inode	= afs_evict_inode, -	.put_super	= afs_put_super,  	.show_options	= generic_show_options,  }; @@ -124,6 +126,11 @@ void __exit afs_fs_exit(void)  		BUG();  	} +	/* +	 * Make sure all delayed rcu free inodes are flushed before we +	 * destroy cache. +	 */ +	rcu_barrier();  	kmem_cache_destroy(afs_inode_cachep);  	_leave("");  } @@ -282,43 +289,38 @@ static int afs_parse_device_name(struct afs_mount_params *params,   */  static int afs_test_super(struct super_block *sb, void *data)  { -	struct afs_mount_params *params = data; +	struct afs_super_info *as1 = data;  	struct afs_super_info *as = sb->s_fs_info; -	return as->volume == params->volume; +	return as->volume == as1->volume; +} + +static int afs_set_super(struct super_block *sb, void *data) +{ +	sb->s_fs_info = data; +	return set_anon_super(sb, NULL);  }  /*   * fill in the superblock   */ -static int afs_fill_super(struct super_block *sb, void *data) +static int afs_fill_super(struct super_block *sb, +			  struct afs_mount_params *params)  { -	struct afs_mount_params *params = data; -	struct afs_super_info *as = NULL; +	struct afs_super_info *as = sb->s_fs_info;  	struct afs_fid fid; -	struct dentry *root = NULL;  	struct inode *inode = NULL;  	int ret;  	_enter(""); -	/* allocate a superblock info record */ -	as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL); -	if (!as) { -		_leave(" = -ENOMEM"); -		return -ENOMEM; -	} - -	afs_get_volume(params->volume); -	as->volume = params->volume; -  	/* fill in the superblock */  	sb->s_blocksize		= PAGE_CACHE_SIZE;  	sb->s_blocksize_bits	= PAGE_CACHE_SHIFT;  	sb->s_magic		= AFS_FS_MAGIC;  	sb->s_op		= &afs_super_ops; -	sb->s_fs_info		= as;  	sb->s_bdi		= &as->volume->bdi; +	strlcpy(sb->s_id, as->volume->vlocation->vldb.name, sizeof(sb->s_id));  	/* allocate the root inode and dentry */  	fid.vid		= as->volume->vid; @@ -326,31 +328,22 @@ static int afs_fill_super(struct super_block *sb, void *data)  	fid.unique	= 1;  	inode = afs_iget(sb, params->key, &fid, NULL, NULL);  	if (IS_ERR(inode)) -		goto error_inode; +		return PTR_ERR(inode);  	if (params->autocell)  		set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags);  	ret = -ENOMEM; -	root = d_alloc_root(inode); -	if (!root) +	sb->s_root = d_make_root(inode); +	if (!sb->s_root)  		goto error; -	sb->s_root = root; +	sb->s_d_op = &afs_fs_dentry_operations;  	_leave(" = 0");  	return 0; -error_inode: -	ret = PTR_ERR(inode); -	inode = NULL;  error: -	iput(inode); -	afs_put_volume(as->volume); -	kfree(as); - -	sb->s_fs_info = NULL; -  	_leave(" = %d", ret);  	return ret;  } @@ -366,12 +359,17 @@ static struct dentry *afs_mount(struct file_system_type *fs_type,  	struct afs_volume *vol;  	struct key *key;  	char *new_opts = kstrdup(options, GFP_KERNEL); +	struct afs_super_info *as;  	int ret;  	_enter(",,%s,%p", dev_name, options);  	memset(¶ms, 0, sizeof(params)); +	ret = -EINVAL; +	if (current->nsproxy->net_ns != &init_net) +		goto error; +  	/* parse the options and device name */  	if (options) {  		ret = afs_parse_options(¶ms, options, &dev_name); @@ -398,19 +396,28 @@ static struct dentry *afs_mount(struct file_system_type *fs_type,  		ret = PTR_ERR(vol);  		goto error;  	} -	params.volume = vol; + +	/* allocate a superblock info record */ +	as = kzalloc(sizeof(struct afs_super_info), GFP_KERNEL); +	if (!as) { +		ret = -ENOMEM; +		afs_put_volume(vol); +		goto error; +	} +	as->volume = vol;  	/* allocate a deviceless superblock */ -	sb = sget(fs_type, afs_test_super, set_anon_super, ¶ms); +	sb = sget(fs_type, afs_test_super, afs_set_super, flags, as);  	if (IS_ERR(sb)) {  		ret = PTR_ERR(sb); +		afs_put_volume(vol); +		kfree(as);  		goto error;  	}  	if (!sb->s_root) {  		/* initial superblock/root creation */  		_debug("create"); -		sb->s_flags = flags;  		ret = afs_fill_super(sb, ¶ms);  		if (ret < 0) {  			deactivate_locked_super(sb); @@ -421,16 +428,16 @@ static struct dentry *afs_mount(struct file_system_type *fs_type,  	} else {  		_debug("reuse");  		ASSERTCMP(sb->s_flags, &, MS_ACTIVE); +		afs_put_volume(vol); +		kfree(as);  	} -	afs_put_volume(params.volume);  	afs_put_cell(params.cell);  	kfree(new_opts);  	_leave(" = 0 [%p]", sb);  	return dget(sb->s_root);  error: -	afs_put_volume(params.volume);  	afs_put_cell(params.cell);  	key_put(params.key);  	kfree(new_opts); @@ -438,18 +445,12 @@ error:  	return ERR_PTR(ret);  } -/* - * finish the unmounting process on the superblock - */ -static void afs_put_super(struct super_block *sb) +static void afs_kill_super(struct super_block *sb)  {  	struct afs_super_info *as = sb->s_fs_info; - -	_enter(""); - +	kill_anon_super(sb);  	afs_put_volume(as->volume); - -	_leave(""); +	kfree(as);  }  /* @@ -498,6 +499,13 @@ static struct inode *afs_alloc_inode(struct super_block *sb)  	return &vnode->vfs_inode;  } +static void afs_i_callback(struct rcu_head *head) +{ +	struct inode *inode = container_of(head, struct inode, i_rcu); +	struct afs_vnode *vnode = AFS_FS_I(inode); +	kmem_cache_free(afs_inode_cachep, vnode); +} +  /*   * destroy an AFS inode struct   */ @@ -511,7 +519,7 @@ static void afs_destroy_inode(struct inode *inode)  	ASSERTCMP(vnode->server, ==, NULL); -	kmem_cache_free(afs_inode_cachep, vnode); +	call_rcu(&inode->i_rcu, afs_i_callback);  	atomic_dec(&afs_count_active_inodes);  } diff --git a/fs/afs/vlocation.c b/fs/afs/vlocation.c index 9ac260d1361..b6df2e83809 100644 --- a/fs/afs/vlocation.c +++ b/fs/afs/vlocation.c @@ -308,7 +308,8 @@ static int afs_vlocation_fill_in_record(struct afs_vlocation *vl,  	/* see if we have an in-cache copy (will set vl->valid if there is) */  #ifdef CONFIG_AFS_FSCACHE  	vl->cache = fscache_acquire_cookie(vl->cell->cache, -					   &afs_vlocation_cache_index_def, vl); +					   &afs_vlocation_cache_index_def, vl, +					   true);  #endif  	if (vl->valid) { @@ -507,8 +508,8 @@ void afs_put_vlocation(struct afs_vlocation *vl)  		_debug("buried");  		list_move_tail(&vl->grave, &afs_vlocation_graveyard);  		vl->time_of_death = get_seconds(); -		schedule_delayed_work(&afs_vlocation_reap, -				      afs_vlocation_timeout * HZ); +		queue_delayed_work(afs_wq, &afs_vlocation_reap, +				   afs_vlocation_timeout * HZ);  		/* suspend updates on this record */  		if (!list_empty(&vl->update)) { @@ -561,12 +562,7 @@ static void afs_vlocation_reaper(struct work_struct *work)  		if (expiry > now) {  			delay = (expiry - now) * HZ;  			_debug("delay %lu", delay); -			if (!schedule_delayed_work(&afs_vlocation_reap, -						   delay)) { -				cancel_delayed_work(&afs_vlocation_reap); -				schedule_delayed_work(&afs_vlocation_reap, -						      delay); -			} +			mod_delayed_work(afs_wq, &afs_vlocation_reap, delay);  			break;  		} @@ -614,13 +610,10 @@ void afs_vlocation_purge(void)  	spin_lock(&afs_vlocation_updates_lock);  	list_del_init(&afs_vlocation_updates);  	spin_unlock(&afs_vlocation_updates_lock); -	cancel_delayed_work(&afs_vlocation_update); -	queue_delayed_work(afs_vlocation_update_worker, -			   &afs_vlocation_update, 0); +	mod_delayed_work(afs_vlocation_update_worker, &afs_vlocation_update, 0);  	destroy_workqueue(afs_vlocation_update_worker); -	cancel_delayed_work(&afs_vlocation_reap); -	schedule_delayed_work(&afs_vlocation_reap, 0); +	mod_delayed_work(afs_wq, &afs_vlocation_reap, 0);  }  /* diff --git a/fs/afs/volume.c b/fs/afs/volume.c index 401eeb21869..2b607257820 100644 --- a/fs/afs/volume.c +++ b/fs/afs/volume.c @@ -131,7 +131,7 @@ struct afs_volume *afs_volume_lookup(struct afs_mount_params *params)  #ifdef CONFIG_AFS_FSCACHE  	volume->cache = fscache_acquire_cookie(vlocation->cache,  					       &afs_volume_cache_index_def, -					       volume); +					       volume, true);  #endif  	afs_get_vlocation(vlocation);  	volume->vlocation = vlocation; diff --git a/fs/afs/write.c b/fs/afs/write.c index 15690bb1d3b..ab6adfd5251 100644 --- a/fs/afs/write.c +++ b/fs/afs/write.c @@ -14,6 +14,7 @@  #include <linux/pagemap.h>  #include <linux/writeback.h>  #include <linux/pagevec.h> +#include <linux/aio.h>  #include "internal.h"  static int afs_write_back_from_locked_page(struct afs_writeback *wb, @@ -84,23 +85,21 @@ void afs_put_writeback(struct afs_writeback *wb)   * partly or wholly fill a page that's under preparation for writing   */  static int afs_fill_page(struct afs_vnode *vnode, struct key *key, -			 loff_t pos, unsigned len, struct page *page) +			 loff_t pos, struct page *page)  {  	loff_t i_size; -	unsigned eof;  	int ret; +	int len; -	_enter(",,%llu,%u", (unsigned long long)pos, len); - -	ASSERTCMP(len, <=, PAGE_CACHE_SIZE); +	_enter(",,%llu", (unsigned long long)pos);  	i_size = i_size_read(&vnode->vfs_inode); -	if (pos + len > i_size) -		eof = i_size; +	if (pos + PAGE_CACHE_SIZE > i_size) +		len = i_size - pos;  	else -		eof = PAGE_CACHE_SIZE; +		len = PAGE_CACHE_SIZE; -	ret = afs_vnode_fetch_data(vnode, key, 0, eof, page); +	ret = afs_vnode_fetch_data(vnode, key, pos, len, page);  	if (ret < 0) {  		if (ret == -ENOENT) {  			_debug("got NOENT from server" @@ -122,7 +121,7 @@ int afs_write_begin(struct file *file, struct address_space *mapping,  		    struct page **pagep, void **fsdata)  {  	struct afs_writeback *candidate, *wb; -	struct afs_vnode *vnode = AFS_FS_I(file->f_dentry->d_inode); +	struct afs_vnode *vnode = AFS_FS_I(file_inode(file));  	struct page *page;  	struct key *key = file->private_data;  	unsigned from = pos & (PAGE_CACHE_SIZE - 1); @@ -140,6 +139,7 @@ int afs_write_begin(struct file *file, struct address_space *mapping,  	candidate->first = candidate->last = index;  	candidate->offset_first = from;  	candidate->to_last = to; +	INIT_LIST_HEAD(&candidate->link);  	candidate->usage = 1;  	candidate->state = AFS_WBACK_PENDING;  	init_waitqueue_head(&candidate->waitq); @@ -152,9 +152,8 @@ int afs_write_begin(struct file *file, struct address_space *mapping,  	*pagep = page;  	/* page won't leak in error case: it eventually gets cleaned off LRU */ -	if (!PageUptodate(page)) { -		_debug("not up to date"); -		ret = afs_fill_page(vnode, key, pos, len, page); +	if (!PageUptodate(page) && len != PAGE_CACHE_SIZE) { +		ret = afs_fill_page(vnode, key, index << PAGE_CACHE_SHIFT, page);  		if (ret < 0) {  			kfree(candidate);  			_leave(" = %d [prep]", ret); @@ -247,7 +246,7 @@ int afs_write_end(struct file *file, struct address_space *mapping,  		  loff_t pos, unsigned len, unsigned copied,  		  struct page *page, void *fsdata)  { -	struct afs_vnode *vnode = AFS_FS_I(file->f_dentry->d_inode); +	struct afs_vnode *vnode = AFS_FS_I(file_inode(file));  	loff_t i_size, maybe_i_size;  	_enter("{%x:%u},{%lx}", @@ -626,16 +625,14 @@ void afs_pages_written_back(struct afs_vnode *vnode, struct afs_call *call)  /*   * write to an AFS file   */ -ssize_t afs_file_write(struct kiocb *iocb, const struct iovec *iov, -		       unsigned long nr_segs, loff_t pos) +ssize_t afs_file_write(struct kiocb *iocb, struct iov_iter *from)  { -	struct dentry *dentry = iocb->ki_filp->f_path.dentry; -	struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode); +	struct afs_vnode *vnode = AFS_FS_I(file_inode(iocb->ki_filp));  	ssize_t result; -	size_t count = iov_length(iov, nr_segs); +	size_t count = iov_iter_count(from); -	_enter("{%x.%u},{%zu},%lu,", -	       vnode->fid.vid, vnode->fid.vnode, count, nr_segs); +	_enter("{%x.%u},{%zu},", +	       vnode->fid.vid, vnode->fid.vnode, count);  	if (IS_SWAPFILE(&vnode->vfs_inode)) {  		printk(KERN_INFO @@ -646,7 +643,7 @@ ssize_t afs_file_write(struct kiocb *iocb, const struct iovec *iov,  	if (!count)  		return 0; -	result = generic_file_aio_write(iocb, iov, nr_segs, pos); +	result = generic_file_write_iter(iocb, from);  	if (IS_ERR_VALUE(result)) {  		_leave(" = %zd", result);  		return result; @@ -683,9 +680,10 @@ int afs_writeback_all(struct afs_vnode *vnode)   * - the return status from this call provides a reliable indication of   *   whether any write errors occurred for this process.   */ -int afs_fsync(struct file *file, int datasync) +int afs_fsync(struct file *file, loff_t start, loff_t end, int datasync)  {  	struct dentry *dentry = file->f_path.dentry; +	struct inode *inode = file->f_mapping->host;  	struct afs_writeback *wb, *xwb;  	struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode);  	int ret; @@ -694,12 +692,19 @@ int afs_fsync(struct file *file, int datasync)  	       vnode->fid.vid, vnode->fid.vnode, dentry->d_name.name,  	       datasync); +	ret = filemap_write_and_wait_range(inode->i_mapping, start, end); +	if (ret) +		return ret; +	mutex_lock(&inode->i_mutex); +  	/* use a writeback record as a marker in the queue - when this reaches  	 * the front of the queue, all the outstanding writes are either  	 * completed or rejected */  	wb = kzalloc(sizeof(*wb), GFP_KERNEL); -	if (!wb) -		return -ENOMEM; +	if (!wb) { +		ret = -ENOMEM; +		goto out; +	}  	wb->vnode = vnode;  	wb->first = 0;  	wb->last = -1; @@ -722,7 +727,7 @@ int afs_fsync(struct file *file, int datasync)  	if (ret < 0) {  		afs_put_writeback(wb);  		_leave(" = %d [wb]", ret); -		return ret; +		goto out;  	}  	/* wait for the preceding writes to actually complete */ @@ -731,6 +736,8 @@ int afs_fsync(struct file *file, int datasync)  				       vnode->writebacks.next == &wb->link);  	afs_put_writeback(wb);  	_leave(" = %d", ret); +out: +	mutex_unlock(&inode->i_mutex);  	return ret;  }  | 
