summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-10-10 20:11:50 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-10-10 20:11:50 -0400
commit97d2116708ca0fd6ad8b00811ee4349b7e19e96f (patch)
tree81f73fc1a6daee60737b591cf1be73cc4f79de37
parent30066ce675d3af350bc5a53858991c0b518dda00 (diff)
parentfd50ecaddf8372a1d96e0daeaac0f93cf04e4d42 (diff)
Merge branch 'work.xattr' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs xattr updates from Al Viro: "xattr stuff from Andreas This completes the switch to xattr_handler ->get()/->set() from ->getxattr/->setxattr/->removexattr" * 'work.xattr' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: vfs: Remove {get,set,remove}xattr inode operations xattr: Stop calling {get,set,remove}xattr inode operations vfs: Check for the IOP_XATTR flag in listxattr xattr: Add __vfs_{get,set,remove}xattr helpers libfs: Use IOP_XATTR flag for empty directory handling vfs: Use IOP_XATTR flag for bad-inode handling vfs: Add IOP_XATTR inode operations flag vfs: Move xattr_resolve_name to the front of fs/xattr.c ecryptfs: Switch to generic xattr handlers sockfs: Get rid of getxattr iop sockfs: getxattr: Fail with -EOPNOTSUPP for invalid attribute names kernfs: Switch to generic xattr handlers hfs: Switch to generic xattr handlers jffs2: Remove jffs2_{get,set,remove}xattr macros xattr: Remove unnecessary NULL attribute name check
-rw-r--r--Documentation/filesystems/Locking24
-rw-r--r--Documentation/filesystems/vfs.txt45
-rw-r--r--drivers/staging/lustre/lustre/llite/file.c3
-rw-r--r--drivers/staging/lustre/lustre/llite/namei.c6
-rw-r--r--drivers/staging/lustre/lustre/llite/symlink.c3
-rw-r--r--fs/9p/vfs_inode_dotl.c9
-rw-r--r--fs/bad_inode.c21
-rw-r--r--fs/btrfs/inode.c12
-rw-r--r--fs/cachefiles/bind.c4
-rw-r--r--fs/cachefiles/namei.c4
-rw-r--r--fs/ceph/dir.c3
-rw-r--r--fs/ceph/inode.c6
-rw-r--r--fs/cifs/cifsfs.c9
-rw-r--r--fs/ecryptfs/ecryptfs_kernel.h2
-rw-r--r--fs/ecryptfs/inode.c67
-rw-r--r--fs/ecryptfs/main.c1
-rw-r--r--fs/ecryptfs/mmap.c13
-rw-r--r--fs/ext2/file.c3
-rw-r--r--fs/ext2/namei.c6
-rw-r--r--fs/ext2/symlink.c6
-rw-r--r--fs/ext4/file.c3
-rw-r--r--fs/ext4/namei.c6
-rw-r--r--fs/ext4/symlink.c9
-rw-r--r--fs/f2fs/file.c3
-rw-r--r--fs/f2fs/namei.c12
-rw-r--r--fs/fuse/dir.c9
-rw-r--r--fs/gfs2/inode.c9
-rw-r--r--fs/hfs/attr.c83
-rw-r--r--fs/hfs/hfs_fs.h6
-rw-r--r--fs/hfs/inode.c5
-rw-r--r--fs/hfs/super.c1
-rw-r--r--fs/hfsplus/dir.c3
-rw-r--r--fs/hfsplus/inode.c3
-rw-r--r--fs/inode.c2
-rw-r--r--fs/jffs2/dir.c3
-rw-r--r--fs/jffs2/file.c3
-rw-r--r--fs/jffs2/symlink.c3
-rw-r--r--fs/jffs2/xattr.h6
-rw-r--r--fs/jfs/file.c3
-rw-r--r--fs/jfs/namei.c3
-rw-r--r--fs/jfs/symlink.c6
-rw-r--r--fs/kernfs/dir.c3
-rw-r--r--fs/kernfs/inode.c155
-rw-r--r--fs/kernfs/kernfs-internal.h7
-rw-r--r--fs/kernfs/mount.c1
-rw-r--r--fs/kernfs/symlink.c3
-rw-r--r--fs/libfs.c29
-rw-r--r--fs/nfs/nfs3proc.c6
-rw-r--r--fs/nfs/nfs4proc.c6
-rw-r--r--fs/ocfs2/file.c3
-rw-r--r--fs/ocfs2/namei.c3
-rw-r--r--fs/ocfs2/symlink.c3
-rw-r--r--fs/orangefs/inode.c3
-rw-r--r--fs/orangefs/namei.c3
-rw-r--r--fs/orangefs/symlink.c1
-rw-r--r--fs/orangefs/xattr.c3
-rw-r--r--fs/overlayfs/copy_up.c4
-rw-r--r--fs/overlayfs/dir.c3
-rw-r--r--fs/overlayfs/inode.c6
-rw-r--r--fs/overlayfs/super.c4
-rw-r--r--fs/reiserfs/file.c3
-rw-r--r--fs/reiserfs/namei.c9
-rw-r--r--fs/squashfs/inode.c1
-rw-r--r--fs/squashfs/namei.c1
-rw-r--r--fs/squashfs/symlink.c1
-rw-r--r--fs/squashfs/xattr.h1
-rw-r--r--fs/ubifs/dir.c3
-rw-r--r--fs/ubifs/file.c6
-rw-r--r--fs/xattr.c250
-rw-r--r--fs/xfs/xfs_iops.c15
-rw-r--r--include/linux/fs.h23
-rw-r--r--include/linux/xattr.h7
-rw-r--r--mm/shmem.c15
-rw-r--r--net/socket.c61
-rw-r--r--security/commoncap.c25
-rw-r--r--security/integrity/evm/evm_crypto.c7
-rw-r--r--security/integrity/evm/evm_main.c4
-rw-r--r--security/integrity/ima/ima_appraise.c21
-rw-r--r--security/selinux/hooks.c19
-rw-r--r--security/smack/smack_lsm.c12
80 files changed, 471 insertions, 687 deletions
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index d30fb2cb5066..f56b39ee2e54 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -61,10 +61,7 @@ prototypes:
61 int (*get_acl)(struct inode *, int); 61 int (*get_acl)(struct inode *, int);
62 int (*setattr) (struct dentry *, struct iattr *); 62 int (*setattr) (struct dentry *, struct iattr *);
63 int (*getattr) (struct vfsmount *, struct dentry *, struct kstat *); 63 int (*getattr) (struct vfsmount *, struct dentry *, struct kstat *);
64 int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
65 ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
66 ssize_t (*listxattr) (struct dentry *, char *, size_t); 64 ssize_t (*listxattr) (struct dentry *, char *, size_t);
67 int (*removexattr) (struct dentry *, const char *);
68 int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, u64 len); 65 int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, u64 len);
69 void (*update_time)(struct inode *, struct timespec *, int); 66 void (*update_time)(struct inode *, struct timespec *, int);
70 int (*atomic_open)(struct inode *, struct dentry *, 67 int (*atomic_open)(struct inode *, struct dentry *,
@@ -91,15 +88,13 @@ setattr: yes
91permission: no (may not block if called in rcu-walk mode) 88permission: no (may not block if called in rcu-walk mode)
92get_acl: no 89get_acl: no
93getattr: no 90getattr: no
94setxattr: yes
95getxattr: no
96listxattr: no 91listxattr: no
97removexattr: yes
98fiemap: no 92fiemap: no
99update_time: no 93update_time: no
100atomic_open: yes 94atomic_open: yes
101tmpfile: no 95tmpfile: no
102 96
97
103 Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on 98 Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on
104victim. 99victim.
105 cross-directory ->rename() and rename2() has (per-superblock) 100 cross-directory ->rename() and rename2() has (per-superblock)
@@ -108,6 +103,23 @@ victim.
108See Documentation/filesystems/directory-locking for more detailed discussion 103See Documentation/filesystems/directory-locking for more detailed discussion
109of the locking scheme for directory operations. 104of the locking scheme for directory operations.
110 105
106----------------------- xattr_handler operations -----------------------
107prototypes:
108 bool (*list)(struct dentry *dentry);
109 int (*get)(const struct xattr_handler *handler, struct dentry *dentry,
110 struct inode *inode, const char *name, void *buffer,
111 size_t size);
112 int (*set)(const struct xattr_handler *handler, struct dentry *dentry,
113 struct inode *inode, const char *name, const void *buffer,
114 size_t size, int flags);
115
116locking rules:
117 all may block
118 i_mutex(inode)
119list: no
120get: no
121set: yes
122
111--------------------------- super_operations --------------------------- 123--------------------------- super_operations ---------------------------
112prototypes: 124prototypes:
113 struct inode *(*alloc_inode)(struct super_block *sb); 125 struct inode *(*alloc_inode)(struct super_block *sb);
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index cbec006e10e4..43ef86c266ec 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -323,6 +323,35 @@ Whoever sets up the inode is responsible for filling in the "i_op" field. This
323is a pointer to a "struct inode_operations" which describes the methods that 323is a pointer to a "struct inode_operations" which describes the methods that
324can be performed on individual inodes. 324can be performed on individual inodes.
325 325
326struct xattr_handlers
327---------------------
328
329On filesystems that support extended attributes (xattrs), the s_xattr
330superblock field points to a NULL-terminated array of xattr handlers. Extended
331attributes are name:value pairs.
332
333 name: Indicates that the handler matches attributes with the specified name
334 (such as "system.posix_acl_access"); the prefix field must be NULL.
335
336 prefix: Indicates that the handler matches all attributes with the specified
337 name prefix (such as "user."); the name field must be NULL.
338
339 list: Determine if attributes matching this xattr handler should be listed
340 for a particular dentry. Used by some listxattr implementations like
341 generic_listxattr.
342
343 get: Called by the VFS to get the value of a particular extended attribute.
344 This method is called by the getxattr(2) system call.
345
346 set: Called by the VFS to set the value of a particular extended attribute.
347 When the new value is NULL, called to remove a particular extended
348 attribute. This method is called by the the setxattr(2) and
349 removexattr(2) system calls.
350
351When none of the xattr handlers of a filesystem match the specified attribute
352name or when a filesystem doesn't support extended attributes, the various
353*xattr(2) system calls return -EOPNOTSUPP.
354
326 355
327The Inode Object 356The Inode Object
328================ 357================
@@ -356,10 +385,7 @@ struct inode_operations {
356 int (*get_acl)(struct inode *, int); 385 int (*get_acl)(struct inode *, int);
357 int (*setattr) (struct dentry *, struct iattr *); 386 int (*setattr) (struct dentry *, struct iattr *);
358 int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *); 387 int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
359 int (*setxattr) (struct dentry *, const char *,const void *,size_t,int);
360 ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t);
361 ssize_t (*listxattr) (struct dentry *, char *, size_t); 388 ssize_t (*listxattr) (struct dentry *, char *, size_t);
362 int (*removexattr) (struct dentry *, const char *);
363 void (*update_time)(struct inode *, struct timespec *, int); 389 void (*update_time)(struct inode *, struct timespec *, int);
364 int (*atomic_open)(struct inode *, struct dentry *, struct file *, 390 int (*atomic_open)(struct inode *, struct dentry *, struct file *,
365 unsigned open_flag, umode_t create_mode, int *opened); 391 unsigned open_flag, umode_t create_mode, int *opened);
@@ -463,19 +489,8 @@ otherwise noted.
463 getattr: called by the VFS to get attributes of a file. This method 489 getattr: called by the VFS to get attributes of a file. This method
464 is called by stat(2) and related system calls. 490 is called by stat(2) and related system calls.
465 491
466 setxattr: called by the VFS to set an extended attribute for a file.
467 Extended attribute is a name:value pair associated with an
468 inode. This method is called by setxattr(2) system call.
469
470 getxattr: called by the VFS to retrieve the value of an extended
471 attribute name. This method is called by getxattr(2) function
472 call.
473
474 listxattr: called by the VFS to list all extended attributes for a 492 listxattr: called by the VFS to list all extended attributes for a
475 given file. This method is called by listxattr(2) system call. 493 given file. This method is called by the listxattr(2) system call.
476
477 removexattr: called by the VFS to remove an extended attribute from
478 a file. This method is called by removexattr(2) system call.
479 494
480 update_time: called by the VFS to update a specific time or the i_version of 495 update_time: called by the VFS to update a specific time or the i_version of
481 an inode. If this is not defined the VFS will update the inode itself 496 an inode. If this is not defined the VFS will update the inode itself
diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c
index 65c945d8bae2..e1d784bae064 100644
--- a/drivers/staging/lustre/lustre/llite/file.c
+++ b/drivers/staging/lustre/lustre/llite/file.c
@@ -3268,10 +3268,7 @@ const struct inode_operations ll_file_inode_operations = {
3268 .setattr = ll_setattr, 3268 .setattr = ll_setattr,
3269 .getattr = ll_getattr, 3269 .getattr = ll_getattr,
3270 .permission = ll_inode_permission, 3270 .permission = ll_inode_permission,
3271 .setxattr = generic_setxattr,
3272 .getxattr = generic_getxattr,
3273 .listxattr = ll_listxattr, 3271 .listxattr = ll_listxattr,
3274 .removexattr = generic_removexattr,
3275 .fiemap = ll_fiemap, 3272 .fiemap = ll_fiemap,
3276 .get_acl = ll_get_acl, 3273 .get_acl = ll_get_acl,
3277}; 3274};
diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c
index dfa36d34c645..ff3ce7486b29 100644
--- a/drivers/staging/lustre/lustre/llite/namei.c
+++ b/drivers/staging/lustre/lustre/llite/namei.c
@@ -1152,10 +1152,7 @@ const struct inode_operations ll_dir_inode_operations = {
1152 .setattr = ll_setattr, 1152 .setattr = ll_setattr,
1153 .getattr = ll_getattr, 1153 .getattr = ll_getattr,
1154 .permission = ll_inode_permission, 1154 .permission = ll_inode_permission,
1155 .setxattr = generic_setxattr,
1156 .getxattr = generic_getxattr,
1157 .listxattr = ll_listxattr, 1155 .listxattr = ll_listxattr,
1158 .removexattr = generic_removexattr,
1159 .get_acl = ll_get_acl, 1156 .get_acl = ll_get_acl,
1160}; 1157};
1161 1158
@@ -1163,9 +1160,6 @@ const struct inode_operations ll_special_inode_operations = {
1163 .setattr = ll_setattr, 1160 .setattr = ll_setattr,
1164 .getattr = ll_getattr, 1161 .getattr = ll_getattr,
1165 .permission = ll_inode_permission, 1162 .permission = ll_inode_permission,
1166 .setxattr = generic_setxattr,
1167 .getxattr = generic_getxattr,
1168 .listxattr = ll_listxattr, 1163 .listxattr = ll_listxattr,
1169 .removexattr = generic_removexattr,
1170 .get_acl = ll_get_acl, 1164 .get_acl = ll_get_acl,
1171}; 1165};
diff --git a/drivers/staging/lustre/lustre/llite/symlink.c b/drivers/staging/lustre/lustre/llite/symlink.c
index f8bc7ed59646..82c7c48aa619 100644
--- a/drivers/staging/lustre/lustre/llite/symlink.c
+++ b/drivers/staging/lustre/lustre/llite/symlink.c
@@ -154,8 +154,5 @@ const struct inode_operations ll_fast_symlink_inode_operations = {
154 .get_link = ll_get_link, 154 .get_link = ll_get_link,
155 .getattr = ll_getattr, 155 .getattr = ll_getattr,
156 .permission = ll_inode_permission, 156 .permission = ll_inode_permission,
157 .setxattr = generic_setxattr,
158 .getxattr = generic_getxattr,
159 .listxattr = ll_listxattr, 157 .listxattr = ll_listxattr,
160 .removexattr = generic_removexattr,
161}; 158};
diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c
index 0e6ad3019711..afaa4b6de801 100644
--- a/fs/9p/vfs_inode_dotl.c
+++ b/fs/9p/vfs_inode_dotl.c
@@ -967,9 +967,6 @@ const struct inode_operations v9fs_dir_inode_operations_dotl = {
967 .rename = v9fs_vfs_rename, 967 .rename = v9fs_vfs_rename,
968 .getattr = v9fs_vfs_getattr_dotl, 968 .getattr = v9fs_vfs_getattr_dotl,
969 .setattr = v9fs_vfs_setattr_dotl, 969 .setattr = v9fs_vfs_setattr_dotl,
970 .setxattr = generic_setxattr,
971 .getxattr = generic_getxattr,
972 .removexattr = generic_removexattr,
973 .listxattr = v9fs_listxattr, 970 .listxattr = v9fs_listxattr,
974 .get_acl = v9fs_iop_get_acl, 971 .get_acl = v9fs_iop_get_acl,
975}; 972};
@@ -977,9 +974,6 @@ const struct inode_operations v9fs_dir_inode_operations_dotl = {
977const struct inode_operations v9fs_file_inode_operations_dotl = { 974const struct inode_operations v9fs_file_inode_operations_dotl = {
978 .getattr = v9fs_vfs_getattr_dotl, 975 .getattr = v9fs_vfs_getattr_dotl,
979 .setattr = v9fs_vfs_setattr_dotl, 976 .setattr = v9fs_vfs_setattr_dotl,
980 .setxattr = generic_setxattr,
981 .getxattr = generic_getxattr,
982 .removexattr = generic_removexattr,
983 .listxattr = v9fs_listxattr, 977 .listxattr = v9fs_listxattr,
984 .get_acl = v9fs_iop_get_acl, 978 .get_acl = v9fs_iop_get_acl,
985}; 979};
@@ -989,8 +983,5 @@ const struct inode_operations v9fs_symlink_inode_operations_dotl = {
989 .get_link = v9fs_vfs_get_link_dotl, 983 .get_link = v9fs_vfs_get_link_dotl,
990 .getattr = v9fs_vfs_getattr_dotl, 984 .getattr = v9fs_vfs_getattr_dotl,
991 .setattr = v9fs_vfs_setattr_dotl, 985 .setattr = v9fs_vfs_setattr_dotl,
992 .setxattr = generic_setxattr,
993 .getxattr = generic_getxattr,
994 .removexattr = generic_removexattr,
995 .listxattr = v9fs_listxattr, 986 .listxattr = v9fs_listxattr,
996}; 987};
diff --git a/fs/bad_inode.c b/fs/bad_inode.c
index 3ba385eaa26e..7bb153c33459 100644
--- a/fs/bad_inode.c
+++ b/fs/bad_inode.c
@@ -100,29 +100,12 @@ static int bad_inode_setattr(struct dentry *direntry, struct iattr *attrs)
100 return -EIO; 100 return -EIO;
101} 101}
102 102
103static int bad_inode_setxattr(struct dentry *dentry, struct inode *inode,
104 const char *name, const void *value, size_t size, int flags)
105{
106 return -EIO;
107}
108
109static ssize_t bad_inode_getxattr(struct dentry *dentry, struct inode *inode,
110 const char *name, void *buffer, size_t size)
111{
112 return -EIO;
113}
114
115static ssize_t bad_inode_listxattr(struct dentry *dentry, char *buffer, 103static ssize_t bad_inode_listxattr(struct dentry *dentry, char *buffer,
116 size_t buffer_size) 104 size_t buffer_size)
117{ 105{
118 return -EIO; 106 return -EIO;
119} 107}
120 108
121static int bad_inode_removexattr(struct dentry *dentry, const char *name)
122{
123 return -EIO;
124}
125
126static const struct inode_operations bad_inode_ops = 109static const struct inode_operations bad_inode_ops =
127{ 110{
128 .create = bad_inode_create, 111 .create = bad_inode_create,
@@ -142,10 +125,7 @@ static const struct inode_operations bad_inode_ops =
142 .permission = bad_inode_permission, 125 .permission = bad_inode_permission,
143 .getattr = bad_inode_getattr, 126 .getattr = bad_inode_getattr,
144 .setattr = bad_inode_setattr, 127 .setattr = bad_inode_setattr,
145 .setxattr = bad_inode_setxattr,
146 .getxattr = bad_inode_getxattr,
147 .listxattr = bad_inode_listxattr, 128 .listxattr = bad_inode_listxattr,
148 .removexattr = bad_inode_removexattr,
149}; 129};
150 130
151 131
@@ -175,6 +155,7 @@ void make_bad_inode(struct inode *inode)
175 inode->i_atime = inode->i_mtime = inode->i_ctime = 155 inode->i_atime = inode->i_mtime = inode->i_ctime =
176 current_fs_time(inode->i_sb); 156 current_fs_time(inode->i_sb);
177 inode->i_op = &bad_inode_ops; 157 inode->i_op = &bad_inode_ops;
158 inode->i_opflags &= ~IOP_XATTR;
178 inode->i_fop = &bad_file_ops; 159 inode->i_fop = &bad_file_ops;
179} 160}
180EXPORT_SYMBOL(make_bad_inode); 161EXPORT_SYMBOL(make_bad_inode);
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index a0d3016f6c26..994fe5af160b 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -10556,10 +10556,7 @@ static const struct inode_operations btrfs_dir_inode_operations = {
10556 .symlink = btrfs_symlink, 10556 .symlink = btrfs_symlink,
10557 .setattr = btrfs_setattr, 10557 .setattr = btrfs_setattr,
10558 .mknod = btrfs_mknod, 10558 .mknod = btrfs_mknod,
10559 .setxattr = generic_setxattr,
10560 .getxattr = generic_getxattr,
10561 .listxattr = btrfs_listxattr, 10559 .listxattr = btrfs_listxattr,
10562 .removexattr = generic_removexattr,
10563 .permission = btrfs_permission, 10560 .permission = btrfs_permission,
10564 .get_acl = btrfs_get_acl, 10561 .get_acl = btrfs_get_acl,
10565 .set_acl = btrfs_set_acl, 10562 .set_acl = btrfs_set_acl,
@@ -10633,10 +10630,7 @@ static const struct address_space_operations btrfs_symlink_aops = {
10633static const struct inode_operations btrfs_file_inode_operations = { 10630static const struct inode_operations btrfs_file_inode_operations = {
10634 .getattr = btrfs_getattr, 10631 .getattr = btrfs_getattr,
10635 .setattr = btrfs_setattr, 10632 .setattr = btrfs_setattr,
10636 .setxattr = generic_setxattr,
10637 .getxattr = generic_getxattr,
10638 .listxattr = btrfs_listxattr, 10633 .listxattr = btrfs_listxattr,
10639 .removexattr = generic_removexattr,
10640 .permission = btrfs_permission, 10634 .permission = btrfs_permission,
10641 .fiemap = btrfs_fiemap, 10635 .fiemap = btrfs_fiemap,
10642 .get_acl = btrfs_get_acl, 10636 .get_acl = btrfs_get_acl,
@@ -10647,10 +10641,7 @@ static const struct inode_operations btrfs_special_inode_operations = {
10647 .getattr = btrfs_getattr, 10641 .getattr = btrfs_getattr,
10648 .setattr = btrfs_setattr, 10642 .setattr = btrfs_setattr,
10649 .permission = btrfs_permission, 10643 .permission = btrfs_permission,
10650 .setxattr = generic_setxattr,
10651 .getxattr = generic_getxattr,
10652 .listxattr = btrfs_listxattr, 10644 .listxattr = btrfs_listxattr,
10653 .removexattr = generic_removexattr,
10654 .get_acl = btrfs_get_acl, 10645 .get_acl = btrfs_get_acl,
10655 .set_acl = btrfs_set_acl, 10646 .set_acl = btrfs_set_acl,
10656 .update_time = btrfs_update_time, 10647 .update_time = btrfs_update_time,
@@ -10661,10 +10652,7 @@ static const struct inode_operations btrfs_symlink_inode_operations = {
10661 .getattr = btrfs_getattr, 10652 .getattr = btrfs_getattr,
10662 .setattr = btrfs_setattr, 10653 .setattr = btrfs_setattr,
10663 .permission = btrfs_permission, 10654 .permission = btrfs_permission,
10664 .setxattr = generic_setxattr,
10665 .getxattr = generic_getxattr,
10666 .listxattr = btrfs_listxattr, 10655 .listxattr = btrfs_listxattr,
10667 .removexattr = generic_removexattr,
10668 .update_time = btrfs_update_time, 10656 .update_time = btrfs_update_time,
10669}; 10657};
10670 10658
diff --git a/fs/cachefiles/bind.c b/fs/cachefiles/bind.c
index 6af790fc3df8..3ff867f87d73 100644
--- a/fs/cachefiles/bind.c
+++ b/fs/cachefiles/bind.c
@@ -20,6 +20,7 @@
20#include <linux/mount.h> 20#include <linux/mount.h>
21#include <linux/statfs.h> 21#include <linux/statfs.h>
22#include <linux/ctype.h> 22#include <linux/ctype.h>
23#include <linux/xattr.h>
23#include "internal.h" 24#include "internal.h"
24 25
25static int cachefiles_daemon_add_cache(struct cachefiles_cache *caches); 26static int cachefiles_daemon_add_cache(struct cachefiles_cache *caches);
@@ -126,8 +127,7 @@ static int cachefiles_daemon_add_cache(struct cachefiles_cache *cache)
126 if (d_is_negative(root) || 127 if (d_is_negative(root) ||
127 !d_backing_inode(root)->i_op->lookup || 128 !d_backing_inode(root)->i_op->lookup ||
128 !d_backing_inode(root)->i_op->mkdir || 129 !d_backing_inode(root)->i_op->mkdir ||
129 !d_backing_inode(root)->i_op->setxattr || 130 !(d_backing_inode(root)->i_opflags & IOP_XATTR) ||
130 !d_backing_inode(root)->i_op->getxattr ||
131 !root->d_sb->s_op->statfs || 131 !root->d_sb->s_op->statfs ||
132 !root->d_sb->s_op->sync_fs) 132 !root->d_sb->s_op->sync_fs)
133 goto error_unsupported; 133 goto error_unsupported;
diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c
index c6ee4b5fb7e6..339c910da916 100644
--- a/fs/cachefiles/namei.c
+++ b/fs/cachefiles/namei.c
@@ -20,6 +20,7 @@
20#include <linux/namei.h> 20#include <linux/namei.h>
21#include <linux/security.h> 21#include <linux/security.h>
22#include <linux/slab.h> 22#include <linux/slab.h>
23#include <linux/xattr.h>
23#include "internal.h" 24#include "internal.h"
24 25
25#define CACHEFILES_KEYBUF_SIZE 512 26#define CACHEFILES_KEYBUF_SIZE 512
@@ -799,8 +800,7 @@ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache,
799 } 800 }
800 801
801 ret = -EPERM; 802 ret = -EPERM;
802 if (!d_backing_inode(subdir)->i_op->setxattr || 803 if (!(d_backing_inode(subdir)->i_opflags & IOP_XATTR) ||
803 !d_backing_inode(subdir)->i_op->getxattr ||
804 !d_backing_inode(subdir)->i_op->lookup || 804 !d_backing_inode(subdir)->i_op->lookup ||
805 !d_backing_inode(subdir)->i_op->mkdir || 805 !d_backing_inode(subdir)->i_op->mkdir ||
806 !d_backing_inode(subdir)->i_op->create || 806 !d_backing_inode(subdir)->i_op->create ||
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
index df4b3e6fa563..e33bd0933396 100644
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -1486,10 +1486,7 @@ const struct inode_operations ceph_dir_iops = {
1486 .permission = ceph_permission, 1486 .permission = ceph_permission,
1487 .getattr = ceph_getattr, 1487 .getattr = ceph_getattr,
1488 .setattr = ceph_setattr, 1488 .setattr = ceph_setattr,
1489 .setxattr = generic_setxattr,
1490 .getxattr = generic_getxattr,
1491 .listxattr = ceph_listxattr, 1489 .listxattr = ceph_listxattr,
1492 .removexattr = generic_removexattr,
1493 .get_acl = ceph_get_acl, 1490 .get_acl = ceph_get_acl,
1494 .set_acl = ceph_set_acl, 1491 .set_acl = ceph_set_acl,
1495 .mknod = ceph_mknod, 1492 .mknod = ceph_mknod,
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
index 082e82dcbaa4..da00b11d4a7a 100644
--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c
@@ -94,10 +94,7 @@ const struct inode_operations ceph_file_iops = {
94 .permission = ceph_permission, 94 .permission = ceph_permission,
95 .setattr = ceph_setattr, 95 .setattr = ceph_setattr,
96 .getattr = ceph_getattr, 96 .getattr = ceph_getattr,
97 .setxattr = generic_setxattr,
98 .getxattr = generic_getxattr,
99 .listxattr = ceph_listxattr, 97 .listxattr = ceph_listxattr,
100 .removexattr = generic_removexattr,
101 .get_acl = ceph_get_acl, 98 .get_acl = ceph_get_acl,
102 .set_acl = ceph_set_acl, 99 .set_acl = ceph_set_acl,
103}; 100};
@@ -1885,10 +1882,7 @@ static const struct inode_operations ceph_symlink_iops = {
1885 .get_link = simple_get_link, 1882 .get_link = simple_get_link,
1886 .setattr = ceph_setattr, 1883 .setattr = ceph_setattr,
1887 .getattr = ceph_getattr, 1884 .getattr = ceph_getattr,
1888 .setxattr = generic_setxattr,
1889 .getxattr = generic_getxattr,
1890 .listxattr = ceph_listxattr, 1885 .listxattr = ceph_listxattr,
1891 .removexattr = generic_removexattr,
1892}; 1886};
1893 1887
1894int __ceph_setattr(struct inode *inode, struct iattr *attr) 1888int __ceph_setattr(struct inode *inode, struct iattr *attr)
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 14ae4b8e1a3c..34aac1c73ee1 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -901,30 +901,21 @@ const struct inode_operations cifs_dir_inode_ops = {
901 .setattr = cifs_setattr, 901 .setattr = cifs_setattr,
902 .symlink = cifs_symlink, 902 .symlink = cifs_symlink,
903 .mknod = cifs_mknod, 903 .mknod = cifs_mknod,
904 .setxattr = generic_setxattr,
905 .getxattr = generic_getxattr,
906 .listxattr = cifs_listxattr, 904 .listxattr = cifs_listxattr,
907 .removexattr = generic_removexattr,
908}; 905};
909 906
910const struct inode_operations cifs_file_inode_ops = { 907const struct inode_operations cifs_file_inode_ops = {
911 .setattr = cifs_setattr, 908 .setattr = cifs_setattr,
912 .getattr = cifs_getattr, 909 .getattr = cifs_getattr,
913 .permission = cifs_permission, 910 .permission = cifs_permission,
914 .setxattr = generic_setxattr,
915 .getxattr = generic_getxattr,
916 .listxattr = cifs_listxattr, 911 .listxattr = cifs_listxattr,
917 .removexattr = generic_removexattr,
918}; 912};
919 913
920const struct inode_operations cifs_symlink_inode_ops = { 914const struct inode_operations cifs_symlink_inode_ops = {
921 .readlink = generic_readlink, 915 .readlink = generic_readlink,
922 .get_link = cifs_get_link, 916 .get_link = cifs_get_link,
923 .permission = cifs_permission, 917 .permission = cifs_permission,
924 .setxattr = generic_setxattr,
925 .getxattr = generic_getxattr,
926 .listxattr = cifs_listxattr, 918 .listxattr = cifs_listxattr,
927 .removexattr = generic_removexattr,
928}; 919};
929 920
930static int cifs_clone_file_range(struct file *src_file, loff_t off, 921static int cifs_clone_file_range(struct file *src_file, loff_t off,
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index 4ba1547bb9ad..599a29237cfe 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -715,4 +715,6 @@ int ecryptfs_set_f_namelen(long *namelen, long lower_namelen,
715int ecryptfs_derive_iv(char *iv, struct ecryptfs_crypt_stat *crypt_stat, 715int ecryptfs_derive_iv(char *iv, struct ecryptfs_crypt_stat *crypt_stat,
716 loff_t offset); 716 loff_t offset);
717 717
718extern const struct xattr_handler *ecryptfs_xattr_handlers[];
719
718#endif /* #ifndef ECRYPTFS_KERNEL_H */ 720#endif /* #ifndef ECRYPTFS_KERNEL_H */
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index 5ffba186f352..ddccec3124d7 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -1005,15 +1005,14 @@ ecryptfs_setxattr(struct dentry *dentry, struct inode *inode,
1005 const char *name, const void *value, 1005 const char *name, const void *value,
1006 size_t size, int flags) 1006 size_t size, int flags)
1007{ 1007{
1008 int rc = 0; 1008 int rc;
1009 struct dentry *lower_dentry; 1009 struct dentry *lower_dentry;
1010 1010
1011 lower_dentry = ecryptfs_dentry_to_lower(dentry); 1011 lower_dentry = ecryptfs_dentry_to_lower(dentry);
1012 if (!d_inode(lower_dentry)->i_op->setxattr) { 1012 if (!(d_inode(lower_dentry)->i_opflags & IOP_XATTR)) {
1013 rc = -EOPNOTSUPP; 1013 rc = -EOPNOTSUPP;
1014 goto out; 1014 goto out;
1015 } 1015 }
1016
1017 rc = vfs_setxattr(lower_dentry, name, value, size, flags); 1016 rc = vfs_setxattr(lower_dentry, name, value, size, flags);
1018 if (!rc && inode) 1017 if (!rc && inode)
1019 fsstack_copy_attr_all(inode, d_inode(lower_dentry)); 1018 fsstack_copy_attr_all(inode, d_inode(lower_dentry));
@@ -1025,15 +1024,14 @@ ssize_t
1025ecryptfs_getxattr_lower(struct dentry *lower_dentry, struct inode *lower_inode, 1024ecryptfs_getxattr_lower(struct dentry *lower_dentry, struct inode *lower_inode,
1026 const char *name, void *value, size_t size) 1025 const char *name, void *value, size_t size)
1027{ 1026{
1028 int rc = 0; 1027 int rc;
1029 1028
1030 if (!lower_inode->i_op->getxattr) { 1029 if (!(lower_inode->i_opflags & IOP_XATTR)) {
1031 rc = -EOPNOTSUPP; 1030 rc = -EOPNOTSUPP;
1032 goto out; 1031 goto out;
1033 } 1032 }
1034 inode_lock(lower_inode); 1033 inode_lock(lower_inode);
1035 rc = lower_inode->i_op->getxattr(lower_dentry, lower_inode, 1034 rc = __vfs_getxattr(lower_dentry, lower_inode, name, value, size);
1036 name, value, size);
1037 inode_unlock(lower_inode); 1035 inode_unlock(lower_inode);
1038out: 1036out:
1039 return rc; 1037 return rc;
@@ -1066,19 +1064,22 @@ out:
1066 return rc; 1064 return rc;
1067} 1065}
1068 1066
1069static int ecryptfs_removexattr(struct dentry *dentry, const char *name) 1067static int ecryptfs_removexattr(struct dentry *dentry, struct inode *inode,
1068 const char *name)
1070{ 1069{
1071 int rc = 0; 1070 int rc;
1072 struct dentry *lower_dentry; 1071 struct dentry *lower_dentry;
1072 struct inode *lower_inode;
1073 1073
1074 lower_dentry = ecryptfs_dentry_to_lower(dentry); 1074 lower_dentry = ecryptfs_dentry_to_lower(dentry);
1075 if (!d_inode(lower_dentry)->i_op->removexattr) { 1075 lower_inode = ecryptfs_inode_to_lower(inode);
1076 if (!(lower_inode->i_opflags & IOP_XATTR)) {
1076 rc = -EOPNOTSUPP; 1077 rc = -EOPNOTSUPP;
1077 goto out; 1078 goto out;
1078 } 1079 }
1079 inode_lock(d_inode(lower_dentry)); 1080 inode_lock(lower_inode);
1080 rc = d_inode(lower_dentry)->i_op->removexattr(lower_dentry, name); 1081 rc = __vfs_removexattr(lower_dentry, name);
1081 inode_unlock(d_inode(lower_dentry)); 1082 inode_unlock(lower_inode);
1082out: 1083out:
1083 return rc; 1084 return rc;
1084} 1085}
@@ -1089,10 +1090,7 @@ const struct inode_operations ecryptfs_symlink_iops = {
1089 .permission = ecryptfs_permission, 1090 .permission = ecryptfs_permission,
1090 .setattr = ecryptfs_setattr, 1091 .setattr = ecryptfs_setattr,
1091 .getattr = ecryptfs_getattr_link, 1092 .getattr = ecryptfs_getattr_link,
1092 .setxattr = ecryptfs_setxattr,
1093 .getxattr = ecryptfs_getxattr,
1094 .listxattr = ecryptfs_listxattr, 1093 .listxattr = ecryptfs_listxattr,
1095 .removexattr = ecryptfs_removexattr
1096}; 1094};
1097 1095
1098const struct inode_operations ecryptfs_dir_iops = { 1096const struct inode_operations ecryptfs_dir_iops = {
@@ -1107,18 +1105,43 @@ const struct inode_operations ecryptfs_dir_iops = {
1107 .rename = ecryptfs_rename, 1105 .rename = ecryptfs_rename,
1108 .permission = ecryptfs_permission, 1106 .permission = ecryptfs_permission,
1109 .setattr = ecryptfs_setattr, 1107 .setattr = ecryptfs_setattr,
1110 .setxattr = ecryptfs_setxattr,
1111 .getxattr = ecryptfs_getxattr,
1112 .listxattr = ecryptfs_listxattr, 1108 .listxattr = ecryptfs_listxattr,
1113 .removexattr = ecryptfs_removexattr
1114}; 1109};
1115 1110
1116const struct inode_operations ecryptfs_main_iops = { 1111const struct inode_operations ecryptfs_main_iops = {
1117 .permission = ecryptfs_permission, 1112 .permission = ecryptfs_permission,
1118 .setattr = ecryptfs_setattr, 1113 .setattr = ecryptfs_setattr,
1119 .getattr = ecryptfs_getattr, 1114 .getattr = ecryptfs_getattr,
1120 .setxattr = ecryptfs_setxattr,
1121 .getxattr = ecryptfs_getxattr,
1122 .listxattr = ecryptfs_listxattr, 1115 .listxattr = ecryptfs_listxattr,
1123 .removexattr = ecryptfs_removexattr 1116};
1117
1118static int ecryptfs_xattr_get(const struct xattr_handler *handler,
1119 struct dentry *dentry, struct inode *inode,
1120 const char *name, void *buffer, size_t size)
1121{
1122 return ecryptfs_getxattr(dentry, inode, name, buffer, size);
1123}
1124
1125static int ecryptfs_xattr_set(const struct xattr_handler *handler,
1126 struct dentry *dentry, struct inode *inode,
1127 const char *name, const void *value, size_t size,
1128 int flags)
1129{
1130 if (value)
1131 return ecryptfs_setxattr(dentry, inode, name, value, size, flags);
1132 else {
1133 BUG_ON(flags != XATTR_REPLACE);
1134 return ecryptfs_removexattr(dentry, inode, name);
1135 }
1136}
1137
1138const struct xattr_handler ecryptfs_xattr_handler = {
1139 .prefix = "", /* match anything */
1140 .get = ecryptfs_xattr_get,
1141 .set = ecryptfs_xattr_set,
1142};
1143
1144const struct xattr_handler *ecryptfs_xattr_handlers[] = {
1145 &ecryptfs_xattr_handler,
1146 NULL
1124}; 1147};
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
index 612004495141..151872dcc1f4 100644
--- a/fs/ecryptfs/main.c
+++ b/fs/ecryptfs/main.c
@@ -529,6 +529,7 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags
529 /* ->kill_sb() will take care of sbi after that point */ 529 /* ->kill_sb() will take care of sbi after that point */
530 sbi = NULL; 530 sbi = NULL;
531 s->s_op = &ecryptfs_sops; 531 s->s_op = &ecryptfs_sops;
532 s->s_xattr = ecryptfs_xattr_handlers;
532 s->s_d_op = &ecryptfs_dops; 533 s->s_d_op = &ecryptfs_dops;
533 534
534 err = "Reading sb failed"; 535 err = "Reading sb failed";
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index 9c3437c8a5b1..1f0c471b4ba3 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -32,6 +32,7 @@
32#include <linux/file.h> 32#include <linux/file.h>
33#include <linux/scatterlist.h> 33#include <linux/scatterlist.h>
34#include <linux/slab.h> 34#include <linux/slab.h>
35#include <linux/xattr.h>
35#include <asm/unaligned.h> 36#include <asm/unaligned.h>
36#include "ecryptfs_kernel.h" 37#include "ecryptfs_kernel.h"
37 38
@@ -422,7 +423,7 @@ static int ecryptfs_write_inode_size_to_xattr(struct inode *ecryptfs_inode)
422 struct inode *lower_inode = d_inode(lower_dentry); 423 struct inode *lower_inode = d_inode(lower_dentry);
423 int rc; 424 int rc;
424 425
425 if (!lower_inode->i_op->getxattr || !lower_inode->i_op->setxattr) { 426 if (!(lower_inode->i_opflags & IOP_XATTR)) {
426 printk(KERN_WARNING 427 printk(KERN_WARNING
427 "No support for setting xattr in lower filesystem\n"); 428 "No support for setting xattr in lower filesystem\n");
428 rc = -ENOSYS; 429 rc = -ENOSYS;
@@ -436,15 +437,13 @@ static int ecryptfs_write_inode_size_to_xattr(struct inode *ecryptfs_inode)
436 goto out; 437 goto out;
437 } 438 }
438 inode_lock(lower_inode); 439 inode_lock(lower_inode);
439 size = lower_inode->i_op->getxattr(lower_dentry, lower_inode, 440 size = __vfs_getxattr(lower_dentry, lower_inode, ECRYPTFS_XATTR_NAME,
440 ECRYPTFS_XATTR_NAME, 441 xattr_virt, PAGE_SIZE);
441 xattr_virt, PAGE_SIZE);
442 if (size < 0) 442 if (size < 0)
443 size = 8; 443 size = 8;
444 put_unaligned_be64(i_size_read(ecryptfs_inode), xattr_virt); 444 put_unaligned_be64(i_size_read(ecryptfs_inode), xattr_virt);
445 rc = lower_inode->i_op->setxattr(lower_dentry, lower_inode, 445 rc = __vfs_setxattr(lower_dentry, lower_inode, ECRYPTFS_XATTR_NAME,
446 ECRYPTFS_XATTR_NAME, 446 xattr_virt, size, 0);
447 xattr_virt, size, 0);
448 inode_unlock(lower_inode); 447 inode_unlock(lower_inode);
449 if (rc) 448 if (rc)
450 printk(KERN_ERR "Error whilst attempting to write inode size " 449 printk(KERN_ERR "Error whilst attempting to write inode size "
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index 0ca363d1341c..a0e1478dfd04 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -241,10 +241,7 @@ const struct file_operations ext2_file_operations = {
241 241
242const struct inode_operations ext2_file_inode_operations = { 242const struct inode_operations ext2_file_inode_operations = {
243#ifdef CONFIG_EXT2_FS_XATTR 243#ifdef CONFIG_EXT2_FS_XATTR
244 .setxattr = generic_setxattr,
245 .getxattr = generic_getxattr,
246 .listxattr = ext2_listxattr, 244 .listxattr = ext2_listxattr,
247 .removexattr = generic_removexattr,
248#endif 245#endif
249 .setattr = ext2_setattr, 246 .setattr = ext2_setattr,
250 .get_acl = ext2_get_acl, 247 .get_acl = ext2_get_acl,
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index d446203127fc..ff32ea799496 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -428,10 +428,7 @@ const struct inode_operations ext2_dir_inode_operations = {
428 .mknod = ext2_mknod, 428 .mknod = ext2_mknod,
429 .rename = ext2_rename, 429 .rename = ext2_rename,
430#ifdef CONFIG_EXT2_FS_XATTR 430#ifdef CONFIG_EXT2_FS_XATTR
431 .setxattr = generic_setxattr,
432 .getxattr = generic_getxattr,
433 .listxattr = ext2_listxattr, 431 .listxattr = ext2_listxattr,
434 .removexattr = generic_removexattr,
435#endif 432#endif
436 .setattr = ext2_setattr, 433 .setattr = ext2_setattr,
437 .get_acl = ext2_get_acl, 434 .get_acl = ext2_get_acl,
@@ -441,10 +438,7 @@ const struct inode_operations ext2_dir_inode_operations = {
441 438
442const struct inode_operations ext2_special_inode_operations = { 439const struct inode_operations ext2_special_inode_operations = {
443#ifdef CONFIG_EXT2_FS_XATTR 440#ifdef CONFIG_EXT2_FS_XATTR
444 .setxattr = generic_setxattr,
445 .getxattr = generic_getxattr,
446 .listxattr = ext2_listxattr, 441 .listxattr = ext2_listxattr,
447 .removexattr = generic_removexattr,
448#endif 442#endif
449 .setattr = ext2_setattr, 443 .setattr = ext2_setattr,
450 .get_acl = ext2_get_acl, 444 .get_acl = ext2_get_acl,
diff --git a/fs/ext2/symlink.c b/fs/ext2/symlink.c
index 3495d8ae4b33..8437b191bf5d 100644
--- a/fs/ext2/symlink.c
+++ b/fs/ext2/symlink.c
@@ -25,10 +25,7 @@ const struct inode_operations ext2_symlink_inode_operations = {
25 .get_link = page_get_link, 25 .get_link = page_get_link,
26 .setattr = ext2_setattr, 26 .setattr = ext2_setattr,
27#ifdef CONFIG_EXT2_FS_XATTR 27#ifdef CONFIG_EXT2_FS_XATTR
28 .setxattr = generic_setxattr,
29 .getxattr = generic_getxattr,
30 .listxattr = ext2_listxattr, 28 .listxattr = ext2_listxattr,
31 .removexattr = generic_removexattr,
32#endif 29#endif
33}; 30};
34 31
@@ -37,9 +34,6 @@ const struct inode_operations ext2_fast_symlink_inode_operations = {
37 .get_link = simple_get_link, 34 .get_link = simple_get_link,
38 .setattr = ext2_setattr, 35 .setattr = ext2_setattr,
39#ifdef CONFIG_EXT2_FS_XATTR 36#ifdef CONFIG_EXT2_FS_XATTR
40 .setxattr = generic_setxattr,
41 .getxattr = generic_getxattr,
42 .listxattr = ext2_listxattr, 37 .listxattr = ext2_listxattr,
43 .removexattr = generic_removexattr,
44#endif 38#endif
45}; 39};
diff --git a/fs/ext4/file.c b/fs/ext4/file.c
index 36d49cfbf2dc..2a822d30e73f 100644
--- a/fs/ext4/file.c
+++ b/fs/ext4/file.c
@@ -706,10 +706,7 @@ const struct file_operations ext4_file_operations = {
706const struct inode_operations ext4_file_inode_operations = { 706const struct inode_operations ext4_file_inode_operations = {
707 .setattr = ext4_setattr, 707 .setattr = ext4_setattr,
708 .getattr = ext4_getattr, 708 .getattr = ext4_getattr,
709 .setxattr = generic_setxattr,
710 .getxattr = generic_getxattr,
711 .listxattr = ext4_listxattr, 709 .listxattr = ext4_listxattr,
712 .removexattr = generic_removexattr,
713 .get_acl = ext4_get_acl, 710 .get_acl = ext4_get_acl,
714 .set_acl = ext4_set_acl, 711 .set_acl = ext4_set_acl,
715 .fiemap = ext4_fiemap, 712 .fiemap = ext4_fiemap,
diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c
index c344b819cffa..a73a9196b929 100644
--- a/fs/ext4/namei.c
+++ b/fs/ext4/namei.c
@@ -3880,10 +3880,7 @@ const struct inode_operations ext4_dir_inode_operations = {
3880 .tmpfile = ext4_tmpfile, 3880 .tmpfile = ext4_tmpfile,
3881 .rename2 = ext4_rename2, 3881 .rename2 = ext4_rename2,
3882 .setattr = ext4_setattr, 3882 .setattr = ext4_setattr,
3883 .setxattr = generic_setxattr,
3884 .getxattr = generic_getxattr,
3885 .listxattr = ext4_listxattr, 3883 .listxattr = ext4_listxattr,
3886 .removexattr = generic_removexattr,
3887 .get_acl = ext4_get_acl, 3884 .get_acl = ext4_get_acl,
3888 .set_acl = ext4_set_acl, 3885 .set_acl = ext4_set_acl,
3889 .fiemap = ext4_fiemap, 3886 .fiemap = ext4_fiemap,
@@ -3891,10 +3888,7 @@ const struct inode_operations ext4_dir_inode_operations = {
3891 3888
3892const struct inode_operations ext4_special_inode_operations = { 3889const struct inode_operations ext4_special_inode_operations = {
3893 .setattr = ext4_setattr, 3890 .setattr = ext4_setattr,
3894 .setxattr = generic_setxattr,
3895 .getxattr = generic_getxattr,
3896 .listxattr = ext4_listxattr, 3891 .listxattr = ext4_listxattr,
3897 .removexattr = generic_removexattr,
3898 .get_acl = ext4_get_acl, 3892 .get_acl = ext4_get_acl,
3899 .set_acl = ext4_set_acl, 3893 .set_acl = ext4_set_acl,
3900}; 3894};
diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c
index fdf1c6154745..557b3b0d668c 100644
--- a/fs/ext4/symlink.c
+++ b/fs/ext4/symlink.c
@@ -86,28 +86,19 @@ const struct inode_operations ext4_encrypted_symlink_inode_operations = {
86 .readlink = generic_readlink, 86 .readlink = generic_readlink,
87 .get_link = ext4_encrypted_get_link, 87 .get_link = ext4_encrypted_get_link,
88 .setattr = ext4_setattr, 88 .setattr = ext4_setattr,
89 .setxattr = generic_setxattr,
90 .getxattr = generic_getxattr,
91 .listxattr = ext4_listxattr, 89 .listxattr = ext4_listxattr,
92 .removexattr = generic_removexattr,
93}; 90};
94 91
95const struct inode_operations ext4_symlink_inode_operations = { 92const struct inode_operations ext4_symlink_inode_operations = {
96 .readlink = generic_readlink, 93 .readlink = generic_readlink,
97 .get_link = page_get_link, 94 .get_link = page_get_link,
98 .setattr = ext4_setattr, 95 .setattr = ext4_setattr,
99 .setxattr = generic_setxattr,
100 .getxattr = generic_getxattr,
101 .listxattr = ext4_listxattr, 96 .listxattr = ext4_listxattr,
102 .removexattr = generic_removexattr,
103}; 97};
104 98
105const struct inode_operations ext4_fast_symlink_inode_operations = { 99const struct inode_operations ext4_fast_symlink_inode_operations = {
106 .readlink = generic_readlink, 100 .readlink = generic_readlink,
107 .get_link = simple_get_link, 101 .get_link = simple_get_link,
108 .setattr = ext4_setattr, 102 .setattr = ext4_setattr,
109 .setxattr = generic_setxattr,
110 .getxattr = generic_getxattr,
111 .listxattr = ext4_listxattr, 103 .listxattr = ext4_listxattr,
112 .removexattr = generic_removexattr,
113}; 104};
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 90455974c2ae..acdf4b929f97 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -732,10 +732,7 @@ const struct inode_operations f2fs_file_inode_operations = {
732 .get_acl = f2fs_get_acl, 732 .get_acl = f2fs_get_acl,
733 .set_acl = f2fs_set_acl, 733 .set_acl = f2fs_set_acl,
734#ifdef CONFIG_F2FS_FS_XATTR 734#ifdef CONFIG_F2FS_FS_XATTR
735 .setxattr = generic_setxattr,
736 .getxattr = generic_getxattr,
737 .listxattr = f2fs_listxattr, 735 .listxattr = f2fs_listxattr,
738 .removexattr = generic_removexattr,
739#endif 736#endif
740 .fiemap = f2fs_fiemap, 737 .fiemap = f2fs_fiemap,
741}; 738};
diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
index 5625b879c98a..e80ed0302c22 100644
--- a/fs/f2fs/namei.c
+++ b/fs/f2fs/namei.c
@@ -1080,10 +1080,7 @@ const struct inode_operations f2fs_encrypted_symlink_inode_operations = {
1080 .getattr = f2fs_getattr, 1080 .getattr = f2fs_getattr,
1081 .setattr = f2fs_setattr, 1081 .setattr = f2fs_setattr,
1082#ifdef CONFIG_F2FS_FS_XATTR 1082#ifdef CONFIG_F2FS_FS_XATTR
1083 .setxattr = generic_setxattr,
1084 .getxattr = generic_getxattr,
1085 .listxattr = f2fs_listxattr, 1083 .listxattr = f2fs_listxattr,
1086 .removexattr = generic_removexattr,
1087#endif 1084#endif
1088}; 1085};
1089 1086
@@ -1103,10 +1100,7 @@ const struct inode_operations f2fs_dir_inode_operations = {
1103 .get_acl = f2fs_get_acl, 1100 .get_acl = f2fs_get_acl,
1104 .set_acl = f2fs_set_acl, 1101 .set_acl = f2fs_set_acl,
1105#ifdef CONFIG_F2FS_FS_XATTR 1102#ifdef CONFIG_F2FS_FS_XATTR
1106 .setxattr = generic_setxattr,
1107 .getxattr = generic_getxattr,
1108 .listxattr = f2fs_listxattr, 1103 .listxattr = f2fs_listxattr,
1109 .removexattr = generic_removexattr,
1110#endif 1104#endif
1111}; 1105};
1112 1106
@@ -1116,10 +1110,7 @@ const struct inode_operations f2fs_symlink_inode_operations = {
1116 .getattr = f2fs_getattr, 1110 .getattr = f2fs_getattr,
1117 .setattr = f2fs_setattr, 1111 .setattr = f2fs_setattr,
1118#ifdef CONFIG_F2FS_FS_XATTR 1112#ifdef CONFIG_F2FS_FS_XATTR
1119 .setxattr = generic_setxattr,
1120 .getxattr = generic_getxattr,
1121 .listxattr = f2fs_listxattr, 1113 .listxattr = f2fs_listxattr,
1122 .removexattr = generic_removexattr,
1123#endif 1114#endif
1124}; 1115};
1125 1116
@@ -1129,9 +1120,6 @@ const struct inode_operations f2fs_special_inode_operations = {
1129 .get_acl = f2fs_get_acl, 1120 .get_acl = f2fs_get_acl,
1130 .set_acl = f2fs_set_acl, 1121 .set_acl = f2fs_set_acl,
1131#ifdef CONFIG_F2FS_FS_XATTR 1122#ifdef CONFIG_F2FS_FS_XATTR
1132 .setxattr = generic_setxattr,
1133 .getxattr = generic_getxattr,
1134 .listxattr = f2fs_listxattr, 1123 .listxattr = f2fs_listxattr,
1135 .removexattr = generic_removexattr,
1136#endif 1124#endif
1137}; 1125};
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index a430c19607f4..572d12410c7c 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -1801,10 +1801,7 @@ static const struct inode_operations fuse_dir_inode_operations = {
1801 .mknod = fuse_mknod, 1801 .mknod = fuse_mknod,
1802 .permission = fuse_permission, 1802 .permission = fuse_permission,
1803 .getattr = fuse_getattr, 1803 .getattr = fuse_getattr,
1804 .setxattr = generic_setxattr,
1805 .getxattr = generic_getxattr,
1806 .listxattr = fuse_listxattr, 1804 .listxattr = fuse_listxattr,
1807 .removexattr = generic_removexattr,
1808 .get_acl = fuse_get_acl, 1805 .get_acl = fuse_get_acl,
1809 .set_acl = fuse_set_acl, 1806 .set_acl = fuse_set_acl,
1810}; 1807};
@@ -1824,10 +1821,7 @@ static const struct inode_operations fuse_common_inode_operations = {
1824 .setattr = fuse_setattr, 1821 .setattr = fuse_setattr,
1825 .permission = fuse_permission, 1822 .permission = fuse_permission,
1826 .getattr = fuse_getattr, 1823 .getattr = fuse_getattr,
1827 .setxattr = generic_setxattr,
1828 .getxattr = generic_getxattr,
1829 .listxattr = fuse_listxattr, 1824 .listxattr = fuse_listxattr,
1830 .removexattr = generic_removexattr,
1831 .get_acl = fuse_get_acl, 1825 .get_acl = fuse_get_acl,
1832 .set_acl = fuse_set_acl, 1826 .set_acl = fuse_set_acl,
1833}; 1827};
@@ -1837,10 +1831,7 @@ static const struct inode_operations fuse_symlink_inode_operations = {
1837 .get_link = fuse_get_link, 1831 .get_link = fuse_get_link,
1838 .readlink = generic_readlink, 1832 .readlink = generic_readlink,
1839 .getattr = fuse_getattr, 1833 .getattr = fuse_getattr,
1840 .setxattr = generic_setxattr,
1841 .getxattr = generic_getxattr,
1842 .listxattr = fuse_listxattr, 1834 .listxattr = fuse_listxattr,
1843 .removexattr = generic_removexattr,
1844}; 1835};
1845 1836
1846void fuse_init_common(struct inode *inode) 1837void fuse_init_common(struct inode *inode)
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index 7efd1d19d325..f6c4f0058899 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -2040,10 +2040,7 @@ const struct inode_operations gfs2_file_iops = {
2040 .permission = gfs2_permission, 2040 .permission = gfs2_permission,
2041 .setattr = gfs2_setattr, 2041 .setattr = gfs2_setattr,
2042 .getattr = gfs2_getattr, 2042 .getattr = gfs2_getattr,
2043 .setxattr = generic_setxattr,
2044 .getxattr = generic_getxattr,
2045 .listxattr = gfs2_listxattr, 2043 .listxattr = gfs2_listxattr,
2046 .removexattr = generic_removexattr,
2047 .fiemap = gfs2_fiemap, 2044 .fiemap = gfs2_fiemap,
2048 .get_acl = gfs2_get_acl, 2045 .get_acl = gfs2_get_acl,
2049 .set_acl = gfs2_set_acl, 2046 .set_acl = gfs2_set_acl,
@@ -2062,10 +2059,7 @@ const struct inode_operations gfs2_dir_iops = {
2062 .permission = gfs2_permission, 2059 .permission = gfs2_permission,
2063 .setattr = gfs2_setattr, 2060 .setattr = gfs2_setattr,
2064 .getattr = gfs2_getattr, 2061 .getattr = gfs2_getattr,
2065 .setxattr = generic_setxattr,
2066 .getxattr = generic_getxattr,
2067 .listxattr = gfs2_listxattr, 2062 .listxattr = gfs2_listxattr,
2068 .removexattr = generic_removexattr,
2069 .fiemap = gfs2_fiemap, 2063 .fiemap = gfs2_fiemap,
2070 .get_acl = gfs2_get_acl, 2064 .get_acl = gfs2_get_acl,
2071 .set_acl = gfs2_set_acl, 2065 .set_acl = gfs2_set_acl,
@@ -2078,10 +2072,7 @@ const struct inode_operations gfs2_symlink_iops = {
2078 .permission = gfs2_permission, 2072 .permission = gfs2_permission,
2079 .setattr = gfs2_setattr, 2073 .setattr = gfs2_setattr,
2080 .getattr = gfs2_getattr, 2074 .getattr = gfs2_getattr,
2081 .setxattr = generic_setxattr,
2082 .getxattr = generic_getxattr,
2083 .listxattr = gfs2_listxattr, 2075 .listxattr = gfs2_listxattr,
2084 .removexattr = generic_removexattr,
2085 .fiemap = gfs2_fiemap, 2076 .fiemap = gfs2_fiemap,
2086}; 2077};
2087 2078
diff --git a/fs/hfs/attr.c b/fs/hfs/attr.c
index d9a86919fdf6..0933600e11c8 100644
--- a/fs/hfs/attr.c
+++ b/fs/hfs/attr.c
@@ -13,9 +13,13 @@
13#include "hfs_fs.h" 13#include "hfs_fs.h"
14#include "btree.h" 14#include "btree.h"
15 15
16int hfs_setxattr(struct dentry *unused, struct inode *inode, 16enum hfs_xattr_type {
17 const char *name, const void *value, 17 HFS_TYPE,
18 size_t size, int flags) 18 HFS_CREATOR,
19};
20
21static int __hfs_setxattr(struct inode *inode, enum hfs_xattr_type type,
22 const void *value, size_t size, int flags)
19{ 23{
20 struct hfs_find_data fd; 24 struct hfs_find_data fd;
21 hfs_cat_rec rec; 25 hfs_cat_rec rec;
@@ -36,18 +40,22 @@ int hfs_setxattr(struct dentry *unused, struct inode *inode,
36 sizeof(struct hfs_cat_file)); 40 sizeof(struct hfs_cat_file));
37 file = &rec.file; 41 file = &rec.file;
38 42
39 if (!strcmp(name, "hfs.type")) { 43 switch (type) {
44 case HFS_TYPE:
40 if (size == 4) 45 if (size == 4)
41 memcpy(&file->UsrWds.fdType, value, 4); 46 memcpy(&file->UsrWds.fdType, value, 4);
42 else 47 else
43 res = -ERANGE; 48 res = -ERANGE;
44 } else if (!strcmp(name, "hfs.creator")) { 49 break;
50
51 case HFS_CREATOR:
45 if (size == 4) 52 if (size == 4)
46 memcpy(&file->UsrWds.fdCreator, value, 4); 53 memcpy(&file->UsrWds.fdCreator, value, 4);
47 else 54 else
48 res = -ERANGE; 55 res = -ERANGE;
49 } else 56 break;
50 res = -EOPNOTSUPP; 57 }
58
51 if (!res) 59 if (!res)
52 hfs_bnode_write(fd.bnode, &rec, fd.entryoffset, 60 hfs_bnode_write(fd.bnode, &rec, fd.entryoffset,
53 sizeof(struct hfs_cat_file)); 61 sizeof(struct hfs_cat_file));
@@ -56,8 +64,8 @@ out:
56 return res; 64 return res;
57} 65}
58 66
59ssize_t hfs_getxattr(struct dentry *unused, struct inode *inode, 67static ssize_t __hfs_getxattr(struct inode *inode, enum hfs_xattr_type type,
60 const char *name, void *value, size_t size) 68 void *value, size_t size)
61{ 69{
62 struct hfs_find_data fd; 70 struct hfs_find_data fd;
63 hfs_cat_rec rec; 71 hfs_cat_rec rec;
@@ -80,41 +88,64 @@ ssize_t hfs_getxattr(struct dentry *unused, struct inode *inode,
80 } 88 }
81 file = &rec.file; 89 file = &rec.file;
82 90
83 if (!strcmp(name, "hfs.type")) { 91 switch (type) {
92 case HFS_TYPE:
84 if (size >= 4) { 93 if (size >= 4) {
85 memcpy(value, &file->UsrWds.fdType, 4); 94 memcpy(value, &file->UsrWds.fdType, 4);
86 res = 4; 95 res = 4;
87 } else 96 } else
88 res = size ? -ERANGE : 4; 97 res = size ? -ERANGE : 4;
89 } else if (!strcmp(name, "hfs.creator")) { 98 break;
99
100 case HFS_CREATOR:
90 if (size >= 4) { 101 if (size >= 4) {
91 memcpy(value, &file->UsrWds.fdCreator, 4); 102 memcpy(value, &file->UsrWds.fdCreator, 4);
92 res = 4; 103 res = 4;
93 } else 104 } else
94 res = size ? -ERANGE : 4; 105 res = size ? -ERANGE : 4;
95 } else 106 break;
96 res = -ENODATA; 107 }
108
97out: 109out:
98 if (size) 110 if (size)
99 hfs_find_exit(&fd); 111 hfs_find_exit(&fd);
100 return res; 112 return res;
101} 113}
102 114
103#define HFS_ATTRLIST_SIZE (sizeof("hfs.creator")+sizeof("hfs.type")) 115static int hfs_xattr_get(const struct xattr_handler *handler,
104 116 struct dentry *unused, struct inode *inode,
105ssize_t hfs_listxattr(struct dentry *dentry, char *buffer, size_t size) 117 const char *name, void *value, size_t size)
106{ 118{
107 struct inode *inode = d_inode(dentry); 119 return __hfs_getxattr(inode, handler->flags, value, size);
120}
108 121
109 if (!S_ISREG(inode->i_mode) || HFS_IS_RSRC(inode)) 122static int hfs_xattr_set(const struct xattr_handler *handler,
123 struct dentry *unused, struct inode *inode,
124 const char *name, const void *value, size_t size,
125 int flags)
126{
127 if (!value)
110 return -EOPNOTSUPP; 128 return -EOPNOTSUPP;
111 129
112 if (!buffer || !size) 130 return __hfs_setxattr(inode, handler->flags, value, size, flags);
113 return HFS_ATTRLIST_SIZE;
114 if (size < HFS_ATTRLIST_SIZE)
115 return -ERANGE;
116 strcpy(buffer, "hfs.type");
117 strcpy(buffer + sizeof("hfs.type"), "hfs.creator");
118
119 return HFS_ATTRLIST_SIZE;
120} 131}
132
133static const struct xattr_handler hfs_creator_handler = {
134 .name = "hfs.creator",
135 .flags = HFS_CREATOR,
136 .get = hfs_xattr_get,
137 .set = hfs_xattr_set,
138};
139
140static const struct xattr_handler hfs_type_handler = {
141 .name = "hfs.type",
142 .flags = HFS_TYPE,
143 .get = hfs_xattr_get,
144 .set = hfs_xattr_set,
145};
146
147const struct xattr_handler *hfs_xattr_handlers[] = {
148 &hfs_creator_handler,
149 &hfs_type_handler,
150 NULL
151};
diff --git a/fs/hfs/hfs_fs.h b/fs/hfs/hfs_fs.h
index 16f5172ee40d..4cdec5a19347 100644
--- a/fs/hfs/hfs_fs.h
+++ b/fs/hfs/hfs_fs.h
@@ -212,11 +212,7 @@ extern void hfs_evict_inode(struct inode *);
212extern void hfs_delete_inode(struct inode *); 212extern void hfs_delete_inode(struct inode *);
213 213
214/* attr.c */ 214/* attr.c */
215extern int hfs_setxattr(struct dentry *dentry, struct inode *inode, const char *name, 215extern const struct xattr_handler *hfs_xattr_handlers[];
216 const void *value, size_t size, int flags);
217extern ssize_t hfs_getxattr(struct dentry *dentry, struct inode *inode,
218 const char *name, void *value, size_t size);
219extern ssize_t hfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
220 216
221/* mdb.c */ 217/* mdb.c */
222extern int hfs_mdb_get(struct super_block *); 218extern int hfs_mdb_get(struct super_block *);
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c
index 09cce23864da..ed373261f26d 100644
--- a/fs/hfs/inode.c
+++ b/fs/hfs/inode.c
@@ -15,6 +15,7 @@
15#include <linux/mpage.h> 15#include <linux/mpage.h>
16#include <linux/sched.h> 16#include <linux/sched.h>
17#include <linux/uio.h> 17#include <linux/uio.h>
18#include <linux/xattr.h>
18 19
19#include "hfs_fs.h" 20#include "hfs_fs.h"
20#include "btree.h" 21#include "btree.h"
@@ -687,7 +688,5 @@ static const struct file_operations hfs_file_operations = {
687static const struct inode_operations hfs_file_inode_operations = { 688static const struct inode_operations hfs_file_inode_operations = {
688 .lookup = hfs_file_lookup, 689 .lookup = hfs_file_lookup,
689 .setattr = hfs_inode_setattr, 690 .setattr = hfs_inode_setattr,
690 .setxattr = hfs_setxattr, 691 .listxattr = generic_listxattr,
691 .getxattr = hfs_getxattr,
692 .listxattr = hfs_listxattr,
693}; 692};
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index 1ca95c232bb5..bf6304a350a6 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -406,6 +406,7 @@ static int hfs_fill_super(struct super_block *sb, void *data, int silent)
406 } 406 }
407 407
408 sb->s_op = &hfs_super_operations; 408 sb->s_op = &hfs_super_operations;
409 sb->s_xattr = hfs_xattr_handlers;
409 sb->s_flags |= MS_NODIRATIME; 410 sb->s_flags |= MS_NODIRATIME;
410 mutex_init(&sbi->bitmap_lock); 411 mutex_init(&sbi->bitmap_lock);
411 412
diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c
index 42e128661dc1..9cbe43075de5 100644
--- a/fs/hfsplus/dir.c
+++ b/fs/hfsplus/dir.c
@@ -562,10 +562,7 @@ const struct inode_operations hfsplus_dir_inode_operations = {
562 .symlink = hfsplus_symlink, 562 .symlink = hfsplus_symlink,
563 .mknod = hfsplus_mknod, 563 .mknod = hfsplus_mknod,
564 .rename = hfsplus_rename, 564 .rename = hfsplus_rename,
565 .setxattr = generic_setxattr,
566 .getxattr = generic_getxattr,
567 .listxattr = hfsplus_listxattr, 565 .listxattr = hfsplus_listxattr,
568 .removexattr = generic_removexattr,
569#ifdef CONFIG_HFSPLUS_FS_POSIX_ACL 566#ifdef CONFIG_HFSPLUS_FS_POSIX_ACL
570 .get_acl = hfsplus_get_posix_acl, 567 .get_acl = hfsplus_get_posix_acl,
571 .set_acl = hfsplus_set_posix_acl, 568 .set_acl = hfsplus_set_posix_acl,
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index c43ef397a3aa..10827c912c4d 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -333,10 +333,7 @@ int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end,
333 333
334static const struct inode_operations hfsplus_file_inode_operations = { 334static const struct inode_operations hfsplus_file_inode_operations = {
335 .setattr = hfsplus_setattr, 335 .setattr = hfsplus_setattr,
336 .setxattr = generic_setxattr,
337 .getxattr = generic_getxattr,
338 .listxattr = hfsplus_listxattr, 336 .listxattr = hfsplus_listxattr,
339 .removexattr = generic_removexattr,
340#ifdef CONFIG_HFSPLUS_FS_POSIX_ACL 337#ifdef CONFIG_HFSPLUS_FS_POSIX_ACL
341 .get_acl = hfsplus_get_posix_acl, 338 .get_acl = hfsplus_get_posix_acl,
342 .set_acl = hfsplus_set_posix_acl, 339 .set_acl = hfsplus_set_posix_acl,
diff --git a/fs/inode.c b/fs/inode.c
index a3c7ba7f6b59..7d037591259d 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -140,6 +140,8 @@ int inode_init_always(struct super_block *sb, struct inode *inode)
140 inode->i_fop = &no_open_fops; 140 inode->i_fop = &no_open_fops;
141 inode->__i_nlink = 1; 141 inode->__i_nlink = 1;
142 inode->i_opflags = 0; 142 inode->i_opflags = 0;
143 if (sb->s_xattr)
144 inode->i_opflags |= IOP_XATTR;
143 i_uid_write(inode, 0); 145 i_uid_write(inode, 0);
144 i_gid_write(inode, 0); 146 i_gid_write(inode, 0);
145 atomic_set(&inode->i_writecount, 0); 147 atomic_set(&inode->i_writecount, 0);
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c
index 30eb33ff8189..9b242434adf2 100644
--- a/fs/jffs2/dir.c
+++ b/fs/jffs2/dir.c
@@ -61,10 +61,7 @@ const struct inode_operations jffs2_dir_inode_operations =
61 .get_acl = jffs2_get_acl, 61 .get_acl = jffs2_get_acl,
62 .set_acl = jffs2_set_acl, 62 .set_acl = jffs2_set_acl,
63 .setattr = jffs2_setattr, 63 .setattr = jffs2_setattr,
64 .setxattr = jffs2_setxattr,
65 .getxattr = jffs2_getxattr,
66 .listxattr = jffs2_listxattr, 64 .listxattr = jffs2_listxattr,
67 .removexattr = jffs2_removexattr
68}; 65};
69 66
70/***********************************************************************/ 67/***********************************************************************/
diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c
index 0e62dec3effc..c12476e309c6 100644
--- a/fs/jffs2/file.c
+++ b/fs/jffs2/file.c
@@ -66,10 +66,7 @@ const struct inode_operations jffs2_file_inode_operations =
66 .get_acl = jffs2_get_acl, 66 .get_acl = jffs2_get_acl,
67 .set_acl = jffs2_set_acl, 67 .set_acl = jffs2_set_acl,
68 .setattr = jffs2_setattr, 68 .setattr = jffs2_setattr,
69 .setxattr = jffs2_setxattr,
70 .getxattr = jffs2_getxattr,
71 .listxattr = jffs2_listxattr, 69 .listxattr = jffs2_listxattr,
72 .removexattr = jffs2_removexattr
73}; 70};
74 71
75const struct address_space_operations jffs2_file_address_operations = 72const struct address_space_operations jffs2_file_address_operations =
diff --git a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c
index 2cabd649d4fb..8f3f0855fcd2 100644
--- a/fs/jffs2/symlink.c
+++ b/fs/jffs2/symlink.c
@@ -16,8 +16,5 @@ const struct inode_operations jffs2_symlink_inode_operations =
16 .readlink = generic_readlink, 16 .readlink = generic_readlink,
17 .get_link = simple_get_link, 17 .get_link = simple_get_link,
18 .setattr = jffs2_setattr, 18 .setattr = jffs2_setattr,
19 .setxattr = jffs2_setxattr,
20 .getxattr = jffs2_getxattr,
21 .listxattr = jffs2_listxattr, 19 .listxattr = jffs2_listxattr,
22 .removexattr = jffs2_removexattr
23}; 20};
diff --git a/fs/jffs2/xattr.h b/fs/jffs2/xattr.h
index 467ff376ee26..720007b2fd65 100644
--- a/fs/jffs2/xattr.h
+++ b/fs/jffs2/xattr.h
@@ -99,9 +99,6 @@ extern const struct xattr_handler jffs2_user_xattr_handler;
99extern const struct xattr_handler jffs2_trusted_xattr_handler; 99extern const struct xattr_handler jffs2_trusted_xattr_handler;
100 100
101extern ssize_t jffs2_listxattr(struct dentry *, char *, size_t); 101extern ssize_t jffs2_listxattr(struct dentry *, char *, size_t);
102#define jffs2_getxattr generic_getxattr
103#define jffs2_setxattr generic_setxattr
104#define jffs2_removexattr generic_removexattr
105 102
106#else 103#else
107 104
@@ -116,9 +113,6 @@ extern ssize_t jffs2_listxattr(struct dentry *, char *, size_t);
116 113
117#define jffs2_xattr_handlers NULL 114#define jffs2_xattr_handlers NULL
118#define jffs2_listxattr NULL 115#define jffs2_listxattr NULL
119#define jffs2_getxattr NULL
120#define jffs2_setxattr NULL
121#define jffs2_removexattr NULL
122 116
123#endif /* CONFIG_JFFS2_FS_XATTR */ 117#endif /* CONFIG_JFFS2_FS_XATTR */
124 118
diff --git a/fs/jfs/file.c b/fs/jfs/file.c
index cf62037b8a04..739492c7a3fd 100644
--- a/fs/jfs/file.c
+++ b/fs/jfs/file.c
@@ -140,10 +140,7 @@ int jfs_setattr(struct dentry *dentry, struct iattr *iattr)
140} 140}
141 141
142const struct inode_operations jfs_file_inode_operations = { 142const struct inode_operations jfs_file_inode_operations = {
143 .setxattr = generic_setxattr,
144 .getxattr = generic_getxattr,
145 .listxattr = jfs_listxattr, 143 .listxattr = jfs_listxattr,
146 .removexattr = generic_removexattr,
147 .setattr = jfs_setattr, 144 .setattr = jfs_setattr,
148#ifdef CONFIG_JFS_POSIX_ACL 145#ifdef CONFIG_JFS_POSIX_ACL
149 .get_acl = jfs_get_acl, 146 .get_acl = jfs_get_acl,
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
index 814b0c58016c..e420c6088336 100644
--- a/fs/jfs/namei.c
+++ b/fs/jfs/namei.c
@@ -1537,10 +1537,7 @@ const struct inode_operations jfs_dir_inode_operations = {
1537 .rmdir = jfs_rmdir, 1537 .rmdir = jfs_rmdir,
1538 .mknod = jfs_mknod, 1538 .mknod = jfs_mknod,
1539 .rename = jfs_rename, 1539 .rename = jfs_rename,
1540 .setxattr = generic_setxattr,
1541 .getxattr = generic_getxattr,
1542 .listxattr = jfs_listxattr, 1540 .listxattr = jfs_listxattr,
1543 .removexattr = generic_removexattr,
1544 .setattr = jfs_setattr, 1541 .setattr = jfs_setattr,
1545#ifdef CONFIG_JFS_POSIX_ACL 1542#ifdef CONFIG_JFS_POSIX_ACL
1546 .get_acl = jfs_get_acl, 1543 .get_acl = jfs_get_acl,
diff --git a/fs/jfs/symlink.c b/fs/jfs/symlink.c
index c94c7e4a1323..c82404fee6cd 100644
--- a/fs/jfs/symlink.c
+++ b/fs/jfs/symlink.c
@@ -25,19 +25,13 @@ const struct inode_operations jfs_fast_symlink_inode_operations = {
25 .readlink = generic_readlink, 25 .readlink = generic_readlink,
26 .get_link = simple_get_link, 26 .get_link = simple_get_link,
27 .setattr = jfs_setattr, 27 .setattr = jfs_setattr,
28 .setxattr = generic_setxattr,
29 .getxattr = generic_getxattr,
30 .listxattr = jfs_listxattr, 28 .listxattr = jfs_listxattr,
31 .removexattr = generic_removexattr,
32}; 29};
33 30
34const struct inode_operations jfs_symlink_inode_operations = { 31const struct inode_operations jfs_symlink_inode_operations = {
35 .readlink = generic_readlink, 32 .readlink = generic_readlink,
36 .get_link = page_get_link, 33 .get_link = page_get_link,
37 .setattr = jfs_setattr, 34 .setattr = jfs_setattr,
38 .setxattr = generic_setxattr,
39 .getxattr = generic_getxattr,
40 .listxattr = jfs_listxattr, 35 .listxattr = jfs_listxattr,
41 .removexattr = generic_removexattr,
42}; 36};
43 37
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index e57174d43683..2b23ad91a464 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -1126,9 +1126,6 @@ const struct inode_operations kernfs_dir_iops = {
1126 .permission = kernfs_iop_permission, 1126 .permission = kernfs_iop_permission,
1127 .setattr = kernfs_iop_setattr, 1127 .setattr = kernfs_iop_setattr,
1128 .getattr = kernfs_iop_getattr, 1128 .getattr = kernfs_iop_getattr,
1129 .setxattr = kernfs_iop_setxattr,
1130 .removexattr = kernfs_iop_removexattr,
1131 .getxattr = kernfs_iop_getxattr,
1132 .listxattr = kernfs_iop_listxattr, 1129 .listxattr = kernfs_iop_listxattr,
1133 1130
1134 .mkdir = kernfs_iop_mkdir, 1131 .mkdir = kernfs_iop_mkdir,
diff --git a/fs/kernfs/inode.c b/fs/kernfs/inode.c
index df21f5b75549..102b6f0bc7af 100644
--- a/fs/kernfs/inode.c
+++ b/fs/kernfs/inode.c
@@ -28,9 +28,6 @@ static const struct inode_operations kernfs_iops = {
28 .permission = kernfs_iop_permission, 28 .permission = kernfs_iop_permission,
29 .setattr = kernfs_iop_setattr, 29 .setattr = kernfs_iop_setattr,
30 .getattr = kernfs_iop_getattr, 30 .getattr = kernfs_iop_getattr,
31 .setxattr = kernfs_iop_setxattr,
32 .removexattr = kernfs_iop_removexattr,
33 .getxattr = kernfs_iop_getxattr,
34 .listxattr = kernfs_iop_listxattr, 31 .listxattr = kernfs_iop_listxattr,
35}; 32};
36 33
@@ -138,17 +135,12 @@ out:
138 return error; 135 return error;
139} 136}
140 137
141static int kernfs_node_setsecdata(struct kernfs_node *kn, void **secdata, 138static int kernfs_node_setsecdata(struct kernfs_iattrs *attrs, void **secdata,
142 u32 *secdata_len) 139 u32 *secdata_len)
143{ 140{
144 struct kernfs_iattrs *attrs;
145 void *old_secdata; 141 void *old_secdata;
146 size_t old_secdata_len; 142 size_t old_secdata_len;
147 143
148 attrs = kernfs_iattrs(kn);
149 if (!attrs)
150 return -ENOMEM;
151
152 old_secdata = attrs->ia_secdata; 144 old_secdata = attrs->ia_secdata;
153 old_secdata_len = attrs->ia_secdata_len; 145 old_secdata_len = attrs->ia_secdata_len;
154 146
@@ -160,71 +152,6 @@ static int kernfs_node_setsecdata(struct kernfs_node *kn, void **secdata,
160 return 0; 152 return 0;
161} 153}
162 154
163int kernfs_iop_setxattr(struct dentry *unused, struct inode *inode,
164 const char *name, const void *value,
165 size_t size, int flags)
166{
167 struct kernfs_node *kn = inode->i_private;
168 struct kernfs_iattrs *attrs;
169 void *secdata;
170 int error;
171 u32 secdata_len = 0;
172
173 attrs = kernfs_iattrs(kn);
174 if (!attrs)
175 return -ENOMEM;
176
177 if (!strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN)) {
178 const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
179 error = security_inode_setsecurity(inode, suffix,
180 value, size, flags);
181 if (error)
182 return error;
183 error = security_inode_getsecctx(inode,
184 &secdata, &secdata_len);
185 if (error)
186 return error;
187
188 mutex_lock(&kernfs_mutex);
189 error = kernfs_node_setsecdata(kn, &secdata, &secdata_len);
190 mutex_unlock(&kernfs_mutex);
191
192 if (secdata)
193 security_release_secctx(secdata, secdata_len);
194 return error;
195 } else if (!strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN)) {
196 return simple_xattr_set(&attrs->xattrs, name, value, size,
197 flags);
198 }
199
200 return -EINVAL;
201}
202
203int kernfs_iop_removexattr(struct dentry *dentry, const char *name)
204{
205 struct kernfs_node *kn = dentry->d_fsdata;
206 struct kernfs_iattrs *attrs;
207
208 attrs = kernfs_iattrs(kn);
209 if (!attrs)
210 return -ENOMEM;
211
212 return simple_xattr_set(&attrs->xattrs, name, NULL, 0, XATTR_REPLACE);
213}
214
215ssize_t kernfs_iop_getxattr(struct dentry *unused, struct inode *inode,
216 const char *name, void *buf, size_t size)
217{
218 struct kernfs_node *kn = inode->i_private;
219 struct kernfs_iattrs *attrs;
220
221 attrs = kernfs_iattrs(kn);
222 if (!attrs)
223 return -ENOMEM;
224
225 return simple_xattr_get(&attrs->xattrs, name, buf, size);
226}
227
228ssize_t kernfs_iop_listxattr(struct dentry *dentry, char *buf, size_t size) 155ssize_t kernfs_iop_listxattr(struct dentry *dentry, char *buf, size_t size)
229{ 156{
230 struct kernfs_node *kn = dentry->d_fsdata; 157 struct kernfs_node *kn = dentry->d_fsdata;
@@ -376,3 +303,83 @@ int kernfs_iop_permission(struct inode *inode, int mask)
376 303
377 return generic_permission(inode, mask); 304 return generic_permission(inode, mask);
378} 305}
306
307static int kernfs_xattr_get(const struct xattr_handler *handler,
308 struct dentry *unused, struct inode *inode,
309 const char *suffix, void *value, size_t size)
310{
311 const char *name = xattr_full_name(handler, suffix);
312 struct kernfs_node *kn = inode->i_private;
313 struct kernfs_iattrs *attrs;
314
315 attrs = kernfs_iattrs(kn);
316 if (!attrs)
317 return -ENOMEM;
318
319 return simple_xattr_get(&attrs->xattrs, name, value, size);
320}
321
322static int kernfs_xattr_set(const struct xattr_handler *handler,
323 struct dentry *unused, struct inode *inode,
324 const char *suffix, const void *value,
325 size_t size, int flags)
326{
327 const char *name = xattr_full_name(handler, suffix);
328 struct kernfs_node *kn = inode->i_private;
329 struct kernfs_iattrs *attrs;
330
331 attrs = kernfs_iattrs(kn);
332 if (!attrs)
333 return -ENOMEM;
334
335 return simple_xattr_set(&attrs->xattrs, name, value, size, flags);
336}
337
338const struct xattr_handler kernfs_trusted_xattr_handler = {
339 .prefix = XATTR_TRUSTED_PREFIX,
340 .get = kernfs_xattr_get,
341 .set = kernfs_xattr_set,
342};
343
344static int kernfs_security_xattr_set(const struct xattr_handler *handler,
345 struct dentry *unused, struct inode *inode,
346 const char *suffix, const void *value,
347 size_t size, int flags)
348{
349 struct kernfs_node *kn = inode->i_private;
350 struct kernfs_iattrs *attrs;
351 void *secdata;
352 u32 secdata_len = 0;
353 int error;
354
355 attrs = kernfs_iattrs(kn);
356 if (!attrs)
357 return -ENOMEM;
358
359 error = security_inode_setsecurity(inode, suffix, value, size, flags);
360 if (error)
361 return error;
362 error = security_inode_getsecctx(inode, &secdata, &secdata_len);
363 if (error)
364 return error;
365
366 mutex_lock(&kernfs_mutex);
367 error = kernfs_node_setsecdata(attrs, &secdata, &secdata_len);
368 mutex_unlock(&kernfs_mutex);
369
370 if (secdata)
371 security_release_secctx(secdata, secdata_len);
372 return error;
373}
374
375const struct xattr_handler kernfs_security_xattr_handler = {
376 .prefix = XATTR_SECURITY_PREFIX,
377 .get = kernfs_xattr_get,
378 .set = kernfs_security_xattr_set,
379};
380
381const struct xattr_handler *kernfs_xattr_handlers[] = {
382 &kernfs_trusted_xattr_handler,
383 &kernfs_security_xattr_handler,
384 NULL
385};
diff --git a/fs/kernfs/kernfs-internal.h b/fs/kernfs/kernfs-internal.h
index 37159235ac10..bfd551bbf231 100644
--- a/fs/kernfs/kernfs-internal.h
+++ b/fs/kernfs/kernfs-internal.h
@@ -76,17 +76,12 @@ extern struct kmem_cache *kernfs_node_cache;
76/* 76/*
77 * inode.c 77 * inode.c
78 */ 78 */
79extern const struct xattr_handler *kernfs_xattr_handlers[];
79void kernfs_evict_inode(struct inode *inode); 80void kernfs_evict_inode(struct inode *inode);
80int kernfs_iop_permission(struct inode *inode, int mask); 81int kernfs_iop_permission(struct inode *inode, int mask);
81int kernfs_iop_setattr(struct dentry *dentry, struct iattr *iattr); 82int kernfs_iop_setattr(struct dentry *dentry, struct iattr *iattr);
82int kernfs_iop_getattr(struct vfsmount *mnt, struct dentry *dentry, 83int kernfs_iop_getattr(struct vfsmount *mnt, struct dentry *dentry,
83 struct kstat *stat); 84 struct kstat *stat);
84int kernfs_iop_setxattr(struct dentry *dentry, struct inode *inode,
85 const char *name, const void *value,
86 size_t size, int flags);
87int kernfs_iop_removexattr(struct dentry *dentry, const char *name);
88ssize_t kernfs_iop_getxattr(struct dentry *dentry, struct inode *inode,
89 const char *name, void *buf, size_t size);
90ssize_t kernfs_iop_listxattr(struct dentry *dentry, char *buf, size_t size); 85ssize_t kernfs_iop_listxattr(struct dentry *dentry, char *buf, size_t size);
91 86
92/* 87/*
diff --git a/fs/kernfs/mount.c b/fs/kernfs/mount.c
index b3d73ad52b22..d5b149a45be1 100644
--- a/fs/kernfs/mount.c
+++ b/fs/kernfs/mount.c
@@ -158,6 +158,7 @@ static int kernfs_fill_super(struct super_block *sb, unsigned long magic)
158 sb->s_blocksize_bits = PAGE_SHIFT; 158 sb->s_blocksize_bits = PAGE_SHIFT;
159 sb->s_magic = magic; 159 sb->s_magic = magic;
160 sb->s_op = &kernfs_sops; 160 sb->s_op = &kernfs_sops;
161 sb->s_xattr = kernfs_xattr_handlers;
161 sb->s_time_gran = 1; 162 sb->s_time_gran = 1;
162 163
163 /* get root inode, initialize and unlock it */ 164 /* get root inode, initialize and unlock it */
diff --git a/fs/kernfs/symlink.c b/fs/kernfs/symlink.c
index 117b8b3416f9..9b43ca02b7ab 100644
--- a/fs/kernfs/symlink.c
+++ b/fs/kernfs/symlink.c
@@ -134,9 +134,6 @@ static const char *kernfs_iop_get_link(struct dentry *dentry,
134} 134}
135 135
136const struct inode_operations kernfs_symlink_iops = { 136const struct inode_operations kernfs_symlink_iops = {
137 .setxattr = kernfs_iop_setxattr,
138 .removexattr = kernfs_iop_removexattr,
139 .getxattr = kernfs_iop_getxattr,
140 .listxattr = kernfs_iop_listxattr, 137 .listxattr = kernfs_iop_listxattr,
141 .readlink = generic_readlink, 138 .readlink = generic_readlink,
142 .get_link = kernfs_iop_get_link, 139 .get_link = kernfs_iop_get_link,
diff --git a/fs/libfs.c b/fs/libfs.c
index 2b3c3ae70153..a6d89f151771 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -236,8 +236,8 @@ static const struct super_operations simple_super_operations = {
236 * Common helper for pseudo-filesystems (sockfs, pipefs, bdev - stuff that 236 * Common helper for pseudo-filesystems (sockfs, pipefs, bdev - stuff that
237 * will never be mountable) 237 * will never be mountable)
238 */ 238 */
239struct dentry *mount_pseudo(struct file_system_type *fs_type, char *name, 239struct dentry *mount_pseudo_xattr(struct file_system_type *fs_type, char *name,
240 const struct super_operations *ops, 240 const struct super_operations *ops, const struct xattr_handler **xattr,
241 const struct dentry_operations *dops, unsigned long magic) 241 const struct dentry_operations *dops, unsigned long magic)
242{ 242{
243 struct super_block *s; 243 struct super_block *s;
@@ -254,6 +254,7 @@ struct dentry *mount_pseudo(struct file_system_type *fs_type, char *name,
254 s->s_blocksize_bits = PAGE_SHIFT; 254 s->s_blocksize_bits = PAGE_SHIFT;
255 s->s_magic = magic; 255 s->s_magic = magic;
256 s->s_op = ops ? ops : &simple_super_operations; 256 s->s_op = ops ? ops : &simple_super_operations;
257 s->s_xattr = xattr;
257 s->s_time_gran = 1; 258 s->s_time_gran = 1;
258 root = new_inode(s); 259 root = new_inode(s);
259 if (!root) 260 if (!root)
@@ -281,7 +282,7 @@ Enomem:
281 deactivate_locked_super(s); 282 deactivate_locked_super(s);
282 return ERR_PTR(-ENOMEM); 283 return ERR_PTR(-ENOMEM);
283} 284}
284EXPORT_SYMBOL(mount_pseudo); 285EXPORT_SYMBOL(mount_pseudo_xattr);
285 286
286int simple_open(struct inode *inode, struct file *file) 287int simple_open(struct inode *inode, struct file *file)
287{ 288{
@@ -1149,24 +1150,6 @@ static int empty_dir_setattr(struct dentry *dentry, struct iattr *attr)
1149 return -EPERM; 1150 return -EPERM;
1150} 1151}
1151 1152
1152static int empty_dir_setxattr(struct dentry *dentry, struct inode *inode,
1153 const char *name, const void *value,
1154 size_t size, int flags)
1155{
1156 return -EOPNOTSUPP;
1157}
1158
1159static ssize_t empty_dir_getxattr(struct dentry *dentry, struct inode *inode,
1160 const char *name, void *value, size_t size)
1161{
1162 return -EOPNOTSUPP;
1163}
1164
1165static int empty_dir_removexattr(struct dentry *dentry, const char *name)
1166{
1167 return -EOPNOTSUPP;
1168}
1169
1170static ssize_t empty_dir_listxattr(struct dentry *dentry, char *list, size_t size) 1153static ssize_t empty_dir_listxattr(struct dentry *dentry, char *list, size_t size)
1171{ 1154{
1172 return -EOPNOTSUPP; 1155 return -EOPNOTSUPP;
@@ -1177,9 +1160,6 @@ static const struct inode_operations empty_dir_inode_operations = {
1177 .permission = generic_permission, 1160 .permission = generic_permission,
1178 .setattr = empty_dir_setattr, 1161 .setattr = empty_dir_setattr,
1179 .getattr = empty_dir_getattr, 1162 .getattr = empty_dir_getattr,
1180 .setxattr = empty_dir_setxattr,
1181 .getxattr = empty_dir_getxattr,
1182 .removexattr = empty_dir_removexattr,
1183 .listxattr = empty_dir_listxattr, 1163 .listxattr = empty_dir_listxattr,
1184}; 1164};
1185 1165
@@ -1215,6 +1195,7 @@ void make_empty_dir_inode(struct inode *inode)
1215 inode->i_blocks = 0; 1195 inode->i_blocks = 0;
1216 1196
1217 inode->i_op = &empty_dir_inode_operations; 1197 inode->i_op = &empty_dir_inode_operations;
1198 inode->i_opflags &= ~IOP_XATTR;
1218 inode->i_fop = &empty_dir_operations; 1199 inode->i_fop = &empty_dir_operations;
1219} 1200}
1220 1201
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c
index 698be9361280..dc925b531f32 100644
--- a/fs/nfs/nfs3proc.c
+++ b/fs/nfs/nfs3proc.c
@@ -899,9 +899,6 @@ static const struct inode_operations nfs3_dir_inode_operations = {
899 .setattr = nfs_setattr, 899 .setattr = nfs_setattr,
900#ifdef CONFIG_NFS_V3_ACL 900#ifdef CONFIG_NFS_V3_ACL
901 .listxattr = nfs3_listxattr, 901 .listxattr = nfs3_listxattr,
902 .getxattr = generic_getxattr,
903 .setxattr = generic_setxattr,
904 .removexattr = generic_removexattr,
905 .get_acl = nfs3_get_acl, 902 .get_acl = nfs3_get_acl,
906 .set_acl = nfs3_set_acl, 903 .set_acl = nfs3_set_acl,
907#endif 904#endif
@@ -913,9 +910,6 @@ static const struct inode_operations nfs3_file_inode_operations = {
913 .setattr = nfs_setattr, 910 .setattr = nfs_setattr,
914#ifdef CONFIG_NFS_V3_ACL 911#ifdef CONFIG_NFS_V3_ACL
915 .listxattr = nfs3_listxattr, 912 .listxattr = nfs3_listxattr,
916 .getxattr = generic_getxattr,
917 .setxattr = generic_setxattr,
918 .removexattr = generic_removexattr,
919 .get_acl = nfs3_get_acl, 913 .get_acl = nfs3_get_acl,
920 .set_acl = nfs3_set_acl, 914 .set_acl = nfs3_set_acl,
921#endif 915#endif
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index a9dec32ba9ba..0e327528a3ce 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -8941,20 +8941,14 @@ static const struct inode_operations nfs4_dir_inode_operations = {
8941 .permission = nfs_permission, 8941 .permission = nfs_permission,
8942 .getattr = nfs_getattr, 8942 .getattr = nfs_getattr,
8943 .setattr = nfs_setattr, 8943 .setattr = nfs_setattr,
8944 .getxattr = generic_getxattr,
8945 .setxattr = generic_setxattr,
8946 .listxattr = nfs4_listxattr, 8944 .listxattr = nfs4_listxattr,
8947 .removexattr = generic_removexattr,
8948}; 8945};
8949 8946
8950static const struct inode_operations nfs4_file_inode_operations = { 8947static const struct inode_operations nfs4_file_inode_operations = {
8951 .permission = nfs_permission, 8948 .permission = nfs_permission,
8952 .getattr = nfs_getattr, 8949 .getattr = nfs_getattr,
8953 .setattr = nfs_setattr, 8950 .setattr = nfs_setattr,
8954 .getxattr = generic_getxattr,
8955 .setxattr = generic_setxattr,
8956 .listxattr = nfs4_listxattr, 8951 .listxattr = nfs4_listxattr,
8957 .removexattr = generic_removexattr,
8958}; 8952};
8959 8953
8960const struct nfs_rpc_ops nfs_v4_clientops = { 8954const struct nfs_rpc_ops nfs_v4_clientops = {
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 5e1901546868..ba5c177d0ed6 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -2444,10 +2444,7 @@ const struct inode_operations ocfs2_file_iops = {
2444 .setattr = ocfs2_setattr, 2444 .setattr = ocfs2_setattr,
2445 .getattr = ocfs2_getattr, 2445 .getattr = ocfs2_getattr,
2446 .permission = ocfs2_permission, 2446 .permission = ocfs2_permission,
2447 .setxattr = generic_setxattr,
2448 .getxattr = generic_getxattr,
2449 .listxattr = ocfs2_listxattr, 2447 .listxattr = ocfs2_listxattr,
2450 .removexattr = generic_removexattr,
2451 .fiemap = ocfs2_fiemap, 2448 .fiemap = ocfs2_fiemap,
2452 .get_acl = ocfs2_iop_get_acl, 2449 .get_acl = ocfs2_iop_get_acl,
2453 .set_acl = ocfs2_iop_set_acl, 2450 .set_acl = ocfs2_iop_set_acl,
diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c
index a8f1225e6d9b..6cc043ebb9fa 100644
--- a/fs/ocfs2/namei.c
+++ b/fs/ocfs2/namei.c
@@ -2913,10 +2913,7 @@ const struct inode_operations ocfs2_dir_iops = {
2913 .setattr = ocfs2_setattr, 2913 .setattr = ocfs2_setattr,
2914 .getattr = ocfs2_getattr, 2914 .getattr = ocfs2_getattr,
2915 .permission = ocfs2_permission, 2915 .permission = ocfs2_permission,
2916 .setxattr = generic_setxattr,
2917 .getxattr = generic_getxattr,
2918 .listxattr = ocfs2_listxattr, 2916 .listxattr = ocfs2_listxattr,
2919 .removexattr = generic_removexattr,
2920 .fiemap = ocfs2_fiemap, 2917 .fiemap = ocfs2_fiemap,
2921 .get_acl = ocfs2_iop_get_acl, 2918 .get_acl = ocfs2_iop_get_acl,
2922 .set_acl = ocfs2_iop_set_acl, 2919 .set_acl = ocfs2_iop_set_acl,
diff --git a/fs/ocfs2/symlink.c b/fs/ocfs2/symlink.c
index 6c2a3e3c521c..6ad8eecefe21 100644
--- a/fs/ocfs2/symlink.c
+++ b/fs/ocfs2/symlink.c
@@ -91,9 +91,6 @@ const struct inode_operations ocfs2_symlink_inode_operations = {
91 .get_link = page_get_link, 91 .get_link = page_get_link,
92 .getattr = ocfs2_getattr, 92 .getattr = ocfs2_getattr,
93 .setattr = ocfs2_setattr, 93 .setattr = ocfs2_setattr,
94 .setxattr = generic_setxattr,
95 .getxattr = generic_getxattr,
96 .listxattr = ocfs2_listxattr, 94 .listxattr = ocfs2_listxattr,
97 .removexattr = generic_removexattr,
98 .fiemap = ocfs2_fiemap, 95 .fiemap = ocfs2_fiemap,
99}; 96};
diff --git a/fs/orangefs/inode.c b/fs/orangefs/inode.c
index c83846fb9b14..0e3bd7e07f88 100644
--- a/fs/orangefs/inode.c
+++ b/fs/orangefs/inode.c
@@ -296,10 +296,7 @@ const struct inode_operations orangefs_file_inode_operations = {
296 .set_acl = orangefs_set_acl, 296 .set_acl = orangefs_set_acl,
297 .setattr = orangefs_setattr, 297 .setattr = orangefs_setattr,
298 .getattr = orangefs_getattr, 298 .getattr = orangefs_getattr,
299 .setxattr = generic_setxattr,
300 .getxattr = generic_getxattr,
301 .listxattr = orangefs_listxattr, 299 .listxattr = orangefs_listxattr,
302 .removexattr = generic_removexattr,
303 .permission = orangefs_permission, 300 .permission = orangefs_permission,
304}; 301};
305 302
diff --git a/fs/orangefs/namei.c b/fs/orangefs/namei.c
index 0e34fcfa4d51..4d5576a21c82 100644
--- a/fs/orangefs/namei.c
+++ b/fs/orangefs/namei.c
@@ -462,9 +462,6 @@ const struct inode_operations orangefs_dir_inode_operations = {
462 .rename = orangefs_rename, 462 .rename = orangefs_rename,
463 .setattr = orangefs_setattr, 463 .setattr = orangefs_setattr,
464 .getattr = orangefs_getattr, 464 .getattr = orangefs_getattr,
465 .setxattr = generic_setxattr,
466 .getxattr = generic_getxattr,
467 .removexattr = generic_removexattr,
468 .listxattr = orangefs_listxattr, 465 .listxattr = orangefs_listxattr,
469 .permission = orangefs_permission, 466 .permission = orangefs_permission,
470}; 467};
diff --git a/fs/orangefs/symlink.c b/fs/orangefs/symlink.c
index 8fecf823f5ba..10b0b06e075e 100644
--- a/fs/orangefs/symlink.c
+++ b/fs/orangefs/symlink.c
@@ -14,6 +14,5 @@ const struct inode_operations orangefs_symlink_inode_operations = {
14 .setattr = orangefs_setattr, 14 .setattr = orangefs_setattr,
15 .getattr = orangefs_getattr, 15 .getattr = orangefs_getattr,
16 .listxattr = orangefs_listxattr, 16 .listxattr = orangefs_listxattr,
17 .setxattr = generic_setxattr,
18 .permission = orangefs_permission, 17 .permission = orangefs_permission,
19}; 18};
diff --git a/fs/orangefs/xattr.c b/fs/orangefs/xattr.c
index 2a9f07f06d10..74a81b1daaac 100644
--- a/fs/orangefs/xattr.c
+++ b/fs/orangefs/xattr.c
@@ -73,6 +73,9 @@ ssize_t orangefs_inode_getxattr(struct inode *inode, const char *name,
73 "%s: name %s, buffer_size %zd\n", 73 "%s: name %s, buffer_size %zd\n",
74 __func__, name, size); 74 __func__, name, size);
75 75
76 if (S_ISLNK(inode->i_mode))
77 return -EOPNOTSUPP;
78
76 if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN) { 79 if (strlen(name) >= ORANGEFS_MAX_XATTR_NAMELEN) {
77 gossip_err("Invalid key length (%d)\n", 80 gossip_err("Invalid key length (%d)\n",
78 (int)strlen(name)); 81 (int)strlen(name));
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
index db37a0e02d32..3f803b3a1f82 100644
--- a/fs/overlayfs/copy_up.c
+++ b/fs/overlayfs/copy_up.c
@@ -58,8 +58,8 @@ int ovl_copy_xattr(struct dentry *old, struct dentry *new)
58 char *buf, *name, *value = NULL; 58 char *buf, *name, *value = NULL;
59 int uninitialized_var(error); 59 int uninitialized_var(error);
60 60
61 if (!old->d_inode->i_op->getxattr || 61 if (!(old->d_inode->i_opflags & IOP_XATTR) ||
62 !new->d_inode->i_op->getxattr) 62 !(new->d_inode->i_opflags & IOP_XATTR))
63 return 0; 63 return 0;
64 64
65 list_size = vfs_listxattr(old, NULL, 0); 65 list_size = vfs_listxattr(old, NULL, 0);
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index b0ffa1d1677e..3a60e68ec965 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -1013,10 +1013,7 @@ const struct inode_operations ovl_dir_inode_operations = {
1013 .mknod = ovl_mknod, 1013 .mknod = ovl_mknod,
1014 .permission = ovl_permission, 1014 .permission = ovl_permission,
1015 .getattr = ovl_dir_getattr, 1015 .getattr = ovl_dir_getattr,
1016 .setxattr = generic_setxattr,
1017 .getxattr = generic_getxattr,
1018 .listxattr = ovl_listxattr, 1016 .listxattr = ovl_listxattr,
1019 .removexattr = generic_removexattr,
1020 .get_acl = ovl_get_acl, 1017 .get_acl = ovl_get_acl,
1021 .update_time = ovl_update_time, 1018 .update_time = ovl_update_time,
1022}; 1019};
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index 251e5253f2c1..c18d6a4ff456 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -367,10 +367,7 @@ static const struct inode_operations ovl_file_inode_operations = {
367 .setattr = ovl_setattr, 367 .setattr = ovl_setattr,
368 .permission = ovl_permission, 368 .permission = ovl_permission,
369 .getattr = ovl_getattr, 369 .getattr = ovl_getattr,
370 .setxattr = generic_setxattr,
371 .getxattr = generic_getxattr,
372 .listxattr = ovl_listxattr, 370 .listxattr = ovl_listxattr,
373 .removexattr = generic_removexattr,
374 .get_acl = ovl_get_acl, 371 .get_acl = ovl_get_acl,
375 .update_time = ovl_update_time, 372 .update_time = ovl_update_time,
376}; 373};
@@ -380,10 +377,7 @@ static const struct inode_operations ovl_symlink_inode_operations = {
380 .get_link = ovl_get_link, 377 .get_link = ovl_get_link,
381 .readlink = ovl_readlink, 378 .readlink = ovl_readlink,
382 .getattr = ovl_getattr, 379 .getattr = ovl_getattr,
383 .setxattr = generic_setxattr,
384 .getxattr = generic_getxattr,
385 .listxattr = ovl_listxattr, 380 .listxattr = ovl_listxattr,
386 .removexattr = generic_removexattr,
387 .update_time = ovl_update_time, 381 .update_time = ovl_update_time,
388}; 382};
389 383
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index 3d0b9dee2b76..7e3f0127fc1a 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -275,10 +275,10 @@ static bool ovl_is_opaquedir(struct dentry *dentry)
275 char val; 275 char val;
276 struct inode *inode = dentry->d_inode; 276 struct inode *inode = dentry->d_inode;
277 277
278 if (!S_ISDIR(inode->i_mode) || !inode->i_op->getxattr) 278 if (!S_ISDIR(inode->i_mode) || !(inode->i_opflags & IOP_XATTR))
279 return false; 279 return false;
280 280
281 res = inode->i_op->getxattr(dentry, inode, OVL_XATTR_OPAQUE, &val, 1); 281 res = __vfs_getxattr(dentry, inode, OVL_XATTR_OPAQUE, &val, 1);
282 if (res == 1 && val == 'y') 282 if (res == 1 && val == 'y')
283 return true; 283 return true;
284 284
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c
index 90f815bdfa8a..2f8c5c9bdaf6 100644
--- a/fs/reiserfs/file.c
+++ b/fs/reiserfs/file.c
@@ -260,10 +260,7 @@ const struct file_operations reiserfs_file_operations = {
260 260
261const struct inode_operations reiserfs_file_inode_operations = { 261const struct inode_operations reiserfs_file_inode_operations = {
262 .setattr = reiserfs_setattr, 262 .setattr = reiserfs_setattr,
263 .setxattr = generic_setxattr,
264 .getxattr = generic_getxattr,
265 .listxattr = reiserfs_listxattr, 263 .listxattr = reiserfs_listxattr,
266 .removexattr = generic_removexattr,
267 .permission = reiserfs_permission, 264 .permission = reiserfs_permission,
268 .get_acl = reiserfs_get_acl, 265 .get_acl = reiserfs_get_acl,
269 .set_acl = reiserfs_set_acl, 266 .set_acl = reiserfs_set_acl,
diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c
index 8a36696d6df9..fd7d0606aa96 100644
--- a/fs/reiserfs/namei.c
+++ b/fs/reiserfs/namei.c
@@ -1650,10 +1650,7 @@ const struct inode_operations reiserfs_dir_inode_operations = {
1650 .mknod = reiserfs_mknod, 1650 .mknod = reiserfs_mknod,
1651 .rename = reiserfs_rename, 1651 .rename = reiserfs_rename,
1652 .setattr = reiserfs_setattr, 1652 .setattr = reiserfs_setattr,
1653 .setxattr = generic_setxattr,
1654 .getxattr = generic_getxattr,
1655 .listxattr = reiserfs_listxattr, 1653 .listxattr = reiserfs_listxattr,
1656 .removexattr = generic_removexattr,
1657 .permission = reiserfs_permission, 1654 .permission = reiserfs_permission,
1658 .get_acl = reiserfs_get_acl, 1655 .get_acl = reiserfs_get_acl,
1659 .set_acl = reiserfs_set_acl, 1656 .set_acl = reiserfs_set_acl,
@@ -1667,10 +1664,7 @@ const struct inode_operations reiserfs_symlink_inode_operations = {
1667 .readlink = generic_readlink, 1664 .readlink = generic_readlink,
1668 .get_link = page_get_link, 1665 .get_link = page_get_link,
1669 .setattr = reiserfs_setattr, 1666 .setattr = reiserfs_setattr,
1670 .setxattr = generic_setxattr,
1671 .getxattr = generic_getxattr,
1672 .listxattr = reiserfs_listxattr, 1667 .listxattr = reiserfs_listxattr,
1673 .removexattr = generic_removexattr,
1674 .permission = reiserfs_permission, 1668 .permission = reiserfs_permission,
1675}; 1669};
1676 1670
@@ -1679,10 +1673,7 @@ const struct inode_operations reiserfs_symlink_inode_operations = {
1679 */ 1673 */
1680const struct inode_operations reiserfs_special_inode_operations = { 1674const struct inode_operations reiserfs_special_inode_operations = {
1681 .setattr = reiserfs_setattr, 1675 .setattr = reiserfs_setattr,
1682 .setxattr = generic_setxattr,
1683 .getxattr = generic_getxattr,
1684 .listxattr = reiserfs_listxattr, 1676 .listxattr = reiserfs_listxattr,
1685 .removexattr = generic_removexattr,
1686 .permission = reiserfs_permission, 1677 .permission = reiserfs_permission,
1687 .get_acl = reiserfs_get_acl, 1678 .get_acl = reiserfs_get_acl,
1688 .set_acl = reiserfs_set_acl, 1679 .set_acl = reiserfs_set_acl,
diff --git a/fs/squashfs/inode.c b/fs/squashfs/inode.c
index 0927b1e80ab6..e9793b1e49a5 100644
--- a/fs/squashfs/inode.c
+++ b/fs/squashfs/inode.c
@@ -425,7 +425,6 @@ failed_read:
425 425
426 426
427const struct inode_operations squashfs_inode_ops = { 427const struct inode_operations squashfs_inode_ops = {
428 .getxattr = generic_getxattr,
429 .listxattr = squashfs_listxattr 428 .listxattr = squashfs_listxattr
430}; 429};
431 430
diff --git a/fs/squashfs/namei.c b/fs/squashfs/namei.c
index 67cad77fefb4..40c10d9974c9 100644
--- a/fs/squashfs/namei.c
+++ b/fs/squashfs/namei.c
@@ -247,6 +247,5 @@ failed:
247 247
248const struct inode_operations squashfs_dir_inode_ops = { 248const struct inode_operations squashfs_dir_inode_ops = {
249 .lookup = squashfs_lookup, 249 .lookup = squashfs_lookup,
250 .getxattr = generic_getxattr,
251 .listxattr = squashfs_listxattr 250 .listxattr = squashfs_listxattr
252}; 251};
diff --git a/fs/squashfs/symlink.c b/fs/squashfs/symlink.c
index d688ef42a6a1..79b9c31a0c8f 100644
--- a/fs/squashfs/symlink.c
+++ b/fs/squashfs/symlink.c
@@ -120,7 +120,6 @@ const struct address_space_operations squashfs_symlink_aops = {
120const struct inode_operations squashfs_symlink_inode_ops = { 120const struct inode_operations squashfs_symlink_inode_ops = {
121 .readlink = generic_readlink, 121 .readlink = generic_readlink,
122 .get_link = page_get_link, 122 .get_link = page_get_link,
123 .getxattr = generic_getxattr,
124 .listxattr = squashfs_listxattr 123 .listxattr = squashfs_listxattr
125}; 124};
126 125
diff --git a/fs/squashfs/xattr.h b/fs/squashfs/xattr.h
index c83f5d9ec125..afe70f815e3d 100644
--- a/fs/squashfs/xattr.h
+++ b/fs/squashfs/xattr.h
@@ -42,6 +42,5 @@ static inline int squashfs_xattr_lookup(struct super_block *sb,
42 return 0; 42 return 0;
43} 43}
44#define squashfs_listxattr NULL 44#define squashfs_listxattr NULL
45#define generic_getxattr NULL
46#define squashfs_xattr_handlers NULL 45#define squashfs_xattr_handlers NULL
47#endif 46#endif
diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c
index 4b86d3a738e1..1d55aeaebf23 100644
--- a/fs/ubifs/dir.c
+++ b/fs/ubifs/dir.c
@@ -1182,10 +1182,7 @@ const struct inode_operations ubifs_dir_inode_operations = {
1182 .rename = ubifs_rename, 1182 .rename = ubifs_rename,
1183 .setattr = ubifs_setattr, 1183 .setattr = ubifs_setattr,
1184 .getattr = ubifs_getattr, 1184 .getattr = ubifs_getattr,
1185 .setxattr = generic_setxattr,
1186 .getxattr = generic_getxattr,
1187 .listxattr = ubifs_listxattr, 1185 .listxattr = ubifs_listxattr,
1188 .removexattr = generic_removexattr,
1189#ifdef CONFIG_UBIFS_ATIME_SUPPORT 1186#ifdef CONFIG_UBIFS_ATIME_SUPPORT
1190 .update_time = ubifs_update_time, 1187 .update_time = ubifs_update_time,
1191#endif 1188#endif
diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c
index b0a6a53263f3..a746982fbcda 100644
--- a/fs/ubifs/file.c
+++ b/fs/ubifs/file.c
@@ -1621,10 +1621,7 @@ const struct address_space_operations ubifs_file_address_operations = {
1621const struct inode_operations ubifs_file_inode_operations = { 1621const struct inode_operations ubifs_file_inode_operations = {
1622 .setattr = ubifs_setattr, 1622 .setattr = ubifs_setattr,
1623 .getattr = ubifs_getattr, 1623 .getattr = ubifs_getattr,
1624 .setxattr = generic_setxattr,
1625 .getxattr = generic_getxattr,
1626 .listxattr = ubifs_listxattr, 1624 .listxattr = ubifs_listxattr,
1627 .removexattr = generic_removexattr,
1628#ifdef CONFIG_UBIFS_ATIME_SUPPORT 1625#ifdef CONFIG_UBIFS_ATIME_SUPPORT
1629 .update_time = ubifs_update_time, 1626 .update_time = ubifs_update_time,
1630#endif 1627#endif
@@ -1635,10 +1632,7 @@ const struct inode_operations ubifs_symlink_inode_operations = {
1635 .get_link = simple_get_link, 1632 .get_link = simple_get_link,
1636 .setattr = ubifs_setattr, 1633 .setattr = ubifs_setattr,
1637 .getattr = ubifs_getattr, 1634 .getattr = ubifs_getattr,
1638 .setxattr = generic_setxattr,
1639 .getxattr = generic_getxattr,
1640 .listxattr = ubifs_listxattr, 1635 .listxattr = ubifs_listxattr,
1641 .removexattr = generic_removexattr,
1642#ifdef CONFIG_UBIFS_ATIME_SUPPORT 1636#ifdef CONFIG_UBIFS_ATIME_SUPPORT
1643 .update_time = ubifs_update_time, 1637 .update_time = ubifs_update_time,
1644#endif 1638#endif
diff --git a/fs/xattr.c b/fs/xattr.c
index c243905835ab..3368659c471e 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -24,6 +24,59 @@
24 24
25#include <asm/uaccess.h> 25#include <asm/uaccess.h>
26 26
27static const char *
28strcmp_prefix(const char *a, const char *a_prefix)
29{
30 while (*a_prefix && *a == *a_prefix) {
31 a++;
32 a_prefix++;
33 }
34 return *a_prefix ? NULL : a;
35}
36
37/*
38 * In order to implement different sets of xattr operations for each xattr
39 * prefix, a filesystem should create a null-terminated array of struct
40 * xattr_handler (one for each prefix) and hang a pointer to it off of the
41 * s_xattr field of the superblock.
42 */
43#define for_each_xattr_handler(handlers, handler) \
44 if (handlers) \
45 for ((handler) = *(handlers)++; \
46 (handler) != NULL; \
47 (handler) = *(handlers)++)
48
49/*
50 * Find the xattr_handler with the matching prefix.
51 */
52static const struct xattr_handler *
53xattr_resolve_name(struct inode *inode, const char **name)
54{
55 const struct xattr_handler **handlers = inode->i_sb->s_xattr;
56 const struct xattr_handler *handler;
57
58 if (!(inode->i_opflags & IOP_XATTR)) {
59 if (unlikely(is_bad_inode(inode)))
60 return ERR_PTR(-EIO);
61 return ERR_PTR(-EOPNOTSUPP);
62 }
63 for_each_xattr_handler(handlers, handler) {
64 const char *n;
65
66 n = strcmp_prefix(*name, xattr_prefix(handler));
67 if (n) {
68 if (!handler->prefix ^ !*n) {
69 if (*n)
70 continue;
71 return ERR_PTR(-EINVAL);
72 }
73 *name = n;
74 return handler;
75 }
76 }
77 return ERR_PTR(-EOPNOTSUPP);
78}
79
27/* 80/*
28 * Check permissions for extended attribute access. This is a bit complicated 81 * Check permissions for extended attribute access. This is a bit complicated
29 * because different namespaces have very different rules. 82 * because different namespaces have very different rules.
@@ -80,6 +133,23 @@ xattr_permission(struct inode *inode, const char *name, int mask)
80 return inode_permission(inode, mask); 133 return inode_permission(inode, mask);
81} 134}
82 135
136int
137__vfs_setxattr(struct dentry *dentry, struct inode *inode, const char *name,
138 const void *value, size_t size, int flags)
139{
140 const struct xattr_handler *handler;
141
142 handler = xattr_resolve_name(inode, &name);
143 if (IS_ERR(handler))
144 return PTR_ERR(handler);
145 if (!handler->set)
146 return -EOPNOTSUPP;
147 if (size == 0)
148 value = ""; /* empty EA, do not remove */
149 return handler->set(handler, dentry, inode, name, value, size, flags);
150}
151EXPORT_SYMBOL(__vfs_setxattr);
152
83/** 153/**
84 * __vfs_setxattr_noperm - perform setxattr operation without performing 154 * __vfs_setxattr_noperm - perform setxattr operation without performing
85 * permission checks. 155 * permission checks.
@@ -106,8 +176,8 @@ int __vfs_setxattr_noperm(struct dentry *dentry, const char *name,
106 176
107 if (issec) 177 if (issec)
108 inode->i_flags &= ~S_NOSEC; 178 inode->i_flags &= ~S_NOSEC;
109 if (inode->i_op->setxattr) { 179 if (inode->i_opflags & IOP_XATTR) {
110 error = inode->i_op->setxattr(dentry, inode, name, value, size, flags); 180 error = __vfs_setxattr(dentry, inode, name, value, size, flags);
111 if (!error) { 181 if (!error) {
112 fsnotify_xattr(dentry); 182 fsnotify_xattr(dentry);
113 security_inode_post_setxattr(dentry, name, value, 183 security_inode_post_setxattr(dentry, name, value,
@@ -115,6 +185,9 @@ int __vfs_setxattr_noperm(struct dentry *dentry, const char *name,
115 } 185 }
116 } else if (issec) { 186 } else if (issec) {
117 const char *suffix = name + XATTR_SECURITY_PREFIX_LEN; 187 const char *suffix = name + XATTR_SECURITY_PREFIX_LEN;
188
189 if (unlikely(is_bad_inode(inode)))
190 return -EIO;
118 error = security_inode_setsecurity(inode, suffix, value, 191 error = security_inode_setsecurity(inode, suffix, value,
119 size, flags); 192 size, flags);
120 if (!error) 193 if (!error)
@@ -188,6 +261,7 @@ ssize_t
188vfs_getxattr_alloc(struct dentry *dentry, const char *name, char **xattr_value, 261vfs_getxattr_alloc(struct dentry *dentry, const char *name, char **xattr_value,
189 size_t xattr_size, gfp_t flags) 262 size_t xattr_size, gfp_t flags)
190{ 263{
264 const struct xattr_handler *handler;
191 struct inode *inode = dentry->d_inode; 265 struct inode *inode = dentry->d_inode;
192 char *value = *xattr_value; 266 char *value = *xattr_value;
193 int error; 267 int error;
@@ -196,10 +270,12 @@ vfs_getxattr_alloc(struct dentry *dentry, const char *name, char **xattr_value,
196 if (error) 270 if (error)
197 return error; 271 return error;
198 272
199 if (!inode->i_op->getxattr) 273 handler = xattr_resolve_name(inode, &name);
274 if (IS_ERR(handler))
275 return PTR_ERR(handler);
276 if (!handler->get)
200 return -EOPNOTSUPP; 277 return -EOPNOTSUPP;
201 278 error = handler->get(handler, dentry, inode, name, NULL, 0);
202 error = inode->i_op->getxattr(dentry, inode, name, NULL, 0);
203 if (error < 0) 279 if (error < 0)
204 return error; 280 return error;
205 281
@@ -210,12 +286,27 @@ vfs_getxattr_alloc(struct dentry *dentry, const char *name, char **xattr_value,
210 memset(value, 0, error + 1); 286 memset(value, 0, error + 1);
211 } 287 }
212 288
213 error = inode->i_op->getxattr(dentry, inode, name, value, error); 289 error = handler->get(handler, dentry, inode, name, value, error);
214 *xattr_value = value; 290 *xattr_value = value;
215 return error; 291 return error;
216} 292}
217 293
218ssize_t 294ssize_t
295__vfs_getxattr(struct dentry *dentry, struct inode *inode, const char *name,
296 void *value, size_t size)
297{
298 const struct xattr_handler *handler;
299
300 handler = xattr_resolve_name(inode, &name);
301 if (IS_ERR(handler))
302 return PTR_ERR(handler);
303 if (!handler->get)
304 return -EOPNOTSUPP;
305 return handler->get(handler, dentry, inode, name, value, size);
306}
307EXPORT_SYMBOL(__vfs_getxattr);
308
309ssize_t
219vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size) 310vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size)
220{ 311{
221 struct inode *inode = dentry->d_inode; 312 struct inode *inode = dentry->d_inode;
@@ -242,28 +333,24 @@ vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size)
242 return ret; 333 return ret;
243 } 334 }
244nolsm: 335nolsm:
245 if (inode->i_op->getxattr) 336 return __vfs_getxattr(dentry, inode, name, value, size);
246 error = inode->i_op->getxattr(dentry, inode, name, value, size);
247 else
248 error = -EOPNOTSUPP;
249
250 return error;
251} 337}
252EXPORT_SYMBOL_GPL(vfs_getxattr); 338EXPORT_SYMBOL_GPL(vfs_getxattr);
253 339
254ssize_t 340ssize_t
255vfs_listxattr(struct dentry *d, char *list, size_t size) 341vfs_listxattr(struct dentry *dentry, char *list, size_t size)
256{ 342{
343 struct inode *inode = d_inode(dentry);
257 ssize_t error; 344 ssize_t error;
258 345
259 error = security_inode_listxattr(d); 346 error = security_inode_listxattr(dentry);
260 if (error) 347 if (error)
261 return error; 348 return error;
262 error = -EOPNOTSUPP; 349 if (inode->i_op->listxattr && (inode->i_opflags & IOP_XATTR)) {
263 if (d->d_inode->i_op->listxattr) { 350 error = -EOPNOTSUPP;
264 error = d->d_inode->i_op->listxattr(d, list, size); 351 error = inode->i_op->listxattr(dentry, list, size);
265 } else { 352 } else {
266 error = security_inode_listsecurity(d->d_inode, list, size); 353 error = security_inode_listsecurity(inode, list, size);
267 if (size && error > size) 354 if (size && error > size)
268 error = -ERANGE; 355 error = -ERANGE;
269 } 356 }
@@ -272,14 +359,26 @@ vfs_listxattr(struct dentry *d, char *list, size_t size)
272EXPORT_SYMBOL_GPL(vfs_listxattr); 359EXPORT_SYMBOL_GPL(vfs_listxattr);
273 360
274int 361int
362__vfs_removexattr(struct dentry *dentry, const char *name)
363{
364 struct inode *inode = d_inode(dentry);
365 const struct xattr_handler *handler;
366
367 handler = xattr_resolve_name(inode, &name);
368 if (IS_ERR(handler))
369 return PTR_ERR(handler);
370 if (!handler->set)
371 return -EOPNOTSUPP;
372 return handler->set(handler, dentry, inode, name, NULL, 0, XATTR_REPLACE);
373}
374EXPORT_SYMBOL(__vfs_removexattr);
375
376int
275vfs_removexattr(struct dentry *dentry, const char *name) 377vfs_removexattr(struct dentry *dentry, const char *name)
276{ 378{
277 struct inode *inode = dentry->d_inode; 379 struct inode *inode = dentry->d_inode;
278 int error; 380 int error;
279 381
280 if (!inode->i_op->removexattr)
281 return -EOPNOTSUPP;
282
283 error = xattr_permission(inode, name, MAY_WRITE); 382 error = xattr_permission(inode, name, MAY_WRITE);
284 if (error) 383 if (error)
285 return error; 384 return error;
@@ -289,7 +388,7 @@ vfs_removexattr(struct dentry *dentry, const char *name)
289 if (error) 388 if (error)
290 goto out; 389 goto out;
291 390
292 error = inode->i_op->removexattr(dentry, name); 391 error = __vfs_removexattr(dentry, name);
293 392
294 if (!error) { 393 if (!error) {
295 fsnotify_xattr(dentry); 394 fsnotify_xattr(dentry);
@@ -641,76 +740,6 @@ SYSCALL_DEFINE2(fremovexattr, int, fd, const char __user *, name)
641 return error; 740 return error;
642} 741}
643 742
644
645static const char *
646strcmp_prefix(const char *a, const char *a_prefix)
647{
648 while (*a_prefix && *a == *a_prefix) {
649 a++;
650 a_prefix++;
651 }
652 return *a_prefix ? NULL : a;
653}
654
655/*
656 * In order to implement different sets of xattr operations for each xattr
657 * prefix with the generic xattr API, a filesystem should create a
658 * null-terminated array of struct xattr_handler (one for each prefix) and
659 * hang a pointer to it off of the s_xattr field of the superblock.
660 *
661 * The generic_fooxattr() functions will use this list to dispatch xattr
662 * operations to the correct xattr_handler.
663 */
664#define for_each_xattr_handler(handlers, handler) \
665 if (handlers) \
666 for ((handler) = *(handlers)++; \
667 (handler) != NULL; \
668 (handler) = *(handlers)++)
669
670/*
671 * Find the xattr_handler with the matching prefix.
672 */
673static const struct xattr_handler *
674xattr_resolve_name(const struct xattr_handler **handlers, const char **name)
675{
676 const struct xattr_handler *handler;
677
678 if (!*name)
679 return ERR_PTR(-EINVAL);
680
681 for_each_xattr_handler(handlers, handler) {
682 const char *n;
683
684 n = strcmp_prefix(*name, xattr_prefix(handler));
685 if (n) {
686 if (!handler->prefix ^ !*n) {
687 if (*n)
688 continue;
689 return ERR_PTR(-EINVAL);
690 }
691 *name = n;
692 return handler;
693 }
694 }
695 return ERR_PTR(-EOPNOTSUPP);
696}
697
698/*
699 * Find the handler for the prefix and dispatch its get() operation.
700 */
701ssize_t
702generic_getxattr(struct dentry *dentry, struct inode *inode,
703 const char *name, void *buffer, size_t size)
704{
705 const struct xattr_handler *handler;
706
707 handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name);
708 if (IS_ERR(handler))
709 return PTR_ERR(handler);
710 return handler->get(handler, dentry, inode,
711 name, buffer, size);
712}
713
714/* 743/*
715 * Combine the results of the list() operation from every xattr_handler in the 744 * Combine the results of the list() operation from every xattr_handler in the
716 * list. 745 * list.
@@ -747,44 +776,7 @@ generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
747 } 776 }
748 return size; 777 return size;
749} 778}
750
751/*
752 * Find the handler for the prefix and dispatch its set() operation.
753 */
754int
755generic_setxattr(struct dentry *dentry, struct inode *inode, const char *name,
756 const void *value, size_t size, int flags)
757{
758 const struct xattr_handler *handler;
759
760 if (size == 0)
761 value = ""; /* empty EA, do not remove */
762 handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name);
763 if (IS_ERR(handler))
764 return PTR_ERR(handler);
765 return handler->set(handler, dentry, inode, name, value, size, flags);
766}
767
768/*
769 * Find the handler for the prefix and dispatch its set() operation to remove
770 * any associated extended attribute.
771 */
772int
773generic_removexattr(struct dentry *dentry, const char *name)
774{
775 const struct xattr_handler *handler;
776
777 handler = xattr_resolve_name(dentry->d_sb->s_xattr, &name);
778 if (IS_ERR(handler))
779 return PTR_ERR(handler);
780 return handler->set(handler, dentry, d_inode(dentry), name, NULL,
781 0, XATTR_REPLACE);
782}
783
784EXPORT_SYMBOL(generic_getxattr);
785EXPORT_SYMBOL(generic_listxattr); 779EXPORT_SYMBOL(generic_listxattr);
786EXPORT_SYMBOL(generic_setxattr);
787EXPORT_SYMBOL(generic_removexattr);
788 780
789/** 781/**
790 * xattr_full_name - Compute full attribute name from suffix 782 * xattr_full_name - Compute full attribute name from suffix
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index ba99803eba98..a7404c5aafe2 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -1066,9 +1066,6 @@ static const struct inode_operations xfs_inode_operations = {
1066 .set_acl = xfs_set_acl, 1066 .set_acl = xfs_set_acl,
1067 .getattr = xfs_vn_getattr, 1067 .getattr = xfs_vn_getattr,
1068 .setattr = xfs_vn_setattr, 1068 .setattr = xfs_vn_setattr,
1069 .setxattr = generic_setxattr,
1070 .getxattr = generic_getxattr,
1071 .removexattr = generic_removexattr,
1072 .listxattr = xfs_vn_listxattr, 1069 .listxattr = xfs_vn_listxattr,
1073 .fiemap = xfs_vn_fiemap, 1070 .fiemap = xfs_vn_fiemap,
1074 .update_time = xfs_vn_update_time, 1071 .update_time = xfs_vn_update_time,
@@ -1094,9 +1091,6 @@ static const struct inode_operations xfs_dir_inode_operations = {
1094 .set_acl = xfs_set_acl, 1091 .set_acl = xfs_set_acl,
1095 .getattr = xfs_vn_getattr, 1092 .getattr = xfs_vn_getattr,
1096 .setattr = xfs_vn_setattr, 1093 .setattr = xfs_vn_setattr,
1097 .setxattr = generic_setxattr,
1098 .getxattr = generic_getxattr,
1099 .removexattr = generic_removexattr,
1100 .listxattr = xfs_vn_listxattr, 1094 .listxattr = xfs_vn_listxattr,
1101 .update_time = xfs_vn_update_time, 1095 .update_time = xfs_vn_update_time,
1102 .tmpfile = xfs_vn_tmpfile, 1096 .tmpfile = xfs_vn_tmpfile,
@@ -1122,9 +1116,6 @@ static const struct inode_operations xfs_dir_ci_inode_operations = {
1122 .set_acl = xfs_set_acl, 1116 .set_acl = xfs_set_acl,
1123 .getattr = xfs_vn_getattr, 1117 .getattr = xfs_vn_getattr,
1124 .setattr = xfs_vn_setattr, 1118 .setattr = xfs_vn_setattr,
1125 .setxattr = generic_setxattr,
1126 .getxattr = generic_getxattr,
1127 .removexattr = generic_removexattr,
1128 .listxattr = xfs_vn_listxattr, 1119 .listxattr = xfs_vn_listxattr,
1129 .update_time = xfs_vn_update_time, 1120 .update_time = xfs_vn_update_time,
1130 .tmpfile = xfs_vn_tmpfile, 1121 .tmpfile = xfs_vn_tmpfile,
@@ -1135,9 +1126,6 @@ static const struct inode_operations xfs_symlink_inode_operations = {
1135 .get_link = xfs_vn_get_link, 1126 .get_link = xfs_vn_get_link,
1136 .getattr = xfs_vn_getattr, 1127 .getattr = xfs_vn_getattr,
1137 .setattr = xfs_vn_setattr, 1128 .setattr = xfs_vn_setattr,
1138 .setxattr = generic_setxattr,
1139 .getxattr = generic_getxattr,
1140 .removexattr = generic_removexattr,
1141 .listxattr = xfs_vn_listxattr, 1129 .listxattr = xfs_vn_listxattr,
1142 .update_time = xfs_vn_update_time, 1130 .update_time = xfs_vn_update_time,
1143}; 1131};
@@ -1147,9 +1135,6 @@ static const struct inode_operations xfs_inline_symlink_inode_operations = {
1147 .get_link = xfs_vn_get_link_inline, 1135 .get_link = xfs_vn_get_link_inline,
1148 .getattr = xfs_vn_getattr, 1136 .getattr = xfs_vn_getattr,
1149 .setattr = xfs_vn_setattr, 1137 .setattr = xfs_vn_setattr,
1150 .setxattr = generic_setxattr,
1151 .getxattr = generic_getxattr,
1152 .removexattr = generic_removexattr,
1153 .listxattr = xfs_vn_listxattr, 1138 .listxattr = xfs_vn_listxattr,
1154 .update_time = xfs_vn_update_time, 1139 .update_time = xfs_vn_update_time,
1155}; 1140};
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 4ba5957ae089..7e09f5926b3b 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -592,6 +592,7 @@ is_uncached_acl(struct posix_acl *acl)
592#define IOP_FASTPERM 0x0001 592#define IOP_FASTPERM 0x0001
593#define IOP_LOOKUP 0x0002 593#define IOP_LOOKUP 0x0002
594#define IOP_NOFOLLOW 0x0004 594#define IOP_NOFOLLOW 0x0004
595#define IOP_XATTR 0x0008
595 596
596/* 597/*
597 * Keep mostly read-only and often accessed (especially for 598 * Keep mostly read-only and often accessed (especially for
@@ -1751,12 +1752,7 @@ struct inode_operations {
1751 struct inode *, struct dentry *, unsigned int); 1752 struct inode *, struct dentry *, unsigned int);
1752 int (*setattr) (struct dentry *, struct iattr *); 1753 int (*setattr) (struct dentry *, struct iattr *);
1753 int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *); 1754 int (*getattr) (struct vfsmount *mnt, struct dentry *, struct kstat *);
1754 int (*setxattr) (struct dentry *, struct inode *,
1755 const char *, const void *, size_t, int);
1756 ssize_t (*getxattr) (struct dentry *, struct inode *,
1757 const char *, void *, size_t);
1758 ssize_t (*listxattr) (struct dentry *, char *, size_t); 1755 ssize_t (*listxattr) (struct dentry *, char *, size_t);
1759 int (*removexattr) (struct dentry *, const char *);
1760 int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, 1756 int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start,
1761 u64 len); 1757 u64 len);
1762 int (*update_time)(struct inode *, struct timespec *, int); 1758 int (*update_time)(struct inode *, struct timespec *, int);
@@ -2087,10 +2083,19 @@ struct super_block *sget(struct file_system_type *type,
2087 int (*test)(struct super_block *,void *), 2083 int (*test)(struct super_block *,void *),
2088 int (*set)(struct super_block *,void *), 2084 int (*set)(struct super_block *,void *),
2089 int flags, void *data); 2085 int flags, void *data);
2090extern struct dentry *mount_pseudo(struct file_system_type *, char *, 2086extern struct dentry *mount_pseudo_xattr(struct file_system_type *, char *,
2091 const struct super_operations *ops, 2087 const struct super_operations *ops,
2092 const struct dentry_operations *dops, 2088 const struct xattr_handler **xattr,
2093 unsigned long); 2089 const struct dentry_operations *dops,
2090 unsigned long);
2091
2092static inline struct dentry *
2093mount_pseudo(struct file_system_type *fs_type, char *name,
2094 const struct super_operations *ops,
2095 const struct dentry_operations *dops, unsigned long magic)
2096{
2097 return mount_pseudo_xattr(fs_type, name, ops, NULL, dops, magic);
2098}
2094 2099
2095/* Alas, no aliases. Too much hassle with bringing module.h everywhere */ 2100/* Alas, no aliases. Too much hassle with bringing module.h everywhere */
2096#define fops_get(fops) \ 2101#define fops_get(fops) \
diff --git a/include/linux/xattr.h b/include/linux/xattr.h
index 94079bab9243..e77605a0c8da 100644
--- a/include/linux/xattr.h
+++ b/include/linux/xattr.h
@@ -46,17 +46,16 @@ struct xattr {
46}; 46};
47 47
48ssize_t xattr_getsecurity(struct inode *, const char *, void *, size_t); 48ssize_t xattr_getsecurity(struct inode *, const char *, void *, size_t);
49ssize_t __vfs_getxattr(struct dentry *, struct inode *, const char *, void *, size_t);
49ssize_t vfs_getxattr(struct dentry *, const char *, void *, size_t); 50ssize_t vfs_getxattr(struct dentry *, const char *, void *, size_t);
50ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size); 51ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size);
52int __vfs_setxattr(struct dentry *, struct inode *, const char *, const void *, size_t, int);
51int __vfs_setxattr_noperm(struct dentry *, const char *, const void *, size_t, int); 53int __vfs_setxattr_noperm(struct dentry *, const char *, const void *, size_t, int);
52int vfs_setxattr(struct dentry *, const char *, const void *, size_t, int); 54int vfs_setxattr(struct dentry *, const char *, const void *, size_t, int);
55int __vfs_removexattr(struct dentry *, const char *);
53int vfs_removexattr(struct dentry *, const char *); 56int vfs_removexattr(struct dentry *, const char *);
54 57
55ssize_t generic_getxattr(struct dentry *dentry, struct inode *inode, const char *name, void *buffer, size_t size);
56ssize_t generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size); 58ssize_t generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size);
57int generic_setxattr(struct dentry *dentry, struct inode *inode,
58 const char *name, const void *value, size_t size, int flags);
59int generic_removexattr(struct dentry *dentry, const char *name);
60ssize_t vfs_getxattr_alloc(struct dentry *dentry, const char *name, 59ssize_t vfs_getxattr_alloc(struct dentry *dentry, const char *name,
61 char **xattr_value, size_t size, gfp_t flags); 60 char **xattr_value, size_t size, gfp_t flags);
62 61
diff --git a/mm/shmem.c b/mm/shmem.c
index 828253ab772c..8596217b5e26 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -3175,10 +3175,7 @@ static const struct inode_operations shmem_short_symlink_operations = {
3175 .readlink = generic_readlink, 3175 .readlink = generic_readlink,
3176 .get_link = simple_get_link, 3176 .get_link = simple_get_link,
3177#ifdef CONFIG_TMPFS_XATTR 3177#ifdef CONFIG_TMPFS_XATTR
3178 .setxattr = generic_setxattr,
3179 .getxattr = generic_getxattr,
3180 .listxattr = shmem_listxattr, 3178 .listxattr = shmem_listxattr,
3181 .removexattr = generic_removexattr,
3182#endif 3179#endif
3183}; 3180};
3184 3181
@@ -3186,10 +3183,7 @@ static const struct inode_operations shmem_symlink_inode_operations = {
3186 .readlink = generic_readlink, 3183 .readlink = generic_readlink,
3187 .get_link = shmem_get_link, 3184 .get_link = shmem_get_link,
3188#ifdef CONFIG_TMPFS_XATTR 3185#ifdef CONFIG_TMPFS_XATTR
3189 .setxattr = generic_setxattr,
3190 .getxattr = generic_getxattr,
3191 .listxattr = shmem_listxattr, 3186 .listxattr = shmem_listxattr,
3192 .removexattr = generic_removexattr,
3193#endif 3187#endif
3194}; 3188};
3195 3189
@@ -3683,10 +3677,7 @@ static const struct inode_operations shmem_inode_operations = {
3683 .getattr = shmem_getattr, 3677 .getattr = shmem_getattr,
3684 .setattr = shmem_setattr, 3678 .setattr = shmem_setattr,
3685#ifdef CONFIG_TMPFS_XATTR 3679#ifdef CONFIG_TMPFS_XATTR
3686 .setxattr = generic_setxattr,
3687 .getxattr = generic_getxattr,
3688 .listxattr = shmem_listxattr, 3680 .listxattr = shmem_listxattr,
3689 .removexattr = generic_removexattr,
3690 .set_acl = simple_set_acl, 3681 .set_acl = simple_set_acl,
3691#endif 3682#endif
3692}; 3683};
@@ -3705,10 +3696,7 @@ static const struct inode_operations shmem_dir_inode_operations = {
3705 .tmpfile = shmem_tmpfile, 3696 .tmpfile = shmem_tmpfile,
3706#endif 3697#endif
3707#ifdef CONFIG_TMPFS_XATTR 3698#ifdef CONFIG_TMPFS_XATTR
3708 .setxattr = generic_setxattr,
3709 .getxattr = generic_getxattr,
3710 .listxattr = shmem_listxattr, 3699 .listxattr = shmem_listxattr,
3711 .removexattr = generic_removexattr,
3712#endif 3700#endif
3713#ifdef CONFIG_TMPFS_POSIX_ACL 3701#ifdef CONFIG_TMPFS_POSIX_ACL
3714 .setattr = shmem_setattr, 3702 .setattr = shmem_setattr,
@@ -3718,10 +3706,7 @@ static const struct inode_operations shmem_dir_inode_operations = {
3718 3706
3719static const struct inode_operations shmem_special_inode_operations = { 3707static const struct inode_operations shmem_special_inode_operations = {
3720#ifdef CONFIG_TMPFS_XATTR 3708#ifdef CONFIG_TMPFS_XATTR
3721 .setxattr = generic_setxattr,
3722 .getxattr = generic_getxattr,
3723 .listxattr = shmem_listxattr, 3709 .listxattr = shmem_listxattr,
3724 .removexattr = generic_removexattr,
3725#endif 3710#endif
3726#ifdef CONFIG_TMPFS_POSIX_ACL 3711#ifdef CONFIG_TMPFS_POSIX_ACL
3727 .setattr = shmem_setattr, 3712 .setattr = shmem_setattr,
diff --git a/net/socket.c b/net/socket.c
index a1bd16106625..5a9bf5ee2464 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -320,11 +320,38 @@ static const struct dentry_operations sockfs_dentry_operations = {
320 .d_dname = sockfs_dname, 320 .d_dname = sockfs_dname,
321}; 321};
322 322
323static int sockfs_xattr_get(const struct xattr_handler *handler,
324 struct dentry *dentry, struct inode *inode,
325 const char *suffix, void *value, size_t size)
326{
327 if (value) {
328 if (dentry->d_name.len + 1 > size)
329 return -ERANGE;
330 memcpy(value, dentry->d_name.name, dentry->d_name.len + 1);
331 }
332 return dentry->d_name.len + 1;
333}
334
335#define XATTR_SOCKPROTONAME_SUFFIX "sockprotoname"
336#define XATTR_NAME_SOCKPROTONAME (XATTR_SYSTEM_PREFIX XATTR_SOCKPROTONAME_SUFFIX)
337#define XATTR_NAME_SOCKPROTONAME_LEN (sizeof(XATTR_NAME_SOCKPROTONAME)-1)
338
339static const struct xattr_handler sockfs_xattr_handler = {
340 .name = XATTR_NAME_SOCKPROTONAME,
341 .get = sockfs_xattr_get,
342};
343
344static const struct xattr_handler *sockfs_xattr_handlers[] = {
345 &sockfs_xattr_handler,
346 NULL
347};
348
323static struct dentry *sockfs_mount(struct file_system_type *fs_type, 349static struct dentry *sockfs_mount(struct file_system_type *fs_type,
324 int flags, const char *dev_name, void *data) 350 int flags, const char *dev_name, void *data)
325{ 351{
326 return mount_pseudo(fs_type, "socket:", &sockfs_ops, 352 return mount_pseudo_xattr(fs_type, "socket:", &sockfs_ops,
327 &sockfs_dentry_operations, SOCKFS_MAGIC); 353 sockfs_xattr_handlers,
354 &sockfs_dentry_operations, SOCKFS_MAGIC);
328} 355}
329 356
330static struct vfsmount *sock_mnt __read_mostly; 357static struct vfsmount *sock_mnt __read_mostly;
@@ -463,35 +490,6 @@ static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed)
463 return NULL; 490 return NULL;
464} 491}
465 492
466#define XATTR_SOCKPROTONAME_SUFFIX "sockprotoname"
467#define XATTR_NAME_SOCKPROTONAME (XATTR_SYSTEM_PREFIX XATTR_SOCKPROTONAME_SUFFIX)
468#define XATTR_NAME_SOCKPROTONAME_LEN (sizeof(XATTR_NAME_SOCKPROTONAME)-1)
469static ssize_t sockfs_getxattr(struct dentry *dentry, struct inode *inode,
470 const char *name, void *value, size_t size)
471{
472 const char *proto_name;
473 size_t proto_size;
474 int error;
475
476 error = -ENODATA;
477 if (!strncmp(name, XATTR_NAME_SOCKPROTONAME, XATTR_NAME_SOCKPROTONAME_LEN)) {
478 proto_name = dentry->d_name.name;
479 proto_size = strlen(proto_name);
480
481 if (value) {
482 error = -ERANGE;
483 if (proto_size + 1 > size)
484 goto out;
485
486 strncpy(value, proto_name, proto_size + 1);
487 }
488 error = proto_size + 1;
489 }
490
491out:
492 return error;
493}
494
495static ssize_t sockfs_listxattr(struct dentry *dentry, char *buffer, 493static ssize_t sockfs_listxattr(struct dentry *dentry, char *buffer,
496 size_t size) 494 size_t size)
497{ 495{
@@ -521,7 +519,6 @@ static ssize_t sockfs_listxattr(struct dentry *dentry, char *buffer,
521} 519}
522 520
523static const struct inode_operations sockfs_inode_ops = { 521static const struct inode_operations sockfs_inode_ops = {
524 .getxattr = sockfs_getxattr,
525 .listxattr = sockfs_listxattr, 522 .listxattr = sockfs_listxattr,
526}; 523};
527 524
diff --git a/security/commoncap.c b/security/commoncap.c
index 14540bd78561..8df676fbd393 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -310,13 +310,8 @@ int cap_inode_need_killpriv(struct dentry *dentry)
310 struct inode *inode = d_backing_inode(dentry); 310 struct inode *inode = d_backing_inode(dentry);
311 int error; 311 int error;
312 312
313 if (!inode->i_op->getxattr) 313 error = __vfs_getxattr(dentry, inode, XATTR_NAME_CAPS, NULL, 0);
314 return 0; 314 return error > 0;
315
316 error = inode->i_op->getxattr(dentry, inode, XATTR_NAME_CAPS, NULL, 0);
317 if (error <= 0)
318 return 0;
319 return 1;
320} 315}
321 316
322/** 317/**
@@ -329,12 +324,12 @@ int cap_inode_need_killpriv(struct dentry *dentry)
329 */ 324 */
330int cap_inode_killpriv(struct dentry *dentry) 325int cap_inode_killpriv(struct dentry *dentry)
331{ 326{
332 struct inode *inode = d_backing_inode(dentry); 327 int error;
333
334 if (!inode->i_op->removexattr)
335 return 0;
336 328
337 return inode->i_op->removexattr(dentry, XATTR_NAME_CAPS); 329 error = __vfs_removexattr(dentry, XATTR_NAME_CAPS);
330 if (error == -EOPNOTSUPP)
331 error = 0;
332 return error;
338} 333}
339 334
340/* 335/*
@@ -394,11 +389,11 @@ int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data
394 389
395 memset(cpu_caps, 0, sizeof(struct cpu_vfs_cap_data)); 390 memset(cpu_caps, 0, sizeof(struct cpu_vfs_cap_data));
396 391
397 if (!inode || !inode->i_op->getxattr) 392 if (!inode)
398 return -ENODATA; 393 return -ENODATA;
399 394
400 size = inode->i_op->getxattr((struct dentry *)dentry, inode, 395 size = __vfs_getxattr((struct dentry *)dentry, inode,
401 XATTR_NAME_CAPS, &caps, XATTR_CAPS_SZ); 396 XATTR_NAME_CAPS, &caps, XATTR_CAPS_SZ);
402 if (size == -ENODATA || size == -EOPNOTSUPP) 397 if (size == -ENODATA || size == -EOPNOTSUPP)
403 /* no data, that's ok */ 398 /* no data, that's ok */
404 return -ENODATA; 399 return -ENODATA;
diff --git a/security/integrity/evm/evm_crypto.c b/security/integrity/evm/evm_crypto.c
index 11c1d30bd705..bf663915412e 100644
--- a/security/integrity/evm/evm_crypto.c
+++ b/security/integrity/evm/evm_crypto.c
@@ -182,8 +182,9 @@ static int evm_calc_hmac_or_hash(struct dentry *dentry,
182 int error; 182 int error;
183 int size; 183 int size;
184 184
185 if (!inode->i_op->getxattr) 185 if (!(inode->i_opflags & IOP_XATTR))
186 return -EOPNOTSUPP; 186 return -EOPNOTSUPP;
187
187 desc = init_desc(type); 188 desc = init_desc(type);
188 if (IS_ERR(desc)) 189 if (IS_ERR(desc))
189 return PTR_ERR(desc); 190 return PTR_ERR(desc);
@@ -253,8 +254,8 @@ int evm_update_evmxattr(struct dentry *dentry, const char *xattr_name,
253 rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_EVM, 254 rc = __vfs_setxattr_noperm(dentry, XATTR_NAME_EVM,
254 &xattr_data, 255 &xattr_data,
255 sizeof(xattr_data), 0); 256 sizeof(xattr_data), 0);
256 } else if (rc == -ENODATA && inode->i_op->removexattr) { 257 } else if (rc == -ENODATA && (inode->i_opflags & IOP_XATTR)) {
257 rc = inode->i_op->removexattr(dentry, XATTR_NAME_EVM); 258 rc = __vfs_removexattr(dentry, XATTR_NAME_EVM);
258 } 259 }
259 return rc; 260 return rc;
260} 261}
diff --git a/security/integrity/evm/evm_main.c b/security/integrity/evm/evm_main.c
index b9e26288d30c..ba8615576d4d 100644
--- a/security/integrity/evm/evm_main.c
+++ b/security/integrity/evm/evm_main.c
@@ -78,11 +78,11 @@ static int evm_find_protected_xattrs(struct dentry *dentry)
78 int error; 78 int error;
79 int count = 0; 79 int count = 0;
80 80
81 if (!inode->i_op->getxattr) 81 if (!(inode->i_opflags & IOP_XATTR))
82 return -EOPNOTSUPP; 82 return -EOPNOTSUPP;
83 83
84 for (xattr = evm_config_xattrnames; *xattr != NULL; xattr++) { 84 for (xattr = evm_config_xattrnames; *xattr != NULL; xattr++) {
85 error = inode->i_op->getxattr(dentry, inode, *xattr, NULL, 0); 85 error = __vfs_getxattr(dentry, inode, *xattr, NULL, 0);
86 if (error < 0) { 86 if (error < 0) {
87 if (error == -ENODATA) 87 if (error == -ENODATA)
88 continue; 88 continue;
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index ef1e4e701780..389325ac6067 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -165,13 +165,13 @@ enum hash_algo ima_get_hash_algo(struct evm_ima_xattr_data *xattr_value,
165int ima_read_xattr(struct dentry *dentry, 165int ima_read_xattr(struct dentry *dentry,
166 struct evm_ima_xattr_data **xattr_value) 166 struct evm_ima_xattr_data **xattr_value)
167{ 167{
168 struct inode *inode = d_backing_inode(dentry); 168 ssize_t ret;
169
170 if (!inode->i_op->getxattr)
171 return 0;
172 169
173 return vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)xattr_value, 170 ret = vfs_getxattr_alloc(dentry, XATTR_NAME_IMA, (char **)xattr_value,
174 0, GFP_NOFS); 171 0, GFP_NOFS);
172 if (ret == -EOPNOTSUPP)
173 ret = 0;
174 return ret;
175} 175}
176 176
177/* 177/*
@@ -195,7 +195,7 @@ int ima_appraise_measurement(enum ima_hooks func,
195 enum integrity_status status = INTEGRITY_UNKNOWN; 195 enum integrity_status status = INTEGRITY_UNKNOWN;
196 int rc = xattr_len, hash_start = 0; 196 int rc = xattr_len, hash_start = 0;
197 197
198 if (!inode->i_op->getxattr) 198 if (!(inode->i_opflags & IOP_XATTR))
199 return INTEGRITY_UNKNOWN; 199 return INTEGRITY_UNKNOWN;
200 200
201 if (rc <= 0) { 201 if (rc <= 0) {
@@ -322,10 +322,10 @@ void ima_inode_post_setattr(struct dentry *dentry)
322{ 322{
323 struct inode *inode = d_backing_inode(dentry); 323 struct inode *inode = d_backing_inode(dentry);
324 struct integrity_iint_cache *iint; 324 struct integrity_iint_cache *iint;
325 int must_appraise, rc; 325 int must_appraise;
326 326
327 if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode) 327 if (!(ima_policy_flag & IMA_APPRAISE) || !S_ISREG(inode->i_mode)
328 || !inode->i_op->removexattr) 328 || !(inode->i_opflags & IOP_XATTR))
329 return; 329 return;
330 330
331 must_appraise = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR); 331 must_appraise = ima_must_appraise(inode, MAY_ACCESS, POST_SETATTR);
@@ -338,8 +338,7 @@ void ima_inode_post_setattr(struct dentry *dentry)
338 iint->flags |= IMA_APPRAISE; 338 iint->flags |= IMA_APPRAISE;
339 } 339 }
340 if (!must_appraise) 340 if (!must_appraise)
341 rc = inode->i_op->removexattr(dentry, XATTR_NAME_IMA); 341 __vfs_removexattr(dentry, XATTR_NAME_IMA);
342 return;
343} 342}
344 343
345/* 344/*
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 2205ea27aa0a..085057936287 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -507,14 +507,14 @@ static int sb_finish_set_opts(struct super_block *sb)
507 the root directory. -ENODATA is ok, as this may be 507 the root directory. -ENODATA is ok, as this may be
508 the first boot of the SELinux kernel before we have 508 the first boot of the SELinux kernel before we have
509 assigned xattr values to the filesystem. */ 509 assigned xattr values to the filesystem. */
510 if (!root_inode->i_op->getxattr) { 510 if (!(root_inode->i_opflags & IOP_XATTR)) {
511 printk(KERN_WARNING "SELinux: (dev %s, type %s) has no " 511 printk(KERN_WARNING "SELinux: (dev %s, type %s) has no "
512 "xattr support\n", sb->s_id, sb->s_type->name); 512 "xattr support\n", sb->s_id, sb->s_type->name);
513 rc = -EOPNOTSUPP; 513 rc = -EOPNOTSUPP;
514 goto out; 514 goto out;
515 } 515 }
516 rc = root_inode->i_op->getxattr(root, root_inode, 516
517 XATTR_NAME_SELINUX, NULL, 0); 517 rc = __vfs_getxattr(root, root_inode, XATTR_NAME_SELINUX, NULL, 0);
518 if (rc < 0 && rc != -ENODATA) { 518 if (rc < 0 && rc != -ENODATA) {
519 if (rc == -EOPNOTSUPP) 519 if (rc == -EOPNOTSUPP)
520 printk(KERN_WARNING "SELinux: (dev %s, type " 520 printk(KERN_WARNING "SELinux: (dev %s, type "
@@ -1410,11 +1410,10 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
1410 case SECURITY_FS_USE_NATIVE: 1410 case SECURITY_FS_USE_NATIVE:
1411 break; 1411 break;
1412 case SECURITY_FS_USE_XATTR: 1412 case SECURITY_FS_USE_XATTR:
1413 if (!inode->i_op->getxattr) { 1413 if (!(inode->i_opflags & IOP_XATTR)) {
1414 isec->sid = sbsec->def_sid; 1414 isec->sid = sbsec->def_sid;
1415 break; 1415 break;
1416 } 1416 }
1417
1418 /* Need a dentry, since the xattr API requires one. 1417 /* Need a dentry, since the xattr API requires one.
1419 Life would be simpler if we could just pass the inode. */ 1418 Life would be simpler if we could just pass the inode. */
1420 if (opt_dentry) { 1419 if (opt_dentry) {
@@ -1445,14 +1444,12 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
1445 goto out_unlock; 1444 goto out_unlock;
1446 } 1445 }
1447 context[len] = '\0'; 1446 context[len] = '\0';
1448 rc = inode->i_op->getxattr(dentry, inode, XATTR_NAME_SELINUX, 1447 rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, context, len);
1449 context, len);
1450 if (rc == -ERANGE) { 1448 if (rc == -ERANGE) {
1451 kfree(context); 1449 kfree(context);
1452 1450
1453 /* Need a larger buffer. Query for the right size. */ 1451 /* Need a larger buffer. Query for the right size. */
1454 rc = inode->i_op->getxattr(dentry, inode, XATTR_NAME_SELINUX, 1452 rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, NULL, 0);
1455 NULL, 0);
1456 if (rc < 0) { 1453 if (rc < 0) {
1457 dput(dentry); 1454 dput(dentry);
1458 goto out_unlock; 1455 goto out_unlock;
@@ -1465,9 +1462,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
1465 goto out_unlock; 1462 goto out_unlock;
1466 } 1463 }
1467 context[len] = '\0'; 1464 context[len] = '\0';
1468 rc = inode->i_op->getxattr(dentry, inode, 1465 rc = __vfs_getxattr(dentry, inode, XATTR_NAME_SELINUX, context, len);
1469 XATTR_NAME_SELINUX,
1470 context, len);
1471 } 1466 }
1472 dput(dentry); 1467 dput(dentry);
1473 if (rc < 0) { 1468 if (rc < 0) {
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index caec2256ab22..1cb060293505 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -265,14 +265,14 @@ static struct smack_known *smk_fetch(const char *name, struct inode *ip,
265 char *buffer; 265 char *buffer;
266 struct smack_known *skp = NULL; 266 struct smack_known *skp = NULL;
267 267
268 if (ip->i_op->getxattr == NULL) 268 if (!(ip->i_opflags & IOP_XATTR))
269 return ERR_PTR(-EOPNOTSUPP); 269 return ERR_PTR(-EOPNOTSUPP);
270 270
271 buffer = kzalloc(SMK_LONGLABEL, GFP_KERNEL); 271 buffer = kzalloc(SMK_LONGLABEL, GFP_KERNEL);
272 if (buffer == NULL) 272 if (buffer == NULL)
273 return ERR_PTR(-ENOMEM); 273 return ERR_PTR(-ENOMEM);
274 274
275 rc = ip->i_op->getxattr(dp, ip, name, buffer, SMK_LONGLABEL); 275 rc = __vfs_getxattr(dp, ip, name, buffer, SMK_LONGLABEL);
276 if (rc < 0) 276 if (rc < 0)
277 skp = ERR_PTR(rc); 277 skp = ERR_PTR(rc);
278 else if (rc == 0) 278 else if (rc == 0)
@@ -3520,8 +3520,8 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
3520 * It would be curious if the label of the task 3520 * It would be curious if the label of the task
3521 * does not match that assigned. 3521 * does not match that assigned.
3522 */ 3522 */
3523 if (inode->i_op->getxattr == NULL) 3523 if (!(inode->i_opflags & IOP_XATTR))
3524 break; 3524 break;
3525 /* 3525 /*
3526 * Get the dentry for xattr. 3526 * Get the dentry for xattr.
3527 */ 3527 */
@@ -3545,12 +3545,12 @@ static void smack_d_instantiate(struct dentry *opt_dentry, struct inode *inode)
3545 */ 3545 */
3546 if (isp->smk_flags & SMK_INODE_CHANGED) { 3546 if (isp->smk_flags & SMK_INODE_CHANGED) {
3547 isp->smk_flags &= ~SMK_INODE_CHANGED; 3547 isp->smk_flags &= ~SMK_INODE_CHANGED;
3548 rc = inode->i_op->setxattr(dp, inode, 3548 rc = __vfs_setxattr(dp, inode,
3549 XATTR_NAME_SMACKTRANSMUTE, 3549 XATTR_NAME_SMACKTRANSMUTE,
3550 TRANS_TRUE, TRANS_TRUE_SIZE, 3550 TRANS_TRUE, TRANS_TRUE_SIZE,
3551 0); 3551 0);
3552 } else { 3552 } else {
3553 rc = inode->i_op->getxattr(dp, inode, 3553 rc = __vfs_getxattr(dp, inode,
3554 XATTR_NAME_SMACKTRANSMUTE, trattr, 3554 XATTR_NAME_SMACKTRANSMUTE, trattr,
3555 TRANS_TRUE_SIZE); 3555 TRANS_TRUE_SIZE);
3556 if (rc >= 0 && strncmp(trattr, TRANS_TRUE, 3556 if (rc >= 0 && strncmp(trattr, TRANS_TRUE,