diff options
Diffstat (limited to 'fs/xfs/xfs_attr.c')
-rw-r--r-- | fs/xfs/xfs_attr.c | 317 |
1 files changed, 1 insertions, 316 deletions
diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c index 0d92e21ca33c..e9fd5acb4305 100644 --- a/fs/xfs/xfs_attr.c +++ b/fs/xfs/xfs_attr.c | |||
@@ -63,7 +63,6 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args); | |||
63 | STATIC int xfs_attr_leaf_get(xfs_da_args_t *args); | 63 | STATIC int xfs_attr_leaf_get(xfs_da_args_t *args); |
64 | STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args); | 64 | STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args); |
65 | STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args); | 65 | STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args); |
66 | STATIC int xfs_attr_leaf_list(xfs_attr_list_context_t *context); | ||
67 | 66 | ||
68 | /* | 67 | /* |
69 | * Internal routines when attribute list is more than one block. | 68 | * Internal routines when attribute list is more than one block. |
@@ -71,7 +70,6 @@ STATIC int xfs_attr_leaf_list(xfs_attr_list_context_t *context); | |||
71 | STATIC int xfs_attr_node_get(xfs_da_args_t *args); | 70 | STATIC int xfs_attr_node_get(xfs_da_args_t *args); |
72 | STATIC int xfs_attr_node_addname(xfs_da_args_t *args); | 71 | STATIC int xfs_attr_node_addname(xfs_da_args_t *args); |
73 | STATIC int xfs_attr_node_removename(xfs_da_args_t *args); | 72 | STATIC int xfs_attr_node_removename(xfs_da_args_t *args); |
74 | STATIC int xfs_attr_node_list(xfs_attr_list_context_t *context); | ||
75 | STATIC int xfs_attr_fillstate(xfs_da_state_t *state); | 73 | STATIC int xfs_attr_fillstate(xfs_da_state_t *state); |
76 | STATIC int xfs_attr_refillstate(xfs_da_state_t *state); | 74 | STATIC int xfs_attr_refillstate(xfs_da_state_t *state); |
77 | 75 | ||
@@ -91,7 +89,7 @@ xfs_attr_name_to_xname( | |||
91 | return 0; | 89 | return 0; |
92 | } | 90 | } |
93 | 91 | ||
94 | STATIC int | 92 | int |
95 | xfs_inode_hasattr( | 93 | xfs_inode_hasattr( |
96 | struct xfs_inode *ip) | 94 | struct xfs_inode *ip) |
97 | { | 95 | { |
@@ -612,157 +610,6 @@ xfs_attr_remove( | |||
612 | return xfs_attr_remove_int(dp, &xname, flags); | 610 | return xfs_attr_remove_int(dp, &xname, flags); |
613 | } | 611 | } |
614 | 612 | ||
615 | int | ||
616 | xfs_attr_list_int(xfs_attr_list_context_t *context) | ||
617 | { | ||
618 | int error; | ||
619 | xfs_inode_t *dp = context->dp; | ||
620 | |||
621 | XFS_STATS_INC(xs_attr_list); | ||
622 | |||
623 | if (XFS_FORCED_SHUTDOWN(dp->i_mount)) | ||
624 | return EIO; | ||
625 | |||
626 | xfs_ilock(dp, XFS_ILOCK_SHARED); | ||
627 | |||
628 | /* | ||
629 | * Decide on what work routines to call based on the inode size. | ||
630 | */ | ||
631 | if (!xfs_inode_hasattr(dp)) { | ||
632 | error = 0; | ||
633 | } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { | ||
634 | error = xfs_attr_shortform_list(context); | ||
635 | } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { | ||
636 | error = xfs_attr_leaf_list(context); | ||
637 | } else { | ||
638 | error = xfs_attr_node_list(context); | ||
639 | } | ||
640 | |||
641 | xfs_iunlock(dp, XFS_ILOCK_SHARED); | ||
642 | |||
643 | return error; | ||
644 | } | ||
645 | |||
646 | #define ATTR_ENTBASESIZE /* minimum bytes used by an attr */ \ | ||
647 | (((struct attrlist_ent *) 0)->a_name - (char *) 0) | ||
648 | #define ATTR_ENTSIZE(namelen) /* actual bytes used by an attr */ \ | ||
649 | ((ATTR_ENTBASESIZE + (namelen) + 1 + sizeof(u_int32_t)-1) \ | ||
650 | & ~(sizeof(u_int32_t)-1)) | ||
651 | |||
652 | /* | ||
653 | * Format an attribute and copy it out to the user's buffer. | ||
654 | * Take care to check values and protect against them changing later, | ||
655 | * we may be reading them directly out of a user buffer. | ||
656 | */ | ||
657 | /*ARGSUSED*/ | ||
658 | STATIC int | ||
659 | xfs_attr_put_listent( | ||
660 | xfs_attr_list_context_t *context, | ||
661 | int flags, | ||
662 | unsigned char *name, | ||
663 | int namelen, | ||
664 | int valuelen, | ||
665 | unsigned char *value) | ||
666 | { | ||
667 | struct attrlist *alist = (struct attrlist *)context->alist; | ||
668 | attrlist_ent_t *aep; | ||
669 | int arraytop; | ||
670 | |||
671 | ASSERT(!(context->flags & ATTR_KERNOVAL)); | ||
672 | ASSERT(context->count >= 0); | ||
673 | ASSERT(context->count < (ATTR_MAX_VALUELEN/8)); | ||
674 | ASSERT(context->firstu >= sizeof(*alist)); | ||
675 | ASSERT(context->firstu <= context->bufsize); | ||
676 | |||
677 | /* | ||
678 | * Only list entries in the right namespace. | ||
679 | */ | ||
680 | if (((context->flags & ATTR_SECURE) == 0) != | ||
681 | ((flags & XFS_ATTR_SECURE) == 0)) | ||
682 | return 0; | ||
683 | if (((context->flags & ATTR_ROOT) == 0) != | ||
684 | ((flags & XFS_ATTR_ROOT) == 0)) | ||
685 | return 0; | ||
686 | |||
687 | arraytop = sizeof(*alist) + | ||
688 | context->count * sizeof(alist->al_offset[0]); | ||
689 | context->firstu -= ATTR_ENTSIZE(namelen); | ||
690 | if (context->firstu < arraytop) { | ||
691 | trace_xfs_attr_list_full(context); | ||
692 | alist->al_more = 1; | ||
693 | context->seen_enough = 1; | ||
694 | return 1; | ||
695 | } | ||
696 | |||
697 | aep = (attrlist_ent_t *)&context->alist[context->firstu]; | ||
698 | aep->a_valuelen = valuelen; | ||
699 | memcpy(aep->a_name, name, namelen); | ||
700 | aep->a_name[namelen] = 0; | ||
701 | alist->al_offset[context->count++] = context->firstu; | ||
702 | alist->al_count = context->count; | ||
703 | trace_xfs_attr_list_add(context); | ||
704 | return 0; | ||
705 | } | ||
706 | |||
707 | /* | ||
708 | * Generate a list of extended attribute names and optionally | ||
709 | * also value lengths. Positive return value follows the XFS | ||
710 | * convention of being an error, zero or negative return code | ||
711 | * is the length of the buffer returned (negated), indicating | ||
712 | * success. | ||
713 | */ | ||
714 | int | ||
715 | xfs_attr_list( | ||
716 | xfs_inode_t *dp, | ||
717 | char *buffer, | ||
718 | int bufsize, | ||
719 | int flags, | ||
720 | attrlist_cursor_kern_t *cursor) | ||
721 | { | ||
722 | xfs_attr_list_context_t context; | ||
723 | struct attrlist *alist; | ||
724 | int error; | ||
725 | |||
726 | /* | ||
727 | * Validate the cursor. | ||
728 | */ | ||
729 | if (cursor->pad1 || cursor->pad2) | ||
730 | return(XFS_ERROR(EINVAL)); | ||
731 | if ((cursor->initted == 0) && | ||
732 | (cursor->hashval || cursor->blkno || cursor->offset)) | ||
733 | return XFS_ERROR(EINVAL); | ||
734 | |||
735 | /* | ||
736 | * Check for a properly aligned buffer. | ||
737 | */ | ||
738 | if (((long)buffer) & (sizeof(int)-1)) | ||
739 | return XFS_ERROR(EFAULT); | ||
740 | if (flags & ATTR_KERNOVAL) | ||
741 | bufsize = 0; | ||
742 | |||
743 | /* | ||
744 | * Initialize the output buffer. | ||
745 | */ | ||
746 | memset(&context, 0, sizeof(context)); | ||
747 | context.dp = dp; | ||
748 | context.cursor = cursor; | ||
749 | context.resynch = 1; | ||
750 | context.flags = flags; | ||
751 | context.alist = buffer; | ||
752 | context.bufsize = (bufsize & ~(sizeof(int)-1)); /* align */ | ||
753 | context.firstu = context.bufsize; | ||
754 | context.put_listent = xfs_attr_put_listent; | ||
755 | |||
756 | alist = (struct attrlist *)context.alist; | ||
757 | alist->al_count = 0; | ||
758 | alist->al_more = 0; | ||
759 | alist->al_offset[0] = context.bufsize; | ||
760 | |||
761 | error = xfs_attr_list_int(&context); | ||
762 | ASSERT(error >= 0); | ||
763 | return error; | ||
764 | } | ||
765 | |||
766 | int /* error */ | 613 | int /* error */ |
767 | xfs_attr_inactive(xfs_inode_t *dp) | 614 | xfs_attr_inactive(xfs_inode_t *dp) |
768 | { | 615 | { |
@@ -1167,28 +1014,6 @@ xfs_attr_leaf_get(xfs_da_args_t *args) | |||
1167 | return error; | 1014 | return error; |
1168 | } | 1015 | } |
1169 | 1016 | ||
1170 | /* | ||
1171 | * Copy out attribute entries for attr_list(), for leaf attribute lists. | ||
1172 | */ | ||
1173 | STATIC int | ||
1174 | xfs_attr_leaf_list(xfs_attr_list_context_t *context) | ||
1175 | { | ||
1176 | int error; | ||
1177 | struct xfs_buf *bp; | ||
1178 | |||
1179 | trace_xfs_attr_leaf_list(context); | ||
1180 | |||
1181 | context->cursor->blkno = 0; | ||
1182 | error = xfs_attr3_leaf_read(NULL, context->dp, 0, -1, &bp); | ||
1183 | if (error) | ||
1184 | return XFS_ERROR(error); | ||
1185 | |||
1186 | error = xfs_attr3_leaf_list_int(bp, context); | ||
1187 | xfs_trans_brelse(NULL, bp); | ||
1188 | return XFS_ERROR(error); | ||
1189 | } | ||
1190 | |||
1191 | |||
1192 | /*======================================================================== | 1017 | /*======================================================================== |
1193 | * External routines when attribute list size > XFS_LBSIZE(mp). | 1018 | * External routines when attribute list size > XFS_LBSIZE(mp). |
1194 | *========================================================================*/ | 1019 | *========================================================================*/ |
@@ -1781,143 +1606,3 @@ xfs_attr_node_get(xfs_da_args_t *args) | |||
1781 | xfs_da_state_free(state); | 1606 | xfs_da_state_free(state); |
1782 | return(retval); | 1607 | return(retval); |
1783 | } | 1608 | } |
1784 | |||
1785 | STATIC int /* error */ | ||
1786 | xfs_attr_node_list(xfs_attr_list_context_t *context) | ||
1787 | { | ||
1788 | attrlist_cursor_kern_t *cursor; | ||
1789 | xfs_attr_leafblock_t *leaf; | ||
1790 | xfs_da_intnode_t *node; | ||
1791 | struct xfs_attr3_icleaf_hdr leafhdr; | ||
1792 | struct xfs_da3_icnode_hdr nodehdr; | ||
1793 | struct xfs_da_node_entry *btree; | ||
1794 | int error, i; | ||
1795 | struct xfs_buf *bp; | ||
1796 | |||
1797 | trace_xfs_attr_node_list(context); | ||
1798 | |||
1799 | cursor = context->cursor; | ||
1800 | cursor->initted = 1; | ||
1801 | |||
1802 | /* | ||
1803 | * Do all sorts of validation on the passed-in cursor structure. | ||
1804 | * If anything is amiss, ignore the cursor and look up the hashval | ||
1805 | * starting from the btree root. | ||
1806 | */ | ||
1807 | bp = NULL; | ||
1808 | if (cursor->blkno > 0) { | ||
1809 | error = xfs_da3_node_read(NULL, context->dp, cursor->blkno, -1, | ||
1810 | &bp, XFS_ATTR_FORK); | ||
1811 | if ((error != 0) && (error != EFSCORRUPTED)) | ||
1812 | return(error); | ||
1813 | if (bp) { | ||
1814 | struct xfs_attr_leaf_entry *entries; | ||
1815 | |||
1816 | node = bp->b_addr; | ||
1817 | switch (be16_to_cpu(node->hdr.info.magic)) { | ||
1818 | case XFS_DA_NODE_MAGIC: | ||
1819 | case XFS_DA3_NODE_MAGIC: | ||
1820 | trace_xfs_attr_list_wrong_blk(context); | ||
1821 | xfs_trans_brelse(NULL, bp); | ||
1822 | bp = NULL; | ||
1823 | break; | ||
1824 | case XFS_ATTR_LEAF_MAGIC: | ||
1825 | case XFS_ATTR3_LEAF_MAGIC: | ||
1826 | leaf = bp->b_addr; | ||
1827 | xfs_attr3_leaf_hdr_from_disk(&leafhdr, leaf); | ||
1828 | entries = xfs_attr3_leaf_entryp(leaf); | ||
1829 | if (cursor->hashval > be32_to_cpu( | ||
1830 | entries[leafhdr.count - 1].hashval)) { | ||
1831 | trace_xfs_attr_list_wrong_blk(context); | ||
1832 | xfs_trans_brelse(NULL, bp); | ||
1833 | bp = NULL; | ||
1834 | } else if (cursor->hashval <= be32_to_cpu( | ||
1835 | entries[0].hashval)) { | ||
1836 | trace_xfs_attr_list_wrong_blk(context); | ||
1837 | xfs_trans_brelse(NULL, bp); | ||
1838 | bp = NULL; | ||
1839 | } | ||
1840 | break; | ||
1841 | default: | ||
1842 | trace_xfs_attr_list_wrong_blk(context); | ||
1843 | xfs_trans_brelse(NULL, bp); | ||
1844 | bp = NULL; | ||
1845 | } | ||
1846 | } | ||
1847 | } | ||
1848 | |||
1849 | /* | ||
1850 | * We did not find what we expected given the cursor's contents, | ||
1851 | * so we start from the top and work down based on the hash value. | ||
1852 | * Note that start of node block is same as start of leaf block. | ||
1853 | */ | ||
1854 | if (bp == NULL) { | ||
1855 | cursor->blkno = 0; | ||
1856 | for (;;) { | ||
1857 | __uint16_t magic; | ||
1858 | |||
1859 | error = xfs_da3_node_read(NULL, context->dp, | ||
1860 | cursor->blkno, -1, &bp, | ||
1861 | XFS_ATTR_FORK); | ||
1862 | if (error) | ||
1863 | return(error); | ||
1864 | node = bp->b_addr; | ||
1865 | magic = be16_to_cpu(node->hdr.info.magic); | ||
1866 | if (magic == XFS_ATTR_LEAF_MAGIC || | ||
1867 | magic == XFS_ATTR3_LEAF_MAGIC) | ||
1868 | break; | ||
1869 | if (magic != XFS_DA_NODE_MAGIC && | ||
1870 | magic != XFS_DA3_NODE_MAGIC) { | ||
1871 | XFS_CORRUPTION_ERROR("xfs_attr_node_list(3)", | ||
1872 | XFS_ERRLEVEL_LOW, | ||
1873 | context->dp->i_mount, | ||
1874 | node); | ||
1875 | xfs_trans_brelse(NULL, bp); | ||
1876 | return XFS_ERROR(EFSCORRUPTED); | ||
1877 | } | ||
1878 | |||
1879 | xfs_da3_node_hdr_from_disk(&nodehdr, node); | ||
1880 | btree = xfs_da3_node_tree_p(node); | ||
1881 | for (i = 0; i < nodehdr.count; btree++, i++) { | ||
1882 | if (cursor->hashval | ||
1883 | <= be32_to_cpu(btree->hashval)) { | ||
1884 | cursor->blkno = be32_to_cpu(btree->before); | ||
1885 | trace_xfs_attr_list_node_descend(context, | ||
1886 | btree); | ||
1887 | break; | ||
1888 | } | ||
1889 | } | ||
1890 | if (i == nodehdr.count) { | ||
1891 | xfs_trans_brelse(NULL, bp); | ||
1892 | return 0; | ||
1893 | } | ||
1894 | xfs_trans_brelse(NULL, bp); | ||
1895 | } | ||
1896 | } | ||
1897 | ASSERT(bp != NULL); | ||
1898 | |||
1899 | /* | ||
1900 | * Roll upward through the blocks, processing each leaf block in | ||
1901 | * order. As long as there is space in the result buffer, keep | ||
1902 | * adding the information. | ||
1903 | */ | ||
1904 | for (;;) { | ||
1905 | leaf = bp->b_addr; | ||
1906 | error = xfs_attr3_leaf_list_int(bp, context); | ||
1907 | if (error) { | ||
1908 | xfs_trans_brelse(NULL, bp); | ||
1909 | return error; | ||
1910 | } | ||
1911 | xfs_attr3_leaf_hdr_from_disk(&leafhdr, leaf); | ||
1912 | if (context->seen_enough || leafhdr.forw == 0) | ||
1913 | break; | ||
1914 | cursor->blkno = leafhdr.forw; | ||
1915 | xfs_trans_brelse(NULL, bp); | ||
1916 | error = xfs_attr3_leaf_read(NULL, context->dp, cursor->blkno, -1, | ||
1917 | &bp); | ||
1918 | if (error) | ||
1919 | return error; | ||
1920 | } | ||
1921 | xfs_trans_brelse(NULL, bp); | ||
1922 | return 0; | ||
1923 | } | ||