diff options
Diffstat (limited to 'fs')
58 files changed, 583 insertions, 569 deletions
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 392c5dac198..d934f04e773 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c @@ -184,10 +184,20 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)  			v9ses->afid = option;  			break;  		case Opt_uname: -			match_strlcpy(v9ses->uname, &args[0], PATH_MAX); +			kfree(v9ses->uname); +			v9ses->uname = match_strdup(&args[0]); +			if (!v9ses->uname) { +				ret = -ENOMEM; +				goto free_and_return; +			}  			break;  		case Opt_remotename: -			match_strlcpy(v9ses->aname, &args[0], PATH_MAX); +			kfree(v9ses->aname); +			v9ses->aname = match_strdup(&args[0]); +			if (!v9ses->aname) { +				ret = -ENOMEM; +				goto free_and_return; +			}  			break;  		case Opt_nodevmap:  			v9ses->nodev = 1; @@ -287,21 +297,21 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,  	struct p9_fid *fid;  	int rc; -	v9ses->uname = __getname(); +	v9ses->uname = kstrdup(V9FS_DEFUSER, GFP_KERNEL);  	if (!v9ses->uname)  		return ERR_PTR(-ENOMEM); -	v9ses->aname = __getname(); +	v9ses->aname = kstrdup(V9FS_DEFANAME, GFP_KERNEL);  	if (!v9ses->aname) { -		__putname(v9ses->uname); +		kfree(v9ses->uname);  		return ERR_PTR(-ENOMEM);  	}  	init_rwsem(&v9ses->rename_sem);  	rc = bdi_setup_and_register(&v9ses->bdi, "9p", BDI_CAP_MAP_COPY);  	if (rc) { -		__putname(v9ses->aname); -		__putname(v9ses->uname); +		kfree(v9ses->aname); +		kfree(v9ses->uname);  		return ERR_PTR(rc);  	} @@ -309,8 +319,6 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,  	list_add(&v9ses->slist, &v9fs_sessionlist);  	spin_unlock(&v9fs_sessionlist_lock); -	strcpy(v9ses->uname, V9FS_DEFUSER); -	strcpy(v9ses->aname, V9FS_DEFANAME);  	v9ses->uid = ~0;  	v9ses->dfltuid = V9FS_DEFUID;  	v9ses->dfltgid = V9FS_DEFGID; @@ -412,8 +420,8 @@ void v9fs_session_close(struct v9fs_session_info *v9ses)  		kfree(v9ses->cachetag);  	}  #endif -	__putname(v9ses->uname); -	__putname(v9ses->aname); +	kfree(v9ses->uname); +	kfree(v9ses->aname);  	bdi_destroy(&v9ses->bdi); diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index cbf9dbb1b2a..890bed538f9 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -1276,12 +1276,12 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)  	}  	/* copy extension buffer into buffer */ -	strncpy(buffer, st->extension, buflen); +	retval = min(strlen(st->extension)+1, (size_t)buflen); +	memcpy(buffer, st->extension, retval); -	p9_debug(P9_DEBUG_VFS, "%s -> %s (%s)\n", -		 dentry->d_name.name, st->extension, buffer); +	p9_debug(P9_DEBUG_VFS, "%s -> %s (%.*s)\n", +		 dentry->d_name.name, st->extension, buflen, buffer); -	retval = strnlen(buffer, buflen);  done:  	p9stat_free(st);  	kfree(st); diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index e568c472f80..61168805f17 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -638,7 +638,7 @@ static int btrfs_may_delete(struct inode *dir,struct dentry *victim,int isdir)  		return -ENOENT;  	BUG_ON(victim->d_parent->d_inode != dir); -	audit_inode_child(victim, dir); +	audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE);  	error = inode_permission(dir, MAY_WRITE | MAY_EXEC);  	if (error) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index e9ebb472b28..81e407d9677 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -2952,8 +2952,8 @@ static void fill_inode_item(struct btrfs_trans_handle *trans,  			    struct btrfs_inode_item *item,  			    struct inode *inode, int log_inode_only)  { -	btrfs_set_inode_uid(leaf, item, inode->i_uid); -	btrfs_set_inode_gid(leaf, item, inode->i_gid); +	btrfs_set_inode_uid(leaf, item, i_uid_read(inode)); +	btrfs_set_inode_gid(leaf, item, i_gid_read(inode));  	btrfs_set_inode_mode(leaf, item, inode->i_mode);  	btrfs_set_inode_nlink(leaf, item, inode->i_nlink); diff --git a/fs/ceph/export.c b/fs/ceph/export.c index 8e1b60e557b..02ce90972d8 100644 --- a/fs/ceph/export.c +++ b/fs/ceph/export.c @@ -99,7 +99,7 @@ static int ceph_encode_fh(struct inode *inode, u32 *rawfh, int *max_len,   * FIXME: we should try harder by querying the mds for the ino.   */  static struct dentry *__fh_to_dentry(struct super_block *sb, -				     struct ceph_nfs_fh *fh) +				     struct ceph_nfs_fh *fh, int fh_len)  {  	struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;  	struct inode *inode; @@ -107,6 +107,9 @@ static struct dentry *__fh_to_dentry(struct super_block *sb,  	struct ceph_vino vino;  	int err; +	if (fh_len < sizeof(*fh) / 4) +		return ERR_PTR(-ESTALE); +  	dout("__fh_to_dentry %llx\n", fh->ino);  	vino.ino = fh->ino;  	vino.snap = CEPH_NOSNAP; @@ -150,7 +153,7 @@ static struct dentry *__fh_to_dentry(struct super_block *sb,   * convert connectable fh to dentry   */  static struct dentry *__cfh_to_dentry(struct super_block *sb, -				      struct ceph_nfs_confh *cfh) +				      struct ceph_nfs_confh *cfh, int fh_len)  {  	struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;  	struct inode *inode; @@ -158,6 +161,9 @@ static struct dentry *__cfh_to_dentry(struct super_block *sb,  	struct ceph_vino vino;  	int err; +	if (fh_len < sizeof(*cfh) / 4) +		return ERR_PTR(-ESTALE); +  	dout("__cfh_to_dentry %llx (%llx/%x)\n",  	     cfh->ino, cfh->parent_ino, cfh->parent_name_hash); @@ -207,9 +213,11 @@ static struct dentry *ceph_fh_to_dentry(struct super_block *sb, struct fid *fid,  					int fh_len, int fh_type)  {  	if (fh_type == 1) -		return __fh_to_dentry(sb, (struct ceph_nfs_fh *)fid->raw); +		return __fh_to_dentry(sb, (struct ceph_nfs_fh *)fid->raw, +								fh_len);  	else -		return __cfh_to_dentry(sb, (struct ceph_nfs_confh *)fid->raw); +		return __cfh_to_dentry(sb, (struct ceph_nfs_confh *)fid->raw, +								fh_len);  }  /* @@ -230,6 +238,8 @@ static struct dentry *ceph_fh_to_parent(struct super_block *sb,  	if (fh_type == 1)  		return ERR_PTR(-ESTALE); +	if (fh_len < sizeof(*cfh) / 4) +		return ERR_PTR(-ESTALE);  	pr_debug("fh_to_parent %llx/%d\n", cfh->parent_ino,  		 cfh->parent_name_hash); diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c index e622863b292..086f381d648 100644 --- a/fs/cifs/cifs_spnego.c +++ b/fs/cifs/cifs_spnego.c @@ -31,18 +31,18 @@  /* create a new cifs key */  static int -cifs_spnego_key_instantiate(struct key *key, const void *data, size_t datalen) +cifs_spnego_key_instantiate(struct key *key, struct key_preparsed_payload *prep)  {  	char *payload;  	int ret;  	ret = -ENOMEM; -	payload = kmalloc(datalen, GFP_KERNEL); +	payload = kmalloc(prep->datalen, GFP_KERNEL);  	if (!payload)  		goto error;  	/* attach the data */ -	memcpy(payload, data, datalen); +	memcpy(payload, prep->data, prep->datalen);  	key->payload.data = payload;  	ret = 0; diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 2ee5c54797f..fc783e26442 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -167,17 +167,17 @@ static struct shrinker cifs_shrinker = {  };  static int -cifs_idmap_key_instantiate(struct key *key, const void *data, size_t datalen) +cifs_idmap_key_instantiate(struct key *key, struct key_preparsed_payload *prep)  {  	char *payload; -	payload = kmalloc(datalen, GFP_KERNEL); +	payload = kmalloc(prep->datalen, GFP_KERNEL);  	if (!payload)  		return -ENOMEM; -	memcpy(payload, data, datalen); +	memcpy(payload, prep->data, prep->datalen);  	key->payload.data = payload; -	key->datalen = datalen; +	key->datalen = prep->datalen;  	return 0;  } diff --git a/fs/compat.c b/fs/compat.c index b7a24d0ca30..015e1e1f87c 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -776,16 +776,16 @@ asmlinkage long compat_sys_mount(const char __user * dev_name,  	char *kernel_type;  	unsigned long data_page;  	char *kernel_dev; -	char *dir_page; +	struct filename *dir;  	int retval;  	retval = copy_mount_string(type, &kernel_type);  	if (retval < 0)  		goto out; -	dir_page = getname(dir_name); -	retval = PTR_ERR(dir_page); -	if (IS_ERR(dir_page)) +	dir = getname(dir_name); +	retval = PTR_ERR(dir); +	if (IS_ERR(dir))  		goto out1;  	retval = copy_mount_string(dev_name, &kernel_dev); @@ -807,7 +807,7 @@ asmlinkage long compat_sys_mount(const char __user * dev_name,  		}  	} -	retval = do_mount(kernel_dev, dir_page, kernel_type, +	retval = do_mount(kernel_dev, dir->name, kernel_type,  			flags, (void*)data_page);   out4: @@ -815,7 +815,7 @@ asmlinkage long compat_sys_mount(const char __user * dev_name,   out3:  	kfree(kernel_dev);   out2: -	putname(dir_page); +	putname(dir);   out1:  	kfree(kernel_type);   out: diff --git a/fs/exec.c b/fs/exec.c index ca434534ae9..8b9011b6704 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -105,7 +105,7 @@ static inline void put_binfmt(struct linux_binfmt * fmt)  SYSCALL_DEFINE1(uselib, const char __user *, library)  {  	struct file *file; -	char *tmp = getname(library); +	struct filename *tmp = getname(library);  	int error = PTR_ERR(tmp);  	static const struct open_flags uselib_flags = {  		.open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC, @@ -751,13 +751,14 @@ struct file *open_exec(const char *name)  {  	struct file *file;  	int err; +	struct filename tmp = { .name = name };  	static const struct open_flags open_exec_flags = {  		.open_flag = O_LARGEFILE | O_RDONLY | __FMODE_EXEC,  		.acc_mode = MAY_EXEC | MAY_OPEN,  		.intent = LOOKUP_OPEN  	}; -	file = do_filp_open(AT_FDCWD, name, &open_exec_flags, LOOKUP_FOLLOW); +	file = do_filp_open(AT_FDCWD, &tmp, &open_exec_flags, LOOKUP_FOLLOW);  	if (IS_ERR(file))  		goto out; @@ -1664,10 +1665,10 @@ SYSCALL_DEFINE3(execve,  		const char __user *const __user *, argv,  		const char __user *const __user *, envp)  { -	const char *path = getname(filename); +	struct filename *path = getname(filename);  	int error = PTR_ERR(path);  	if (!IS_ERR(path)) { -		error = do_execve(path, argv, envp, current_pt_regs()); +		error = do_execve(path->name, argv, envp, current_pt_regs());  		putname(path);  	}  	return error; @@ -1677,10 +1678,11 @@ asmlinkage long compat_sys_execve(const char __user * filename,  	const compat_uptr_t __user * argv,  	const compat_uptr_t __user * envp)  { -	const char *path = getname(filename); +	struct filename *path = getname(filename);  	int error = PTR_ERR(path);  	if (!IS_ERR(path)) { -		error = compat_do_execve(path, argv, envp, current_pt_regs()); +		error = compat_do_execve(path->name, argv, envp, +							current_pt_regs());  		putname(path);  	}  	return error; diff --git a/fs/exofs/super.c b/fs/exofs/super.c index 59e3bbfac0b..5e59280d42d 100644 --- a/fs/exofs/super.c +++ b/fs/exofs/super.c @@ -389,8 +389,6 @@ static int exofs_sync_fs(struct super_block *sb, int wait)  	if (unlikely(ret))  		goto out; -	lock_super(sb); -  	ios->length = offsetof(struct exofs_fscb, s_dev_table_oid);  	memset(fscb, 0, ios->length);  	fscb->s_nextid = cpu_to_le64(sbi->s_nextid); @@ -406,8 +404,6 @@ static int exofs_sync_fs(struct super_block *sb, int wait)  	if (unlikely(ret))  		EXOFS_ERR("%s: ore_write failed.\n", __func__); - -	unlock_super(sb);  out:  	EXOFS_DBGMSG("s_nextid=0x%llx ret=%d\n", _LLU(sbi->s_nextid), ret);  	ore_put_io_state(ios); diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 17ae5c83d23..29e79713c7e 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -2578,11 +2578,9 @@ out:  static int ext3_unfreeze(struct super_block *sb)  {  	if (!(sb->s_flags & MS_RDONLY)) { -		lock_super(sb);  		/* Reser the needs_recovery flag before the fs is unlocked. */  		EXT3_SET_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER);  		ext3_commit_super(sb, EXT3_SB(sb)->s_es, 1); -		unlock_super(sb);  		journal_unlock_updates(EXT3_SB(sb)->s_journal);  	}  	return 0; @@ -2602,7 +2600,6 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)  #endif  	/* Store the original options */ -	lock_super(sb);  	old_sb_flags = sb->s_flags;  	old_opts.s_mount_opt = sbi->s_mount_opt;  	old_opts.s_resuid = sbi->s_resuid; @@ -2708,8 +2705,6 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)  		    old_opts.s_qf_names[i] != sbi->s_qf_names[i])  			kfree(old_opts.s_qf_names[i]);  #endif -	unlock_super(sb); -  	if (enable_quota)  		dquot_resume(sb, -1);  	return 0; @@ -2728,7 +2723,6 @@ restore_opts:  		sbi->s_qf_names[i] = old_opts.s_qf_names[i];  	}  #endif -	unlock_super(sb);  	return err;  } diff --git a/fs/fat/dir.c b/fs/fat/dir.c index bca6d0a1255..2a182342442 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c @@ -571,7 +571,7 @@ static int __fat_readdir(struct inode *inode, struct file *filp, void *dirent,  	int short_len = 0, fill_len = 0;  	int ret = 0; -	lock_super(sb); +	mutex_lock(&sbi->s_lock);  	cpos = filp->f_pos;  	/* Fake . and .. for the root directory. */ @@ -693,7 +693,7 @@ fill_failed:  	if (unicode)  		__putname(unicode);  out: -	unlock_super(sb); +	mutex_unlock(&sbi->s_lock);  	return ret;  } diff --git a/fs/fat/fat.h b/fs/fat/fat.h index ca7e8f8bad7..623f36f0423 100644 --- a/fs/fat/fat.h +++ b/fs/fat/fat.h @@ -71,8 +71,9 @@ struct msdos_sb_info {  	unsigned long root_cluster;   /* first cluster of the root directory */  	unsigned long fsinfo_sector;  /* sector number of FAT32 fsinfo */  	struct mutex fat_lock; -	unsigned int prev_free;       /* previously allocated cluster number */ -	unsigned int free_clusters;   /* -1 if undefined */ +	struct mutex s_lock; +	unsigned int prev_free;      /* previously allocated cluster number */ +	unsigned int free_clusters;  /* -1 if undefined */  	unsigned int free_clus_valid; /* is free_clusters valid? */  	struct fat_mount_options options;  	struct nls_table *nls_disk;   /* Codepage used on disk */ diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 76f60c642c0..5bafaad0053 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -673,9 +673,9 @@ static int fat_write_inode(struct inode *inode, struct writeback_control *wbc)  	if (inode->i_ino == MSDOS_FSINFO_INO) {  		struct super_block *sb = inode->i_sb; -		lock_super(sb); +		mutex_lock(&MSDOS_SB(sb)->s_lock);  		err = fat_clusters_flush(sb); -		unlock_super(sb); +		mutex_unlock(&MSDOS_SB(sb)->s_lock);  	} else  		err = __fat_write_inode(inode, wbc->sync_mode == WB_SYNC_ALL); @@ -1268,6 +1268,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, int isvfat,  		b = (struct fat_boot_sector *) bh->b_data;  	} +	mutex_init(&sbi->s_lock);  	sbi->cluster_size = sb->s_blocksize * sbi->sec_per_clus;  	sbi->cluster_bits = ffs(sbi->cluster_size) - 1;  	sbi->fats = b->fats; diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c index c1055e778ff..e2cfda94a28 100644 --- a/fs/fat/namei_msdos.c +++ b/fs/fat/namei_msdos.c @@ -208,7 +208,7 @@ static struct dentry *msdos_lookup(struct inode *dir, struct dentry *dentry,  	struct inode *inode;  	int err; -	lock_super(sb); +	mutex_lock(&MSDOS_SB(sb)->s_lock);  	err = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo);  	switch (err) {  	case -ENOENT: @@ -221,7 +221,7 @@ static struct dentry *msdos_lookup(struct inode *dir, struct dentry *dentry,  	default:  		inode = ERR_PTR(err);  	} -	unlock_super(sb); +	mutex_unlock(&MSDOS_SB(sb)->s_lock);  	return d_splice_alias(inode, dentry);  } @@ -273,7 +273,7 @@ static int msdos_create(struct inode *dir, struct dentry *dentry, umode_t mode,  	unsigned char msdos_name[MSDOS_NAME];  	int err, is_hid; -	lock_super(sb); +	mutex_lock(&MSDOS_SB(sb)->s_lock);  	err = msdos_format_name(dentry->d_name.name, dentry->d_name.len,  				msdos_name, &MSDOS_SB(sb)->options); @@ -302,7 +302,7 @@ static int msdos_create(struct inode *dir, struct dentry *dentry, umode_t mode,  	d_instantiate(dentry, inode);  out: -	unlock_super(sb); +	mutex_unlock(&MSDOS_SB(sb)->s_lock);  	if (!err)  		err = fat_flush_inodes(sb, dir, inode);  	return err; @@ -316,7 +316,7 @@ static int msdos_rmdir(struct inode *dir, struct dentry *dentry)  	struct fat_slot_info sinfo;  	int err; -	lock_super(sb); +	mutex_lock(&MSDOS_SB(sb)->s_lock);  	/*  	 * Check whether the directory is not in use, then check  	 * whether it is empty. @@ -337,7 +337,7 @@ static int msdos_rmdir(struct inode *dir, struct dentry *dentry)  	inode->i_ctime = CURRENT_TIME_SEC;  	fat_detach(inode);  out: -	unlock_super(sb); +	mutex_unlock(&MSDOS_SB(sb)->s_lock);  	if (!err)  		err = fat_flush_inodes(sb, dir, inode); @@ -354,7 +354,7 @@ static int msdos_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)  	struct timespec ts;  	int err, is_hid, cluster; -	lock_super(sb); +	mutex_lock(&MSDOS_SB(sb)->s_lock);  	err = msdos_format_name(dentry->d_name.name, dentry->d_name.len,  				msdos_name, &MSDOS_SB(sb)->options); @@ -392,14 +392,14 @@ static int msdos_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)  	d_instantiate(dentry, inode); -	unlock_super(sb); +	mutex_unlock(&MSDOS_SB(sb)->s_lock);  	fat_flush_inodes(sb, dir, inode);  	return 0;  out_free:  	fat_free_clusters(dir, cluster);  out: -	unlock_super(sb); +	mutex_unlock(&MSDOS_SB(sb)->s_lock);  	return err;  } @@ -411,7 +411,7 @@ static int msdos_unlink(struct inode *dir, struct dentry *dentry)  	struct fat_slot_info sinfo;  	int err; -	lock_super(sb); +	mutex_lock(&MSDOS_SB(sb)->s_lock);  	err = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &sinfo);  	if (err)  		goto out; @@ -423,7 +423,7 @@ static int msdos_unlink(struct inode *dir, struct dentry *dentry)  	inode->i_ctime = CURRENT_TIME_SEC;  	fat_detach(inode);  out: -	unlock_super(sb); +	mutex_unlock(&MSDOS_SB(sb)->s_lock);  	if (!err)  		err = fat_flush_inodes(sb, dir, inode); @@ -606,7 +606,7 @@ static int msdos_rename(struct inode *old_dir, struct dentry *old_dentry,  	unsigned char old_msdos_name[MSDOS_NAME], new_msdos_name[MSDOS_NAME];  	int err, is_hid; -	lock_super(sb); +	mutex_lock(&MSDOS_SB(sb)->s_lock);  	err = msdos_format_name(old_dentry->d_name.name,  				old_dentry->d_name.len, old_msdos_name, @@ -625,7 +625,7 @@ static int msdos_rename(struct inode *old_dir, struct dentry *old_dentry,  	err = do_msdos_rename(old_dir, old_msdos_name, old_dentry,  			      new_dir, new_msdos_name, new_dentry, is_hid);  out: -	unlock_super(sb); +	mutex_unlock(&MSDOS_SB(sb)->s_lock);  	if (!err)  		err = fat_flush_inodes(sb, old_dir, new_dir);  	return err; diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index e535dd75b98..ac959d655e7 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c @@ -721,7 +721,7 @@ static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry,  	struct dentry *alias;  	int err; -	lock_super(sb); +	mutex_lock(&MSDOS_SB(sb)->s_lock);  	err = vfat_find(dir, &dentry->d_name, &sinfo);  	if (err) { @@ -752,13 +752,13 @@ static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry,  		if (!S_ISDIR(inode->i_mode))  			d_move(alias, dentry);  		iput(inode); -		unlock_super(sb); +		mutex_unlock(&MSDOS_SB(sb)->s_lock);  		return alias;  	} else  		dput(alias);  out: -	unlock_super(sb); +	mutex_unlock(&MSDOS_SB(sb)->s_lock);  	dentry->d_time = dentry->d_parent->d_inode->i_version;  	dentry = d_splice_alias(inode, dentry);  	if (dentry) @@ -766,7 +766,7 @@ out:  	return dentry;  error: -	unlock_super(sb); +	mutex_unlock(&MSDOS_SB(sb)->s_lock);  	return ERR_PTR(err);  } @@ -779,7 +779,7 @@ static int vfat_create(struct inode *dir, struct dentry *dentry, umode_t mode,  	struct timespec ts;  	int err; -	lock_super(sb); +	mutex_lock(&MSDOS_SB(sb)->s_lock);  	ts = CURRENT_TIME_SEC;  	err = vfat_add_entry(dir, &dentry->d_name, 0, 0, &ts, &sinfo); @@ -800,7 +800,7 @@ static int vfat_create(struct inode *dir, struct dentry *dentry, umode_t mode,  	dentry->d_time = dentry->d_parent->d_inode->i_version;  	d_instantiate(dentry, inode);  out: -	unlock_super(sb); +	mutex_unlock(&MSDOS_SB(sb)->s_lock);  	return err;  } @@ -811,7 +811,7 @@ static int vfat_rmdir(struct inode *dir, struct dentry *dentry)  	struct fat_slot_info sinfo;  	int err; -	lock_super(sb); +	mutex_lock(&MSDOS_SB(sb)->s_lock);  	err = fat_dir_empty(inode);  	if (err) @@ -829,7 +829,7 @@ static int vfat_rmdir(struct inode *dir, struct dentry *dentry)  	inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;  	fat_detach(inode);  out: -	unlock_super(sb); +	mutex_unlock(&MSDOS_SB(sb)->s_lock);  	return err;  } @@ -841,7 +841,7 @@ static int vfat_unlink(struct inode *dir, struct dentry *dentry)  	struct fat_slot_info sinfo;  	int err; -	lock_super(sb); +	mutex_lock(&MSDOS_SB(sb)->s_lock);  	err = vfat_find(dir, &dentry->d_name, &sinfo);  	if (err) @@ -854,7 +854,7 @@ static int vfat_unlink(struct inode *dir, struct dentry *dentry)  	inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;  	fat_detach(inode);  out: -	unlock_super(sb); +	mutex_unlock(&MSDOS_SB(sb)->s_lock);  	return err;  } @@ -867,7 +867,7 @@ static int vfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)  	struct timespec ts;  	int err, cluster; -	lock_super(sb); +	mutex_lock(&MSDOS_SB(sb)->s_lock);  	ts = CURRENT_TIME_SEC;  	cluster = fat_alloc_new_dir(dir, &ts); @@ -896,13 +896,13 @@ static int vfat_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)  	dentry->d_time = dentry->d_parent->d_inode->i_version;  	d_instantiate(dentry, inode); -	unlock_super(sb); +	mutex_unlock(&MSDOS_SB(sb)->s_lock);  	return 0;  out_free:  	fat_free_clusters(dir, cluster);  out: -	unlock_super(sb); +	mutex_unlock(&MSDOS_SB(sb)->s_lock);  	return err;  } @@ -921,7 +921,7 @@ static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,  	old_sinfo.bh = sinfo.bh = dotdot_bh = NULL;  	old_inode = old_dentry->d_inode;  	new_inode = new_dentry->d_inode; -	lock_super(sb); +	mutex_lock(&MSDOS_SB(sb)->s_lock);  	err = vfat_find(old_dir, &old_dentry->d_name, &old_sinfo);  	if (err)  		goto out; @@ -996,7 +996,7 @@ out:  	brelse(sinfo.bh);  	brelse(dotdot_bh);  	brelse(old_sinfo.bh); -	unlock_super(sb); +	mutex_unlock(&MSDOS_SB(sb)->s_lock);  	return err; diff --git a/fs/file.c b/fs/file.c index 0f1bda4bebf..d3b5fa80b71 100644 --- a/fs/file.c +++ b/fs/file.c @@ -922,6 +922,9 @@ SYSCALL_DEFINE3(dup3, unsigned int, oldfd, unsigned int, newfd, int, flags)  	if ((flags & ~O_CLOEXEC) != 0)  		return -EINVAL; +	if (unlikely(oldfd == newfd)) +		return -EINVAL; +  	if (newfd >= rlimit(RLIMIT_NOFILE))  		return -EMFILE; diff --git a/fs/file_table.c b/fs/file_table.c index dac67923330..a72bf9ddd0d 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -36,7 +36,7 @@ struct files_stat_struct files_stat = {  	.max_files = NR_FILE  }; -DEFINE_LGLOCK(files_lglock); +DEFINE_STATIC_LGLOCK(files_lglock);  /* SLAB cache for file structures */  static struct kmem_cache *filp_cachep __read_mostly; diff --git a/fs/filesystems.c b/fs/filesystems.c index 96f24286667..da165f6adcb 100644 --- a/fs/filesystems.c +++ b/fs/filesystems.c @@ -124,7 +124,7 @@ EXPORT_SYMBOL(unregister_filesystem);  static int fs_index(const char __user * __name)  {  	struct file_system_type * tmp; -	char * name; +	struct filename *name;  	int err, index;  	name = getname(__name); @@ -135,7 +135,7 @@ static int fs_index(const char __user * __name)  	err = -EINVAL;  	read_lock(&file_systems_lock);  	for (tmp=file_systems, index=0 ; tmp ; tmp=tmp->next, index++) { -		if (strcmp(tmp->name,name) == 0) { +		if (strcmp(tmp->name, name->name) == 0) {  			err = index;  			break;  		} diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 401b6c6248a..51ea267d444 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c @@ -249,7 +249,7 @@ static bool inode_dirtied_after(struct inode *inode, unsigned long t)  }  /* - * Move expired (dirtied after work->older_than_this) dirty inodes from + * Move expired (dirtied before work->older_than_this) dirty inodes from   * @delaying_queue to @dispatch_queue.   */  static int move_expired_inodes(struct list_head *delaying_queue, diff --git a/fs/gfs2/export.c b/fs/gfs2/export.c index e8ed6d4a618..4767774a5f3 100644 --- a/fs/gfs2/export.c +++ b/fs/gfs2/export.c @@ -161,6 +161,8 @@ static struct dentry *gfs2_fh_to_dentry(struct super_block *sb, struct fid *fid,  	case GFS2_SMALL_FH_SIZE:  	case GFS2_LARGE_FH_SIZE:  	case GFS2_OLD_FH_SIZE: +		if (fh_len < GFS2_SMALL_FH_SIZE) +			return NULL;  		this.no_formal_ino = ((u64)be32_to_cpu(fh[0])) << 32;  		this.no_formal_ino |= be32_to_cpu(fh[1]);  		this.no_addr = ((u64)be32_to_cpu(fh[2])) << 32; @@ -180,6 +182,8 @@ static struct dentry *gfs2_fh_to_parent(struct super_block *sb, struct fid *fid,  	switch (fh_type) {  	case GFS2_LARGE_FH_SIZE:  	case GFS2_OLD_FH_SIZE: +		if (fh_len < GFS2_LARGE_FH_SIZE) +			return NULL;  		parent.no_formal_ino = ((u64)be32_to_cpu(fh[4])) << 32;  		parent.no_formal_ino |= be32_to_cpu(fh[5]);  		parent.no_addr = ((u64)be32_to_cpu(fh[6])) << 32; diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index bc28bf077a6..a3076228523 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -398,7 +398,6 @@ static int hpfs_remount_fs(struct super_block *s, int *flags, char *data)  	*flags |= MS_NOATIME;  	hpfs_lock(s); -	lock_super(s);  	uid = sbi->sb_uid; gid = sbi->sb_gid;  	umask = 0777 & ~sbi->sb_mode;  	lowercase = sbi->sb_lowercase; @@ -431,12 +430,10 @@ static int hpfs_remount_fs(struct super_block *s, int *flags, char *data)  	replace_mount_options(s, new_opts); -	unlock_super(s);  	hpfs_unlock(s);  	return 0;  out_err: -	unlock_super(s);  	hpfs_unlock(s);  	kfree(new_opts);  	return -EINVAL; diff --git a/fs/internal.h b/fs/internal.h index 371bcc4b169..916b7cbf3e3 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -97,8 +97,8 @@ struct open_flags {  	int acc_mode;  	int intent;  }; -extern struct file *do_filp_open(int dfd, const char *pathname, -		const struct open_flags *op, int lookup_flags); +extern struct file *do_filp_open(int dfd, struct filename *pathname, +		const struct open_flags *op, int flags);  extern struct file *do_file_open_root(struct dentry *, struct vfsmount *,  		const char *, const struct open_flags *, int lookup_flags); diff --git a/fs/isofs/export.c b/fs/isofs/export.c index 1d3804492aa..2b4f2358ead 100644 --- a/fs/isofs/export.c +++ b/fs/isofs/export.c @@ -175,7 +175,7 @@ static struct dentry *isofs_fh_to_parent(struct super_block *sb,  {  	struct isofs_fid *ifid = (struct isofs_fid *)fid; -	if (fh_type != 2) +	if (fh_len < 2 || fh_type != 2)  		return NULL;  	return isofs_export_iget(sb, diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 7e355870d51..a2aa97d4567 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -126,7 +126,7 @@ static void restart_grace(void)  static int  lockd(void *vrqstp)  { -	int		err = 0, preverr = 0; +	int		err = 0;  	struct svc_rqst *rqstp = vrqstp;  	/* try_to_freeze() is called from svc_recv() */ @@ -165,21 +165,8 @@ lockd(void *vrqstp)  		 * recvfrom routine.  		 */  		err = svc_recv(rqstp, timeout); -		if (err == -EAGAIN || err == -EINTR) { -			preverr = err; +		if (err == -EAGAIN || err == -EINTR)  			continue; -		} -		if (err < 0) { -			if (err != preverr) { -				printk(KERN_WARNING "%s: unexpected error " -					"from svc_recv (%d)\n", __func__, err); -				preverr = err; -			} -			schedule_timeout_interruptible(HZ); -			continue; -		} -		preverr = err; -  		dprintk("lockd: request from %s\n",  				svc_print_addr(rqstp, buf, sizeof(buf))); diff --git a/fs/locks.c b/fs/locks.c index abc7dc6c490..a94e331a52a 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -1289,7 +1289,7 @@ EXPORT_SYMBOL(__break_lease);  void lease_get_mtime(struct inode *inode, struct timespec *time)  {  	struct file_lock *flock = inode->i_flock; -	if (flock && IS_LEASE(flock) && (flock->fl_type & F_WRLCK)) +	if (flock && IS_LEASE(flock) && (flock->fl_type == F_WRLCK))  		*time = current_fs_time(inode->i_sb);  	else  		*time = inode->i_mtime; @@ -2185,8 +2185,8 @@ static void lock_get_status(struct seq_file *f, struct file_lock *fl,  	} else {  		seq_printf(f, "%s ",  			       (lease_breaking(fl)) -			       ? (fl->fl_type & F_UNLCK) ? "UNLCK" : "READ " -			       : (fl->fl_type & F_WRLCK) ? "WRITE" : "READ "); +			       ? (fl->fl_type == F_UNLCK) ? "UNLCK" : "READ " +			       : (fl->fl_type == F_WRLCK) ? "WRITE" : "READ ");  	}  	if (inode) {  #ifdef WE_CAN_BREAK_LSLK_NOW diff --git a/fs/namei.c b/fs/namei.c index aa30d19e9ed..d1895f30815 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -117,18 +117,70 @@   * POSIX.1 2.4: an empty pathname is invalid (ENOENT).   * PATH_MAX includes the nul terminator --RR.   */ -static char *getname_flags(const char __user *filename, int flags, int *empty) +void final_putname(struct filename *name)  { -	char *result = __getname(), *err; +	if (name->separate) { +		__putname(name->name); +		kfree(name); +	} else { +		__putname(name); +	} +} + +#define EMBEDDED_NAME_MAX	(PATH_MAX - sizeof(struct filename)) + +static struct filename * +getname_flags(const char __user *filename, int flags, int *empty) +{ +	struct filename *result, *err;  	int len; +	long max; +	char *kname; +	result = audit_reusename(filename); +	if (result) +		return result; + +	result = __getname();  	if (unlikely(!result))  		return ERR_PTR(-ENOMEM); -	len = strncpy_from_user(result, filename, PATH_MAX); -	err = ERR_PTR(len); -	if (unlikely(len < 0)) +	/* +	 * First, try to embed the struct filename inside the names_cache +	 * allocation +	 */ +	kname = (char *)result + sizeof(*result); +	result->name = kname; +	result->separate = false; +	max = EMBEDDED_NAME_MAX; + +recopy: +	len = strncpy_from_user(kname, filename, max); +	if (unlikely(len < 0)) { +		err = ERR_PTR(len);  		goto error; +	} + +	/* +	 * Uh-oh. We have a name that's approaching PATH_MAX. Allocate a +	 * separate struct filename so we can dedicate the entire +	 * names_cache allocation for the pathname, and re-do the copy from +	 * userland. +	 */ +	if (len == EMBEDDED_NAME_MAX && max == EMBEDDED_NAME_MAX) { +		kname = (char *)result; + +		result = kzalloc(sizeof(*result), GFP_KERNEL); +		if (!result) { +			err = ERR_PTR(-ENOMEM); +			result = (struct filename *)kname; +			goto error; +		} +		result->name = kname; +		result->separate = true; +		max = PATH_MAX; +		goto recopy; +	}  	/* The empty path is special. */  	if (unlikely(!len)) { @@ -140,30 +192,32 @@ static char *getname_flags(const char __user *filename, int flags, int *empty)  	}  	err = ERR_PTR(-ENAMETOOLONG); -	if (likely(len < PATH_MAX)) { -		audit_getname(result); -		return result; -	} +	if (unlikely(len >= PATH_MAX)) +		goto error; + +	result->uptr = filename; +	audit_getname(result); +	return result;  error: -	__putname(result); +	final_putname(result);  	return err;  } -char *getname(const char __user * filename) +struct filename * +getname(const char __user * filename)  {  	return getname_flags(filename, 0, NULL);  } +EXPORT_SYMBOL(getname);  #ifdef CONFIG_AUDITSYSCALL -void putname(const char *name) +void putname(struct filename *name)  {  	if (unlikely(!audit_dummy_context())) -		audit_putname(name); -	else -		__putname(name); +		return audit_putname(name); +	final_putname(name);  } -EXPORT_SYMBOL(putname);  #endif  static int check_acl(struct inode *inode, int mask) @@ -692,9 +746,9 @@ static inline int may_follow_link(struct path *link, struct nameidata *nd)  	if (uid_eq(parent->i_uid, inode->i_uid))  		return 0; +	audit_log_link_denied("follow_link", link);  	path_put_conditional(link, nd);  	path_put(&nd->path); -	audit_log_link_denied("follow_link", link);  	return -EACCES;  } @@ -810,6 +864,7 @@ follow_link(struct path *link, struct nameidata *nd, void **p)  	return error;  out_put_nd_path: +	*p = NULL;  	path_put(&nd->path);  	path_put(link);  	return error; @@ -1962,24 +2017,29 @@ static int path_lookupat(int dfd, const char *name,  	return err;  } -static int do_path_lookup(int dfd, const char *name, +static int filename_lookup(int dfd, struct filename *name,  				unsigned int flags, struct nameidata *nd)  { -	int retval = path_lookupat(dfd, name, flags | LOOKUP_RCU, nd); +	int retval = path_lookupat(dfd, name->name, flags | LOOKUP_RCU, nd);  	if (unlikely(retval == -ECHILD)) -		retval = path_lookupat(dfd, name, flags, nd); +		retval = path_lookupat(dfd, name->name, flags, nd);  	if (unlikely(retval == -ESTALE)) -		retval = path_lookupat(dfd, name, flags | LOOKUP_REVAL, nd); +		retval = path_lookupat(dfd, name->name, +						flags | LOOKUP_REVAL, nd); -	if (likely(!retval)) { -		if (unlikely(!audit_dummy_context())) { -			if (nd->path.dentry && nd->inode) -				audit_inode(name, nd->path.dentry); -		} -	} +	if (likely(!retval)) +		audit_inode(name, nd->path.dentry, flags & LOOKUP_PARENT);  	return retval;  } +static int do_path_lookup(int dfd, const char *name, +				unsigned int flags, struct nameidata *nd) +{ +	struct filename filename = { .name = name }; + +	return filename_lookup(dfd, &filename, flags, nd); +} +  /* does lookup, returns the object with parent locked */  struct dentry *kern_path_locked(const char *name, struct path *path)  { @@ -2097,13 +2157,13 @@ int user_path_at_empty(int dfd, const char __user *name, unsigned flags,  		 struct path *path, int *empty)  {  	struct nameidata nd; -	char *tmp = getname_flags(name, flags, empty); +	struct filename *tmp = getname_flags(name, flags, empty);  	int err = PTR_ERR(tmp);  	if (!IS_ERR(tmp)) {  		BUG_ON(flags & LOOKUP_PARENT); -		err = do_path_lookup(dfd, tmp, flags, &nd); +		err = filename_lookup(dfd, tmp, flags, &nd);  		putname(tmp);  		if (!err)  			*path = nd.path; @@ -2117,22 +2177,28 @@ int user_path_at(int dfd, const char __user *name, unsigned flags,  	return user_path_at_empty(dfd, name, flags, path, NULL);  } -static int user_path_parent(int dfd, const char __user *path, -			struct nameidata *nd, char **name) +/* + * NB: most callers don't do anything directly with the reference to the + *     to struct filename, but the nd->last pointer points into the name string + *     allocated by getname. So we must hold the reference to it until all + *     path-walking is complete. + */ +static struct filename * +user_path_parent(int dfd, const char __user *path, struct nameidata *nd)  { -	char *s = getname(path); +	struct filename *s = getname(path);  	int error;  	if (IS_ERR(s)) -		return PTR_ERR(s); +		return s; -	error = do_path_lookup(dfd, s, LOOKUP_PARENT, nd); -	if (error) +	error = filename_lookup(dfd, s, LOOKUP_PARENT, nd); +	if (error) {  		putname(s); -	else -		*name = s; +		return ERR_PTR(error); +	} -	return error; +	return s;  }  /* @@ -2179,7 +2245,7 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir)  		return -ENOENT;  	BUG_ON(victim->d_parent->d_inode != dir); -	audit_inode_child(victim, dir); +	audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE);  	error = inode_permission(dir, MAY_WRITE | MAY_EXEC);  	if (error) @@ -2624,7 +2690,7 @@ out_dput:   */  static int do_last(struct nameidata *nd, struct path *path,  		   struct file *file, const struct open_flags *op, -		   int *opened, const char *pathname) +		   int *opened, struct filename *name)  {  	struct dentry *dir = nd->path.dentry;  	int open_flag = op->open_flag; @@ -2651,7 +2717,7 @@ static int do_last(struct nameidata *nd, struct path *path,  		error = complete_walk(nd);  		if (error)  			return error; -		audit_inode(pathname, nd->path.dentry); +		audit_inode(name, nd->path.dentry, 0);  		if (open_flag & O_CREAT) {  			error = -EISDIR;  			goto out; @@ -2661,7 +2727,7 @@ static int do_last(struct nameidata *nd, struct path *path,  		error = complete_walk(nd);  		if (error)  			return error; -		audit_inode(pathname, dir); +		audit_inode(name, dir, 0);  		goto finish_open;  	} @@ -2690,7 +2756,7 @@ static int do_last(struct nameidata *nd, struct path *path,  		if (error)  			return error; -		audit_inode(pathname, dir); +		audit_inode(name, dir, 0);  		error = -EISDIR;  		/* trailing slashes? */  		if (nd->last.name[nd->last.len]) @@ -2720,7 +2786,7 @@ retry_lookup:  		    !S_ISREG(file->f_path.dentry->d_inode->i_mode))  			will_truncate = false; -		audit_inode(pathname, file->f_path.dentry); +		audit_inode(name, file->f_path.dentry, 0);  		goto opened;  	} @@ -2737,7 +2803,7 @@ retry_lookup:  	 * create/update audit record if it already exists.  	 */  	if (path->dentry->d_inode) -		audit_inode(pathname, path->dentry); +		audit_inode(name, path->dentry, 0);  	/*  	 * If atomic_open() acquired write access it is dropped now due to @@ -2802,7 +2868,7 @@ finish_lookup:  	error = -ENOTDIR;  	if ((nd->flags & LOOKUP_DIRECTORY) && !nd->inode->i_op->lookup)  		goto out; -	audit_inode(pathname, nd->path.dentry); +	audit_inode(name, nd->path.dentry, 0);  finish_open:  	if (!S_ISREG(nd->inode->i_mode))  		will_truncate = false; @@ -2870,7 +2936,7 @@ stale_open:  	goto retry_lookup;  } -static struct file *path_openat(int dfd, const char *pathname, +static struct file *path_openat(int dfd, struct filename *pathname,  		struct nameidata *nd, const struct open_flags *op, int flags)  {  	struct file *base = NULL; @@ -2885,12 +2951,12 @@ static struct file *path_openat(int dfd, const char *pathname,  	file->f_flags = op->open_flag; -	error = path_init(dfd, pathname, flags | LOOKUP_PARENT, nd, &base); +	error = path_init(dfd, pathname->name, flags | LOOKUP_PARENT, nd, &base);  	if (unlikely(error))  		goto out;  	current->total_link_count = 0; -	error = link_path_walk(pathname, nd); +	error = link_path_walk(pathname->name, nd);  	if (unlikely(error))  		goto out; @@ -2936,7 +3002,7 @@ out:  	return file;  } -struct file *do_filp_open(int dfd, const char *pathname, +struct file *do_filp_open(int dfd, struct filename *pathname,  		const struct open_flags *op, int flags)  {  	struct nameidata nd; @@ -2955,6 +3021,7 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,  {  	struct nameidata nd;  	struct file *file; +	struct filename filename = { .name = name };  	nd.root.mnt = mnt;  	nd.root.dentry = dentry; @@ -2964,11 +3031,11 @@ struct file *do_file_open_root(struct dentry *dentry, struct vfsmount *mnt,  	if (dentry->d_inode->i_op->follow_link && op->intent & LOOKUP_OPEN)  		return ERR_PTR(-ELOOP); -	file = path_openat(-1, name, &nd, op, flags | LOOKUP_RCU); +	file = path_openat(-1, &filename, &nd, op, flags | LOOKUP_RCU);  	if (unlikely(file == ERR_PTR(-ECHILD))) -		file = path_openat(-1, name, &nd, op, flags); +		file = path_openat(-1, &filename, &nd, op, flags);  	if (unlikely(file == ERR_PTR(-ESTALE))) -		file = path_openat(-1, name, &nd, op, flags | LOOKUP_REVAL); +		file = path_openat(-1, &filename, &nd, op, flags | LOOKUP_REVAL);  	return file;  } @@ -3043,11 +3110,11 @@ EXPORT_SYMBOL(done_path_create);  struct dentry *user_path_create(int dfd, const char __user *pathname, struct path *path, int is_dir)  { -	char *tmp = getname(pathname); +	struct filename *tmp = getname(pathname);  	struct dentry *res;  	if (IS_ERR(tmp))  		return ERR_CAST(tmp); -	res = kern_path_create(dfd, tmp, path, is_dir); +	res = kern_path_create(dfd, tmp->name, path, is_dir);  	putname(tmp);  	return res;  } @@ -3252,13 +3319,13 @@ out:  static long do_rmdir(int dfd, const char __user *pathname)  {  	int error = 0; -	char * name; +	struct filename *name;  	struct dentry *dentry;  	struct nameidata nd; -	error = user_path_parent(dfd, pathname, &nd, &name); -	if (error) -		return error; +	name = user_path_parent(dfd, pathname, &nd); +	if (IS_ERR(name)) +		return PTR_ERR(name);  	switch(nd.last_type) {  	case LAST_DOTDOT: @@ -3347,14 +3414,14 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry)  static long do_unlinkat(int dfd, const char __user *pathname)  {  	int error; -	char *name; +	struct filename *name;  	struct dentry *dentry;  	struct nameidata nd;  	struct inode *inode = NULL; -	error = user_path_parent(dfd, pathname, &nd, &name); -	if (error) -		return error; +	name = user_path_parent(dfd, pathname, &nd); +	if (IS_ERR(name)) +		return PTR_ERR(name);  	error = -EISDIR;  	if (nd.last_type != LAST_NORM) @@ -3438,7 +3505,7 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,  		int, newdfd, const char __user *, newname)  {  	int error; -	char *from; +	struct filename *from;  	struct dentry *dentry;  	struct path path; @@ -3451,9 +3518,9 @@ SYSCALL_DEFINE3(symlinkat, const char __user *, oldname,  	if (IS_ERR(dentry))  		goto out_putname; -	error = security_path_symlink(&path, dentry, from); +	error = security_path_symlink(&path, dentry, from->name);  	if (!error) -		error = vfs_symlink(path.dentry->d_inode, dentry, from); +		error = vfs_symlink(path.dentry->d_inode, dentry, from->name);  	done_path_create(&path, dentry);  out_putname:  	putname(from); @@ -3733,17 +3800,21 @@ SYSCALL_DEFINE4(renameat, int, olddfd, const char __user *, oldname,  	struct dentry *old_dentry, *new_dentry;  	struct dentry *trap;  	struct nameidata oldnd, newnd; -	char *from; -	char *to; +	struct filename *from; +	struct filename *to;  	int error; -	error = user_path_parent(olddfd, oldname, &oldnd, &from); -	if (error) +	from = user_path_parent(olddfd, oldname, &oldnd); +	if (IS_ERR(from)) { +		error = PTR_ERR(from);  		goto exit; +	} -	error = user_path_parent(newdfd, newname, &newnd, &to); -	if (error) +	to = user_path_parent(newdfd, newname, &newnd); +	if (IS_ERR(to)) { +		error = PTR_ERR(to);  		goto exit1; +	}  	error = -EXDEV;  	if (oldnd.path.mnt != newnd.path.mnt) @@ -3967,7 +4038,6 @@ EXPORT_SYMBOL(follow_down_one);  EXPORT_SYMBOL(follow_down);  EXPORT_SYMBOL(follow_up);  EXPORT_SYMBOL(get_write_access); /* nfsd */ -EXPORT_SYMBOL(getname);  EXPORT_SYMBOL(lock_rename);  EXPORT_SYMBOL(lookup_one_len);  EXPORT_SYMBOL(page_follow_link_light); diff --git a/fs/namespace.c b/fs/namespace.c index 7bdf7907413..24960626bb6 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1640,7 +1640,7 @@ static int do_change_type(struct path *path, int flag)  /*   * do loopback mount.   */ -static int do_loopback(struct path *path, char *old_name, +static int do_loopback(struct path *path, const char *old_name,  				int recurse)  {  	LIST_HEAD(umount_list); @@ -1764,7 +1764,7 @@ static inline int tree_contains_unbindable(struct mount *mnt)  	return 0;  } -static int do_move_mount(struct path *path, char *old_name) +static int do_move_mount(struct path *path, const char *old_name)  {  	struct path old_path, parent_path;  	struct mount *p; @@ -1917,8 +1917,8 @@ unlock:   * create a new mount for userspace and request it to be added into the   * namespace's tree   */ -static int do_new_mount(struct path *path, char *type, int flags, -			int mnt_flags, char *name, void *data) +static int do_new_mount(struct path *path, const char *type, int flags, +			int mnt_flags, const char *name, void *data)  {  	struct vfsmount *mnt;  	int err; @@ -2191,8 +2191,8 @@ int copy_mount_string(const void __user *data, char **where)   * Therefore, if this magic number is present, it carries no information   * and must be discarded.   */ -long do_mount(char *dev_name, char *dir_name, char *type_page, -		  unsigned long flags, void *data_page) +long do_mount(const char *dev_name, const char *dir_name, +		const char *type_page, unsigned long flags, void *data_page)  {  	struct path path;  	int retval = 0; @@ -2408,7 +2408,7 @@ SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,  {  	int ret;  	char *kernel_type; -	char *kernel_dir; +	struct filename *kernel_dir;  	char *kernel_dev;  	unsigned long data_page; @@ -2430,7 +2430,7 @@ SYSCALL_DEFINE5(mount, char __user *, dev_name, char __user *, dir_name,  	if (ret < 0)  		goto out_data; -	ret = do_mount(kernel_dev, kernel_dir, kernel_type, flags, +	ret = do_mount(kernel_dev, kernel_dir->name, kernel_type, flags,  		(void *) data_page);  	free_page(data_page); diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 2245bef50f3..9a521fb3986 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c @@ -72,7 +72,7 @@ out_err:  static int  nfs4_callback_svc(void *vrqstp)  { -	int err, preverr = 0; +	int err;  	struct svc_rqst *rqstp = vrqstp;  	set_freezable(); @@ -82,20 +82,8 @@ nfs4_callback_svc(void *vrqstp)  		 * Listen for a request on the socket  		 */  		err = svc_recv(rqstp, MAX_SCHEDULE_TIMEOUT); -		if (err == -EAGAIN || err == -EINTR) { -			preverr = err; +		if (err == -EAGAIN || err == -EINTR)  			continue; -		} -		if (err < 0) { -			if (err != preverr) { -				printk(KERN_WARNING "NFS: %s: unexpected error " -					"from svc_recv (%d)\n", __func__, err); -				preverr = err; -			} -			schedule_timeout_uninterruptible(HZ); -			continue; -		} -		preverr = err;  		svc_process(rqstp);  	}  	return 0; diff --git a/fs/nfsd/nfs2acl.c b/fs/nfsd/nfs2acl.c index 6aa5590c367..b314888825d 100644 --- a/fs/nfsd/nfs2acl.c +++ b/fs/nfsd/nfs2acl.c @@ -218,8 +218,7 @@ static int nfsaclsvc_decode_accessargs(struct svc_rqst *rqstp, __be32 *p,   * There must be an encoding function for void results so svc_process   * will work properly.   */ -int -nfsaclsvc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy) +static int nfsaclsvc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy)  {  	return xdr_ressize_check(rqstp, p);  } diff --git a/fs/nfsd/nfs3proc.c b/fs/nfsd/nfs3proc.c index 9095f3c21df..97d90d1c860 100644 --- a/fs/nfsd/nfs3proc.c +++ b/fs/nfsd/nfs3proc.c @@ -247,7 +247,7 @@ nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,  	/* Now create the file and set attributes */  	nfserr = do_nfsd_create(rqstp, dirfhp, argp->name, argp->len,  				attr, newfhp, -				argp->createmode, argp->verf, NULL, NULL); +				argp->createmode, (u32 *)argp->verf, NULL, NULL);  	RETURN_STATUS(nfserr);  } diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 4c7bd35b187..bdf29c96e4c 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -1028,7 +1028,6 @@ void nfsd4_cb_recall(struct nfs4_delegation *dp)  	cb->cb_msg.rpc_cred = callback_cred;  	cb->cb_ops = &nfsd4_cb_recall_ops; -	dp->dl_retries = 1;  	INIT_LIST_HEAD(&cb->cb_per_client);  	cb->cb_done = true; diff --git a/fs/nfsd/nfs4idmap.c b/fs/nfsd/nfs4idmap.c index fdc91a6fc9c..a1f10c0a625 100644 --- a/fs/nfsd/nfs4idmap.c +++ b/fs/nfsd/nfs4idmap.c @@ -478,7 +478,7 @@ nfsd_idmap_init(struct net *net)  		goto destroy_idtoname_cache;  	nn->nametoid_cache = cache_create_net(&nametoid_cache_template, net);  	if (IS_ERR(nn->nametoid_cache)) { -		rv = PTR_ERR(nn->idtoname_cache); +		rv = PTR_ERR(nn->nametoid_cache);  		goto unregister_idtoname_cache;  	}  	rv = cache_register_net(nn->nametoid_cache, net); @@ -598,7 +598,7 @@ numeric_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namel  	/* Just to make sure it's null-terminated: */  	memcpy(buf, name, namelen);  	buf[namelen] = '\0'; -	ret = kstrtouint(name, 10, id); +	ret = kstrtouint(buf, 10, id);  	return ret == 0;  } diff --git a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c index c9c1c0a2541..6c9a4b291db 100644 --- a/fs/nfsd/nfs4proc.c +++ b/fs/nfsd/nfs4proc.c @@ -370,7 +370,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,  			break;  		case NFS4_OPEN_CLAIM_PREVIOUS:  			open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED; -			status = nfs4_check_open_reclaim(&open->op_clientid); +			status = nfs4_check_open_reclaim(&open->op_clientid, cstate->minorversion);  			if (status)  				goto out;  		case NFS4_OPEN_CLAIM_FH: @@ -1054,8 +1054,8 @@ struct nfsd4_operation {  	char *op_name;  	/* Try to get response size before operation */  	nfsd4op_rsize op_rsize_bop; -	stateid_setter op_get_currentstateid; -	stateid_getter op_set_currentstateid; +	stateid_getter op_get_currentstateid; +	stateid_setter op_set_currentstateid;  };  static struct nfsd4_operation nfsd4_ops[]; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 48a1bad3733..d0237f872cc 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -758,7 +758,7 @@ static void nfsd4_put_drc_mem(int slotsize, int num)  	spin_unlock(&nfsd_drc_lock);  } -static struct nfsd4_session *alloc_session(int slotsize, int numslots) +static struct nfsd4_session *__alloc_session(int slotsize, int numslots)  {  	struct nfsd4_session *new;  	int mem, i; @@ -852,35 +852,28 @@ static int nfsd4_register_conn(struct nfsd4_conn *conn)  	return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user);  } -static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses, u32 dir) +static void nfsd4_init_conn(struct svc_rqst *rqstp, struct nfsd4_conn *conn, struct nfsd4_session *ses)  { -	struct nfsd4_conn *conn;  	int ret; -	conn = alloc_conn(rqstp, dir); -	if (!conn) -		return nfserr_jukebox;  	nfsd4_hash_conn(conn, ses);  	ret = nfsd4_register_conn(conn);  	if (ret)  		/* oops; xprt is already down: */  		nfsd4_conn_lost(&conn->cn_xpt_user); -	if (ses->se_client->cl_cb_state == NFSD4_CB_DOWN && -		dir & NFS4_CDFC4_BACK) { +	if (conn->cn_flags & NFS4_CDFC4_BACK) {  		/* callback channel may be back up */  		nfsd4_probe_callback(ses->se_client);  	} -	return nfs_ok;  } -static __be32 nfsd4_new_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_session *ses) +static struct nfsd4_conn *alloc_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_create_session *cses)  {  	u32 dir = NFS4_CDFC4_FORE; -	if (ses->se_flags & SESSION4_BACK_CHAN) +	if (cses->flags & SESSION4_BACK_CHAN)  		dir |= NFS4_CDFC4_BACK; - -	return nfsd4_new_conn(rqstp, ses, dir); +	return alloc_conn(rqstp, dir);  }  /* must be called under client_lock */ @@ -903,20 +896,21 @@ static void nfsd4_del_conns(struct nfsd4_session *s)  	spin_unlock(&clp->cl_lock);  } +static void __free_session(struct nfsd4_session *ses) +{ +	nfsd4_put_drc_mem(slot_bytes(&ses->se_fchannel), ses->se_fchannel.maxreqs); +	free_session_slots(ses); +	kfree(ses); +} +  static void free_session(struct kref *kref)  {  	struct nfsd4_session *ses; -	int mem;  	lockdep_assert_held(&client_lock);  	ses = container_of(kref, struct nfsd4_session, se_ref);  	nfsd4_del_conns(ses); -	spin_lock(&nfsd_drc_lock); -	mem = ses->se_fchannel.maxreqs * slot_bytes(&ses->se_fchannel); -	nfsd_drc_mem_used -= mem; -	spin_unlock(&nfsd_drc_lock); -	free_session_slots(ses); -	kfree(ses); +	__free_session(ses);  }  void nfsd4_put_session(struct nfsd4_session *ses) @@ -926,14 +920,10 @@ void nfsd4_put_session(struct nfsd4_session *ses)  	spin_unlock(&client_lock);  } -static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, struct nfsd4_create_session *cses) +static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fchan)  {  	struct nfsd4_session *new; -	struct nfsd4_channel_attrs *fchan = &cses->fore_channel;  	int numslots, slotsize; -	__be32 status; -	int idx; -  	/*  	 * Note decreasing slot size below client's request may  	 * make it difficult for client to function correctly, whereas @@ -946,12 +936,18 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n  	if (numslots < 1)  		return NULL; -	new = alloc_session(slotsize, numslots); +	new = __alloc_session(slotsize, numslots);  	if (!new) {  		nfsd4_put_drc_mem(slotsize, fchan->maxreqs);  		return NULL;  	}  	init_forechannel_attrs(&new->se_fchannel, fchan, numslots, slotsize); +	return new; +} + +static struct nfsd4_session *init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, struct nfs4_client *clp, struct nfsd4_create_session *cses) +{ +	int idx;  	new->se_client = clp;  	gen_sessionid(new); @@ -970,14 +966,6 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n  	spin_unlock(&clp->cl_lock);  	spin_unlock(&client_lock); -	status = nfsd4_new_conn_from_crses(rqstp, new); -	/* whoops: benny points out, status is ignored! (err, or bogus) */ -	if (status) { -		spin_lock(&client_lock); -		free_session(&new->se_ref); -		spin_unlock(&client_lock); -		return NULL; -	}  	if (cses->flags & SESSION4_BACK_CHAN) {  		struct sockaddr *sa = svc_addr(rqstp);  		/* @@ -990,7 +978,6 @@ static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct n  		rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa);  		clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa);  	} -	nfsd4_probe_callback(clp);  	return new;  } @@ -1131,7 +1118,7 @@ unhash_client_locked(struct nfs4_client *clp)  }  static void -expire_client(struct nfs4_client *clp) +destroy_client(struct nfs4_client *clp)  {  	struct nfs4_openowner *oo;  	struct nfs4_delegation *dp; @@ -1165,6 +1152,12 @@ expire_client(struct nfs4_client *clp)  	spin_unlock(&client_lock);  } +static void expire_client(struct nfs4_client *clp) +{ +	nfsd4_client_record_remove(clp); +	destroy_client(clp); +} +  static void copy_verf(struct nfs4_client *target, nfs4_verifier *source)  {  	memcpy(target->cl_verifier.data, source->data, @@ -1223,10 +1216,26 @@ static bool groups_equal(struct group_info *g1, struct group_info *g2)  	return true;  } +/* + * RFC 3530 language requires clid_inuse be returned when the + * "principal" associated with a requests differs from that previously + * used.  We use uid, gid's, and gss principal string as our best + * approximation.  We also don't want to allow non-gss use of a client + * established using gss: in theory cr_principal should catch that + * change, but in practice cr_principal can be null even in the gss case + * since gssd doesn't always pass down a principal string. + */ +static bool is_gss_cred(struct svc_cred *cr) +{ +	/* Is cr_flavor one of the gss "pseudoflavors"?: */ +	return (cr->cr_flavor > RPC_AUTH_MAXFLAVOR); +} + +  static bool  same_creds(struct svc_cred *cr1, struct svc_cred *cr2)  { -	if ((cr1->cr_flavor != cr2->cr_flavor) +	if ((is_gss_cred(cr1) != is_gss_cred(cr2))  		|| (cr1->cr_uid != cr2->cr_uid)  		|| (cr1->cr_gid != cr2->cr_gid)  		|| !groups_equal(cr1->cr_group_info, cr2->cr_group_info)) @@ -1340,13 +1349,15 @@ move_to_confirmed(struct nfs4_client *clp)  }  static struct nfs4_client * -find_confirmed_client(clientid_t *clid) +find_confirmed_client(clientid_t *clid, bool sessions)  {  	struct nfs4_client *clp;  	unsigned int idhashval = clientid_hashval(clid->cl_id);  	list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) {  		if (same_clid(&clp->cl_clientid, clid)) { +			if ((bool)clp->cl_minorversion != sessions) +				return NULL;  			renew_client(clp);  			return clp;  		} @@ -1355,14 +1366,17 @@ find_confirmed_client(clientid_t *clid)  }  static struct nfs4_client * -find_unconfirmed_client(clientid_t *clid) +find_unconfirmed_client(clientid_t *clid, bool sessions)  {  	struct nfs4_client *clp;  	unsigned int idhashval = clientid_hashval(clid->cl_id);  	list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) { -		if (same_clid(&clp->cl_clientid, clid)) +		if (same_clid(&clp->cl_clientid, clid)) { +			if ((bool)clp->cl_minorversion != sessions) +				return NULL;  			return clp; +		}  	}  	return NULL;  } @@ -1651,6 +1665,7 @@ out_new:  		status = nfserr_jukebox;  		goto out;  	} +	new->cl_minorversion = 1;  	gen_clid(new);  	add_to_unconfirmed(new, strhashval); @@ -1743,67 +1758,71 @@ nfsd4_create_session(struct svc_rqst *rqstp,  	struct sockaddr *sa = svc_addr(rqstp);  	struct nfs4_client *conf, *unconf;  	struct nfsd4_session *new; +	struct nfsd4_conn *conn;  	struct nfsd4_clid_slot *cs_slot = NULL; -	bool confirm_me = false;  	__be32 status = 0;  	if (cr_ses->flags & ~SESSION4_FLAG_MASK_A)  		return nfserr_inval; +	if (check_forechannel_attrs(cr_ses->fore_channel)) +		return nfserr_toosmall; +	new = alloc_session(&cr_ses->fore_channel); +	if (!new) +		return nfserr_jukebox; +	status = nfserr_jukebox; +	conn = alloc_conn_from_crses(rqstp, cr_ses); +	if (!conn) +		goto out_free_session;  	nfs4_lock_state(); -	unconf = find_unconfirmed_client(&cr_ses->clientid); -	conf = find_confirmed_client(&cr_ses->clientid); +	unconf = find_unconfirmed_client(&cr_ses->clientid, true); +	conf = find_confirmed_client(&cr_ses->clientid, true);  	if (conf) {  		cs_slot = &conf->cl_cs_slot;  		status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);  		if (status == nfserr_replay_cache) {  			status = nfsd4_replay_create_session(cr_ses, cs_slot); -			goto out; +			goto out_free_conn;  		} else if (cr_ses->seqid != cs_slot->sl_seqid + 1) {  			status = nfserr_seq_misordered; -			goto out; +			goto out_free_conn;  		}  	} else if (unconf) { +		unsigned int hash; +		struct nfs4_client *old;  		if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) ||  		    !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) {  			status = nfserr_clid_inuse; -			goto out; +			goto out_free_conn;  		}  		cs_slot = &unconf->cl_cs_slot;  		status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);  		if (status) {  			/* an unconfirmed replay returns misordered */  			status = nfserr_seq_misordered; -			goto out; +			goto out_free_conn;  		} -		confirm_me = true; +		hash = clientstr_hashval(unconf->cl_recdir); +		old = find_confirmed_client_by_str(unconf->cl_recdir, hash); +		if (old) +			expire_client(old); +		move_to_confirmed(unconf);  		conf = unconf;  	} else {  		status = nfserr_stale_clientid; -		goto out; +		goto out_free_conn;  	} - -	/* -	 * XXX: we should probably set this at creation time, and check -	 * for consistent minorversion use throughout: -	 */ -	conf->cl_minorversion = 1; +	status = nfs_ok;  	/*  	 * We do not support RDMA or persistent sessions  	 */  	cr_ses->flags &= ~SESSION4_PERSIST;  	cr_ses->flags &= ~SESSION4_RDMA; -	status = nfserr_toosmall; -	if (check_forechannel_attrs(cr_ses->fore_channel)) -		goto out; +	init_session(rqstp, new, conf, cr_ses); +	nfsd4_init_conn(rqstp, conn, new); -	status = nfserr_jukebox; -	new = alloc_init_session(rqstp, conf, cr_ses); -	if (!new) -		goto out; -	status = nfs_ok;  	memcpy(cr_ses->sessionid.data, new->se_sessionid.data,  	       NFS4_MAX_SESSIONID_LEN);  	memcpy(&cr_ses->fore_channel, &new->se_fchannel, @@ -1813,18 +1832,15 @@ nfsd4_create_session(struct svc_rqst *rqstp,  	/* cache solo and embedded create sessions under the state lock */  	nfsd4_cache_create_session(cr_ses, cs_slot, status); -	if (confirm_me) { -		unsigned int hash = clientstr_hashval(unconf->cl_recdir); -		struct nfs4_client *old = -			find_confirmed_client_by_str(conf->cl_recdir, hash); -		if (old) -			expire_client(old); -		move_to_confirmed(conf); -	}  out:  	nfs4_unlock_state();  	dprintk("%s returns %d\n", __func__, ntohl(status));  	return status; +out_free_conn: +	free_conn(conn); +out_free_session: +	__free_session(new); +	goto out;  }  static bool nfsd4_last_compound_op(struct svc_rqst *rqstp) @@ -1854,6 +1870,7 @@ __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,  		     struct nfsd4_bind_conn_to_session *bcts)  {  	__be32 status; +	struct nfsd4_conn *conn;  	if (!nfsd4_last_compound_op(rqstp))  		return nfserr_not_only_op; @@ -1870,9 +1887,13 @@ __be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,  		return nfserr_badsession;  	status = nfsd4_map_bcts_dir(&bcts->dir); -	if (!status) -		nfsd4_new_conn(rqstp, cstate->session, bcts->dir); -	return status; +	if (status) +		return status; +	conn = alloc_conn(rqstp, bcts->dir); +	if (!conn) +		return nfserr_jukebox; +	nfsd4_init_conn(rqstp, conn, cstate->session); +	return nfs_ok;  }  static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid) @@ -2085,8 +2106,8 @@ nfsd4_destroy_clientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *csta  	__be32 status = 0;  	nfs4_lock_state(); -	unconf = find_unconfirmed_client(&dc->clientid); -	conf = find_confirmed_client(&dc->clientid); +	unconf = find_unconfirmed_client(&dc->clientid, true); +	conf = find_confirmed_client(&dc->clientid, true);  	if (conf) {  		clp = conf; @@ -2200,10 +2221,6 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,  		copy_clid(new, conf);  	else /* case 4 (new client) or cases 2, 3 (client reboot): */  		gen_clid(new); -	/* -	 * XXX: we should probably set this at creation time, and check -	 * for consistent minorversion use throughout: -	 */  	new->cl_minorversion = 0;  	gen_callback(new, setclid, rqstp);  	add_to_unconfirmed(new, strhashval); @@ -2232,8 +2249,8 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,  		return nfserr_stale_clientid;  	nfs4_lock_state(); -	conf = find_confirmed_client(clid); -	unconf = find_unconfirmed_client(clid); +	conf = find_confirmed_client(clid, false); +	unconf = find_unconfirmed_client(clid, false);  	/*  	 * We try hard to give out unique clientid's, so if we get an  	 * attempt to confirm the same clientid with a different cred, @@ -2262,10 +2279,8 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp,  		unsigned int hash = clientstr_hashval(unconf->cl_recdir);  		conf = find_confirmed_client_by_str(unconf->cl_recdir, hash); -		if (conf) { -			nfsd4_client_record_remove(conf); +		if (conf)  			expire_client(conf); -		}  		move_to_confirmed(unconf);  		nfsd4_probe_callback(unconf);  	} @@ -2447,16 +2462,20 @@ same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner,  }  static struct nfs4_openowner * -find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open) +find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open, bool sessions)  {  	struct nfs4_stateowner *so;  	struct nfs4_openowner *oo; +	struct nfs4_client *clp;  	list_for_each_entry(so, &ownerstr_hashtbl[hashval], so_strhash) {  		if (!so->so_is_open_owner)  			continue;  		if (same_owner_str(so, &open->op_owner, &open->op_clientid)) {  			oo = openowner(so); +			clp = oo->oo_owner.so_client; +			if ((bool)clp->cl_minorversion != sessions) +				return NULL;  			renew_client(oo->oo_owner.so_client);  			return oo;  		} @@ -2600,10 +2619,10 @@ nfsd4_process_open1(struct nfsd4_compound_state *cstate,  		return nfserr_jukebox;  	strhashval = ownerstr_hashval(clientid->cl_id, &open->op_owner); -	oo = find_openstateowner_str(strhashval, open); +	oo = find_openstateowner_str(strhashval, open, cstate->minorversion);  	open->op_openowner = oo;  	if (!oo) { -		clp = find_confirmed_client(clientid); +		clp = find_confirmed_client(clientid, cstate->minorversion);  		if (clp == NULL)  			return nfserr_expired;  		goto new_owner; @@ -2705,11 +2724,6 @@ nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_ol_st  	return nfs_ok;  } -static void nfs4_free_stateid(struct nfs4_ol_stateid *s) -{ -	kmem_cache_free(stateid_slab, s); -} -  static inline int nfs4_access_to_access(u32 nfs4_access)  {  	int flags = 0; @@ -3087,7 +3101,7 @@ void nfsd4_cleanup_open_state(struct nfsd4_open *open, __be32 status)  	if (open->op_file)  		nfsd4_free_file(open->op_file);  	if (open->op_stp) -		nfs4_free_stateid(open->op_stp); +		free_generic_stateid(open->op_stp);  }  __be32 @@ -3104,7 +3118,7 @@ nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,  	status = nfserr_stale_clientid;  	if (STALE_CLIENTID(clid, nn))  		goto out; -	clp = find_confirmed_client(clid); +	clp = find_confirmed_client(clid, cstate->minorversion);  	status = nfserr_expired;  	if (clp == NULL) {  		/* We assume the client took too long to RENEW. */ @@ -3180,7 +3194,6 @@ nfs4_laundromat(void)  		clp = list_entry(pos, struct nfs4_client, cl_lru);  		dprintk("NFSD: purging unused client (clientid %08x)\n",  			clp->cl_clientid.cl_id); -		nfsd4_client_record_remove(clp);  		expire_client(clp);  	}  	spin_lock(&recall_lock); @@ -3372,7 +3385,7 @@ static __be32 nfsd4_validate_stateid(struct nfs4_client *cl, stateid_t *stateid)  	return nfs_ok;  } -static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, struct nfs4_stid **s) +static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, struct nfs4_stid **s, bool sessions)  {  	struct nfs4_client *cl;  	struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); @@ -3381,7 +3394,7 @@ static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask, s  		return nfserr_bad_stateid;  	if (STALE_STATEID(stateid, nn))  		return nfserr_stale_stateid; -	cl = find_confirmed_client(&stateid->si_opaque.so_clid); +	cl = find_confirmed_client(&stateid->si_opaque.so_clid, sessions);  	if (!cl)  		return nfserr_expired;  	*s = find_stateid_by_type(cl, stateid, typemask); @@ -3414,7 +3427,7 @@ nfs4_preprocess_stateid_op(struct net *net, struct nfsd4_compound_state *cstate,  	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))  		return check_special_stateids(net, current_fh, stateid, flags); -	status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, &s); +	status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID|NFS4_OPEN_STID|NFS4_LOCK_STID, &s, cstate->minorversion);  	if (status)  		return status;  	status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate)); @@ -3564,7 +3577,7 @@ nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,  		seqid, STATEID_VAL(stateid));  	*stpp = NULL; -	status = nfsd4_lookup_stateid(stateid, typemask, &s); +	status = nfsd4_lookup_stateid(stateid, typemask, &s, cstate->minorversion);  	if (status)  		return status;  	*stpp = openlockstateid(s); @@ -3765,6 +3778,7 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,  	memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));  	nfsd4_close_open_stateid(stp); +	release_last_closed_stateid(oo);  	oo->oo_last_closed_stid = stp;  	if (list_empty(&oo->oo_owner.so_stateids)) { @@ -3801,7 +3815,7 @@ nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,  	inode = cstate->current_fh.fh_dentry->d_inode;  	nfs4_lock_state(); -	status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID, &s); +	status = nfsd4_lookup_stateid(stateid, NFS4_DELEG_STID, &s, cstate->minorversion);  	if (status)  		goto out;  	dp = delegstateid(s); @@ -4045,8 +4059,8 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,  	struct nfs4_lockowner *lock_sop = NULL;  	struct nfs4_ol_stateid *lock_stp;  	struct file *filp = NULL; -	struct file_lock file_lock; -	struct file_lock conflock; +	struct file_lock *file_lock = NULL; +	struct file_lock *conflock = NULL;  	__be32 status = 0;  	bool new_state = false;  	int lkflg; @@ -4116,21 +4130,28 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,  	if (!locks_in_grace(SVC_NET(rqstp)) && lock->lk_reclaim)  		goto out; -	locks_init_lock(&file_lock); +	file_lock = locks_alloc_lock(); +	if (!file_lock) { +		dprintk("NFSD: %s: unable to allocate lock!\n", __func__); +		status = nfserr_jukebox; +		goto out; +	} + +	locks_init_lock(file_lock);  	switch (lock->lk_type) {  		case NFS4_READ_LT:  		case NFS4_READW_LT:  			filp = find_readable_file(lock_stp->st_file);  			if (filp)  				get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ); -			file_lock.fl_type = F_RDLCK; +			file_lock->fl_type = F_RDLCK;  			break;  		case NFS4_WRITE_LT:  		case NFS4_WRITEW_LT:  			filp = find_writeable_file(lock_stp->st_file);  			if (filp)  				get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE); -			file_lock.fl_type = F_WRLCK; +			file_lock->fl_type = F_WRLCK;  			break;  		default:  			status = nfserr_inval; @@ -4140,22 +4161,23 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,  		status = nfserr_openmode;  		goto out;  	} -	file_lock.fl_owner = (fl_owner_t)lock_sop; -	file_lock.fl_pid = current->tgid; -	file_lock.fl_file = filp; -	file_lock.fl_flags = FL_POSIX; -	file_lock.fl_lmops = &nfsd_posix_mng_ops; +	file_lock->fl_owner = (fl_owner_t)lock_sop; +	file_lock->fl_pid = current->tgid; +	file_lock->fl_file = filp; +	file_lock->fl_flags = FL_POSIX; +	file_lock->fl_lmops = &nfsd_posix_mng_ops; +	file_lock->fl_start = lock->lk_offset; +	file_lock->fl_end = last_byte_offset(lock->lk_offset, lock->lk_length); +	nfs4_transform_lock_offset(file_lock); -	file_lock.fl_start = lock->lk_offset; -	file_lock.fl_end = last_byte_offset(lock->lk_offset, lock->lk_length); -	nfs4_transform_lock_offset(&file_lock); - -	/* -	* Try to lock the file in the VFS. -	* Note: locks.c uses the BKL to protect the inode's lock list. -	*/ +	conflock = locks_alloc_lock(); +	if (!conflock) { +		dprintk("NFSD: %s: unable to allocate lock!\n", __func__); +		status = nfserr_jukebox; +		goto out; +	} -	err = vfs_lock_file(filp, F_SETLK, &file_lock, &conflock); +	err = vfs_lock_file(filp, F_SETLK, file_lock, conflock);  	switch (-err) {  	case 0: /* success! */  		update_stateid(&lock_stp->st_stid.sc_stateid); @@ -4166,7 +4188,7 @@ nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,  	case (EAGAIN):		/* conflock holds conflicting lock */  		status = nfserr_denied;  		dprintk("NFSD: nfsd4_lock: conflicting lock found!\n"); -		nfs4_set_lock_denied(&conflock, &lock->lk_denied); +		nfs4_set_lock_denied(conflock, &lock->lk_denied);  		break;  	case (EDEADLK):  		status = nfserr_deadlock; @@ -4181,6 +4203,10 @@ out:  		release_lockowner(lock_sop);  	if (!cstate->replay_owner)  		nfs4_unlock_state(); +	if (file_lock) +		locks_free_lock(file_lock); +	if (conflock) +		locks_free_lock(conflock);  	return status;  } @@ -4209,7 +4235,7 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,  	    struct nfsd4_lockt *lockt)  {  	struct inode *inode; -	struct file_lock file_lock; +	struct file_lock *file_lock = NULL;  	struct nfs4_lockowner *lo;  	__be32 status;  	struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id); @@ -4230,15 +4256,21 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,  		goto out;  	inode = cstate->current_fh.fh_dentry->d_inode; -	locks_init_lock(&file_lock); +	file_lock = locks_alloc_lock(); +	if (!file_lock) { +		dprintk("NFSD: %s: unable to allocate lock!\n", __func__); +		status = nfserr_jukebox; +		goto out; +	} +	locks_init_lock(file_lock);  	switch (lockt->lt_type) {  		case NFS4_READ_LT:  		case NFS4_READW_LT: -			file_lock.fl_type = F_RDLCK; +			file_lock->fl_type = F_RDLCK;  		break;  		case NFS4_WRITE_LT:  		case NFS4_WRITEW_LT: -			file_lock.fl_type = F_WRLCK; +			file_lock->fl_type = F_WRLCK;  		break;  		default:  			dprintk("NFSD: nfs4_lockt: bad lock type!\n"); @@ -4248,25 +4280,27 @@ nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,  	lo = find_lockowner_str(inode, &lockt->lt_clientid, &lockt->lt_owner);  	if (lo) -		file_lock.fl_owner = (fl_owner_t)lo; -	file_lock.fl_pid = current->tgid; -	file_lock.fl_flags = FL_POSIX; +		file_lock->fl_owner = (fl_owner_t)lo; +	file_lock->fl_pid = current->tgid; +	file_lock->fl_flags = FL_POSIX; -	file_lock.fl_start = lockt->lt_offset; -	file_lock.fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length); +	file_lock->fl_start = lockt->lt_offset; +	file_lock->fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length); -	nfs4_transform_lock_offset(&file_lock); +	nfs4_transform_lock_offset(file_lock); -	status = nfsd_test_lock(rqstp, &cstate->current_fh, &file_lock); +	status = nfsd_test_lock(rqstp, &cstate->current_fh, file_lock);  	if (status)  		goto out; -	if (file_lock.fl_type != F_UNLCK) { +	if (file_lock->fl_type != F_UNLCK) {  		status = nfserr_denied; -		nfs4_set_lock_denied(&file_lock, &lockt->lt_denied); +		nfs4_set_lock_denied(file_lock, &lockt->lt_denied);  	}  out:  	nfs4_unlock_state(); +	if (file_lock) +		locks_free_lock(file_lock);  	return status;  } @@ -4276,7 +4310,7 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,  {  	struct nfs4_ol_stateid *stp;  	struct file *filp = NULL; -	struct file_lock file_lock; +	struct file_lock *file_lock = NULL;  	__be32 status;  	int err; @@ -4298,23 +4332,29 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,  		status = nfserr_lock_range;  		goto out;  	} -	BUG_ON(!filp); -	locks_init_lock(&file_lock); -	file_lock.fl_type = F_UNLCK; -	file_lock.fl_owner = (fl_owner_t)lockowner(stp->st_stateowner); -	file_lock.fl_pid = current->tgid; -	file_lock.fl_file = filp; -	file_lock.fl_flags = FL_POSIX;  -	file_lock.fl_lmops = &nfsd_posix_mng_ops; -	file_lock.fl_start = locku->lu_offset; +	file_lock = locks_alloc_lock(); +	if (!file_lock) { +		dprintk("NFSD: %s: unable to allocate lock!\n", __func__); +		status = nfserr_jukebox; +		goto out; +	} +	locks_init_lock(file_lock); +	file_lock->fl_type = F_UNLCK; +	file_lock->fl_owner = (fl_owner_t)lockowner(stp->st_stateowner); +	file_lock->fl_pid = current->tgid; +	file_lock->fl_file = filp; +	file_lock->fl_flags = FL_POSIX; +	file_lock->fl_lmops = &nfsd_posix_mng_ops; +	file_lock->fl_start = locku->lu_offset; -	file_lock.fl_end = last_byte_offset(locku->lu_offset, locku->lu_length); -	nfs4_transform_lock_offset(&file_lock); +	file_lock->fl_end = last_byte_offset(locku->lu_offset, +						locku->lu_length); +	nfs4_transform_lock_offset(file_lock);  	/*  	*  Try to unlock the file in the VFS.  	*/ -	err = vfs_lock_file(filp, F_SETLK, &file_lock, NULL); +	err = vfs_lock_file(filp, F_SETLK, file_lock, NULL);  	if (err) {  		dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n");  		goto out_nfserr; @@ -4328,6 +4368,8 @@ nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,  out:  	if (!cstate->replay_owner)  		nfs4_unlock_state(); +	if (file_lock) +		locks_free_lock(file_lock);  	return status;  out_nfserr: @@ -4501,12 +4543,12 @@ nfsd4_find_reclaim_client(struct nfs4_client *clp)  * Called from OPEN. Look for clientid in reclaim list.  */  __be32 -nfs4_check_open_reclaim(clientid_t *clid) +nfs4_check_open_reclaim(clientid_t *clid, bool sessions)  {  	struct nfs4_client *clp;  	/* find clientid in conf_id_hashtbl */ -	clp = find_confirmed_client(clid); +	clp = find_confirmed_client(clid, sessions);  	if (clp == NULL)  		return nfserr_reclaim_bad; @@ -4522,7 +4564,6 @@ void nfsd_forget_clients(u64 num)  	nfs4_lock_state();  	list_for_each_entry_safe(clp, next, &client_lru, cl_lru) { -		nfsd4_client_record_remove(clp);  		expire_client(clp);  		if (++count == num)  			break; @@ -4582,7 +4623,7 @@ void nfsd_forget_openowners(u64 num)  	printk(KERN_INFO "NFSD: Forgot %d open owners", count);  } -int nfsd_process_n_delegations(u64 num, struct list_head *list) +static int nfsd_process_n_delegations(u64 num, struct list_head *list)  {  	int i, count = 0;  	struct nfs4_file *fp, *fnext; @@ -4747,11 +4788,11 @@ __nfs4_state_shutdown(void)  	for (i = 0; i < CLIENT_HASH_SIZE; i++) {  		while (!list_empty(&conf_id_hashtbl[i])) {  			clp = list_entry(conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash); -			expire_client(clp); +			destroy_client(clp);  		}  		while (!list_empty(&unconf_str_hashtbl[i])) {  			clp = list_entry(unconf_str_hashtbl[i].next, struct nfs4_client, cl_strhash); -			expire_client(clp); +			destroy_client(clp);  		}  	}  	INIT_LIST_HEAD(&reaplist); diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 6322df36031..fd548d15508 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2659,7 +2659,7 @@ static __be32 nfsd4_encode_bind_conn_to_session(struct nfsd4_compoundres *resp,  		RESERVE_SPACE(NFS4_MAX_SESSIONID_LEN + 8);  		WRITEMEM(bcts->sessionid.data, NFS4_MAX_SESSIONID_LEN);  		WRITE32(bcts->dir); -		/* XXX: ? */ +		/* Sorry, we do not yet support RDMA over 4.1: */  		WRITE32(0);  		ADJUST_ARGS();  	} diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index fa49cff5ee6..dab350dfc37 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -406,7 +406,7 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size)  			return rv;  		if (newthreads < 0)  			return -EINVAL; -		rv = nfsd_svc(NFS_PORT, newthreads); +		rv = nfsd_svc(newthreads);  		if (rv < 0)  			return rv;  	} else @@ -683,25 +683,6 @@ static ssize_t __write_ports_addfd(char *buf)  }  /* - * A '-' followed by the 'name' of a socket means we close the socket. - */ -static ssize_t __write_ports_delfd(char *buf) -{ -	char *toclose; -	int len = 0; - -	toclose = kstrdup(buf + 1, GFP_KERNEL); -	if (toclose == NULL) -		return -ENOMEM; - -	if (nfsd_serv != NULL) -		len = svc_sock_names(nfsd_serv, buf, -					SIMPLE_TRANSACTION_LIMIT, toclose); -	kfree(toclose); -	return len; -} - -/*   * A transport listener is added by writing it's transport name and   * a port number.   */ @@ -712,7 +693,7 @@ static ssize_t __write_ports_addxprt(char *buf)  	int port, err;  	struct net *net = &init_net; -	if (sscanf(buf, "%15s %4u", transport, &port) != 2) +	if (sscanf(buf, "%15s %5u", transport, &port) != 2)  		return -EINVAL;  	if (port < 1 || port > USHRT_MAX) @@ -746,31 +727,6 @@ out_err:  	return err;  } -/* - * A transport listener is removed by writing a "-", it's transport - * name, and it's port number. - */ -static ssize_t __write_ports_delxprt(char *buf) -{ -	struct svc_xprt *xprt; -	char transport[16]; -	int port; - -	if (sscanf(&buf[1], "%15s %4u", transport, &port) != 2) -		return -EINVAL; - -	if (port < 1 || port > USHRT_MAX || nfsd_serv == NULL) -		return -EINVAL; - -	xprt = svc_find_xprt(nfsd_serv, transport, &init_net, AF_UNSPEC, port); -	if (xprt == NULL) -		return -ENOTCONN; - -	svc_close_xprt(xprt); -	svc_xprt_put(xprt); -	return 0; -} -  static ssize_t __write_ports(struct file *file, char *buf, size_t size)  {  	if (size == 0) @@ -779,15 +735,9 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size)  	if (isdigit(buf[0]))  		return __write_ports_addfd(buf); -	if (buf[0] == '-' && isdigit(buf[1])) -		return __write_ports_delfd(buf); -  	if (isalpha(buf[0]))  		return __write_ports_addxprt(buf); -	if (buf[0] == '-' && isalpha(buf[1])) -		return __write_ports_delxprt(buf); -  	return -EINVAL;  } @@ -825,21 +775,6 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size)   * OR   *   * Input: - *			buf:		C string containing a "-" followed - *					by an integer value representing a - *					previously passed in socket file - *					descriptor - *			size:		non-zero length of C string in @buf - * Output: - *	On success:	NFS service no longer listens on that socket; - *			passed-in buffer filled with a '\n'-terminated C - *			string containing a unique name of the listener; - *			return code is the size in bytes of the string - *	On error:	return code is a negative errno value - * - * OR - * - * Input:   *			buf:		C string containing a transport   *					name and an unsigned integer value   *					representing the port to listen on, @@ -848,19 +783,6 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size)   * Output:   *	On success:	returns zero; NFS service is started   *	On error:	return code is a negative errno value - * - * OR - * - * Input: - *			buf:		C string containing a "-" followed - *					by a transport name and an unsigned - *					integer value representing the port - *					to listen on, separated by whitespace - *			size:		non-zero length of C string in @buf - * Output: - *	On success:	returns zero; NFS service no longer listens - *			on that transport - *	On error:	return code is a negative errno value   */  static ssize_t write_ports(struct file *file, char *buf, size_t size)  { @@ -1008,8 +930,6 @@ static ssize_t write_gracetime(struct file *file, char *buf, size_t size)  	return nfsd4_write_time(file, buf, size, &nfsd4_grace);  } -extern char *nfs4_recoverydir(void); -  static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size)  {  	char *mesg = buf; diff --git a/fs/nfsd/nfsd.h b/fs/nfsd/nfsd.h index 2244222368a..80d5ce40aad 100644 --- a/fs/nfsd/nfsd.h +++ b/fs/nfsd/nfsd.h @@ -65,7 +65,7 @@ extern const struct seq_operations nfs_exports_op;  /*   * Function prototypes.   */ -int		nfsd_svc(unsigned short port, int nrservs); +int		nfsd_svc(int nrservs);  int		nfsd_dispatch(struct svc_rqst *rqstp, __be32 *statp);  int		nfsd_nrthreads(void); @@ -124,6 +124,7 @@ int nfs4_state_start(void);  void nfs4_state_shutdown(void);  void nfs4_reset_lease(time_t leasetime);  int nfs4_reset_recoverydir(char *recdir); +char * nfs4_recoverydir(void);  #else  static inline void nfs4_state_init(void) { }  static inline int nfsd4_init_slabs(void) { return 0; } @@ -132,6 +133,7 @@ static inline int nfs4_state_start(void) { return 0; }  static inline void nfs4_state_shutdown(void) { }  static inline void nfs4_reset_lease(time_t leasetime) { }  static inline int nfs4_reset_recoverydir(char *recdir) { return 0; } +static inline char * nfs4_recoverydir(void) {return NULL; }  #endif  /* diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 240473cb708..2013aa001da 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -183,18 +183,18 @@ int nfsd_nrthreads(void)  	return rv;  } -static int nfsd_init_socks(int port) +static int nfsd_init_socks(void)  {  	int error;  	if (!list_empty(&nfsd_serv->sv_permsocks))  		return 0; -	error = svc_create_xprt(nfsd_serv, "udp", &init_net, PF_INET, port, +	error = svc_create_xprt(nfsd_serv, "udp", &init_net, PF_INET, NFS_PORT,  					SVC_SOCK_DEFAULTS);  	if (error < 0)  		return error; -	error = svc_create_xprt(nfsd_serv, "tcp", &init_net, PF_INET, port, +	error = svc_create_xprt(nfsd_serv, "tcp", &init_net, PF_INET, NFS_PORT,  					SVC_SOCK_DEFAULTS);  	if (error < 0)  		return error; @@ -204,7 +204,7 @@ static int nfsd_init_socks(int port)  static bool nfsd_up = false; -static int nfsd_startup(unsigned short port, int nrservs) +static int nfsd_startup(int nrservs)  {  	int ret; @@ -218,7 +218,7 @@ static int nfsd_startup(unsigned short port, int nrservs)  	ret = nfsd_racache_init(2*nrservs);  	if (ret)  		return ret; -	ret = nfsd_init_socks(port); +	ret = nfsd_init_socks();  	if (ret)  		goto out_racache;  	ret = lockd_up(&init_net); @@ -436,7 +436,7 @@ int nfsd_set_nrthreads(int n, int *nthreads)   * this is the first time nrservs is nonzero.   */  int -nfsd_svc(unsigned short port, int nrservs) +nfsd_svc(int nrservs)  {  	int	error;  	bool	nfsd_up_before; @@ -458,7 +458,7 @@ nfsd_svc(unsigned short port, int nrservs)  	nfsd_up_before = nfsd_up; -	error = nfsd_startup(port, nrservs); +	error = nfsd_startup(nrservs);  	if (error)  		goto out_destroy;  	error = svc_set_num_threads(nfsd_serv, NULL, nrservs); @@ -487,7 +487,7 @@ static int  nfsd(void *vrqstp)  {  	struct svc_rqst *rqstp = (struct svc_rqst *) vrqstp; -	int err, preverr = 0; +	int err;  	/* Lock module and set up kernel thread */  	mutex_lock(&nfsd_mutex); @@ -534,16 +534,6 @@ nfsd(void *vrqstp)  			;  		if (err == -EINTR)  			break; -		else if (err < 0) { -			if (err != preverr) { -				printk(KERN_WARNING "%s: unexpected error " -					"from svc_recv (%d)\n", __func__, -err); -				preverr = err; -			} -			schedule_timeout_uninterruptible(HZ); -			continue; -		} -  		validate_process_creds();  		svc_process(rqstp);  		validate_process_creds(); diff --git a/fs/nfsd/state.h b/fs/nfsd/state.h index 22bd0a66c35..e036894bce5 100644 --- a/fs/nfsd/state.h +++ b/fs/nfsd/state.h @@ -373,11 +373,7 @@ static inline struct nfs4_lockowner * lockowner(struct nfs4_stateowner *so)  	return container_of(so, struct nfs4_lockowner, lo_owner);  } -/* -*  nfs4_file: a file opened by some number of (open) nfs4_stateowners. -*    o fi_perfile list is used to search for conflicting  -*      share_acces, share_deny on the file. -*/ +/* nfs4_file: a file opened by some number of (open) nfs4_stateowners. */  struct nfs4_file {  	atomic_t		fi_ref;  	struct list_head        fi_hash;    /* hash by "struct inode *" */ @@ -459,7 +455,7 @@ extern void nfs4_unlock_state(void);  extern int nfs4_in_grace(void);  extern void nfs4_release_reclaim(void);  extern struct nfs4_client_reclaim *nfsd4_find_reclaim_client(struct nfs4_client *crp); -extern __be32 nfs4_check_open_reclaim(clientid_t *clid); +extern __be32 nfs4_check_open_reclaim(clientid_t *clid, bool sessions);  extern void nfs4_free_openowner(struct nfs4_openowner *);  extern void nfs4_free_lockowner(struct nfs4_lockowner *);  extern int set_callback_cred(void); diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 3f67b8e1225..c120b48ec30 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1581,7 +1581,7 @@ nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp)  	 */  	oldfs = get_fs(); set_fs(KERNEL_DS); -	host_err = inode->i_op->readlink(path.dentry, buf, *lenp); +	host_err = inode->i_op->readlink(path.dentry, (char __user *)buf, *lenp);  	set_fs(oldfs);  	if (host_err < 0) diff --git a/fs/open.c b/fs/open.c index 44da0feeca2..59071f55bf7 100644 --- a/fs/open.c +++ b/fs/open.c @@ -478,7 +478,7 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd, umode_t, mode)  	file = fget(fd);  	if (file) { -		audit_inode(NULL, file->f_path.dentry); +		audit_inode(NULL, file->f_path.dentry, 0);  		err = chmod_common(&file->f_path, mode);  		fput(file);  	} @@ -588,7 +588,7 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group)  	error = mnt_want_write_file(f.file);  	if (error)  		goto out_fput; -	audit_inode(NULL, f.file->f_path.dentry); +	audit_inode(NULL, f.file->f_path.dentry, 0);  	error = chown_common(&f.file->f_path, user, group);  	mnt_drop_write_file(f.file);  out_fput: @@ -859,6 +859,24 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o  }  /** + * file_open_name - open file and return file pointer + * + * @name:	struct filename containing path to open + * @flags:	open flags as per the open(2) second argument + * @mode:	mode for the new file if O_CREAT is set, else ignored + * + * This is the helper to open a file from kernelspace if you really + * have to.  But in generally you should not do this, so please move + * along, nothing to see here.. + */ +struct file *file_open_name(struct filename *name, int flags, umode_t mode) +{ +	struct open_flags op; +	int lookup = build_open_flags(flags, mode, &op); +	return do_filp_open(AT_FDCWD, name, &op, lookup); +} + +/**   * filp_open - open file and return file pointer   *   * @filename:	path to open @@ -871,9 +889,8 @@ static inline int build_open_flags(int flags, umode_t mode, struct open_flags *o   */  struct file *filp_open(const char *filename, int flags, umode_t mode)  { -	struct open_flags op; -	int lookup = build_open_flags(flags, mode, &op); -	return do_filp_open(AT_FDCWD, filename, &op, lookup); +	struct filename name = {.name = filename}; +	return file_open_name(&name, flags, mode);  }  EXPORT_SYMBOL(filp_open); @@ -895,7 +912,7 @@ long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)  {  	struct open_flags op;  	int lookup = build_open_flags(flags, mode, &op); -	char *tmp = getname(filename); +	struct filename *tmp = getname(filename);  	int fd = PTR_ERR(tmp);  	if (!IS_ERR(tmp)) { diff --git a/fs/proc/base.c b/fs/proc/base.c index ef5c84be66f..144a96732dd 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -2258,7 +2258,8 @@ static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd)  	pid_t tgid = task_tgid_nr_ns(current, ns);  	char *name = ERR_PTR(-ENOENT);  	if (tgid) { -		name = __getname(); +		/* 11 for max length of signed int in decimal + NULL term */ +		name = kmalloc(12, GFP_KERNEL);  		if (!name)  			name = ERR_PTR(-ENOMEM);  		else @@ -2273,7 +2274,7 @@ static void proc_self_put_link(struct dentry *dentry, struct nameidata *nd,  {  	char *s = nd_get_link(nd);  	if (!IS_ERR(s)) -		__putname(s); +		kfree(s);  }  static const struct inode_operations proc_self_inode_operations = { diff --git a/fs/quota/quota.c b/fs/quota/quota.c index ff0135d6bc5..af1661f7a54 100644 --- a/fs/quota/quota.c +++ b/fs/quota/quota.c @@ -331,11 +331,11 @@ static struct super_block *quotactl_block(const char __user *special, int cmd)  #ifdef CONFIG_BLOCK  	struct block_device *bdev;  	struct super_block *sb; -	char *tmp = getname(special); +	struct filename *tmp = getname(special);  	if (IS_ERR(tmp))  		return ERR_CAST(tmp); -	bdev = lookup_bdev(tmp); +	bdev = lookup_bdev(tmp->name);  	putname(tmp);  	if (IS_ERR(bdev))  		return ERR_CAST(bdev); diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 46485557cdc..f27f01a98aa 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c @@ -1573,8 +1573,10 @@ struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, struct fid *fid,  			reiserfs_warning(sb, "reiserfs-13077",  				"nfsd/reiserfs, fhtype=%d, len=%d - odd",  				fh_type, fh_len); -		fh_type = 5; +		fh_type = fh_len;  	} +	if (fh_len < 2) +		return NULL;  	return reiserfs_get_dentry(sb, fid->raw[0], fid->raw[1],  		(fh_type == 3 || fh_type >= 5) ? fid->raw[2] : 0); @@ -1583,6 +1585,8 @@ struct dentry *reiserfs_fh_to_dentry(struct super_block *sb, struct fid *fid,  struct dentry *reiserfs_fh_to_parent(struct super_block *sb, struct fid *fid,  		int fh_len, int fh_type)  { +	if (fh_type > fh_len) +		fh_type = fh_len;  	if (fh_type < 4)  		return NULL; diff --git a/fs/super.c b/fs/super.c index a3bc935069d..12f12371216 100644 --- a/fs/super.c +++ b/fs/super.c @@ -186,15 +186,8 @@ static struct super_block *alloc_super(struct file_system_type *type, int flags)  		spin_lock_init(&s->s_inode_lru_lock);  		INIT_LIST_HEAD(&s->s_mounts);  		init_rwsem(&s->s_umount); -		mutex_init(&s->s_lock);  		lockdep_set_class(&s->s_umount, &type->s_umount_key);  		/* -		 * The locking rules for s_lock are up to the -		 * filesystem. For example ext3fs has different -		 * lock ordering than usbfs: -		 */ -		lockdep_set_class(&s->s_lock, &type->s_lock_key); -		/*  		 * sget() can have s_umount recursion.  		 *  		 * When it cannot find a suitable sb, it allocates a new @@ -394,22 +387,6 @@ bool grab_super_passive(struct super_block *sb)  	return false;  } -/* - * Superblock locking.  We really ought to get rid of these two. - */ -void lock_super(struct super_block * sb) -{ -	mutex_lock(&sb->s_lock); -} - -void unlock_super(struct super_block * sb) -{ -	mutex_unlock(&sb->s_lock); -} - -EXPORT_SYMBOL(lock_super); -EXPORT_SYMBOL(unlock_super); -  /**   *	generic_shutdown_super	-	common helper for ->kill_sb()   *	@sb: superblock to kill diff --git a/fs/sysv/balloc.c b/fs/sysv/balloc.c index 9a6ad96acf2..921c053fc05 100644 --- a/fs/sysv/balloc.c +++ b/fs/sysv/balloc.c @@ -60,12 +60,12 @@ void sysv_free_block(struct super_block * sb, sysv_zone_t nr)  		return;  	} -	lock_super(sb); +	mutex_lock(&sbi->s_lock);  	count = fs16_to_cpu(sbi, *sbi->s_bcache_count);  	if (count > sbi->s_flc_size) {  		printk("sysv_free_block: flc_count > flc_size\n"); -		unlock_super(sb); +		mutex_unlock(&sbi->s_lock);  		return;  	}  	/* If the free list head in super-block is full, it is copied @@ -77,7 +77,7 @@ void sysv_free_block(struct super_block * sb, sysv_zone_t nr)  		bh = sb_getblk(sb, block);  		if (!bh) {  			printk("sysv_free_block: getblk() failed\n"); -			unlock_super(sb); +			mutex_unlock(&sbi->s_lock);  			return;  		}  		memset(bh->b_data, 0, sb->s_blocksize); @@ -93,7 +93,7 @@ void sysv_free_block(struct super_block * sb, sysv_zone_t nr)  	*sbi->s_bcache_count = cpu_to_fs16(sbi, count);  	fs32_add(sbi, sbi->s_free_blocks, 1);  	dirty_sb(sb); -	unlock_super(sb); +	mutex_unlock(&sbi->s_lock);  }  sysv_zone_t sysv_new_block(struct super_block * sb) @@ -104,7 +104,7 @@ sysv_zone_t sysv_new_block(struct super_block * sb)  	struct buffer_head * bh;  	unsigned count; -	lock_super(sb); +	mutex_lock(&sbi->s_lock);  	count = fs16_to_cpu(sbi, *sbi->s_bcache_count);  	if (count == 0) /* Applies only to Coherent FS */ @@ -147,11 +147,11 @@ sysv_zone_t sysv_new_block(struct super_block * sb)  	/* Now the free list head in the superblock is valid again. */  	fs32_add(sbi, sbi->s_free_blocks, -1);  	dirty_sb(sb); -	unlock_super(sb); +	mutex_unlock(&sbi->s_lock);  	return nr;  Enospc: -	unlock_super(sb); +	mutex_unlock(&sbi->s_lock);  	return 0;  } @@ -173,7 +173,7 @@ unsigned long sysv_count_free_blocks(struct super_block * sb)  	if (sbi->s_type == FSTYPE_AFS)  		return 0; -	lock_super(sb); +	mutex_lock(&sbi->s_lock);  	sb_count = fs32_to_cpu(sbi, *sbi->s_free_blocks);  	if (0) @@ -211,7 +211,7 @@ unsigned long sysv_count_free_blocks(struct super_block * sb)  	if (count != sb_count)  		goto Ecount;  done: -	unlock_super(sb); +	mutex_unlock(&sbi->s_lock);  	return count;  Einval: diff --git a/fs/sysv/ialloc.c b/fs/sysv/ialloc.c index 8233b02ecca..f9db4eb31db 100644 --- a/fs/sysv/ialloc.c +++ b/fs/sysv/ialloc.c @@ -118,7 +118,7 @@ void sysv_free_inode(struct inode * inode)  		       "%s\n", inode->i_sb->s_id);  		return;  	} -	lock_super(sb); +	mutex_lock(&sbi->s_lock);  	count = fs16_to_cpu(sbi, *sbi->s_sb_fic_count);  	if (count < sbi->s_fic_size) {  		*sv_sb_fic_inode(sb,count++) = cpu_to_fs16(sbi, ino); @@ -128,7 +128,7 @@ void sysv_free_inode(struct inode * inode)  	dirty_sb(sb);  	memset(raw_inode, 0, sizeof(struct sysv_inode));  	mark_buffer_dirty(bh); -	unlock_super(sb); +	mutex_unlock(&sbi->s_lock);  	brelse(bh);  } @@ -147,13 +147,13 @@ struct inode * sysv_new_inode(const struct inode * dir, umode_t mode)  	if (!inode)  		return ERR_PTR(-ENOMEM); -	lock_super(sb); +	mutex_lock(&sbi->s_lock);  	count = fs16_to_cpu(sbi, *sbi->s_sb_fic_count);  	if (count == 0 || (*sv_sb_fic_inode(sb,count-1) == 0)) {  		count = refill_free_cache(sb);  		if (count == 0) {  			iput(inode); -			unlock_super(sb); +			mutex_unlock(&sbi->s_lock);  			return ERR_PTR(-ENOSPC);  		}  	} @@ -174,7 +174,7 @@ struct inode * sysv_new_inode(const struct inode * dir, umode_t mode)  	sysv_write_inode(inode, &wbc);	/* ensure inode not allocated again */  	mark_inode_dirty(inode);	/* cleared by sysv_write_inode() */  	/* That's it. */ -	unlock_super(sb); +	mutex_unlock(&sbi->s_lock);  	return inode;  } @@ -185,7 +185,7 @@ unsigned long sysv_count_free_inodes(struct super_block * sb)  	struct sysv_inode * raw_inode;  	int ino, count, sb_count; -	lock_super(sb); +	mutex_lock(&sbi->s_lock);  	sb_count = fs16_to_cpu(sbi, *sbi->s_sb_total_free_inodes); @@ -213,7 +213,7 @@ unsigned long sysv_count_free_inodes(struct super_block * sb)  	if (count != sb_count)  		goto Einval;  out: -	unlock_super(sb); +	mutex_unlock(&sbi->s_lock);  	return count;  Einval: diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index d33e506c1ea..c327d4ee123 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c @@ -36,7 +36,7 @@ static int sysv_sync_fs(struct super_block *sb, int wait)  	struct sysv_sb_info *sbi = SYSV_SB(sb);  	unsigned long time = get_seconds(), old_time; -	lock_super(sb); +	mutex_lock(&sbi->s_lock);  	/*  	 * If we are going to write out the super block, @@ -51,7 +51,7 @@ static int sysv_sync_fs(struct super_block *sb, int wait)  		mark_buffer_dirty(sbi->s_bh2);  	} -	unlock_super(sb); +	mutex_unlock(&sbi->s_lock);  	return 0;  } diff --git a/fs/sysv/super.c b/fs/sysv/super.c index 7491c33b646..a38e87bdd78 100644 --- a/fs/sysv/super.c +++ b/fs/sysv/super.c @@ -368,6 +368,7 @@ static int sysv_fill_super(struct super_block *sb, void *data, int silent)  	sbi->s_sb = sb;  	sbi->s_block_base = 0; +	mutex_init(&sbi->s_lock);  	sb->s_fs_info = sbi;  	sb_set_blocksize(sb, BLOCK_SIZE); diff --git a/fs/sysv/sysv.h b/fs/sysv/sysv.h index 0bc35fdc58e..69d488986cc 100644 --- a/fs/sysv/sysv.h +++ b/fs/sysv/sysv.h @@ -58,6 +58,7 @@ struct sysv_sb_info {  	u32            s_nzones;	/* same as s_sbd->s_fsize */  	u16	       s_namelen;       /* max length of dir entry */  	int	       s_forced_ro; +	struct mutex s_lock;  };  /* diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c index 1b3e410bf33..a7ea492ae66 100644 --- a/fs/ufs/balloc.c +++ b/fs/ufs/balloc.c @@ -54,7 +54,7 @@ void ufs_free_fragments(struct inode *inode, u64 fragment, unsigned count)  	if (ufs_fragnum(fragment) + count > uspi->s_fpg)  		ufs_error (sb, "ufs_free_fragments", "internal error"); -	lock_super(sb); +	mutex_lock(&UFS_SB(sb)->s_lock);  	cgno = ufs_dtog(uspi, fragment);  	bit = ufs_dtogd(uspi, fragment); @@ -118,12 +118,12 @@ void ufs_free_fragments(struct inode *inode, u64 fragment, unsigned count)  		ubh_sync_block(UCPI_UBH(ucpi));  	ufs_mark_sb_dirty(sb); -	unlock_super (sb); +	mutex_unlock(&UFS_SB(sb)->s_lock);  	UFSD("EXIT\n");  	return;  failed: -	unlock_super (sb); +	mutex_unlock(&UFS_SB(sb)->s_lock);  	UFSD("EXIT (FAILED)\n");  	return;  } @@ -155,7 +155,7 @@ void ufs_free_blocks(struct inode *inode, u64 fragment, unsigned count)  		goto failed;  	} -	lock_super(sb); +	mutex_lock(&UFS_SB(sb)->s_lock);  do_more:  	overflow = 0; @@ -215,12 +215,12 @@ do_more:  	}  	ufs_mark_sb_dirty(sb); -	unlock_super (sb); +	mutex_unlock(&UFS_SB(sb)->s_lock);  	UFSD("EXIT\n");  	return;  failed_unlock: -	unlock_super (sb); +	mutex_unlock(&UFS_SB(sb)->s_lock);  failed:  	UFSD("EXIT (FAILED)\n");  	return; @@ -361,7 +361,7 @@ u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment,  	usb1 = ubh_get_usb_first(uspi);  	*err = -ENOSPC; -	lock_super (sb); +	mutex_lock(&UFS_SB(sb)->s_lock);  	tmp = ufs_data_ptr_to_cpu(sb, p);  	if (count + ufs_fragnum(fragment) > uspi->s_fpb) { @@ -382,19 +382,19 @@ u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment,  				  "fragment %llu, tmp %llu\n",  				  (unsigned long long)fragment,  				  (unsigned long long)tmp); -			unlock_super(sb); +			mutex_unlock(&UFS_SB(sb)->s_lock);  			return INVBLOCK;  		}  		if (fragment < UFS_I(inode)->i_lastfrag) {  			UFSD("EXIT (ALREADY ALLOCATED)\n"); -			unlock_super (sb); +			mutex_unlock(&UFS_SB(sb)->s_lock);  			return 0;  		}  	}  	else {  		if (tmp) {  			UFSD("EXIT (ALREADY ALLOCATED)\n"); -			unlock_super(sb); +			mutex_unlock(&UFS_SB(sb)->s_lock);  			return 0;  		}  	} @@ -403,7 +403,7 @@ u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment,  	 * There is not enough space for user on the device  	 */  	if (!capable(CAP_SYS_RESOURCE) && ufs_freespace(uspi, UFS_MINFREE) <= 0) { -		unlock_super (sb); +		mutex_unlock(&UFS_SB(sb)->s_lock);  		UFSD("EXIT (FAILED)\n");  		return 0;  	} @@ -428,7 +428,7 @@ u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment,  			ufs_clear_frags(inode, result + oldcount,  					newcount - oldcount, locked_page != NULL);  		} -		unlock_super(sb); +		mutex_unlock(&UFS_SB(sb)->s_lock);  		UFSD("EXIT, result %llu\n", (unsigned long long)result);  		return result;  	} @@ -443,7 +443,7 @@ u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment,  						fragment + count);  		ufs_clear_frags(inode, result + oldcount, newcount - oldcount,  				locked_page != NULL); -		unlock_super(sb); +		mutex_unlock(&UFS_SB(sb)->s_lock);  		UFSD("EXIT, result %llu\n", (unsigned long long)result);  		return result;  	} @@ -481,7 +481,7 @@ u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment,  		*err = 0;  		UFS_I(inode)->i_lastfrag = max(UFS_I(inode)->i_lastfrag,  						fragment + count); -		unlock_super(sb); +		mutex_unlock(&UFS_SB(sb)->s_lock);  		if (newcount < request)  			ufs_free_fragments (inode, result + newcount, request - newcount);  		ufs_free_fragments (inode, tmp, oldcount); @@ -489,7 +489,7 @@ u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment,  		return result;  	} -	unlock_super(sb); +	mutex_unlock(&UFS_SB(sb)->s_lock);  	UFSD("EXIT (FAILED)\n");  	return 0;  }		 diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c index e84cbe21b98..d0426d74817 100644 --- a/fs/ufs/ialloc.c +++ b/fs/ufs/ialloc.c @@ -71,11 +71,11 @@ void ufs_free_inode (struct inode * inode)  	ino = inode->i_ino; -	lock_super (sb); +	mutex_lock(&UFS_SB(sb)->s_lock);  	if (!((ino > 1) && (ino < (uspi->s_ncg * uspi->s_ipg )))) {  		ufs_warning(sb, "ufs_free_inode", "reserved inode or nonexistent inode %u\n", ino); -		unlock_super (sb); +		mutex_unlock(&UFS_SB(sb)->s_lock);  		return;  	} @@ -83,7 +83,7 @@ void ufs_free_inode (struct inode * inode)  	bit = ufs_inotocgoff (ino);  	ucpi = ufs_load_cylinder (sb, cg);  	if (!ucpi) { -		unlock_super (sb); +		mutex_unlock(&UFS_SB(sb)->s_lock);  		return;  	}  	ucg = ubh_get_ucg(UCPI_UBH(ucpi)); @@ -117,7 +117,7 @@ void ufs_free_inode (struct inode * inode)  		ubh_sync_block(UCPI_UBH(ucpi));  	ufs_mark_sb_dirty(sb); -	unlock_super (sb); +	mutex_unlock(&UFS_SB(sb)->s_lock);  	UFSD("EXIT\n");  } @@ -197,7 +197,7 @@ struct inode *ufs_new_inode(struct inode *dir, umode_t mode)  	uspi = sbi->s_uspi;  	usb1 = ubh_get_usb_first(uspi); -	lock_super (sb); +	mutex_lock(&sbi->s_lock);  	/*  	 * Try to place the inode in its parent directory @@ -333,20 +333,20 @@ cg_found:  		brelse(bh);  	} -	unlock_super (sb); +	mutex_unlock(&sbi->s_lock);  	UFSD("allocating inode %lu\n", inode->i_ino);  	UFSD("EXIT\n");  	return inode;  fail_remove_inode: -	unlock_super(sb); +	mutex_unlock(&sbi->s_lock);  	clear_nlink(inode);  	iput(inode);  	UFSD("EXIT (FAILED): err %d\n", err);  	return ERR_PTR(err);  failed: -	unlock_super (sb); +	mutex_unlock(&sbi->s_lock);  	make_bad_inode(inode);  	iput (inode);  	UFSD("EXIT (FAILED): err %d\n", err); diff --git a/fs/ufs/super.c b/fs/ufs/super.c index f7cfecfe1ca..dc8e3a861d0 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -699,7 +699,7 @@ static int ufs_sync_fs(struct super_block *sb, int wait)  	unsigned flags;  	lock_ufs(sb); -	lock_super(sb); +	mutex_lock(&UFS_SB(sb)->s_lock);  	UFSD("ENTER\n"); @@ -717,7 +717,7 @@ static int ufs_sync_fs(struct super_block *sb, int wait)  	ufs_put_cstotal(sb);  	UFSD("EXIT\n"); -	unlock_super(sb); +	mutex_unlock(&UFS_SB(sb)->s_lock);  	unlock_ufs(sb);  	return 0; @@ -805,6 +805,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent)  	}  #endif  	mutex_init(&sbi->mutex); +	mutex_init(&sbi->s_lock);  	spin_lock_init(&sbi->work_lock);  	INIT_DELAYED_WORK(&sbi->sync_work, delayed_sync_fs);  	/* @@ -1280,7 +1281,7 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data)  	unsigned flags;  	lock_ufs(sb); -	lock_super(sb); +	mutex_lock(&UFS_SB(sb)->s_lock);  	uspi = UFS_SB(sb)->s_uspi;  	flags = UFS_SB(sb)->s_flags;  	usb1 = ubh_get_usb_first(uspi); @@ -1294,7 +1295,7 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data)  	new_mount_opt = 0;  	ufs_set_opt (new_mount_opt, ONERROR_LOCK);  	if (!ufs_parse_options (data, &new_mount_opt)) { -		unlock_super(sb); +		mutex_unlock(&UFS_SB(sb)->s_lock);  		unlock_ufs(sb);  		return -EINVAL;  	} @@ -1302,14 +1303,14 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data)  		new_mount_opt |= ufstype;  	} else if ((new_mount_opt & UFS_MOUNT_UFSTYPE) != ufstype) {  		printk("ufstype can't be changed during remount\n"); -		unlock_super(sb); +		mutex_unlock(&UFS_SB(sb)->s_lock);  		unlock_ufs(sb);  		return -EINVAL;  	}  	if ((*mount_flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) {  		UFS_SB(sb)->s_mount_opt = new_mount_opt; -		unlock_super(sb); +		mutex_unlock(&UFS_SB(sb)->s_lock);  		unlock_ufs(sb);  		return 0;  	} @@ -1334,7 +1335,7 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data)  #ifndef CONFIG_UFS_FS_WRITE  		printk("ufs was compiled with read-only support, "  		"can't be mounted as read-write\n"); -		unlock_super(sb); +		mutex_unlock(&UFS_SB(sb)->s_lock);  		unlock_ufs(sb);  		return -EINVAL;  #else @@ -1344,13 +1345,13 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data)  		    ufstype != UFS_MOUNT_UFSTYPE_SUNx86 &&  		    ufstype != UFS_MOUNT_UFSTYPE_UFS2) {  			printk("this ufstype is read-only supported\n"); -			unlock_super(sb); +			mutex_unlock(&UFS_SB(sb)->s_lock);  			unlock_ufs(sb);  			return -EINVAL;  		}  		if (!ufs_read_cylinder_structures(sb)) {  			printk("failed during remounting\n"); -			unlock_super(sb); +			mutex_unlock(&UFS_SB(sb)->s_lock);  			unlock_ufs(sb);  			return -EPERM;  		} @@ -1358,7 +1359,7 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data)  #endif  	}  	UFS_SB(sb)->s_mount_opt = new_mount_opt; -	unlock_super(sb); +	mutex_unlock(&UFS_SB(sb)->s_lock);  	unlock_ufs(sb);  	return 0;  } diff --git a/fs/ufs/ufs.h b/fs/ufs/ufs.h index 343e6fc571e..ff2c15ab81a 100644 --- a/fs/ufs/ufs.h +++ b/fs/ufs/ufs.h @@ -24,6 +24,7 @@ struct ufs_sb_info {  	int work_queued; /* non-zero if the delayed work is queued */  	struct delayed_work sync_work; /* FS sync delayed work */  	spinlock_t work_lock; /* protects sync_work and work_queued */ +	struct mutex s_lock;  };  struct ufs_inode_info { diff --git a/fs/xattr.c b/fs/xattr.c index 1780f062dba..e164dddb8e9 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -412,7 +412,7 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name,  	if (!f.file)  		return error;  	dentry = f.file->f_path.dentry; -	audit_inode(NULL, dentry); +	audit_inode(NULL, dentry, 0);  	error = mnt_want_write_file(f.file);  	if (!error) {  		error = setxattr(dentry, name, value, size, flags); @@ -507,7 +507,7 @@ SYSCALL_DEFINE4(fgetxattr, int, fd, const char __user *, name,  	if (!f.file)  		return error; -	audit_inode(NULL, f.file->f_path.dentry); +	audit_inode(NULL, f.file->f_path.dentry, 0);  	error = getxattr(f.file->f_path.dentry, name, value, size);  	fdput(f);  	return error; @@ -586,7 +586,7 @@ SYSCALL_DEFINE3(flistxattr, int, fd, char __user *, list, size_t, size)  	if (!f.file)  		return error; -	audit_inode(NULL, f.file->f_path.dentry); +	audit_inode(NULL, f.file->f_path.dentry, 0);  	error = listxattr(f.file->f_path.dentry, list, size);  	fdput(f);  	return error; @@ -655,7 +655,7 @@ SYSCALL_DEFINE2(fremovexattr, int, fd, const char __user *, name)  	if (!f.file)  		return error;  	dentry = f.file->f_path.dentry; -	audit_inode(NULL, dentry); +	audit_inode(NULL, dentry, 0);  	error = mnt_want_write_file(f.file);  	if (!error) {  		error = removexattr(dentry, name); diff --git a/fs/xattr_acl.c b/fs/xattr_acl.c index 11efd830b5f..9fbea87fdb6 100644 --- a/fs/xattr_acl.c +++ b/fs/xattr_acl.c @@ -45,7 +45,7 @@ static void posix_acl_fix_xattr_userns(  			break;  		case ACL_GROUP:  			gid = make_kgid(from, le32_to_cpu(entry->e_id)); -			entry->e_id = cpu_to_le32(from_kuid(to, uid)); +			entry->e_id = cpu_to_le32(from_kgid(to, gid));  			break;  		default:  			break; diff --git a/fs/xfs/xfs_export.c b/fs/xfs/xfs_export.c index 42679223a0f..8c6d1d70278 100644 --- a/fs/xfs/xfs_export.c +++ b/fs/xfs/xfs_export.c @@ -189,6 +189,9 @@ xfs_fs_fh_to_parent(struct super_block *sb, struct fid *fid,  	struct xfs_fid64	*fid64 = (struct xfs_fid64 *)fid;  	struct inode		*inode = NULL; +	if (fh_len < xfs_fileid_length(fileid_type)) +		return NULL; +  	switch (fileid_type) {  	case FILEID_INO32_GEN_PARENT:  		inode = xfs_nfs_get_inode(sb, fid->i32.parent_ino,  |