STATIC int xfs_ioc_setxflags( xfs_inode_t *ip, struct file *filp, void __user *arg) { struct fsxattr fa; unsigned int flags; unsigned int mask; 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; mask = FSX_XFLAGS; if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) mask |= FSX_NONBLOCK; fa.fsx_xflags = xfs_merge_ioc_xflags(flags, xfs_ip2xflags(ip)); error = mnt_want_write_file(filp); if (error) return error; error = xfs_ioctl_setattr(ip, &fa, mask); mnt_drop_write_file(filp); return -error; }
STATIC int xfs_ioc_fsgetxattr( xfs_inode_t *ip, int attr, void __user *arg) { struct fsxattr fa; 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_projid = ip->i_d.di_projid; if (attr) { if (ip->i_afp) { if (ip->i_afp->if_flags & XFS_IFEXTENTS) fa.fsx_nextents = ip->i_afp->if_bytes / sizeof(xfs_bmbt_rec_t); 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 = ip->i_df.if_bytes / sizeof(xfs_bmbt_rec_t); 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; }
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; }
/* * Revalidate the Linux inode from the XFS inode. * Note: i_size _not_ updated; we must hold the inode * semaphore when doing that - callers responsibility. */ int vn_revalidate( bhv_vnode_t *vp) { struct inode *inode = vn_to_inode(vp); struct xfs_inode *ip = XFS_I(inode); struct xfs_mount *mp = ip->i_mount; unsigned long xflags; xfs_itrace_entry(ip); if (XFS_FORCED_SHUTDOWN(mp)) return -EIO; xfs_ilock(ip, XFS_ILOCK_SHARED); inode->i_mode = ip->i_d.di_mode; inode->i_uid = ip->i_d.di_uid; inode->i_gid = ip->i_d.di_gid; inode->i_mtime.tv_sec = ip->i_d.di_mtime.t_sec; inode->i_mtime.tv_nsec = ip->i_d.di_mtime.t_nsec; inode->i_ctime.tv_sec = ip->i_d.di_ctime.t_sec; inode->i_ctime.tv_nsec = ip->i_d.di_ctime.t_nsec; xflags = xfs_ip2xflags(ip); if (xflags & XFS_XFLAG_IMMUTABLE) inode->i_flags |= S_IMMUTABLE; else inode->i_flags &= ~S_IMMUTABLE; if (xflags & XFS_XFLAG_APPEND) inode->i_flags |= S_APPEND; else inode->i_flags &= ~S_APPEND; if (xflags & XFS_XFLAG_SYNC) inode->i_flags |= S_SYNC; else inode->i_flags &= ~S_SYNC; if (xflags & XFS_XFLAG_NOATIME) inode->i_flags |= S_NOATIME; else inode->i_flags &= ~S_NOATIME; xfs_iunlock(ip, XFS_ILOCK_SHARED); xfs_iflags_clear(ip, XFS_IMODIFIED); return 0; }
/* * Return stat information for one inode. * Return 0 if ok, else errno. */ int xfs_bulkstat_one_int( struct xfs_mount *mp, /* mount point for filesystem */ xfs_ino_t ino, /* inode to get data for */ void __user *buffer, /* buffer to place output in */ int ubsize, /* size of buffer */ bulkstat_one_fmt_pf formatter, /* formatter, copy to user */ int *ubused, /* bytes used by me */ int *stat) /* BULKSTAT_RV_... */ { struct xfs_icdinode *dic; /* dinode core info pointer */ struct xfs_inode *ip; /* incore inode pointer */ struct xfs_bstat *buf; /* return buffer */ int error = 0; /* error value */ *stat = BULKSTAT_RV_NOTHING; if (!buffer || xfs_internal_inum(mp, ino)) return -EINVAL; buf = kmem_alloc(sizeof(*buf), KM_SLEEP | KM_MAYFAIL); if (!buf) return -ENOMEM; error = xfs_iget(mp, NULL, ino, (XFS_IGET_DONTCACHE | XFS_IGET_UNTRUSTED), XFS_ILOCK_SHARED, &ip); if (error) goto out_free; ASSERT(ip != NULL); ASSERT(ip->i_imap.im_blkno != 0); dic = &ip->i_d; /* xfs_iget returns the following without needing * further change. */ buf->bs_nlink = dic->di_nlink; buf->bs_projid_lo = dic->di_projid_lo; buf->bs_projid_hi = dic->di_projid_hi; buf->bs_ino = ino; buf->bs_mode = dic->di_mode; buf->bs_uid = dic->di_uid; buf->bs_gid = dic->di_gid; buf->bs_size = dic->di_size; buf->bs_atime.tv_sec = dic->di_atime.t_sec; buf->bs_atime.tv_nsec = dic->di_atime.t_nsec; buf->bs_mtime.tv_sec = dic->di_mtime.t_sec; buf->bs_mtime.tv_nsec = dic->di_mtime.t_nsec; buf->bs_ctime.tv_sec = dic->di_ctime.t_sec; buf->bs_ctime.tv_nsec = dic->di_ctime.t_nsec; buf->bs_xflags = xfs_ip2xflags(ip); buf->bs_extsize = dic->di_extsize << mp->m_sb.sb_blocklog; buf->bs_extents = dic->di_nextents; buf->bs_gen = dic->di_gen; memset(buf->bs_pad, 0, sizeof(buf->bs_pad)); buf->bs_dmevmask = dic->di_dmevmask; buf->bs_dmstate = dic->di_dmstate; buf->bs_aextents = dic->di_anextents; buf->bs_forkoff = XFS_IFORK_BOFF(ip); switch (dic->di_format) { case XFS_DINODE_FMT_DEV: buf->bs_rdev = ip->i_df.if_u2.if_rdev; buf->bs_blksize = BLKDEV_IOSIZE; buf->bs_blocks = 0; break; case XFS_DINODE_FMT_LOCAL: case XFS_DINODE_FMT_UUID: buf->bs_rdev = 0; buf->bs_blksize = mp->m_sb.sb_blocksize; buf->bs_blocks = 0; break; case XFS_DINODE_FMT_EXTENTS: case XFS_DINODE_FMT_BTREE: buf->bs_rdev = 0; buf->bs_blksize = mp->m_sb.sb_blocksize; buf->bs_blocks = dic->di_nblocks + ip->i_delayed_blks; break; } xfs_iunlock(ip, XFS_ILOCK_SHARED); IRELE(ip); error = formatter(buffer, ubsize, ubused, buf); if (!error) *stat = BULKSTAT_RV_DIDONE; out_free: kmem_free(buf); return error; }
STATIC int xfs_ioc_xattr( vnode_t *vp, xfs_inode_t *ip, struct file *filp, unsigned int cmd, void __user *arg) { struct fsxattr fa; struct vattr *vattr; int error = 0; int attr_flags; unsigned int flags; vattr = kmalloc(sizeof(*vattr), GFP_KERNEL); if (unlikely(!vattr)) return -ENOMEM; switch (cmd) { case XFS_IOC_FSGETXATTR: { vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | \ XFS_AT_NEXTENTS | XFS_AT_PROJID; VOP_GETATTR(vp, vattr, 0, NULL, error); if (unlikely(error)) { error = -error; break; } fa.fsx_xflags = vattr->va_xflags; fa.fsx_extsize = vattr->va_extsize; fa.fsx_nextents = vattr->va_nextents; fa.fsx_projid = vattr->va_projid; if (copy_to_user(arg, &fa, sizeof(fa))) { error = -EFAULT; break; } break; } case XFS_IOC_FSSETXATTR: { if (copy_from_user(&fa, arg, sizeof(fa))) { error = -EFAULT; break; } attr_flags = 0; if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) attr_flags |= ATTR_NONBLOCK; vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | XFS_AT_PROJID; vattr->va_xflags = fa.fsx_xflags; vattr->va_extsize = fa.fsx_extsize; vattr->va_projid = fa.fsx_projid; VOP_SETATTR(vp, vattr, attr_flags, NULL, error); if (likely(!error)) __vn_revalidate(vp, vattr); /* update flags */ error = -error; break; } case XFS_IOC_FSGETXATTRA: { vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | \ XFS_AT_ANEXTENTS | XFS_AT_PROJID; VOP_GETATTR(vp, vattr, 0, NULL, error); if (unlikely(error)) { error = -error; break; } fa.fsx_xflags = vattr->va_xflags; fa.fsx_extsize = vattr->va_extsize; fa.fsx_nextents = vattr->va_anextents; fa.fsx_projid = vattr->va_projid; if (copy_to_user(arg, &fa, sizeof(fa))) { error = -EFAULT; break; } break; } case XFS_IOC_GETXFLAGS: { flags = xfs_di2lxflags(ip->i_d.di_flags); if (copy_to_user(arg, &flags, sizeof(flags))) error = -EFAULT; break; } case XFS_IOC_SETXFLAGS: { if (copy_from_user(&flags, arg, sizeof(flags))) { error = -EFAULT; break; } if (flags & ~(LINUX_XFLAG_IMMUTABLE | LINUX_XFLAG_APPEND | \ LINUX_XFLAG_NOATIME | LINUX_XFLAG_NODUMP | \ LINUX_XFLAG_SYNC)) { error = -EOPNOTSUPP; break; } attr_flags = 0; if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) attr_flags |= ATTR_NONBLOCK; vattr->va_mask = XFS_AT_XFLAGS; vattr->va_xflags = xfs_merge_ioc_xflags(flags, xfs_ip2xflags(ip)); VOP_SETATTR(vp, vattr, attr_flags, NULL, error); if (likely(!error)) __vn_revalidate(vp, vattr); /* update flags */ error = -error; break; } case XFS_IOC_GETVERSION: { flags = vn_to_inode(vp)->i_generation; if (copy_to_user(arg, &flags, sizeof(flags))) error = -EFAULT; break; } default: error = -ENOTTY; break; } kfree(vattr); return error; }