]> git.ipfire.org Git - ipfire-2.x.git/blame - src/patches/suse-2.6.27.31/patches.suse/nfs4acl-common.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-common.diff
CommitLineData
6a930a95
BS
1From: Andreas Gruenbacher <agruen@suse.de>
2Subject: NFSv4 ACL in-memory representation and manipulation
3
4* In-memory representation (struct nfs4acl).
5* Functionality a filesystem needs such as permission checking,
6 apply mode to acl, compute mode from acl, inheritance upon file
7 create.
8* Compute a mask-less acl from struct nfs4acl that grants the same
9 permissions. Protocols which don't understand the masks need
10 this.
11* Convert to/from xattrs.
12
13Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
14
15---
16 fs/Kconfig | 4
17 fs/Makefile | 4
18 fs/nfs4acl_base.c | 565 +++++++++++++++++++++++++++++++
19 fs/nfs4acl_compat.c | 757 ++++++++++++++++++++++++++++++++++++++++++
20 fs/nfs4acl_xattr.c | 146 ++++++++
21 include/linux/nfs4acl.h | 205 +++++++++++
22 include/linux/nfs4acl_xattr.h | 32 +
23 7 files changed, 1713 insertions(+)
24
25--- a/fs/Kconfig
26+++ b/fs/Kconfig
27@@ -419,6 +419,10 @@ config FS_POSIX_ACL
28 bool
29 default n
30
31+config FS_NFS4ACL
32+ bool
33+ default n
34+
35 source "fs/xfs/Kconfig"
36 source "fs/gfs2/Kconfig"
37
38--- a/fs/Makefile
39+++ b/fs/Makefile
40@@ -50,6 +50,10 @@ obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.
41 obj-$(CONFIG_NFS_COMMON) += nfs_common/
42 obj-$(CONFIG_GENERIC_ACL) += generic_acl.o
43
44+obj-$(CONFIG_FS_NFS4ACL) += nfs4acl.o
45+nfs4acl-y := nfs4acl_base.o nfs4acl_xattr.o \
46+ nfs4acl_compat.o
47+
48 obj-$(CONFIG_QUOTA) += dquot.o
49 obj-$(CONFIG_QFMT_V1) += quota_v1.o
50 obj-$(CONFIG_QFMT_V2) += quota_v2.o
51--- /dev/null
52+++ b/fs/nfs4acl_base.c
53@@ -0,0 +1,565 @@
54+/*
55+ * Copyright (C) 2006 Andreas Gruenbacher <a.gruenbacher@computer.org>
56+ *
57+ * This program is free software; you can redistribute it and/or modify it
58+ * under the terms of the GNU General Public License as published by the
59+ * Free Software Foundation; either version 2, or (at your option) any
60+ * later version.
61+ *
62+ * This program is distributed in the hope that it will be useful, but
63+ * WITHOUT ANY WARRANTY; without even the implied warranty of
64+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
65+ * General Public License for more details.
66+ */
67+
68+#include <linux/sched.h>
69+#include <linux/module.h>
70+#include <linux/fs.h>
71+#include <linux/nfs4acl.h>
72+
73+MODULE_LICENSE("GPL");
74+
75+/*
76+ * ACL entries that have ACE4_SPECIAL_WHO set in ace->e_flags use the
77+ * pointer values of these constants in ace->u.e_who to avoid massive
78+ * amounts of string comparisons.
79+ */
80+
81+const char nfs4ace_owner_who[] = "OWNER@";
82+const char nfs4ace_group_who[] = "GROUP@";
83+const char nfs4ace_everyone_who[] = "EVERYONE@";
84+
85+EXPORT_SYMBOL(nfs4ace_owner_who);
86+EXPORT_SYMBOL(nfs4ace_group_who);
87+EXPORT_SYMBOL(nfs4ace_everyone_who);
88+
89+/**
90+ * nfs4acl_alloc - allocate an acl
91+ * @count: number of entries
92+ */
93+struct nfs4acl *
94+nfs4acl_alloc(int count)
95+{
96+ size_t size = sizeof(struct nfs4acl) + count * sizeof(struct nfs4ace);
97+ struct nfs4acl *acl = kmalloc(size, GFP_KERNEL);
98+
99+ if (acl) {
100+ memset(acl, 0, size);
101+ atomic_set(&acl->a_refcount, 1);
102+ acl->a_count = count;
103+ }
104+ return acl;
105+}
106+EXPORT_SYMBOL(nfs4acl_alloc);
107+
108+/**
109+ * nfs4acl_clone - create a copy of an acl
110+ */
111+struct nfs4acl *
112+nfs4acl_clone(const struct nfs4acl *acl)
113+{
114+ int count = acl->a_count;
115+ size_t size = sizeof(struct nfs4acl) + count * sizeof(struct nfs4ace);
116+ struct nfs4acl *dup = kmalloc(size, GFP_KERNEL);
117+
118+ if (dup) {
119+ memcpy(dup, acl, size);
120+ atomic_set(&dup->a_refcount, 1);
121+ }
122+ return dup;
123+}
124+
125+/*
126+ * The POSIX permissions are supersets of the below mask flags.
127+ *
128+ * The ACE4_READ_ATTRIBUTES and ACE4_READ_ACL flags are always granted
129+ * in POSIX. The ACE4_SYNCHRONIZE flag has no meaning under POSIX. We
130+ * make sure that we do not mask them if they are set, so that users who
131+ * rely on these flags won't get confused.
132+ */
133+#define ACE4_POSIX_MODE_READ ( \
134+ ACE4_READ_DATA | ACE4_LIST_DIRECTORY )
135+#define ACE4_POSIX_MODE_WRITE ( \
136+ ACE4_WRITE_DATA | ACE4_ADD_FILE | \
137+ ACE4_APPEND_DATA | ACE4_ADD_SUBDIRECTORY | \
138+ ACE4_DELETE_CHILD )
139+#define ACE4_POSIX_MODE_EXEC ( \
140+ ACE4_EXECUTE)
141+
142+static int
143+nfs4acl_mask_to_mode(unsigned int mask)
144+{
145+ int mode = 0;
146+
147+ if (mask & ACE4_POSIX_MODE_READ)
148+ mode |= MAY_READ;
149+ if (mask & ACE4_POSIX_MODE_WRITE)
150+ mode |= MAY_WRITE;
151+ if (mask & ACE4_POSIX_MODE_EXEC)
152+ mode |= MAY_EXEC;
153+
154+ return mode;
155+}
156+
157+/**
158+ * nfs4acl_masks_to_mode - compute file mode permission bits from file masks
159+ *
160+ * Compute the file mode permission bits from the file masks in the acl.
161+ */
162+int
163+nfs4acl_masks_to_mode(const struct nfs4acl *acl)
164+{
165+ return nfs4acl_mask_to_mode(acl->a_owner_mask) << 6 |
166+ nfs4acl_mask_to_mode(acl->a_group_mask) << 3 |
167+ nfs4acl_mask_to_mode(acl->a_other_mask);
168+}
169+EXPORT_SYMBOL(nfs4acl_masks_to_mode);
170+
171+static unsigned int
172+nfs4acl_mode_to_mask(mode_t mode)
173+{
174+ unsigned int mask = ACE4_POSIX_ALWAYS_ALLOWED;
175+
176+ if (mode & MAY_READ)
177+ mask |= ACE4_POSIX_MODE_READ;
178+ if (mode & MAY_WRITE)
179+ mask |= ACE4_POSIX_MODE_WRITE;
180+ if (mode & MAY_EXEC)
181+ mask |= ACE4_POSIX_MODE_EXEC;
182+
183+ return mask;
184+}
185+
186+/**
187+ * nfs4acl_chmod - update the file masks to reflect the new mode
188+ * @mode: file mode permission bits to apply to the @acl
189+ *
190+ * Converts the mask flags corresponding to the owner, group, and other file
191+ * permissions and computes the file masks. Returns @acl if it already has the
192+ * appropriate file masks, or updates the flags in a copy of @acl. Takes over
193+ * @acl.
194+ */
195+struct nfs4acl *
196+nfs4acl_chmod(struct nfs4acl *acl, mode_t mode)
197+{
198+ unsigned int owner_mask, group_mask, other_mask;
199+ struct nfs4acl *clone;
200+
201+ owner_mask = nfs4acl_mode_to_mask(mode >> 6);
202+ group_mask = nfs4acl_mode_to_mask(mode >> 3);
203+ other_mask = nfs4acl_mode_to_mask(mode);
204+
205+ if (acl->a_owner_mask == owner_mask &&
206+ acl->a_group_mask == group_mask &&
207+ acl->a_other_mask == other_mask)
208+ return acl;
209+
210+ clone = nfs4acl_clone(acl);
211+ nfs4acl_put(acl);
212+ if (!clone)
213+ return ERR_PTR(-ENOMEM);
214+
215+ clone->a_owner_mask = owner_mask;
216+ clone->a_group_mask = group_mask;
217+ clone->a_other_mask = other_mask;
218+
219+ if (nfs4acl_write_through(&clone)) {
220+ nfs4acl_put(clone);
221+ clone = ERR_PTR(-ENOMEM);
222+ }
223+ return clone;
224+}
225+EXPORT_SYMBOL(nfs4acl_chmod);
226+
227+/**
228+ * nfs4acl_want_to_mask - convert permission want argument to a mask
229+ * @want: @want argument of the permission inode operation
230+ *
231+ * When checking for append, @want is (MAY_WRITE | MAY_APPEND).
232+ */
233+unsigned int
234+nfs4acl_want_to_mask(int want)
235+{
236+ unsigned int mask = 0;
237+
238+ if (want & MAY_READ)
239+ mask |= ACE4_READ_DATA;
240+ if (want & MAY_APPEND)
241+ mask |= ACE4_APPEND_DATA;
242+ else if (want & MAY_WRITE)
243+ mask |= ACE4_WRITE_DATA;
244+ if (want & MAY_EXEC)
245+ mask |= ACE4_EXECUTE;
246+
247+ return mask;
248+}
249+EXPORT_SYMBOL(nfs4acl_want_to_mask);
250+
251+/**
252+ * nfs4acl_capability_check - check for capabilities overriding read/write access
253+ * @inode: inode to check
254+ * @mask: requested access (ACE4_* bitmask)
255+ *
256+ * Capabilities other than CAP_DAC_OVERRIDE and CAP_DAC_READ_SEARCH must be checked
257+ * separately.
258+ */
259+static inline int nfs4acl_capability_check(struct inode *inode, unsigned int mask)
260+{
261+ /*
262+ * Read/write DACs are always overridable.
263+ * Executable DACs are overridable if at least one exec bit is set.
264+ */
265+ if (!(mask & (ACE4_WRITE_ACL | ACE4_WRITE_OWNER)) &&
266+ (!(mask & ACE4_EXECUTE) ||
267+ (inode->i_mode & S_IXUGO) || S_ISDIR(inode->i_mode)))
268+ if (capable(CAP_DAC_OVERRIDE))
269+ return 0;
270+
271+ /*
272+ * Searching includes executable on directories, else just read.
273+ */
274+ if (!(mask & ~(ACE4_READ_DATA | ACE4_EXECUTE)) &&
275+ (S_ISDIR(inode->i_mode) || !(mask & ACE4_EXECUTE)))
276+ if (capable(CAP_DAC_READ_SEARCH))
277+ return 0;
278+
279+ return -EACCES;
280+}
281+
282+/**
283+ * nfs4acl_permission - permission check algorithm with masking
284+ * @inode: inode to check
285+ * @acl: nfs4 acl of the inode
286+ * @mask: requested access (ACE4_* bitmask)
287+ *
288+ * Checks if the current process is granted @mask flags in @acl. With
289+ * write-through, the OWNER@ is always granted the owner file mask, the
290+ * GROUP@ is always granted the group file mask, and EVERYONE@ is always
291+ * granted the other file mask. Otherwise, processes are only granted
292+ * @mask flags which they are granted in the @acl as well as in their
293+ * file mask.
294+ */
295+int nfs4acl_permission(struct inode *inode, const struct nfs4acl *acl,
296+ unsigned int mask)
297+{
298+ const struct nfs4ace *ace;
299+ unsigned int file_mask, requested = mask, denied = 0;
300+ int in_owning_group = in_group_p(inode->i_gid);
301+ int owner_or_group_class = in_owning_group;
302+
303+ /*
304+ * A process is in the
305+ * - owner file class if it owns the file, in the
306+ * - group file class if it is in the file's owning group or
307+ * it matches any of the user or group entries, and in the
308+ * - other file class otherwise.
309+ */
310+
311+ nfs4acl_for_each_entry(ace, acl) {
312+ unsigned int ace_mask = ace->e_mask;
313+
314+ if (nfs4ace_is_inherit_only(ace))
315+ continue;
316+ if (nfs4ace_is_owner(ace)) {
317+ if (current->fsuid != inode->i_uid)
318+ continue;
319+ goto is_owner;
320+ } else if (nfs4ace_is_group(ace)) {
321+ if (!in_owning_group)
322+ continue;
323+ } else if (nfs4ace_is_unix_id(ace)) {
324+ if (ace->e_flags & ACE4_IDENTIFIER_GROUP) {
325+ if (!in_group_p(ace->u.e_id))
326+ continue;
327+ } else {
328+ if (current->fsuid != ace->u.e_id)
329+ continue;
330+ }
331+ } else
332+ goto is_everyone;
333+
334+ /*
335+ * Apply the group file mask to entries other than OWNER@ and
336+ * EVERYONE@. This is not required for correct access checking
337+ * but ensures that we grant the same permissions as the acl
338+ * computed by nfs4acl_apply_masks().
339+ *
340+ * For example, without this restriction, 'group@:rw::allow'
341+ * with mode 0600 would grant rw access to owner processes
342+ * which are also in the owning group. This cannot be expressed
343+ * in an acl.
344+ */
345+ if (nfs4ace_is_allow(ace))
346+ ace_mask &= acl->a_group_mask;
347+
348+ is_owner:
349+ /* The process is in the owner or group file class. */
350+ owner_or_group_class = 1;
351+
352+ is_everyone:
353+ /* Check which mask flags the ACE allows or denies. */
354+ if (nfs4ace_is_deny(ace))
355+ denied |= ace_mask & mask;
356+ mask &= ~ace_mask;
357+
358+ /* Keep going until we know which file class the process is in. */
359+ if (!mask && owner_or_group_class)
360+ break;
361+ }
362+ denied |= mask;
363+
364+ /*
365+ * Figure out which file mask applies.
366+ * Clear write-through if the process is in the file group class but
367+ * not in the owning group, and so the denied permissions apply.
368+ */
369+ if (current->fsuid == inode->i_uid)
370+ file_mask = acl->a_owner_mask;
371+ else if (in_owning_group || owner_or_group_class)
372+ file_mask = acl->a_group_mask;
373+ else
374+ file_mask = acl->a_other_mask;
375+
376+ denied |= requested & ~file_mask;
377+ if (!denied)
378+ return 0;
379+ return nfs4acl_capability_check(inode, requested);
380+}
381+EXPORT_SYMBOL(nfs4acl_permission);
382+
383+/**
384+ * nfs4acl_generic_permission - permission check algorithm without explicit acl
385+ * @inode: inode to check permissions for
386+ * @mask: requested access (ACE4_* bitmask)
387+ *
388+ * The file mode of a file without ACL corresponds to an ACL with a single
389+ * "EVERYONE:~0::ALLOW" entry, with file masks that correspond to the file mode
390+ * permissions. Instead of constructing a temporary ACL and applying
391+ * nfs4acl_permission() to it, compute the identical result directly from the file
392+ * mode.
393+ */
394+int nfs4acl_generic_permission(struct inode *inode, unsigned int mask)
395+{
396+ int mode = inode->i_mode;
397+
398+ if (current->fsuid == inode->i_uid)
399+ mode >>= 6;
400+ else if (in_group_p(inode->i_gid))
401+ mode >>= 3;
402+ if (!(mask & ~nfs4acl_mode_to_mask(mode)))
403+ return 0;
404+ return nfs4acl_capability_check(inode, mask);
405+}
406+EXPORT_SYMBOL(nfs4acl_generic_permission);
407+
408+/*
409+ * nfs4ace_is_same_who - do both acl entries refer to the same identifier?
410+ */
411+int
412+nfs4ace_is_same_who(const struct nfs4ace *a, const struct nfs4ace *b)
413+{
414+#define WHO_FLAGS (ACE4_SPECIAL_WHO | ACE4_IDENTIFIER_GROUP)
415+ if ((a->e_flags & WHO_FLAGS) != (b->e_flags & WHO_FLAGS))
416+ return 0;
417+ if (a->e_flags & ACE4_SPECIAL_WHO)
418+ return a->u.e_who == b->u.e_who;
419+ else
420+ return a->u.e_id == b->u.e_id;
421+#undef WHO_FLAGS
422+}
423+
424+/**
425+ * nfs4acl_set_who - set a special who value
426+ * @ace: acl entry
427+ * @who: who value to use
428+ */
429+int
430+nfs4ace_set_who(struct nfs4ace *ace, const char *who)
431+{
432+ if (!strcmp(who, nfs4ace_owner_who))
433+ who = nfs4ace_owner_who;
434+ else if (!strcmp(who, nfs4ace_group_who))
435+ who = nfs4ace_group_who;
436+ else if (!strcmp(who, nfs4ace_everyone_who))
437+ who = nfs4ace_everyone_who;
438+ else
439+ return -EINVAL;
440+
441+ ace->u.e_who = who;
442+ ace->e_flags |= ACE4_SPECIAL_WHO;
443+ ace->e_flags &= ~ACE4_IDENTIFIER_GROUP;
444+ return 0;
445+}
446+EXPORT_SYMBOL(nfs4ace_set_who);
447+
448+/**
449+ * nfs4acl_allowed_to_who - mask flags allowed to a specific who value
450+ *
451+ * Computes the mask values allowed to a specific who value, taking
452+ * EVERYONE@ entries into account.
453+ */
454+static unsigned int
455+nfs4acl_allowed_to_who(struct nfs4acl *acl, struct nfs4ace *who)
456+{
457+ struct nfs4ace *ace;
458+ unsigned int allowed = 0;
459+
460+ nfs4acl_for_each_entry_reverse(ace, acl) {
461+ if (nfs4ace_is_inherit_only(ace))
462+ continue;
463+ if (nfs4ace_is_same_who(ace, who) ||
464+ nfs4ace_is_everyone(ace)) {
465+ if (nfs4ace_is_allow(ace))
466+ allowed |= ace->e_mask;
467+ else if (nfs4ace_is_deny(ace))
468+ allowed &= ~ace->e_mask;
469+ }
470+ }
471+ return allowed;
472+}
473+
474+/**
475+ * nfs4acl_compute_max_masks - compute upper bound masks
476+ *
477+ * Computes upper bound owner, group, and other masks so that none of
478+ * the mask flags allowed by the acl are disabled (for any choice of the
479+ * file owner or group membership).
480+ */
481+static void
482+nfs4acl_compute_max_masks(struct nfs4acl *acl)
483+{
484+ struct nfs4ace *ace;
485+
486+ acl->a_owner_mask = 0;
487+ acl->a_group_mask = 0;
488+ acl->a_other_mask = 0;
489+
490+ nfs4acl_for_each_entry_reverse(ace, acl) {
491+ if (nfs4ace_is_inherit_only(ace))
492+ continue;
493+
494+ if (nfs4ace_is_owner(ace)) {
495+ if (nfs4ace_is_allow(ace))
496+ acl->a_owner_mask |= ace->e_mask;
497+ else if (nfs4ace_is_deny(ace))
498+ acl->a_owner_mask &= ~ace->e_mask;
499+ } else if (nfs4ace_is_everyone(ace)) {
500+ if (nfs4ace_is_allow(ace)) {
501+ struct nfs4ace who = {
502+ .e_flags = ACE4_SPECIAL_WHO,
503+ .u.e_who = nfs4ace_group_who,
504+ };
505+
506+ acl->a_other_mask |= ace->e_mask;
507+ acl->a_group_mask |=
508+ nfs4acl_allowed_to_who(acl, &who);
509+ acl->a_owner_mask |= ace->e_mask;
510+ } else if (nfs4ace_is_deny(ace)) {
511+ acl->a_other_mask &= ~ace->e_mask;
512+ acl->a_group_mask &= ~ace->e_mask;
513+ acl->a_owner_mask &= ~ace->e_mask;
514+ }
515+ } else {
516+ if (nfs4ace_is_allow(ace)) {
517+ unsigned int mask =
518+ nfs4acl_allowed_to_who(acl, ace);
519+
520+ acl->a_group_mask |= mask;
521+ acl->a_owner_mask |= mask;
522+ }
523+ }
524+ }
525+}
526+
527+/**
528+ * nfs4acl_inherit - compute the acl a new file will inherit
529+ * @dir_acl: acl of the containing direcory
530+ * @mode: file type and create mode of the new file
531+ *
532+ * Given the containing directory's acl, this function will compute the
533+ * acl that new files in that directory will inherit, or %NULL if
534+ * @dir_acl does not contain acl entries inheritable by this file.
535+ *
536+ * Without write-through, the file masks in the returned acl are set to
537+ * the intersection of the create mode and the maximum permissions
538+ * allowed to each file class. With write-through, the file masks are
539+ * set to the create mode.
540+ */
541+struct nfs4acl *
542+nfs4acl_inherit(const struct nfs4acl *dir_acl, mode_t mode)
543+{
544+ const struct nfs4ace *dir_ace;
545+ struct nfs4acl *acl;
546+ struct nfs4ace *ace;
547+ int count = 0;
548+
549+ if (S_ISDIR(mode)) {
550+ nfs4acl_for_each_entry(dir_ace, dir_acl) {
551+ if (!nfs4ace_is_inheritable(dir_ace))
552+ continue;
553+ count++;
554+ }
555+ if (!count)
556+ return NULL;
557+ acl = nfs4acl_alloc(count);
558+ if (!acl)
559+ return ERR_PTR(-ENOMEM);
560+ ace = acl->a_entries;
561+ nfs4acl_for_each_entry(dir_ace, dir_acl) {
562+ if (!nfs4ace_is_inheritable(dir_ace))
563+ continue;
564+ memcpy(ace, dir_ace, sizeof(struct nfs4ace));
565+ if (dir_ace->e_flags & ACE4_NO_PROPAGATE_INHERIT_ACE)
566+ nfs4ace_clear_inheritance_flags(ace);
567+ if ((dir_ace->e_flags & ACE4_FILE_INHERIT_ACE) &&
568+ !(dir_ace->e_flags & ACE4_DIRECTORY_INHERIT_ACE))
569+ ace->e_flags |= ACE4_INHERIT_ONLY_ACE;
570+ ace++;
571+ }
572+ } else {
573+ nfs4acl_for_each_entry(dir_ace, dir_acl) {
574+ if (!(dir_ace->e_flags & ACE4_FILE_INHERIT_ACE))
575+ continue;
576+ count++;
577+ }
578+ if (!count)
579+ return NULL;
580+ acl = nfs4acl_alloc(count);
581+ if (!acl)
582+ return ERR_PTR(-ENOMEM);
583+ ace = acl->a_entries;
584+ nfs4acl_for_each_entry(dir_ace, dir_acl) {
585+ if (!(dir_ace->e_flags & ACE4_FILE_INHERIT_ACE))
586+ continue;
587+ memcpy(ace, dir_ace, sizeof(struct nfs4ace));
588+ nfs4ace_clear_inheritance_flags(ace);
589+ ace++;
590+ }
591+ }
592+
593+ /* The maximum max flags that the owner, group, and other classes
594+ are allowed. */
595+ if (dir_acl->a_flags & ACL4_WRITE_THROUGH) {
596+ acl->a_owner_mask = ACE4_VALID_MASK;
597+ acl->a_group_mask = ACE4_VALID_MASK;
598+ acl->a_other_mask = ACE4_VALID_MASK;
599+
600+ mode &= ~current->fs->umask;
601+ } else
602+ nfs4acl_compute_max_masks(acl);
603+
604+ /* Apply the create mode. */
605+ acl->a_owner_mask &= nfs4acl_mode_to_mask(mode >> 6);
606+ acl->a_group_mask &= nfs4acl_mode_to_mask(mode >> 3);
607+ acl->a_other_mask &= nfs4acl_mode_to_mask(mode);
608+
609+ if (nfs4acl_write_through(&acl)) {
610+ nfs4acl_put(acl);
611+ return ERR_PTR(-ENOMEM);
612+ }
613+
614+ acl->a_flags = (dir_acl->a_flags & ACL4_WRITE_THROUGH);
615+
616+ return acl;
617+}
618+EXPORT_SYMBOL(nfs4acl_inherit);
619--- /dev/null
620+++ b/fs/nfs4acl_compat.c
621@@ -0,0 +1,757 @@
622+/*
623+ * Copyright (C) 2006 Andreas Gruenbacher <a.gruenbacher@computer.org>
624+ *
625+ * This program is free software; you can redistribute it and/or modify it
626+ * under the terms of the GNU General Public License as published by the
627+ * Free Software Foundation; either version 2, or (at your option) any
628+ * later version.
629+ *
630+ * This program is distributed in the hope that it will be useful, but
631+ * WITHOUT ANY WARRANTY; without even the implied warranty of
632+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
633+ * General Public License for more details.
634+ */
635+
636+#include <linux/module.h>
637+#include <linux/fs.h>
638+#include <linux/nfs4acl.h>
639+
640+/**
641+ * struct nfs4acl_alloc - remember how many entries are actually allocated
642+ * @acl: acl with a_count <= @count
643+ * @count: the actual number of entries allocated in @acl
644+ *
645+ * We pass around this structure while modifying an acl, so that we do
646+ * not have to reallocate when we remove existing entries followed by
647+ * adding new entries.
648+ */
649+struct nfs4acl_alloc {
650+ struct nfs4acl *acl;
651+ unsigned int count;
652+};
653+
654+/**
655+ * nfs4acl_delete_entry - delete an entry in an acl
656+ * @x: acl and number of allocated entries
657+ * @ace: an entry in @x->acl
658+ *
659+ * Updates @ace so that it points to the entry before the deleted entry
660+ * on return. (When deleting the first entry, @ace will point to the
661+ * (non-existant) entry before the first entry). This behavior is the
662+ * expected behavior when deleting entries while forward iterating over
663+ * an acl.
664+ */
665+static void
666+nfs4acl_delete_entry(struct nfs4acl_alloc *x, struct nfs4ace **ace)
667+{
668+ void *end = x->acl->a_entries + x->acl->a_count;
669+
670+ memmove(*ace, *ace + 1, end - (void *)(*ace + 1));
671+ (*ace)--;
672+ x->acl->a_count--;
673+}
674+
675+/**
676+ * nfs4acl_insert_entry - insert an entry in an acl
677+ * @x: acl and number of allocated entries
678+ * @ace: entry before which the new entry shall be inserted
679+ *
680+ * Insert a new entry in @x->acl at position @ace, and zero-initialize
681+ * it. This may require reallocating @x->acl.
682+ */
683+static int
684+nfs4acl_insert_entry(struct nfs4acl_alloc *x, struct nfs4ace **ace)
685+{
686+ if (x->count == x->acl->a_count) {
687+ int n = *ace - x->acl->a_entries;
688+ struct nfs4acl *acl2;
689+
690+ acl2 = nfs4acl_alloc(x->acl->a_count + 1);
691+ if (!acl2)
692+ return -1;
693+ acl2->a_flags = x->acl->a_flags;
694+ acl2->a_owner_mask = x->acl->a_owner_mask;
695+ acl2->a_group_mask = x->acl->a_group_mask;
696+ acl2->a_other_mask = x->acl->a_other_mask;
697+ memcpy(acl2->a_entries, x->acl->a_entries,
698+ n * sizeof(struct nfs4ace));
699+ memcpy(acl2->a_entries + n + 1, *ace,
700+ (x->acl->a_count - n) * sizeof(struct nfs4ace));
701+ kfree(x->acl);
702+ x->acl = acl2;
703+ x->count = acl2->a_count;
704+ *ace = acl2->a_entries + n;
705+ } else {
706+ void *end = x->acl->a_entries + x->acl->a_count;
707+
708+ memmove(*ace + 1, *ace, end - (void *)*ace);
709+ x->acl->a_count++;
710+ }
711+ memset(*ace, 0, sizeof(struct nfs4ace));
712+ return 0;
713+}
714+
715+/**
716+ * nfs4ace_change_mask - change the mask in @ace to @mask
717+ * @x: acl and number of allocated entries
718+ * @ace: entry to modify
719+ * @mask: new mask for @ace
720+ *
721+ * Set the effective mask of @ace to @mask. This will require splitting
722+ * off a separate acl entry if @ace is inheritable. In that case, the
723+ * effective- only acl entry is inserted after the inheritable acl
724+ * entry, end the inheritable acl entry is set to inheritable-only. If
725+ * @mode is 0, either set the original acl entry to inheritable-only if
726+ * it was inheritable, or remove it otherwise. The returned @ace points
727+ * to the modified or inserted effective-only acl entry if that entry
728+ * exists, to the entry that has become inheritable-only, or else to the
729+ * previous entry in the acl. This is the expected behavior when
730+ * modifying masks while forward iterating over an acl.
731+ */
732+static int
733+nfs4ace_change_mask(struct nfs4acl_alloc *x, struct nfs4ace **ace,
734+ unsigned int mask)
735+{
736+ if (mask && (*ace)->e_mask == mask)
737+ return 0;
738+ if (mask & ~ACE4_POSIX_ALWAYS_ALLOWED) {
739+ if (nfs4ace_is_inheritable(*ace)) {
740+ if (nfs4acl_insert_entry(x, ace))
741+ return -1;
742+ memcpy(*ace, *ace + 1, sizeof(struct nfs4ace));
743+ (*ace)->e_flags |= ACE4_INHERIT_ONLY_ACE;
744+ (*ace)++;
745+ nfs4ace_clear_inheritance_flags(*ace);
746+ }
747+ (*ace)->e_mask = mask;
748+ } else {
749+ if (nfs4ace_is_inheritable(*ace))
750+ (*ace)->e_flags |= ACE4_INHERIT_ONLY_ACE;
751+ else
752+ nfs4acl_delete_entry(x, ace);
753+ }
754+ return 0;
755+}
756+
757+/**
758+ * nfs4acl_move_everyone_aces_down - move everyone@ acl entries to the end
759+ * @x: acl and number of allocated entries
760+ *
761+ * Move all everyone acl entries to the bottom of the acl so that only a
762+ * single everyone@ allow acl entry remains at the end, and update the
763+ * mask fields of all acl entries on the way. If everyone@ is not
764+ * granted any permissions, no empty everyone@ acl entry is inserted.
765+ *
766+ * This transformation does not modify the permissions that the acl
767+ * grants, but we need it to simplify successive transformations.
768+ */
769+static int
770+nfs4acl_move_everyone_aces_down(struct nfs4acl_alloc *x)
771+{
772+ struct nfs4ace *ace;
773+ unsigned int allowed = 0, denied = 0;
774+
775+ nfs4acl_for_each_entry(ace, x->acl) {
776+ if (nfs4ace_is_inherit_only(ace))
777+ continue;
778+ if (nfs4ace_is_everyone(ace)) {
779+ if (nfs4ace_is_allow(ace))
780+ allowed |= (ace->e_mask & ~denied);
781+ else if (nfs4ace_is_deny(ace))
782+ denied |= (ace->e_mask & ~allowed);
783+ else
784+ continue;
785+ if (nfs4ace_change_mask(x, &ace, 0))
786+ return -1;
787+ } else {
788+ if (nfs4ace_is_allow(ace)) {
789+ if (nfs4ace_change_mask(x, &ace, allowed |
790+ (ace->e_mask & ~denied)))
791+ return -1;
792+ } else if (nfs4ace_is_deny(ace)) {
793+ if (nfs4ace_change_mask(x, &ace, denied |
794+ (ace->e_mask & ~allowed)))
795+ return -1;
796+ }
797+ }
798+ }
799+ if (allowed & ~ACE4_POSIX_ALWAYS_ALLOWED) {
800+ struct nfs4ace *last_ace = ace - 1;
801+
802+ if (nfs4ace_is_everyone(last_ace) &&
803+ nfs4ace_is_allow(last_ace) &&
804+ nfs4ace_is_inherit_only(last_ace) &&
805+ last_ace->e_mask == allowed)
806+ last_ace->e_flags &= ~ACE4_INHERIT_ONLY_ACE;
807+ else {
808+ if (nfs4acl_insert_entry(x, &ace))
809+ return -1;
810+ ace->e_type = ACE4_ACCESS_ALLOWED_ACE_TYPE;
811+ ace->e_flags = ACE4_SPECIAL_WHO;
812+ ace->e_mask = allowed;
813+ ace->u.e_who = nfs4ace_everyone_who;
814+ }
815+ }
816+ return 0;
817+}
818+
819+/**
820+ * __nfs4acl_propagate_everyone - propagate everyone@ mask flags up for @who
821+ * @x: acl and number of allocated entries
822+ * @who: identifier to propagate mask flags for
823+ * @allow: mask flags to propagate up
824+ *
825+ * Propagate mask flags from the trailing everyone@ allow acl entry up
826+ * for the specified @who.
827+ *
828+ * The idea here is to precede the trailing EVERYONE@ ALLOW entry by an
829+ * additional @who ALLOW entry, but with the following optimizations:
830+ * (1) we don't bother setting any flags in the new @who ALLOW entry
831+ * that has already been allowed or denied by a previous @who entry, (2)
832+ * we merge the new @who entry with a previous @who entry if there is
833+ * such a previous @who entry and there are no intervening DENY entries
834+ * with mask flags that overlap the flags we care about.
835+ */
836+static int
837+__nfs4acl_propagate_everyone(struct nfs4acl_alloc *x, struct nfs4ace *who,
838+ unsigned int allow)
839+{
840+ struct nfs4ace *allow_last = NULL, *ace;
841+
842+ /* Remove the mask flags from allow that are already determined for
843+ this who value, and figure out if there is an ALLOW entry for
844+ this who value that is "reachable" from the trailing EVERYONE@
845+ ALLOW ACE. */
846+ nfs4acl_for_each_entry(ace, x->acl) {
847+ if (nfs4ace_is_inherit_only(ace))
848+ continue;
849+ if (nfs4ace_is_allow(ace)) {
850+ if (nfs4ace_is_same_who(ace, who)) {
851+ allow &= ~ace->e_mask;
852+ allow_last = ace;
853+ }
854+ } else if (nfs4ace_is_deny(ace)) {
855+ if (nfs4ace_is_same_who(ace, who))
856+ allow &= ~ace->e_mask;
857+ if (allow & ace->e_mask)
858+ allow_last = NULL;
859+ }
860+ }
861+
862+ if (allow) {
863+ if (allow_last)
864+ return nfs4ace_change_mask(x, &allow_last,
865+ allow_last->e_mask | allow);
866+ else {
867+ struct nfs4ace who_copy;
868+
869+ ace = x->acl->a_entries + x->acl->a_count - 1;
870+ memcpy(&who_copy, who, sizeof(struct nfs4ace));
871+ if (nfs4acl_insert_entry(x, &ace))
872+ return -1;
873+ memcpy(ace, &who_copy, sizeof(struct nfs4ace));
874+ ace->e_type = ACE4_ACCESS_ALLOWED_ACE_TYPE;
875+ nfs4ace_clear_inheritance_flags(ace);
876+ ace->e_mask = allow;
877+ }
878+ }
879+ return 0;
880+}
881+
882+/**
883+ * nfs4acl_propagate_everyone - propagate everyone@ mask flags up the acl
884+ * @x: acl and number of allocated entries
885+ *
886+ * Make sure for owner@, group@, and all other users, groups, and
887+ * special identifiers that they are allowed or denied all permissions
888+ * that are granted be the trailing everyone@ acl entry. If they are
889+ * not, try to add the missing permissions to existing allow acl entries
890+ * for those users, or introduce additional acl entries if that is not
891+ * possible.
892+ *
893+ * We do this so that no mask flags will get lost when finally applying
894+ * the file masks to the acl entries: otherwise, with an other file mask
895+ * that is more restrictive than the owner and/or group file mask, mask
896+ * flags that were allowed to processes in the owner and group classes
897+ * and that the other mask denies would be lost. For example, the
898+ * following two acls show the problem when mode 0664 is applied to
899+ * them:
900+ *
901+ * masking without propagation (wrong)
902+ * ===========================================================
903+ * joe:r::allow => joe:r::allow
904+ * everyone@:rwx::allow => everyone@:r::allow
905+ * -----------------------------------------------------------
906+ * joe:w::deny => joe:w::deny
907+ * everyone@:rwx::allow everyone@:r::allow
908+ *
909+ * Note that the permissions of joe end up being more restrictive than
910+ * what the acl would allow when first computing the allowed flags and
911+ * then applying the respective mask. With propagation of permissions,
912+ * we get:
913+ *
914+ * masking after propagation (correct)
915+ * ===========================================================
916+ * joe:r::allow => joe:rw::allow
917+ * owner@:rw::allow
918+ * group@:rw::allow
919+ * everyone@:rwx::allow everyone@:r::allow
920+ * -----------------------------------------------------------
921+ * joe:w::deny => owner@:x::deny
922+ * joe:w::deny
923+ * owner@:rw::allow
924+ * owner@:rw::allow
925+ * joe:r::allow
926+ * everyone@:rwx::allow everyone@:r::allow
927+ *
928+ * The examples show the acls that would result from propagation with no
929+ * masking performed. In fact, we do apply the respective mask to the
930+ * acl entries before computing the propagation because this will save
931+ * us from adding acl entries that would end up with empty mask fields
932+ * after applying the masks.
933+ *
934+ * It is ensured that no more than one entry will be inserted for each
935+ * who value, no matter how many entries each who value has already.
936+ */
937+static int
938+nfs4acl_propagate_everyone(struct nfs4acl_alloc *x)
939+{
940+ int write_through = (x->acl->a_flags & ACL4_WRITE_THROUGH);
941+ struct nfs4ace who = { .e_flags = ACE4_SPECIAL_WHO };
942+ struct nfs4ace *ace;
943+ unsigned int owner_allow, group_allow;
944+ int retval;
945+
946+ if (!((x->acl->a_owner_mask | x->acl->a_group_mask) &
947+ ~x->acl->a_other_mask))
948+ return 0;
949+ if (!x->acl->a_count)
950+ return 0;
951+ ace = x->acl->a_entries + x->acl->a_count - 1;
952+ if (nfs4ace_is_inherit_only(ace) || !nfs4ace_is_everyone(ace))
953+ return 0;
954+ if (!(ace->e_mask & ~x->acl->a_other_mask)) {
955+ /* None of the allowed permissions will get masked. */
956+ return 0;
957+ }
958+ owner_allow = ace->e_mask & x->acl->a_owner_mask;
959+ group_allow = ace->e_mask & x->acl->a_group_mask;
960+
961+ /* Propagate everyone@ permissions through to owner@. */
962+ if (owner_allow && !write_through &&
963+ (x->acl->a_owner_mask & ~x->acl->a_other_mask)) {
964+ who.u.e_who = nfs4ace_owner_who;
965+ retval = __nfs4acl_propagate_everyone(x, &who, owner_allow);
966+ if (retval)
967+ return -1;
968+ }
969+
970+ if (group_allow && (x->acl->a_group_mask & ~x->acl->a_other_mask)) {
971+ int n;
972+
973+ if (!write_through) {
974+ /* Propagate everyone@ permissions through to group@. */
975+ who.u.e_who = nfs4ace_group_who;
976+ retval = __nfs4acl_propagate_everyone(x, &who,
977+ group_allow);
978+ if (retval)
979+ return -1;
980+ }
981+
982+ /* Start from the entry before the trailing EVERYONE@ ALLOW
983+ entry. We will not hit EVERYONE@ entries in the loop. */
984+ for (n = x->acl->a_count - 2; n != -1; n--) {
985+ ace = x->acl->a_entries + n;
986+
987+ if (nfs4ace_is_inherit_only(ace) ||
988+ nfs4ace_is_owner(ace) ||
989+ nfs4ace_is_group(ace))
990+ continue;
991+ if (nfs4ace_is_allow(ace) || nfs4ace_is_deny(ace)) {
992+ /* Any inserted entry will end up below the
993+ current entry. */
994+ retval = __nfs4acl_propagate_everyone(x, ace,
995+ group_allow);
996+ if (retval)
997+ return -1;
998+ }
999+ }
1000+ }
1001+ return 0;
1002+}
1003+
1004+/**
1005+ * __nfs4acl_apply_masks - apply the masks to the acl entries
1006+ * @x: acl and number of allocated entries
1007+ *
1008+ * Apply the owner file mask to owner@ entries, the intersection of the
1009+ * group and other file masks to everyone@ entries, and the group file
1010+ * mask to all other entries.
1011+ */
1012+static int
1013+__nfs4acl_apply_masks(struct nfs4acl_alloc *x)
1014+{
1015+ struct nfs4ace *ace;
1016+
1017+ nfs4acl_for_each_entry(ace, x->acl) {
1018+ unsigned int mask;
1019+
1020+ if (nfs4ace_is_inherit_only(ace) || !nfs4ace_is_allow(ace))
1021+ continue;
1022+ if (nfs4ace_is_owner(ace))
1023+ mask = x->acl->a_owner_mask;
1024+ else if (nfs4ace_is_everyone(ace))
1025+ mask = x->acl->a_other_mask;
1026+ else
1027+ mask = x->acl->a_group_mask;
1028+ if (nfs4ace_change_mask(x, &ace, ace->e_mask & mask))
1029+ return -1;
1030+ }
1031+ return 0;
1032+}
1033+
1034+/**
1035+ * nfs4acl_max_allowed - maximum mask flags that anybody is allowed
1036+ */
1037+static unsigned int
1038+nfs4acl_max_allowed(struct nfs4acl *acl)
1039+{
1040+ struct nfs4ace *ace;
1041+ unsigned int allowed = 0;
1042+
1043+ nfs4acl_for_each_entry_reverse(ace, acl) {
1044+ if (nfs4ace_is_inherit_only(ace))
1045+ continue;
1046+ if (nfs4ace_is_allow(ace))
1047+ allowed |= ace->e_mask;
1048+ else if (nfs4ace_is_deny(ace)) {
1049+ if (nfs4ace_is_everyone(ace))
1050+ allowed &= ~ace->e_mask;
1051+ }
1052+ }
1053+ return allowed;
1054+}
1055+
1056+/**
1057+ * nfs4acl_isolate_owner_class - limit the owner class to the owner file mask
1058+ * @x: acl and number of allocated entries
1059+ *
1060+ * Make sure the owner class (owner@) is granted no more than the owner
1061+ * mask by first checking which permissions anyone is granted, and then
1062+ * denying owner@ all permissions beyond that.
1063+ */
1064+static int
1065+nfs4acl_isolate_owner_class(struct nfs4acl_alloc *x)
1066+{
1067+ struct nfs4ace *ace;
1068+ unsigned int allowed = 0;
1069+
1070+ allowed = nfs4acl_max_allowed(x->acl);
1071+ if (allowed & ~x->acl->a_owner_mask) {
1072+ /* Figure out if we can update an existig OWNER@ DENY entry. */
1073+ nfs4acl_for_each_entry(ace, x->acl) {
1074+ if (nfs4ace_is_inherit_only(ace))
1075+ continue;
1076+ if (nfs4ace_is_deny(ace)) {
1077+ if (nfs4ace_is_owner(ace))
1078+ break;
1079+ } else if (nfs4ace_is_allow(ace)) {
1080+ ace = x->acl->a_entries + x->acl->a_count;
1081+ break;
1082+ }
1083+ }
1084+ if (ace != x->acl->a_entries + x->acl->a_count) {
1085+ if (nfs4ace_change_mask(x, &ace, ace->e_mask |
1086+ (allowed & ~x->acl->a_owner_mask)))
1087+ return -1;
1088+ } else {
1089+ /* Insert an owner@ deny entry at the front. */
1090+ ace = x->acl->a_entries;
1091+ if (nfs4acl_insert_entry(x, &ace))
1092+ return -1;
1093+ ace->e_type = ACE4_ACCESS_DENIED_ACE_TYPE;
1094+ ace->e_flags = ACE4_SPECIAL_WHO;
1095+ ace->e_mask = allowed & ~x->acl->a_owner_mask;
1096+ ace->u.e_who = nfs4ace_owner_who;
1097+ }
1098+ }
1099+ return 0;
1100+}
1101+
1102+/**
1103+ * __nfs4acl_isolate_who - isolate entry from EVERYONE@ ALLOW entry
1104+ * @x: acl and number of allocated entries
1105+ * @who: identifier to isolate
1106+ * @deny: mask flags this identifier should not be allowed
1107+ *
1108+ * Make sure that @who is not allowed any mask flags in @deny by checking
1109+ * which mask flags this identifier is allowed, and adding excess allowed
1110+ * mask flags to an existing DENY entry before the trailing EVERYONE@ ALLOW
1111+ * entry, or inserting such an entry.
1112+ */
1113+static int
1114+__nfs4acl_isolate_who(struct nfs4acl_alloc *x, struct nfs4ace *who,
1115+ unsigned int deny)
1116+{
1117+ struct nfs4ace *ace;
1118+ unsigned int allowed = 0, n;
1119+
1120+ /* Compute the mask flags granted to this who value. */
1121+ nfs4acl_for_each_entry_reverse(ace, x->acl) {
1122+ if (nfs4ace_is_inherit_only(ace))
1123+ continue;
1124+ if (nfs4ace_is_same_who(ace, who)) {
1125+ if (nfs4ace_is_allow(ace))
1126+ allowed |= ace->e_mask;
1127+ else if (nfs4ace_is_deny(ace))
1128+ allowed &= ~ace->e_mask;
1129+ deny &= ~ace->e_mask;
1130+ }
1131+ }
1132+ if (!deny)
1133+ return 0;
1134+
1135+ /* Figure out if we can update an existig DENY entry. Start
1136+ from the entry before the trailing EVERYONE@ ALLOW entry. We
1137+ will not hit EVERYONE@ entries in the loop. */
1138+ for (n = x->acl->a_count - 2; n != -1; n--) {
1139+ ace = x->acl->a_entries + n;
1140+ if (nfs4ace_is_inherit_only(ace))
1141+ continue;
1142+ if (nfs4ace_is_deny(ace)) {
1143+ if (nfs4ace_is_same_who(ace, who))
1144+ break;
1145+ } else if (nfs4ace_is_allow(ace) &&
1146+ (ace->e_mask & deny)) {
1147+ n = -1;
1148+ break;
1149+ }
1150+ }
1151+ if (n != -1) {
1152+ if (nfs4ace_change_mask(x, &ace, ace->e_mask | deny))
1153+ return -1;
1154+ } else {
1155+ /* Insert a eny entry before the trailing EVERYONE@ DENY
1156+ entry. */
1157+ struct nfs4ace who_copy;
1158+
1159+ ace = x->acl->a_entries + x->acl->a_count - 1;
1160+ memcpy(&who_copy, who, sizeof(struct nfs4ace));
1161+ if (nfs4acl_insert_entry(x, &ace))
1162+ return -1;
1163+ memcpy(ace, &who_copy, sizeof(struct nfs4ace));
1164+ ace->e_type = ACE4_ACCESS_DENIED_ACE_TYPE;
1165+ nfs4ace_clear_inheritance_flags(ace);
1166+ ace->e_mask = deny;
1167+ }
1168+ return 0;
1169+}
1170+
1171+/**
1172+ * nfs4acl_isolate_group_class - limit the group class to the group file mask
1173+ * @x: acl and number of allocated entries
1174+ *
1175+ * Make sure the group class (all entries except owner@ and everyone@) is
1176+ * granted no more than the group mask by inserting DENY entries for group
1177+ * class entries where necessary.
1178+ */
1179+static int
1180+nfs4acl_isolate_group_class(struct nfs4acl_alloc *x)
1181+{
1182+ struct nfs4ace who = {
1183+ .e_flags = ACE4_SPECIAL_WHO,
1184+ .u.e_who = nfs4ace_group_who,
1185+ };
1186+ struct nfs4ace *ace;
1187+ unsigned int deny;
1188+
1189+ if (!x->acl->a_count)
1190+ return 0;
1191+ ace = x->acl->a_entries + x->acl->a_count - 1;
1192+ if (nfs4ace_is_inherit_only(ace) || !nfs4ace_is_everyone(ace))
1193+ return 0;
1194+ deny = ace->e_mask & ~x->acl->a_group_mask;
1195+
1196+ if (deny) {
1197+ unsigned int n;
1198+
1199+ if (__nfs4acl_isolate_who(x, &who, deny))
1200+ return -1;
1201+
1202+ /* Start from the entry before the trailing EVERYONE@ ALLOW
1203+ entry. We will not hit EVERYONE@ entries in the loop. */
1204+ for (n = x->acl->a_count - 2; n != -1; n--) {
1205+ ace = x->acl->a_entries + n;
1206+
1207+ if (nfs4ace_is_inherit_only(ace) ||
1208+ nfs4ace_is_owner(ace) ||
1209+ nfs4ace_is_group(ace))
1210+ continue;
1211+ if (__nfs4acl_isolate_who(x, ace, deny))
1212+ return -1;
1213+ }
1214+ }
1215+ return 0;
1216+}
1217+
1218+/**
1219+ * __nfs4acl_write_through - grant the full masks to owner@, group@, everyone@
1220+ *
1221+ * Make sure that owner, group@, and everyone@ are allowed the full mask
1222+ * permissions, and not only the permissions granted both by the acl and
1223+ * the masks.
1224+ */
1225+static int
1226+__nfs4acl_write_through(struct nfs4acl_alloc *x)
1227+{
1228+ struct nfs4ace *ace;
1229+ unsigned int allowed;
1230+
1231+ /* Remove all owner@ and group@ ACEs: we re-insert them at the
1232+ top. */
1233+ nfs4acl_for_each_entry(ace, x->acl) {
1234+ if (nfs4ace_is_inherit_only(ace))
1235+ continue;
1236+ if ((nfs4ace_is_owner(ace) || nfs4ace_is_group(ace)) &&
1237+ nfs4ace_change_mask(x, &ace, 0))
1238+ return -1;
1239+ }
1240+
1241+ /* Insert the everyone@ allow entry at the end, or update the
1242+ existing entry. */
1243+ allowed = x->acl->a_other_mask;
1244+ if (allowed & ~ACE4_POSIX_ALWAYS_ALLOWED) {
1245+ ace = x->acl->a_entries + x->acl->a_count - 1;
1246+ if (x->acl->a_count && nfs4ace_is_everyone(ace) &&
1247+ !nfs4ace_is_inherit_only(ace)) {
1248+ if (nfs4ace_change_mask(x, &ace, allowed))
1249+ return -1;
1250+ } else {
1251+ ace = x->acl->a_entries + x->acl->a_count;
1252+ if (nfs4acl_insert_entry(x, &ace))
1253+ return -1;
1254+ ace->e_type = ACE4_ACCESS_ALLOWED_ACE_TYPE;
1255+ ace->e_flags = ACE4_SPECIAL_WHO;
1256+ ace->e_mask = allowed;
1257+ ace->u.e_who = nfs4ace_everyone_who;
1258+ }
1259+ }
1260+
1261+ /* Compute the permissions that owner@ and group@ are already granted
1262+ though the everyone@ allow entry at the end. Note that the acl
1263+ contains no owner@ or group@ entries at this point. */
1264+ allowed = 0;
1265+ nfs4acl_for_each_entry_reverse(ace, x->acl) {
1266+ if (nfs4ace_is_inherit_only(ace))
1267+ continue;
1268+ if (nfs4ace_is_allow(ace)) {
1269+ if (nfs4ace_is_everyone(ace))
1270+ allowed |= ace->e_mask;
1271+ } else if (nfs4ace_is_deny(ace))
1272+ allowed &= ~ace->e_mask;
1273+ }
1274+
1275+ /* Insert the appropriate group@ allow entry at the front. */
1276+ if (x->acl->a_group_mask & ~allowed) {
1277+ ace = x->acl->a_entries;
1278+ if (nfs4acl_insert_entry(x, &ace))
1279+ return -1;
1280+ ace->e_type = ACE4_ACCESS_ALLOWED_ACE_TYPE;
1281+ ace->e_flags = ACE4_SPECIAL_WHO;
1282+ ace->e_mask = x->acl->a_group_mask /*& ~allowed*/;
1283+ ace->u.e_who = nfs4ace_group_who;
1284+ }
1285+
1286+ /* Insert the appropriate owner@ allow entry at the front. */
1287+ if (x->acl->a_owner_mask & ~allowed) {
1288+ ace = x->acl->a_entries;
1289+ if (nfs4acl_insert_entry(x, &ace))
1290+ return -1;
1291+ ace->e_type = ACE4_ACCESS_ALLOWED_ACE_TYPE;
1292+ ace->e_flags = ACE4_SPECIAL_WHO;
1293+ ace->e_mask = x->acl->a_owner_mask /*& ~allowed*/;
1294+ ace->u.e_who = nfs4ace_owner_who;
1295+ }
1296+
1297+ /* Insert the appropriate owner@ deny entry at the front. */
1298+ allowed = nfs4acl_max_allowed(x->acl);
1299+ if (allowed & ~x->acl->a_owner_mask) {
1300+ nfs4acl_for_each_entry(ace, x->acl) {
1301+ if (nfs4ace_is_inherit_only(ace))
1302+ continue;
1303+ if (nfs4ace_is_allow(ace)) {
1304+ ace = x->acl->a_entries + x->acl->a_count;
1305+ break;
1306+ }
1307+ if (nfs4ace_is_deny(ace) && nfs4ace_is_owner(ace))
1308+ break;
1309+ }
1310+ if (ace != x->acl->a_entries + x->acl->a_count) {
1311+ if (nfs4ace_change_mask(x, &ace, ace->e_mask |
1312+ (allowed & ~x->acl->a_owner_mask)))
1313+ return -1;
1314+ } else {
1315+ ace = x->acl->a_entries;
1316+ if (nfs4acl_insert_entry(x, &ace))
1317+ return -1;
1318+ ace->e_type = ACE4_ACCESS_DENIED_ACE_TYPE;
1319+ ace->e_flags = ACE4_SPECIAL_WHO;
1320+ ace->e_mask = allowed & ~x->acl->a_owner_mask;
1321+ ace->u.e_who = nfs4ace_owner_who;
1322+ }
1323+ }
1324+
1325+ return 0;
1326+}
1327+
1328+/**
1329+ * nfs4acl_apply_masks - apply the masks to the acl
1330+ *
1331+ * Apply the masks so that the acl allows no more flags than the
1332+ * intersection between the flags that the original acl allows and the
1333+ * mask matching the process.
1334+ *
1335+ * Note: this algorithm may push the number of entries in the acl above
1336+ * ACL4_XATTR_MAX_COUNT, so a read-modify-write cycle would fail.
1337+ */
1338+int
1339+nfs4acl_apply_masks(struct nfs4acl **acl)
1340+{
1341+ struct nfs4acl_alloc x = {
1342+ .acl = *acl,
1343+ .count = (*acl)->a_count,
1344+ };
1345+ int retval = 0;
1346+
1347+ if (nfs4acl_move_everyone_aces_down(&x) ||
1348+ nfs4acl_propagate_everyone(&x) ||
1349+ __nfs4acl_apply_masks(&x) ||
1350+ nfs4acl_isolate_owner_class(&x) ||
1351+ nfs4acl_isolate_group_class(&x))
1352+ retval = -ENOMEM;
1353+
1354+ *acl = x.acl;
1355+ return retval;
1356+}
1357+EXPORT_SYMBOL(nfs4acl_apply_masks);
1358+
1359+int nfs4acl_write_through(struct nfs4acl **acl)
1360+{
1361+ struct nfs4acl_alloc x = {
1362+ .acl = *acl,
1363+ .count = (*acl)->a_count,
1364+ };
1365+ int retval = 0;
1366+
1367+ if (!((*acl)->a_flags & ACL4_WRITE_THROUGH))
1368+ goto out;
1369+
1370+ if (nfs4acl_move_everyone_aces_down(&x) ||
1371+ nfs4acl_propagate_everyone(&x) ||
1372+ __nfs4acl_write_through(&x))
1373+ retval = -ENOMEM;
1374+
1375+ *acl = x.acl;
1376+out:
1377+ return retval;
1378+}
1379--- /dev/null
1380+++ b/fs/nfs4acl_xattr.c
1381@@ -0,0 +1,146 @@
1382+/*
1383+ * Copyright (C) 2006 Andreas Gruenbacher <a.gruenbacher@computer.org>
1384+ *
1385+ * This program is free software; you can redistribute it and/or modify it
1386+ * under the terms of the GNU General Public License as published by the
1387+ * Free Software Foundation; either version 2, or (at your option) any
1388+ * later version.
1389+ *
1390+ * This program is distributed in the hope that it will be useful, but
1391+ * WITHOUT ANY WARRANTY; without even the implied warranty of
1392+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1393+ * General Public License for more details.
1394+ */
1395+
1396+#include <linux/kernel.h>
1397+#include <linux/fs.h>
1398+#include <linux/slab.h>
1399+#include <linux/module.h>
1400+#include <linux/nfs4acl_xattr.h>
1401+
1402+MODULE_LICENSE("GPL");
1403+
1404+struct nfs4acl *
1405+nfs4acl_from_xattr(const void *value, size_t size)
1406+{
1407+ const struct nfs4acl_xattr *xattr_acl = value;
1408+ const struct nfs4ace_xattr *xattr_ace = (void *)(xattr_acl + 1);
1409+ struct nfs4acl *acl;
1410+ struct nfs4ace *ace;
1411+ int count;
1412+
1413+ if (size < sizeof(struct nfs4acl_xattr) ||
1414+ xattr_acl->a_version != ACL4_XATTR_VERSION ||
1415+ (xattr_acl->a_flags & ~ACL4_VALID_FLAGS))
1416+ return ERR_PTR(-EINVAL);
1417+
1418+ count = be16_to_cpu(xattr_acl->a_count);
1419+ if (count > ACL4_XATTR_MAX_COUNT)
1420+ return ERR_PTR(-EINVAL);
1421+
1422+ acl = nfs4acl_alloc(count);
1423+ if (!acl)
1424+ return ERR_PTR(-ENOMEM);
1425+
1426+ acl->a_flags = xattr_acl->a_flags;
1427+ acl->a_owner_mask = be32_to_cpu(xattr_acl->a_owner_mask);
1428+ if (acl->a_owner_mask & ~ACE4_VALID_MASK)
1429+ goto fail_einval;
1430+ acl->a_group_mask = be32_to_cpu(xattr_acl->a_group_mask);
1431+ if (acl->a_group_mask & ~ACE4_VALID_MASK)
1432+ goto fail_einval;
1433+ acl->a_other_mask = be32_to_cpu(xattr_acl->a_other_mask);
1434+ if (acl->a_other_mask & ~ACE4_VALID_MASK)
1435+ goto fail_einval;
1436+
1437+ nfs4acl_for_each_entry(ace, acl) {
1438+ const char *who = (void *)(xattr_ace + 1), *end;
1439+ ssize_t used = (void *)who - value;
1440+
1441+ if (used > size)
1442+ goto fail_einval;
1443+ end = memchr(who, 0, size - used);
1444+ if (!end)
1445+ goto fail_einval;
1446+
1447+ ace->e_type = be16_to_cpu(xattr_ace->e_type);
1448+ ace->e_flags = be16_to_cpu(xattr_ace->e_flags);
1449+ ace->e_mask = be32_to_cpu(xattr_ace->e_mask);
1450+ ace->u.e_id = be32_to_cpu(xattr_ace->e_id);
1451+
1452+ if (ace->e_flags & ~ACE4_VALID_FLAGS) {
1453+ memset(ace, 0, sizeof(struct nfs4ace));
1454+ goto fail_einval;
1455+ }
1456+ if (ace->e_type > ACE4_ACCESS_DENIED_ACE_TYPE ||
1457+ (ace->e_mask & ~ACE4_VALID_MASK))
1458+ goto fail_einval;
1459+
1460+ if (who == end) {
1461+ if (ace->u.e_id == -1)
1462+ goto fail_einval; /* uid/gid needed */
1463+ } else if (nfs4ace_set_who(ace, who))
1464+ goto fail_einval;
1465+
1466+ xattr_ace = (void *)who + ALIGN(end - who + 1, 4);
1467+ }
1468+
1469+ return acl;
1470+
1471+fail_einval:
1472+ nfs4acl_put(acl);
1473+ return ERR_PTR(-EINVAL);
1474+}
1475+EXPORT_SYMBOL(nfs4acl_from_xattr);
1476+
1477+size_t
1478+nfs4acl_xattr_size(const struct nfs4acl *acl)
1479+{
1480+ size_t size = sizeof(struct nfs4acl_xattr);
1481+ const struct nfs4ace *ace;
1482+
1483+ nfs4acl_for_each_entry(ace, acl) {
1484+ size += sizeof(struct nfs4ace_xattr) +
1485+ (nfs4ace_is_unix_id(ace) ? 4 :
1486+ ALIGN(strlen(ace->u.e_who) + 1, 4));
1487+ }
1488+ return size;
1489+}
1490+EXPORT_SYMBOL(nfs4acl_xattr_size);
1491+
1492+void
1493+nfs4acl_to_xattr(const struct nfs4acl *acl, void *buffer)
1494+{
1495+ struct nfs4acl_xattr *xattr_acl = buffer;
1496+ struct nfs4ace_xattr *xattr_ace;
1497+ const struct nfs4ace *ace;
1498+
1499+ xattr_acl->a_version = ACL4_XATTR_VERSION;
1500+ xattr_acl->a_flags = acl->a_flags;
1501+ xattr_acl->a_count = cpu_to_be16(acl->a_count);
1502+
1503+ xattr_acl->a_owner_mask = cpu_to_be32(acl->a_owner_mask);
1504+ xattr_acl->a_group_mask = cpu_to_be32(acl->a_group_mask);
1505+ xattr_acl->a_other_mask = cpu_to_be32(acl->a_other_mask);
1506+
1507+ xattr_ace = (void *)(xattr_acl + 1);
1508+ nfs4acl_for_each_entry(ace, acl) {
1509+ xattr_ace->e_type = cpu_to_be16(ace->e_type);
1510+ xattr_ace->e_flags = cpu_to_be16(ace->e_flags &
1511+ ACE4_VALID_FLAGS);
1512+ xattr_ace->e_mask = cpu_to_be32(ace->e_mask);
1513+ if (nfs4ace_is_unix_id(ace)) {
1514+ xattr_ace->e_id = cpu_to_be32(ace->u.e_id);
1515+ memset(xattr_ace->e_who, 0, 4);
1516+ xattr_ace = (void *)xattr_ace->e_who + 4;
1517+ } else {
1518+ int sz = ALIGN(strlen(ace->u.e_who) + 1, 4);
1519+
1520+ xattr_ace->e_id = cpu_to_be32(-1);
1521+ memset(xattr_ace->e_who + sz - 4, 0, 4);
1522+ strcpy(xattr_ace->e_who, ace->u.e_who);
1523+ xattr_ace = (void *)xattr_ace->e_who + sz;
1524+ }
1525+ }
1526+}
1527+EXPORT_SYMBOL(nfs4acl_to_xattr);
1528--- /dev/null
1529+++ b/include/linux/nfs4acl.h
1530@@ -0,0 +1,205 @@
1531+#ifndef __NFS4ACL_H
1532+#define __NFS4ACL_H
1533+
1534+struct nfs4ace {
1535+ unsigned short e_type;
1536+ unsigned short e_flags;
1537+ unsigned int e_mask;
1538+ union {
1539+ unsigned int e_id;
1540+ const char *e_who;
1541+ } u;
1542+};
1543+
1544+struct nfs4acl {
1545+ atomic_t a_refcount;
1546+ unsigned int a_owner_mask;
1547+ unsigned int a_group_mask;
1548+ unsigned int a_other_mask;
1549+ unsigned short a_count;
1550+ unsigned short a_flags;
1551+ struct nfs4ace a_entries[0];
1552+};
1553+
1554+#define nfs4acl_for_each_entry(_ace, _acl) \
1555+ for (_ace = _acl->a_entries; \
1556+ _ace != _acl->a_entries + _acl->a_count; \
1557+ _ace++)
1558+
1559+#define nfs4acl_for_each_entry_reverse(_ace, _acl) \
1560+ for (_ace = _acl->a_entries + _acl->a_count - 1; \
1561+ _ace != _acl->a_entries - 1; \
1562+ _ace--)
1563+
1564+/* a_flags values */
1565+#define ACL4_WRITE_THROUGH 0x40
1566+
1567+#define ACL4_VALID_FLAGS \
1568+ ACL4_WRITE_THROUGH
1569+
1570+/* e_type values */
1571+#define ACE4_ACCESS_ALLOWED_ACE_TYPE 0x0000
1572+#define ACE4_ACCESS_DENIED_ACE_TYPE 0x0001
1573+/*#define ACE4_SYSTEM_AUDIT_ACE_TYPE 0x0002*/
1574+/*#define ACE4_SYSTEM_ALARM_ACE_TYPE 0x0003*/
1575+
1576+/* e_flags bitflags */
1577+#define ACE4_FILE_INHERIT_ACE 0x0001
1578+#define ACE4_DIRECTORY_INHERIT_ACE 0x0002
1579+#define ACE4_NO_PROPAGATE_INHERIT_ACE 0x0004
1580+#define ACE4_INHERIT_ONLY_ACE 0x0008
1581+/*#define ACE4_SUCCESSFUL_ACCESS_ACE_FLAG 0x0010*/
1582+/*#define ACE4_FAILED_ACCESS_ACE_FLAG 0x0020*/
1583+#define ACE4_IDENTIFIER_GROUP 0x0040
1584+#define ACE4_SPECIAL_WHO 0x4000 /* in-memory representation only */
1585+
1586+#define ACE4_VALID_FLAGS ( \
1587+ ACE4_FILE_INHERIT_ACE | \
1588+ ACE4_DIRECTORY_INHERIT_ACE | \
1589+ ACE4_NO_PROPAGATE_INHERIT_ACE | \
1590+ ACE4_INHERIT_ONLY_ACE | \
1591+ ACE4_IDENTIFIER_GROUP )
1592+
1593+/* e_mask bitflags */
1594+#define ACE4_READ_DATA 0x00000001
1595+#define ACE4_LIST_DIRECTORY 0x00000001
1596+#define ACE4_WRITE_DATA 0x00000002
1597+#define ACE4_ADD_FILE 0x00000002
1598+#define ACE4_APPEND_DATA 0x00000004
1599+#define ACE4_ADD_SUBDIRECTORY 0x00000004
1600+#define ACE4_READ_NAMED_ATTRS 0x00000008
1601+#define ACE4_WRITE_NAMED_ATTRS 0x00000010
1602+#define ACE4_EXECUTE 0x00000020
1603+#define ACE4_DELETE_CHILD 0x00000040
1604+#define ACE4_READ_ATTRIBUTES 0x00000080
1605+#define ACE4_WRITE_ATTRIBUTES 0x00000100
1606+#define ACE4_DELETE 0x00010000
1607+#define ACE4_READ_ACL 0x00020000
1608+#define ACE4_WRITE_ACL 0x00040000
1609+#define ACE4_WRITE_OWNER 0x00080000
1610+#define ACE4_SYNCHRONIZE 0x00100000
1611+
1612+#define ACE4_VALID_MASK ( \
1613+ ACE4_READ_DATA | ACE4_LIST_DIRECTORY | \
1614+ ACE4_WRITE_DATA | ACE4_ADD_FILE | \
1615+ ACE4_APPEND_DATA | ACE4_ADD_SUBDIRECTORY | \
1616+ ACE4_READ_NAMED_ATTRS | \
1617+ ACE4_WRITE_NAMED_ATTRS | \
1618+ ACE4_EXECUTE | \
1619+ ACE4_DELETE_CHILD | \
1620+ ACE4_READ_ATTRIBUTES | \
1621+ ACE4_WRITE_ATTRIBUTES | \
1622+ ACE4_DELETE | \
1623+ ACE4_READ_ACL | \
1624+ ACE4_WRITE_ACL | \
1625+ ACE4_WRITE_OWNER | \
1626+ ACE4_SYNCHRONIZE )
1627+
1628+#define ACE4_POSIX_ALWAYS_ALLOWED ( \
1629+ ACE4_SYNCHRONIZE | \
1630+ ACE4_READ_ATTRIBUTES | \
1631+ ACE4_READ_ACL )
1632+/*
1633+ * Duplicate an NFS4ACL handle.
1634+ */
1635+static inline struct nfs4acl *
1636+nfs4acl_get(struct nfs4acl *acl)
1637+{
1638+ if (acl)
1639+ atomic_inc(&acl->a_refcount);
1640+ return acl;
1641+}
1642+
1643+/*
1644+ * Free an NFS4ACL handle
1645+ */
1646+static inline void
1647+nfs4acl_put(struct nfs4acl *acl)
1648+{
1649+ if (acl && atomic_dec_and_test(&acl->a_refcount))
1650+ kfree(acl);
1651+}
1652+
1653+/* Special e_who identifiers: we use these pointer values in comparisons
1654+ instead of strcmp for efficiency. */
1655+
1656+extern const char nfs4ace_owner_who[];
1657+extern const char nfs4ace_group_who[];
1658+extern const char nfs4ace_everyone_who[];
1659+
1660+static inline int
1661+nfs4ace_is_owner(const struct nfs4ace *ace)
1662+{
1663+ return (ace->e_flags & ACE4_SPECIAL_WHO) &&
1664+ ace->u.e_who == nfs4ace_owner_who;
1665+}
1666+
1667+static inline int
1668+nfs4ace_is_group(const struct nfs4ace *ace)
1669+{
1670+ return (ace->e_flags & ACE4_SPECIAL_WHO) &&
1671+ ace->u.e_who == nfs4ace_group_who;
1672+}
1673+
1674+static inline int
1675+nfs4ace_is_everyone(const struct nfs4ace *ace)
1676+{
1677+ return (ace->e_flags & ACE4_SPECIAL_WHO) &&
1678+ ace->u.e_who == nfs4ace_everyone_who;
1679+}
1680+
1681+static inline int
1682+nfs4ace_is_unix_id(const struct nfs4ace *ace)
1683+{
1684+ return !(ace->e_flags & ACE4_SPECIAL_WHO);
1685+}
1686+
1687+static inline int
1688+nfs4ace_is_inherit_only(const struct nfs4ace *ace)
1689+{
1690+ return ace->e_flags & ACE4_INHERIT_ONLY_ACE;
1691+}
1692+
1693+static inline int
1694+nfs4ace_is_inheritable(const struct nfs4ace *ace)
1695+{
1696+ return ace->e_flags & (ACE4_FILE_INHERIT_ACE |
1697+ ACE4_DIRECTORY_INHERIT_ACE);
1698+}
1699+
1700+static inline void
1701+nfs4ace_clear_inheritance_flags(struct nfs4ace *ace)
1702+{
1703+ ace->e_flags &= ~(ACE4_FILE_INHERIT_ACE |
1704+ ACE4_DIRECTORY_INHERIT_ACE |
1705+ ACE4_NO_PROPAGATE_INHERIT_ACE |
1706+ ACE4_INHERIT_ONLY_ACE);
1707+}
1708+
1709+static inline int
1710+nfs4ace_is_allow(const struct nfs4ace *ace)
1711+{
1712+ return ace->e_type == ACE4_ACCESS_ALLOWED_ACE_TYPE;
1713+}
1714+
1715+static inline int
1716+nfs4ace_is_deny(const struct nfs4ace *ace)
1717+{
1718+ return ace->e_type == ACE4_ACCESS_DENIED_ACE_TYPE;
1719+}
1720+
1721+extern struct nfs4acl *nfs4acl_alloc(int count);
1722+extern struct nfs4acl *nfs4acl_clone(const struct nfs4acl *acl);
1723+
1724+extern unsigned int nfs4acl_want_to_mask(int want);
1725+extern int nfs4acl_permission(struct inode *, const struct nfs4acl *, unsigned int);
1726+extern int nfs4acl_generic_permission(struct inode *, unsigned int);
1727+extern int nfs4ace_is_same_who(const struct nfs4ace *, const struct nfs4ace *);
1728+extern int nfs4ace_set_who(struct nfs4ace *ace, const char *who);
1729+extern struct nfs4acl *nfs4acl_inherit(const struct nfs4acl *, mode_t);
1730+extern int nfs4acl_masks_to_mode(const struct nfs4acl *);
1731+extern struct nfs4acl *nfs4acl_chmod(struct nfs4acl *, mode_t);
1732+extern int nfs4acl_apply_masks(struct nfs4acl **acl);
1733+extern int nfs4acl_write_through(struct nfs4acl **acl);
1734+
1735+#endif /* __NFS4ACL_H */
1736--- /dev/null
1737+++ b/include/linux/nfs4acl_xattr.h
1738@@ -0,0 +1,32 @@
1739+#ifndef __NFS4ACL_XATTR_H
1740+#define __NFS4ACL_XATTR_H
1741+
1742+#include <linux/nfs4acl.h>
1743+
1744+#define NFS4ACL_XATTR "system.nfs4acl"
1745+
1746+struct nfs4ace_xattr {
1747+ __be16 e_type;
1748+ __be16 e_flags;
1749+ __be32 e_mask;
1750+ __be32 e_id;
1751+ char e_who[0];
1752+};
1753+
1754+struct nfs4acl_xattr {
1755+ unsigned char a_version;
1756+ unsigned char a_flags;
1757+ __be16 a_count;
1758+ __be32 a_owner_mask;
1759+ __be32 a_group_mask;
1760+ __be32 a_other_mask;
1761+};
1762+
1763+#define ACL4_XATTR_VERSION 0
1764+#define ACL4_XATTR_MAX_COUNT 1024
1765+
1766+extern struct nfs4acl *nfs4acl_from_xattr(const void *, size_t);
1767+extern size_t nfs4acl_xattr_size(const struct nfs4acl *acl);
1768+extern void nfs4acl_to_xattr(const struct nfs4acl *, void *);
1769+
1770+#endif /* __NFS4ACL_XATTR_H */