aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/linux-2.6/xfs_ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/linux-2.6/xfs_ioctl.c')
-rw-r--r--fs/xfs/linux-2.6/xfs_ioctl.c390
1 files changed, 343 insertions, 47 deletions
diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c
index a42ba9d71156..acb978d9d085 100644
--- a/fs/xfs/linux-2.6/xfs_ioctl.c
+++ b/fs/xfs/linux-2.6/xfs_ioctl.c
@@ -48,6 +48,8 @@
48#include "xfs_dfrag.h" 48#include "xfs_dfrag.h"
49#include "xfs_fsops.h" 49#include "xfs_fsops.h"
50#include "xfs_vnodeops.h" 50#include "xfs_vnodeops.h"
51#include "xfs_quota.h"
52#include "xfs_inode_item.h"
51 53
52#include <linux/capability.h> 54#include <linux/capability.h>
53#include <linux/dcache.h> 55#include <linux/dcache.h>
@@ -84,17 +86,15 @@ xfs_find_handle(
84 switch (cmd) { 86 switch (cmd) {
85 case XFS_IOC_PATH_TO_FSHANDLE: 87 case XFS_IOC_PATH_TO_FSHANDLE:
86 case XFS_IOC_PATH_TO_HANDLE: { 88 case XFS_IOC_PATH_TO_HANDLE: {
87 struct nameidata nd; 89 struct path path;
88 int error; 90 int error = user_lpath((const char __user *)hreq.path, &path);
89
90 error = user_path_walk_link((const char __user *)hreq.path, &nd);
91 if (error) 91 if (error)
92 return error; 92 return error;
93 93
94 ASSERT(nd.path.dentry); 94 ASSERT(path.dentry);
95 ASSERT(nd.path.dentry->d_inode); 95 ASSERT(path.dentry->d_inode);
96 inode = igrab(nd.path.dentry->d_inode); 96 inode = igrab(path.dentry->d_inode);
97 path_put(&nd.path); 97 path_put(&path);
98 break; 98 break;
99 } 99 }
100 100
@@ -470,6 +470,12 @@ xfs_attrlist_by_handle(
470 if (al_hreq.buflen > XATTR_LIST_MAX) 470 if (al_hreq.buflen > XATTR_LIST_MAX)
471 return -XFS_ERROR(EINVAL); 471 return -XFS_ERROR(EINVAL);
472 472
473 /*
474 * Reject flags, only allow namespaces.
475 */
476 if (al_hreq.flags & ~(ATTR_ROOT | ATTR_SECURE))
477 return -XFS_ERROR(EINVAL);
478
473 error = xfs_vget_fsop_handlereq(mp, parinode, &al_hreq.hreq, &inode); 479 error = xfs_vget_fsop_handlereq(mp, parinode, &al_hreq.hreq, &inode);
474 if (error) 480 if (error)
475 goto out; 481 goto out;
@@ -589,7 +595,7 @@ xfs_attrmulti_by_handle(
589 goto out; 595 goto out;
590 596
591 error = E2BIG; 597 error = E2BIG;
592 size = am_hreq.opcount * sizeof(attr_multiop_t); 598 size = am_hreq.opcount * sizeof(xfs_attr_multiop_t);
593 if (!size || size > 16 * PAGE_SIZE) 599 if (!size || size > 16 * PAGE_SIZE)
594 goto out_vn_rele; 600 goto out_vn_rele;
595 601
@@ -682,9 +688,9 @@ xfs_ioc_space(
682 return -XFS_ERROR(EFAULT); 688 return -XFS_ERROR(EFAULT);
683 689
684 if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) 690 if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
685 attr_flags |= ATTR_NONBLOCK; 691 attr_flags |= XFS_ATTR_NONBLOCK;
686 if (ioflags & IO_INVIS) 692 if (ioflags & IO_INVIS)
687 attr_flags |= ATTR_DMI; 693 attr_flags |= XFS_ATTR_DMI;
688 694
689 error = xfs_change_file_space(ip, cmd, &bf, filp->f_pos, 695 error = xfs_change_file_space(ip, cmd, &bf, filp->f_pos,
690 NULL, attr_flags); 696 NULL, attr_flags);
@@ -875,6 +881,322 @@ xfs_ioc_fsgetxattr(
875 return 0; 881 return 0;
876} 882}
877 883
884STATIC void
885xfs_set_diflags(
886 struct xfs_inode *ip,
887 unsigned int xflags)
888{
889 unsigned int di_flags;
890
891 /* can't set PREALLOC this way, just preserve it */
892 di_flags = (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC);
893 if (xflags & XFS_XFLAG_IMMUTABLE)
894 di_flags |= XFS_DIFLAG_IMMUTABLE;
895 if (xflags & XFS_XFLAG_APPEND)
896 di_flags |= XFS_DIFLAG_APPEND;
897 if (xflags & XFS_XFLAG_SYNC)
898 di_flags |= XFS_DIFLAG_SYNC;
899 if (xflags & XFS_XFLAG_NOATIME)
900 di_flags |= XFS_DIFLAG_NOATIME;
901 if (xflags & XFS_XFLAG_NODUMP)
902 di_flags |= XFS_DIFLAG_NODUMP;
903 if (xflags & XFS_XFLAG_PROJINHERIT)
904 di_flags |= XFS_DIFLAG_PROJINHERIT;
905 if (xflags & XFS_XFLAG_NODEFRAG)
906 di_flags |= XFS_DIFLAG_NODEFRAG;
907 if (xflags & XFS_XFLAG_FILESTREAM)
908 di_flags |= XFS_DIFLAG_FILESTREAM;
909 if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) {
910 if (xflags & XFS_XFLAG_RTINHERIT)
911 di_flags |= XFS_DIFLAG_RTINHERIT;
912 if (xflags & XFS_XFLAG_NOSYMLINKS)
913 di_flags |= XFS_DIFLAG_NOSYMLINKS;
914 if (xflags & XFS_XFLAG_EXTSZINHERIT)
915 di_flags |= XFS_DIFLAG_EXTSZINHERIT;
916 } else if ((ip->i_d.di_mode & S_IFMT) == S_IFREG) {
917 if (xflags & XFS_XFLAG_REALTIME)
918 di_flags |= XFS_DIFLAG_REALTIME;
919 if (xflags & XFS_XFLAG_EXTSIZE)
920 di_flags |= XFS_DIFLAG_EXTSIZE;
921 }
922
923 ip->i_d.di_flags = di_flags;
924}
925
926STATIC void
927xfs_diflags_to_linux(
928 struct xfs_inode *ip)
929{
930 struct inode *inode = XFS_ITOV(ip);
931 unsigned int xflags = xfs_ip2xflags(ip);
932
933 if (xflags & XFS_XFLAG_IMMUTABLE)
934 inode->i_flags |= S_IMMUTABLE;
935 else
936 inode->i_flags &= ~S_IMMUTABLE;
937 if (xflags & XFS_XFLAG_APPEND)
938 inode->i_flags |= S_APPEND;
939 else
940 inode->i_flags &= ~S_APPEND;
941 if (xflags & XFS_XFLAG_SYNC)
942 inode->i_flags |= S_SYNC;
943 else
944 inode->i_flags &= ~S_SYNC;
945 if (xflags & XFS_XFLAG_NOATIME)
946 inode->i_flags |= S_NOATIME;
947 else
948 inode->i_flags &= ~S_NOATIME;
949}
950
951#define FSX_PROJID 1
952#define FSX_EXTSIZE 2
953#define FSX_XFLAGS 4
954#define FSX_NONBLOCK 8
955
956STATIC int
957xfs_ioctl_setattr(
958 xfs_inode_t *ip,
959 struct fsxattr *fa,
960 int mask)
961{
962 struct xfs_mount *mp = ip->i_mount;
963 struct xfs_trans *tp;
964 unsigned int lock_flags = 0;
965 struct xfs_dquot *udqp = NULL, *gdqp = NULL;
966 struct xfs_dquot *olddquot = NULL;
967 int code;
968
969 xfs_itrace_entry(ip);
970
971 if (mp->m_flags & XFS_MOUNT_RDONLY)
972 return XFS_ERROR(EROFS);
973 if (XFS_FORCED_SHUTDOWN(mp))
974 return XFS_ERROR(EIO);
975
976 /*
977 * If disk quotas is on, we make sure that the dquots do exist on disk,
978 * before we start any other transactions. Trying to do this later
979 * is messy. We don't care to take a readlock to look at the ids
980 * in inode here, because we can't hold it across the trans_reserve.
981 * If the IDs do change before we take the ilock, we're covered
982 * because the i_*dquot fields will get updated anyway.
983 */
984 if (XFS_IS_QUOTA_ON(mp) && (mask & FSX_PROJID)) {
985 code = XFS_QM_DQVOPALLOC(mp, ip, ip->i_d.di_uid,
986 ip->i_d.di_gid, fa->fsx_projid,
987 XFS_QMOPT_PQUOTA, &udqp, &gdqp);
988 if (code)
989 return code;
990 }
991
992 /*
993 * For the other attributes, we acquire the inode lock and
994 * first do an error checking pass.
995 */
996 tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE);
997 code = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp), 0, 0, 0);
998 if (code)
999 goto error_return;
1000
1001 lock_flags = XFS_ILOCK_EXCL;
1002 xfs_ilock(ip, lock_flags);
1003
1004 /*
1005 * CAP_FOWNER overrides the following restrictions:
1006 *
1007 * The user ID of the calling process must be equal
1008 * to the file owner ID, except in cases where the
1009 * CAP_FSETID capability is applicable.
1010 */
1011 if (current->fsuid != ip->i_d.di_uid && !capable(CAP_FOWNER)) {
1012 code = XFS_ERROR(EPERM);
1013 goto error_return;
1014 }
1015
1016 /*
1017 * Do a quota reservation only if projid is actually going to change.
1018 */
1019 if (mask & FSX_PROJID) {
1020 if (XFS_IS_PQUOTA_ON(mp) &&
1021 ip->i_d.di_projid != fa->fsx_projid) {
1022 ASSERT(tp);
1023 code = XFS_QM_DQVOPCHOWNRESV(mp, tp, ip, udqp, gdqp,
1024 capable(CAP_FOWNER) ?
1025 XFS_QMOPT_FORCE_RES : 0);
1026 if (code) /* out of quota */
1027 goto error_return;
1028 }
1029 }
1030
1031 if (mask & FSX_EXTSIZE) {
1032 /*
1033 * Can't change extent size if any extents are allocated.
1034 */
1035 if (ip->i_d.di_nextents &&
1036 ((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) !=
1037 fa->fsx_extsize)) {
1038 code = XFS_ERROR(EINVAL); /* EFBIG? */
1039 goto error_return;
1040 }
1041
1042 /*
1043 * Extent size must be a multiple of the appropriate block
1044 * size, if set at all.
1045 */
1046 if (fa->fsx_extsize != 0) {
1047 xfs_extlen_t size;
1048
1049 if (XFS_IS_REALTIME_INODE(ip) ||
1050 ((mask & FSX_XFLAGS) &&
1051 (fa->fsx_xflags & XFS_XFLAG_REALTIME))) {
1052 size = mp->m_sb.sb_rextsize <<
1053 mp->m_sb.sb_blocklog;
1054 } else {
1055 size = mp->m_sb.sb_blocksize;
1056 }
1057
1058 if (fa->fsx_extsize % size) {
1059 code = XFS_ERROR(EINVAL);
1060 goto error_return;
1061 }
1062 }
1063 }
1064
1065
1066 if (mask & FSX_XFLAGS) {
1067 /*
1068 * Can't change realtime flag if any extents are allocated.
1069 */
1070 if ((ip->i_d.di_nextents || ip->i_delayed_blks) &&
1071 (XFS_IS_REALTIME_INODE(ip)) !=
1072 (fa->fsx_xflags & XFS_XFLAG_REALTIME)) {
1073 code = XFS_ERROR(EINVAL); /* EFBIG? */
1074 goto error_return;
1075 }
1076
1077 /*
1078 * If realtime flag is set then must have realtime data.
1079 */
1080 if ((fa->fsx_xflags & XFS_XFLAG_REALTIME)) {
1081 if ((mp->m_sb.sb_rblocks == 0) ||
1082 (mp->m_sb.sb_rextsize == 0) ||
1083 (ip->i_d.di_extsize % mp->m_sb.sb_rextsize)) {
1084 code = XFS_ERROR(EINVAL);
1085 goto error_return;
1086 }
1087 }
1088
1089 /*
1090 * Can't modify an immutable/append-only file unless
1091 * we have appropriate permission.
1092 */
1093 if ((ip->i_d.di_flags &
1094 (XFS_DIFLAG_IMMUTABLE|XFS_DIFLAG_APPEND) ||
1095 (fa->fsx_xflags &
1096 (XFS_XFLAG_IMMUTABLE | XFS_XFLAG_APPEND))) &&
1097 !capable(CAP_LINUX_IMMUTABLE)) {
1098 code = XFS_ERROR(EPERM);
1099 goto error_return;
1100 }
1101 }
1102
1103 xfs_trans_ijoin(tp, ip, lock_flags);
1104 xfs_trans_ihold(tp, ip);
1105
1106 /*
1107 * Change file ownership. Must be the owner or privileged.
1108 * If the system was configured with the "restricted_chown"
1109 * option, the owner is not permitted to give away the file,
1110 * and can change the group id only to a group of which he
1111 * or she is a member.
1112 */
1113 if (mask & FSX_PROJID) {
1114 /*
1115 * CAP_FSETID overrides the following restrictions:
1116 *
1117 * The set-user-ID and set-group-ID bits of a file will be
1118 * cleared upon successful return from chown()
1119 */
1120 if ((ip->i_d.di_mode & (S_ISUID|S_ISGID)) &&
1121 !capable(CAP_FSETID))
1122 ip->i_d.di_mode &= ~(S_ISUID|S_ISGID);
1123
1124 /*
1125 * Change the ownerships and register quota modifications
1126 * in the transaction.
1127 */
1128 if (ip->i_d.di_projid != fa->fsx_projid) {
1129 if (XFS_IS_PQUOTA_ON(mp)) {
1130 olddquot = XFS_QM_DQVOPCHOWN(mp, tp, ip,
1131 &ip->i_gdquot, gdqp);
1132 }
1133 ip->i_d.di_projid = fa->fsx_projid;
1134
1135 /*
1136 * We may have to rev the inode as well as
1137 * the superblock version number since projids didn't
1138 * exist before DINODE_VERSION_2 and SB_VERSION_NLINK.
1139 */
1140 if (ip->i_d.di_version == XFS_DINODE_VERSION_1)
1141 xfs_bump_ino_vers2(tp, ip);
1142 }
1143
1144 }
1145
1146 if (mask & FSX_EXTSIZE)
1147 ip->i_d.di_extsize = fa->fsx_extsize >> mp->m_sb.sb_blocklog;
1148 if (mask & FSX_XFLAGS) {
1149 xfs_set_diflags(ip, fa->fsx_xflags);
1150 xfs_diflags_to_linux(ip);
1151 }
1152
1153 xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
1154 xfs_ichgtime(ip, XFS_ICHGTIME_CHG);
1155
1156 XFS_STATS_INC(xs_ig_attrchg);
1157
1158 /*
1159 * If this is a synchronous mount, make sure that the
1160 * transaction goes to disk before returning to the user.
1161 * This is slightly sub-optimal in that truncates require
1162 * two sync transactions instead of one for wsync filesystems.
1163 * One for the truncate and one for the timestamps since we
1164 * don't want to change the timestamps unless we're sure the
1165 * truncate worked. Truncates are less than 1% of the laddis
1166 * mix so this probably isn't worth the trouble to optimize.
1167 */
1168 if (mp->m_flags & XFS_MOUNT_WSYNC)
1169 xfs_trans_set_sync(tp);
1170 code = xfs_trans_commit(tp, 0);
1171 xfs_iunlock(ip, lock_flags);
1172
1173 /*
1174 * Release any dquot(s) the inode had kept before chown.
1175 */
1176 XFS_QM_DQRELE(mp, olddquot);
1177 XFS_QM_DQRELE(mp, udqp);
1178 XFS_QM_DQRELE(mp, gdqp);
1179
1180 if (code)
1181 return code;
1182
1183 if (DM_EVENT_ENABLED(ip, DM_EVENT_ATTRIBUTE)) {
1184 XFS_SEND_NAMESP(mp, DM_EVENT_ATTRIBUTE, ip, DM_RIGHT_NULL,
1185 NULL, DM_RIGHT_NULL, NULL, NULL, 0, 0,
1186 (mask & FSX_NONBLOCK) ? DM_FLAGS_NDELAY : 0);
1187 }
1188
1189 return 0;
1190
1191 error_return:
1192 XFS_QM_DQRELE(mp, udqp);
1193 XFS_QM_DQRELE(mp, gdqp);
1194 xfs_trans_cancel(tp, 0);
1195 if (lock_flags)
1196 xfs_iunlock(ip, lock_flags);
1197 return code;
1198}
1199
878STATIC int 1200STATIC int
879xfs_ioc_fssetxattr( 1201xfs_ioc_fssetxattr(
880 xfs_inode_t *ip, 1202 xfs_inode_t *ip,
@@ -882,31 +1204,16 @@ xfs_ioc_fssetxattr(
882 void __user *arg) 1204 void __user *arg)
883{ 1205{
884 struct fsxattr fa; 1206 struct fsxattr fa;
885 struct bhv_vattr *vattr; 1207 unsigned int mask;
886 int error;
887 int attr_flags;
888 1208
889 if (copy_from_user(&fa, arg, sizeof(fa))) 1209 if (copy_from_user(&fa, arg, sizeof(fa)))
890 return -EFAULT; 1210 return -EFAULT;
891 1211
892 vattr = kmalloc(sizeof(*vattr), GFP_KERNEL); 1212 mask = FSX_XFLAGS | FSX_EXTSIZE | FSX_PROJID;
893 if (unlikely(!vattr))
894 return -ENOMEM;
895
896 attr_flags = 0;
897 if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) 1213 if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
898 attr_flags |= ATTR_NONBLOCK; 1214 mask |= FSX_NONBLOCK;
899
900 vattr->va_mask = XFS_AT_XFLAGS | XFS_AT_EXTSIZE | XFS_AT_PROJID;
901 vattr->va_xflags = fa.fsx_xflags;
902 vattr->va_extsize = fa.fsx_extsize;
903 vattr->va_projid = fa.fsx_projid;
904 1215
905 error = -xfs_setattr(ip, vattr, attr_flags, NULL); 1216 return -xfs_ioctl_setattr(ip, &fa, mask);
906 if (!error)
907 vn_revalidate(XFS_ITOV(ip)); /* update flags */
908 kfree(vattr);
909 return 0;
910} 1217}
911 1218
912STATIC int 1219STATIC int
@@ -928,10 +1235,9 @@ xfs_ioc_setxflags(
928 struct file *filp, 1235 struct file *filp,
929 void __user *arg) 1236 void __user *arg)
930{ 1237{
931 struct bhv_vattr *vattr; 1238 struct fsxattr fa;
932 unsigned int flags; 1239 unsigned int flags;
933 int attr_flags; 1240 unsigned int mask;
934 int error;
935 1241
936 if (copy_from_user(&flags, arg, sizeof(flags))) 1242 if (copy_from_user(&flags, arg, sizeof(flags)))
937 return -EFAULT; 1243 return -EFAULT;
@@ -941,22 +1247,12 @@ xfs_ioc_setxflags(
941 FS_SYNC_FL)) 1247 FS_SYNC_FL))
942 return -EOPNOTSUPP; 1248 return -EOPNOTSUPP;
943 1249
944 vattr = kmalloc(sizeof(*vattr), GFP_KERNEL); 1250 mask = FSX_XFLAGS;
945 if (unlikely(!vattr))
946 return -ENOMEM;
947
948 attr_flags = 0;
949 if (filp->f_flags & (O_NDELAY|O_NONBLOCK)) 1251 if (filp->f_flags & (O_NDELAY|O_NONBLOCK))
950 attr_flags |= ATTR_NONBLOCK; 1252 mask |= FSX_NONBLOCK;
951 1253 fa.fsx_xflags = xfs_merge_ioc_xflags(flags, xfs_ip2xflags(ip));
952 vattr->va_mask = XFS_AT_XFLAGS;
953 vattr->va_xflags = xfs_merge_ioc_xflags(flags, xfs_ip2xflags(ip));
954 1254
955 error = -xfs_setattr(ip, vattr, attr_flags, NULL); 1255 return -xfs_ioctl_setattr(ip, &fa, mask);
956 if (likely(!error))
957 vn_revalidate(XFS_ITOV(ip)); /* update flags */
958 kfree(vattr);
959 return error;
960} 1256}
961 1257
962STATIC int 1258STATIC int