cregit-Linux how code gets into the kernel

Release 4.11 fs/xfs/xfs_ioctl.c

Directory: fs/xfs
/*
 * 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_shared.h"
#include "xfs_format.h"
#include "xfs_log_format.h"
#include "xfs_trans_resv.h"
#include "xfs_mount.h"
#include "xfs_inode.h"
#include "xfs_ioctl.h"
#include "xfs_alloc.h"
#include "xfs_rtalloc.h"
#include "xfs_itable.h"
#include "xfs_error.h"
#include "xfs_attr.h"
#include "xfs_bmap.h"
#include "xfs_bmap_util.h"
#include "xfs_fsops.h"
#include "xfs_discard.h"
#include "xfs_quota.h"
#include "xfs_export.h"
#include "xfs_trace.h"
#include "xfs_icache.h"
#include "xfs_symlink.h"
#include "xfs_trans.h"
#include "xfs_pnfs.h"
#include "xfs_acl.h"

#include <linux/capability.h>
#include <linux/cred.h>
#include <linux/dcache.h>
#include <linux/mount.h>
#include <linux/namei.h>
#include <linux/pagemap.h>
#include <linux/slab.h>
#include <linux/exportfs.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
 */

int xfs_find_handle( unsigned int cmd, xfs_fsop_handlereq_t *hreq) { int hsize; xfs_handle_t handle; struct inode *inode; struct fd f = {NULL}; struct path path; int error; struct xfs_inode *ip; if (cmd == XFS_IOC_FD_TO_HANDLE) { f = fdget(hreq->fd); if (!f.file) return -EBADF; inode = file_inode(f.file); } else { error = user_lpath((const char __user *)hreq->path, &path); if (error) return error; inode = d_inode(path.dentry); } ip = XFS_I(inode); /* * We can only generate handles for inodes residing on a XFS filesystem, * and only for regular files, directories or symbolic links. */ error = -EINVAL; if (inode->i_sb->s_magic != XFS_SB_MAGIC) goto out_put; error = -EBADF; if (!S_ISREG(inode->i_mode) && !S_ISDIR(inode->i_mode) && !S_ISLNK(inode->i_mode)) goto out_put; memcpy(&handle.ha_fsid, ip->i_mount->m_fixedfsid, sizeof(xfs_fsid_t)); if (cmd == XFS_IOC_PATH_TO_FSHANDLE) { /* * This handle only contains an fsid, zero the rest. */ memset(&handle.ha_fid, 0, sizeof(handle.ha_fid)); hsize = sizeof(xfs_fsid_t); } else { handle.ha_fid.fid_len = sizeof(xfs_fid_t) - sizeof(handle.ha_fid.fid_len); handle.ha_fid.fid_pad = 0; handle.ha_fid.fid_gen = inode->i_generation; handle.ha_fid.fid_ino = ip->i_ino; hsize = XFS_HSIZE(handle); } error = -EFAULT; if (copy_to_user(hreq->ohandle, &handle, hsize) || copy_to_user(hreq->ohandlen, &hsize, sizeof(__s32))) goto out_put; error = 0; out_put: if (cmd == XFS_IOC_FD_TO_HANDLE) fdput(f); else path_put(&path); return error; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig31990.62%741.18%
Al Viro164.55%317.65%
Dave Chinner51.42%211.76%
Eric Sandeen51.42%15.88%
David Howells30.85%15.88%
Josef 'Jeff' Sipek20.57%15.88%
Nathan Scott10.28%15.88%
David Chinner10.28%15.88%
Total352100.00%17100.00%

/* * No need to do permission checks on the various pathname components * as the handle operations are privileged. */
STATIC int xfs_handle_acceptable( void *context, struct dentry *dentry) { return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig18100.00%2100.00%
Total18100.00%2100.00%

/* * Convert userspace handle data into a dentry. */
struct dentry * xfs_handle_to_dentry( struct file *parfilp, void __user *uhandle, u32 hlen) { xfs_handle_t handle; struct xfs_fid64 fid; /* * Only allow handle opens under a directory. */ if (!S_ISDIR(file_inode(parfilp)->i_mode)) return ERR_PTR(-ENOTDIR); if (hlen != sizeof(xfs_handle_t)) return ERR_PTR(-EINVAL); if (copy_from_user(&handle, uhandle, hlen)) return ERR_PTR(-EFAULT); if (handle.ha_fid.fid_len != sizeof(handle.ha_fid) - sizeof(handle.ha_fid.fid_len)) return ERR_PTR(-EINVAL); memset(&fid, 0, sizeof(struct fid)); fid.ino = handle.ha_fid.fid_ino; fid.gen = handle.ha_fid.fid_gen; return exportfs_decode_fh(parfilp->f_path.mnt, (struct fid *)&fid, 3, FILEID_INO32_GEN | XFS_FILEID_TYPE_64FLAG, xfs_handle_acceptable, NULL); }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig17297.73%466.67%
Al Viro31.70%116.67%
Nathan Scott10.57%116.67%
Total176100.00%6100.00%


STATIC struct dentry * xfs_handlereq_to_dentry( struct file *parfilp, xfs_fsop_handlereq_t *hreq) { return xfs_handle_to_dentry(parfilp, hreq->ihandle, hreq->ihandlen); }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig31100.00%3100.00%
Total31100.00%3100.00%


int xfs_open_by_handle( struct file *parfilp, xfs_fsop_handlereq_t *hreq) { const struct cred *cred = current_cred(); int error; int fd; int permflag; struct file *filp; struct inode *inode; struct dentry *dentry; fmode_t fmode; struct path path; if (!capable(CAP_SYS_ADMIN)) return -EPERM; dentry = xfs_handlereq_to_dentry(parfilp, hreq); if (IS_ERR(dentry)) return PTR_ERR(dentry); inode = d_inode(dentry); /* Restrict xfs_open_by_handle to directories & regular files. */ if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) { error = -EPERM; goto out_dput; } #if BITS_PER_LONG != 32 hreq->oflags |= O_LARGEFILE; #endif permflag = hreq->oflags; fmode = OPEN_FMODE(permflag); if ((!(permflag & O_APPEND) || (permflag & O_TRUNC)) && (fmode & FMODE_WRITE) && IS_APPEND(inode)) { error = -EPERM; goto out_dput; } if ((fmode & FMODE_WRITE) && IS_IMMUTABLE(inode)) { error = -EPERM; goto out_dput; } /* Can't write directories. */ if (S_ISDIR(inode->i_mode) && (fmode & FMODE_WRITE)) { error = -EISDIR; goto out_dput; } fd = get_unused_fd_flags(0); if (fd < 0) { error = fd; goto out_dput; } path.mnt = parfilp->f_path.mnt; path.dentry = dentry; filp = dentry_open(&path, hreq->oflags, cred); dput(dentry); if (IS_ERR(filp)) { put_unused_fd(fd); return PTR_ERR(filp); } if (S_ISREG(inode->i_mode)) { filp->f_flags |= O_NOATIME; filp->f_mode |= FMODE_NOCMTIME; } fd_install(fd, filp); return fd; out_dput: dput(dentry); return error; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig23465.36%425.00%
Nathan Scott4612.85%16.25%
Al Viro287.82%212.50%
David Howells143.91%212.50%
Dave Chinner113.07%16.25%
Vlad Apostolov82.23%16.25%
Stephen Lord61.68%16.25%
Yann Droneaud41.12%16.25%
Josef 'Jeff' Sipek30.84%16.25%
Eric Sandeen30.84%16.25%
Eryu Guan10.28%16.25%
Total358100.00%16100.00%


int xfs_readlink_by_handle( struct file *parfilp, xfs_fsop_handlereq_t *hreq) { struct dentry *dentry; __u32 olen; int error; if (!capable(CAP_SYS_ADMIN)) return -EPERM; dentry = xfs_handlereq_to_dentry(parfilp, hreq); if (IS_ERR(dentry)) return PTR_ERR(dentry); /* Restrict this handle operation to symlinks only. */ if (!d_is_symlink(dentry)) { error = -EINVAL; goto out_dput; } if (copy_from_user(&olen, hreq->ohandlen, sizeof(__u32))) { error = -EFAULT; goto out_dput; } error = vfs_readlink(dentry, hreq->ohandle, olen); out_dput: dput(dentry); return error; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig11690.62%660.00%
Nathan Scott64.69%220.00%
Eric Sandeen43.12%110.00%
Miklos Szeredi21.56%110.00%
Total128100.00%10100.00%


int xfs_set_dmattrs( xfs_inode_t *ip, u_int evmask, u_int16_t state) { xfs_mount_t *mp = ip->i_mount; xfs_trans_t *tp; int error; if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (XFS_FORCED_SHUTDOWN(mp)) return -EIO; error = xfs_trans_alloc(mp, &M_RES(mp)->tr_ichange, 0, 0, 0, &tp); if (error) return error; xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); ip->i_d.di_dmevmask = evmask; ip->i_d.di_dmstate = state; xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); error = xfs_trans_commit(tp); return error; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Chinner12592.59%250.00%
Christoph Hellwig64.44%125.00%
Jie Liu42.96%125.00%
Total135100.00%4100.00%


STATIC int xfs_fssetdm_by_handle( struct file *parfilp, void __user *arg) { int error; struct fsdmidata fsd; xfs_fsop_setdm_handlereq_t dmhreq; struct dentry *dentry; if (!capable(CAP_MKNOD)) return -EPERM; if (copy_from_user(&dmhreq, arg, sizeof(xfs_fsop_setdm_handlereq_t))) return -EFAULT; error = mnt_want_write_file(parfilp); if (error) return error; dentry = xfs_handlereq_to_dentry(parfilp, &dmhreq.hreq); if (IS_ERR(dentry)) { mnt_drop_write_file(parfilp); return PTR_ERR(dentry); } if (IS_IMMUTABLE(d_inode(dentry)) || IS_APPEND(d_inode(dentry))) { error = -EPERM; goto out; } if (copy_from_user(&fsd, dmhreq.data, sizeof(fsd))) { error = -EFAULT; goto out; } error = xfs_set_dmattrs(XFS_I(d_inode(dentry)), fsd.fsd_dmevmask, fsd.fsd_dmstate); out: mnt_drop_write_file(parfilp); dput(dentry); return error; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig14773.87%555.56%
Jan Kara2613.07%111.11%
Nathan Scott178.54%222.22%
David Howells94.52%111.11%
Total199100.00%9100.00%


STATIC int xfs_attrlist_by_handle( struct file *parfilp, void __user *arg) { int error = -ENOMEM; attrlist_cursor_kern_t *cursor; struct xfs_fsop_attrlist_handlereq __user *p = arg; xfs_fsop_attrlist_handlereq_t al_hreq; struct dentry *dentry; char *kbuf; if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user(&al_hreq, arg, sizeof(xfs_fsop_attrlist_handlereq_t))) return -EFAULT; if (al_hreq.buflen < sizeof(struct attrlist) || al_hreq.buflen > XFS_XATTR_LIST_MAX) return -EINVAL; /* * Reject flags, only allow namespaces. */ if (al_hreq.flags & ~(ATTR_ROOT | ATTR_SECURE)) return -EINVAL; dentry = xfs_handlereq_to_dentry(parfilp, &al_hreq.hreq); if (IS_ERR(dentry)) return PTR_ERR(dentry); kbuf = kmem_zalloc_large(al_hreq.buflen, KM_SLEEP); if (!kbuf) goto out_dput; cursor = (attrlist_cursor_kern_t *)&al_hreq.pos; error = xfs_attr_list(XFS_I(d_inode(dentry)), kbuf, al_hreq.buflen, al_hreq.flags, cursor); if (error) goto out_kfree; if (copy_to_user(&p->pos, cursor, sizeof(attrlist_cursor_kern_t))) { error = -EFAULT; goto out_kfree; } if (copy_to_user(al_hreq.buffer, kbuf, al_hreq.buflen)) error = -EFAULT; out_kfree: kmem_free(kbuf); out_dput: dput(dentry); return error; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig21178.73%538.46%
Darrick J. Wong3513.06%17.69%
Dan Carpenter103.73%17.69%
Nathan Scott51.87%215.38%
David Howells31.12%17.69%
Eric Sandeen20.75%17.69%
Jan Tulak10.37%17.69%
Dave Chinner10.37%17.69%
Total268100.00%13100.00%


int xfs_attrmulti_attr_get( struct inode *inode, unsigned char *name, unsigned char __user *ubuf, __uint32_t *len, __uint32_t flags) { unsigned char *kbuf; int error = -EFAULT; if (*len > XFS_XATTR_SIZE_MAX) return -EINVAL; kbuf = kmem_zalloc_large(*len, KM_SLEEP); if (!kbuf) return -ENOMEM; error = xfs_attr_get(XFS_I(inode), name, kbuf, (int *)len, flags); if (error) goto out_kfree; if (copy_to_user(ubuf, kbuf, *len)) error = -EFAULT; out_kfree: kmem_free(kbuf); return error; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig10886.40%330.00%
David Chinner75.60%220.00%
Dave Chinner75.60%330.00%
Nathan Scott21.60%110.00%
Jan Tulak10.80%110.00%
Total125100.00%10100.00%


int xfs_attrmulti_attr_set( struct inode *inode, unsigned char *name, const unsigned char __user *ubuf, __uint32_t len, __uint32_t flags) { unsigned char *kbuf; int error; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) return -EPERM; if (len > XFS_XATTR_SIZE_MAX) return -EINVAL; kbuf = memdup_user(ubuf, len); if (IS_ERR(kbuf)) return PTR_ERR(kbuf); error = xfs_attr_set(XFS_I(inode), name, kbuf, len, flags); if (!error) xfs_forget_acl(inode, name, flags); kfree(kbuf); return error; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig8366.94%333.33%
Andreas Gruenbacher2721.77%222.22%
Li Zefan86.45%111.11%
David Chinner32.42%111.11%
Dave Chinner21.61%111.11%
Jan Tulak10.81%111.11%
Total124100.00%9100.00%


int xfs_attrmulti_attr_remove( struct inode *inode, unsigned char *name, __uint32_t flags) { int error; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) return -EPERM; error = xfs_attr_remove(XFS_I(inode), name, flags); if (!error) xfs_forget_acl(inode, name, flags); return error; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig4464.71%350.00%
Andreas Gruenbacher2232.35%116.67%
David Chinner11.47%116.67%
Dave Chinner11.47%116.67%
Total68100.00%6100.00%


STATIC int xfs_attrmulti_by_handle( struct file *parfilp, void __user *arg) { int error; xfs_attr_multiop_t *ops; xfs_fsop_attrmulti_handlereq_t am_hreq; struct dentry *dentry; unsigned int i, size; unsigned char *attr_name; if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user(&am_hreq, arg, sizeof(xfs_fsop_attrmulti_handlereq_t))) return -EFAULT; /* overflow check */ if (am_hreq.opcount >= INT_MAX / sizeof(xfs_attr_multiop_t)) return -E2BIG; dentry = xfs_handlereq_to_dentry(parfilp, &am_hreq.hreq); if (IS_ERR(dentry)) return PTR_ERR(dentry); error = -E2BIG; size = am_hreq.opcount * sizeof(xfs_attr_multiop_t); if (!size || size > 16 * PAGE_SIZE) goto out_dput; ops = memdup_user(am_hreq.ops, size); if (IS_ERR(ops)) { error = PTR_ERR(ops); goto out_dput; } error = -ENOMEM; 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((char *)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( d_inode(dentry), attr_name, ops[i].am_attrvalue, &ops[i].am_length, ops[i].am_flags); break; case ATTR_OP_SET: ops[i].am_error = mnt_want_write_file(parfilp); if (ops[i].am_error) break; ops[i].am_error = xfs_attrmulti_attr_set( d_inode(dentry), attr_name, ops[i].am_attrvalue, ops[i].am_length, ops[i].am_flags); mnt_drop_write_file(parfilp); break; case ATTR_OP_REMOVE: ops[i].am_error = mnt_want_write_file(parfilp); if (ops[i].am_error) break; ops[i].am_error = xfs_attrmulti_attr_remove( d_inode(dentry), attr_name, ops[i].am_flags); mnt_drop_write_file(parfilp); break; default: ops[i].am_error = -EINVAL; } } if (copy_to_user(am_hreq.ops, ops, size)) error = -EFAULT; kfree(attr_name); out_kfree_ops: kfree(ops); out_dput: dput(dentry); return error; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig37072.55%426.67%
Dave Hansen5410.59%16.67%
Nathan Scott285.49%213.33%
Zhitong Wang183.53%16.67%
Li Zefan132.55%16.67%
David Howells91.76%16.67%
Dave Chinner50.98%16.67%
David Chinner50.98%16.67%
Al Viro40.78%213.33%
Tuomas Tynkkynen40.78%16.67%
Total510100.00%15100.00%


int xfs_ioc_space( struct file *filp, unsigned int cmd, xfs_flock64_t *bf) { struct inode *inode = file_inode(filp); struct xfs_inode *ip = XFS_I(inode); struct iattr iattr; enum xfs_prealloc_flags flags = 0; uint iolock = XFS_IOLOCK_EXCL; int error; /* * Only allow the sys admin to reserve space unless * unwritten extents are enabled. */ if (!xfs_sb_version_hasextflgbit(&ip->i_mount->m_sb) && !capable(CAP_SYS_ADMIN)) return -EPERM; if (inode->i_flags & (S_IMMUTABLE|S_APPEND)) return -EPERM; if (!(filp->f_mode & FMODE_WRITE)) return -EBADF; if (!S_ISREG(inode->i_mode)) return -EINVAL; if (filp->f_flags & O_DSYNC) flags |= XFS_PREALLOC_SYNC; if (filp->f_mode & FMODE_NOCMTIME) flags |= XFS_PREALLOC_INVISIBLE; error = mnt_want_write_file(filp); if (error) return error; xfs_ilock(ip, iolock); error = xfs_break_layouts(inode, &iolock); if (error) goto out_unlock; xfs_ilock(ip, XFS_MMAPLOCK_EXCL); iolock |= XFS_MMAPLOCK_EXCL; switch (bf->l_whence) { case 0: /*SEEK_SET*/ break; case 1: /*SEEK_CUR*/ bf->l_start += filp->f_pos; break; case 2: /*SEEK_END*/ bf->l_start += XFS_ISIZE(ip); break; default: error = -EINVAL; goto out_unlock; } /* * length of <= 0 for resv/unresv/zero is invalid. length for * alloc/free is ignored completely and we have no idea what userspace * might have set it to, so set it to zero to allow range * checks to pass. */ switch (cmd) { case XFS_IOC_ZERO_RANGE: case XFS_IOC_RESVSP: case XFS_IOC_RESVSP64: case XFS_IOC_UNRESVSP: case XFS_IOC_UNRESVSP64: if (bf->l_len <= 0) { error = -EINVAL; goto out_unlock; } break; default: bf->l_len = 0; break; } if (bf->l_start < 0 || bf->l_start > inode->i_sb->s_maxbytes || bf->l_start + bf->l_len < 0 || bf->l_start + bf->l_len >= inode->i_sb->s_maxbytes) { error = -EINVAL; goto out_unlock; } switch (cmd) { case XFS_IOC_ZERO_RANGE: flags |= XFS_PREALLOC_SET; error = xfs_zero_file_space(ip, bf->l_start, bf->l_len); break; case XFS_IOC_RESVSP: case XFS_IOC_RESVSP64: flags |= XFS_PREALLOC_SET; error = xfs_alloc_file_space(ip, bf->l_start, bf->l_len, XFS_BMAPI_PREALLOC); break; case XFS_IOC_UNRESVSP: case XFS_IOC_UNRESVSP64: error = xfs_free_file_space(ip, bf->l_start, bf->l_len); break; case XFS_IOC_ALLOCSP: case XFS_IOC_ALLOCSP64: case XFS_IOC_FREESP: case XFS_IOC_FREESP64: flags |= XFS_PREALLOC_CLEAR; if (bf->l_start > XFS_ISIZE(ip)) { error = xfs_alloc_file_space(ip, XFS_ISIZE(ip), bf->l_start - XFS_ISIZE(ip), 0); if (error) goto out_unlock; } iattr.ia_valid = ATTR_SIZE; iattr.ia_size = bf->l_start; error = xfs_vn_setattr_size(file_dentry(filp), &iattr); break; default: ASSERT(0); error = -EINVAL; } if (error) goto out_unlock; error = xfs_update_prealloc_flags(ip, flags); out_unlock: xfs_iunlock(ip, iolock); mnt_drop_write_file(filp); return error; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig47585.13%947.37%
Eric Sandeen274.84%210.53%
Dave Chinner193.41%315.79%
Jan Kara162.87%210.53%
Nathan Scott162.87%210.53%
Alexey Dobriyan50.90%15.26%
Total558100.00%19100.00%


STATIC int xfs_ioc_bulkstat( xfs_mount_t *mp, unsigned int cmd, void __user *arg) { xfs_fsop_bulkreq_t bulkreq; int count; /* # of records returned */ xfs_ino_t inlast; /* last inode number */ int done; int error; /* done = 1 if there are more stats to get and if bulkstat */ /* should be called again (unused here, but used in dmapi) */ if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (XFS_FORCED_SHUTDOWN(mp)) return -EIO; if (copy_from_user(&bulkreq, arg, sizeof(xfs_fsop_bulkreq_t))) return -EFAULT; if (copy_from_user(&inlast, bulkreq.lastip, sizeof(__s64))) return -EFAULT; if ((count = bulkreq.icount) <= 0) return -EINVAL; if (bulkreq.ubuffer == NULL) return -EINVAL; if (cmd == XFS_IOC_FSINUMBERS) error = xfs_inumbers(mp, &inlast, &count, bulkreq.ubuffer, xfs_inumbers_fmt); else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE) error = xfs_bulkstat_one(mp, inlast, bulkreq.ubuffer, sizeof(xfs_bstat_t), NULL, &done); else /* XFS_IOC_FSBULKSTAT */ error = xfs_bulkstat(mp, &inlast, &count, xfs_bulkstat_one, sizeof(xfs_bstat_t), bulkreq.ubuffer, &done); if (error) return error; if (bulkreq.ocount != NULL) { if (copy_to_user(bulkreq.lastip, &inlast, sizeof(xfs_ino_t))) return -EFAULT; if (copy_to_user(bulkreq.ocount, &count, sizeof(count))) return -EFAULT; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig25793.45%233.33%
Lachlan McIlroy124.36%116.67%
Nathan Scott41.45%233.33%
Michal Marek20.73%116.67%
Total275100.00%6100.00%


STATIC int xfs_ioc_fsgeometry_v1( xfs_mount_t *mp, void __user *arg) { xfs_fsop_geom_t fsgeo; int error; error = xfs_fs_geometry(mp, &fsgeo, 3); if (error) return error; /* * Caller should have passed an argument of type * xfs_fsop_geom_v1_t. This is a proper subset of the * xfs_fsop_geom_t that xfs_fs_geometry() fills in. */ if (copy_to_user(arg, &fsgeo, sizeof(xfs_fsop_geom_v1_t))) return -EFAULT; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig5688.89%125.00%
Nathan Scott46.35%250.00%
Alex Elder34.76%125.00%
Total63100.00%4100.00%


STATIC int xfs_ioc_fsgeometry( xfs_mount_t *mp, void __user *arg) { xfs_fsop_geom_t fsgeo; int error; error = xfs_fs_geometry(mp, &fsgeo, 4); if (error) return error; if (copy_to_user(arg, &fsgeo, sizeof(fsgeo))) return -EFAULT; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig5893.55%133.33%
Nathan Scott46.45%266.67%
Total62100.00%3100.00%

/* * Linux extended inode flags interface. */
STATIC unsigned int xfs_merge_ioc_xflags( unsigned int flags, unsigned int start) { unsigned int xflags = start; if (flags & FS_IMMUTABLE_FL) xflags |= FS_XFLAG_IMMUTABLE; else xflags &= ~FS_XFLAG_IMMUTABLE; if (flags & FS_APPEND_FL) xflags |= FS_XFLAG_APPEND; else xflags &= ~FS_XFLAG_APPEND; if (flags & FS_SYNC_FL) xflags |= FS_XFLAG_SYNC; else xflags &= ~FS_XFLAG_SYNC; if (flags & FS_NOATIME_FL) xflags |= FS_XFLAG_NOATIME; else xflags &= ~FS_XFLAG_NOATIME; if (flags & FS_NODUMP_FL) xflags |= FS_XFLAG_NODUMP; else xflags &= ~FS_XFLAG_NODUMP; return xflags; }

Contributors

PersonTokensPropCommitsCommitProp
Nathan Scott8985.58%133.33%
Dave Chinner109.62%133.33%
Eric Sandeen54.81%133.33%
Total104100.00%3100.00%


STATIC unsigned int xfs_di2lxflags( __uint16_t di_flags) { unsigned int flags = 0; if (di_flags & XFS_DIFLAG_IMMUTABLE) flags |= FS_IMMUTABLE_FL; if (di_flags & XFS_DIFLAG_APPEND) flags |= FS_APPEND_FL; if (di_flags & XFS_DIFLAG_SYNC) flags |= FS_SYNC_FL; if (di_flags & XFS_DIFLAG_NOATIME) flags |= FS_NOATIME_FL; if (di_flags & XFS_DIFLAG_NODUMP) flags |= FS_NODUMP_FL; return flags; }

Contributors

PersonTokensPropCommitsCommitProp
Nathan Scott6492.75%266.67%
Eric Sandeen57.25%133.33%
Total69100.00%3100.00%


STATIC int xfs_ioc_fsgetxattr( xfs_inode_t *ip, int attr, void __user *arg) { struct fsxattr fa; memset(&fa, 0, sizeof(struct fsxattr)); xfs_ilock(ip, XFS_ILOCK_SHARED); fa.fsx_xflags = xfs_ip2xflags(ip); fa.fsx_extsize = ip->i_d.di_extsize << ip->i_mount->m_sb.sb_blocklog; fa.fsx_cowextsize = ip->i_d.di_cowextsize << ip->i_mount->m_sb.sb_blocklog; fa.fsx_projid = xfs_get_projid(ip); if (attr) { if (ip->i_afp) { if (ip->i_afp->if_flags & XFS_IFEXTENTS) fa.fsx_nextents = xfs_iext_count(ip->i_afp); else fa.fsx_nextents = ip->i_d.di_anextents; } else fa.fsx_nextents = 0; } else { if (ip->i_df.if_flags & XFS_IFEXTENTS) fa.fsx_nextents = xfs_iext_count(&ip->i_df); else fa.fsx_nextents = ip->i_d.di_nextents; } xfs_iunlock(ip, XFS_ILOCK_SHARED); if (copy_to_user(arg, &fa, sizeof(fa))) return -EFAULT; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig17480.93%228.57%
Darrick J. Wong188.37%114.29%
Dan Rosenberg146.51%114.29%
Eric Sandeen52.33%114.29%
Arkadiusz Miskiewicz31.40%114.29%
Nathan Scott10.47%114.29%
Total215100.00%7100.00%


STATIC void xfs_set_diflags( struct xfs_inode *ip, unsigned int xflags) { unsigned int di_flags; uint64_t di_flags2; /* can't set PREALLOC this way, just preserve it */ di_flags = (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC); if (xflags & FS_XFLAG_IMMUTABLE) di_flags |= XFS_DIFLAG_IMMUTABLE; if (xflags & FS_XFLAG_APPEND) di_flags |= XFS_DIFLAG_APPEND; if (xflags & FS_XFLAG_SYNC) di_flags |= XFS_DIFLAG_SYNC; if (xflags & FS_XFLAG_NOATIME) di_flags |= XFS_DIFLAG_NOATIME; if (xflags & FS_XFLAG_NODUMP) di_flags |= XFS_DIFLAG_NODUMP; if (xflags & FS_XFLAG_NODEFRAG) di_flags |= XFS_DIFLAG_NODEFRAG; if (xflags & FS_XFLAG_FILESTREAM) di_flags |= XFS_DIFLAG_FILESTREAM; if (S_ISDIR(VFS_I(ip)->i_mode)) { if (xflags & FS_XFLAG_RTINHERIT) di_flags |= XFS_DIFLAG_RTINHERIT; if (xflags & FS_XFLAG_NOSYMLINKS) di_flags |= XFS_DIFLAG_NOSYMLINKS; if (xflags & FS_XFLAG_EXTSZINHERIT) di_flags |= XFS_DIFLAG_EXTSZINHERIT; if (xflags & FS_XFLAG_PROJINHERIT) di_flags |= XFS_DIFLAG_PROJINHERIT; } else if (S_ISREG(VFS_I(ip)->i_mode)) { if (xflags & FS_XFLAG_REALTIME) di_flags |= XFS_DIFLAG_REALTIME; if (xflags & FS_XFLAG_EXTSIZE) di_flags |= XFS_DIFLAG_EXTSIZE; } ip->i_d.di_flags = di_flags; /* diflags2 only valid for v3 inodes. */ if (ip->i_d.di_version < 3) return; di_flags2 = (ip->i_d.di_flags2 & XFS_DIFLAG2_REFLINK); if (xflags & FS_XFLAG_DAX) di_flags2 |= XFS_DIFLAG2_DAX; if (xflags & FS_XFLAG_COWEXTSIZE) di_flags2 |= XFS_DIFLAG2_COWEXTSIZE; ip->i_d.di_flags2 = di_flags2; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig13553.15%323.08%
Dave Chinner6625.98%430.77%
Nathan Scott249.45%323.08%
Darrick J. Wong197.48%17.69%
Al Viro62.36%17.69%
Lachlan McIlroy41.57%17.69%
Total254100.00%13100.00%


STATIC void xfs_diflags_to_linux( struct xfs_inode *ip) { struct inode *inode = VFS_I(ip); unsigned int xflags = xfs_ip2xflags(ip); if (xflags & FS_XFLAG_IMMUTABLE) inode->i_flags |= S_IMMUTABLE; else inode->i_flags &= ~S_IMMUTABLE; if (xflags & FS_XFLAG_APPEND) inode->i_flags |= S_APPEND; else inode->i_flags &= ~S_APPEND; if (xflags & FS_XFLAG_SYNC) inode->i_flags |= S_SYNC; else inode->i_flags &= ~S_SYNC; if (xflags & FS_XFLAG_NOATIME) inode->i_flags |= S_NOATIME; else inode->i_flags &= ~S_NOATIME; if (xflags & FS_XFLAG_DAX) inode->i_flags |= S_DAX; else inode->i_flags &= ~S_DAX; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig10580.77%125.00%
Dave Chinner2418.46%250.00%
David Chinner10.77%125.00%
Total130100.00%4100.00%


static int xfs_ioctl_setattr_xflags( struct xfs_trans *tp, struct xfs_inode *ip, struct fsxattr *fa) { struct xfs_mount *mp = ip->i_mount; /* Can't change realtime flag if any extents are allocated. */ if ((ip->i_d.di_nextents || ip->i_delayed_blks) && XFS_IS_REALTIME_INODE(ip) != (fa->fsx_xflags & FS_XFLAG_REALTIME)) return -EINVAL; /* If realtime flag is set then must have realtime device */ if (fa->fsx_xflags & FS_XFLAG_REALTIME) { if (mp->m_sb.sb_rblocks == 0 || mp->m_sb.sb_rextsize == 0 || (ip->i_d.di_extsize % mp->m_sb.sb_rextsize)) return -EINVAL; } /* Clear reflink if we are actually able to set the rt flag. */ if ((fa->fsx_xflags & FS_XFLAG_REALTIME) && xfs_is_reflink_inode(ip)) ip->i_d.di_flags2 &= ~XFS_DIFLAG2_REFLINK; /* Don't allow us to set DAX mode for a reflinked file for now. */ if ((fa->fsx_xflags & FS_XFLAG_DAX) && xfs_is_reflink_inode(ip)) return -EINVAL; /* * Can't modify an immutable/append-only file unless * we have appropriate permission. */ if (((ip->i_d.di_flags & (XFS_DIFLAG_IMMUTABLE | XFS_DIFLAG_APPEND)) || (fa->fsx_xflags & (FS_XFLAG_IMMUTABLE | FS_XFLAG_APPEND))) && !capable(CAP_LINUX_IMMUTABLE)) return -EPERM; xfs_set_diflags(ip, fa->fsx_xflags); xfs_diflags_to_linux(ip); xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG); xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); XFS_STATS_INC(mp, xs_ig_attrchg); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Chinner11347.68%327.27%
Christoph Hellwig5824.47%19.09%
Darrick J. Wong4518.99%327.27%
Arkadiusz Miskiewicz187.59%218.18%
Bill O'Donnell20.84%19.09%
Dwight Engen10.42%19.09%
Total237100.00%11100.00%

/* * If we are changing DAX flags, we have to ensure the file is clean and any * cached objects in the address space are invalidated and removed. This * requires us to lock out other IO and page faults similar to a truncate * operation. The locks need to be held until the transaction has been committed * so that the cache invalidation is atomic with respect to the DAX flag * manipulation. */
static int xfs_ioctl_setattr_dax_invalidate( struct xfs_inode *ip, struct fsxattr *fa, int *join_flags) { struct inode *inode = VFS_I(ip); int error; *join_flags = 0; /* * It is only valid to set the DAX flag on regular files and * directories on filesystems where the block size is equal to the page * size. On directories it serves as an inherit hint. */ if (fa->fsx_xflags & FS_XFLAG_DAX) { if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) return -EINVAL; if (ip->i_mount->m_sb.sb_blocksize != PAGE_SIZE) return -EINVAL; } /* If the DAX state is not changing, we have nothing to do here. */ if ((fa->fsx_xflags & FS_XFLAG_DAX) && IS_DAX(inode)) return 0; if (!(fa->fsx_xflags & FS_XFLAG_DAX) && !IS_DAX(inode)) return 0; /* lock, flush and invalidate mapping in preparation for flag change */ xfs_ilock(ip, XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL); error = filemap_write_and_wait(inode->i_mapping); if (error) goto out_unlock; error = invalidate_inode_pages2(inode->i_mapping); if (error) goto out_unlock; *join_flags = XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL; return 0; out_unlock: xfs_iunlock(ip, XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL); return error; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Chinner17590.67%457.14%
Christoph Hellwig168.29%114.29%
Dwight Engen10.52%114.29%
Bill O'Donnell10.52%114.29%
Total193100.00%7100.00%

/* * Set up the transaction structure for the setattr operation, checking that we * have permission to do so. On success, return a clean transaction and the * inode locked exclusively ready for further operation specific checks. On * failure, return an error without modifying or locking the inode. * * The inode might already be IO locked on call. If this is the case, it is * indicated in @join_flags and we take full responsibility for ensuring they * are unlocked from now on. Hence if we have an error here, we still have to * unlock them. Otherwise, once they are joined to the transaction, they will * be unlocked on commit/cancel. */
static struct xfs_trans * xfs_ioctl_setattr_get_trans( struct xfs_inode *ip, int join_flags) { struct xfs_mount *mp = ip->i_mount; struct xfs_trans *tp; int error = -EROFS; if (mp->m_flags & XFS_MOUNT_RDONLY) goto out_unlock; error = -EIO; if (XFS_FORCED_SHUTDOWN(mp)) goto out_unlock; error = xfs_trans_alloc(mp, &M_RES(mp)->tr_ichange, 0, 0, 0, &tp); if (error) return ERR_PTR(error); xfs_ilock(ip, XFS_ILOCK_EXCL); xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | join_flags); join_flags = 0; /* * CAP_FOWNER overrides the following restrictions: * * The user ID of the calling process must be equal to the file owner * ID, except in cases where the CAP_FSETID capability is applicable. */ if (!inode_owner_or_capable(VFS_I(ip))) { error = -EPERM; goto out_cancel; } if (mp->m_flags & XFS_MOUNT_WSYNC) xfs_trans_set_sync(tp); return tp; out_cancel: xfs_trans_cancel(tp); out_unlock: if (join_flags) xfs_iunlock(ip, join_flags); return ERR_PTR(error); }

Contributors

PersonTokensPropCommitsCommitProp
Dave Chinner13574.18%337.50%
Christoph Hellwig4223.08%337.50%
Dwight Engen42.20%112.50%
Arkadiusz Miskiewicz10.55%112.50%
Total182100.00%8100.00%

/* * extent size hint validation is somewhat cumbersome. Rules are: * * 1. extent size hint is only valid for directories and regular files * 2. FS_XFLAG_EXTSIZE is only valid for regular files * 3. FS_XFLAG_EXTSZINHERIT is only valid for directories. * 4. can only be changed on regular files if no extents are allocated * 5. can be changed on directories at any time * 6. extsize hint of 0 turns off hints, clears inode flags. * 7. Extent size must be a multiple of the appropriate block size. * 8. for non-realtime files, the extent size hint must be limited * to half the AG size to avoid alignment extending the extent beyond the * limits of the AG. */
static int xfs_ioctl_setattr_check_extsize( struct xfs_inode *ip, struct fsxattr *fa) { struct xfs_mount *mp = ip->i_mount; if ((fa->fsx_xflags & FS_XFLAG_EXTSIZE) && !S_ISREG(VFS_I(ip)->i_mode)) return -EINVAL; if ((fa->fsx_xflags & FS_XFLAG_EXTSZINHERIT) && !S_ISDIR(VFS_I(ip)->i_mode)) return -EINVAL; if (S_ISREG(VFS_I(ip)->i_mode) && ip->i_d.di_nextents && ((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) != fa->fsx_extsize)) return -EINVAL; if (fa->fsx_extsize != 0) { xfs_extlen_t size; xfs_fsblock_t extsize_fsb; extsize_fsb = XFS_B_TO_FSB(mp, fa->fsx_extsize); if (extsize_fsb > MAXEXTLEN) return -EINVAL; if (XFS_IS_REALTIME_INODE(ip) || (fa->fsx_xflags & FS_XFLAG_REALTIME)) { size = mp->m_sb.sb_rextsize << mp->m_sb.sb_blocklog; } else { size = mp->m_sb.sb_blocksize; if (extsize_fsb > mp->m_sb.sb_agblocks / 2) return -EINVAL; } if (fa->fsx_extsize % size) return -EINVAL; } else fa->fsx_xflags &= ~(FS_XFLAG_EXTSIZE | FS_XFLAG_EXTSZINHERIT); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Chinner12853.56%562.50%
Christoph Hellwig6527.20%112.50%
Iustin Pop4518.83%112.50%
Fengguang Wu10.42%112.50%
Total239100.00%8100.00%

/* * CoW extent size hint validation rules are: * * 1. CoW extent size hint can only be set if reflink is enabled on the fs. * The inode does not have to have any shared blocks, but it must be a v3. * 2. FS_XFLAG_COWEXTSIZE is only valid for directories and regular files; * for a directory, the hint is propagated to new files. * 3. Can be changed on files & directories at any time. * 4. CoW extsize hint of 0 turns off hints, clears inode flags. * 5. Extent size must be a multiple of the appropriate block size. * 6. The extent size hint must be limited to half the AG size to avoid * alignment extending the extent beyond the limits of the AG. */
static int xfs_ioctl_setattr_check_cowextsize( struct xfs_inode *ip, struct fsxattr *fa) { struct xfs_mount *mp = ip->i_mount; if (!(fa->fsx_xflags & FS_XFLAG_COWEXTSIZE)) return 0; if (!xfs_sb_version_hasreflink(&ip->i_mount->m_sb) || ip->i_d.di_version != 3) return -EINVAL; if (!S_ISREG(VFS_I(ip)->i_mode) && !S_ISDIR(VFS_I(ip)->i_mode)) return -EINVAL; if (fa->fsx_cowextsize != 0) { xfs_extlen_t size; xfs_fsblock_t cowextsize_fsb; cowextsize_fsb = XFS_B_TO_FSB(mp, fa->fsx_cowextsize); if (cowextsize_fsb > MAXEXTLEN) return -EINVAL; size = mp->m_sb.sb_blocksize; if (cowextsize_fsb > mp->m_sb.sb_agblocks / 2) return -EINVAL; if (fa->fsx_cowextsize % size) return -EINVAL; } else fa->fsx_xflags &= ~FS_XFLAG_COWEXTSIZE; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Darrick J. Wong176100.00%1100.00%
Total176100.00%1100.00%


static int xfs_ioctl_setattr_check_projid( struct xfs_inode *ip, struct fsxattr *fa) { /* Disallow 32bit project ids if projid32bit feature is not enabled. */ if (fa->fsx_projid > (__uint16_t)-1 && !xfs_sb_version_hasprojid32bit(&ip->i_mount->m_sb)) return -EINVAL; /* * Project Quota ID state is only allowed to change from within the init * namespace. Enforce that restriction only if we are trying to change * the quota ID state. Everything else is allowed in user namespaces. */ if (current_user_ns() == &init_user_ns) return 0; if (xfs_get_projid(ip) != fa->fsx_projid) return -EINVAL; if ((fa->fsx_xflags & FS_XFLAG_PROJINHERIT) != (ip->i_d.di_flags & XFS_DIFLAG_PROJINHERIT)) return -EINVAL; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig3737.76%112.50%
Dave Chinner2929.59%337.50%
Arkadiusz Miskiewicz2020.41%225.00%
David Chinner1111.22%112.50%
Fengguang Wu11.02%112.50%
Total98100.00%8100.00%


STATIC int xfs_ioctl_setattr( xfs_inode_t *ip, struct fsxattr *fa) { struct xfs_mount *mp = ip->i_mount; struct xfs_trans *tp; struct xfs_dquot *udqp = NULL; struct xfs_dquot *pdqp = NULL; struct xfs_dquot *olddquot = NULL; int code; int join_flags = 0; trace_xfs_ioctl_setattr(ip); code = xfs_ioctl_setattr_check_projid(ip, fa); if (code) return code; /* * If disk quotas is on, we make sure that the dquots do exist on disk, * before we start any other transactions. Trying to do this later * is messy. We don't care to take a readlock to look at the ids * in inode here, because we can't hold it across the trans_reserve. * If the IDs do change before we take the ilock, we're covered * because the i_*dquot fields will get updated anyway. */ if (XFS_IS_QUOTA_ON(mp)) { code = xfs_qm_vop_dqalloc(ip, ip->i_d.di_uid, ip->i_d.di_gid, fa->fsx_projid, XFS_QMOPT_PQUOTA, &udqp, NULL, &pdqp); if (code) return code; } /* * Changing DAX config may require inode locking for mapping * invalidation. These need to be held all the way to transaction commit * or cancel time, so need to be passed through to * xfs_ioctl_setattr_get_trans() so it can apply them to the join call * appropriately. */ code = xfs_ioctl_setattr_dax_invalidate(ip, fa, &join_flags); if (code) goto error_free_dquots; tp = xfs_ioctl_setattr_get_trans(ip, join_flags); if (IS_ERR(tp)) { code = PTR_ERR(tp); goto error_free_dquots; } if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_PQUOTA_ON(mp) && xfs_get_projid(ip) != fa->fsx_projid) { code = xfs_qm_vop_chown_reserve(tp, ip, udqp, NULL, pdqp, capable(CAP_FOWNER) ? XFS_QMOPT_FORCE_RES : 0); if (code) /* out of quota */ goto error_trans_cancel; } code = xfs_ioctl_setattr_check_extsize(ip, fa); if (code) goto error_trans_cancel; code = xfs_ioctl_setattr_check_cowextsize(ip, fa); if (code) goto error_trans_cancel; code = xfs_ioctl_setattr_xflags(tp, ip, fa); if (code) goto error_trans_cancel; /* * Change file ownership. Must be the owner or privileged. CAP_FSETID * overrides the following restrictions: * * The set-user-ID and set-group-ID bits of a file will be cleared upon * successful return from chown() */ if ((VFS_I(ip)->i_mode & (S_ISUID|S_ISGID)) && !capable_wrt_inode_uidgid(VFS_I(ip), CAP_FSETID)) VFS_I(ip)->i_mode &= ~(S_ISUID|S_ISGID); /* Change the ownerships and register project quota modifications */ if (xfs_get_projid(ip) != fa->fsx_projid) { if (XFS_IS_QUOTA_RUNNING(mp) && XFS_IS_PQUOTA_ON(mp)) { olddquot = xfs_qm_vop_chown(tp, ip, &ip->i_pdquot, pdqp); } ASSERT(ip->i_d.di_version > 1); xfs_set_projid(ip, fa->fsx_projid); } /* * Only set the extent size hint if we've already determined that the * extent size hint should be set on the inode. If no extent size flags * are set on the inode then unconditionally clear the extent size hint. */ if (ip->i_d.di_flags & (XFS_DIFLAG_EXTSIZE | XFS_DIFLAG_EXTSZINHERIT)) ip->i_d.di_extsize = fa->fsx_extsize >> mp->m_sb.sb_blocklog; else ip->i_d.di_extsize = 0; if (ip->i_d.di_version == 3 && (ip->i_d.di_flags2 & XFS_DIFLAG2_COWEXTSIZE)) ip->i_d.di_cowextsize = fa->fsx_cowextsize >> mp->m_sb.sb_blocklog; else ip->i_d.di_cowextsize = 0; code = xfs_trans_commit(tp); /* * Release any dquot(s) the inode had kept before chown. */ xfs_qm_dqrele(olddquot); xfs_qm_dqrele(udqp); xfs_qm_dqrele(pdqp); return code; error_trans_cancel: xfs_trans_cancel(tp); error_free_dquots: xfs_qm_dqrele(udqp); xfs_qm_dqrele(pdqp); return code; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig26450.57%419.05%
Dave Chinner10119.35%942.86%
David Chinner7113.60%14.76%
Darrick J. Wong6111.69%14.76%
Chandra Seetharaman91.72%14.76%
Arkadiusz Miskiewicz71.34%14.76%
Dwight Engen61.15%14.76%
Andrew Lutomirski10.19%14.76%
Lachlan McIlroy10.19%14.76%
Nathan Scott10.19%14.76%
Total522100.00%21100.00%


STATIC int xfs_ioc_fssetxattr( xfs_inode_t *ip, struct file *filp, void __user *arg) { struct fsxattr fa; int error; if (copy_from_user(&fa, arg, sizeof(fa))) return -EFAULT; error = mnt_want_write_file(filp); if (error) return error; error = xfs_ioctl_setattr(ip, &fa); mnt_drop_write_file(filp); return error; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig3241.03%125.00%
Jan Kara2633.33%125.00%
Lachlan McIlroy1924.36%125.00%
Nathan Scott11.28%125.00%
Total78100.00%4100.00%


STATIC int xfs_ioc_getxflags( xfs_inode_t *ip, void __user *arg) { unsigned int flags; flags = xfs_di2lxflags(ip->i_d.di_flags); if (copy_to_user(arg, &flags, sizeof(flags))) return -EFAULT; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig5096.15%150.00%
Lachlan McIlroy23.85%150.00%
Total52100.00%2100.00%


STATIC int xfs_ioc_setxflags( struct xfs_inode *ip, struct file *filp, void __user *arg) { struct xfs_trans *tp; struct fsxattr fa; unsigned int flags; int join_flags = 0; int error; if (copy_from_user(&flags, arg, sizeof(flags))) return -EFAULT; if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \ FS_NOATIME_FL | FS_NODUMP_FL | \ FS_SYNC_FL)) return -EOPNOTSUPP; fa.fsx_xflags = xfs_merge_ioc_xflags(flags, xfs_ip2xflags(ip)); error = mnt_want_write_file(filp); if (error) return error; /* * Changing DAX config may require inode locking for mapping * invalidation. These need to be held all the way to transaction commit * or cancel time, so need to be passed through to * xfs_ioctl_setattr_get_trans() so it can apply them to the join call * appropriately. */ error = xfs_ioctl_setattr_dax_invalidate(ip, &fa, &join_flags); if (error) goto out_drop_write; tp = xfs_ioctl_setattr_get_trans(ip, join_flags); if (IS_ERR(tp)) { error = PTR_ERR(tp); goto out_drop_write; } error = xfs_ioctl_setattr_xflags(tp, ip, &fa); if (error) { xfs_trans_cancel(tp); goto out_drop_write; } error = xfs_trans_commit(tp); out_drop_write: mnt_drop_write_file(filp); return error; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Chinner8541.67%216.67%
Nathan Scott4823.53%325.00%
Christoph Hellwig3215.69%433.33%
Jan Kara2713.24%18.33%
Lachlan McIlroy73.43%18.33%
Eric Sandeen52.45%18.33%
Total204100.00%12100.00%


STATIC int xfs_getbmap_format(void **ap, struct getbmapx *bmv) { struct getbmap __user *base = (struct getbmap __user *)*ap; /* copy only getbmap portion (not getbmapx) */ if (copy_to_user(base, bmv, sizeof(struct getbmap))) return -EFAULT; *ap += sizeof(struct getbmap); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Sandeen5485.71%120.00%
Dave Chinner711.11%240.00%
Nathan Scott11.59%120.00%
Christoph Hellwig11.59%120.00%
Total63100.00%5100.00%


STATIC int xfs_ioc_getbmap( struct file *file, unsigned int cmd, void __user *arg) { struct getbmapx bmx; int error; if (copy_from_user(&bmx, arg, sizeof(struct getbmapx))) return -EFAULT; if (bmx.bmv_count < 2) return -EINVAL; bmx.bmv_iflags = (cmd == XFS_IOC_GETBMAPA ? BMV_IF_ATTRFORK : 0); if (file->f_mode & FMODE_NOCMTIME) bmx.bmv_iflags |= BMV_IF_NO_DMAPI_READ; error = xfs_getbmap(XFS_I(file_inode(file)), &bmx, xfs_getbmap_format, (__force struct getbmap *)arg+1); if (error) return error; /* copy back header - only size of getbmap */ if (copy_to_user(arg, &bmx, sizeof(struct getbmap))) return -EFAULT; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig12082.19%342.86%
Eric Sandeen2114.38%114.29%
Nathan Scott32.05%114.29%
Stephen Lord10.68%114.29%
Dave Chinner10.68%114.29%
Total146100.00%7100.00%


STATIC int xfs_getbmapx_format(void **ap, struct getbmapx *bmv) { struct getbmapx __user *base = (struct getbmapx __user *)*ap; if (copy_to_user(base, bmv, sizeof(struct getbmapx))) return -EFAULT; *ap += sizeof(struct getbmapx); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Sandeen5385.48%120.00%
Dave Chinner711.29%240.00%
Nathan Scott11.61%120.00%
Christoph Hellwig11.61%120.00%
Total62100.00%5100.00%


STATIC int xfs_ioc_getbmapx( struct xfs_inode *ip, void __user *arg) { struct getbmapx bmx; int error; if (copy_from_user(&bmx, arg, sizeof(bmx))) return -EFAULT; if (bmx.bmv_count < 2) return -EINVAL; if (bmx.bmv_iflags & (~BMV_IF_VALID)) return -EINVAL; error = xfs_getbmap(ip, &bmx, xfs_getbmapx_format, (__force struct getbmapx *)arg+1); if (error) return error; /* copy back header */ if (copy_to_user(arg, &bmx, sizeof(struct getbmapx))) return -EFAULT; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig10888.52%240.00%
Eric Sandeen108.20%120.00%
Nathan Scott32.46%120.00%
Dave Chinner10.82%120.00%
Total122100.00%5100.00%


int xfs_ioc_swapext( xfs_swapext_t *sxp) { xfs_inode_t *ip, *tip; struct fd f, tmp; int error = 0; /* Pull information for the target fd */ f = fdget((int)sxp->sx_fdtarget); if (!f.file) { error = -EINVAL; goto out; } if (!(f.file->f_mode & FMODE_WRITE) || !(f.file->f_mode & FMODE_READ) || (f.file->f_flags & O_APPEND)) { error = -EBADF; goto out_put_file; } tmp = fdget((int)sxp->sx_fdtmp); if (!tmp.file) { error = -EINVAL; goto out_put_file; } if (!(tmp.file->f_mode & FMODE_WRITE) || !(tmp.file->f_mode & FMODE_READ) || (tmp.file->f_flags & O_APPEND)) { error = -EBADF; goto out_put_tmp_file; } if (IS_SWAPFILE(file_inode(f.file)) || IS_SWAPFILE(file_inode(tmp.file))) { error = -EINVAL; goto out_put_tmp_file; } /* * We need to ensure that the fds passed in point to XFS inodes * before we cast and access them as XFS structures as we have no * control over what the user passes us here. */ if (f.file->f_op != &xfs_file_operations || tmp.file->f_op != &xfs_file_operations) { error = -EINVAL; goto out_put_tmp_file; } ip = XFS_I(file_inode(f.file)); tip = XFS_I(file_inode(tmp.file)); if (ip->i_mount != tip->i_mount) { error = -EINVAL; goto out_put_tmp_file; } if (ip->i_ino == tip->i_ino) { error = -EINVAL; goto out_put_tmp_file; } if (XFS_FORCED_SHUTDOWN(ip->i_mount)) { error = -EIO; goto out_put_tmp_file; } error = xfs_swap_extents(ip, tip, sxp); out_put_tmp_file: fdput(tmp); out_put_file: fdput(f); out: return error; }

Contributors

PersonTokensPropCommitsCommitProp
Dave Chinner31991.14%266.67%
Jann Horn318.86%133.33%
Total350100.00%3100.00%

/* * Note: some of the ioctl's return positive numbers as a * byte count indicating success, such as readlink_by_handle. * So we don't "sign flip" like most other routines. This means * true errors need to be returned as a negative value. */
long xfs_file_ioctl( struct file *filp, unsigned int cmd, unsigned long p) { struct inode *inode = file_inode(filp); struct xfs_inode *ip = XFS_I(inode); struct xfs_mount *mp = ip->i_mount; void __user *arg = (void __user *)p; int error; trace_xfs_file_ioctl(ip); switch (cmd) { case FITRIM: return xfs_ioc_trim(mp, arg); case XFS_IOC_ALLOCSP: case XFS_IOC_FREESP: case XFS_IOC_RESVSP: case XFS_IOC_UNRESVSP: case XFS_IOC_ALLOCSP64: case XFS_IOC_FREESP64: case XFS_IOC_RESVSP64: case XFS_IOC_UNRESVSP64: case XFS_IOC_ZERO_RANGE: { xfs_flock64_t bf; if (copy_from_user(&bf, arg, sizeof(bf))) return -EFAULT; return xfs_ioc_space(filp, cmd, &bf); } case XFS_IOC_DIOINFO: { struct dioattr da; xfs_buftarg_t *target = XFS_IS_REALTIME_INODE(ip) ? mp->m_rtdev_targp : mp->m_ddev_targp; da.d_mem = da.d_miniosz = target->bt_logical_sectorsize; da.d_maxiosz = INT_MAX & ~(da.d_miniosz - 1); if (copy_to_user(arg, &da, sizeof(da))) return -EFAULT; return 0; } case XFS_IOC_FSBULKSTAT_SINGLE: case XFS_IOC_FSBULKSTAT: case XFS_IOC_FSINUMBERS: return xfs_ioc_bulkstat(mp, cmd, arg); case XFS_IOC_FSGEOMETRY_V1: return xfs_ioc_fsgeometry_v1(mp, arg); case XFS_IOC_FSGEOMETRY: return xfs_ioc_fsgeometry(mp, arg); case XFS_IOC_GETVERSION: return put_user(inode->i_generation, (int __user *)arg); case XFS_IOC_FSGETXATTR: return xfs_ioc_fsgetxattr(ip, 0, arg); case XFS_IOC_FSGETXATTRA: return xfs_ioc_fsgetxattr(ip, 1, arg); case XFS_IOC_FSSETXATTR: return xfs_ioc_fssetxattr(ip, filp, arg); case XFS_IOC_GETXFLAGS: return xfs_ioc_getxflags(ip, arg); case XFS_IOC_SETXFLAGS: return xfs_ioc_setxflags(ip, filp, arg); case XFS_IOC_FSSETDM: { struct fsdmidata dmi; if (copy_from_user(&dmi, arg, sizeof(dmi))) return -EFAULT; error = mnt_want_write_file(filp); if (error) return error; error = xfs_set_dmattrs(ip, dmi.fsd_dmevmask, dmi.fsd_dmstate); mnt_drop_write_file(filp); return error; } case XFS_IOC_GETBMAP: case XFS_IOC_GETBMAPA: return xfs_ioc_getbmap(filp, cmd, arg); case XFS_IOC_GETBMAPX: return xfs_ioc_getbmapx(ip, arg); case XFS_IOC_FD_TO_HANDLE: case XFS_IOC_PATH_TO_HANDLE: case XFS_IOC_PATH_TO_FSHANDLE: { xfs_fsop_handlereq_t hreq; if (copy_from_user(&hreq, arg, sizeof(hreq))) return -EFAULT; return xfs_find_handle(cmd, &hreq); } case XFS_IOC_OPEN_BY_HANDLE: { xfs_fsop_handlereq_t hreq; if (copy_from_user(&hreq, arg, sizeof(xfs_fsop_handlereq_t))) return -EFAULT; return xfs_open_by_handle(filp, &hreq); } case XFS_IOC_FSSETDM_BY_HANDLE: return xfs_fssetdm_by_handle(filp, arg); case XFS_IOC_READLINK_BY_HANDLE: { xfs_fsop_handlereq_t hreq; if (copy_from_user(&hreq, arg, sizeof(xfs_fsop_handlereq_t))) return -EFAULT; return xfs_readlink_by_handle(filp, &hreq); } case XFS_IOC_ATTRLIST_BY_HANDLE: return xfs_attrlist_by_handle(filp, arg); case XFS_IOC_ATTRMULTI_BY_HANDLE: return xfs_attrmulti_by_handle(filp, arg); case XFS_IOC_SWAPEXT: { struct xfs_swapext sxp; if (copy_from_user(&sxp, arg, sizeof(xfs_swapext_t))) return -EFAULT; error = mnt_want_write_file(filp); if (error) return error; error = xfs_ioc_swapext(&sxp); mnt_drop_write_file(filp); return error; } case XFS_IOC_FSCOUNTS: { xfs_fsop_counts_t out; error = xfs_fs_counts(mp, &out); if (error) return error; if (copy_to_user(arg, &out, sizeof(out))) return -EFAULT; return 0; } case XFS_IOC_SET_RESBLKS: { xfs_fsop_resblks_t inout; __uint64_t in; if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (mp->m_flags & XFS_MOUNT_RDONLY) return -EROFS; if (copy_from_user(&inout, arg, sizeof(inout))) return -EFAULT; error = mnt_want_write_file(filp); if (error) return error; /* input parameter is passed in resblks field of structure */ in = inout.resblks; error = xfs_reserve_blocks(mp, &in, &inout); mnt_drop_write_file(filp); if (error) return error; if (copy_to_user(arg, &inout, sizeof(inout))) return -EFAULT; return 0; } case XFS_IOC_GET_RESBLKS: { xfs_fsop_resblks_t out; if (!capable(CAP_SYS_ADMIN)) return -EPERM; error = xfs_reserve_blocks(mp, NULL, &out); if (error) return error; if (copy_to_user(arg, &out, sizeof(out))) return -EFAULT; return 0; } case XFS_IOC_FSGROWFSDATA: { xfs_growfs_data_t in; if (copy_from_user(&in, arg, sizeof(in))) return -EFAULT; error = mnt_want_write_file(filp); if (error) return error; error = xfs_growfs_data(mp, &in); mnt_drop_write_file(filp); return error; } case XFS_IOC_FSGROWFSLOG: { xfs_growfs_log_t in; if (copy_from_user(&in, arg, sizeof(in))) return -EFAULT; error = mnt_want_write_file(filp); if (error) return error; error = xfs_growfs_log(mp, &in); mnt_drop_write_file(filp); return error; } case XFS_IOC_FSGROWFSRT: { xfs_growfs_rt_t in; if (copy_from_user(&in, arg, sizeof(in))) return -EFAULT; error = mnt_want_write_file(filp); if (error) return error; error = xfs_growfs_rt(mp, &in); mnt_drop_write_file(filp); return error; } case XFS_IOC_GOINGDOWN: { __uint32_t in; if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (get_user(in, (__uint32_t __user *)arg)) return -EFAULT; return xfs_fs_goingdown(mp, in); } case XFS_IOC_ERROR_INJECTION: { xfs_error_injection_t in; if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (copy_from_user(&in, arg, sizeof(in))) return -EFAULT; return xfs_errortag_add(in.errtag, mp); } case XFS_IOC_ERROR_CLEARALL: if (!capable(CAP_SYS_ADMIN)) return -EPERM; return xfs_errortag_clearall(mp, 1); case XFS_IOC_FREE_EOFBLOCKS: { struct xfs_fs_eofblocks eofb; struct xfs_eofblocks keofb; if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (mp->m_flags & XFS_MOUNT_RDONLY) return -EROFS; if (copy_from_user(&eofb, arg, sizeof(eofb))) return -EFAULT; error = xfs_fs_eofblocks_from_user(&eofb, &keofb); if (error) return error; return xfs_icache_free_eofblocks(mp, &keofb); } default: return -ENOTTY; } }

Contributors

PersonTokensPropCommitsCommitProp
Lachlan McIlroy86368.87%315.00%
Eric Sandeen13210.53%315.00%
Jan Kara1149.10%15.00%
Christoph Hellwig493.91%525.00%
Brian Foster433.43%15.00%
Dwight Engen403.19%210.00%
Dave Chinner70.56%315.00%
Al Viro30.24%15.00%
Dave Hansen20.16%15.00%
Total1253100.00%20100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Christoph Hellwig403248.51%3724.50%
Dave Chinner141116.98%3321.85%
Lachlan McIlroy90810.93%42.65%
Nathan Scott3794.56%106.62%
Darrick J. Wong3554.27%53.31%
Eric Sandeen3313.98%85.30%
Jan Kara2092.51%21.32%
David Chinner1001.20%53.31%
Al Viro600.72%85.30%
Dave Hansen560.67%10.66%
Andreas Gruenbacher520.63%21.32%
Dwight Engen520.63%31.99%
Arkadiusz Miskiewicz490.59%21.32%
Iustin Pop450.54%10.66%
Brian Foster430.52%10.66%
David Howells380.46%21.32%
Jann Horn310.37%10.66%
Russell Cattelan230.28%10.66%
Li Zefan210.25%10.66%
Zhitong Wang180.22%10.66%
Dan Rosenberg140.17%10.66%
Dan Carpenter100.12%10.66%
Chandra Seetharaman90.11%10.66%
Vlad Apostolov80.10%10.66%
Stephen Lord70.08%10.66%
Alexey Dobriyan50.06%10.66%
Josef 'Jeff' Sipek50.06%10.66%
Jie Liu40.05%10.66%
Yann Droneaud40.05%10.66%
Tuomas Tynkkynen40.05%10.66%
Ingo Molnar30.04%10.66%
Tejun Heo30.04%10.66%
Jan Tulak30.04%21.32%
Randy Dunlap30.04%10.66%
Alex Elder30.04%10.66%
Bill O'Donnell30.04%10.66%
Michal Marek20.02%10.66%
Fengguang Wu20.02%10.66%
Miklos Szeredi20.02%10.66%
Hannes Eder20.02%10.66%
Eryu Guan10.01%10.66%
Andrew Lutomirski10.01%10.66%
Total8311100.00%151100.00%
Directory: fs/xfs
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.