]> git.ipfire.org Git - ipfire-2.x.git/blame - src/patches/suse-2.6.27.31/patches.suse/nfs4acl-ext3.diff
Add a patch to fix Intel E100 wake-on-lan problems.
[ipfire-2.x.git] / src / patches / suse-2.6.27.31 / patches.suse / nfs4acl-ext3.diff
CommitLineData
6a930a95
BS
1From: Andreas Gruenbacher <agruen@suse.de>
2Subject: NFSv4 ACLs for ext3
3
4With the acl=nfs4 mount option, ext3 will use NFSv4 ACLs instead of
5POSIX ACLs. See http://www.suse.de/~agruen/nfs4acl/ for some
6documentation and examples.
7
8Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
9
10---
11 fs/Kconfig | 7
12 fs/ext3/Makefile | 1
13 fs/ext3/acl.c | 8
14 fs/ext3/acl.h | 4
15 fs/ext3/file.c | 4
16 fs/ext3/ialloc.c | 6
17 fs/ext3/inode.c | 73 ++++++++-
18 fs/ext3/namei.c | 15 +
19 fs/ext3/namei.h | 1
20 fs/ext3/nfs4acl.c | 370 ++++++++++++++++++++++++++++++++++++++++++++++
21 fs/ext3/nfs4acl.h | 36 ++++
22 fs/ext3/super.c | 60 +++++--
23 fs/ext3/xattr.c | 9 +
24 fs/ext3/xattr.h | 5
25 include/linux/ext3_fs.h | 1
26 include/linux/ext3_fs_i.h | 3
27 16 files changed, 577 insertions(+), 26 deletions(-)
28
29--- a/fs/Kconfig
30+++ b/fs/Kconfig
31@@ -124,6 +124,13 @@ config EXT3_FS_POSIX_ACL
32
33 If you don't know what Access Control Lists are, say N
34
35+config EXT3_FS_NFS4ACL
36+ bool "Native NFSv4 ACLs (EXPERIMENTAL)"
37+ depends on EXT3_FS_XATTR && EXPERIMENTAL
38+ select FS_NFS4ACL
39+ help
40+ Allow to use NFSv4 ACLs instead of POSIX ACLs.
41+
42 config EXT3_FS_SECURITY
43 bool "Ext3 Security Labels"
44 depends on EXT3_FS_XATTR
45--- a/fs/ext3/Makefile
46+++ b/fs/ext3/Makefile
47@@ -10,3 +10,4 @@ ext3-y := balloc.o bitmap.o dir.o file.o
48 ext3-$(CONFIG_EXT3_FS_XATTR) += xattr.o xattr_user.o xattr_trusted.o
49 ext3-$(CONFIG_EXT3_FS_POSIX_ACL) += acl.o
50 ext3-$(CONFIG_EXT3_FS_SECURITY) += xattr_security.o
51+ext3-$(CONFIG_EXT3_FS_NFS4ACL) += nfs4acl.o
52--- a/fs/ext3/acl.c
53+++ b/fs/ext3/acl.c
54@@ -282,7 +282,7 @@ ext3_set_acl(handle_t *handle, struct in
55 return error;
56 }
57
58-static int
59+int
60 ext3_check_acl(struct inode *inode, int mask)
61 {
62 struct posix_acl *acl = ext3_get_acl(inode, ACL_TYPE_ACCESS);
63@@ -298,12 +298,6 @@ ext3_check_acl(struct inode *inode, int
64 return -EAGAIN;
65 }
66
67-int
68-ext3_permission(struct inode *inode, int mask)
69-{
70- return generic_permission(inode, mask, ext3_check_acl);
71-}
72-
73 /*
74 * Initialize the ACLs of a new inode. Called from ext3_new_inode.
75 *
76--- a/fs/ext3/acl.h
77+++ b/fs/ext3/acl.h
78@@ -58,13 +58,13 @@ static inline int ext3_acl_count(size_t
79 #define EXT3_ACL_NOT_CACHED ((void *)-1)
80
81 /* acl.c */
82-extern int ext3_permission (struct inode *, int);
83+extern int ext3_check_acl (struct inode *, int);
84 extern int ext3_acl_chmod (struct inode *);
85 extern int ext3_init_acl (handle_t *, struct inode *, struct inode *);
86
87 #else /* CONFIG_EXT3_FS_POSIX_ACL */
88 #include <linux/sched.h>
89-#define ext3_permission NULL
90+#define ext3_check_acl NULL
91
92 static inline int
93 ext3_acl_chmod(struct inode *inode)
94--- a/fs/ext3/file.c
95+++ b/fs/ext3/file.c
96@@ -23,8 +23,10 @@
97 #include <linux/jbd.h>
98 #include <linux/ext3_fs.h>
99 #include <linux/ext3_jbd.h>
100+#include "namei.h"
101 #include "xattr.h"
102 #include "acl.h"
103+#include "nfs4acl.h"
104
105 /*
106 * Called when an inode is released. Note that this is different
107@@ -134,5 +136,7 @@ const struct inode_operations ext3_file_
108 .removexattr = generic_removexattr,
109 #endif
110 .permission = ext3_permission,
111+ .may_create = ext3_may_create,
112+ .may_delete = ext3_may_delete,
113 };
114
115--- a/fs/ext3/ialloc.c
116+++ b/fs/ext3/ialloc.c
117@@ -28,6 +28,7 @@
118
119 #include "xattr.h"
120 #include "acl.h"
121+#include "nfs4acl.h"
122
123 /*
124 * ialloc.c contains the inodes allocation and deallocation routines
125@@ -595,7 +596,10 @@ got:
126 goto fail_drop;
127 }
128
129- err = ext3_init_acl(handle, inode, dir);
130+ if (test_opt(sb, NFS4ACL))
131+ err = ext3_nfs4acl_init(handle, inode, dir);
132+ else
133+ err = ext3_init_acl(handle, inode, dir);
134 if (err)
135 goto fail_free_drop;
136
137--- a/fs/ext3/inode.c
138+++ b/fs/ext3/inode.c
139@@ -38,6 +38,7 @@
140 #include <linux/bio.h>
141 #include "xattr.h"
142 #include "acl.h"
143+#include "nfs4acl.h"
144
145 static int ext3_writepage_trans_blocks(struct inode *inode);
146
147@@ -2684,6 +2685,9 @@ struct inode *ext3_iget(struct super_blo
148 ei->i_acl = EXT3_ACL_NOT_CACHED;
149 ei->i_default_acl = EXT3_ACL_NOT_CACHED;
150 #endif
151+#ifdef CONFIG_EXT3_FS_NFS4ACL
152+ ei->i_nfs4acl = EXT3_NFS4ACL_NOT_CACHED;
153+#endif
154 ei->i_block_alloc_info = NULL;
155
156 ret = __ext3_get_inode_loc(inode, &iloc, 0);
157@@ -2983,6 +2987,65 @@ int ext3_write_inode(struct inode *inode
158 return ext3_force_commit(inode->i_sb);
159 }
160
161+#ifdef CONFIG_EXT3_FS_NFS4ACL
162+static int ext3_inode_change_ok(struct inode *inode, struct iattr *attr)
163+{
164+ unsigned int ia_valid = attr->ia_valid;
165+
166+ if (!test_opt(inode->i_sb, NFS4ACL))
167+ return inode_change_ok(inode, attr);
168+
169+ /* If force is set do it anyway. */
170+ if (ia_valid & ATTR_FORCE)
171+ return 0;
172+
173+ /* Make sure a caller can chown. */
174+ if ((ia_valid & ATTR_UID) &&
175+ (current->fsuid != inode->i_uid ||
176+ attr->ia_uid != inode->i_uid) &&
177+ (current->fsuid != attr->ia_uid ||
178+ ext3_nfs4acl_permission(inode, ACE4_WRITE_OWNER)) &&
179+ !capable(CAP_CHOWN))
180+ goto error;
181+
182+ /* Make sure caller can chgrp. */
183+ if ((ia_valid & ATTR_GID)) {
184+ int in_group = in_group_p(attr->ia_gid);
185+ if ((current->fsuid != inode->i_uid ||
186+ (!in_group && attr->ia_gid != inode->i_gid)) &&
187+ (!in_group ||
188+ ext3_nfs4acl_permission(inode, ACE4_WRITE_OWNER)) &&
189+ !capable(CAP_CHOWN))
190+ goto error;
191+ }
192+
193+ /* Make sure a caller can chmod. */
194+ if (ia_valid & ATTR_MODE) {
195+ if (current->fsuid != inode->i_uid &&
196+ ext3_nfs4acl_permission(inode, ACE4_WRITE_ACL) &&
197+ !capable(CAP_FOWNER))
198+ goto error;
199+ /* Also check the setgid bit! */
200+ if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
201+ inode->i_gid) && !capable(CAP_FSETID))
202+ attr->ia_mode &= ~S_ISGID;
203+ }
204+
205+ /* Check for setting the inode time. */
206+ if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) {
207+ if (current->fsuid != inode->i_uid &&
208+ ext3_nfs4acl_permission(inode, ACE4_WRITE_ATTRIBUTES) &&
209+ !capable(CAP_FOWNER))
210+ goto error;
211+ }
212+ return 0;
213+error:
214+ return -EPERM;
215+}
216+#else
217+# define ext3_inode_change_ok inode_change_ok
218+#endif
219+
220 /*
221 * ext3_setattr()
222 *
223@@ -3006,7 +3069,7 @@ int ext3_setattr(struct dentry *dentry,
224 int error, rc = 0;
225 const unsigned int ia_valid = attr->ia_valid;
226
227- error = inode_change_ok(inode, attr);
228+ error = ext3_inode_change_ok(inode, attr);
229 if (error)
230 return error;
231
232@@ -3063,8 +3126,12 @@ int ext3_setattr(struct dentry *dentry,
233 if (inode->i_nlink)
234 ext3_orphan_del(NULL, inode);
235
236- if (!rc && (ia_valid & ATTR_MODE))
237- rc = ext3_acl_chmod(inode);
238+ if (!rc && (ia_valid & ATTR_MODE)) {
239+ if (test_opt(inode->i_sb, NFS4ACL))
240+ rc = ext3_nfs4acl_chmod(inode);
241+ else
242+ rc = ext3_acl_chmod(inode);
243+ }
244
245 err_out:
246 ext3_std_error(inode->i_sb, error);
247--- a/fs/ext3/namei.c
248+++ b/fs/ext3/namei.c
249@@ -40,6 +40,7 @@
250 #include "namei.h"
251 #include "xattr.h"
252 #include "acl.h"
253+#include "nfs4acl.h"
254
255 /*
256 * define how far ahead to read directories while searching them.
257@@ -2412,6 +2413,16 @@ end_rename:
258 return retval;
259 }
260
261+int ext3_permission(struct inode *inode, int mask)
262+{
263+#ifdef CONFIG_EXT3_FS_NFS4ACL
264+ if (test_opt(inode->i_sb, NFS4ACL))
265+ return ext3_nfs4acl_permission(inode, nfs4acl_want_to_mask(mask));
266+ else
267+#endif
268+ return generic_permission(inode, mask, ext3_check_acl);
269+}
270+
271 /*
272 * directories can handle most operations...
273 */
274@@ -2433,6 +2444,8 @@ const struct inode_operations ext3_dir_i
275 .removexattr = generic_removexattr,
276 #endif
277 .permission = ext3_permission,
278+ .may_create = ext3_may_create,
279+ .may_delete = ext3_may_delete,
280 };
281
282 const struct inode_operations ext3_special_inode_operations = {
283@@ -2444,4 +2457,6 @@ const struct inode_operations ext3_speci
284 .removexattr = generic_removexattr,
285 #endif
286 .permission = ext3_permission,
287+ .may_create = ext3_may_create,
288+ .may_delete = ext3_may_delete,
289 };
290--- a/fs/ext3/namei.h
291+++ b/fs/ext3/namei.h
292@@ -5,4 +5,5 @@
293 *
294 */
295
296+extern int ext3_permission (struct inode *, int);
297 extern struct dentry *ext3_get_parent(struct dentry *child);
298--- /dev/null
299+++ b/fs/ext3/nfs4acl.c
300@@ -0,0 +1,370 @@
301+/*
302+ * Copyright (C) 2006 Andreas Gruenbacher <a.gruenbacher@computer.org>
303+ *
304+ * This program is free software; you can redistribute it and/or modify it
305+ * under the terms of the GNU General Public License as published by the
306+ * Free Software Foundation; either version 2, or (at your option) any
307+ * later version.
308+ *
309+ * This program is distributed in the hope that it will be useful, but
310+ * WITHOUT ANY WARRANTY; without even the implied warranty of
311+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
312+ * General Public License for more details.
313+ */
314+
315+#include <linux/kernel.h>
316+#include <linux/fs.h>
317+#include <linux/ext3_jbd.h>
318+#include <linux/ext3_fs.h>
319+#include <linux/nfs4acl_xattr.h>
320+#include "namei.h"
321+#include "xattr.h"
322+#include "nfs4acl.h"
323+
324+static inline struct nfs4acl *
325+ext3_iget_nfs4acl(struct inode *inode)
326+{
327+ struct nfs4acl *acl = EXT3_NFS4ACL_NOT_CACHED;
328+ struct ext3_inode_info *ei = EXT3_I(inode);
329+
330+ spin_lock(&inode->i_lock);
331+ if (ei->i_nfs4acl != EXT3_NFS4ACL_NOT_CACHED)
332+ acl = nfs4acl_get(ei->i_nfs4acl);
333+ spin_unlock(&inode->i_lock);
334+
335+ return acl;
336+}
337+
338+static inline void
339+ext3_iset_nfs4acl(struct inode *inode, struct nfs4acl *acl)
340+{
341+ struct ext3_inode_info *ei = EXT3_I(inode);
342+
343+ spin_lock(&inode->i_lock);
344+ if (ei->i_nfs4acl != EXT3_NFS4ACL_NOT_CACHED)
345+ nfs4acl_put(ei->i_nfs4acl);
346+ ei->i_nfs4acl = nfs4acl_get(acl);
347+ spin_unlock(&inode->i_lock);
348+}
349+
350+static struct nfs4acl *
351+ext3_get_nfs4acl(struct inode *inode)
352+{
353+ const int name_index = EXT3_XATTR_INDEX_NFS4ACL;
354+ void *value = NULL;
355+ struct nfs4acl *acl;
356+ int retval;
357+
358+ if (!test_opt(inode->i_sb, NFS4ACL))
359+ return NULL;
360+
361+ acl = ext3_iget_nfs4acl(inode);
362+ if (acl != EXT3_NFS4ACL_NOT_CACHED)
363+ return acl;
364+ retval = ext3_xattr_get(inode, name_index, "", NULL, 0);
365+ if (retval > 0) {
366+ value = kmalloc(retval, GFP_KERNEL);
367+ if (!value)
368+ return ERR_PTR(-ENOMEM);
369+ retval = ext3_xattr_get(inode, name_index, "", value, retval);
370+ }
371+ if (retval > 0) {
372+ acl = nfs4acl_from_xattr(value, retval);
373+ if (acl == ERR_PTR(-EINVAL))
374+ acl = ERR_PTR(-EIO);
375+ } else if (retval == -ENODATA || retval == -ENOSYS)
376+ acl = NULL;
377+ else
378+ acl = ERR_PTR(retval);
379+ kfree(value);
380+
381+ if (!IS_ERR(acl))
382+ ext3_iset_nfs4acl(inode, acl);
383+
384+ return acl;
385+}
386+
387+static int
388+ext3_set_nfs4acl(handle_t *handle, struct inode *inode, struct nfs4acl *acl)
389+{
390+ const int name_index = EXT3_XATTR_INDEX_NFS4ACL;
391+ size_t size = 0;
392+ void *value = NULL;
393+ int retval;
394+
395+ if (acl) {
396+ size = nfs4acl_xattr_size(acl);
397+ value = kmalloc(size, GFP_KERNEL);
398+ if (!value)
399+ return -ENOMEM;
400+ nfs4acl_to_xattr(acl, value);
401+ }
402+ if (handle)
403+ retval = ext3_xattr_set_handle(handle, inode, name_index, "",
404+ value, size, 0);
405+ else
406+ retval = ext3_xattr_set(inode, name_index, "", value, size, 0);
407+ if (value)
408+ kfree(value);
409+ if (!retval)
410+ ext3_iset_nfs4acl(inode, acl);
411+
412+ return retval;
413+}
414+
415+int
416+ext3_nfs4acl_permission(struct inode *inode, unsigned int mask)
417+{
418+ struct nfs4acl *acl;
419+ int retval;
420+
421+ BUG_ON(!test_opt(inode->i_sb, NFS4ACL));
422+
423+ acl = ext3_get_nfs4acl(inode);
424+ if (!acl)
425+ retval = nfs4acl_generic_permission(inode, mask);
426+ else if (IS_ERR(acl))
427+ retval = PTR_ERR(acl);
428+ else {
429+ retval = nfs4acl_permission(inode, acl, mask);
430+ nfs4acl_put(acl);
431+ }
432+
433+ return retval;
434+}
435+
436+int ext3_may_create(struct inode *dir, int isdir)
437+{
438+ int error;
439+
440+ if (test_opt(dir->i_sb, NFS4ACL)) {
441+ unsigned int mask = (isdir ? ACE4_ADD_SUBDIRECTORY : ACE4_ADD_FILE) |
442+ ACE4_EXECUTE;
443+
444+ error = ext3_nfs4acl_permission(dir, mask);
445+ } else
446+ error = ext3_permission(dir, MAY_WRITE | MAY_EXEC);
447+
448+ return error;
449+}
450+
451+static int check_sticky(struct inode *dir, struct inode *inode)
452+{
453+ if (!(dir->i_mode & S_ISVTX))
454+ return 0;
455+ if (inode->i_uid == current->fsuid)
456+ return 0;
457+ if (dir->i_uid == current->fsuid)
458+ return 0;
459+ return !capable(CAP_FOWNER);
460+}
461+
462+int ext3_may_delete(struct inode *dir, struct inode *inode)
463+{
464+ int error;
465+
466+ if (test_opt(inode->i_sb, NFS4ACL)) {
467+ error = ext3_nfs4acl_permission(dir, ACE4_DELETE_CHILD | ACE4_EXECUTE);
468+ if (!error && check_sticky(dir, inode))
469+ error = -EPERM;
470+ if (error && !ext3_nfs4acl_permission(inode, ACE4_DELETE))
471+ error = 0;
472+ } else {
473+ error = ext3_permission(dir, MAY_WRITE | MAY_EXEC);
474+ if (!error && check_sticky(dir, inode))
475+ error = -EPERM;
476+ }
477+
478+ return error;
479+}
480+
481+int
482+ext3_nfs4acl_init(handle_t *handle, struct inode *inode, struct inode *dir)
483+{
484+ struct nfs4acl *dir_acl = NULL, *acl;
485+ int retval;
486+
487+ if (!S_ISLNK(inode->i_mode))
488+ dir_acl = ext3_get_nfs4acl(dir);
489+ if (!dir_acl || IS_ERR(dir_acl)) {
490+ inode->i_mode &= ~current->fs->umask;
491+ return PTR_ERR(dir_acl);
492+ }
493+ acl = nfs4acl_inherit(dir_acl, inode->i_mode);
494+ nfs4acl_put(dir_acl);
495+
496+ retval = PTR_ERR(acl);
497+ if (acl && !IS_ERR(acl)) {
498+ retval = ext3_set_nfs4acl(handle, inode, acl);
499+ inode->i_mode = (inode->i_mode & ~S_IRWXUGO) |
500+ nfs4acl_masks_to_mode(acl);
501+ nfs4acl_put(acl);
502+ }
503+ return retval;
504+}
505+
506+int
507+ext3_nfs4acl_chmod(struct inode *inode)
508+{
509+ struct nfs4acl *acl;
510+ int retval;
511+
512+ if (S_ISLNK(inode->i_mode))
513+ return -EOPNOTSUPP;
514+ acl = ext3_get_nfs4acl(inode);
515+ if (!acl || IS_ERR(acl))
516+ return PTR_ERR(acl);
517+ acl = nfs4acl_chmod(acl, inode->i_mode);
518+ if (IS_ERR(acl))
519+ return PTR_ERR(acl);
520+ retval = ext3_set_nfs4acl(NULL, inode, acl);
521+ nfs4acl_put(acl);
522+
523+ return retval;
524+}
525+
526+static size_t
527+ext3_xattr_list_nfs4acl(struct inode *inode, char *list, size_t list_len,
528+ const char *name, size_t name_len)
529+{
530+ const size_t size = sizeof(NFS4ACL_XATTR);
531+
532+ if (!test_opt(inode->i_sb, NFS4ACL))
533+ return 0;
534+ if (list && size <= list_len)
535+ memcpy(list, NFS4ACL_XATTR, size);
536+ return size;
537+}
538+
539+static int
540+ext3_xattr_get_nfs4acl(struct inode *inode, const char *name, void *buffer,
541+ size_t buffer_size)
542+{
543+ struct nfs4acl *acl;
544+ size_t size;
545+
546+ if (!test_opt(inode->i_sb, NFS4ACL))
547+ return -EOPNOTSUPP;
548+ if (strcmp(name, "") != 0)
549+ return -EINVAL;
550+
551+ acl = ext3_get_nfs4acl(inode);
552+ if (IS_ERR(acl))
553+ return PTR_ERR(acl);
554+ if (acl == NULL)
555+ return -ENODATA;
556+ size = nfs4acl_xattr_size(acl);
557+ if (buffer) {
558+ if (size > buffer_size)
559+ return -ERANGE;
560+ nfs4acl_to_xattr(acl, buffer);
561+ }
562+ nfs4acl_put(acl);
563+
564+ return size;
565+}
566+
567+#ifdef NFS4ACL_DEBUG
568+static size_t
569+ext3_xattr_list_masked_nfs4acl(struct inode *inode, char *list, size_t list_len,
570+ const char *name, size_t name_len)
571+{
572+ return 0;
573+}
574+
575+static int
576+ext3_xattr_get_masked_nfs4acl(struct inode *inode, const char *name,
577+ void *buffer, size_t buffer_size)
578+{
579+ const int name_index = EXT3_XATTR_INDEX_NFS4ACL;
580+ struct nfs4acl *acl;
581+ void *xattr;
582+ size_t size;
583+ int retval;
584+
585+ if (!test_opt(inode->i_sb, NFS4ACL))
586+ return -EOPNOTSUPP;
587+ if (strcmp(name, "") != 0)
588+ return -EINVAL;
589+ retval = ext3_xattr_get(inode, name_index, "", NULL, 0);
590+ if (retval <= 0)
591+ return retval;
592+ xattr = kmalloc(retval, GFP_KERNEL);
593+ if (!xattr)
594+ return -ENOMEM;
595+ retval = ext3_xattr_get(inode, name_index, "", xattr, retval);
596+ if (retval <= 0)
597+ return retval;
598+ acl = nfs4acl_from_xattr(xattr, retval);
599+ kfree(xattr);
600+ if (IS_ERR(acl))
601+ return PTR_ERR(acl);
602+ retval = nfs4acl_apply_masks(&acl);
603+ if (retval) {
604+ nfs4acl_put(acl);
605+ return retval;
606+ }
607+ size = nfs4acl_xattr_size(acl);
608+ if (buffer) {
609+ if (size > buffer_size)
610+ return -ERANGE;
611+ nfs4acl_to_xattr(acl, buffer);
612+ }
613+ nfs4acl_put(acl);
614+ return size;
615+}
616+#endif
617+
618+static int
619+ext3_xattr_set_nfs4acl(struct inode *inode, const char *name,
620+ const void *value, size_t size, int flags)
621+{
622+ handle_t *handle;
623+ struct nfs4acl *acl = NULL;
624+ int retval, retries = 0;
625+
626+ if (S_ISLNK(inode->i_mode) || !test_opt(inode->i_sb, NFS4ACL))
627+ return -EOPNOTSUPP;
628+ if (strcmp(name, "") != 0)
629+ return -EINVAL;
630+ if (current->fsuid != inode->i_uid &&
631+ ext3_nfs4acl_permission(inode, ACE4_WRITE_ACL) &&
632+ !capable(CAP_FOWNER))
633+ return -EPERM;
634+ if (value) {
635+ acl = nfs4acl_from_xattr(value, size);
636+ if (IS_ERR(acl))
637+ return PTR_ERR(acl);
638+
639+ inode->i_mode &= ~S_IRWXUGO;
640+ inode->i_mode |= nfs4acl_masks_to_mode(acl);
641+ }
642+
643+retry:
644+ handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS(inode->i_sb));
645+ if (IS_ERR(handle))
646+ return PTR_ERR(handle);
647+ ext3_mark_inode_dirty(handle, inode);
648+ retval = ext3_set_nfs4acl(handle, inode, acl);
649+ ext3_journal_stop(handle);
650+ if (retval == ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries))
651+ goto retry;
652+ nfs4acl_put(acl);
653+ return retval;
654+}
655+
656+struct xattr_handler ext3_nfs4acl_xattr_handler = {
657+ .prefix = NFS4ACL_XATTR,
658+ .list = ext3_xattr_list_nfs4acl,
659+ .get = ext3_xattr_get_nfs4acl,
660+ .set = ext3_xattr_set_nfs4acl,
661+};
662+
663+#ifdef NFS4ACL_DEBUG
664+struct xattr_handler ext3_masked_nfs4acl_xattr_handler = {
665+ .prefix = "system.masked-nfs4acl",
666+ .list = ext3_xattr_list_masked_nfs4acl,
667+ .get = ext3_xattr_get_masked_nfs4acl,
668+ .set = ext3_xattr_set_nfs4acl,
669+};
670+#endif
671--- /dev/null
672+++ b/fs/ext3/nfs4acl.h
673@@ -0,0 +1,36 @@
674+#ifndef __FS_EXT3_NFS4ACL_H
675+#define __FS_EXT3_NFS4ACL_H
676+
677+#ifdef CONFIG_EXT3_FS_NFS4ACL
678+
679+#include <linux/nfs4acl.h>
680+
681+/* Value for i_nfs4acl if NFS4ACL has not been cached */
682+#define EXT3_NFS4ACL_NOT_CACHED ((void *)-1)
683+
684+extern int ext3_nfs4acl_permission(struct inode *, unsigned int);
685+extern int ext3_may_create(struct inode *, int);
686+extern int ext3_may_delete(struct inode *, struct inode *);
687+extern int ext3_nfs4acl_init(handle_t *, struct inode *, struct inode *);
688+extern int ext3_nfs4acl_chmod(struct inode *);
689+
690+#else /* CONFIG_FS_EXT3_NFS4ACL */
691+
692+#define ext3_may_create NULL
693+#define ext3_may_delete NULL
694+
695+static inline int
696+ext3_nfs4acl_init(handle_t *handle, struct inode *inode, struct inode *dir)
697+{
698+ return 0;
699+}
700+
701+static inline int
702+ext3_nfs4acl_chmod(struct inode *inode)
703+{
704+ return 0;
705+}
706+
707+#endif /* CONFIG_FS_EXT3_NFS4ACL */
708+
709+#endif /* __FS_EXT3_NFS4ACL_H */
710--- a/fs/ext3/super.c
711+++ b/fs/ext3/super.c
712@@ -36,12 +36,14 @@
713 #include <linux/namei.h>
714 #include <linux/quotaops.h>
715 #include <linux/seq_file.h>
716+#include <linux/nfs4acl.h>
717 #include <linux/log2.h>
718
719 #include <asm/uaccess.h>
720
721 #include "xattr.h"
722 #include "acl.h"
723+#include "nfs4acl.h"
724 #include "namei.h"
725
726 static int ext3_load_journal(struct super_block *, struct ext3_super_block *,
727@@ -454,6 +456,9 @@ static struct inode *ext3_alloc_inode(st
728 ei->i_acl = EXT3_ACL_NOT_CACHED;
729 ei->i_default_acl = EXT3_ACL_NOT_CACHED;
730 #endif
731+#ifdef CONFIG_EXT3_FS_NFS4ACL
732+ ei->i_nfs4acl = EXT3_NFS4ACL_NOT_CACHED;
733+#endif
734 ei->i_block_alloc_info = NULL;
735 ei->vfs_inode.i_version = 1;
736 return &ei->vfs_inode;
737@@ -516,6 +521,13 @@ static void ext3_clear_inode(struct inod
738 EXT3_I(inode)->i_default_acl = EXT3_ACL_NOT_CACHED;
739 }
740 #endif
741+#ifdef CONFIG_EXT3_FS_NFS4ACL
742+ if (EXT3_I(inode)->i_nfs4acl &&
743+ EXT3_I(inode)->i_nfs4acl != EXT3_NFS4ACL_NOT_CACHED) {
744+ nfs4acl_put(EXT3_I(inode)->i_nfs4acl);
745+ EXT3_I(inode)->i_nfs4acl = EXT3_NFS4ACL_NOT_CACHED;
746+ }
747+#endif
748 ext3_discard_reservation(inode);
749 EXT3_I(inode)->i_block_alloc_info = NULL;
750 if (unlikely(rsv))
751@@ -750,7 +762,7 @@ enum {
752 Opt_bsd_df, Opt_minix_df, Opt_grpid, Opt_nogrpid,
753 Opt_resgid, Opt_resuid, Opt_sb, Opt_err_cont, Opt_err_panic, Opt_err_ro,
754 Opt_nouid32, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov,
755- Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl,
756+ Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_acl_flavor, Opt_noacl,
757 Opt_reservation, Opt_noreservation, Opt_noload, Opt_nobh, Opt_bh,
758 Opt_commit, Opt_journal_update, Opt_journal_inum, Opt_journal_dev,
759 Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
760@@ -782,6 +794,7 @@ static match_table_t tokens = {
761 {Opt_user_xattr, "user_xattr"},
762 {Opt_nouser_xattr, "nouser_xattr"},
763 {Opt_acl, "acl"},
764+ {Opt_acl_flavor, "acl=%s"},
765 {Opt_noacl, "noacl"},
766 {Opt_reservation, "reservation"},
767 {Opt_noreservation, "noreservation"},
768@@ -925,19 +938,33 @@ static int parse_options (char *options,
769 printk("EXT3 (no)user_xattr options not supported\n");
770 break;
771 #endif
772-#ifdef CONFIG_EXT3_FS_POSIX_ACL
773 case Opt_acl:
774- set_opt(sbi->s_mount_opt, POSIX_ACL);
775+ args[0].to = args[0].from;
776+ /* fall through */
777+ case Opt_acl_flavor:
778+#ifdef CONFIG_EXT3_FS_POSIX_ACL
779+ if (match_string(&args[0], "") ||
780+ match_string(&args[0], "posix")) {
781+ set_opt(sbi->s_mount_opt, POSIX_ACL);
782+ clear_opt(sbi->s_mount_opt, NFS4ACL);
783+ } else
784+#endif
785+#ifdef CONFIG_EXT3_FS_NFS4ACL
786+ if (match_string(&args[0], "nfs4")) {
787+ clear_opt(sbi->s_mount_opt, POSIX_ACL);
788+ set_opt(sbi->s_mount_opt, NFS4ACL);
789+ } else
790+#endif
791+ {
792+ printk(KERN_ERR "EXT3-fs: unsupported acl "
793+ "flavor\n");
794+ return 0;
795+ }
796 break;
797 case Opt_noacl:
798 clear_opt(sbi->s_mount_opt, POSIX_ACL);
799+ clear_opt(sbi->s_mount_opt, NFS4ACL);
800 break;
801-#else
802- case Opt_acl:
803- case Opt_noacl:
804- printk("EXT3 (no)acl options not supported\n");
805- break;
806-#endif
807 case Opt_reservation:
808 set_opt(sbi->s_mount_opt, RESERVATION);
809 break;
810@@ -1607,8 +1634,11 @@ static int ext3_fill_super (struct super
811 NULL, 0))
812 goto failed_mount;
813
814- sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
815- ((sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
816+ sb->s_flags = (sb->s_flags & ~MS_POSIXACL);
817+ if (sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL)
818+ sb->s_flags |= MS_POSIXACL;
819+ if (sbi->s_mount_opt & EXT3_MOUNT_NFS4ACL)
820+ sb->s_flags |= MS_POSIXACL | MS_WITHAPPEND;
821
822 if (le32_to_cpu(es->s_rev_level) == EXT3_GOOD_OLD_REV &&
823 (EXT3_HAS_COMPAT_FEATURE(sb, ~0U) ||
824@@ -2451,8 +2481,12 @@ static int ext3_remount (struct super_bl
825 if (sbi->s_mount_opt & EXT3_MOUNT_ABORT)
826 ext3_abort(sb, __func__, "Abort forced by user");
827
828- sb->s_flags = (sb->s_flags & ~MS_POSIXACL) |
829- ((sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0);
830+ sb->s_flags = (sb->s_flags & ~MS_POSIXACL);
831+ if (sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL)
832+ sb->s_flags |= MS_POSIXACL;
833+ if (sbi->s_mount_opt & EXT3_MOUNT_NFS4ACL)
834+ sb->s_flags |= MS_POSIXACL;
835+
836
837 es = sbi->s_es;
838
839--- a/fs/ext3/xattr.c
840+++ b/fs/ext3/xattr.c
841@@ -114,6 +114,9 @@ static struct xattr_handler *ext3_xattr_
842 #ifdef CONFIG_EXT3_FS_SECURITY
843 [EXT3_XATTR_INDEX_SECURITY] = &ext3_xattr_security_handler,
844 #endif
845+#ifdef CONFIG_EXT3_FS_NFS4ACL
846+ [EXT3_XATTR_INDEX_NFS4ACL] = &ext3_nfs4acl_xattr_handler,
847+#endif
848 };
849
850 struct xattr_handler *ext3_xattr_handlers[] = {
851@@ -126,6 +129,12 @@ struct xattr_handler *ext3_xattr_handler
852 #ifdef CONFIG_EXT3_FS_SECURITY
853 &ext3_xattr_security_handler,
854 #endif
855+#ifdef CONFIG_EXT3_FS_NFS4ACL
856+ &ext3_nfs4acl_xattr_handler,
857+#ifdef NFS4ACL_DEBUG
858+ &ext3_masked_nfs4acl_xattr_handler,
859+#endif
860+#endif
861 NULL
862 };
863
864--- a/fs/ext3/xattr.h
865+++ b/fs/ext3/xattr.h
866@@ -21,6 +21,7 @@
867 #define EXT3_XATTR_INDEX_TRUSTED 4
868 #define EXT3_XATTR_INDEX_LUSTRE 5
869 #define EXT3_XATTR_INDEX_SECURITY 6
870+#define EXT3_XATTR_INDEX_NFS4ACL 7
871
872 struct ext3_xattr_header {
873 __le32 h_magic; /* magic number for identification */
874@@ -63,6 +64,10 @@ extern struct xattr_handler ext3_xattr_t
875 extern struct xattr_handler ext3_xattr_acl_access_handler;
876 extern struct xattr_handler ext3_xattr_acl_default_handler;
877 extern struct xattr_handler ext3_xattr_security_handler;
878+extern struct xattr_handler ext3_nfs4acl_xattr_handler;
879+#ifdef NFS4ACL_DEBUG
880+extern struct xattr_handler ext3_masked_nfs4acl_xattr_handler;
881+#endif
882
883 extern ssize_t ext3_listxattr(struct dentry *, char *, size_t);
884
885--- a/include/linux/ext3_fs.h
886+++ b/include/linux/ext3_fs.h
887@@ -380,6 +380,7 @@ struct ext3_inode {
888 #define EXT3_MOUNT_QUOTA 0x80000 /* Some quota option set */
889 #define EXT3_MOUNT_USRQUOTA 0x100000 /* "old" user quota */
890 #define EXT3_MOUNT_GRPQUOTA 0x200000 /* "old" group quota */
891+#define EXT3_MOUNT_NFS4ACL 0x400000 /* NFS version 4 ACLs */
892
893 /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
894 #ifndef _LINUX_EXT2_FS_H
895--- a/include/linux/ext3_fs_i.h
896+++ b/include/linux/ext3_fs_i.h
897@@ -107,6 +107,9 @@ struct ext3_inode_info {
898 struct posix_acl *i_acl;
899 struct posix_acl *i_default_acl;
900 #endif
901+#ifdef CONFIG_EXT3_FS_NFS4ACL
902+ struct nfs4acl *i_nfs4acl;
903+#endif
904
905 struct list_head i_orphan; /* unlinked but open inodes */
906