aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_ioctl.c')
-rw-r--r--fs/xfs/xfs_ioctl.c130
1 files changed, 122 insertions, 8 deletions
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 45287419dc37..e448d735346b 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -641,7 +641,11 @@ xfs_ioc_space(
641 unsigned int cmd, 641 unsigned int cmd,
642 xfs_flock64_t *bf) 642 xfs_flock64_t *bf)
643{ 643{
644 int attr_flags = 0; 644 struct xfs_mount *mp = ip->i_mount;
645 struct xfs_trans *tp;
646 struct iattr iattr;
647 bool setprealloc = false;
648 bool clrprealloc = false;
645 int error; 649 int error;
646 650
647 /* 651 /*
@@ -661,17 +665,127 @@ xfs_ioc_space(
661 if (!S_ISREG(inode->i_mode)) 665 if (!S_ISREG(inode->i_mode))
662 return -XFS_ERROR(EINVAL); 666 return -XFS_ERROR(EINVAL);
663 667
664 if (filp->f_flags & O_DSYNC)
665 attr_flags |= XFS_ATTR_SYNC;
666
667 if (ioflags & IO_INVIS)
668 attr_flags |= XFS_ATTR_DMI;
669
670 error = mnt_want_write_file(filp); 668 error = mnt_want_write_file(filp);
671 if (error) 669 if (error)
672 return error; 670 return error;
671
673 xfs_ilock(ip, XFS_IOLOCK_EXCL); 672 xfs_ilock(ip, XFS_IOLOCK_EXCL);
674 error = xfs_change_file_space(ip, cmd, bf, filp->f_pos, attr_flags); 673
674 switch (bf->l_whence) {
675 case 0: /*SEEK_SET*/
676 break;
677 case 1: /*SEEK_CUR*/
678 bf->l_start += filp->f_pos;
679 break;
680 case 2: /*SEEK_END*/
681 bf->l_start += XFS_ISIZE(ip);
682 break;
683 default:
684 error = XFS_ERROR(EINVAL);
685 goto out_unlock;
686 }
687
688 /*
689 * length of <= 0 for resv/unresv/zero is invalid. length for
690 * alloc/free is ignored completely and we have no idea what userspace
691 * might have set it to, so set it to zero to allow range
692 * checks to pass.
693 */
694 switch (cmd) {
695 case XFS_IOC_ZERO_RANGE:
696 case XFS_IOC_RESVSP:
697 case XFS_IOC_RESVSP64:
698 case XFS_IOC_UNRESVSP:
699 case XFS_IOC_UNRESVSP64:
700 if (bf->l_len <= 0) {
701 error = XFS_ERROR(EINVAL);
702 goto out_unlock;
703 }
704 break;
705 default:
706 bf->l_len = 0;
707 break;
708 }
709
710 if (bf->l_start < 0 ||
711 bf->l_start > mp->m_super->s_maxbytes ||
712 bf->l_start + bf->l_len < 0 ||
713 bf->l_start + bf->l_len >= mp->m_super->s_maxbytes) {
714 error = XFS_ERROR(EINVAL);
715 goto out_unlock;
716 }
717
718 switch (cmd) {
719 case XFS_IOC_ZERO_RANGE:
720 error = xfs_zero_file_space(ip, bf->l_start, bf->l_len);
721 if (!error)
722 setprealloc = true;
723 break;
724 case XFS_IOC_RESVSP:
725 case XFS_IOC_RESVSP64:
726 error = xfs_alloc_file_space(ip, bf->l_start, bf->l_len,
727 XFS_BMAPI_PREALLOC);
728 if (!error)
729 setprealloc = true;
730 break;
731 case XFS_IOC_UNRESVSP:
732 case XFS_IOC_UNRESVSP64:
733 error = xfs_free_file_space(ip, bf->l_start, bf->l_len);
734 break;
735 case XFS_IOC_ALLOCSP:
736 case XFS_IOC_ALLOCSP64:
737 case XFS_IOC_FREESP:
738 case XFS_IOC_FREESP64:
739 if (bf->l_start > XFS_ISIZE(ip)) {
740 error = xfs_alloc_file_space(ip, XFS_ISIZE(ip),
741 bf->l_start - XFS_ISIZE(ip), 0);
742 if (error)
743 goto out_unlock;
744 }
745
746 iattr.ia_valid = ATTR_SIZE;
747 iattr.ia_size = bf->l_start;
748
749 error = xfs_setattr_size(ip, &iattr);
750 if (!error)
751 clrprealloc = true;
752 break;
753 default:
754 ASSERT(0);
755 error = XFS_ERROR(EINVAL);
756 }
757
758 if (error)
759 goto out_unlock;
760
761 tp = xfs_trans_alloc(mp, XFS_TRANS_WRITEID);
762 error = xfs_trans_reserve(tp, &M_RES(mp)->tr_writeid, 0, 0);
763 if (error) {
764 xfs_trans_cancel(tp, 0);
765 goto out_unlock;
766 }
767
768 xfs_ilock(ip, XFS_ILOCK_EXCL);
769 xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
770
771 if (!(ioflags & IO_INVIS)) {
772 ip->i_d.di_mode &= ~S_ISUID;
773 if (ip->i_d.di_mode & S_IXGRP)
774 ip->i_d.di_mode &= ~S_ISGID;
775 xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
776 }
777
778 if (setprealloc)
779 ip->i_d.di_flags |= XFS_DIFLAG_PREALLOC;
780 else if (clrprealloc)
781 ip->i_d.di_flags &= ~XFS_DIFLAG_PREALLOC;
782
783 xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
784 if (filp->f_flags & O_DSYNC)
785 xfs_trans_set_sync(tp);
786 error = xfs_trans_commit(tp, 0);
787
788out_unlock:
675 xfs_iunlock(ip, XFS_IOLOCK_EXCL); 789 xfs_iunlock(ip, XFS_IOLOCK_EXCL);
676 mnt_drop_write_file(filp); 790 mnt_drop_write_file(filp);
677 return -error; 791 return -error;