diff options
Diffstat (limited to 'fs/ncpfs/inode.c')
| -rw-r--r-- | fs/ncpfs/inode.c | 229 | 
1 files changed, 119 insertions, 110 deletions
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index d290545aa0c..e31e589369a 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -9,9 +9,10 @@   *   */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +  #include <linux/module.h> -#include <asm/system.h>  #include <asm/uaccess.h>  #include <asm/byteorder.h> @@ -26,16 +27,14 @@  #include <linux/slab.h>  #include <linux/vmalloc.h>  #include <linux/init.h> -#include <linux/smp_lock.h>  #include <linux/vfs.h>  #include <linux/mount.h>  #include <linux/seq_file.h> - -#include <linux/ncp_fs.h> +#include <linux/namei.h>  #include <net/sock.h> -#include "ncplib_kernel.h" +#include "ncp_fs.h"  #include "getopt.h"  #define NCP_DEFAULT_FILE_MODE 0600 @@ -46,7 +45,7 @@  static void ncp_evict_inode(struct inode *);  static void ncp_put_super(struct super_block *);  static int  ncp_statfs(struct dentry *, struct kstatfs *); -static int  ncp_show_options(struct seq_file *, struct vfsmount *); +static int  ncp_show_options(struct seq_file *, struct dentry *);  static struct kmem_cache * ncp_inode_cachep; @@ -59,11 +58,17 @@ static struct inode *ncp_alloc_inode(struct super_block *sb)  	return &ei->vfs_inode;  } -static void ncp_destroy_inode(struct inode *inode) +static void ncp_i_callback(struct rcu_head *head)  { +	struct inode *inode = container_of(head, struct inode, i_rcu);  	kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode));  } +static void ncp_destroy_inode(struct inode *inode) +{ +	call_rcu(&inode->i_rcu, ncp_i_callback); +} +  static void init_once(void *foo)  {  	struct ncp_inode_info *ei = (struct ncp_inode_info *) foo; @@ -86,11 +91,17 @@ static int init_inodecache(void)  static void destroy_inodecache(void)  { +	/* +	 * Make sure all delayed rcu free inodes are flushed before we +	 * destroy cache. +	 */ +	rcu_barrier();  	kmem_cache_destroy(ncp_inode_cachep);  }  static int ncp_remount(struct super_block *sb, int *flags, char* data)  { +	sync_filesystem(sb);  	*flags |= MS_NODIRATIME;  	return 0;  } @@ -124,7 +135,7 @@ void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)  	NCP_FINFO(inode)->access = nwinfo->access;  	memcpy(NCP_FINFO(inode)->file_handle, nwinfo->file_handle,  			sizeof(nwinfo->file_handle)); -	DPRINTK("ncp_update_inode: updated %s, volnum=%d, dirent=%u\n", +	ncp_dbg(1, "updated %s, volnum=%d, dirent=%u\n",  		nwinfo->i.entryName, NCP_FINFO(inode)->volNumber,  		NCP_FINFO(inode)->dirEntNum);  } @@ -132,8 +143,7 @@ void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)  static void ncp_update_dates(struct inode *inode, struct nw_info_struct *nwi)  {  	/* NFS namespace mode overrides others if it's set. */ -	DPRINTK(KERN_DEBUG "ncp_update_dates_and_mode: (%s) nfs.mode=0%o\n", -		nwi->entryName, nwi->nfs.mode); +	ncp_dbg(1, "(%s) nfs.mode=0%o\n", nwi->entryName, nwi->nfs.mode);  	if (nwi->nfs.mode) {  		/* XXX Security? */  		inode->i_mode = nwi->nfs.mode; @@ -221,9 +231,9 @@ static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)  	ncp_update_attrs(inode, nwinfo); -	DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode); +	ncp_dbg(2, "inode->i_mode = %u\n", inode->i_mode); -	inode->i_nlink = 1; +	set_nlink(inode, 1);  	inode->i_uid = server->m.uid;  	inode->i_gid = server->m.gid; @@ -249,7 +259,7 @@ ncp_iget(struct super_block *sb, struct ncp_entry_info *info)  	struct inode *inode;  	if (info == NULL) { -		printk(KERN_ERR "ncp_iget: info is NULL\n"); +		pr_err("%s: info is NULL\n", __func__);  		return NULL;  	} @@ -281,23 +291,23 @@ ncp_iget(struct super_block *sb, struct ncp_entry_info *info)  		}  		insert_inode_hash(inode);  	} else -		printk(KERN_ERR "ncp_iget: iget failed!\n"); +		pr_err("%s: iget failed!\n", __func__);  	return inode;  }  static void  ncp_evict_inode(struct inode *inode)  { -	truncate_inode_pages(&inode->i_data, 0); -	end_writeback(inode); +	truncate_inode_pages_final(&inode->i_data); +	clear_inode(inode);  	if (S_ISDIR(inode->i_mode)) { -		DDPRINTK("ncp_evict_inode: put directory %ld\n", inode->i_ino); +		ncp_dbg(2, "put directory %ld\n", inode->i_ino);  	}  	if (ncp_make_closed(inode) != 0) {  		/* We can't do anything but complain. */ -		printk(KERN_ERR "ncp_evict_inode: could not close\n"); +		pr_err("%s: could not close\n", __func__);  	}  } @@ -310,20 +320,28 @@ static void ncp_stop_tasks(struct ncp_server *server) {  	sk->sk_write_space  = server->write_space;  	release_sock(sk);  	del_timer_sync(&server->timeout_tm); -	flush_scheduled_work(); + +	flush_work(&server->rcv.tq); +	if (sk->sk_socket->type == SOCK_STREAM) +		flush_work(&server->tx.tq); +	else +		flush_work(&server->timeout_tq);  } -static int  ncp_show_options(struct seq_file *seq, struct vfsmount *mnt) +static int  ncp_show_options(struct seq_file *seq, struct dentry *root)  { -	struct ncp_server *server = NCP_SBP(mnt->mnt_sb); +	struct ncp_server *server = NCP_SBP(root->d_sb);  	unsigned int tmp; -	if (server->m.uid != 0) -		seq_printf(seq, ",uid=%u", server->m.uid); -	if (server->m.gid != 0) -		seq_printf(seq, ",gid=%u", server->m.gid); -	if (server->m.mounted_uid != 0) -		seq_printf(seq, ",owner=%u", server->m.mounted_uid); +	if (!uid_eq(server->m.uid, GLOBAL_ROOT_UID)) +		seq_printf(seq, ",uid=%u", +			   from_kuid_munged(&init_user_ns, server->m.uid)); +	if (!gid_eq(server->m.gid, GLOBAL_ROOT_GID)) +		seq_printf(seq, ",gid=%u", +			   from_kgid_munged(&init_user_ns, server->m.gid)); +	if (!uid_eq(server->m.mounted_uid, GLOBAL_ROOT_UID)) +		seq_printf(seq, ",owner=%u", +			   from_kuid_munged(&init_user_ns, server->m.mounted_uid));  	tmp = server->m.file_mode & S_IALLUGO;  	if (tmp != NCP_DEFAULT_FILE_MODE)  		seq_printf(seq, ",mode=0%o", tmp); @@ -368,13 +386,13 @@ static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options)  	data->flags = 0;  	data->int_flags = 0; -	data->mounted_uid = 0; +	data->mounted_uid = GLOBAL_ROOT_UID;  	data->wdog_pid = NULL;  	data->ncp_fd = ~0;  	data->time_out = NCP_DEFAULT_TIME_OUT;  	data->retry_count = NCP_DEFAULT_RETRY_COUNT; -	data->uid = 0; -	data->gid = 0; +	data->uid = GLOBAL_ROOT_UID; +	data->gid = GLOBAL_ROOT_GID;  	data->file_mode = NCP_DEFAULT_FILE_MODE;  	data->dir_mode = NCP_DEFAULT_DIR_MODE;  	data->info_fd = -1; @@ -386,13 +404,25 @@ static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options)  			goto err;  		switch (optval) {  			case 'u': -				data->uid = optint; +				data->uid = make_kuid(current_user_ns(), optint); +				if (!uid_valid(data->uid)) { +					ret = -EINVAL; +					goto err; +				}  				break;  			case 'g': -				data->gid = optint; +				data->gid = make_kgid(current_user_ns(), optint); +				if (!gid_valid(data->gid)) { +					ret = -EINVAL; +					goto err; +				}  				break;  			case 'o': -				data->mounted_uid = optint; +				data->mounted_uid = make_kuid(current_user_ns(), optint); +				if (!uid_valid(data->mounted_uid)) { +					ret = -EINVAL; +					goto err; +				}  				break;  			case 'm':  				data->file_mode = optint; @@ -440,9 +470,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)  {  	struct ncp_mount_data_kernel data;  	struct ncp_server *server; -	struct file *ncp_filp;  	struct inode *root_inode; -	struct inode *sock_inode;  	struct socket *sock;  	int error;  	int default_bufsize; @@ -451,7 +479,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)  #endif  	struct ncp_entry_info finfo; -	data.wdog_pid = NULL; +	memset(&data, 0, sizeof(data));  	server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL);  	if (!server)  		return -ENOMEM; @@ -467,13 +495,13 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)  				data.flags = md->flags;  				data.int_flags = NCP_IMOUNT_LOGGEDIN_POSSIBLE; -				data.mounted_uid = md->mounted_uid; +				data.mounted_uid = make_kuid(current_user_ns(), md->mounted_uid);  				data.wdog_pid = find_get_pid(md->wdog_pid);  				data.ncp_fd = md->ncp_fd;  				data.time_out = md->time_out;  				data.retry_count = md->retry_count; -				data.uid = md->uid; -				data.gid = md->gid; +				data.uid = make_kuid(current_user_ns(), md->uid); +				data.gid = make_kgid(current_user_ns(), md->gid);  				data.file_mode = md->file_mode;  				data.dir_mode = md->dir_mode;  				data.info_fd = -1; @@ -486,18 +514,16 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)  				struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data;  				data.flags = md->flags; -				data.int_flags = 0; -				data.mounted_uid = md->mounted_uid; +				data.mounted_uid = make_kuid(current_user_ns(), md->mounted_uid);  				data.wdog_pid = find_get_pid(md->wdog_pid);  				data.ncp_fd = md->ncp_fd;  				data.time_out = md->time_out;  				data.retry_count = md->retry_count; -				data.uid = md->uid; -				data.gid = md->gid; +				data.uid = make_kuid(current_user_ns(), md->uid); +				data.gid = make_kgid(current_user_ns(), md->gid);  				data.file_mode = md->file_mode;  				data.dir_mode = md->dir_mode;  				data.info_fd = -1; -				data.mounted_vol[0] = 0;  			}  			break;  		default: @@ -509,18 +535,14 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)  				goto out;  			break;  	} -	error = -EBADF; -	ncp_filp = fget(data.ncp_fd); -	if (!ncp_filp) +	error = -EINVAL; +	if (!uid_valid(data.mounted_uid) || !uid_valid(data.uid) || +	    !gid_valid(data.gid))  		goto out; -	error = -ENOTSOCK; -	sock_inode = ncp_filp->f_path.dentry->d_inode; -	if (!S_ISSOCK(sock_inode->i_mode)) -		goto out_fput; -	sock = SOCKET_I(sock_inode); +	sock = sockfd_lookup(data.ncp_fd, &error);  	if (!sock) -		goto out_fput; -		 +		goto out; +  	if (sock->type == SOCK_STREAM)  		default_bufsize = 0xF000;  	else @@ -532,6 +554,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)  	sb->s_blocksize_bits = 10;  	sb->s_magic = NCP_SUPER_MAGIC;  	sb->s_op = &ncp_sops; +	sb->s_d_op = &ncp_dentry_operations;  	sb->s_bdi = &server->bdi;  	server = NCP_SBP(sb); @@ -539,29 +562,18 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)  	error = bdi_setup_and_register(&server->bdi, "ncpfs", BDI_CAP_MAP_COPY);  	if (error) -		goto out_bdi; +		goto out_fput; -	server->ncp_filp = ncp_filp;  	server->ncp_sock = sock;  	if (data.info_fd != -1) { -		struct socket *info_sock; - -		error = -EBADF; -		server->info_filp = fget(data.info_fd); -		if (!server->info_filp) -			goto out_fput; -		error = -ENOTSOCK; -		sock_inode = server->info_filp->f_path.dentry->d_inode; -		if (!S_ISSOCK(sock_inode->i_mode)) -			goto out_fput2; -		info_sock = SOCKET_I(sock_inode); +		struct socket *info_sock = sockfd_lookup(data.info_fd, &error);  		if (!info_sock) -			goto out_fput2; +			goto out_bdi; +		server->info_sock = info_sock;  		error = -EBADFD;  		if (info_sock->type != SOCK_STREAM)  			goto out_fput2; -		server->info_sock = info_sock;  	}  /*	server->lock = 0;	*/ @@ -585,11 +597,11 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)  /*	server->priv.data = NULL;		*/  	server->m = data; -	/* Althought anything producing this is buggy, it happens +	/* Although anything producing this is buggy, it happens  	   now because of PATH_MAX changes.. */  	if (server->m.time_out < 1) {  		server->m.time_out = 10; -		printk(KERN_INFO "You need to recompile your ncpfs utils..\n"); +		pr_info("You need to recompile your ncpfs utils..\n");  	}  	server->m.time_out = server->m.time_out * HZ / 100;  	server->m.file_mode = (server->m.file_mode & S_IRWXUGO) | S_IFREG; @@ -650,7 +662,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)  	ncp_unlock_server(server);  	if (error < 0)  		goto out_rxbuf; -	DPRINTK("ncp_fill_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb)); +	ncp_dbg(1, "NCP_SBP(sb) = %p\n", NCP_SBP(sb));  	error = -EMSGSIZE;	/* -EREMOTESIDEINCOMPATIBLE */  #ifdef CONFIG_NCPFS_PACKET_SIGNING @@ -678,7 +690,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)  	if (ncp_negotiate_buffersize(server, default_bufsize,    				     &(server->buffer_size)) != 0)  		goto out_disconnect; -	DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size); +	ncp_dbg(1, "bufsize = %d\n", server->buffer_size);  	memset(&finfo, 0, sizeof(finfo));  	finfo.i.attributes	= aDIR; @@ -707,15 +719,12 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)          root_inode = ncp_iget(sb, &finfo);          if (!root_inode)  		goto out_disconnect; -	DPRINTK("ncp_fill_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber); -	sb->s_root = d_alloc_root(root_inode); +	ncp_dbg(1, "root vol=%d\n", NCP_FINFO(root_inode)->volNumber); +	sb->s_root = d_make_root(root_inode);          if (!sb->s_root) -		goto out_no_root; -	sb->s_root->d_op = &ncp_root_dentry_operations; +		goto out_disconnect;  	return 0; -out_no_root: -	iput(root_inode);  out_disconnect:  	ncp_lock_server(server);  	ncp_disconnect(server); @@ -736,17 +745,12 @@ out_nls:  	mutex_destroy(&server->root_setup_lock);  	mutex_destroy(&server->mutex);  out_fput2: -	if (server->info_filp) -		fput(server->info_filp); -out_fput: -	bdi_destroy(&server->bdi); +	if (server->info_sock) +		sockfd_put(server->info_sock);  out_bdi: -	/* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>: -	 *  -	 * The previously used put_filp(ncp_filp); was bogus, since -	 * it doesn't perform proper unlocking. -	 */ -	fput(ncp_filp); +	bdi_destroy(&server->bdi); +out_fput: +	sockfd_put(sock);  out:  	put_pid(data.wdog_pid);  	sb->s_fs_info = NULL; @@ -754,6 +758,17 @@ out:  	return error;  } +static void delayed_free(struct rcu_head *p) +{ +	struct ncp_server *server = container_of(p, struct ncp_server, rcu); +#ifdef CONFIG_NCPFS_NLS +	/* unload the NLS charsets */ +	unload_nls(server->nls_vol); +	unload_nls(server->nls_io); +#endif /* CONFIG_NCPFS_NLS */ +	kfree(server); +} +  static void ncp_put_super(struct super_block *sb)  {  	struct ncp_server *server = NCP_SBP(sb); @@ -764,18 +779,13 @@ static void ncp_put_super(struct super_block *sb)  	ncp_stop_tasks(server); -#ifdef CONFIG_NCPFS_NLS -	/* unload the NLS charsets */ -	unload_nls(server->nls_vol); -	unload_nls(server->nls_io); -#endif /* CONFIG_NCPFS_NLS */  	mutex_destroy(&server->rcv.creq_mutex);  	mutex_destroy(&server->root_setup_lock);  	mutex_destroy(&server->mutex); -	if (server->info_filp) -		fput(server->info_filp); -	fput(server->ncp_filp); +	if (server->info_sock) +		sockfd_put(server->info_sock); +	sockfd_put(server->ncp_sock);  	kill_pid(server->m.wdog_pid, SIGTERM, 1);  	put_pid(server->m.wdog_pid); @@ -785,8 +795,7 @@ static void ncp_put_super(struct super_block *sb)  	vfree(server->rxbuf);  	vfree(server->txbuf);  	vfree(server->packet); -	sb->s_fs_info = NULL; -	kfree(server); +	call_rcu(&server->rcu, delayed_free);  }  static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf) @@ -869,6 +878,10 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)  	if (!server)	/* How this could happen? */  		goto out; +	result = -EPERM; +	if (IS_DEADDIR(dentry->d_inode)) +		goto out; +  	/* ageing the dentry to force validation */  	ncp_age_dentry(server, dentry); @@ -877,12 +890,10 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)  		goto out;  	result = -EPERM; -	if (((attr->ia_valid & ATTR_UID) && -	     (attr->ia_uid != server->m.uid))) +	if ((attr->ia_valid & ATTR_UID) && !uid_eq(attr->ia_uid, server->m.uid))  		goto out; -	if (((attr->ia_valid & ATTR_GID) && -	     (attr->ia_gid != server->m.gid))) +	if ((attr->ia_valid & ATTR_GID) && !gid_eq(attr->ia_gid, server->m.gid))  		goto out;  	if (((attr->ia_valid & ATTR_MODE) && @@ -949,8 +960,7 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)  	if ((attr->ia_valid & ATTR_SIZE) != 0) {  		int written; -		DPRINTK("ncpfs: trying to change size to %ld\n", -			attr->ia_size); +		ncp_dbg(1, "trying to change size to %llu\n", attr->ia_size);  		if ((result = ncp_make_open(inode, O_WRONLY)) < 0) {  			result = -EACCES; @@ -967,9 +977,7 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)  			goto out;  		if (attr->ia_size != i_size_read(inode)) { -			result = vmtruncate(inode, attr->ia_size); -			if (result) -				goto out; +			truncate_setsize(inode, attr->ia_size);  			mark_inode_dirty(inode);  		}  	} @@ -1033,11 +1041,12 @@ static struct file_system_type ncp_fs_type = {  	.kill_sb	= kill_anon_super,  	.fs_flags	= FS_BINARY_MOUNTDATA,  }; +MODULE_ALIAS_FS("ncpfs");  static int __init init_ncp_fs(void)  {  	int err; -	DPRINTK("ncpfs: init_ncp_fs called\n"); +	ncp_dbg(1, "called\n");  	err = init_inodecache();  	if (err) @@ -1054,7 +1063,7 @@ out1:  static void __exit exit_ncp_fs(void)  { -	DPRINTK("ncpfs: exit_ncp_fs called\n"); +	ncp_dbg(1, "called\n");  	unregister_filesystem(&ncp_fs_type);  	destroy_inodecache();  }  | 
