aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@infradead.org>2013-12-20 08:16:50 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2014-01-25 23:58:21 -0500
commit2401dc2975fc5a33021dc8347ea82984c4707a08 (patch)
treeae501653de1dd6bd50cf69344bad968e467bda23 /fs
parent47f70d08facf288a9faad6e6c36ac2e670be8195 (diff)
xfs: use generic posix ACL infrastructure
Also don't bother to set up a .get_acl method for symlinks as we do not support access control (ACLs or even mode bits) for symlinks in Linux, and create inodes with the proper mode instead of fixing it up later. Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r--fs/xfs/xfs_acl.c151
-rw-r--r--fs/xfs/xfs_acl.h9
-rw-r--r--fs/xfs/xfs_iops.c41
-rw-r--r--fs/xfs/xfs_iops.h2
-rw-r--r--fs/xfs/xfs_xattr.c4
5 files changed, 36 insertions, 171 deletions
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
index 057ae2d502dc..0ecec1896f25 100644
--- a/fs/xfs/xfs_acl.c
+++ b/fs/xfs/xfs_acl.c
@@ -124,16 +124,12 @@ struct posix_acl *
124xfs_get_acl(struct inode *inode, int type) 124xfs_get_acl(struct inode *inode, int type)
125{ 125{
126 struct xfs_inode *ip = XFS_I(inode); 126 struct xfs_inode *ip = XFS_I(inode);
127 struct posix_acl *acl; 127 struct posix_acl *acl = NULL;
128 struct xfs_acl *xfs_acl; 128 struct xfs_acl *xfs_acl;
129 unsigned char *ea_name; 129 unsigned char *ea_name;
130 int error; 130 int error;
131 int len; 131 int len;
132 132
133 acl = get_cached_acl(inode, type);
134 if (acl != ACL_NOT_CACHED)
135 return acl;
136
137 trace_xfs_get_acl(ip); 133 trace_xfs_get_acl(ip);
138 134
139 switch (type) { 135 switch (type) {
@@ -164,10 +160,8 @@ xfs_get_acl(struct inode *inode, int type)
164 * cache entry, for any other error assume it is transient and 160 * cache entry, for any other error assume it is transient and
165 * leave the cache entry as ACL_NOT_CACHED. 161 * leave the cache entry as ACL_NOT_CACHED.
166 */ 162 */
167 if (error == -ENOATTR) { 163 if (error == -ENOATTR)
168 acl = NULL;
169 goto out_update_cache; 164 goto out_update_cache;
170 }
171 goto out; 165 goto out;
172 } 166 }
173 167
@@ -183,15 +177,12 @@ out:
183} 177}
184 178
185STATIC int 179STATIC int
186xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl) 180__xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
187{ 181{
188 struct xfs_inode *ip = XFS_I(inode); 182 struct xfs_inode *ip = XFS_I(inode);
189 unsigned char *ea_name; 183 unsigned char *ea_name;
190 int error; 184 int error;
191 185
192 if (S_ISLNK(inode->i_mode))
193 return -EOPNOTSUPP;
194
195 switch (type) { 186 switch (type) {
196 case ACL_TYPE_ACCESS: 187 case ACL_TYPE_ACCESS:
197 ea_name = SGI_ACL_FILE; 188 ea_name = SGI_ACL_FILE;
@@ -282,131 +273,23 @@ posix_acl_default_exists(struct inode *inode)
282 return xfs_acl_exists(inode, SGI_ACL_DEFAULT); 273 return xfs_acl_exists(inode, SGI_ACL_DEFAULT);
283} 274}
284 275
285/*
286 * No need for i_mutex because the inode is not yet exposed to the VFS.
287 */
288int 276int
289xfs_inherit_acl(struct inode *inode, struct posix_acl *acl) 277xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
290{ 278{
291 umode_t mode = inode->i_mode;
292 int error = 0, inherit = 0;
293
294 if (S_ISDIR(inode->i_mode)) {
295 error = xfs_set_acl(inode, ACL_TYPE_DEFAULT, acl);
296 if (error)
297 goto out;
298 }
299
300 error = __posix_acl_create(&acl, GFP_KERNEL, &mode);
301 if (error < 0)
302 return error;
303
304 /*
305 * If __posix_acl_create returns a positive value we need to
306 * inherit a permission that can't be represented using the Unix
307 * mode bits and we actually need to set an ACL.
308 */
309 if (error > 0)
310 inherit = 1;
311
312 error = xfs_set_mode(inode, mode);
313 if (error)
314 goto out;
315
316 if (inherit)
317 error = xfs_set_acl(inode, ACL_TYPE_ACCESS, acl);
318
319out:
320 posix_acl_release(acl);
321 return error;
322}
323
324int
325xfs_acl_chmod(struct inode *inode)
326{
327 struct posix_acl *acl;
328 int error;
329
330 if (S_ISLNK(inode->i_mode))
331 return -EOPNOTSUPP;
332
333 acl = xfs_get_acl(inode, ACL_TYPE_ACCESS);
334 if (IS_ERR(acl) || !acl)
335 return PTR_ERR(acl);
336
337 error = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
338 if (error)
339 return error;
340
341 error = xfs_set_acl(inode, ACL_TYPE_ACCESS, acl);
342 posix_acl_release(acl);
343 return error;
344}
345
346static int
347xfs_xattr_acl_get(struct dentry *dentry, const char *name,
348 void *value, size_t size, int type)
349{
350 struct posix_acl *acl;
351 int error;
352
353 acl = xfs_get_acl(dentry->d_inode, type);
354 if (IS_ERR(acl))
355 return PTR_ERR(acl);
356 if (acl == NULL)
357 return -ENODATA;
358
359 error = posix_acl_to_xattr(&init_user_ns, acl, value, size);
360 posix_acl_release(acl);
361
362 return error;
363}
364
365static int
366xfs_xattr_acl_set(struct dentry *dentry, const char *name,
367 const void *value, size_t size, int flags, int type)
368{
369 struct inode *inode = dentry->d_inode;
370 struct posix_acl *acl = NULL;
371 int error = 0; 279 int error = 0;
372 280
373 if (flags & XATTR_CREATE) 281 if (!acl)
374 return -EINVAL;
375 if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode))
376 return value ? -EACCES : 0;
377 if (!inode_owner_or_capable(inode))
378 return -EPERM;
379
380 if (!value)
381 goto set_acl; 282 goto set_acl;
382 283
383 acl = posix_acl_from_xattr(&init_user_ns, value, size);
384 if (!acl) {
385 /*
386 * acl_set_file(3) may request that we set default ACLs with
387 * zero length -- defend (gracefully) against that here.
388 */
389 goto out;
390 }
391 if (IS_ERR(acl)) {
392 error = PTR_ERR(acl);
393 goto out;
394 }
395
396 error = posix_acl_valid(acl);
397 if (error)
398 goto out_release;
399
400 error = -EINVAL; 284 error = -EINVAL;
401 if (acl->a_count > XFS_ACL_MAX_ENTRIES(XFS_M(inode->i_sb))) 285 if (acl->a_count > XFS_ACL_MAX_ENTRIES(XFS_M(inode->i_sb)))
402 goto out_release; 286 return error;
403 287
404 if (type == ACL_TYPE_ACCESS) { 288 if (type == ACL_TYPE_ACCESS) {
405 umode_t mode = inode->i_mode; 289 umode_t mode = inode->i_mode;
406 error = posix_acl_equiv_mode(acl, &mode); 290 error = posix_acl_equiv_mode(acl, &mode);
407 291
408 if (error <= 0) { 292 if (error <= 0) {
409 posix_acl_release(acl);
410 acl = NULL; 293 acl = NULL;
411 294
412 if (error < 0) 295 if (error < 0)
@@ -415,27 +298,9 @@ xfs_xattr_acl_set(struct dentry *dentry, const char *name,
415 298
416 error = xfs_set_mode(inode, mode); 299 error = xfs_set_mode(inode, mode);
417 if (error) 300 if (error)
418 goto out_release; 301 return error;
419 } 302 }
420 303
421 set_acl: 304 set_acl:
422 error = xfs_set_acl(inode, type, acl); 305 return __xfs_set_acl(inode, type, acl);
423 out_release:
424 posix_acl_release(acl);
425 out:
426 return error;
427} 306}
428
429const struct xattr_handler xfs_xattr_acl_access_handler = {
430 .prefix = POSIX_ACL_XATTR_ACCESS,
431 .flags = ACL_TYPE_ACCESS,
432 .get = xfs_xattr_acl_get,
433 .set = xfs_xattr_acl_set,
434};
435
436const struct xattr_handler xfs_xattr_acl_default_handler = {
437 .prefix = POSIX_ACL_XATTR_DEFAULT,
438 .flags = ACL_TYPE_DEFAULT,
439 .get = xfs_xattr_acl_get,
440 .set = xfs_xattr_acl_set,
441};
diff --git a/fs/xfs/xfs_acl.h b/fs/xfs/xfs_acl.h
index 4016a567b83c..5dc163744511 100644
--- a/fs/xfs/xfs_acl.h
+++ b/fs/xfs/xfs_acl.h
@@ -60,20 +60,15 @@ struct xfs_acl {
60 60
61#ifdef CONFIG_XFS_POSIX_ACL 61#ifdef CONFIG_XFS_POSIX_ACL
62extern struct posix_acl *xfs_get_acl(struct inode *inode, int type); 62extern struct posix_acl *xfs_get_acl(struct inode *inode, int type);
63extern int xfs_inherit_acl(struct inode *inode, struct posix_acl *default_acl); 63extern int xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
64extern int xfs_acl_chmod(struct inode *inode);
65extern int posix_acl_access_exists(struct inode *inode); 64extern int posix_acl_access_exists(struct inode *inode);
66extern int posix_acl_default_exists(struct inode *inode); 65extern int posix_acl_default_exists(struct inode *inode);
67
68extern const struct xattr_handler xfs_xattr_acl_access_handler;
69extern const struct xattr_handler xfs_xattr_acl_default_handler;
70#else 66#else
71static inline struct posix_acl *xfs_get_acl(struct inode *inode, int type) 67static inline struct posix_acl *xfs_get_acl(struct inode *inode, int type)
72{ 68{
73 return NULL; 69 return NULL;
74} 70}
75# define xfs_inherit_acl(inode, default_acl) 0 71# define xfs_set_acl NULL
76# define xfs_acl_chmod(inode) 0
77# define posix_acl_access_exists(inode) 0 72# define posix_acl_access_exists(inode) 0
78# define posix_acl_default_exists(inode) 0 73# define posix_acl_default_exists(inode) 0
79#endif /* CONFIG_XFS_POSIX_ACL */ 74#endif /* CONFIG_XFS_POSIX_ACL */
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index a3dad17b1351..d47fbee3121e 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -123,7 +123,7 @@ xfs_vn_mknod(
123{ 123{
124 struct inode *inode; 124 struct inode *inode;
125 struct xfs_inode *ip = NULL; 125 struct xfs_inode *ip = NULL;
126 struct posix_acl *default_acl = NULL; 126 struct posix_acl *default_acl, *acl;
127 struct xfs_name name; 127 struct xfs_name name;
128 int error; 128 int error;
129 129
@@ -139,14 +139,9 @@ xfs_vn_mknod(
139 rdev = 0; 139 rdev = 0;
140 } 140 }
141 141
142 if (IS_POSIXACL(dir)) { 142 error = posix_acl_create(dir, &mode, &default_acl, &acl);
143 default_acl = xfs_get_acl(dir, ACL_TYPE_DEFAULT); 143 if (error)
144 if (IS_ERR(default_acl)) 144 return error;
145 return PTR_ERR(default_acl);
146
147 if (!default_acl)
148 mode &= ~current_umask();
149 }
150 145
151 xfs_dentry_to_name(&name, dentry, mode); 146 xfs_dentry_to_name(&name, dentry, mode);
152 error = xfs_create(XFS_I(dir), &name, mode, rdev, &ip); 147 error = xfs_create(XFS_I(dir), &name, mode, rdev, &ip);
@@ -159,22 +154,30 @@ xfs_vn_mknod(
159 if (unlikely(error)) 154 if (unlikely(error))
160 goto out_cleanup_inode; 155 goto out_cleanup_inode;
161 156
157#ifdef CONFIG_XFS_POSIX_ACL
162 if (default_acl) { 158 if (default_acl) {
163 error = -xfs_inherit_acl(inode, default_acl); 159 error = xfs_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
164 default_acl = NULL; 160 if (error)
165 if (unlikely(error))
166 goto out_cleanup_inode; 161 goto out_cleanup_inode;
167 } 162 }
168 163 if (acl) {
164 error = xfs_set_acl(inode, acl, ACL_TYPE_ACCESS);
165 if (error)
166 goto out_cleanup_inode;
167 }
168#endif
169 169
170 d_instantiate(dentry, inode); 170 d_instantiate(dentry, inode);
171 out_free_acl:
172 if (default_acl)
173 posix_acl_release(default_acl);
174 if (acl)
175 posix_acl_release(acl);
171 return -error; 176 return -error;
172 177
173 out_cleanup_inode: 178 out_cleanup_inode:
174 xfs_cleanup_inode(dir, inode, dentry); 179 xfs_cleanup_inode(dir, inode, dentry);
175 out_free_acl: 180 goto out_free_acl;
176 posix_acl_release(default_acl);
177 return -error;
178} 181}
179 182
180STATIC int 183STATIC int
@@ -672,7 +675,7 @@ xfs_setattr_nonsize(
672 * Posix ACL code seems to care about this issue either. 675 * Posix ACL code seems to care about this issue either.
673 */ 676 */
674 if ((mask & ATTR_MODE) && !(flags & XFS_ATTR_NOACL)) { 677 if ((mask & ATTR_MODE) && !(flags & XFS_ATTR_NOACL)) {
675 error = -xfs_acl_chmod(inode); 678 error = -posix_acl_chmod(inode, inode->i_mode);
676 if (error) 679 if (error)
677 return XFS_ERROR(error); 680 return XFS_ERROR(error);
678 } 681 }
@@ -1041,6 +1044,7 @@ xfs_vn_fiemap(
1041 1044
1042static const struct inode_operations xfs_inode_operations = { 1045static const struct inode_operations xfs_inode_operations = {
1043 .get_acl = xfs_get_acl, 1046 .get_acl = xfs_get_acl,
1047 .set_acl = xfs_set_acl,
1044 .getattr = xfs_vn_getattr, 1048 .getattr = xfs_vn_getattr,
1045 .setattr = xfs_vn_setattr, 1049 .setattr = xfs_vn_setattr,
1046 .setxattr = generic_setxattr, 1050 .setxattr = generic_setxattr,
@@ -1068,6 +1072,7 @@ static const struct inode_operations xfs_dir_inode_operations = {
1068 .mknod = xfs_vn_mknod, 1072 .mknod = xfs_vn_mknod,
1069 .rename = xfs_vn_rename, 1073 .rename = xfs_vn_rename,
1070 .get_acl = xfs_get_acl, 1074 .get_acl = xfs_get_acl,
1075 .set_acl = xfs_set_acl,
1071 .getattr = xfs_vn_getattr, 1076 .getattr = xfs_vn_getattr,
1072 .setattr = xfs_vn_setattr, 1077 .setattr = xfs_vn_setattr,
1073 .setxattr = generic_setxattr, 1078 .setxattr = generic_setxattr,
@@ -1094,6 +1099,7 @@ static const struct inode_operations xfs_dir_ci_inode_operations = {
1094 .mknod = xfs_vn_mknod, 1099 .mknod = xfs_vn_mknod,
1095 .rename = xfs_vn_rename, 1100 .rename = xfs_vn_rename,
1096 .get_acl = xfs_get_acl, 1101 .get_acl = xfs_get_acl,
1102 .set_acl = xfs_set_acl,
1097 .getattr = xfs_vn_getattr, 1103 .getattr = xfs_vn_getattr,
1098 .setattr = xfs_vn_setattr, 1104 .setattr = xfs_vn_setattr,
1099 .setxattr = generic_setxattr, 1105 .setxattr = generic_setxattr,
@@ -1107,7 +1113,6 @@ static const struct inode_operations xfs_symlink_inode_operations = {
1107 .readlink = generic_readlink, 1113 .readlink = generic_readlink,
1108 .follow_link = xfs_vn_follow_link, 1114 .follow_link = xfs_vn_follow_link,
1109 .put_link = kfree_put_link, 1115 .put_link = kfree_put_link,
1110 .get_acl = xfs_get_acl,
1111 .getattr = xfs_vn_getattr, 1116 .getattr = xfs_vn_getattr,
1112 .setattr = xfs_vn_setattr, 1117 .setattr = xfs_vn_setattr,
1113 .setxattr = generic_setxattr, 1118 .setxattr = generic_setxattr,
diff --git a/fs/xfs/xfs_iops.h b/fs/xfs/xfs_iops.h
index d2c5057b5cc4..1c34e4335920 100644
--- a/fs/xfs/xfs_iops.h
+++ b/fs/xfs/xfs_iops.h
@@ -30,7 +30,7 @@ extern void xfs_setup_inode(struct xfs_inode *);
30/* 30/*
31 * Internal setattr interfaces. 31 * Internal setattr interfaces.
32 */ 32 */
33#define XFS_ATTR_NOACL 0x01 /* Don't call xfs_acl_chmod */ 33#define XFS_ATTR_NOACL 0x01 /* Don't call posix_acl_chmod */
34 34
35extern int xfs_setattr_nonsize(struct xfs_inode *ip, struct iattr *vap, 35extern int xfs_setattr_nonsize(struct xfs_inode *ip, struct iattr *vap,
36 int flags); 36 int flags);
diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
index 9d479073ba41..78ed92a46fdd 100644
--- a/fs/xfs/xfs_xattr.c
+++ b/fs/xfs/xfs_xattr.c
@@ -102,8 +102,8 @@ const struct xattr_handler *xfs_xattr_handlers[] = {
102 &xfs_xattr_trusted_handler, 102 &xfs_xattr_trusted_handler,
103 &xfs_xattr_security_handler, 103 &xfs_xattr_security_handler,
104#ifdef CONFIG_XFS_POSIX_ACL 104#ifdef CONFIG_XFS_POSIX_ACL
105 &xfs_xattr_acl_access_handler, 105 &posix_acl_access_xattr_handler,
106 &xfs_xattr_acl_default_handler, 106 &posix_acl_default_xattr_handler,
107#endif 107#endif
108 NULL 108 NULL
109}; 109};