diff options
author | Aristeu Rozanski <aris@redhat.com> | 2012-08-23 16:53:28 -0400 |
---|---|---|
committer | Tejun Heo <tj@kernel.org> | 2012-08-24 18:55:33 -0400 |
commit | 38f38657444d15e1a8574eae80ed3de9f501737a (patch) | |
tree | b39bf533c5acb4b3ee48b6602dea9d92c2e9f72f /fs/xattr.c | |
parent | fea7a08acb13524b47711625eebea40a0ede69a0 (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.c | 166 |
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); | |||
791 | EXPORT_SYMBOL(generic_listxattr); | 791 | EXPORT_SYMBOL(generic_listxattr); |
792 | EXPORT_SYMBOL(generic_setxattr); | 792 | EXPORT_SYMBOL(generic_setxattr); |
793 | EXPORT_SYMBOL(generic_removexattr); | 793 | EXPORT_SYMBOL(generic_removexattr); |
794 | |||
795 | /* | ||
796 | * Allocate new xattr and copy in the value; but leave the name to callers. | ||
797 | */ | ||
798 | struct 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 | */ | ||
820 | int 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 | |||
844 | static 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 | } | ||
885 | out: | ||
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 | */ | ||
898 | int 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 | */ | ||
909 | int simple_xattr_remove(struct simple_xattrs *xattrs, const char *name) | ||
910 | { | ||
911 | return __simple_xattr_set(xattrs, name, NULL, 0, XATTR_REPLACE); | ||
912 | } | ||
913 | |||
914 | static 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 | */ | ||
922 | ssize_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 | |||
953 | void 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 | } | ||