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.c294
1 files changed, 261 insertions, 33 deletions
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index fe29aa61293c..6f7848cd5527 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -11,9 +11,8 @@
11#include "xfs_trans_resv.h" 11#include "xfs_trans_resv.h"
12#include "xfs_mount.h" 12#include "xfs_mount.h"
13#include "xfs_inode.h" 13#include "xfs_inode.h"
14#include "xfs_ioctl.h"
15#include "xfs_alloc.h"
16#include "xfs_rtalloc.h" 14#include "xfs_rtalloc.h"
15#include "xfs_iwalk.h"
17#include "xfs_itable.h" 16#include "xfs_itable.h"
18#include "xfs_error.h" 17#include "xfs_error.h"
19#include "xfs_attr.h" 18#include "xfs_attr.h"
@@ -25,7 +24,6 @@
25#include "xfs_export.h" 24#include "xfs_export.h"
26#include "xfs_trace.h" 25#include "xfs_trace.h"
27#include "xfs_icache.h" 26#include "xfs_icache.h"
28#include "xfs_symlink.h"
29#include "xfs_trans.h" 27#include "xfs_trans.h"
30#include "xfs_acl.h" 28#include "xfs_acl.h"
31#include "xfs_btree.h" 29#include "xfs_btree.h"
@@ -36,14 +34,8 @@
36#include "xfs_ag.h" 34#include "xfs_ag.h"
37#include "xfs_health.h" 35#include "xfs_health.h"
38 36
39#include <linux/capability.h>
40#include <linux/cred.h>
41#include <linux/dcache.h>
42#include <linux/mount.h> 37#include <linux/mount.h>
43#include <linux/namei.h> 38#include <linux/namei.h>
44#include <linux/pagemap.h>
45#include <linux/slab.h>
46#include <linux/exportfs.h>
47 39
48/* 40/*
49 * xfs_find_handle maps from userspace xfs_fsop_handlereq structure to 41 * xfs_find_handle maps from userspace xfs_fsop_handlereq structure to
@@ -721,16 +713,45 @@ out_unlock:
721 return error; 713 return error;
722} 714}
723 715
716/* Return 0 on success or positive error */
717int
718xfs_fsbulkstat_one_fmt(
719 struct xfs_ibulk *breq,
720 const struct xfs_bulkstat *bstat)
721{
722 struct xfs_bstat bs1;
723
724 xfs_bulkstat_to_bstat(breq->mp, &bs1, bstat);
725 if (copy_to_user(breq->ubuffer, &bs1, sizeof(bs1)))
726 return -EFAULT;
727 return xfs_ibulk_advance(breq, sizeof(struct xfs_bstat));
728}
729
730int
731xfs_fsinumbers_fmt(
732 struct xfs_ibulk *breq,
733 const struct xfs_inumbers *igrp)
734{
735 struct xfs_inogrp ig1;
736
737 xfs_inumbers_to_inogrp(&ig1, igrp);
738 if (copy_to_user(breq->ubuffer, &ig1, sizeof(struct xfs_inogrp)))
739 return -EFAULT;
740 return xfs_ibulk_advance(breq, sizeof(struct xfs_inogrp));
741}
742
724STATIC int 743STATIC int
725xfs_ioc_bulkstat( 744xfs_ioc_fsbulkstat(
726 xfs_mount_t *mp, 745 xfs_mount_t *mp,
727 unsigned int cmd, 746 unsigned int cmd,
728 void __user *arg) 747 void __user *arg)
729{ 748{
730 xfs_fsop_bulkreq_t bulkreq; 749 struct xfs_fsop_bulkreq bulkreq;
731 int count; /* # of records returned */ 750 struct xfs_ibulk breq = {
732 xfs_ino_t inlast; /* last inode number */ 751 .mp = mp,
733 int done; 752 .ocount = 0,
753 };
754 xfs_ino_t lastino;
734 int error; 755 int error;
735 756
736 /* done = 1 if there are more stats to get and if bulkstat */ 757 /* done = 1 if there are more stats to get and if bulkstat */
@@ -742,41 +763,243 @@ xfs_ioc_bulkstat(
742 if (XFS_FORCED_SHUTDOWN(mp)) 763 if (XFS_FORCED_SHUTDOWN(mp))
743 return -EIO; 764 return -EIO;
744 765
745 if (copy_from_user(&bulkreq, arg, sizeof(xfs_fsop_bulkreq_t))) 766 if (copy_from_user(&bulkreq, arg, sizeof(struct xfs_fsop_bulkreq)))
746 return -EFAULT; 767 return -EFAULT;
747 768
748 if (copy_from_user(&inlast, bulkreq.lastip, sizeof(__s64))) 769 if (copy_from_user(&lastino, bulkreq.lastip, sizeof(__s64)))
749 return -EFAULT; 770 return -EFAULT;
750 771
751 if ((count = bulkreq.icount) <= 0) 772 if (bulkreq.icount <= 0)
752 return -EINVAL; 773 return -EINVAL;
753 774
754 if (bulkreq.ubuffer == NULL) 775 if (bulkreq.ubuffer == NULL)
755 return -EINVAL; 776 return -EINVAL;
756 777
757 if (cmd == XFS_IOC_FSINUMBERS) 778 breq.ubuffer = bulkreq.ubuffer;
758 error = xfs_inumbers(mp, &inlast, &count, 779 breq.icount = bulkreq.icount;
759 bulkreq.ubuffer, xfs_inumbers_fmt); 780
760 else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE) 781 /*
761 error = xfs_bulkstat_one(mp, inlast, bulkreq.ubuffer, 782 * FSBULKSTAT_SINGLE expects that *lastip contains the inode number
762 sizeof(xfs_bstat_t), NULL, &done); 783 * that we want to stat. However, FSINUMBERS and FSBULKSTAT expect
763 else /* XFS_IOC_FSBULKSTAT */ 784 * that *lastip contains either zero or the number of the last inode to
764 error = xfs_bulkstat(mp, &inlast, &count, xfs_bulkstat_one, 785 * be examined by the previous call and return results starting with
765 sizeof(xfs_bstat_t), bulkreq.ubuffer, 786 * the next inode after that. The new bulk request back end functions
766 &done); 787 * take the inode to start with, so we have to compute the startino
788 * parameter from lastino to maintain correct function. lastino == 0
789 * is a special case because it has traditionally meant "first inode
790 * in filesystem".
791 */
792 if (cmd == XFS_IOC_FSINUMBERS) {
793 breq.startino = lastino ? lastino + 1 : 0;
794 error = xfs_inumbers(&breq, xfs_fsinumbers_fmt);
795 lastino = breq.startino - 1;
796 } else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE) {
797 breq.startino = lastino;
798 breq.icount = 1;
799 error = xfs_bulkstat_one(&breq, xfs_fsbulkstat_one_fmt);
800 } else { /* XFS_IOC_FSBULKSTAT */
801 breq.startino = lastino ? lastino + 1 : 0;
802 error = xfs_bulkstat(&breq, xfs_fsbulkstat_one_fmt);
803 lastino = breq.startino - 1;
804 }
767 805
768 if (error) 806 if (error)
769 return error; 807 return error;
770 808
771 if (bulkreq.ocount != NULL) { 809 if (bulkreq.lastip != NULL &&
772 if (copy_to_user(bulkreq.lastip, &inlast, 810 copy_to_user(bulkreq.lastip, &lastino, sizeof(xfs_ino_t)))
773 sizeof(xfs_ino_t))) 811 return -EFAULT;
774 return -EFAULT;
775 812
776 if (copy_to_user(bulkreq.ocount, &count, sizeof(count))) 813 if (bulkreq.ocount != NULL &&
777 return -EFAULT; 814 copy_to_user(bulkreq.ocount, &breq.ocount, sizeof(__s32)))
815 return -EFAULT;
816
817 return 0;
818}
819
820/* Return 0 on success or positive error */
821static int
822xfs_bulkstat_fmt(
823 struct xfs_ibulk *breq,
824 const struct xfs_bulkstat *bstat)
825{
826 if (copy_to_user(breq->ubuffer, bstat, sizeof(struct xfs_bulkstat)))
827 return -EFAULT;
828 return xfs_ibulk_advance(breq, sizeof(struct xfs_bulkstat));
829}
830
831/*
832 * Check the incoming bulk request @hdr from userspace and initialize the
833 * internal @breq bulk request appropriately. Returns 0 if the bulk request
834 * should proceed; XFS_ITER_ABORT if there's nothing to do; or the usual
835 * negative error code.
836 */
837static int
838xfs_bulk_ireq_setup(
839 struct xfs_mount *mp,
840 struct xfs_bulk_ireq *hdr,
841 struct xfs_ibulk *breq,
842 void __user *ubuffer)
843{
844 if (hdr->icount == 0 ||
845 (hdr->flags & ~XFS_BULK_IREQ_FLAGS_ALL) ||
846 memchr_inv(hdr->reserved, 0, sizeof(hdr->reserved)))
847 return -EINVAL;
848
849 breq->startino = hdr->ino;
850 breq->ubuffer = ubuffer;
851 breq->icount = hdr->icount;
852 breq->ocount = 0;
853 breq->flags = 0;
854
855 /*
856 * The @ino parameter is a special value, so we must look it up here.
857 * We're not allowed to have IREQ_AGNO, and we only return one inode
858 * worth of data.
859 */
860 if (hdr->flags & XFS_BULK_IREQ_SPECIAL) {
861 if (hdr->flags & XFS_BULK_IREQ_AGNO)
862 return -EINVAL;
863
864 switch (hdr->ino) {
865 case XFS_BULK_IREQ_SPECIAL_ROOT:
866 hdr->ino = mp->m_sb.sb_rootino;
867 break;
868 default:
869 return -EINVAL;
870 }
871 breq->icount = 1;
778 } 872 }
779 873
874 /*
875 * The IREQ_AGNO flag means that we only want results from a given AG.
876 * If @hdr->ino is zero, we start iterating in that AG. If @hdr->ino is
877 * beyond the specified AG then we return no results.
878 */
879 if (hdr->flags & XFS_BULK_IREQ_AGNO) {
880 if (hdr->agno >= mp->m_sb.sb_agcount)
881 return -EINVAL;
882
883 if (breq->startino == 0)
884 breq->startino = XFS_AGINO_TO_INO(mp, hdr->agno, 0);
885 else if (XFS_INO_TO_AGNO(mp, breq->startino) < hdr->agno)
886 return -EINVAL;
887
888 breq->flags |= XFS_IBULK_SAME_AG;
889
890 /* Asking for an inode past the end of the AG? We're done! */
891 if (XFS_INO_TO_AGNO(mp, breq->startino) > hdr->agno)
892 return XFS_ITER_ABORT;
893 } else if (hdr->agno)
894 return -EINVAL;
895
896 /* Asking for an inode past the end of the FS? We're done! */
897 if (XFS_INO_TO_AGNO(mp, breq->startino) >= mp->m_sb.sb_agcount)
898 return XFS_ITER_ABORT;
899
900 return 0;
901}
902
903/*
904 * Update the userspace bulk request @hdr to reflect the end state of the
905 * internal bulk request @breq.
906 */
907static void
908xfs_bulk_ireq_teardown(
909 struct xfs_bulk_ireq *hdr,
910 struct xfs_ibulk *breq)
911{
912 hdr->ino = breq->startino;
913 hdr->ocount = breq->ocount;
914}
915
916/* Handle the v5 bulkstat ioctl. */
917STATIC int
918xfs_ioc_bulkstat(
919 struct xfs_mount *mp,
920 unsigned int cmd,
921 struct xfs_bulkstat_req __user *arg)
922{
923 struct xfs_bulk_ireq hdr;
924 struct xfs_ibulk breq = {
925 .mp = mp,
926 };
927 int error;
928
929 if (!capable(CAP_SYS_ADMIN))
930 return -EPERM;
931
932 if (XFS_FORCED_SHUTDOWN(mp))
933 return -EIO;
934
935 if (copy_from_user(&hdr, &arg->hdr, sizeof(hdr)))
936 return -EFAULT;
937
938 error = xfs_bulk_ireq_setup(mp, &hdr, &breq, arg->bulkstat);
939 if (error == XFS_ITER_ABORT)
940 goto out_teardown;
941 if (error < 0)
942 return error;
943
944 error = xfs_bulkstat(&breq, xfs_bulkstat_fmt);
945 if (error)
946 return error;
947
948out_teardown:
949 xfs_bulk_ireq_teardown(&hdr, &breq);
950 if (copy_to_user(&arg->hdr, &hdr, sizeof(hdr)))
951 return -EFAULT;
952
953 return 0;
954}
955
956STATIC int
957xfs_inumbers_fmt(
958 struct xfs_ibulk *breq,
959 const struct xfs_inumbers *igrp)
960{
961 if (copy_to_user(breq->ubuffer, igrp, sizeof(struct xfs_inumbers)))
962 return -EFAULT;
963 return xfs_ibulk_advance(breq, sizeof(struct xfs_inumbers));
964}
965
966/* Handle the v5 inumbers ioctl. */
967STATIC int
968xfs_ioc_inumbers(
969 struct xfs_mount *mp,
970 unsigned int cmd,
971 struct xfs_inumbers_req __user *arg)
972{
973 struct xfs_bulk_ireq hdr;
974 struct xfs_ibulk breq = {
975 .mp = mp,
976 };
977 int error;
978
979 if (!capable(CAP_SYS_ADMIN))
980 return -EPERM;
981
982 if (XFS_FORCED_SHUTDOWN(mp))
983 return -EIO;
984
985 if (copy_from_user(&hdr, &arg->hdr, sizeof(hdr)))
986 return -EFAULT;
987
988 error = xfs_bulk_ireq_setup(mp, &hdr, &breq, arg->inumbers);
989 if (error == XFS_ITER_ABORT)
990 goto out_teardown;
991 if (error < 0)
992 return error;
993
994 error = xfs_inumbers(&breq, xfs_inumbers_fmt);
995 if (error)
996 return error;
997
998out_teardown:
999 xfs_bulk_ireq_teardown(&hdr, &breq);
1000 if (copy_to_user(&arg->hdr, &hdr, sizeof(hdr)))
1001 return -EFAULT;
1002
780 return 0; 1003 return 0;
781} 1004}
782 1005
@@ -1926,7 +2149,12 @@ xfs_file_ioctl(
1926 case XFS_IOC_FSBULKSTAT_SINGLE: 2149 case XFS_IOC_FSBULKSTAT_SINGLE:
1927 case XFS_IOC_FSBULKSTAT: 2150 case XFS_IOC_FSBULKSTAT:
1928 case XFS_IOC_FSINUMBERS: 2151 case XFS_IOC_FSINUMBERS:
2152 return xfs_ioc_fsbulkstat(mp, cmd, arg);
2153
2154 case XFS_IOC_BULKSTAT:
1929 return xfs_ioc_bulkstat(mp, cmd, arg); 2155 return xfs_ioc_bulkstat(mp, cmd, arg);
2156 case XFS_IOC_INUMBERS:
2157 return xfs_ioc_inumbers(mp, cmd, arg);
1930 2158
1931 case XFS_IOC_FSGEOMETRY_V1: 2159 case XFS_IOC_FSGEOMETRY_V1:
1932 return xfs_ioc_fsgeometry(mp, arg, 3); 2160 return xfs_ioc_fsgeometry(mp, arg, 3);