⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xfs_ioctl.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */#include "xfs.h"#include "xfs_fs.h"#include "xfs_bit.h"#include "xfs_log.h"#include "xfs_inum.h"#include "xfs_trans.h"#include "xfs_sb.h"#include "xfs_ag.h"#include "xfs_dir.h"#include "xfs_dir2.h"#include "xfs_alloc.h"#include "xfs_dmapi.h"#include "xfs_mount.h"#include "xfs_bmap_btree.h"#include "xfs_alloc_btree.h"#include "xfs_ialloc_btree.h"#include "xfs_dir_sf.h"#include "xfs_attr_sf.h"#include "xfs_dir2_sf.h"#include "xfs_dinode.h"#include "xfs_inode.h"#include "xfs_btree.h"#include "xfs_ialloc.h"#include "xfs_rtalloc.h"#include "xfs_itable.h"#include "xfs_error.h"#include "xfs_rw.h"#include "xfs_acl.h"#include "xfs_cap.h"#include "xfs_mac.h"#include "xfs_attr.h"#include "xfs_bmap.h"#include "xfs_buf_item.h"#include "xfs_utils.h"#include "xfs_dfrag.h"#include "xfs_fsops.h"#include <linux/dcache.h>#include <linux/mount.h>#include <linux/namei.h>#include <linux/pagemap.h>/* * xfs_find_handle maps from userspace xfs_fsop_handlereq structure to * a file or fs handle. * * XFS_IOC_PATH_TO_FSHANDLE *    returns fs handle for a mount point or path within that mount point * XFS_IOC_FD_TO_HANDLE *    returns full handle for a FD opened in user space * XFS_IOC_PATH_TO_HANDLE *    returns full handle for a path */STATIC intxfs_find_handle(	unsigned int		cmd,	void			__user *arg){	int			hsize;	xfs_handle_t		handle;	xfs_fsop_handlereq_t	hreq;	struct inode		*inode;	struct vnode		*vp;	if (copy_from_user(&hreq, arg, sizeof(hreq)))		return -XFS_ERROR(EFAULT);	memset((char *)&handle, 0, sizeof(handle));	switch (cmd) {	case XFS_IOC_PATH_TO_FSHANDLE:	case XFS_IOC_PATH_TO_HANDLE: {		struct nameidata	nd;		int			error;		error = user_path_walk_link((const char __user *)hreq.path, &nd);		if (error)			return error;		ASSERT(nd.dentry);		ASSERT(nd.dentry->d_inode);		inode = igrab(nd.dentry->d_inode);		path_release(&nd);		break;	}	case XFS_IOC_FD_TO_HANDLE: {		struct file	*file;		file = fget(hreq.fd);		if (!file)		    return -EBADF;		ASSERT(file->f_dentry);		ASSERT(file->f_dentry->d_inode);		inode = igrab(file->f_dentry->d_inode);		fput(file);		break;	}	default:		ASSERT(0);		return -XFS_ERROR(EINVAL);	}	if (inode->i_sb->s_magic != XFS_SB_MAGIC) {		/* we're not in XFS anymore, Toto */		iput(inode);		return -XFS_ERROR(EINVAL);	}	switch (inode->i_mode & S_IFMT) {	case S_IFREG:	case S_IFDIR:	case S_IFLNK:		break;	default:		iput(inode);		return -XFS_ERROR(EBADF);	}	/* we need the vnode */	vp = LINVFS_GET_VP(inode);	/* now we can grab the fsid */	memcpy(&handle.ha_fsid, vp->v_vfsp->vfs_altfsid, sizeof(xfs_fsid_t));	hsize = sizeof(xfs_fsid_t);	if (cmd != XFS_IOC_PATH_TO_FSHANDLE) {		xfs_inode_t	*ip;		bhv_desc_t	*bhv;		int		lock_mode;		/* need to get access to the xfs_inode to read the generation */		bhv = vn_bhv_lookup_unlocked(VN_BHV_HEAD(vp), &xfs_vnodeops);		ASSERT(bhv);		ip = XFS_BHVTOI(bhv);		ASSERT(ip);		lock_mode = xfs_ilock_map_shared(ip);		/* fill in fid section of handle from inode */		handle.ha_fid.xfs_fid_len = sizeof(xfs_fid_t) -					    sizeof(handle.ha_fid.xfs_fid_len);		handle.ha_fid.xfs_fid_pad = 0;		handle.ha_fid.xfs_fid_gen = ip->i_d.di_gen;		handle.ha_fid.xfs_fid_ino = ip->i_ino;		xfs_iunlock_map_shared(ip, lock_mode);		hsize = XFS_HSIZE(handle);	}	/* now copy our handle into the user buffer & write out the size */	if (copy_to_user(hreq.ohandle, &handle, hsize) ||	    copy_to_user(hreq.ohandlen, &hsize, sizeof(__s32))) {		iput(inode);		return -XFS_ERROR(EFAULT);	}	iput(inode);	return 0;}/* * Convert userspace handle data into vnode (and inode). * We [ab]use the fact that all the fsop_handlereq ioctl calls * have a data structure argument whose first component is always * a xfs_fsop_handlereq_t, so we can cast to and from this type. * This allows us to optimise the copy_from_user calls and gives * a handy, shared routine. * * If no error, caller must always VN_RELE the returned vp. */STATIC intxfs_vget_fsop_handlereq(	xfs_mount_t		*mp,	struct inode		*parinode,	/* parent inode pointer    */	xfs_fsop_handlereq_t	*hreq,	vnode_t			**vp,	struct inode		**inode){	void			__user *hanp;	size_t			hlen;	xfs_fid_t		*xfid;	xfs_handle_t		*handlep;	xfs_handle_t		handle;	xfs_inode_t		*ip;	struct inode		*inodep;	vnode_t			*vpp;	xfs_ino_t		ino;	__u32			igen;	int			error;	/*	 * Only allow handle opens under a directory.	 */	if (!S_ISDIR(parinode->i_mode))		return XFS_ERROR(ENOTDIR);	hanp = hreq->ihandle;	hlen = hreq->ihandlen;	handlep = &handle;	if (hlen < sizeof(handlep->ha_fsid) || hlen > sizeof(*handlep))		return XFS_ERROR(EINVAL);	if (copy_from_user(handlep, hanp, hlen))		return XFS_ERROR(EFAULT);	if (hlen < sizeof(*handlep))		memset(((char *)handlep) + hlen, 0, sizeof(*handlep) - hlen);	if (hlen > sizeof(handlep->ha_fsid)) {		if (handlep->ha_fid.xfs_fid_len !=				(hlen - sizeof(handlep->ha_fsid)					- sizeof(handlep->ha_fid.xfs_fid_len))		    || handlep->ha_fid.xfs_fid_pad)			return XFS_ERROR(EINVAL);	}	/*	 * Crack the handle, obtain the inode # & generation #	 */	xfid = (struct xfs_fid *)&handlep->ha_fid;	if (xfid->xfs_fid_len == sizeof(*xfid) - sizeof(xfid->xfs_fid_len)) {		ino  = xfid->xfs_fid_ino;		igen = xfid->xfs_fid_gen;	} else {		return XFS_ERROR(EINVAL);	}	/*	 * Get the XFS inode, building a vnode to go with it.	 */	error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, 0);	if (error)		return error;	if (ip == NULL)		return XFS_ERROR(EIO);	if (ip->i_d.di_mode == 0 || ip->i_d.di_gen != igen) {		xfs_iput_new(ip, XFS_ILOCK_SHARED);		return XFS_ERROR(ENOENT);	}	vpp = XFS_ITOV(ip);	inodep = LINVFS_GET_IP(vpp);	xfs_iunlock(ip, XFS_ILOCK_SHARED);	*vp = vpp;	*inode = inodep;	return 0;}STATIC intxfs_open_by_handle(	xfs_mount_t		*mp,	void			__user *arg,	struct file		*parfilp,	struct inode		*parinode){	int			error;	int			new_fd;	int			permflag;	struct file		*filp;	struct inode		*inode;	struct dentry		*dentry;	vnode_t			*vp;	xfs_fsop_handlereq_t	hreq;	if (!capable(CAP_SYS_ADMIN))		return -XFS_ERROR(EPERM);	if (copy_from_user(&hreq, arg, sizeof(xfs_fsop_handlereq_t)))		return -XFS_ERROR(EFAULT);	error = xfs_vget_fsop_handlereq(mp, parinode, &hreq, &vp, &inode);	if (error)		return -error;	/* Restrict xfs_open_by_handle to directories & regular files. */	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) {		iput(inode);		return -XFS_ERROR(EINVAL);	}#if BITS_PER_LONG != 32	hreq.oflags |= O_LARGEFILE;#endif	/* Put open permission in namei format. */	permflag = hreq.oflags;	if ((permflag+1) & O_ACCMODE)		permflag++;	if (permflag & O_TRUNC)		permflag |= 2;	if ((!(permflag & O_APPEND) || (permflag & O_TRUNC)) &&	    (permflag & FMODE_WRITE) && IS_APPEND(inode)) {		iput(inode);		return -XFS_ERROR(EPERM);	}	if ((permflag & FMODE_WRITE) && IS_IMMUTABLE(inode)) {		iput(inode);		return -XFS_ERROR(EACCES);	}	/* Can't write directories. */	if ( S_ISDIR(inode->i_mode) && (permflag & FMODE_WRITE)) {		iput(inode);		return -XFS_ERROR(EISDIR);	}	if ((new_fd = get_unused_fd()) < 0) {		iput(inode);		return new_fd;	}	dentry = d_alloc_anon(inode);	if (dentry == NULL) {		iput(inode);		put_unused_fd(new_fd);		return -XFS_ERROR(ENOMEM);	}	/* Ensure umount returns EBUSY on umounts while this file is open. */	mntget(parfilp->f_vfsmnt);	/* Create file pointer. */	filp = dentry_open(dentry, parfilp->f_vfsmnt, hreq.oflags);	if (IS_ERR(filp)) {		put_unused_fd(new_fd);		return -XFS_ERROR(-PTR_ERR(filp));	}	if (inode->i_mode & S_IFREG)		filp->f_op = &linvfs_invis_file_operations;	fd_install(new_fd, filp);	return new_fd;}STATIC intxfs_readlink_by_handle(	xfs_mount_t		*mp,	void			__user *arg,	struct file		*parfilp,	struct inode		*parinode){	int			error;	struct iovec		aiov;	struct uio		auio;	struct inode		*inode;	xfs_fsop_handlereq_t	hreq;	vnode_t			*vp;	__u32			olen;	if (!capable(CAP_SYS_ADMIN))		return -XFS_ERROR(EPERM);	if (copy_from_user(&hreq, arg, sizeof(xfs_fsop_handlereq_t)))		return -XFS_ERROR(EFAULT);	error = xfs_vget_fsop_handlereq(mp, parinode, &hreq, &vp, &inode);	if (error)		return -error;	/* Restrict this handle operation to symlinks only. */	if (!S_ISLNK(inode->i_mode)) {		VN_RELE(vp);		return -XFS_ERROR(EINVAL);	}	if (copy_from_user(&olen, hreq.ohandlen, sizeof(__u32))) {		VN_RELE(vp);		return -XFS_ERROR(EFAULT);	}	aiov.iov_len	= olen;	aiov.iov_base	= hreq.ohandle;	auio.uio_iov	= &aiov;	auio.uio_iovcnt	= 1;	auio.uio_offset	= 0;	auio.uio_segflg	= UIO_USERSPACE;	auio.uio_resid	= olen;	VOP_READLINK(vp, &auio, IO_INVIS, NULL, error);	VN_RELE(vp);	return (olen - auio.uio_resid);}STATIC intxfs_fssetdm_by_handle(	xfs_mount_t		*mp,	void			__user *arg,	struct file		*parfilp,	struct inode		*parinode){	int			error;	struct fsdmidata	fsd;	xfs_fsop_setdm_handlereq_t dmhreq;	struct inode		*inode;	bhv_desc_t		*bdp;	vnode_t			*vp;	if (!capable(CAP_MKNOD))		return -XFS_ERROR(EPERM);	if (copy_from_user(&dmhreq, arg, sizeof(xfs_fsop_setdm_handlereq_t)))		return -XFS_ERROR(EFAULT);	error = xfs_vget_fsop_handlereq(mp, parinode, &dmhreq.hreq, &vp, &inode);	if (error)		return -error;	if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) {		VN_RELE(vp);		return -XFS_ERROR(EPERM);	}	if (copy_from_user(&fsd, dmhreq.data, sizeof(fsd))) {		VN_RELE(vp);		return -XFS_ERROR(EFAULT);	}	bdp = bhv_base_unlocked(VN_BHV_HEAD(vp));	error = xfs_set_dmattrs(bdp, fsd.fsd_dmevmask, fsd.fsd_dmstate, NULL);	VN_RELE(vp);	if (error)		return -error;	return 0;}STATIC intxfs_attrlist_by_handle(	xfs_mount_t		*mp,	void			__user *arg,	struct file		*parfilp,	struct inode		*parinode){	int			error;	attrlist_cursor_kern_t	*cursor;	xfs_fsop_attrlist_handlereq_t al_hreq;	struct inode		*inode;	vnode_t			*vp;	char			*kbuf;	if (!capable(CAP_SYS_ADMIN))		return -XFS_ERROR(EPERM);	if (copy_from_user(&al_hreq, arg, sizeof(xfs_fsop_attrlist_handlereq_t)))		return -XFS_ERROR(EFAULT);	if (al_hreq.buflen > XATTR_LIST_MAX)		return -XFS_ERROR(EINVAL);	error = xfs_vget_fsop_handlereq(mp, parinode, &al_hreq.hreq,			&vp, &inode);	if (error)		goto out;	kbuf = kmalloc(al_hreq.buflen, GFP_KERNEL);	if (!kbuf)		goto out_vn_rele;	cursor = (attrlist_cursor_kern_t *)&al_hreq.pos;	VOP_ATTR_LIST(vp, kbuf, al_hreq.buflen, al_hreq.flags,			cursor, NULL, error);	if (error)		goto out_kfree;	if (copy_to_user(al_hreq.buffer, kbuf, al_hreq.buflen))		error = -EFAULT; out_kfree:	kfree(kbuf); out_vn_rele:	VN_RELE(vp); out:	return -error;}STATIC intxfs_attrmulti_attr_get(	struct vnode		*vp,	char			*name,	char			__user *ubuf,	__uint32_t		*len,	__uint32_t		flags){	char			*kbuf;	int			error = EFAULT;		if (*len > XATTR_SIZE_MAX)		return EINVAL;	kbuf = kmalloc(*len, GFP_KERNEL);	if (!kbuf)		return ENOMEM;	VOP_ATTR_GET(vp, name, kbuf, len, flags, NULL, error);	if (error)		goto out_kfree;	if (copy_to_user(ubuf, kbuf, *len))		error = EFAULT; out_kfree:	kfree(kbuf);	return error;}STATIC intxfs_attrmulti_attr_set(	struct vnode		*vp,	char			*name,	const char		__user *ubuf,	__uint32_t		len,	__uint32_t		flags){	char			*kbuf;	int			error = EFAULT;	if (IS_IMMUTABLE(&vp->v_inode) || IS_APPEND(&vp->v_inode))		return EPERM;	if (len > XATTR_SIZE_MAX)		return EINVAL;	kbuf = kmalloc(len, GFP_KERNEL);	if (!kbuf)		return ENOMEM;	if (copy_from_user(kbuf, ubuf, len))		goto out_kfree;				VOP_ATTR_SET(vp, name, kbuf, len, flags, NULL, error); out_kfree:	kfree(kbuf);	return error;}STATIC intxfs_attrmulti_attr_remove(	struct vnode		*vp,	char			*name,	__uint32_t		flags){	int			error;	if (IS_IMMUTABLE(&vp->v_inode) || IS_APPEND(&vp->v_inode))		return EPERM;	VOP_ATTR_REMOVE(vp, name, flags, NULL, error);	return error;}STATIC intxfs_attrmulti_by_handle(	xfs_mount_t		*mp,	void			__user *arg,	struct file		*parfilp,	struct inode		*parinode){	int			error;	xfs_attr_multiop_t	*ops;	xfs_fsop_attrmulti_handlereq_t am_hreq;	struct inode		*inode;	vnode_t			*vp;	unsigned int		i, size;	char			*attr_name;	if (!capable(CAP_SYS_ADMIN))		return -XFS_ERROR(EPERM);	if (copy_from_user(&am_hreq, arg, sizeof(xfs_fsop_attrmulti_handlereq_t)))		return -XFS_ERROR(EFAULT);	error = xfs_vget_fsop_handlereq(mp, parinode, &am_hreq.hreq, &vp, &inode);	if (error)		goto out;	error = E2BIG;	size = am_hreq.opcount * sizeof(attr_multiop_t);	if (!size || size > 16 * PAGE_SIZE)		goto out_vn_rele;	error = ENOMEM;	ops = kmalloc(size, GFP_KERNEL);	if (!ops)		goto out_vn_rele;	error = EFAULT;	if (copy_from_user(ops, am_hreq.ops, size))		goto out_kfree_ops;	attr_name = kmalloc(MAXNAMELEN, GFP_KERNEL);	if (!attr_name)		goto out_kfree_ops;	error = 0;	for (i = 0; i < am_hreq.opcount; i++) {		ops[i].am_error = strncpy_from_user(attr_name,				ops[i].am_attrname, MAXNAMELEN);		if (ops[i].am_error == 0 || ops[i].am_error == MAXNAMELEN)			error = -ERANGE;		if (ops[i].am_error < 0)			break;		switch (ops[i].am_opcode) {		case ATTR_OP_GET:			ops[i].am_error = xfs_attrmulti_attr_get(vp,					attr_name, ops[i].am_attrvalue,					&ops[i].am_length, ops[i].am_flags);			break;		case ATTR_OP_SET:			ops[i].am_error = xfs_attrmulti_attr_set(vp,					attr_name, ops[i].am_attrvalue,					ops[i].am_length, ops[i].am_flags);			break;		case ATTR_OP_REMOVE:			ops[i].am_error = xfs_attrmulti_attr_remove(vp,					attr_name, ops[i].am_flags);			break;		default:			ops[i].am_error = EINVAL;		}	}	if (copy_to_user(am_hreq.ops, ops, size))		error = XFS_ERROR(EFAULT);	kfree(attr_name); out_kfree_ops:	kfree(ops); out_vn_rele:	VN_RELE(vp); out:	return -error;}/* prototypes for a few of the stack-hungry cases that have * their own functions.  Functions are defined after their use * so gcc doesn't get fancy and inline them with -03 */STATIC intxfs_ioc_space(	bhv_desc_t		*bdp,	vnode_t			*vp,	struct file		*filp,	int			flags,	unsigned int		cmd,	void			__user *arg);STATIC intxfs_ioc_bulkstat(	xfs_mount_t		*mp,	unsigned int		cmd,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -