aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xattr.c
diff options
context:
space:
mode:
authorAristeu Rozanski <aris@redhat.com>2012-08-23 16:53:28 -0400
committerTejun Heo <tj@kernel.org>2012-08-24 18:55:33 -0400
commit38f38657444d15e1a8574eae80ed3de9f501737a (patch)
treeb39bf533c5acb4b3ee48b6602dea9d92c2e9f72f /fs/xattr.c
parentfea7a08acb13524b47711625eebea40a0ede69a0 (diff)
xattr: extract simple_xattr code from tmpfs
Extract in-memory xattr APIs from tmpfs. Will be used by cgroup. $ size vmlinux.o text data bss dec hex filename 4658782 880729 5195032 10734543 a3cbcf vmlinux.o $ size vmlinux.o text data bss dec hex filename 4658957 880729 5195032 10734718 a3cc7e vmlinux.o v7: - checkpatch warnings fixed - Implement the changes requested by Hugh Dickins: - make simple_xattrs_init and simple_xattrs_free inline - get rid of locking and list reinitialization in simple_xattrs_free, they're not needed v6: - no changes v5: - no changes v4: - move simple_xattrs_free() to fs/xattr.c v3: - in kmem_xattrs_free(), reinitialize the list - use simple_xattr_* prefix - introduce simple_xattr_add() to prevent direct list usage Original-patch-by: Li Zefan <lizefan@huawei.com> Cc: Li Zefan <lizefan@huawei.com> Cc: Hillf Danton <dhillf@gmail.com> Cc: Lennart Poettering <lpoetter@redhat.com> Acked-by: Hugh Dickins <hughd@google.com> Signed-off-by: Li Zefan <lizefan@huawei.com> Signed-off-by: Aristeu Rozanski <aris@redhat.com> Signed-off-by: Tejun Heo <tj@kernel.org>
Diffstat (limited to 'fs/xattr.c')
-rw-r--r--fs/xattr.c166
1 files changed, 166 insertions, 0 deletions
diff --git a/fs/xattr.c b/fs/xattr.c
index 4d45b7189e7e..e17e773517ef 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -791,3 +791,169 @@ EXPORT_SYMBOL(generic_getxattr);
791EXPORT_SYMBOL(generic_listxattr); 791EXPORT_SYMBOL(generic_listxattr);
792EXPORT_SYMBOL(generic_setxattr); 792EXPORT_SYMBOL(generic_setxattr);
793EXPORT_SYMBOL(generic_removexattr); 793EXPORT_SYMBOL(generic_removexattr);
794
795/*
796 * Allocate new xattr and copy in the value; but leave the name to callers.
797 */
798struct simple_xattr *simple_xattr_alloc(const void *value, size_t size)
799{
800 struct simple_xattr *new_xattr;
801 size_t len;
802
803 /* wrap around? */
804 len = sizeof(*new_xattr) + size;
805 if (len <= sizeof(*new_xattr))
806 return NULL;
807
808 new_xattr = kmalloc(len, GFP_KERNEL);
809 if (!new_xattr)
810 return NULL;
811
812 new_xattr->size = size;
813 memcpy(new_xattr->value, value, size);
814 return new_xattr;
815}
816
817/*
818 * xattr GET operation for in-memory/pseudo filesystems
819 */
820int simple_xattr_get(struct simple_xattrs *xattrs, const char *name,
821 void *buffer, size_t size)
822{
823 struct simple_xattr *xattr;
824 int ret = -ENODATA;
825
826 spin_lock(&xattrs->lock);
827 list_for_each_entry(xattr, &xattrs->head, list) {
828 if (strcmp(name, xattr->name))
829 continue;
830
831 ret = xattr->size;
832 if (buffer) {
833 if (size < xattr->size)
834 ret = -ERANGE;
835 else
836 memcpy(buffer, xattr->value, xattr->size);
837 }
838 break;
839 }
840 spin_unlock(&xattrs->lock);
841 return ret;
842}
843
844static int __simple_xattr_set(struct simple_xattrs *xattrs, const char *name,
845 const void *value, size_t size, int flags)
846{
847 struct simple_xattr *xattr;
848 struct simple_xattr *new_xattr = NULL;
849 int err = 0;
850
851 /* value == NULL means remove */
852 if (value) {
853 new_xattr = simple_xattr_alloc(value, size);
854 if (!new_xattr)
855 return -ENOMEM;
856
857 new_xattr->name = kstrdup(name, GFP_KERNEL);
858 if (!new_xattr->name) {
859 kfree(new_xattr);
860 return -ENOMEM;
861 }
862 }
863
864 spin_lock(&xattrs->lock);
865 list_for_each_entry(xattr, &xattrs->head, list) {
866 if (!strcmp(name, xattr->name)) {
867 if (flags & XATTR_CREATE) {
868 xattr = new_xattr;
869 err = -EEXIST;
870 } else if (new_xattr) {
871 list_replace(&xattr->list, &new_xattr->list);
872 } else {
873 list_del(&xattr->list);
874 }
875 goto out;
876 }
877 }
878 if (flags & XATTR_REPLACE) {
879 xattr = new_xattr;
880 err = -ENODATA;
881 } else {
882 list_add(&new_xattr->list, &xattrs->head);
883 xattr = NULL;
884 }
885out:
886 spin_unlock(&xattrs->lock);
887 if (xattr) {
888 kfree(xattr->name);
889 kfree(xattr);
890 }
891 return err;
892
893}
894
895/*
896 * xattr SET operation for in-memory/pseudo filesystems
897 */
898int simple_xattr_set(struct simple_xattrs *xattrs, const char *name,
899 const void *value, size_t size, int flags)
900{
901 if (size == 0)
902 value = ""; /* empty EA, do not remove */
903 return __simple_xattr_set(xattrs, name, value, size, flags);
904}
905
906/*
907 * xattr REMOVE operation for in-memory/pseudo filesystems
908 */
909int simple_xattr_remove(struct simple_xattrs *xattrs, const char *name)
910{
911 return __simple_xattr_set(xattrs, name, NULL, 0, XATTR_REPLACE);
912}
913
914static bool xattr_is_trusted(const char *name)
915{
916 return !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN);
917}
918
919/*
920 * xattr LIST operation for in-memory/pseudo filesystems
921 */
922ssize_t simple_xattr_list(struct simple_xattrs *xattrs, char *buffer,
923 size_t size)
924{
925 bool trusted = capable(CAP_SYS_ADMIN);
926 struct simple_xattr *xattr;
927 size_t used = 0;
928
929 spin_lock(&xattrs->lock);
930 list_for_each_entry(xattr, &xattrs->head, list) {
931 size_t len;
932
933 /* skip "trusted." attributes for unprivileged callers */
934 if (!trusted && xattr_is_trusted(xattr->name))
935 continue;
936
937 len = strlen(xattr->name) + 1;
938 used += len;
939 if (buffer) {
940 if (size < used) {
941 used = -ERANGE;
942 break;
943 }
944 memcpy(buffer, xattr->name, len);
945 buffer += len;
946 }
947 }
948 spin_unlock(&xattrs->lock);
949
950 return used;
951}
952
953void simple_xattr_list_add(struct simple_xattrs *xattrs,
954 struct simple_xattr *new_xattr)
955{
956 spin_lock(&xattrs->lock);
957 list_add(&new_xattr->list, &xattrs->head);
958 spin_unlock(&xattrs->lock);
959}