* [nfsacl v2 00/16] NFSACL protocol extension for NFSv3
@ 2005-02-27 16:59 Andreas Gruenbacher
2005-02-27 16:59 ` [nfsacl v2 01/16] acl kconfig cleanup Andreas Gruenbacher
` (15 more replies)
0 siblings, 16 replies; 21+ messages in thread
From: Andreas Gruenbacher @ 2005-02-27 16:59 UTC (permalink / raw)
To: linux-kernel, Neil Brown, Trond Myklebust
Cc: Olaf Kirch, Andries E. Brouwer, Andrew Morton
This is the proper nfsacl patchset against 2.6.11-rc5. Again, these are
the open issues:
- Not sure what do do about the Solaris compatibility hack. It's
ugly no matter how we hide it, so I'll probably keep it the way
it is now,
- Matt's heapsort is defective, so I'm not using it, yet.
Regards,
--
Andreas Gruenbacher <agruen@suse.de>
SUSE Labs, SUSE LINUX PRODUCTS GMBH
^ permalink raw reply [flat|nested] 21+ messages in thread
* [nfsacl v2 01/16] acl kconfig cleanup
2005-02-27 16:59 [nfsacl v2 00/16] NFSACL protocol extension for NFSv3 Andreas Gruenbacher
@ 2005-02-27 16:59 ` Andreas Gruenbacher
[not found] ` <4225FAE8.80308@tomt.net>
2005-02-27 16:59 ` [nfsacl v2 02/16] Qsort Andreas Gruenbacher
` (14 subsequent siblings)
15 siblings, 1 reply; 21+ messages in thread
From: Andreas Gruenbacher @ 2005-02-27 16:59 UTC (permalink / raw)
To: linux-kernel, Neil Brown, Trond Myklebust
Cc: Olaf Kirch, Andries E. Brouwer, Andrew Morton
[-- Attachment #1: acl-kconfig-cleanup.diff --]
[-- Type: text/plain, Size: 2070 bytes --]
Original patch from Matt Mackall <mpm@selenic.com>.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Index: linux-2.6.11-rc5/fs/Kconfig
===================================================================
--- linux-2.6.11-rc5.orig/fs/Kconfig
+++ linux-2.6.11-rc5/fs/Kconfig
@@ -29,6 +29,7 @@ config EXT2_FS_XATTR
config EXT2_FS_POSIX_ACL
bool "Ext2 POSIX Access Control Lists"
depends on EXT2_FS_XATTR
+ select FS_POSIX_ACL
help
Posix Access Control Lists (ACLs) support permissions for users and
groups beyond the owner/group/world scheme.
@@ -97,6 +98,7 @@ config EXT3_FS_XATTR
config EXT3_FS_POSIX_ACL
bool "Ext3 POSIX Access Control Lists"
depends on EXT3_FS_XATTR
+ select FS_POSIX_ACL
help
Posix Access Control Lists (ACLs) support permissions for users and
groups beyond the owner/group/world scheme.
@@ -224,6 +226,7 @@ config REISERFS_FS_XATTR
config REISERFS_FS_POSIX_ACL
bool "ReiserFS POSIX Access Control Lists"
depends on REISERFS_FS_XATTR
+ select FS_POSIX_ACL
help
Posix Access Control Lists (ACLs) support permissions for users and
groups beyond the owner/group/world scheme.
@@ -257,6 +260,7 @@ config JFS_FS
config JFS_POSIX_ACL
bool "JFS POSIX Access Control Lists"
depends on JFS_FS
+ select FS_POSIX_ACL
help
Posix Access Control Lists (ACLs) support permissions for users and
groups beyond the owner/group/world scheme.
@@ -289,8 +293,7 @@ config FS_POSIX_ACL
# Never use this symbol for ifdefs.
#
bool
- depends on EXT2_FS_POSIX_ACL || EXT3_FS_POSIX_ACL || JFS_POSIX_ACL || REISERFS_FS_POSIX_ACL || NFSD_V4
- default y
+ default n
config XFS_FS
tristate "XFS filesystem support"
@@ -1531,6 +1534,7 @@ config NFSD_V4
bool "Provide NFSv4 server support (EXPERIMENTAL)"
depends on NFSD_V3 && EXPERIMENTAL
select NFSD_TCP
+ select FS_POSIX_ACL
help
If you would like to include the NFSv4 server as well as the NFSv2
and NFSv3 servers, say Y here. This feature is experimental, and
--
Andreas Gruenbacher <agruen@suse.de>
SUSE Labs, SUSE LINUX PRODUCTS GMBH
^ permalink raw reply [flat|nested] 21+ messages in thread
* [nfsacl v2 02/16] Qsort
2005-02-27 16:59 [nfsacl v2 00/16] NFSACL protocol extension for NFSv3 Andreas Gruenbacher
2005-02-27 16:59 ` [nfsacl v2 01/16] acl kconfig cleanup Andreas Gruenbacher
@ 2005-02-27 16:59 ` Andreas Gruenbacher
2005-02-27 22:54 ` Andreas Gruenbacher
2005-02-27 16:59 ` [nfsacl v2 03/16] Return -ENOSYS for RPC programs that are unavailable Andreas Gruenbacher
` (13 subsequent siblings)
15 siblings, 1 reply; 21+ messages in thread
From: Andreas Gruenbacher @ 2005-02-27 16:59 UTC (permalink / raw)
To: linux-kernel, Neil Brown, Trond Myklebust
Cc: Olaf Kirch, Andries E. Brouwer, Andrew Morton
[-- Attachment #1: qsort --]
[-- Type: text/plain, Size: 18680 bytes --]
Add a quicksort from glibc as a kernel library function, and switch
xfs over to using it. The implementations are equivalent. The nfsacl
protocol also requires a sort function, so it makes more sense in
the common code.
The plan is to replace this by Matt Machall's heap sort implementation
after it has been fixed.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Index: linux-2.6.11-rc5/include/linux/kernel.h
===================================================================
--- linux-2.6.11-rc5.orig/include/linux/kernel.h
+++ linux-2.6.11-rc5/include/linux/kernel.h
@@ -93,6 +93,8 @@ extern int sscanf(const char *, const ch
__attribute__ ((format (scanf,2,3)));
extern int vsscanf(const char *, const char *, va_list);
+extern void qsort(void *, size_t, size_t, int (*)(const void *,const void *));
+
extern int get_option(char **str, int *pint);
extern char *get_options(const char *str, int nints, int *ints);
extern unsigned long long memparse(char *ptr, char **retptr);
Index: linux-2.6.11-rc5/lib/Kconfig
===================================================================
--- linux-2.6.11-rc5.orig/lib/Kconfig
+++ linux-2.6.11-rc5/lib/Kconfig
@@ -30,6 +30,9 @@ config LIBCRC32C
require M here. See Castagnoli93.
Module will be libcrc32c.
+config QSORT
+ bool "Quick Sort"
+
#
# compression support is select'ed if needed
#
Index: linux-2.6.11-rc5/lib/Makefile
===================================================================
--- linux-2.6.11-rc5.orig/lib/Makefile
+++ linux-2.6.11-rc5/lib/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_CRC_CCITT) += crc-ccitt.o
obj-$(CONFIG_CRC32) += crc32.o
obj-$(CONFIG_LIBCRC32C) += libcrc32c.o
obj-$(CONFIG_GENERIC_IOMAP) += iomap.o
+obj-$(CONFIG_QSORT) += qsort.o
obj-$(CONFIG_ZLIB_INFLATE) += zlib_inflate/
obj-$(CONFIG_ZLIB_DEFLATE) += zlib_deflate/
Index: linux-2.6.11-rc5/lib/qsort.c
===================================================================
--- /dev/null
+++ linux-2.6.11-rc5/lib/qsort.c
@@ -0,0 +1,249 @@
+/* Copyright (C) 1991, 1992, 1996, 1997, 1999 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Written by Douglas C. Schmidt (schmidt@ics.uci.edu).
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/* If you consider tuning this algorithm, you should consult first:
+ Engineering a sort function; Jon Bentley and M. Douglas McIlroy;
+ Software - Practice and Experience; Vol. 23 (11), 1249-1265, 1993. */
+
+# include <linux/module.h>
+# include <linux/slab.h>
+# include <linux/string.h>
+
+MODULE_LICENSE("GPL");
+
+/* Byte-wise swap two items of size SIZE. */
+#define SWAP(a, b, size) \
+ do \
+ { \
+ register size_t __size = (size); \
+ register char *__a = (a), *__b = (b); \
+ do \
+ { \
+ char __tmp = *__a; \
+ *__a++ = *__b; \
+ *__b++ = __tmp; \
+ } while (--__size > 0); \
+ } while (0)
+
+/* Discontinue quicksort algorithm when partition gets below this size.
+ This particular magic number was chosen to work best on a Sun 4/260. */
+#define MAX_THRESH 4
+
+/* Stack node declarations used to store unfulfilled partition obligations. */
+typedef struct
+ {
+ char *lo;
+ char *hi;
+ } stack_node;
+
+/* The next 5 #defines implement a very fast in-line stack abstraction. */
+/* The stack needs log (total_elements) entries (we could even subtract
+ log(MAX_THRESH)). Since total_elements has type size_t, we get as
+ upper bound for log (total_elements):
+ bits per byte (CHAR_BIT) * sizeof(size_t). */
+#define CHAR_BIT 8
+#define STACK_SIZE (CHAR_BIT * sizeof(size_t))
+#define PUSH(low, high) ((void) ((top->lo = (low)), (top->hi = (high)), ++top))
+#define POP(low, high) ((void) (--top, (low = top->lo), (high = top->hi)))
+#define STACK_NOT_EMPTY (stack < top)
+
+
+/* Order size using quicksort. This implementation incorporates
+ four optimizations discussed in Sedgewick:
+
+ 1. Non-recursive, using an explicit stack of pointer that store the
+ next array partition to sort. To save time, this maximum amount
+ of space required to store an array of SIZE_MAX is allocated on the
+ stack. Assuming a 32-bit (64 bit) integer for size_t, this needs
+ only 32 * sizeof(stack_node) == 256 bytes (for 64 bit: 1024 bytes).
+ Pretty cheap, actually.
+
+ 2. Chose the pivot element using a median-of-three decision tree.
+ This reduces the probability of selecting a bad pivot value and
+ eliminates certain extraneous comparisons.
+
+ 3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
+ insertion sort to order the MAX_THRESH items within each partition.
+ This is a big win, since insertion sort is faster for small, mostly
+ sorted array segments.
+
+ 4. The larger of the two sub-partitions is always pushed onto the
+ stack first, with the algorithm then concentrating on the
+ smaller partition. This *guarantees* no more than log (total_elems)
+ stack size is needed (actually O(1) in this case)! */
+
+void
+qsort(void *const pbase, size_t total_elems, size_t size,
+ int(*cmp)(const void *,const void *))
+{
+ register char *base_ptr = (char *) pbase;
+
+ const size_t max_thresh = MAX_THRESH * size;
+
+ if (total_elems == 0)
+ /* Avoid lossage with unsigned arithmetic below. */
+ return;
+
+ if (total_elems > MAX_THRESH)
+ {
+ char *lo = base_ptr;
+ char *hi = &lo[size * (total_elems - 1)];
+ stack_node stack[STACK_SIZE];
+ stack_node *top = stack + 1;
+
+ while (STACK_NOT_EMPTY)
+ {
+ char *left_ptr;
+ char *right_ptr;
+
+ /* Select median value from among LO, MID, and HI. Rearrange
+ LO and HI so the three values are sorted. This lowers the
+ probability of picking a pathological pivot value and
+ skips a comparison for both the LEFT_PTR and RIGHT_PTR in
+ the while loops. */
+
+ char *mid = lo + size * ((hi - lo) / size >> 1);
+
+ if ((*cmp) ((void *) mid, (void *) lo) < 0)
+ SWAP (mid, lo, size);
+ if ((*cmp) ((void *) hi, (void *) mid) < 0)
+ SWAP (mid, hi, size);
+ else
+ goto jump_over;
+ if ((*cmp) ((void *) mid, (void *) lo) < 0)
+ SWAP (mid, lo, size);
+ jump_over:;
+
+ left_ptr = lo + size;
+ right_ptr = hi - size;
+
+ /* Here's the famous ``collapse the walls'' section of quicksort.
+ Gotta like those tight inner loops! They are the main reason
+ that this algorithm runs much faster than others. */
+ do
+ {
+ while ((*cmp) ((void *) left_ptr, (void *) mid) < 0)
+ left_ptr += size;
+
+ while ((*cmp) ((void *) mid, (void *) right_ptr) < 0)
+ right_ptr -= size;
+
+ if (left_ptr < right_ptr)
+ {
+ SWAP (left_ptr, right_ptr, size);
+ if (mid == left_ptr)
+ mid = right_ptr;
+ else if (mid == right_ptr)
+ mid = left_ptr;
+ left_ptr += size;
+ right_ptr -= size;
+ }
+ else if (left_ptr == right_ptr)
+ {
+ left_ptr += size;
+ right_ptr -= size;
+ break;
+ }
+ }
+ while (left_ptr <= right_ptr);
+
+ /* Set up pointers for next iteration. First determine whether
+ left and right partitions are below the threshold size. If so,
+ ignore one or both. Otherwise, push the larger partition's
+ bounds on the stack and continue sorting the smaller one. */
+
+ if ((size_t) (right_ptr - lo) <= max_thresh)
+ {
+ if ((size_t) (hi - left_ptr) <= max_thresh)
+ /* Ignore both small partitions. */
+ POP (lo, hi);
+ else
+ /* Ignore small left partition. */
+ lo = left_ptr;
+ }
+ else if ((size_t) (hi - left_ptr) <= max_thresh)
+ /* Ignore small right partition. */
+ hi = right_ptr;
+ else if ((right_ptr - lo) > (hi - left_ptr))
+ {
+ /* Push larger left partition indices. */
+ PUSH (lo, right_ptr);
+ lo = left_ptr;
+ }
+ else
+ {
+ /* Push larger right partition indices. */
+ PUSH (left_ptr, hi);
+ hi = right_ptr;
+ }
+ }
+ }
+
+ /* Once the BASE_PTR array is partially sorted by quicksort the rest
+ is completely sorted using insertion sort, since this is efficient
+ for partitions below MAX_THRESH size. BASE_PTR points to the beginning
+ of the array to sort, and END_PTR points at the very last element in
+ the array (*not* one beyond it!). */
+
+ {
+ char *end_ptr = &base_ptr[size * (total_elems - 1)];
+ char *tmp_ptr = base_ptr;
+ char *thresh = min(end_ptr, base_ptr + max_thresh);
+ register char *run_ptr;
+
+ /* Find smallest element in first threshold and place it at the
+ array's beginning. This is the smallest array element,
+ and the operation speeds up insertion sort's inner loop. */
+
+ for (run_ptr = tmp_ptr + size; run_ptr <= thresh; run_ptr += size)
+ if ((*cmp) ((void *) run_ptr, (void *) tmp_ptr) < 0)
+ tmp_ptr = run_ptr;
+
+ if (tmp_ptr != base_ptr)
+ SWAP (tmp_ptr, base_ptr, size);
+
+ /* Insertion sort, running from left-hand-side up to right-hand-side. */
+
+ run_ptr = base_ptr + size;
+ while ((run_ptr += size) <= end_ptr)
+ {
+ tmp_ptr = run_ptr - size;
+ while ((*cmp) ((void *) run_ptr, (void *) tmp_ptr) < 0)
+ tmp_ptr -= size;
+
+ tmp_ptr += size;
+ if (tmp_ptr != run_ptr)
+ {
+ char *trav;
+
+ trav = run_ptr + size;
+ while (--trav >= run_ptr)
+ {
+ char c = *trav;
+ char *hi, *lo;
+
+ for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo)
+ *hi = *lo;
+ *hi = c;
+ }
+ }
+ }
+ }
+}
+EXPORT_SYMBOL(qsort);
Index: linux-2.6.11-rc5/fs/xfs/support/qsort.c
===================================================================
--- linux-2.6.11-rc5.orig/fs/xfs/support/qsort.c
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (c) 1992, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-
-/*
- * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
- */
-#define swapcode(TYPE, parmi, parmj, n) { \
- long i = (n) / sizeof (TYPE); \
- register TYPE *pi = (TYPE *) (parmi); \
- register TYPE *pj = (TYPE *) (parmj); \
- do { \
- register TYPE t = *pi; \
- *pi++ = *pj; \
- *pj++ = t; \
- } while (--i > 0); \
-}
-
-#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
- es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
-
-static __inline void
-swapfunc(char *a, char *b, int n, int swaptype)
-{
- if (swaptype <= 1)
- swapcode(long, a, b, n)
- else
- swapcode(char, a, b, n)
-}
-
-#define swap(a, b) \
- if (swaptype == 0) { \
- long t = *(long *)(a); \
- *(long *)(a) = *(long *)(b); \
- *(long *)(b) = t; \
- } else \
- swapfunc(a, b, es, swaptype)
-
-#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype)
-
-static __inline char *
-med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *))
-{
- return cmp(a, b) < 0 ?
- (cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a ))
- :(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c ));
-}
-
-void
-qsort(void *aa, size_t n, size_t es, int (*cmp)(const void *, const void *))
-{
- char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
- int d, r, swaptype, swap_cnt;
- register char *a = aa;
-
-loop: SWAPINIT(a, es);
- swap_cnt = 0;
- if (n < 7) {
- for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es)
- for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
- pl -= es)
- swap(pl, pl - es);
- return;
- }
- pm = (char *)a + (n / 2) * es;
- if (n > 7) {
- pl = (char *)a;
- pn = (char *)a + (n - 1) * es;
- if (n > 40) {
- d = (n / 8) * es;
- pl = med3(pl, pl + d, pl + 2 * d, cmp);
- pm = med3(pm - d, pm, pm + d, cmp);
- pn = med3(pn - 2 * d, pn - d, pn, cmp);
- }
- pm = med3(pl, pm, pn, cmp);
- }
- swap(a, pm);
- pa = pb = (char *)a + es;
-
- pc = pd = (char *)a + (n - 1) * es;
- for (;;) {
- while (pb <= pc && (r = cmp(pb, a)) <= 0) {
- if (r == 0) {
- swap_cnt = 1;
- swap(pa, pb);
- pa += es;
- }
- pb += es;
- }
- while (pb <= pc && (r = cmp(pc, a)) >= 0) {
- if (r == 0) {
- swap_cnt = 1;
- swap(pc, pd);
- pd -= es;
- }
- pc -= es;
- }
- if (pb > pc)
- break;
- swap(pb, pc);
- swap_cnt = 1;
- pb += es;
- pc -= es;
- }
- if (swap_cnt == 0) { /* Switch to insertion sort */
- for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
- for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
- pl -= es)
- swap(pl, pl - es);
- return;
- }
-
- pn = (char *)a + n * es;
- r = min(pa - (char *)a, pb - pa);
- vecswap(a, pb - r, r);
- r = min((long)(pd - pc), (long)(pn - pd - es));
- vecswap(pb, pn - r, r);
- if ((r = pb - pa) > es)
- qsort(a, r / es, es, cmp);
- if ((r = pd - pc) > es) {
- /* Iterate rather than recurse to save stack space */
- a = pn - r;
- n = r / es;
- goto loop;
- }
-/* qsort(pn - r, r / es, es, cmp);*/
-}
Index: linux-2.6.11-rc5/fs/xfs/Makefile
===================================================================
--- linux-2.6.11-rc5.orig/fs/xfs/Makefile
+++ linux-2.6.11-rc5/fs/xfs/Makefile
@@ -143,7 +143,6 @@ xfs-y += $(addprefix linux-2.6/, \
xfs-y += $(addprefix support/, \
debug.o \
move.o \
- qsort.o \
uuid.o)
xfs-$(CONFIG_XFS_TRACE) += support/ktrace.o
Index: linux-2.6.11-rc5/fs/xfs/support/qsort.h
===================================================================
--- linux-2.6.11-rc5.orig/fs/xfs/support/qsort.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of version 2 of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- * Further, this software is distributed without any warranty that it is
- * free of the rightful claim of any third person regarding infringement
- * or the like. Any license provided herein, whether implied or
- * otherwise, applies only to this software file. Patent licenses, if
- * any, provided herein do not apply to combinations of this program with
- * other software, or any other product whatsoever.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write the Free Software Foundation, Inc., 59
- * Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
- * Mountain View, CA 94043, or:
- *
- * http://www.sgi.com
- *
- * For further information regarding this notice, see:
- *
- * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
- */
-
-#ifndef QSORT_H
-#define QSORT_H
-
-extern void qsort (void *const pbase,
- size_t total_elems,
- size_t size,
- int (*cmp)(const void *, const void *));
-
-#endif
Index: linux-2.6.11-rc5/fs/xfs/linux-2.6/xfs_linux.h
===================================================================
--- linux-2.6.11-rc5.orig/fs/xfs/linux-2.6/xfs_linux.h
+++ linux-2.6.11-rc5/fs/xfs/linux-2.6/xfs_linux.h
@@ -64,7 +64,6 @@
#include <sema.h>
#include <time.h>
-#include <support/qsort.h>
#include <support/ktrace.h>
#include <support/debug.h>
#include <support/move.h>
Index: linux-2.6.11-rc5/fs/xfs/Kconfig
===================================================================
--- linux-2.6.11-rc5.orig/fs/xfs/Kconfig
+++ linux-2.6.11-rc5/fs/xfs/Kconfig
@@ -3,6 +3,7 @@ menu "XFS support"
config XFS_FS
tristate "XFS filesystem support"
select EXPORTFS if NFSD!=n
+ select QSORT
help
XFS is a high performance journaling filesystem which originated
on the SGI IRIX platform. It is completely multi-threaded, can
--
Andreas Gruenbacher <agruen@suse.de>
SUSE Labs, SUSE LINUX PRODUCTS GMBH
^ permalink raw reply [flat|nested] 21+ messages in thread
* [nfsacl v2 03/16] Return -ENOSYS for RPC programs that are unavailable
2005-02-27 16:59 [nfsacl v2 00/16] NFSACL protocol extension for NFSv3 Andreas Gruenbacher
2005-02-27 16:59 ` [nfsacl v2 01/16] acl kconfig cleanup Andreas Gruenbacher
2005-02-27 16:59 ` [nfsacl v2 02/16] Qsort Andreas Gruenbacher
@ 2005-02-27 16:59 ` Andreas Gruenbacher
2005-02-27 16:59 ` [nfsacl v2 04/16] Add missing -EOPNOTSUPP => NFS3ERR_NOTSUPP mapping in nfsd Andreas Gruenbacher
` (12 subsequent siblings)
15 siblings, 0 replies; 21+ messages in thread
From: Andreas Gruenbacher @ 2005-02-27 16:59 UTC (permalink / raw)
To: linux-kernel, Neil Brown, Trond Myklebust
Cc: Olaf Kirch, Andries E. Brouwer, Andrew Morton
[-- Attachment #1: nfsacl-return-enosys-for-rpc-programs-that-are-unavailable.patch --]
[-- Type: text/plain, Size: 1955 bytes --]
The issuer of an RPC call should be able to tell the difference between
an I/O error and program unavailable / program version unavailable /
procedure unavailable. Return -ENOSYS for unavailable RPCs instead of
-EIO.
Only issue a program unavailable warning for program numbers other than
the one for nfsacl: Clients with nfsacl support are quite common
already; no need to clutter the syslog.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Index: linux-2.6.11-rc5/net/sunrpc/clnt.c
===================================================================
--- linux-2.6.11-rc5.orig/net/sunrpc/clnt.c
+++ linux-2.6.11-rc5/net/sunrpc/clnt.c
@@ -1041,23 +1041,26 @@ call_verify(struct rpc_task *task)
case RPC_SUCCESS:
return p;
case RPC_PROG_UNAVAIL:
- printk(KERN_WARNING "RPC: call_verify: program %u is unsupported by server %s\n",
- (unsigned int)task->tk_client->cl_prog,
- task->tk_client->cl_server);
- goto out_eio;
+ dprintk(KERN_WARNING "RPC: call_verify: program %u is unsupported by server %s\n",
+ (unsigned int)task->tk_client->cl_prog,
+ task->tk_client->cl_server);
+ error = -ENOSYS;
+ goto out_err;
case RPC_PROG_MISMATCH:
printk(KERN_WARNING "RPC: call_verify: program %u, version %u unsupported by server %s\n",
(unsigned int)task->tk_client->cl_prog,
(unsigned int)task->tk_client->cl_vers,
task->tk_client->cl_server);
- goto out_eio;
+ error = -ENOSYS;
+ goto out_err;
case RPC_PROC_UNAVAIL:
printk(KERN_WARNING "RPC: call_verify: proc %p unsupported by program %u, version %u on server %s\n",
task->tk_msg.rpc_proc,
task->tk_client->cl_prog,
task->tk_client->cl_vers,
task->tk_client->cl_server);
- goto out_eio;
+ error = -EOPNOTSUPP;
+ goto out_err;
case RPC_GARBAGE_ARGS:
dprintk("RPC: %4d %s: server saw garbage\n", task->tk_pid, __FUNCTION__);
break; /* retry */
--
Andreas Gruenbacher <agruen@suse.de>
SUSE Labs, SUSE LINUX PRODUCTS GMBH
^ permalink raw reply [flat|nested] 21+ messages in thread
* [nfsacl v2 04/16] Add missing -EOPNOTSUPP => NFS3ERR_NOTSUPP mapping in nfsd
2005-02-27 16:59 [nfsacl v2 00/16] NFSACL protocol extension for NFSv3 Andreas Gruenbacher
` (2 preceding siblings ...)
2005-02-27 16:59 ` [nfsacl v2 03/16] Return -ENOSYS for RPC programs that are unavailable Andreas Gruenbacher
@ 2005-02-27 16:59 ` Andreas Gruenbacher
2005-02-27 16:59 ` [nfsacl v2 05/16] Allow multiple programs to listen on the same port Andreas Gruenbacher
` (11 subsequent siblings)
15 siblings, 0 replies; 21+ messages in thread
From: Andreas Gruenbacher @ 2005-02-27 16:59 UTC (permalink / raw)
To: linux-kernel, Neil Brown, Trond Myklebust
Cc: Olaf Kirch, Andries E. Brouwer, Andrew Morton
[-- Attachment #1: nfsacl-add-missing-eopnotsupp-=-nfs3err_notsupp-mapping-in-nfsd.patch --]
[-- Type: text/plain, Size: 719 bytes --]
Add the missing NFS3ERR_NOTSUPP error code (defined in NFSv3) to the
system-to-protocol-error table in nfsd. The nfsacl extension uses this error
code.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: Olaf Kirch <okir@suse.de>
Index: linux-2.6.11-rc5/fs/nfsd/nfsproc.c
===================================================================
--- linux-2.6.11-rc5.orig/fs/nfsd/nfsproc.c
+++ linux-2.6.11-rc5/fs/nfsd/nfsproc.c
@@ -590,6 +590,7 @@ nfserrno (int errno)
{ nfserr_dropit, -EAGAIN },
{ nfserr_dropit, -ENOMEM },
{ nfserr_badname, -ESRCH },
+ { nfserr_notsupp, -EOPNOTSUPP },
{ -1, -EIO }
};
int i;
--
Andreas Gruenbacher <agruen@suse.de>
SUSE Labs, SUSE LINUX PRODUCTS GMBH
^ permalink raw reply [flat|nested] 21+ messages in thread
* [nfsacl v2 05/16] Allow multiple programs to listen on the same port
2005-02-27 16:59 [nfsacl v2 00/16] NFSACL protocol extension for NFSv3 Andreas Gruenbacher
` (3 preceding siblings ...)
2005-02-27 16:59 ` [nfsacl v2 04/16] Add missing -EOPNOTSUPP => NFS3ERR_NOTSUPP mapping in nfsd Andreas Gruenbacher
@ 2005-02-27 16:59 ` Andreas Gruenbacher
2005-02-27 17:00 ` [nfsacl v2 06/16] Allow multiple programs to share the same transport Andreas Gruenbacher
` (10 subsequent siblings)
15 siblings, 0 replies; 21+ messages in thread
From: Andreas Gruenbacher @ 2005-02-27 16:59 UTC (permalink / raw)
To: linux-kernel, Neil Brown, Trond Myklebust
Cc: Olaf Kirch, Andries E. Brouwer, Andrew Morton
[-- Attachment #1: nfsacl-allow-multiple-programs-to-listen-on-the-same-port.patch --]
[-- Type: text/plain, Size: 3221 bytes --]
The NFS and NFSACL programs run on the same RPC transport. This patch adds
support for this by converting svc_program into a chained list of programs
(server-side).
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: Olaf Kirch <okir@suse.de>
Index: linux-2.6.11-rc5/include/linux/sunrpc/svc.h
===================================================================
--- linux-2.6.11-rc5.orig/include/linux/sunrpc/svc.h
+++ linux-2.6.11-rc5/include/linux/sunrpc/svc.h
@@ -240,9 +240,10 @@ struct svc_deferred_req {
};
/*
- * RPC program
+ * List of RPC programs on the same transport endpoint
*/
struct svc_program {
+ struct svc_program * pg_next; /* other programs (same xprt) */
u32 pg_prog; /* program number */
unsigned int pg_lovers; /* lowest version */
unsigned int pg_hivers; /* lowest version */
Index: linux-2.6.11-rc5/net/sunrpc/svc.c
===================================================================
--- linux-2.6.11-rc5.orig/net/sunrpc/svc.c
+++ linux-2.6.11-rc5/net/sunrpc/svc.c
@@ -35,20 +35,24 @@ svc_create(struct svc_program *prog, uns
if (!(serv = (struct svc_serv *) kmalloc(sizeof(*serv), GFP_KERNEL)))
return NULL;
memset(serv, 0, sizeof(*serv));
+ serv->sv_name = prog->pg_name;
serv->sv_program = prog;
serv->sv_nrthreads = 1;
serv->sv_stats = prog->pg_stats;
serv->sv_bufsz = bufsize? bufsize : 4096;
- prog->pg_lovers = prog->pg_nvers-1;
xdrsize = 0;
- for (vers=0; vers<prog->pg_nvers ; vers++)
- if (prog->pg_vers[vers]) {
- prog->pg_hivers = vers;
- if (prog->pg_lovers > vers)
- prog->pg_lovers = vers;
- if (prog->pg_vers[vers]->vs_xdrsize > xdrsize)
- xdrsize = prog->pg_vers[vers]->vs_xdrsize;
- }
+ while (prog) {
+ prog->pg_lovers = prog->pg_nvers-1;
+ for (vers=0; vers<prog->pg_nvers ; vers++)
+ if (prog->pg_vers[vers]) {
+ prog->pg_hivers = vers;
+ if (prog->pg_lovers > vers)
+ prog->pg_lovers = vers;
+ if (prog->pg_vers[vers]->vs_xdrsize > xdrsize)
+ xdrsize = prog->pg_vers[vers]->vs_xdrsize;
+ }
+ prog = prog->pg_next;
+ }
serv->sv_xdrsize = xdrsize;
INIT_LIST_HEAD(&serv->sv_threads);
INIT_LIST_HEAD(&serv->sv_sockets);
@@ -56,8 +60,6 @@ svc_create(struct svc_program *prog, uns
INIT_LIST_HEAD(&serv->sv_permsocks);
spin_lock_init(&serv->sv_lock);
- serv->sv_name = prog->pg_name;
-
/* Remove any stale portmap registrations */
svc_register(serv, 0, 0);
@@ -332,7 +334,10 @@ svc_process(struct svc_serv *serv, struc
goto sendit;
}
- if (prog != progp->pg_prog)
+ for (progp = serv->sv_program; progp; progp = progp->pg_next)
+ if (prog == progp->pg_prog)
+ break;
+ if (progp == NULL)
goto err_bad_prog;
if (vers >= progp->pg_nvers ||
@@ -444,11 +449,7 @@ err_bad_auth:
goto sendit;
err_bad_prog:
-#ifdef RPC_PARANOIA
- if (prog != 100227 || progp->pg_prog != 100003)
- printk("svc: unknown program %d (me %d)\n", prog, progp->pg_prog);
- /* else it is just a Solaris client seeing if ACLs are supported */
-#endif
+ dprintk("svc: unknown program %d\n", prog);
serv->sv_stats->rpcbadfmt++;
svc_putu32(resv, rpc_prog_unavail);
goto sendit;
--
Andreas Gruenbacher <agruen@suse.de>
SUSE Labs, SUSE LINUX PRODUCTS GMBH
^ permalink raw reply [flat|nested] 21+ messages in thread
* [nfsacl v2 06/16] Allow multiple programs to share the same transport
2005-02-27 16:59 [nfsacl v2 00/16] NFSACL protocol extension for NFSv3 Andreas Gruenbacher
` (4 preceding siblings ...)
2005-02-27 16:59 ` [nfsacl v2 05/16] Allow multiple programs to listen on the same port Andreas Gruenbacher
@ 2005-02-27 17:00 ` Andreas Gruenbacher
2005-02-27 17:00 ` [nfsacl v2 07/16] Lazy RPC receive buffer allocation Andreas Gruenbacher
` (9 subsequent siblings)
15 siblings, 0 replies; 21+ messages in thread
From: Andreas Gruenbacher @ 2005-02-27 17:00 UTC (permalink / raw)
To: linux-kernel, Neil Brown, Trond Myklebust
Cc: Olaf Kirch, Andries E. Brouwer, Andrew Morton
[-- Attachment #1: nfsacl-allow-multiple-programs-to-share-the-same-transport.patch --]
[-- Type: text/plain, Size: 4167 bytes --]
Allow a clone of an RPC client (created with rpc_clone_client()) to change to
another program. This allows the NFS and NFSACL programs to share the same
transport.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Acked-by: Olaf Kirch <okir@suse.de>
Index: linux-2.6.11-rc5/include/linux/sunrpc/clnt.h
===================================================================
--- linux-2.6.11-rc5.orig/include/linux/sunrpc/clnt.h
+++ linux-2.6.11-rc5/include/linux/sunrpc/clnt.h
@@ -22,6 +22,7 @@
* This defines an RPC port mapping
*/
struct rpc_portmap {
+ struct rpc_portmap *pm_parent;
__u32 pm_prog;
__u32 pm_vers;
__u32 pm_prot;
@@ -116,6 +117,8 @@ struct rpc_clnt *rpc_clone_client(struct
int rpc_shutdown_client(struct rpc_clnt *);
int rpc_destroy_client(struct rpc_clnt *);
void rpc_release_client(struct rpc_clnt *);
+void rpc_change_program(struct rpc_clnt *, struct rpc_program *,
+ int);
void rpc_getport(struct rpc_task *, struct rpc_clnt *);
int rpc_register(u32, u32, int, unsigned short, int *);
Index: linux-2.6.11-rc5/net/sunrpc/clnt.c
===================================================================
--- linux-2.6.11-rc5.orig/net/sunrpc/clnt.c
+++ linux-2.6.11-rc5/net/sunrpc/clnt.c
@@ -139,6 +139,7 @@ rpc_create_client(struct rpc_xprt *xprt,
clnt->cl_maxproc = version->nrprocs;
clnt->cl_protname = program->name;
clnt->cl_pmap = &clnt->cl_pmap_default;
+ clnt->cl_pmap->pm_parent = clnt->cl_pmap;
clnt->cl_port = xprt->addr.sin_port;
clnt->cl_prog = program->number;
clnt->cl_vers = version->number;
@@ -207,6 +208,9 @@ rpc_clone_client(struct rpc_clnt *clnt)
rpc_init_rtt(&new->cl_rtt_default, clnt->cl_xprt->timeout.to_initval);
if (new->cl_auth)
atomic_inc(&new->cl_auth->au_count);
+ new->cl_pmap = &new->cl_pmap_default;
+ new->cl_pmap->pm_parent = clnt->cl_pmap->pm_parent;
+ rpc_init_wait_queue(&new->cl_pmap_default.pm_bindwait, "bindwait");
return new;
out_no_clnt:
printk(KERN_INFO "RPC: out of memory in %s\n", __FUNCTION__);
@@ -296,6 +300,25 @@ rpc_release_client(struct rpc_clnt *clnt
}
/*
+ * Change the program of a (usually cloned) client
+ */
+void
+rpc_change_program(struct rpc_clnt *clnt, struct rpc_program *program,
+ int vers)
+{
+ struct rpc_version *version;
+
+ BUG_ON(vers >= program->nrvers || !program->version[vers]);
+ version = program->version[vers];
+ clnt->cl_procinfo = version->procs;
+ clnt->cl_maxproc = version->nrprocs;
+ clnt->cl_protname = program->name;
+ clnt->cl_prog = program->number;
+ clnt->cl_vers = version->number;
+ clnt->cl_stats = program->stats;
+}
+
+/*
* Default callback for async RPC calls
*/
static void
Index: linux-2.6.11-rc5/net/sunrpc/pmap_clnt.c
===================================================================
--- linux-2.6.11-rc5.orig/net/sunrpc/pmap_clnt.c
+++ linux-2.6.11-rc5/net/sunrpc/pmap_clnt.c
@@ -41,7 +41,7 @@ static spinlock_t pmap_lock = SPIN_LOCK
void
rpc_getport(struct rpc_task *task, struct rpc_clnt *clnt)
{
- struct rpc_portmap *map = clnt->cl_pmap;
+ struct rpc_portmap *map = clnt->cl_pmap->pm_parent;
struct sockaddr_in *sap = &clnt->cl_xprt->addr;
struct rpc_message msg = {
.rpc_proc = &pmap_procedures[PMAP_GETPORT],
@@ -132,7 +132,7 @@ static void
pmap_getport_done(struct rpc_task *task)
{
struct rpc_clnt *clnt = task->tk_client;
- struct rpc_portmap *map = clnt->cl_pmap;
+ struct rpc_portmap *map = clnt->cl_pmap->pm_parent;
dprintk("RPC: %4d pmap_getport_done(status %d, port %d)\n",
task->tk_pid, task->tk_status, clnt->cl_port);
Index: linux-2.6.11-rc5/net/sunrpc/sunrpc_syms.c
===================================================================
--- linux-2.6.11-rc5.orig/net/sunrpc/sunrpc_syms.c
+++ linux-2.6.11-rc5/net/sunrpc/sunrpc_syms.c
@@ -42,6 +42,7 @@ EXPORT_SYMBOL(rpc_release_task);
/* RPC client functions */
EXPORT_SYMBOL(rpc_create_client);
EXPORT_SYMBOL(rpc_clone_client);
+EXPORT_SYMBOL(rpc_change_program);
EXPORT_SYMBOL(rpc_destroy_client);
EXPORT_SYMBOL(rpc_shutdown_client);
EXPORT_SYMBOL(rpc_release_client);
--
Andreas Gruenbacher <agruen@suse.de>
SUSE Labs, SUSE LINUX PRODUCTS GMBH
^ permalink raw reply [flat|nested] 21+ messages in thread
* [nfsacl v2 07/16] Lazy RPC receive buffer allocation
2005-02-27 16:59 [nfsacl v2 00/16] NFSACL protocol extension for NFSv3 Andreas Gruenbacher
` (5 preceding siblings ...)
2005-02-27 17:00 ` [nfsacl v2 06/16] Allow multiple programs to share the same transport Andreas Gruenbacher
@ 2005-02-27 17:00 ` Andreas Gruenbacher
2005-02-27 17:00 ` [nfsacl v2 08/16] Encode and decode arbitrary XDR arrays Andreas Gruenbacher
` (8 subsequent siblings)
15 siblings, 0 replies; 21+ messages in thread
From: Andreas Gruenbacher @ 2005-02-27 17:00 UTC (permalink / raw)
To: linux-kernel, Neil Brown, Trond Myklebust
Cc: Olaf Kirch, Andries E. Brouwer, Andrew Morton
[-- Attachment #1: nfsacl-lazy-rpc-receive-buffer-allocation.patch --]
[-- Type: text/plain, Size: 4788 bytes --]
Allow to allocate pages in the receive buffer lazily. Used for the GETACL
RPC, which has a big maximum reply size, but a small average reply size.
Signed-off-by: Olaf Kirch <okir@suse.de>
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Index: linux-2.6.11-rc5/include/linux/sunrpc/xdr.h
===================================================================
--- linux-2.6.11-rc5.orig/include/linux/sunrpc/xdr.h
+++ linux-2.6.11-rc5/include/linux/sunrpc/xdr.h
@@ -160,7 +160,7 @@ typedef struct {
typedef size_t (*skb_read_actor_t)(skb_reader_t *desc, void *to, size_t len);
-extern void xdr_partial_copy_from_skb(struct xdr_buf *, unsigned int,
+extern int xdr_partial_copy_from_skb(struct xdr_buf *, unsigned int,
skb_reader_t *, skb_read_actor_t);
struct socket;
Index: linux-2.6.11-rc5/net/sunrpc/xdr.c
===================================================================
--- linux-2.6.11-rc5.orig/net/sunrpc/xdr.c
+++ linux-2.6.11-rc5/net/sunrpc/xdr.c
@@ -176,7 +176,7 @@ xdr_inline_pages(struct xdr_buf *xdr, un
xdr->buflen += len;
}
-void
+int
xdr_partial_copy_from_skb(struct xdr_buf *xdr, unsigned int base,
skb_reader_t *desc,
skb_read_actor_t copy_actor)
@@ -190,7 +190,7 @@ xdr_partial_copy_from_skb(struct xdr_buf
len -= base;
ret = copy_actor(desc, (char *)xdr->head[0].iov_base + base, len);
if (ret != len || !desc->count)
- return;
+ return 0;
base = 0;
} else
base -= len;
@@ -210,6 +210,13 @@ xdr_partial_copy_from_skb(struct xdr_buf
do {
char *kaddr;
+ /* ACL likes to be lazy in allocating pages - ACLs
+ * are small by default but can get huge. */
+ if (unlikely(*ppage == NULL)) {
+ if (!(*ppage = alloc_page(GFP_ATOMIC)))
+ return -ENOMEM;
+ }
+
len = PAGE_CACHE_SIZE;
kaddr = kmap_atomic(*ppage, KM_SKB_SUNRPC_DATA);
if (base) {
@@ -226,13 +233,15 @@ xdr_partial_copy_from_skb(struct xdr_buf
flush_dcache_page(*ppage);
kunmap_atomic(kaddr, KM_SKB_SUNRPC_DATA);
if (ret != len || !desc->count)
- return;
+ return 0;
ppage++;
} while ((pglen -= len) != 0);
copy_tail:
len = xdr->tail[0].iov_len;
if (base < len)
copy_actor(desc, (char *)xdr->tail[0].iov_base + base, len - base);
+
+ return 0;
}
Index: linux-2.6.11-rc5/net/sunrpc/xprt.c
===================================================================
--- linux-2.6.11-rc5.orig/net/sunrpc/xprt.c
+++ linux-2.6.11-rc5/net/sunrpc/xprt.c
@@ -725,7 +725,8 @@ csum_partial_copy_to_xdr(struct xdr_buf
goto no_checksum;
desc.csum = csum_partial(skb->data, desc.offset, skb->csum);
- xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_and_csum_bits);
+ if (xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_and_csum_bits) < 0)
+ return -1;
if (desc.offset != skb->len) {
unsigned int csum2;
csum2 = skb_checksum(skb, desc.offset, skb->len - desc.offset, 0);
@@ -737,7 +738,8 @@ csum_partial_copy_to_xdr(struct xdr_buf
return -1;
return 0;
no_checksum:
- xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_bits);
+ if (xdr_partial_copy_from_skb(xdr, 0, &desc, skb_read_bits) < 0)
+ return -1;
if (desc.count)
return -1;
return 0;
@@ -907,6 +909,7 @@ tcp_read_request(struct rpc_xprt *xprt,
struct rpc_rqst *req;
struct xdr_buf *rcvbuf;
size_t len;
+ int r;
/* Find and lock the request corresponding to this xid */
spin_lock(&xprt->sock_lock);
@@ -927,16 +930,30 @@ tcp_read_request(struct rpc_xprt *xprt,
len = xprt->tcp_reclen - xprt->tcp_offset;
memcpy(&my_desc, desc, sizeof(my_desc));
my_desc.count = len;
- xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied,
+ r = xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied,
&my_desc, tcp_copy_data);
desc->count -= len;
desc->offset += len;
} else
- xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied,
+ r = xdr_partial_copy_from_skb(rcvbuf, xprt->tcp_copied,
desc, tcp_copy_data);
xprt->tcp_copied += len;
xprt->tcp_offset += len;
+ if (r < 0) {
+ /* Error when copying to the receive buffer,
+ * usually because we weren't able to allocate
+ * additional buffer pages. All we can do now
+ * is turn off XPRT_COPY_DATA, so the request
+ * will not receive any additional updates,
+ * and time out.
+ * Any remaining data from this record will
+ * be discarded.
+ */
+ xprt->tcp_flags &= ~XPRT_COPY_DATA;
+ goto out;
+ }
+
if (xprt->tcp_copied == req->rq_private_buf.buflen)
xprt->tcp_flags &= ~XPRT_COPY_DATA;
else if (xprt->tcp_offset == xprt->tcp_reclen) {
@@ -949,6 +966,7 @@ tcp_read_request(struct rpc_xprt *xprt,
req->rq_task->tk_pid);
xprt_complete_rqst(xprt, req, xprt->tcp_copied);
}
+out:
spin_unlock(&xprt->sock_lock);
tcp_check_recm(xprt);
}
--
Andreas Gruenbacher <agruen@suse.de>
SUSE Labs, SUSE LINUX PRODUCTS GMBH
^ permalink raw reply [flat|nested] 21+ messages in thread
* [nfsacl v2 08/16] Encode and decode arbitrary XDR arrays
2005-02-27 16:59 [nfsacl v2 00/16] NFSACL protocol extension for NFSv3 Andreas Gruenbacher
` (6 preceding siblings ...)
2005-02-27 17:00 ` [nfsacl v2 07/16] Lazy RPC receive buffer allocation Andreas Gruenbacher
@ 2005-02-27 17:00 ` Andreas Gruenbacher
2005-02-27 17:00 ` [nfsacl v2 09/16] Add noacl nfs mount option Andreas Gruenbacher
` (7 subsequent siblings)
15 siblings, 0 replies; 21+ messages in thread
From: Andreas Gruenbacher @ 2005-02-27 17:00 UTC (permalink / raw)
To: linux-kernel, Neil Brown, Trond Myklebust
Cc: Olaf Kirch, Andries E. Brouwer, Andrew Morton
[-- Attachment #1: nfsacl-encode-and-decode-arbitrary-xdr-arrays.patch --]
[-- Type: text/plain, Size: 9431 bytes --]
Add xdr_encode_array2 and xdr_decode_array2 functions for encoding end
decoding arrays with arbitrary entries, such as acl entries. The goal here is
to do this without allocating a contiguous temporary buffer.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Acked-by: Olaf Kirch <okir@suse.de>
Index: linux-2.6.11-rc5/include/linux/sunrpc/xdr.h
===================================================================
--- linux-2.6.11-rc5.orig/include/linux/sunrpc/xdr.h
+++ linux-2.6.11-rc5/include/linux/sunrpc/xdr.h
@@ -146,7 +146,8 @@ extern void xdr_shift_buf(struct xdr_buf
extern void xdr_buf_from_iov(struct kvec *, struct xdr_buf *);
extern int xdr_buf_subsegment(struct xdr_buf *, struct xdr_buf *, int, int);
extern int xdr_buf_read_netobj(struct xdr_buf *, struct xdr_netobj *, int);
-extern int read_bytes_from_xdr_buf(struct xdr_buf *buf, int base, void *obj, int len);
+extern int read_bytes_from_xdr_buf(struct xdr_buf *, int, void *, int);
+extern int write_bytes_to_xdr_buf(struct xdr_buf *, int, void *, int);
/*
* Helper structure for copying from an sk_buff.
@@ -168,6 +169,22 @@ struct sockaddr;
extern int xdr_sendpages(struct socket *, struct sockaddr *, int,
struct xdr_buf *, unsigned int, int);
+extern int xdr_encode_word(struct xdr_buf *, int, u32);
+extern int xdr_decode_word(struct xdr_buf *, int, u32 *);
+
+struct xdr_array2_desc;
+typedef int (*xdr_xcode_elem_t)(struct xdr_array2_desc *desc, void *elem);
+struct xdr_array2_desc {
+ unsigned int elem_size;
+ unsigned int array_len;
+ xdr_xcode_elem_t xcode;
+};
+
+extern int xdr_decode_array2(struct xdr_buf *buf, unsigned int base,
+ struct xdr_array2_desc *desc);
+extern int xdr_encode_array2(struct xdr_buf *buf, unsigned int base,
+ struct xdr_array2_desc *desc);
+
/*
* Provide some simple tools for XDR buffer overflow-checking etc.
*/
Index: linux-2.6.11-rc5/net/sunrpc/sunrpc_syms.c
===================================================================
--- linux-2.6.11-rc5.orig/net/sunrpc/sunrpc_syms.c
+++ linux-2.6.11-rc5/net/sunrpc/sunrpc_syms.c
@@ -129,6 +129,10 @@ EXPORT_SYMBOL(xdr_encode_netobj);
EXPORT_SYMBOL(xdr_encode_pages);
EXPORT_SYMBOL(xdr_inline_pages);
EXPORT_SYMBOL(xdr_shift_buf);
+EXPORT_SYMBOL(xdr_encode_word);
+EXPORT_SYMBOL(xdr_decode_word);
+EXPORT_SYMBOL(xdr_encode_array2);
+EXPORT_SYMBOL(xdr_decode_array2);
EXPORT_SYMBOL(xdr_buf_from_iov);
EXPORT_SYMBOL(xdr_buf_subsegment);
EXPORT_SYMBOL(xdr_buf_read_netobj);
Index: linux-2.6.11-rc5/net/sunrpc/xdr.c
===================================================================
--- linux-2.6.11-rc5.orig/net/sunrpc/xdr.c
+++ linux-2.6.11-rc5/net/sunrpc/xdr.c
@@ -868,8 +868,34 @@ out:
return status;
}
-static int
-read_u32_from_xdr_buf(struct xdr_buf *buf, int base, u32 *obj)
+/* obj is assumed to point to allocated memory of size at least len: */
+int
+write_bytes_to_xdr_buf(struct xdr_buf *buf, int base, void *obj, int len)
+{
+ struct xdr_buf subbuf;
+ int this_len;
+ int status;
+
+ status = xdr_buf_subsegment(buf, &subbuf, base, len);
+ if (status)
+ goto out;
+ this_len = min(len, (int)subbuf.head[0].iov_len);
+ memcpy(subbuf.head[0].iov_base, obj, this_len);
+ len -= this_len;
+ obj += this_len;
+ this_len = min(len, (int)subbuf.page_len);
+ if (this_len)
+ _copy_to_pages(subbuf.pages, subbuf.page_base, obj, this_len);
+ len -= this_len;
+ obj += this_len;
+ this_len = min(len, (int)subbuf.tail[0].iov_len);
+ memcpy(subbuf.tail[0].iov_base, obj, this_len);
+out:
+ return status;
+}
+
+int
+xdr_decode_word(struct xdr_buf *buf, int base, u32 *obj)
{
u32 raw;
int status;
@@ -881,6 +907,14 @@ read_u32_from_xdr_buf(struct xdr_buf *bu
return 0;
}
+int
+xdr_encode_word(struct xdr_buf *buf, int base, u32 obj)
+{
+ u32 raw = htonl(obj);
+
+ return write_bytes_to_xdr_buf(buf, base, &raw, sizeof(obj));
+}
+
/* If the netobj starting offset bytes from the start of xdr_buf is contained
* entirely in the head or the tail, set object to point to it; otherwise
* try to find space for it at the end of the tail, copy it there, and
@@ -891,7 +925,7 @@ xdr_buf_read_netobj(struct xdr_buf *buf,
u32 tail_offset = buf->head[0].iov_len + buf->page_len;
u32 obj_end_offset;
- if (read_u32_from_xdr_buf(buf, offset, &obj->len))
+ if (xdr_decode_word(buf, offset, &obj->len))
goto out;
obj_end_offset = offset + 4 + obj->len;
@@ -924,3 +958,219 @@ xdr_buf_read_netobj(struct xdr_buf *buf,
out:
return -1;
}
+
+/* Returns 0 on success, or else a negative error code. */
+static int
+xdr_xcode_array2(struct xdr_buf *buf, unsigned int base,
+ struct xdr_array2_desc *desc, int encode)
+{
+ char *elem = NULL, *c;
+ unsigned int copied = 0, todo, avail_here;
+ struct page **ppages = NULL;
+ int err;
+
+ if (encode) {
+ if (xdr_encode_word(buf, base, desc->array_len) != 0)
+ return -EINVAL;
+ } else {
+ if (xdr_decode_word(buf, base, &desc->array_len) != 0 ||
+ (unsigned long) base + 4 + desc->array_len *
+ desc->elem_size > buf->len)
+ return -EINVAL;
+ }
+ base += 4;
+
+ if (!desc->xcode)
+ return 0;
+
+ todo = desc->array_len * desc->elem_size;
+
+ /* process head */
+ if (todo && base < buf->head->iov_len) {
+ c = buf->head->iov_base + base;
+ avail_here = min_t(unsigned int, todo,
+ buf->head->iov_len - base);
+ todo -= avail_here;
+
+ while (avail_here >= desc->elem_size) {
+ err = desc->xcode(desc, c);
+ if (err)
+ goto out;
+ c += desc->elem_size;
+ avail_here -= desc->elem_size;
+ }
+ if (avail_here) {
+ if (!elem) {
+ elem = kmalloc(desc->elem_size, GFP_KERNEL);
+ err = -ENOMEM;
+ if (!elem)
+ goto out;
+ }
+ if (encode) {
+ err = desc->xcode(desc, elem);
+ if (err)
+ goto out;
+ memcpy(c, elem, avail_here);
+ } else
+ memcpy(elem, c, avail_here);
+ copied = avail_here;
+ }
+ base = buf->head->iov_len; /* align to start of pages */
+ }
+
+ /* process pages array */
+ base -= buf->head->iov_len;
+ if (todo && base < buf->page_len) {
+ unsigned int avail_page;
+
+ avail_here = min(todo, buf->page_len - base);
+ todo -= avail_here;
+
+ base += buf->page_base;
+ ppages = buf->pages + (base >> PAGE_CACHE_SHIFT);
+ base &= ~PAGE_CACHE_MASK;
+ avail_page = min_t(unsigned int, PAGE_CACHE_SIZE - base,
+ avail_here);
+ c = kmap(*ppages) + base;
+
+ while (avail_here) {
+ avail_here -= avail_page;
+ if (copied || avail_page < desc->elem_size) {
+ unsigned int l = min(avail_page,
+ desc->elem_size - copied);
+ if (!elem) {
+ elem = kmalloc(desc->elem_size,
+ GFP_KERNEL);
+ err = -ENOMEM;
+ if (!elem)
+ goto out;
+ }
+ if (encode) {
+ if (!copied) {
+ err = desc->xcode(desc, elem);
+ if (err)
+ goto out;
+ }
+ memcpy(c, elem + copied, l);
+ copied += l;
+ if (copied == desc->elem_size)
+ copied = 0;
+ } else {
+ memcpy(elem + copied, c, l);
+ copied += l;
+ if (copied == desc->elem_size) {
+ err = desc->xcode(desc, elem);
+ if (err)
+ goto out;
+ copied = 0;
+ }
+ }
+ avail_page -= l;
+ c += l;
+ }
+ while (avail_page >= desc->elem_size) {
+ err = desc->xcode(desc, c);
+ if (err)
+ goto out;
+ c += desc->elem_size;
+ avail_page -= desc->elem_size;
+ }
+ if (avail_page) {
+ unsigned int l = min(avail_page,
+ desc->elem_size - copied);
+ if (!elem) {
+ elem = kmalloc(desc->elem_size,
+ GFP_KERNEL);
+ err = -ENOMEM;
+ if (!elem)
+ goto out;
+ }
+ if (encode) {
+ if (!copied) {
+ err = desc->xcode(desc, elem);
+ if (err)
+ goto out;
+ }
+ memcpy(c, elem + copied, l);
+ copied += l;
+ if (copied == desc->elem_size)
+ copied = 0;
+ } else {
+ memcpy(elem + copied, c, l);
+ copied += l;
+ if (copied == desc->elem_size) {
+ err = desc->xcode(desc, elem);
+ if (err)
+ goto out;
+ copied = 0;
+ }
+ }
+ }
+ if (avail_here) {
+ kunmap(*ppages);
+ ppages++;
+ c = kmap(*ppages);
+ }
+
+ avail_page = min(avail_here,
+ (unsigned int) PAGE_CACHE_SIZE);
+ }
+ base = buf->page_len; /* align to start of tail */
+ }
+
+ /* process tail */
+ base -= buf->page_len;
+ if (todo) {
+ c = buf->tail->iov_base + base;
+ if (copied) {
+ unsigned int l = desc->elem_size - copied;
+
+ if (encode)
+ memcpy(c, elem + copied, l);
+ else {
+ memcpy(elem + copied, c, l);
+ err = desc->xcode(desc, elem);
+ if (err)
+ goto out;
+ }
+ todo -= l;
+ c += l;
+ }
+ while (todo) {
+ err = desc->xcode(desc, c);
+ if (err)
+ goto out;
+ c += desc->elem_size;
+ todo -= desc->elem_size;
+ }
+ }
+ err = 0;
+
+out:
+ if (elem)
+ kfree(elem);
+ if (ppages)
+ kunmap(*ppages);
+ return err;
+}
+
+int
+xdr_decode_array2(struct xdr_buf *buf, unsigned int base,
+ struct xdr_array2_desc *desc)
+{
+ if (base >= buf->len)
+ return -EINVAL;
+
+ return xdr_xcode_array2(buf, base, desc, 0);
+}
+
+int
+xdr_encode_array2(struct xdr_buf *buf, unsigned int base,
+ struct xdr_array2_desc *desc)
+{
+ if ((unsigned long) base + 4 + desc->array_len * desc->elem_size >
+ buf->head->iov_len + buf->page_len + buf->tail->iov_len)
+ return -EINVAL;
+
+ return xdr_xcode_array2(buf, base, desc, 1);
+}
--
Andreas Gruenbacher <agruen@suse.de>
SUSE Labs, SUSE LINUX PRODUCTS GMBH
^ permalink raw reply [flat|nested] 21+ messages in thread
* [nfsacl v2 09/16] Add noacl nfs mount option
2005-02-27 16:59 [nfsacl v2 00/16] NFSACL protocol extension for NFSv3 Andreas Gruenbacher
` (7 preceding siblings ...)
2005-02-27 17:00 ` [nfsacl v2 08/16] Encode and decode arbitrary XDR arrays Andreas Gruenbacher
@ 2005-02-27 17:00 ` Andreas Gruenbacher
2005-02-27 17:00 ` [nfsacl v2 10/16] Infrastructure and server side of nfsacl Andreas Gruenbacher
` (6 subsequent siblings)
15 siblings, 0 replies; 21+ messages in thread
From: Andreas Gruenbacher @ 2005-02-27 17:00 UTC (permalink / raw)
To: linux-kernel, Neil Brown, Trond Myklebust
Cc: Olaf Kirch, Andries E. Brouwer, Andrew Morton
[-- Attachment #1: nfsacl-add-noacl-nfs-mount-option.patch --]
[-- Type: text/plain, Size: 2471 bytes --]
With the noacl mount option, nfs clients stop using the ACCESS RPC which they
usually use to get an access decision from the server. Instead, they make the
decision based on the file ownership and file mode permission bits.
Security-wise using this option can lead to illicit read access to data cached
locally on the client if the server uses POSIX ACLs. Local access decisions
are correct as long as the server does not support POSIX access control lists.
This approach was discussed with Trond Myklebust <trond.myklebust@fys.uio.no>
and Olaf Kirch <okir@suse.de>. Requires a patch to mount (util-linux).
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: Olaf Kirch <okir@suse.de>
Index: linux-2.6.11-rc5/fs/nfs/dir.c
===================================================================
--- linux-2.6.11-rc5.orig/fs/nfs/dir.c
+++ linux-2.6.11-rc5/fs/nfs/dir.c
@@ -1497,6 +1497,7 @@ out:
int nfs_permission(struct inode *inode, int mask, struct nameidata *nd)
{
+ struct nfs_server *server = NFS_SERVER(inode);
struct rpc_cred *cred;
int res;
@@ -1515,7 +1516,7 @@ int nfs_permission(struct inode *inode,
lock_kernel();
- if (!NFS_PROTO(inode)->access)
+ if ((server->flags & NFS_MOUNT_NOACL) || !NFS_PROTO(inode)->access)
goto out_notsup;
cred = rpcauth_lookupcred(NFS_CLIENT(inode)->cl_auth, 0);
Index: linux-2.6.11-rc5/fs/nfs/inode.c
===================================================================
--- linux-2.6.11-rc5.orig/fs/nfs/inode.c
+++ linux-2.6.11-rc5/fs/nfs/inode.c
@@ -539,6 +539,7 @@ static int nfs_show_options(struct seq_f
{ NFS_MOUNT_NOAC, ",noac", "" },
{ NFS_MOUNT_NONLM, ",nolock", ",lock" },
{ NFS_MOUNT_BROKEN_SUID, ",broken_suid", "" },
+ { NFS_MOUNT_NOACL, ",noacl", "" },
{ 0, NULL, NULL }
};
struct proc_nfs_info *nfs_infop;
Index: linux-2.6.11-rc5/include/linux/nfs_mount.h
===================================================================
--- linux-2.6.11-rc5.orig/include/linux/nfs_mount.h
+++ linux-2.6.11-rc5/include/linux/nfs_mount.h
@@ -58,6 +58,7 @@ struct nfs_mount_data {
#define NFS_MOUNT_KERBEROS 0x0100 /* 3 */
#define NFS_MOUNT_NONLM 0x0200 /* 3 */
#define NFS_MOUNT_BROKEN_SUID 0x0400 /* 4 */
+#define NFS_MOUNT_NOACL 0x0800 /* 4 */
#define NFS_MOUNT_STRICTLOCK 0x1000 /* reserved for NFSv4 */
#define NFS_MOUNT_SECFLAVOUR 0x2000 /* 5 */
#define NFS_MOUNT_FLAGMASK 0xFFFF
--
Andreas Gruenbacher <agruen@suse.de>
SUSE Labs, SUSE LINUX PRODUCTS GMBH
^ permalink raw reply [flat|nested] 21+ messages in thread
* [nfsacl v2 10/16] Infrastructure and server side of nfsacl
2005-02-27 16:59 [nfsacl v2 00/16] NFSACL protocol extension for NFSv3 Andreas Gruenbacher
` (8 preceding siblings ...)
2005-02-27 17:00 ` [nfsacl v2 09/16] Add noacl nfs mount option Andreas Gruenbacher
@ 2005-02-27 17:00 ` Andreas Gruenbacher
2005-02-27 22:56 ` Andreas Gruenbacher
2005-02-27 17:00 ` [nfsacl v2 11/16] Solaris nfsacl workaround Andreas Gruenbacher
` (5 subsequent siblings)
15 siblings, 1 reply; 21+ messages in thread
From: Andreas Gruenbacher @ 2005-02-27 17:00 UTC (permalink / raw)
To: linux-kernel, Neil Brown, Trond Myklebust
Cc: Olaf Kirch, Andries E. Brouwer, Andrew Morton
[-- Attachment #1: nfsacl-infrastructure-and-server-side-of-nfsacl.patch --]
[-- Type: text/plain, Size: 28061 bytes --]
This adds functions for encoding and decoding POSIX ACLs for the NFSACL
protocol extension, and the GETACL and SETACL RPCs. The implementation is
compatible with NFSACL in Solaris.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Acked-by: Olaf Kirch <okir@suse.de>
Index: linux-2.6.11-rc5/fs/Kconfig
===================================================================
--- linux-2.6.11-rc5.orig/fs/Kconfig
+++ linux-2.6.11-rc5/fs/Kconfig
@@ -1435,6 +1435,20 @@ config NFSD_V3
If you would like to include the NFSv3 server as well as the NFSv2
server, say Y here. If unsure, say Y.
+config NFSD_ACL
+ bool "NFS_ACL protocol extension"
+ depends on NFSD_V3
+ select NFS_ACL_SUPPORT
+ help
+ Implement the NFS_ACL protocol extension for manipulating POSIX
+ Access Control Lists on exported file systems. The clients must
+ also implement the NFS_ACL protocol extension; see the
+ CONFIG_NFS_ACL option. If unsure, say N.
+
+config NFS_ACL_SUPPORT
+ bool
+ select FS_POSIX_ACL
+
config NFSD_V4
bool "Provide NFSv4 server support (EXPERIMENTAL)"
depends on NFSD_V3 && EXPERIMENTAL
Index: linux-2.6.11-rc5/fs/Makefile
===================================================================
--- linux-2.6.11-rc5.orig/fs/Makefile
+++ linux-2.6.11-rc5/fs/Makefile
@@ -31,6 +31,7 @@ obj-$(CONFIG_BINFMT_FLAT) += binfmt_flat
obj-$(CONFIG_FS_MBCACHE) += mbcache.o
obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o xattr_acl.o
+obj-$(CONFIG_NFS_ACL_SUPPORT) += nfsacl.o
obj-$(CONFIG_QUOTA) += dquot.o
obj-$(CONFIG_QFMT_V1) += quota_v1.o
Index: linux-2.6.11-rc5/fs/nfsacl.c
===================================================================
--- /dev/null
+++ linux-2.6.11-rc5/fs/nfsacl.c
@@ -0,0 +1,254 @@
+/*
+ * fs/nfsacl.c
+ *
+ * Copyright (C) 2002-2003 Andreas Gruenbacher <agruen@suse.de>
+ */
+
+/*
+ * The Solaris nfsacl protocol represents some ACLs slightly differently
+ * than POSIX 1003.1e draft 17 does (and we do):
+ *
+ * - Minimal ACLs always have an ACL_MASK entry, so they have
+ * four instead of three entries.
+ * - The ACL_MASK entry in such minimal ACLs always has the same
+ * permissions as the ACL_GROUP_OBJ entry. (In extended ACLs
+ * the ACL_MASK and ACL_GROUP_OBJ entries may differ.)
+ * - The identifier fields of the ACL_USER_OBJ and ACL_GROUP_OBJ
+ * entries contain the identifiers of the owner and owning group.
+ * (In POSIX ACLs we always set them to ACL_UNDEFINED_ID).
+ * - ACL entries in the kernel are kept sorted in ascending order
+ * of (e_tag, e_id). Solaris ACLs are unsorted.
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/sunrpc/xdr.h>
+#include <linux/nfsacl.h>
+#include <linux/nfs3.h>
+
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(nfsacl_encode);
+EXPORT_SYMBOL(nfsacl_decode);
+
+struct nfsacl_encode_desc {
+ struct xdr_array2_desc desc;
+ unsigned int count;
+ struct posix_acl *acl;
+ int typeflag;
+ uid_t uid;
+ gid_t gid;
+};
+
+static int
+xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem)
+{
+ struct nfsacl_encode_desc *nfsacl_desc =
+ (struct nfsacl_encode_desc *) desc;
+ u32 *p = (u32 *) elem;
+
+ if (nfsacl_desc->count < nfsacl_desc->acl->a_count) {
+ struct posix_acl_entry *entry =
+ &nfsacl_desc->acl->a_entries[nfsacl_desc->count++];
+
+ *p++ = htonl(entry->e_tag | nfsacl_desc->typeflag);
+ switch(entry->e_tag) {
+ case ACL_USER_OBJ:
+ *p++ = htonl(nfsacl_desc->uid);
+ break;
+ case ACL_GROUP_OBJ:
+ *p++ = htonl(nfsacl_desc->gid);
+ break;
+ case ACL_USER:
+ case ACL_GROUP:
+ *p++ = htonl(entry->e_id);
+ break;
+ default: /* Solaris depends on that! */
+ *p++ = 0;
+ break;
+ }
+ *p++ = htonl(entry->e_perm & S_IRWXO);
+ } else {
+ const struct posix_acl_entry *pa, *pe;
+ int group_obj_perm = ACL_READ|ACL_WRITE|ACL_EXECUTE;
+
+ FOREACH_ACL_ENTRY(pa, nfsacl_desc->acl, pe) {
+ if (pa->e_tag == ACL_GROUP_OBJ) {
+ group_obj_perm = pa->e_perm & S_IRWXO;
+ break;
+ }
+ }
+ /* fake up ACL_MASK entry */
+ *p++ = htonl(ACL_MASK | nfsacl_desc->typeflag);
+ *p++ = htonl(0);
+ *p++ = htonl(group_obj_perm);
+ }
+
+ return 0;
+}
+
+unsigned int
+nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
+ struct posix_acl *acl, int encode_entries, int typeflag)
+{
+ int entries = (acl && acl->a_count) ? max_t(int, acl->a_count, 4) : 0;
+ struct nfsacl_encode_desc nfsacl_desc = {
+ .desc = {
+ .elem_size = 12,
+ .array_len = encode_entries ? entries : 0,
+ .xcode = xdr_nfsace_encode,
+ },
+ .acl = acl,
+ .typeflag = typeflag,
+ .uid = inode->i_uid,
+ .gid = inode->i_gid,
+ };
+ int err;
+
+ if (entries > NFS3_ACL_MAX_ENTRIES ||
+ xdr_encode_word(buf, base, entries))
+ return -EINVAL;
+ err = xdr_encode_array2(buf, base + 4, &nfsacl_desc.desc);
+ if (!err)
+ err = 8 + nfsacl_desc.desc.elem_size *
+ nfsacl_desc.desc.array_len;
+ return err;
+}
+
+struct nfsacl_decode_desc {
+ struct xdr_array2_desc desc;
+ unsigned int count;
+ struct posix_acl *acl;
+};
+
+static int
+xdr_nfsace_decode(struct xdr_array2_desc *desc, void *elem)
+{
+ struct nfsacl_decode_desc *nfsacl_desc =
+ (struct nfsacl_decode_desc *) desc;
+ u32 *p = (u32 *) elem;
+ struct posix_acl_entry *entry;
+
+ if (!nfsacl_desc->acl) {
+ if (desc->array_len > NFS3_ACL_MAX_ENTRIES)
+ return -EINVAL;
+ nfsacl_desc->acl = posix_acl_alloc(desc->array_len, GFP_KERNEL);
+ if (!nfsacl_desc->acl)
+ return -ENOMEM;
+ nfsacl_desc->count = 0;
+ }
+
+ entry = &nfsacl_desc->acl->a_entries[nfsacl_desc->count++];
+ entry->e_tag = ntohl(*p++) & ~NFS3_ACL_DEFAULT;
+ entry->e_id = ntohl(*p++);
+ entry->e_perm = ntohl(*p++);
+
+ switch(entry->e_tag) {
+ case ACL_USER_OBJ:
+ case ACL_USER:
+ case ACL_GROUP_OBJ:
+ case ACL_GROUP:
+ case ACL_OTHER:
+ if (entry->e_perm & ~S_IRWXO)
+ return -EINVAL;
+ break;
+ case ACL_MASK:
+ /* Solaris sometimes sets additonal bits in the mask */
+ entry->e_perm &= S_IRWXO;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+cmp_acl_entry(const struct posix_acl_entry *a, const struct posix_acl_entry *b)
+{
+ if (a->e_tag != b->e_tag)
+ return a->e_tag - b->e_tag;
+ else if (a->e_id > b->e_id)
+ return 1;
+ else if (a->e_id < b->e_id)
+ return -1;
+ else
+ return 0;
+}
+
+/*
+ * Convert from a Solaris ACL to a POSIX 1003.1e draft 17 ACL.
+ */
+static int
+posix_acl_from_nfsacl(struct posix_acl *acl)
+{
+ struct posix_acl_entry *pa, *pe,
+ *group_obj = NULL, *mask = NULL;
+
+ if (!acl)
+ return 0;
+
+ qsort(acl->a_entries, acl->a_count, sizeof(struct posix_acl_entry),
+ (int(*)(const void *,const void *))cmp_acl_entry);
+
+ /* Clear undefined identifier fields and find the ACL_GROUP_OBJ
+ and ACL_MASK entries. */
+ FOREACH_ACL_ENTRY(pa, acl, pe) {
+ switch(pa->e_tag) {
+ case ACL_USER_OBJ:
+ pa->e_id = ACL_UNDEFINED_ID;
+ break;
+ case ACL_GROUP_OBJ:
+ pa->e_id = ACL_UNDEFINED_ID;
+ group_obj = pa;
+ break;
+ case ACL_MASK:
+ mask = pa;
+ /* fall through */
+ case ACL_OTHER:
+ pa->e_id = ACL_UNDEFINED_ID;
+ break;
+ }
+ }
+ if (acl->a_count == 4 && group_obj && mask &&
+ mask->e_perm == group_obj->e_perm) {
+ /* remove bogus ACL_MASK entry */
+ memmove(mask, mask+1, (3 - (mask - acl->a_entries)) *
+ sizeof(struct posix_acl_entry));
+ acl->a_count = 3;
+ }
+ return 0;
+}
+
+unsigned int
+nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt,
+ struct posix_acl **pacl)
+{
+ struct nfsacl_decode_desc nfsacl_desc = {
+ .desc = {
+ .elem_size = 12,
+ .xcode = pacl ? xdr_nfsace_decode : NULL,
+ },
+ };
+ u32 entries;
+ int err;
+
+ if (xdr_decode_word(buf, base, &entries) ||
+ entries > NFS3_ACL_MAX_ENTRIES)
+ return -EINVAL;
+ err = xdr_decode_array2(buf, base + 4, &nfsacl_desc.desc);
+ if (err)
+ return err;
+ if (pacl) {
+ if (entries != nfsacl_desc.desc.array_len ||
+ posix_acl_from_nfsacl(nfsacl_desc.acl) != 0) {
+ posix_acl_release(nfsacl_desc.acl);
+ return -EINVAL;
+ }
+ *pacl = nfsacl_desc.acl;
+ }
+ if (aclcnt)
+ *aclcnt = entries;
+ return 8 + nfsacl_desc.desc.elem_size *
+ nfsacl_desc.desc.array_len;
+}
Index: linux-2.6.11-rc5/fs/nfsd/nfs3proc.c
===================================================================
--- linux-2.6.11-rc5.orig/fs/nfsd/nfs3proc.c
+++ linux-2.6.11-rc5/fs/nfsd/nfs3proc.c
@@ -24,6 +24,7 @@
#include <linux/nfsd/cache.h>
#include <linux/nfsd/xdr3.h>
#include <linux/nfs3.h>
+#include <linux/nfsacl.h>
#define NFSDDBG_FACILITY NFSDDBG_PROC
@@ -630,6 +631,105 @@ nfsd3_proc_commit(struct svc_rqst * rqst
RETURN_STATUS(nfserr);
}
+#ifdef CONFIG_NFSD_ACL
+/*
+ * Get the Access and/or Default ACL of a file.
+ */
+static int
+nfsd3_proc_getacl(struct svc_rqst * rqstp, struct nfsd3_getaclargs *argp,
+ struct nfsd3_getaclres *resp)
+{
+ svc_fh *fh;
+ struct posix_acl *acl;
+ int nfserr = 0;
+
+ fh = fh_copy(&resp->fh, &argp->fh);
+ if ((nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP)))
+ RETURN_STATUS(nfserr_inval);
+
+ if (argp->mask & ~(NFS3_ACL|NFS3_ACLCNT|NFS3_DFACL|NFS3_DFACLCNT))
+ RETURN_STATUS(nfserr_inval);
+ resp->mask = argp->mask;
+
+ if (resp->mask & (NFS3_ACL|NFS3_ACLCNT)) {
+ acl = nfsd_get_posix_acl(fh, ACL_TYPE_ACCESS);
+ if (IS_ERR(acl)) {
+ int err = PTR_ERR(acl);
+
+ if (err == -ENODATA || err == -EOPNOTSUPP)
+ acl = NULL;
+ else {
+ nfserr = nfserrno(err);
+ goto fail;
+ }
+ }
+ if (acl == NULL) {
+ /* Solaris returns the inode's minimum ACL. */
+
+ struct inode *inode = fh->fh_dentry->d_inode;
+ acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
+ }
+ resp->acl_access = acl;
+ }
+ if (resp->mask & (NFS3_DFACL|NFS3_DFACLCNT)) {
+ /* Check how Solaris handles requests for the Default ACL
+ of a non-directory! */
+
+ acl = nfsd_get_posix_acl(fh, ACL_TYPE_DEFAULT);
+ if (IS_ERR(acl)) {
+ int err = PTR_ERR(acl);
+
+ if (err == -ENODATA || err == -EOPNOTSUPP)
+ acl = NULL;
+ else {
+ nfserr = nfserrno(err);
+ goto fail;
+ }
+ }
+ resp->acl_default = acl;
+ }
+
+ /* resp->acl_{access,default} are released in nfs3svc_release_getacl. */
+ RETURN_STATUS(0);
+
+fail:
+ posix_acl_release(resp->acl_access);
+ posix_acl_release(resp->acl_default);
+ RETURN_STATUS(nfserr);
+}
+#endif /* CONFIG_NFSD_ACL */
+
+#ifdef CONFIG_NFSD_ACL
+/*
+ * Set the Access and/or Default ACL of a file.
+ */
+static int
+nfsd3_proc_setacl(struct svc_rqst * rqstp, struct nfsd3_setaclargs *argp,
+ struct nfsd3_attrstat *resp)
+{
+ svc_fh *fh;
+ int nfserr = 0;
+
+ fh = fh_copy(&resp->fh, &argp->fh);
+ nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP);
+
+ if (!nfserr) {
+ nfserr = nfserrno( nfsd_set_posix_acl(
+ fh, ACL_TYPE_ACCESS, argp->acl_access) );
+ }
+ if (!nfserr) {
+ nfserr = nfserrno( nfsd_set_posix_acl(
+ fh, ACL_TYPE_DEFAULT, argp->acl_default) );
+ }
+
+ /* argp->acl_{access,default} may have been allocated in
+ nfs3svc_decode_setaclargs. */
+ posix_acl_release(argp->acl_access);
+ posix_acl_release(argp->acl_default);
+ RETURN_STATUS(nfserr);
+}
+#endif /* CONFIG_NFSD_ACL */
+
/*
* NFSv3 Server procedures.
@@ -647,6 +747,7 @@ nfsd3_proc_commit(struct svc_rqst * rqst
#define nfsd3_attrstatres nfsd3_attrstat
#define nfsd3_wccstatres nfsd3_attrstat
#define nfsd3_createres nfsd3_diropres
+#define nfsd3_setaclres nfsd3_attrstat
#define nfsd3_voidres nfsd3_voidargs
struct nfsd3_voidargs { int dummy; };
@@ -667,6 +768,7 @@ struct nfsd3_voidargs { int dummy; };
#define AT 21 /* attributes */
#define pAT (1+AT) /* post attributes - conditional */
#define WC (7+pAT) /* WCC attributes */
+#define ACL (1+NFS3_ACL_MAX_ENTRIES*3) /* Access Control List */
static struct svc_procedure nfsd_procedures3[22] = {
PROC(null, void, void, void, RC_NOCACHE, ST),
@@ -700,3 +802,19 @@ struct svc_version nfsd_version3 = {
.vs_dispatch = nfsd_dispatch,
.vs_xdrsize = NFS3_SVC_XDRSIZE,
};
+
+#ifdef CONFIG_NFSD_ACL
+struct svc_procedure nfsd_acl_procedures3[] = {
+ PROC(null, void, void, void, RC_NOCACHE, ST),
+ PROC(getacl, getacl, getacl, getacl, RC_NOCACHE, ST+1+2*(1+ACL)),
+ PROC(setacl, setacl, setacl, fhandle, RC_NOCACHE, ST+pAT),
+};
+
+struct svc_version nfsd_acl_version3 = {
+ .vs_vers = 3,
+ .vs_nproc = 3,
+ .vs_proc = nfsd_acl_procedures3,
+ .vs_dispatch = nfsd_dispatch,
+ .vs_xdrsize = NFS3_SVC_XDRSIZE,
+};
+#endif /* CONFIG_NFSD_ACL */
Index: linux-2.6.11-rc5/fs/nfsd/nfs3xdr.c
===================================================================
--- linux-2.6.11-rc5.orig/fs/nfsd/nfs3xdr.c
+++ linux-2.6.11-rc5/fs/nfsd/nfs3xdr.c
@@ -21,6 +21,7 @@
#include <linux/sunrpc/svc.h>
#include <linux/nfsd/nfsd.h>
#include <linux/nfsd/xdr3.h>
+#include <linux/nfsacl.h>
#define NFSDDBG_FACILITY NFSDDBG_XDR
@@ -583,6 +584,47 @@ nfs3svc_decode_commitargs(struct svc_rqs
return xdr_argsize_check(rqstp, p);
}
+#ifdef CONFIG_NFSD_ACL
+int
+nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, u32 *p,
+ struct nfsd3_getaclargs *args)
+{
+ if (!(p = decode_fh(p, &args->fh)))
+ return 0;
+ args->mask = ntohl(*p); p++;
+
+ return xdr_argsize_check(rqstp, p);
+}
+#endif /* CONFIG_NFSD_ACL */
+
+#ifdef CONFIG_NFSD_ACL
+int
+nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, u32 *p,
+ struct nfsd3_setaclargs *args)
+{
+ struct kvec *head = rqstp->rq_arg.head;
+ unsigned int base;
+ int n;
+
+ if (!(p = decode_fh(p, &args->fh)))
+ return 0;
+ args->mask = ntohl(*p++);
+ if (args->mask & ~(NFS3_ACL|NFS3_ACLCNT|NFS3_DFACL|NFS3_DFACLCNT) ||
+ !xdr_argsize_check(rqstp, p))
+ return 0;
+
+ base = (char *)p - (char *)head->iov_base;
+ n = nfsacl_decode(&rqstp->rq_arg, base, NULL,
+ (args->mask & NFS3_ACL) ?
+ &args->acl_access : NULL);
+ if (n > 0)
+ n = nfsacl_decode(&rqstp->rq_arg, base + n, NULL,
+ (args->mask & NFS3_DFACL) ?
+ &args->acl_default : NULL);
+ return (n > 0);
+}
+#endif /* CONFIG_NFSD_ACL */
+
/*
* XDR encode functions
*/
@@ -1066,6 +1108,66 @@ nfs3svc_encode_commitres(struct svc_rqst
return xdr_ressize_check(rqstp, p);
}
+#ifdef CONFIG_NFSD_ACL
+/* GETACL */
+int
+nfs3svc_encode_getaclres(struct svc_rqst *rqstp, u32 *p,
+ struct nfsd3_getaclres *resp)
+{
+ struct dentry *dentry = resp->fh.fh_dentry;
+
+ p = encode_post_op_attr(rqstp, p, &resp->fh);
+ if (resp->status == 0 && dentry && dentry->d_inode) {
+ struct inode *inode = dentry->d_inode;
+ int w = nfsacl_size(
+ (resp->mask & NFS3_ACL) ? resp->acl_access : NULL,
+ (resp->mask & NFS3_DFACL) ? resp->acl_default : NULL);
+ struct kvec *head = rqstp->rq_res.head;
+ unsigned int base;
+ int n;
+
+ *p++ = htonl(resp->mask);
+ if (!xdr_ressize_check(rqstp, p))
+ return 0;
+ base = (char *)p - (char *)head->iov_base;
+
+ rqstp->rq_res.page_len = w;
+ while (w > 0) {
+ if (!svc_take_res_page(rqstp))
+ return 0;
+ w -= PAGE_SIZE;
+ }
+
+ n = nfsacl_encode(&rqstp->rq_res, base, inode,
+ resp->acl_access,
+ resp->mask & NFS3_ACL, 0);
+ if (n > 0)
+ n = nfsacl_encode(&rqstp->rq_res, base + n, inode,
+ resp->acl_default,
+ resp->mask & NFS3_DFACL,
+ NFS3_ACL_DEFAULT);
+ if (n <= 0)
+ return 0;
+ } else
+ if (!xdr_ressize_check(rqstp, p))
+ return 0;
+
+ return 1;
+}
+#endif /* CONFIG_NFSD_ACL */
+
+#ifdef CONFIG_NFSD_ACL
+/* SETACL */
+int
+nfs3svc_encode_setaclres(struct svc_rqst *rqstp, u32 *p,
+ struct nfsd3_attrstat *resp)
+{
+ p = encode_post_op_attr(rqstp, p, &resp->fh);
+
+ return xdr_ressize_check(rqstp, p);
+}
+#endif /* CONFIG_NFSD_ACL */
+
/*
* XDR release functions
*/
@@ -1085,3 +1187,15 @@ nfs3svc_release_fhandle2(struct svc_rqst
fh_put(&resp->fh2);
return 1;
}
+
+#ifdef CONFIG_NFSD_ACL
+int
+nfs3svc_release_getacl(struct svc_rqst *rqstp, u32 *p,
+ struct nfsd3_getaclres *resp)
+{
+ fh_put(&resp->fh);
+ posix_acl_release(resp->acl_access);
+ posix_acl_release(resp->acl_default);
+ return 1;
+}
+#endif /* CONFIG_NFSD_ACL */
Index: linux-2.6.11-rc5/fs/nfsd/nfssvc.c
===================================================================
--- linux-2.6.11-rc5.orig/fs/nfsd/nfssvc.c
+++ linux-2.6.11-rc5/fs/nfsd/nfssvc.c
@@ -49,6 +49,9 @@
#define SIG_NOCLEAN SIGHUP
extern struct svc_program nfsd_program;
+#ifdef CONFIG_NFSD_ACL
+extern struct svc_program nfsd_acl_program;
+#endif
static void nfsd(struct svc_rqst *rqstp);
struct timeval nfssvc_boot;
static struct svc_serv *nfsd_serv;
@@ -370,8 +373,29 @@ static struct svc_version * nfsd_version
#endif
};
+#ifdef CONFIG_NFSD_ACL
+extern struct svc_version nfsd_acl_version3;
+
+static struct svc_version * nfsd_acl_version[] = {
+ [3] = &nfsd_acl_version3,
+};
+
+#define NFSD_ACL_NRVERS (sizeof(nfsd_acl_version)/sizeof(nfsd_acl_version[0]))
+struct svc_program nfsd_acl_program = {
+ .pg_prog = NFS3_ACL_PROGRAM,
+ .pg_nvers = NFSD_ACL_NRVERS,
+ .pg_vers = nfsd_acl_version,
+ .pg_name = "nfsd",
+ .pg_stats = &nfsd_acl_svcstats,
+};
+# define nfsd_acl_program_p &nfsd_acl_program
+#else
+# define nfsd_acl_program_p NULL
+#endif
+
#define NFSD_NRVERS (sizeof(nfsd_version)/sizeof(nfsd_version[0]))
struct svc_program nfsd_program = {
+ .pg_next = nfsd_acl_program_p,
.pg_prog = NFS_PROGRAM, /* program number */
.pg_nvers = NFSD_NRVERS, /* nr of entries in nfsd_version */
.pg_vers = nfsd_version, /* version table */
Index: linux-2.6.11-rc5/fs/nfsd/stats.c
===================================================================
--- linux-2.6.11-rc5.orig/fs/nfsd/stats.c
+++ linux-2.6.11-rc5/fs/nfsd/stats.c
@@ -40,6 +40,12 @@ struct svc_stat nfsd_svcstats = {
.program = &nfsd_program,
};
+#ifdef CONFIG_NFSD_ACL
+struct svc_stat nfsd_acl_svcstats = {
+ .program = &nfsd_acl_program,
+};
+#endif
+
static int nfsd_proc_show(struct seq_file *seq, void *v)
{
int i;
Index: linux-2.6.11-rc5/fs/nfsd/vfs.c
===================================================================
--- linux-2.6.11-rc5.orig/fs/nfsd/vfs.c
+++ linux-2.6.11-rc5/fs/nfsd/vfs.c
@@ -45,6 +45,7 @@
#include <linux/nfsd/nfsfh.h>
#include <linux/quotaops.h>
#include <linux/dnotify.h>
+#include <linux/xattr_acl.h>
#ifdef CONFIG_NFSD_V4
#include <linux/posix_acl.h>
#include <linux/posix_acl_xattr.h>
@@ -1817,3 +1818,109 @@ nfsd_racache_init(int cache_size)
nfsdstats.ra_size = cache_size;
return 0;
}
+
+#ifdef CONFIG_NFSD_ACL
+struct posix_acl *
+nfsd_get_posix_acl(struct svc_fh *fhp, int type)
+{
+ struct inode *inode = fhp->fh_dentry->d_inode;
+ char *name;
+ void *value = NULL;
+ ssize_t size;
+ struct posix_acl *acl;
+
+ if (!IS_POSIXACL(inode) || !inode->i_op || !inode->i_op->getxattr)
+ return ERR_PTR(-EOPNOTSUPP);
+ switch(type) {
+ case ACL_TYPE_ACCESS:
+ name = XATTR_NAME_ACL_ACCESS;
+ break;
+ case ACL_TYPE_DEFAULT:
+ name = XATTR_NAME_ACL_DEFAULT;
+ break;
+ default:
+ return ERR_PTR(-EOPNOTSUPP);
+ }
+
+ size = inode->i_op->getxattr(fhp->fh_dentry, name, NULL, 0);
+
+ if (size < 0) {
+ acl = ERR_PTR(size);
+ goto getout;
+ } else if (size > 0) {
+ value = kmalloc(size, GFP_KERNEL);
+ if (!value) {
+ acl = ERR_PTR(-ENOMEM);
+ goto getout;
+ }
+ size = inode->i_op->getxattr(fhp->fh_dentry, name, value, size);
+ if (size < 0) {
+ acl = ERR_PTR(size);
+ goto getout;
+ }
+ }
+ acl = posix_acl_from_xattr(value, size);
+
+getout:
+ kfree(value);
+ return acl;
+}
+#endif /* CONFIG_NFSD_ACL */
+
+#ifdef CONFIG_NFSD_ACL
+int
+nfsd_set_posix_acl(struct svc_fh *fhp, int type, struct posix_acl *acl)
+{
+ struct inode *inode = fhp->fh_dentry->d_inode;
+ char *name;
+ void *value = NULL;
+ size_t size;
+ int error;
+
+ if (!IS_POSIXACL(inode) || !inode->i_op ||
+ !inode->i_op->setxattr || !inode->i_op->removexattr)
+ return -EOPNOTSUPP;
+ switch(type) {
+ case ACL_TYPE_ACCESS:
+ name = XATTR_NAME_ACL_ACCESS;
+ break;
+ case ACL_TYPE_DEFAULT:
+ name = XATTR_NAME_ACL_DEFAULT;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ if (acl && acl->a_count) {
+ size = xattr_acl_size(acl->a_count);
+ value = kmalloc(size, GFP_KERNEL);
+ if (!value)
+ return -ENOMEM;
+ size = posix_acl_to_xattr(acl, value, size);
+ if (size < 0) {
+ error = size;
+ goto getout;
+ }
+ } else
+ size = 0;
+
+ if (!fhp->fh_locked)
+ fh_lock(fhp); /* unlocking is done automatically */
+ if (size)
+ error = inode->i_op->setxattr(fhp->fh_dentry, name,
+ value, size, 0);
+ else {
+ if (!S_ISDIR(inode->i_mode) && type == ACL_TYPE_DEFAULT)
+ error = 0;
+ else {
+ error = inode->i_op->removexattr(fhp->fh_dentry, name);
+ if (error == -ENODATA)
+ error = 0;
+ }
+ }
+
+getout:
+ kfree(value);
+ return error;
+}
+#endif /* CONFIG_NFSD_ACL */
Index: linux-2.6.11-rc5/include/linux/nfs3.h
===================================================================
--- linux-2.6.11-rc5.orig/include/linux/nfs3.h
+++ linux-2.6.11-rc5/include/linux/nfs3.h
@@ -37,6 +37,15 @@ enum nfs3_createmode {
NFS3_CREATE_EXCLUSIVE = 2
};
+/* Flags for the getacl/setacl mode */
+#define NFS3_ACL 0x0001
+#define NFS3_ACLCNT 0x0002
+#define NFS3_DFACL 0x0004
+#define NFS3_DFACLCNT 0x0008
+
+/* Flag for Default ACL entries */
+#define NFS3_ACL_DEFAULT 0x1000
+
/* NFSv3 file system properties */
#define NFS3_FSF_LINK 0x0001
#define NFS3_FSF_SYMLINK 0x0002
@@ -88,6 +97,10 @@ struct nfs3_fh {
#define NFS3PROC_PATHCONF 20
#define NFS3PROC_COMMIT 21
+#define NFS3_ACL_PROGRAM 100227
+#define NFS3PROC_GETACL 1
+#define NFS3PROC_SETACL 2
+
#define NFS_MNT3_PROGRAM 100005
#define NFS_MNT3_VERSION 3
#define MOUNTPROC3_NULL 0
Index: linux-2.6.11-rc5/include/linux/nfsacl.h
===================================================================
--- /dev/null
+++ linux-2.6.11-rc5/include/linux/nfsacl.h
@@ -0,0 +1,37 @@
+/*
+ * File: linux/nfsacl.h
+ *
+ * (C) 2003 Andreas Gruenbacher <agruen@suse.de>
+ */
+
+
+#ifndef __LINUX_NFSACL_H
+#define __LINUX_NFSACL_H
+
+#include <linux/posix_acl.h>
+
+/* Maximum number of ACL entries over NFS */
+#define NFS3_ACL_MAX_ENTRIES 1024
+
+#define NFSACL_MAXWORDS (2*(2+3*NFS3_ACL_MAX_ENTRIES))
+#define NFSACL_MAXPAGES ((2*(8+12*NFS3_ACL_MAX_ENTRIES) + PAGE_SIZE-1) \
+ >> PAGE_SHIFT)
+
+static inline unsigned int
+nfsacl_size(struct posix_acl *acl_access, struct posix_acl *acl_default)
+{
+ unsigned int w = 16;
+ w += max(acl_access ? (int)acl_access->a_count : 3, 4) * 12;
+ if (acl_default)
+ w += max((int)acl_default->a_count, 4) * 12;
+ return w;
+}
+
+extern unsigned int
+nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
+ struct posix_acl *acl, int encode_entries, int typeflag);
+extern unsigned int
+nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt,
+ struct posix_acl **pacl);
+
+#endif /* __LINUX_NFSACL_H */
Index: linux-2.6.11-rc5/include/linux/nfsd/nfsd.h
===================================================================
--- linux-2.6.11-rc5.orig/include/linux/nfsd/nfsd.h
+++ linux-2.6.11-rc5/include/linux/nfsd/nfsd.h
@@ -15,6 +15,7 @@
#include <linux/unistd.h>
#include <linux/dirent.h>
#include <linux/fs.h>
+#include <linux/posix_acl.h>
#include <linux/mount.h>
#include <linux/nfsd/debug.h>
@@ -60,6 +61,8 @@ extern struct svc_program nfsd_program;
extern struct svc_version nfsd_version2, nfsd_version3,
nfsd_version4;
+extern struct svc_program nfsd_acl_program;
+extern struct svc_version nfsd_acl_version3;
/*
* Function prototypes.
*/
@@ -124,6 +127,22 @@ int nfsd_statfs(struct svc_rqst *, stru
int nfsd_notify_change(struct inode *, struct iattr *);
int nfsd_permission(struct svc_export *, struct dentry *, int);
+#ifdef CONFIG_NFSD_ACL
+struct posix_acl *nfsd_get_posix_acl(struct svc_fh *, int);
+int nfsd_set_posix_acl(struct svc_fh *, int, struct posix_acl *);
+#else
+static inline struct posix_acl *
+nfsd_get_posix_acl(struct svc_fh *fhp, int acl_type)
+{
+ return ERR_PTR(-EOPNOTSUPP);
+}
+static inline int
+nfsd_set_posix_acl(struct svc_fh *fhp, int type, struct posix_acl *acl)
+{
+ return -EOPNOTSUPP;
+}
+#endif
+
/*
* NFSv4 State
Index: linux-2.6.11-rc5/include/linux/nfsd/stats.h
===================================================================
--- linux-2.6.11-rc5.orig/include/linux/nfsd/stats.h
+++ linux-2.6.11-rc5/include/linux/nfsd/stats.h
@@ -36,6 +36,7 @@ struct nfsd_stats {
extern struct nfsd_stats nfsdstats;
extern struct svc_stat nfsd_svcstats;
+extern struct svc_stat nfsd_acl_svcstats;
void nfsd_stat_init(void);
void nfsd_stat_shutdown(void);
Index: linux-2.6.11-rc5/include/linux/nfsd/xdr3.h
===================================================================
--- linux-2.6.11-rc5.orig/include/linux/nfsd/xdr3.h
+++ linux-2.6.11-rc5/include/linux/nfsd/xdr3.h
@@ -10,6 +10,7 @@
#define _LINUX_NFSD_XDR3_H
#include <linux/nfsd/xdr.h>
+#include <linux/posix_acl.h>
struct nfsd3_sattrargs {
struct svc_fh fh;
@@ -110,6 +111,18 @@ struct nfsd3_commitargs {
__u32 count;
};
+struct nfsd3_getaclargs {
+ struct svc_fh fh;
+ int mask;
+};
+
+struct nfsd3_setaclargs {
+ struct svc_fh fh;
+ int mask;
+ struct posix_acl *acl_access;
+ struct posix_acl *acl_default;
+};
+
struct nfsd3_attrstat {
__u32 status;
struct svc_fh fh;
@@ -209,6 +222,14 @@ struct nfsd3_commitres {
struct svc_fh fh;
};
+struct nfsd3_getaclres {
+ __u32 status;
+ struct svc_fh fh;
+ int mask;
+ struct posix_acl *acl_access;
+ struct posix_acl *acl_default;
+};
+
/* dummy type for release */
struct nfsd3_fhandle_pair {
__u32 dummy;
@@ -241,6 +262,7 @@ union nfsd3_xdrstore {
struct nfsd3_fsinfores fsinfores;
struct nfsd3_pathconfres pathconfres;
struct nfsd3_commitres commitres;
+ struct nfsd3_getaclres getaclres;
};
#define NFS3_SVC_XDRSIZE sizeof(union nfsd3_xdrstore)
@@ -276,6 +298,10 @@ int nfs3svc_decode_readdirplusargs(struc
struct nfsd3_readdirargs *);
int nfs3svc_decode_commitargs(struct svc_rqst *, u32 *,
struct nfsd3_commitargs *);
+int nfs3svc_decode_getaclargs(struct svc_rqst *, u32 *,
+ struct nfsd3_getaclargs *);
+int nfs3svc_decode_setaclargs(struct svc_rqst *, u32 *,
+ struct nfsd3_setaclargs *);
int nfs3svc_encode_voidres(struct svc_rqst *, u32 *, void *);
int nfs3svc_encode_attrstat(struct svc_rqst *, u32 *,
struct nfsd3_attrstat *);
@@ -305,11 +331,17 @@ int nfs3svc_encode_pathconfres(struct sv
struct nfsd3_pathconfres *);
int nfs3svc_encode_commitres(struct svc_rqst *, u32 *,
struct nfsd3_commitres *);
+int nfs3svc_encode_getaclres(struct svc_rqst *, u32 *,
+ struct nfsd3_getaclres *);
+int nfs3svc_encode_setaclres(struct svc_rqst *, u32 *,
+ struct nfsd3_attrstat *);
int nfs3svc_release_fhandle(struct svc_rqst *, u32 *,
struct nfsd3_attrstat *);
int nfs3svc_release_fhandle2(struct svc_rqst *, u32 *,
struct nfsd3_fhandle_pair *);
+int nfs3svc_release_getacl(struct svc_rqst *rqstp, u32 *p,
+ struct nfsd3_getaclres *resp);
int nfs3svc_encode_entry(struct readdir_cd *, const char *name,
int namlen, loff_t offset, ino_t ino,
unsigned int);
Index: linux-2.6.11-rc5/include/linux/sunrpc/svc.h
===================================================================
--- linux-2.6.11-rc5.orig/include/linux/sunrpc/svc.h
+++ linux-2.6.11-rc5/include/linux/sunrpc/svc.h
@@ -185,6 +185,27 @@ xdr_ressize_check(struct svc_rqst *rqstp
return vec->iov_len <= PAGE_SIZE;
}
+#if 0
+static inline struct page *
+svc_take_arg_page(struct svc_rqst *rqstp)
+{
+ if (rqstp->rq_arghi <= rqstp->rq_argused)
+ return NULL;
+ return rqstp->rq_argpages[rqstp->rq_argused++];
+}
+#endif
+
+static inline struct page *
+svc_take_res_page(struct svc_rqst *rqstp)
+{
+ if (rqstp->rq_arghi <= rqstp->rq_argused)
+ return NULL;
+ rqstp->rq_arghi--;
+ rqstp->rq_respages[rqstp->rq_resused] =
+ rqstp->rq_argpages[rqstp->rq_arghi];
+ return rqstp->rq_respages[rqstp->rq_resused++];
+}
+
static inline int svc_take_page(struct svc_rqst *rqstp)
{
if (rqstp->rq_arghi <= rqstp->rq_argused)
--
Andreas Gruenbacher <agruen@suse.de>
SUSE Labs, SUSE LINUX PRODUCTS GMBH
^ permalink raw reply [flat|nested] 21+ messages in thread
* [nfsacl v2 11/16] Solaris nfsacl workaround
2005-02-27 16:59 [nfsacl v2 00/16] NFSACL protocol extension for NFSv3 Andreas Gruenbacher
` (9 preceding siblings ...)
2005-02-27 17:00 ` [nfsacl v2 10/16] Infrastructure and server side of nfsacl Andreas Gruenbacher
@ 2005-02-27 17:00 ` Andreas Gruenbacher
2005-02-27 17:00 ` [nfsacl v2 12/16] nfs mknod cleanup Andreas Gruenbacher
` (4 subsequent siblings)
15 siblings, 0 replies; 21+ messages in thread
From: Andreas Gruenbacher @ 2005-02-27 17:00 UTC (permalink / raw)
To: linux-kernel, Neil Brown, Trond Myklebust
Cc: Olaf Kirch, Andries E. Brouwer, Andrew Morton
[-- Attachment #1: nfsacl-solaris-nfsacl-workaround.patch --]
[-- Type: text/plain, Size: 1159 bytes --]
If the nfs_acl program is available, Solaris clients expect both version
2 and version 3 to be available; RPC_PROG_MISMATCH leads to a mount
failure. Fake RPC_PROG_UNAVAIL when asked for nfs_acl version 2.
Trond has rejected this patch. I'm not sure how to deal with it in a
truly clean way, so probably I won't care and still use this as a vendor
patch.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Signed-off-by: Olaf Kirch <okir@suse.de>
Index: linux-2.6.11-rc5/net/sunrpc/svc.c
===================================================================
--- linux-2.6.11-rc5.orig/net/sunrpc/svc.c
+++ linux-2.6.11-rc5/net/sunrpc/svc.c
@@ -455,6 +455,13 @@ err_bad_prog:
goto sendit;
err_bad_vers:
+ if (prog == 100227 && vers == 2) {
+ /* If the nfs_acl program is available, Solaris clients expect
+ both version 2 and version 3 to be available;
+ RPC_PROG_MISMATCH leads to a mount failure. Fake
+ RPC_PROG_UNAVAIL when asked for nfs_acl version 2. */
+ goto err_bad_prog;
+ }
#ifdef RPC_PARANOIA
printk("svc: unknown version (%d)\n", vers);
#endif
--
Andreas Gruenbacher <agruen@suse.de>
SUSE Labs, SUSE LINUX PRODUCTS GMBH
^ permalink raw reply [flat|nested] 21+ messages in thread
* [nfsacl v2 12/16] nfs mknod cleanup
2005-02-27 16:59 [nfsacl v2 00/16] NFSACL protocol extension for NFSv3 Andreas Gruenbacher
` (10 preceding siblings ...)
2005-02-27 17:00 ` [nfsacl v2 11/16] Solaris nfsacl workaround Andreas Gruenbacher
@ 2005-02-27 17:00 ` Andreas Gruenbacher
2005-02-27 17:00 ` [nfsacl v2 13/16] nfs mkdir cleanup Andreas Gruenbacher
` (3 subsequent siblings)
15 siblings, 0 replies; 21+ messages in thread
From: Andreas Gruenbacher @ 2005-02-27 17:00 UTC (permalink / raw)
To: linux-kernel, Neil Brown, Trond Myklebust
Cc: Olaf Kirch, Andries E. Brouwer, Andrew Morton
[-- Attachment #1: nfs-cleanup_mknod.diff --]
[-- Type: text/plain, Size: 8334 bytes --]
Trond Myklebust <trond.myklebust@fys.uio.no> wrote:
[...] How about if we change the interfaces for NFS_PROTO()->mknod(), and
mkdir, so that they take a dentry argument instead of the struct qstr,
and then have them instantiate the dentry? The appended (untested) patch
tries to do this for mknod()...
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Index: linux-2.6.11-rc5/fs/nfs/nfs3proc.c
===================================================================
--- linux-2.6.11-rc5.orig/fs/nfs/nfs3proc.c
+++ linux-2.6.11-rc5/fs/nfs/nfs3proc.c
@@ -639,23 +639,24 @@ nfs3_proc_readdir(struct dentry *dentry,
}
static int
-nfs3_proc_mknod(struct inode *dir, struct qstr *name, struct iattr *sattr,
- dev_t rdev, struct nfs_fh *fh, struct nfs_fattr *fattr)
+nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
+ dev_t rdev)
{
- struct nfs_fattr dir_attr;
+ struct nfs_fh fh;
+ struct nfs_fattr fattr, dir_attr;
struct nfs3_mknodargs arg = {
.fh = NFS_FH(dir),
- .name = name->name,
- .len = name->len,
+ .name = dentry->d_name.name,
+ .len = dentry->d_name.len,
.sattr = sattr,
.rdev = rdev
};
struct nfs3_diropres res = {
.dir_attr = &dir_attr,
- .fh = fh,
- .fattr = fattr
+ .fh = &fh,
+ .fattr = &fattr
};
- int status;
+ int status;
switch (sattr->ia_mode & S_IFMT) {
case S_IFBLK: arg.type = NF3BLK; break;
@@ -665,12 +666,14 @@ nfs3_proc_mknod(struct inode *dir, struc
default: return -EINVAL;
}
- dprintk("NFS call mknod %s %u:%u\n", name->name,
+ dprintk("NFS call mknod %s %u:%u\n", dentry->d_name.name,
MAJOR(rdev), MINOR(rdev));
dir_attr.valid = 0;
- fattr->valid = 0;
+ fattr.valid = 0;
status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKNOD, &arg, &res, 0);
nfs_refresh_inode(dir, &dir_attr);
+ if (!status)
+ status = nfs_instantiate(dentry, &fh, &fattr);
dprintk("NFS reply mknod: %d\n", status);
return status;
}
Index: linux-2.6.11-rc5/fs/nfs/nfs4proc.c
===================================================================
--- linux-2.6.11-rc5.orig/fs/nfs/nfs4proc.c
+++ linux-2.6.11-rc5/fs/nfs/nfs4proc.c
@@ -1630,22 +1630,23 @@ static int nfs4_proc_readdir(struct dent
return err;
}
-static int _nfs4_proc_mknod(struct inode *dir, struct qstr *name,
- struct iattr *sattr, dev_t rdev, struct nfs_fh *fh,
- struct nfs_fattr *fattr)
+static int _nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
+ struct iattr *sattr, dev_t rdev)
{
struct nfs_server *server = NFS_SERVER(dir);
+ struct nfs_fh fh;
+ struct nfs_fattr fattr;
struct nfs4_create_arg arg = {
.dir_fh = NFS_FH(dir),
.server = server,
- .name = name,
+ .name = &dentry->d_name,
.attrs = sattr,
.bitmask = server->attr_bitmask,
};
struct nfs4_create_res res = {
.server = server,
- .fh = fh,
- .fattr = fattr,
+ .fh = &fh,
+ .fattr = &fattr,
};
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE],
@@ -1655,7 +1656,7 @@ static int _nfs4_proc_mknod(struct inode
int status;
int mode = sattr->ia_mode;
- fattr->valid = 0;
+ fattr.valid = 0;
BUG_ON(!(sattr->ia_valid & ATTR_MODE));
BUG_ON(!S_ISFIFO(mode) && !S_ISBLK(mode) && !S_ISCHR(mode) && !S_ISSOCK(mode));
@@ -1677,19 +1678,19 @@ static int _nfs4_proc_mknod(struct inode
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
if (!status)
update_changeattr(dir, &res.dir_cinfo);
+ if (!status)
+ status = nfs_instantiate(dentry, &fh, &fattr);
return status;
}
-static int nfs4_proc_mknod(struct inode *dir, struct qstr *name,
- struct iattr *sattr, dev_t rdev, struct nfs_fh *fh,
- struct nfs_fattr *fattr)
+static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry,
+ struct iattr *sattr, dev_t rdev)
{
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(NFS_SERVER(dir),
- _nfs4_proc_mknod(dir, name, sattr, rdev,
- fh, fattr),
+ _nfs4_proc_mknod(dir, dentry, sattr, rdev),
&exception);
} while (exception.retry);
return err;
Index: linux-2.6.11-rc5/fs/nfs/proc.c
===================================================================
--- linux-2.6.11-rc5.orig/fs/nfs/proc.c
+++ linux-2.6.11-rc5/fs/nfs/proc.c
@@ -248,22 +248,24 @@ nfs_proc_create(struct inode *dir, struc
* In NFSv2, mknod is grafted onto the create call.
*/
static int
-nfs_proc_mknod(struct inode *dir, struct qstr *name, struct iattr *sattr,
- dev_t rdev, struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+nfs_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
+ dev_t rdev)
{
+ struct nfs_fh fhandle;
+ struct nfs_fattr fattr;
struct nfs_createargs arg = {
.fh = NFS_FH(dir),
- .name = name->name,
- .len = name->len,
+ .name = dentry->d_name.name,
+ .len = dentry->d_name.len,
.sattr = sattr
};
struct nfs_diropok res = {
- .fh = fhandle,
- .fattr = fattr
+ .fh = &fhandle,
+ .fattr = &fattr
};
- int status, mode;
+ int status, mode;
- dprintk("NFS call mknod %s\n", name->name);
+ dprintk("NFS call mknod %s\n", dentry->d_name.name);
mode = sattr->ia_mode;
if (S_ISFIFO(mode)) {
@@ -274,14 +276,16 @@ nfs_proc_mknod(struct inode *dir, struct
sattr->ia_size = new_encode_dev(rdev);/* get out your barf bag */
}
- fattr->valid = 0;
+ fattr.valid = 0;
status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0);
if (status == -EINVAL && S_ISFIFO(mode)) {
sattr->ia_mode = mode;
- fattr->valid = 0;
+ fattr.valid = 0;
status = rpc_call(NFS_CLIENT(dir), NFSPROC_CREATE, &arg, &res, 0);
}
+ if (!status)
+ status = nfs_instantiate(dentry, &fhandle, &fattr);
dprintk("NFS reply mknod: %d\n", status);
return status;
}
Index: linux-2.6.11-rc5/fs/nfs/dir.c
===================================================================
--- linux-2.6.11-rc5.orig/fs/nfs/dir.c
+++ linux-2.6.11-rc5/fs/nfs/dir.c
@@ -938,7 +938,7 @@ static struct dentry *nfs_readdir_lookup
/*
* Code common to create, mkdir, and mknod.
*/
-static int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
+int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fhandle,
struct nfs_fattr *fattr)
{
struct inode *inode;
@@ -1019,9 +1019,7 @@ static int
nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
{
struct iattr attr;
- struct nfs_fattr fattr;
- struct nfs_fh fhandle;
- int error;
+ int status;
dfprintk(VFS, "NFS: mknod(%s/%ld, %s\n", dir->i_sb->s_id,
dir->i_ino, dentry->d_name.name);
@@ -1034,15 +1032,12 @@ nfs_mknod(struct inode *dir, struct dent
lock_kernel();
nfs_begin_data_update(dir);
- error = NFS_PROTO(dir)->mknod(dir, &dentry->d_name, &attr, rdev,
- &fhandle, &fattr);
+ status = NFS_PROTO(dir)->mknod(dir, dentry, &attr, rdev);
nfs_end_data_update(dir);
- if (!error)
- error = nfs_instantiate(dentry, &fhandle, &fattr);
- else
+ if (status)
d_drop(dentry);
unlock_kernel();
- return error;
+ return status;
}
/*
Index: linux-2.6.11-rc5/include/linux/nfs_xdr.h
===================================================================
--- linux-2.6.11-rc5.orig/include/linux/nfs_xdr.h
+++ linux-2.6.11-rc5/include/linux/nfs_xdr.h
@@ -698,8 +698,8 @@ struct nfs_rpc_ops {
int (*rmdir) (struct inode *, struct qstr *);
int (*readdir) (struct dentry *, struct rpc_cred *,
u64, struct page *, unsigned int, int);
- int (*mknod) (struct inode *, struct qstr *, struct iattr *,
- dev_t, struct nfs_fh *, struct nfs_fattr *);
+ int (*mknod) (struct inode *, struct dentry *, struct iattr *,
+ dev_t);
int (*statfs) (struct nfs_server *, struct nfs_fh *,
struct nfs_fsstat *);
int (*fsinfo) (struct nfs_server *, struct nfs_fh *,
Index: linux-2.6.11-rc5/include/linux/nfs_fs.h
===================================================================
--- linux-2.6.11-rc5.orig/include/linux/nfs_fs.h
+++ linux-2.6.11-rc5/include/linux/nfs_fs.h
@@ -345,6 +345,8 @@ extern struct inode_operations nfs_dir_i
extern struct file_operations nfs_dir_operations;
extern struct dentry_operations nfs_dentry_operations;
+extern int nfs_instantiate(struct dentry *dentry, struct nfs_fh *fh, struct nfs_fattr *fattr);
+
/*
* linux/fs/nfs/symlink.c
*/
--
Andreas Gruenbacher <agruen@suse.de>
SUSE Labs, SUSE LINUX PRODUCTS GMBH
^ permalink raw reply [flat|nested] 21+ messages in thread
* [nfsacl v2 13/16] nfs mkdir cleanup
2005-02-27 16:59 [nfsacl v2 00/16] NFSACL protocol extension for NFSv3 Andreas Gruenbacher
` (11 preceding siblings ...)
2005-02-27 17:00 ` [nfsacl v2 12/16] nfs mknod cleanup Andreas Gruenbacher
@ 2005-02-27 17:00 ` Andreas Gruenbacher
2005-02-27 17:00 ` [nfsacl v2 14/16] Client side of nfsacl Andreas Gruenbacher
` (2 subsequent siblings)
15 siblings, 0 replies; 21+ messages in thread
From: Andreas Gruenbacher @ 2005-02-27 17:00 UTC (permalink / raw)
To: linux-kernel, Neil Brown, Trond Myklebust
Cc: Olaf Kirch, Andries E. Brouwer, Andrew Morton
[-- Attachment #1: nfs-cleanup_mkdir.diff --]
[-- Type: text/plain, Size: 6552 bytes --]
Trond Myklebust <trond.myklebust@fys.uio.no> wrote:
[...] How about if we change the interfaces for NFS_PROTO()->mknod(), and
mkdir, so that they take a dentry argument instead of the struct qstr,
and then have them instantiate the dentry? The appended (untested) patch
tries to do this for mknod()...
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Index: linux-2.6.11-rc5/fs/nfs/nfs3proc.c
===================================================================
--- linux-2.6.11-rc5.orig/fs/nfs/nfs3proc.c
+++ linux-2.6.11-rc5/fs/nfs/nfs3proc.c
@@ -540,28 +540,30 @@ nfs3_proc_symlink(struct inode *dir, str
}
static int
-nfs3_proc_mkdir(struct inode *dir, struct qstr *name, struct iattr *sattr,
- struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr)
{
- struct nfs_fattr dir_attr;
+ struct nfs_fattr fattr, dir_attr;
+ struct nfs_fh fh;
struct nfs3_mkdirargs arg = {
.fh = NFS_FH(dir),
- .name = name->name,
- .len = name->len,
+ .name = dentry->d_name.name,
+ .len = dentry->d_name.len,
.sattr = sattr
};
struct nfs3_diropres res = {
.dir_attr = &dir_attr,
- .fh = fhandle,
- .fattr = fattr
+ .fh = &fh,
+ .fattr = &fattr
};
- int status;
+ int status;
- dprintk("NFS call mkdir %s\n", name->name);
+ dprintk("NFS call mkdir %s\n", dentry->d_name.name);
dir_attr.valid = 0;
- fattr->valid = 0;
+ fattr.valid = 0;
status = rpc_call(NFS_CLIENT(dir), NFS3PROC_MKDIR, &arg, &res, 0);
nfs_refresh_inode(dir, &dir_attr);
+ if (!status)
+ status = nfs_instantiate(dentry, &fh, &fattr);
dprintk("NFS reply mkdir: %d\n", status);
return status;
}
Index: linux-2.6.11-rc5/fs/nfs/nfs4proc.c
===================================================================
--- linux-2.6.11-rc5.orig/fs/nfs/nfs4proc.c
+++ linux-2.6.11-rc5/fs/nfs/nfs4proc.c
@@ -1539,49 +1539,50 @@ static int nfs4_proc_symlink(struct inod
return err;
}
-static int _nfs4_proc_mkdir(struct inode *dir, struct qstr *name,
- struct iattr *sattr, struct nfs_fh *fhandle,
- struct nfs_fattr *fattr)
+static int _nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
+ struct iattr *sattr)
{
struct nfs_server *server = NFS_SERVER(dir);
+ struct nfs_fh fh;
+ struct nfs_fattr fattr;
struct nfs4_create_arg arg = {
.dir_fh = NFS_FH(dir),
.server = server,
- .name = name,
+ .name = &dentry->d_name,
.attrs = sattr,
.ftype = NF4DIR,
.bitmask = server->attr_bitmask,
};
struct nfs4_create_res res = {
.server = server,
- .fh = fhandle,
- .fattr = fattr,
+ .fh = &fh,
+ .fattr = &fattr,
};
struct rpc_message msg = {
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_CREATE],
.rpc_argp = &arg,
.rpc_resp = &res,
};
- int status;
+ int status;
- fattr->valid = 0;
+ fattr.valid = 0;
status = rpc_call_sync(NFS_CLIENT(dir), &msg, 0);
- if (!status)
+ if (!status) {
update_changeattr(dir, &res.dir_cinfo);
+ status = nfs_instantiate(dentry, &fh, &fattr);
+ }
return status;
}
-static int nfs4_proc_mkdir(struct inode *dir, struct qstr *name,
- struct iattr *sattr, struct nfs_fh *fhandle,
- struct nfs_fattr *fattr)
+static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry,
+ struct iattr *sattr)
{
struct nfs4_exception exception = { };
int err;
do {
err = nfs4_handle_exception(NFS_SERVER(dir),
- _nfs4_proc_mkdir(dir, name, sattr,
- fhandle, fattr),
+ _nfs4_proc_mkdir(dir, dentry, sattr),
&exception);
} while (exception.retry);
return err;
Index: linux-2.6.11-rc5/fs/nfs/proc.c
===================================================================
--- linux-2.6.11-rc5.orig/fs/nfs/proc.c
+++ linux-2.6.11-rc5/fs/nfs/proc.c
@@ -402,24 +402,27 @@ nfs_proc_symlink(struct inode *dir, stru
}
static int
-nfs_proc_mkdir(struct inode *dir, struct qstr *name, struct iattr *sattr,
- struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+nfs_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr)
{
+ struct nfs_fh fh;
+ struct nfs_fattr fattr;
struct nfs_createargs arg = {
.fh = NFS_FH(dir),
- .name = name->name,
- .len = name->len,
+ .name = dentry->d_name.name,
+ .len = dentry->d_name.len,
.sattr = sattr
};
struct nfs_diropok res = {
- .fh = fhandle,
- .fattr = fattr
+ .fh = &fh,
+ .fattr = &fattr
};
int status;
- dprintk("NFS call mkdir %s\n", name->name);
- fattr->valid = 0;
+ dprintk("NFS call mkdir %s\n", dentry->d_name.name);
+ fattr.valid = 0;
status = rpc_call(NFS_CLIENT(dir), NFSPROC_MKDIR, &arg, &res, 0);
+ if (!status)
+ status = nfs_instantiate(dentry, &fh, &fattr);
dprintk("NFS reply mkdir: %d\n", status);
return status;
}
Index: linux-2.6.11-rc5/fs/nfs/dir.c
===================================================================
--- linux-2.6.11-rc5.orig/fs/nfs/dir.c
+++ linux-2.6.11-rc5/fs/nfs/dir.c
@@ -1046,9 +1046,7 @@ nfs_mknod(struct inode *dir, struct dent
static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
struct iattr attr;
- struct nfs_fattr fattr;
- struct nfs_fh fhandle;
- int error;
+ int status;
dfprintk(VFS, "NFS: mkdir(%s/%ld, %s\n", dir->i_sb->s_id,
dir->i_ino, dentry->d_name.name);
@@ -1067,15 +1065,12 @@ static int nfs_mkdir(struct inode *dir,
d_drop(dentry);
#endif
nfs_begin_data_update(dir);
- error = NFS_PROTO(dir)->mkdir(dir, &dentry->d_name, &attr, &fhandle,
- &fattr);
+ status = NFS_PROTO(dir)->mkdir(dir, dentry, &attr);
nfs_end_data_update(dir);
- if (!error)
- error = nfs_instantiate(dentry, &fhandle, &fattr);
- else
+ if (status)
d_drop(dentry);
unlock_kernel();
- return error;
+ return status;
}
static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
Index: linux-2.6.11-rc5/include/linux/nfs_xdr.h
===================================================================
--- linux-2.6.11-rc5.orig/include/linux/nfs_xdr.h
+++ linux-2.6.11-rc5/include/linux/nfs_xdr.h
@@ -693,8 +693,7 @@ struct nfs_rpc_ops {
int (*symlink) (struct inode *, struct qstr *, struct qstr *,
struct iattr *, struct nfs_fh *,
struct nfs_fattr *);
- int (*mkdir) (struct inode *, struct qstr *, struct iattr *,
- struct nfs_fh *, struct nfs_fattr *);
+ int (*mkdir) (struct inode *, struct dentry *, struct iattr *);
int (*rmdir) (struct inode *, struct qstr *);
int (*readdir) (struct dentry *, struct rpc_cred *,
u64, struct page *, unsigned int, int);
--
Andreas Gruenbacher <agruen@suse.de>
SUSE Labs, SUSE LINUX PRODUCTS GMBH
^ permalink raw reply [flat|nested] 21+ messages in thread
* [nfsacl v2 14/16] Client side of nfsacl
2005-02-27 16:59 [nfsacl v2 00/16] NFSACL protocol extension for NFSv3 Andreas Gruenbacher
` (12 preceding siblings ...)
2005-02-27 17:00 ` [nfsacl v2 13/16] nfs mkdir cleanup Andreas Gruenbacher
@ 2005-02-27 17:00 ` Andreas Gruenbacher
2005-02-27 17:00 ` [nfsacl v2 15/16] ACL umask handling workaround in nfs client Andreas Gruenbacher
2005-02-27 17:00 ` [nfsacl v2 16/16] Cache acls on the nfs client side Andreas Gruenbacher
15 siblings, 0 replies; 21+ messages in thread
From: Andreas Gruenbacher @ 2005-02-27 17:00 UTC (permalink / raw)
To: linux-kernel, Neil Brown, Trond Myklebust
Cc: Olaf Kirch, Andries E. Brouwer, Andrew Morton
[-- Attachment #1: nfsacl-client-side-of-nfsacl.patch --]
[-- Type: text/plain, Size: 28128 bytes --]
This adds acl support fo nfs clients via the NFSACL protocol extension, by
implementing the getxattr, listxattr, setxattr, and removexattr iops for the
system.posix_acl_access and system.posix_acl_default attributes. This patch
implements a dumb version that uses no caching (and thus adds some overhead).
(Another patch in this patchset adds caching as well.)
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Acked-by: Olaf Kirch <okir@suse.de>
Index: linux-2.6.11-rc5/fs/Kconfig
===================================================================
--- linux-2.6.11-rc5.orig/fs/Kconfig
+++ linux-2.6.11-rc5/fs/Kconfig
@@ -1362,6 +1362,16 @@ config NFS_V3
If unsure, say Y.
+config NFS_ACL
+ bool "NFS_ACL protocol extension"
+ depends on NFS_V3
+ help
+ Implement the NFS_ACL protocol extension for manipulating POSIX
+ Access Control Lists. The server must also implement the NFS_ACL
+ protocol extension; see the CONFIG_NFSD_ACL option.
+
+ If unsure, say N.
+
config NFS_V4
bool "Provide NFSv4 client support (EXPERIMENTAL)"
depends on NFS_FS && EXPERIMENTAL
@@ -1405,6 +1415,7 @@ config NFSD
select LOCKD
select SUNRPC
select EXPORTFS
+ select NFS_ACL_SUPPORT if NFS_ACL
help
If you want your Linux box to act as an NFS *server*, so that other
computers on your local network which support NFS can access certain
Index: linux-2.6.11-rc5/fs/nfs/dir.c
===================================================================
--- linux-2.6.11-rc5.orig/fs/nfs/dir.c
+++ linux-2.6.11-rc5/fs/nfs/dir.c
@@ -74,6 +74,27 @@ struct inode_operations nfs_dir_inode_op
.setattr = nfs_setattr,
};
+#ifdef CONFIG_NFS_V3
+struct inode_operations nfs3_dir_inode_operations = {
+ .create = nfs_create,
+ .lookup = nfs_lookup,
+ .link = nfs_link,
+ .unlink = nfs_unlink,
+ .symlink = nfs_symlink,
+ .mkdir = nfs_mkdir,
+ .rmdir = nfs_rmdir,
+ .mknod = nfs_mknod,
+ .rename = nfs_rename,
+ .permission = nfs_permission,
+ .getattr = nfs_getattr,
+ .setattr = nfs_setattr,
+ .listxattr = nfs_listxattr,
+ .getxattr = nfs_getxattr,
+ .setxattr = nfs_setxattr,
+ .removexattr = nfs_removexattr,
+};
+#endif /* CONFIG_NFS_V3 */
+
#ifdef CONFIG_NFS_V4
static struct dentry *nfs_atomic_lookup(struct inode *, struct dentry *, struct nameidata *);
Index: linux-2.6.11-rc5/fs/nfs/file.c
===================================================================
--- linux-2.6.11-rc5.orig/fs/nfs/file.c
+++ linux-2.6.11-rc5/fs/nfs/file.c
@@ -67,6 +67,18 @@ struct inode_operations nfs_file_inode_o
.setattr = nfs_setattr,
};
+#ifdef CONFIG_NFS_V3
+struct inode_operations nfs3_file_inode_operations = {
+ .permission = nfs_permission,
+ .getattr = nfs_getattr,
+ .setattr = nfs_setattr,
+ .listxattr = nfs_listxattr,
+ .getxattr = nfs_getxattr,
+ .setxattr = nfs_setxattr,
+ .removexattr = nfs_removexattr,
+};
+#endif /* CONFIG_NFS_v3 */
+
/* Hack for future NFS swap support */
#ifndef IS_SWAPFILE
# define IS_SWAPFILE(inode) (0)
Index: linux-2.6.11-rc5/fs/nfs/inode.c
===================================================================
--- linux-2.6.11-rc5.orig/fs/nfs/inode.c
+++ linux-2.6.11-rc5/fs/nfs/inode.c
@@ -104,6 +104,21 @@ struct rpc_program nfs_program = {
.pipe_dir_name = "/nfs",
};
+#ifdef CONFIG_NFS_ACL
+static struct rpc_stat nfsacl_rpcstat = { &nfsacl_program };
+static struct rpc_version * nfsacl_version[] = {
+ [3] = &nfsacl_version3,
+};
+
+struct rpc_program nfsacl_program = {
+ .name = "nfsacl",
+ .number = NFS3_ACL_PROGRAM,
+ .nrvers = sizeof(nfsacl_version) / sizeof(nfsacl_version[0]),
+ .version = nfsacl_version,
+ .stats = &nfsacl_rpcstat,
+};
+#endif /* CONFIG_NFS_ACL */
+
static inline unsigned long
nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
{
@@ -165,6 +180,10 @@ nfs_umount_begin(struct super_block *sb)
/* -EIO all pending I/O */
if ((rpc = server->client) != NULL)
rpc_killall_tasks(rpc);
+#ifdef CONFIG_NFS_ACL
+ if ((rpc = server->client_acl) != NULL)
+ rpc_killall_tasks(rpc);
+#endif /* CONFIG_NFS_ACL */
}
@@ -453,7 +472,21 @@ nfs_fill_super(struct super_block *sb, s
atomic_inc(&server->client->cl_count);
server->client_sys = server->client;
}
+#ifdef CONFIG_NFS_ACL
+ if (server->flags & NFS_MOUNT_VER3) {
+ struct rpc_clnt *clnt = rpc_clone_client(server->client);
+ if (IS_ERR(clnt)) {
+ rpc_release_client(server->client_sys);
+ server->client_sys = NULL;
+ return PTR_ERR(clnt);
+ }
+ rpc_change_program(clnt, &nfsacl_program, 3);
+ server->client_acl = clnt;
+ /* Initially assume the nfsacl program is supported */
+ server->flags |= NFSACL;
+ }
+#endif
if (server->flags & NFS_MOUNT_VER3) {
if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
server->namelen = NFS3_MAXNAMLEN;
@@ -640,6 +673,18 @@ nfs_init_locked(struct inode *inode, voi
/* Don't use READDIRPLUS on directories that we believe are too large */
#define NFS_LIMIT_READDIRPLUS (8*PAGE_SIZE)
+#ifdef CONFIG_NFS_ACL
+struct inode_operations nfs3_special_inode_operations = {
+ .permission = nfs_permission,
+ .getattr = nfs_getattr,
+ .setattr = nfs_setattr,
+ .listxattr = nfs_listxattr,
+ .getxattr = nfs_getxattr,
+ .setxattr = nfs_setxattr,
+ .removexattr = nfs_removexattr,
+};
+#endif /* CONFIG_NFS_ACL */
+
/*
* This is our front-end to iget that looks up inodes by file handle
* instead of inode number.
@@ -680,7 +725,7 @@ nfs_fhget(struct super_block *sb, struct
/* Why so? Because we want revalidate for devices/FIFOs, and
* that's precisely what we have in nfs_file_inode_operations.
*/
- inode->i_op = &nfs_file_inode_operations;
+ inode->i_op = NFS_SB(sb)->rpc_ops->file_inode_ops;
if (S_ISREG(inode->i_mode)) {
inode->i_fop = &nfs_file_operations;
inode->i_data.a_ops = &nfs_file_aops;
@@ -693,8 +738,12 @@ nfs_fhget(struct super_block *sb, struct
NFS_FLAGS(inode) |= NFS_INO_ADVISE_RDPLUS;
} else if (S_ISLNK(inode->i_mode))
inode->i_op = &nfs_symlink_inode_operations;
- else
+ else {
+ if (NFS_SB(sb)->rpc_ops->special_inode_ops)
+ inode->i_op = NFS_SB(sb)->rpc_ops->
+ special_inode_ops;
init_special_inode(inode, inode->i_mode, fattr->rdev);
+ }
nfsi->read_cache_jiffies = fattr->timestamp;
inode->i_atime = fattr->atime;
@@ -1458,6 +1507,10 @@ static void nfs_kill_super(struct super_
rpc_shutdown_client(server->client);
if (server->client_sys != NULL && !IS_ERR(server->client_sys))
rpc_shutdown_client(server->client_sys);
+#ifdef CONFIG_NFS_ACL
+ if (server->client_acl != NULL && !IS_ERR(server->client_acl))
+ rpc_shutdown_client(server->client_acl);
+#endif
if (!(server->flags & NFS_MOUNT_NONLM))
lockd_down(); /* release rpc.lockd */
Index: linux-2.6.11-rc5/fs/nfs/Makefile
===================================================================
--- linux-2.6.11-rc5.orig/fs/nfs/Makefile
+++ linux-2.6.11-rc5/fs/nfs/Makefile
@@ -8,6 +8,7 @@ nfs-y := dir.o file.o inode.o nfs2xdr
proc.o read.o symlink.o unlink.o write.o
nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o
nfs-$(CONFIG_NFS_V3) += nfs3proc.o nfs3xdr.o
+nfs-$(CONFIG_NFS_ACL) += xattr.o
nfs-$(CONFIG_NFS_V4) += nfs4proc.o nfs4xdr.o nfs4state.o nfs4renewd.o \
delegation.o idmap.o \
callback.o callback_xdr.o callback_proc.o
Index: linux-2.6.11-rc5/fs/nfs/nfs3proc.c
===================================================================
--- linux-2.6.11-rc5.orig/fs/nfs/nfs3proc.c
+++ linux-2.6.11-rc5/fs/nfs/nfs3proc.c
@@ -17,6 +17,7 @@
#include <linux/nfs_page.h>
#include <linux/lockd/bind.h>
#include <linux/smp_lock.h>
+#include <linux/nfs_mount.h>
#define NFSDBG_FACILITY NFSDBG_PROC
@@ -45,7 +46,7 @@ static inline int
nfs3_rpc_call_wrapper(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags)
{
struct rpc_message msg = {
- .rpc_proc = &nfs3_procedures[proc],
+ .rpc_proc = &clnt->cl_procinfo[proc],
.rpc_argp = argp,
.rpc_resp = resp,
};
@@ -719,6 +720,214 @@ nfs3_proc_pathconf(struct nfs_server *se
return status;
}
+#ifdef CONFIG_NFS_ACL
+static struct posix_acl *
+nfs3_proc_getacl(struct inode *inode, int type)
+{
+ struct nfs_server *server = NFS_SERVER(inode);
+ struct nfs_fattr fattr;
+ struct page *pages[NFSACL_MAXPAGES] = { };
+ struct nfs3_getaclargs args = {
+ /* The xdr layer may allocate pages here. */
+ .pages = pages,
+ };
+ struct nfs3_getaclres res = {
+ .fattr = &fattr,
+ };
+ struct posix_acl *acl = NULL;
+ int status, count;
+
+ if (!(server->flags & NFSACL) || (server->flags & NFS_MOUNT_NOACL))
+ return ERR_PTR(-EOPNOTSUPP);
+
+ switch (type) {
+ case ACL_TYPE_ACCESS:
+ args.mask = NFS3_ACLCNT|NFS3_ACL;
+ break;
+
+ case ACL_TYPE_DEFAULT:
+ if (!S_ISDIR(inode->i_mode))
+ return NULL;
+ args.mask = NFS3_DFACLCNT|NFS3_DFACL;
+ break;
+
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+ args.fh = NFS_FH(inode);
+
+ dprintk("NFS call getacl\n");
+ status = rpc_call(server->client_acl, NFS3PROC_GETACL,
+ &args, &res, 0);
+ dprintk("NFS reply getacl: %d\n", status);
+
+ /* pages may have been allocated at the xdr layer. */
+ for (count = 0; count < NFSACL_MAXPAGES && args.pages[count]; count++)
+ __free_page(args.pages[count]);
+
+ if (status) {
+ if (status == -ENOSYS || status == -EOPNOTSUPP) {
+ dprintk("NFS_ACL extension not supported; disabling\n");
+ server->flags &= ~NFSACL;
+ status = -EOPNOTSUPP;
+ } else if (status == -ENOTSUPP)
+ status = -EOPNOTSUPP;
+ goto getout;
+ }
+ if ((args.mask & res.mask) != args.mask) {
+ status = -EIO;
+ goto getout;
+ }
+
+ status = nfs_refresh_inode(inode, &fattr);
+ if (res.acl_access) {
+ if (posix_acl_equiv_mode(res.acl_access, NULL) == 0) {
+ posix_acl_release(res.acl_access);
+ res.acl_access = NULL;
+ }
+ }
+
+ switch(type) {
+ case ACL_TYPE_ACCESS:
+ acl = res.acl_access;
+ res.acl_access = NULL;
+ break;
+
+ case ACL_TYPE_DEFAULT:
+ acl = res.acl_default;
+ res.acl_default = NULL;
+ break;
+ }
+
+getout:
+ posix_acl_release(res.acl_access);
+ posix_acl_release(res.acl_default);
+
+ if (status) {
+ posix_acl_release(acl);
+ acl = ERR_PTR(status);
+ }
+ return acl;
+}
+#endif /* CONFIG_NFS_ACL */
+
+#ifdef CONFIG_NFS_ACL
+static int
+nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
+ struct posix_acl *dfacl)
+{
+ struct nfs_server *server = NFS_SERVER(inode);
+ struct nfs_fattr fattr;
+ struct page *pages[NFSACL_MAXPAGES] = { };
+ struct nfs3_setaclargs args = {
+ .pages = pages,
+ };
+ int status, count;
+
+ if (!(server->flags & NFSACL) || (server->flags & NFS_MOUNT_NOACL))
+ return -EOPNOTSUPP;
+
+ /* We are doing this here, because XDR marshalling can only
+ return -ENOMEM. */
+ if (acl && acl->a_count > NFS3_ACL_MAX_ENTRIES)
+ return -ENOSPC;
+ if (dfacl && dfacl->a_count > NFS3_ACL_MAX_ENTRIES)
+ return -ENOSPC;
+ args.inode = inode;
+ args.mask = NFS3_ACL;
+ args.acl_access = acl;
+ if (S_ISDIR(inode->i_mode)) {
+ args.mask |= NFS3_DFACL;
+ args.acl_default = dfacl;
+ }
+
+ dprintk("NFS call setacl\n");
+ status = rpc_call(server->client_acl, NFS3PROC_SETACL,
+ &args, &fattr, 0);
+ dprintk("NFS reply setacl: %d\n", status);
+
+ /* pages may have been allocated at the xdr layer. */
+ for (count = 0; count < NFSACL_MAXPAGES && args.pages[count]; count++)
+ __free_page(args.pages[count]);
+
+ if (status) {
+ if (status == -ENOSYS || status == -EOPNOTSUPP) {
+ dprintk("NFS_ACL SETACL RPC not supported"
+ "(will not retry)\n");
+ server->flags &= ~NFSACL;
+ status = -EOPNOTSUPP;
+ } else if (status == -ENOTSUPP)
+ status = -EOPNOTSUPP;
+ } else {
+ NFS_FLAGS(inode) |= NFS_INO_INVALID_ACCESS;
+ if (acl) {
+ /*
+ * Updating the access acl modifies the file mode
+ * mode permission bits, so update the icache.
+ */
+ mode_t mode = inode->i_mode;
+ int error = posix_acl_equiv_mode(acl, &mode);
+ if (error >= 0)
+ inode->i_mode = mode;
+ if (error == 0) {
+ /*
+ * The acl is equivalent to the file mode
+ * permission bits. No need to cache it.
+ */
+ acl = NULL;
+ }
+ }
+ status = nfs_refresh_inode(inode, &fattr);
+ }
+
+ return status;
+}
+#endif /* CONFIG_NFS_ACL */
+
+#ifdef CONFIG_NFS_ACL
+static int
+nfs3_proc_setacl(struct inode *inode, int type, struct posix_acl *acl)
+{
+ struct posix_acl *alloc = NULL, *dfacl = NULL;
+ int status;
+
+ if (S_ISDIR(inode->i_mode)) {
+ switch(type) {
+ case ACL_TYPE_ACCESS:
+ alloc = dfacl = NFS_PROTO(inode)->
+ getacl(inode, ACL_TYPE_DEFAULT);
+ if (IS_ERR(alloc))
+ goto fail;
+ break;
+
+ case ACL_TYPE_DEFAULT:
+ dfacl = acl;
+ alloc = acl = NFS_PROTO(inode)->
+ getacl(inode, ACL_TYPE_ACCESS);
+ if (IS_ERR(alloc))
+ goto fail;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ } else if (type != ACL_TYPE_ACCESS)
+ return -EINVAL;
+
+ if (acl == NULL) {
+ alloc = acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
+ if (IS_ERR(alloc))
+ goto fail;
+ }
+ status = nfs3_proc_setacls(inode, acl, dfacl);
+ posix_acl_release(alloc);
+ return status;
+
+fail:
+ return PTR_ERR(alloc);
+}
+#endif /* CONFIG_NFS_ACL */
+
extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int);
static void
@@ -842,7 +1051,9 @@ nfs3_proc_lock(struct file *filp, int cm
struct nfs_rpc_ops nfs_v3_clientops = {
.version = 3, /* protocol version */
.dentry_ops = &nfs_dentry_operations,
- .dir_inode_ops = &nfs_dir_inode_operations,
+ .file_inode_ops = &nfs3_file_inode_operations,
+ .dir_inode_ops = &nfs3_dir_inode_operations,
+ .special_inode_ops = &nfs3_special_inode_operations,
.getroot = nfs3_proc_get_root,
.getattr = nfs3_proc_getattr,
.setattr = nfs3_proc_setattr,
@@ -873,4 +1084,9 @@ struct nfs_rpc_ops nfs_v3_clientops = {
.file_open = nfs_open,
.file_release = nfs_release,
.lock = nfs3_proc_lock,
+#ifdef CONFIG_NFS_ACL
+ .getacl = nfs3_proc_getacl,
+ .setacl = nfs3_proc_setacl,
+ .setacls = nfs3_proc_setacls,
+#endif /* CONFIG_NFS_ACL */
};
Index: linux-2.6.11-rc5/fs/nfs/nfs3xdr.c
===================================================================
--- linux-2.6.11-rc5.orig/fs/nfs/nfs3xdr.c
+++ linux-2.6.11-rc5/fs/nfs/nfs3xdr.c
@@ -21,6 +21,7 @@
#include <linux/nfs.h>
#include <linux/nfs3.h>
#include <linux/nfs_fs.h>
+#include <linux/nfsacl.h>
#define NFSDBG_FACILITY NFSDBG_XDR
@@ -62,6 +63,8 @@ extern int nfs_stat_to_errno(int);
#define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz)
#define NFS3_readdirargs_sz (NFS3_fh_sz+2)
#define NFS3_commitargs_sz (NFS3_fh_sz+3)
+#define NFS3_getaclargs_sz (NFS3_fh_sz+1)
+#define NFS3_setaclargs_sz (NFS3_fh_sz+1+2*(2+5*3))
#define NFS3_attrstat_sz (1+NFS3_fattr_sz)
#define NFS3_wccstat_sz (1+NFS3_wcc_data_sz)
@@ -78,6 +81,8 @@ extern int nfs_stat_to_errno(int);
#define NFS3_fsinfores_sz (1+NFS3_post_op_attr_sz+12)
#define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6)
#define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2)
+#define NFS3_getaclres_sz (1+NFS3_post_op_attr_sz+1+2*(2+5*3))
+#define NFS3_setaclres_sz (1+NFS3_post_op_attr_sz)
/*
* Map file type to S_IFMT bits
@@ -627,6 +632,76 @@ nfs3_xdr_commitargs(struct rpc_rqst *req
return 0;
}
+#ifdef CONFIG_NFS_ACL
+/*
+ * Encode GETACL arguments
+ */
+static int
+nfs3_xdr_getaclargs(struct rpc_rqst *req, u32 *p,
+ struct nfs3_getaclargs *args)
+{
+ struct rpc_auth *auth = req->rq_task->tk_auth;
+ unsigned int replen;
+
+ p = xdr_encode_fhandle(p, args->fh);
+ *p++ = htonl(args->mask);
+ req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+
+ if (args->mask & (NFS3_ACL | NFS3_DFACL)) {
+ /* Inline the page array */
+ replen = (RPC_REPHDRSIZE + auth->au_rslack +
+ NFS3_getaclres_sz) << 2;
+ xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0,
+ NFSACL_MAXPAGES << PAGE_SHIFT);
+ }
+ return 0;
+}
+#endif /* CONFIG_NFS_ACL */
+
+#ifdef CONFIG_NFS_ACL
+/*
+ * Encode SETACL arguments
+ */
+static int
+nfs3_xdr_setaclargs(struct rpc_rqst *req, u32 *p,
+ struct nfs3_setaclargs *args)
+{
+ struct xdr_buf *buf = &req->rq_snd_buf;
+ unsigned int base, len_in_head, len = nfsacl_size(
+ (args->mask & NFS3_ACL) ? args->acl_access : NULL,
+ (args->mask & NFS3_DFACL) ? args->acl_default : NULL);
+ int count, err;
+
+ p = xdr_encode_fhandle(p, NFS_FH(args->inode));
+ *p++ = htonl(args->mask);
+ base = (char *)p - (char *)buf->head->iov_base;
+ /* put as much of the acls into head as possible. */
+ len_in_head = min_t(unsigned int, buf->head->iov_len - base, len);
+ len -= len_in_head;
+ req->rq_slen = xdr_adjust_iovec(req->rq_svec, p + len_in_head);
+
+ for (count = 0; (count << PAGE_SHIFT) < len; count++) {
+ args->pages[count] = alloc_page(GFP_KERNEL);
+ if (!args->pages[count]) {
+ while (count)
+ __free_page(args->pages[--count]);
+ return -ENOMEM;
+ }
+ }
+ xdr_encode_pages(buf, args->pages, 0, len);
+
+ err = nfsacl_encode(buf, base, args->inode,
+ (args->mask & NFS3_ACL) ?
+ args->acl_access : NULL, 1, 0);
+ if (err > 0)
+ err = nfsacl_encode(buf, base + err, args->inode,
+ (args->mask & NFS3_DFACL) ?
+ args->acl_default : NULL, 1,
+ NFS3_ACL_DEFAULT);
+ return (err > 0) ? 0 : err;
+}
+#endif /* CONFIG_NFS_ACL */
+
/*
* NFS XDR decode functions
*/
@@ -978,6 +1053,56 @@ nfs3_xdr_commitres(struct rpc_rqst *req,
return 0;
}
+#ifdef CONFIG_NFS_ACL
+/*
+ * Decode GETACL reply
+ */
+static int
+nfs3_xdr_getaclres(struct rpc_rqst *req, u32 *p,
+ struct nfs3_getaclres *res)
+{
+ struct xdr_buf *buf = &req->rq_rcv_buf;
+ int status = ntohl(*p++);
+ struct posix_acl **acl;
+ unsigned int *aclcnt;
+ int err, base;
+
+ if (status != 0)
+ return -nfs_stat_to_errno(status);
+ p = xdr_decode_post_op_attr(p, res->fattr);
+ res->mask = ntohl(*p++);
+ if (res->mask & ~(NFS3_ACL|NFS3_ACLCNT|NFS3_DFACL|NFS3_DFACLCNT))
+ return -EINVAL;
+ base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base;
+
+ acl = (res->mask & NFS3_ACL) ? &res->acl_access : NULL;
+ aclcnt = (res->mask & NFS3_ACLCNT) ? &res->acl_access_count : NULL;
+ err = nfsacl_decode(buf, base, aclcnt, acl);
+
+ acl = (res->mask & NFS3_DFACL) ? &res->acl_default : NULL;
+ aclcnt = (res->mask & NFS3_DFACLCNT) ? &res->acl_default_count : NULL;
+ if (err > 0)
+ err = nfsacl_decode(buf, base + err, aclcnt, acl);
+ return (err > 0) ? 0 : err;
+}
+#endif /* CONFIG_NFS_ACL */
+
+#ifdef CONFIG_NFS_ACL
+/*
+ * Decode setacl reply.
+ */
+static int
+nfs3_xdr_setaclres(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
+{
+ int status = ntohl(*p++);
+
+ if (status)
+ return -nfs_stat_to_errno(status);
+ xdr_decode_post_op_attr(p, fattr);
+ return 0;
+}
+#endif /* CONFIG_NFS_ACL */
+
#ifndef MAX
# define MAX(a, b) (((a) > (b))? (a) : (b))
#endif
@@ -1021,3 +1146,16 @@ struct rpc_version nfs_version3 = {
.procs = nfs3_procedures
};
+#ifdef CONFIG_NFS_ACL
+static struct rpc_procinfo nfs3_acl_procedures[] = {
+ PROC(GETACL, getaclargs, getaclres, 1),
+ PROC(SETACL, setaclargs, setaclres, 0),
+};
+
+struct rpc_version nfsacl_version3 = {
+ .number = 3,
+ .nrprocs = sizeof(nfs3_acl_procedures)/
+ sizeof(nfs3_acl_procedures[0]),
+ .procs = nfs3_acl_procedures,
+};
+#endif /* CONFIG_NFS_ACL */
Index: linux-2.6.11-rc5/fs/nfs/xattr.c
===================================================================
--- /dev/null
+++ linux-2.6.11-rc5/fs/nfs/xattr.c
@@ -0,0 +1,114 @@
+#include <linux/fs.h>
+#include <linux/nfs.h>
+#include <linux/nfs3.h>
+#include <linux/nfs_fs.h>
+#include <linux/xattr_acl.h>
+
+ssize_t
+nfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
+{
+ struct inode *inode = dentry->d_inode;
+ struct posix_acl *acl;
+ int pos=0, len=0;
+
+# define output(s) do { \
+ if (pos + sizeof(s) <= size) { \
+ memcpy(buffer + pos, s, sizeof(s)); \
+ pos += sizeof(s); \
+ } \
+ len += sizeof(s); \
+ } while(0)
+
+ acl = NFS_PROTO(inode)->getacl(inode, ACL_TYPE_ACCESS);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+ if (acl) {
+ output("system.posix_acl_access");
+ posix_acl_release(acl);
+ }
+
+ if (S_ISDIR(inode->i_mode)) {
+ acl = NFS_PROTO(inode)->getacl(inode, ACL_TYPE_DEFAULT);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+ if (acl) {
+ output("system.posix_acl_default");
+ posix_acl_release(acl);
+ }
+ }
+
+# undef output
+
+ if (!buffer || len <= size)
+ return len;
+ return -ERANGE;
+}
+
+ssize_t
+nfs_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size)
+{
+ struct inode *inode = dentry->d_inode;
+ struct posix_acl *acl;
+ int type, error = 0;
+
+ if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0)
+ type = ACL_TYPE_ACCESS;
+ else if (strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0)
+ type = ACL_TYPE_DEFAULT;
+ else
+ return -EOPNOTSUPP;
+
+ acl = NFS_PROTO(inode)->getacl(inode, type);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+ else if (acl) {
+ if (type == ACL_TYPE_ACCESS && acl->a_count == 0)
+ error = -ENODATA;
+ else
+ error = posix_acl_to_xattr(acl, buffer, size);
+ posix_acl_release(acl);
+ } else
+ error = -ENODATA;
+
+ return error;
+}
+
+int
+nfs_setxattr(struct dentry *dentry, const char *name,
+ const void *value, size_t size, int flags)
+{
+ struct inode *inode = dentry->d_inode;
+ struct posix_acl *acl;
+ int type, error;
+
+ if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0)
+ type = ACL_TYPE_ACCESS;
+ else if (strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0)
+ type = ACL_TYPE_DEFAULT;
+ else
+ return -EOPNOTSUPP;
+
+ acl = posix_acl_from_xattr(value, size);
+ if (IS_ERR(acl))
+ return PTR_ERR(acl);
+ error = NFS_PROTO(inode)->setacl(inode, type, acl);
+ posix_acl_release(acl);
+
+ return error;
+}
+
+int
+nfs_removexattr(struct dentry *dentry, const char *name)
+{
+ struct inode *inode = dentry->d_inode;
+ int type;
+
+ if (strcmp(name, XATTR_NAME_ACL_ACCESS) == 0)
+ type = ACL_TYPE_ACCESS;
+ else if (strcmp(name, XATTR_NAME_ACL_DEFAULT) == 0)
+ type = ACL_TYPE_DEFAULT;
+ else
+ return -EOPNOTSUPP;
+
+ return NFS_PROTO(inode)->setacl(inode, type, NULL);
+}
Index: linux-2.6.11-rc5/include/linux/nfs_fs.h
===================================================================
--- linux-2.6.11-rc5.orig/include/linux/nfs_fs.h
+++ linux-2.6.11-rc5/include/linux/nfs_fs.h
@@ -281,6 +281,8 @@ static inline int nfs_verify_change_attr
/*
* linux/fs/nfs/inode.c
*/
+extern struct inode_operations nfs3_special_inode_operations;
+
extern void nfs_zap_caches(struct inode *);
extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *,
struct nfs_fattr *);
@@ -314,6 +316,7 @@ extern u32 root_nfs_parse_addr(char *nam
* linux/fs/nfs/file.c
*/
extern struct inode_operations nfs_file_inode_operations;
+extern struct inode_operations nfs3_file_inode_operations;
extern struct file_operations nfs_file_operations;
extern struct address_space_operations nfs_file_aops;
@@ -329,6 +332,22 @@ static inline struct rpc_cred *nfs_file_
}
/*
+ * linux/fs/nfs/xattr.c
+ */
+#ifdef CONFIG_NFS_ACL
+extern ssize_t nfs_listxattr(struct dentry *, char *, size_t);
+extern ssize_t nfs_getxattr(struct dentry *, const char *, void *, size_t);
+extern int nfs_setxattr(struct dentry *, const char *,
+ const void *, size_t, int);
+extern int nfs_removexattr (struct dentry *, const char *name);
+#else
+# define nfs_listxattr NULL
+# define nfs_getxattr NULL
+# define nfs_setxattr NULL
+# define nfs_removexattr NULL
+#endif
+
+/*
* linux/fs/nfs/direct.c
*/
extern ssize_t nfs_direct_IO(int, struct kiocb *, const struct iovec *, loff_t,
@@ -342,6 +361,7 @@ extern ssize_t nfs_file_direct_write(str
* linux/fs/nfs/dir.c
*/
extern struct inode_operations nfs_dir_inode_operations;
+extern struct inode_operations nfs3_dir_inode_operations;
extern struct file_operations nfs_dir_operations;
extern struct dentry_operations nfs_dentry_operations;
Index: linux-2.6.11-rc5/include/linux/nfs_fs_sb.h
===================================================================
--- linux-2.6.11-rc5.orig/include/linux/nfs_fs_sb.h
+++ linux-2.6.11-rc5/include/linux/nfs_fs_sb.h
@@ -10,6 +10,9 @@
struct nfs_server {
struct rpc_clnt * client; /* RPC client handle */
struct rpc_clnt * client_sys; /* 2nd handle for FSINFO */
+#ifdef CONFIG_NFS_ACL
+ struct rpc_clnt * client_acl; /* ACL RPC client handle */
+#endif /* CONFIG_NFS_ACL */
struct nfs_rpc_ops * rpc_ops; /* NFS protocol vector */
struct backing_dev_info backing_dev_info;
int flags; /* various flags */
Index: linux-2.6.11-rc5/include/linux/nfs_mount.h
===================================================================
--- linux-2.6.11-rc5.orig/include/linux/nfs_mount.h
+++ linux-2.6.11-rc5/include/linux/nfs_mount.h
@@ -63,4 +63,7 @@ struct nfs_mount_data {
#define NFS_MOUNT_SECFLAVOUR 0x2000 /* 5 */
#define NFS_MOUNT_FLAGMASK 0xFFFF
+/* Feature flag for the NFS_ACL protocol extension */
+#define NFSACL 0x10000
+
#endif
Index: linux-2.6.11-rc5/include/linux/nfs_xdr.h
===================================================================
--- linux-2.6.11-rc5.orig/include/linux/nfs_xdr.h
+++ linux-2.6.11-rc5/include/linux/nfs_xdr.h
@@ -2,6 +2,7 @@
#define _LINUX_NFS_XDR_H
#include <linux/sunrpc/xprt.h>
+#include <linux/nfsacl.h>
struct nfs4_fsid {
__u64 major;
@@ -354,6 +355,20 @@ struct nfs_readdirargs {
struct page ** pages;
};
+struct nfs3_getaclargs {
+ struct nfs_fh * fh;
+ int mask;
+ struct page ** pages;
+};
+
+struct nfs3_setaclargs {
+ struct inode * inode;
+ int mask;
+ struct posix_acl * acl_access;
+ struct posix_acl * acl_default;
+ struct page ** pages;
+};
+
struct nfs_diropok {
struct nfs_fh * fh;
struct nfs_fattr * fattr;
@@ -477,6 +492,15 @@ struct nfs3_readdirres {
int plus;
};
+struct nfs3_getaclres {
+ struct nfs_fattr * fattr;
+ int mask;
+ unsigned int acl_access_count;
+ unsigned int acl_default_count;
+ struct posix_acl * acl_access;
+ struct posix_acl * acl_default;
+};
+
#ifdef CONFIG_NFS_V4
typedef u64 clientid4;
@@ -665,7 +689,9 @@ struct nfs_access_entry;
struct nfs_rpc_ops {
int version; /* Protocol version */
struct dentry_operations *dentry_ops;
+ struct inode_operations *file_inode_ops;
struct inode_operations *dir_inode_ops;
+ struct inode_operations *special_inode_ops;
int (*getroot) (struct nfs_server *, struct nfs_fh *,
struct nfs_fsinfo *);
@@ -712,6 +738,11 @@ struct nfs_rpc_ops {
int (*file_open) (struct inode *, struct file *);
int (*file_release) (struct inode *, struct file *);
int (*lock)(struct file *, int, struct file_lock *);
+#ifdef CONFIG_NFS_ACL
+ struct posix_acl * (*getacl)(struct inode *, int);
+ int (*setacl)(struct inode *, int, struct posix_acl *);
+ int (*setacls)(struct inode *, struct posix_acl *, struct posix_acl *);
+#endif /* CONFIG_NFS_ACL */
};
/*
@@ -733,4 +764,7 @@ extern struct rpc_version nfs_version4;
extern struct rpc_program nfs_program;
extern struct rpc_stat nfs_rpcstat;
+extern struct rpc_version nfsacl_version3;
+extern struct rpc_program nfsacl_program;
+
#endif
Index: linux-2.6.11-rc5/fs/nfs/nfs4proc.c
===================================================================
--- linux-2.6.11-rc5.orig/fs/nfs/nfs4proc.c
+++ linux-2.6.11-rc5/fs/nfs/nfs4proc.c
@@ -2579,6 +2579,7 @@ nfs4_proc_lock(struct file *filp, int cm
struct nfs_rpc_ops nfs_v4_clientops = {
.version = 4, /* protocol version */
.dentry_ops = &nfs4_dentry_operations,
+ .file_inode_ops = &nfs_file_inode_operations,
.dir_inode_ops = &nfs4_dir_inode_operations,
.getroot = nfs4_proc_get_root,
.getattr = nfs4_proc_getattr,
Index: linux-2.6.11-rc5/fs/nfs/proc.c
===================================================================
--- linux-2.6.11-rc5.orig/fs/nfs/proc.c
+++ linux-2.6.11-rc5/fs/nfs/proc.c
@@ -626,6 +626,7 @@ nfs_proc_lock(struct file *filp, int cmd
struct nfs_rpc_ops nfs_v2_clientops = {
.version = 2, /* protocol version */
.dentry_ops = &nfs_dentry_operations,
+ .file_inode_ops = &nfs_file_inode_operations,
.dir_inode_ops = &nfs_dir_inode_operations,
.getroot = nfs_proc_get_root,
.getattr = nfs_proc_getattr,
--
Andreas Gruenbacher <agruen@suse.de>
SUSE Labs, SUSE LINUX PRODUCTS GMBH
^ permalink raw reply [flat|nested] 21+ messages in thread
* [nfsacl v2 15/16] ACL umask handling workaround in nfs client
2005-02-27 16:59 [nfsacl v2 00/16] NFSACL protocol extension for NFSv3 Andreas Gruenbacher
` (13 preceding siblings ...)
2005-02-27 17:00 ` [nfsacl v2 14/16] Client side of nfsacl Andreas Gruenbacher
@ 2005-02-27 17:00 ` Andreas Gruenbacher
2005-03-02 15:49 ` Andreas Gruenbacher
2005-02-27 17:00 ` [nfsacl v2 16/16] Cache acls on the nfs client side Andreas Gruenbacher
15 siblings, 1 reply; 21+ messages in thread
From: Andreas Gruenbacher @ 2005-02-27 17:00 UTC (permalink / raw)
To: linux-kernel, Neil Brown, Trond Myklebust
Cc: Olaf Kirch, Andries E. Brouwer, Andrew Morton
[-- Attachment #1: nfsacl-acl-umask-handling-workaround-in-nfs-client-2.patch --]
[-- Type: text/plain, Size: 4697 bytes --]
NFSv3 has no concept of a umask on the server side: The client applies
the umask locally, and sends the effective permissions to the server.
This behavior is wrong when files are created in a directory that has a
default ACL. In this case, the umask is supposed to be ignored, and
only the default ACL determines the file's effective permissions.
Usually its the server's task to conditionally apply the umask. But
since the server knows nothing about the umask, we have to do it on the
client side. This patch tries to fetch the parent directory's default
ACL before creating a new file, computes the appropriate create mode to
send to the server, and finally sets the new file's access and default
acl appropriately.
Many thanks to Buck Huppmann <buchk@pobox.com> for sending the initial
version of this patch, as well as for arguing why we need this change.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Acked-by: Olaf Kirch <okir@suse.de>
Index: linux-2.6.11-rc5/fs/nfs/nfs3proc.c
===================================================================
--- linux-2.6.11-rc5.orig/fs/nfs/nfs3proc.c
+++ linux-2.6.11-rc5/fs/nfs/nfs3proc.c
@@ -292,6 +292,38 @@ static int nfs3_proc_commit(struct nfs_w
return status;
}
+static int nfs3_set_default_acl(struct inode *dir, struct inode *inode,
+ mode_t mode)
+{
+#ifdef CONFIG_NFS_ACL
+ struct posix_acl *dfacl, *acl;
+ int error = 0;
+
+ dfacl = NFS_PROTO(dir)->getacl(dir, ACL_TYPE_DEFAULT);
+ if (IS_ERR(dfacl)) {
+ error = PTR_ERR(dfacl);
+ return (error == -EOPNOTSUPP) ? 0 : error;
+ }
+ if (!dfacl)
+ return 0;
+ acl = posix_acl_clone(dfacl, GFP_KERNEL);
+ error = -ENOMEM;
+ if (!acl)
+ goto out;
+ error = posix_acl_create_masq(acl, &mode);
+ if (error < 0)
+ goto out;
+ error = NFS_PROTO(inode)->setacls(inode, acl, S_ISDIR(inode->i_mode) ?
+ dfacl : NULL);
+out:
+ posix_acl_release(acl);
+ posix_acl_release(dfacl);
+ return error;
+#else
+ return 0;
+#endif
+}
+
/*
* Create a regular file.
* For now, we don't implement O_EXCL.
@@ -314,8 +346,12 @@ nfs3_proc_create(struct inode *dir, stru
.fh = &fhandle,
.fattr = &fattr
};
+ mode_t mode;
int status;
+ mode = sattr->ia_mode;
+ sattr->ia_mode &= ~current->fs->umask;
+
dprintk("NFS call create %s\n", dentry->d_name.name);
arg.createmode = NFS3_CREATE_UNCHECKED;
if (flags & O_EXCL) {
@@ -350,7 +386,6 @@ again:
exit:
dprintk("NFS reply create: %d\n", status);
-
if (status != 0)
goto out;
if (fhandle.size == 0 || !(fattr.valid & NFS_ATTR_FATTR)) {
@@ -384,9 +419,10 @@ exit:
if (status == 0) {
struct inode *inode;
inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
- if (inode)
- return inode;
status = -ENOMEM;
+ if (!inode)
+ goto out;
+ status = nfs3_set_default_acl(dir, inode, mode);
}
out:
return ERR_PTR(status);
@@ -556,8 +592,12 @@ nfs3_proc_mkdir(struct inode *dir, struc
.fh = &fh,
.fattr = &fattr
};
+ mode_t mode;
int status;
+ mode = sattr->ia_mode;
+ sattr->ia_mode &= ~current->fs->umask;
+
dprintk("NFS call mkdir %s\n", dentry->d_name.name);
dir_attr.valid = 0;
fattr.valid = 0;
@@ -566,6 +606,8 @@ nfs3_proc_mkdir(struct inode *dir, struc
if (!status)
status = nfs_instantiate(dentry, &fh, &fattr);
dprintk("NFS reply mkdir: %d\n", status);
+ if (!status)
+ status = nfs3_set_default_acl(dir, dentry->d_inode, mode);
return status;
}
@@ -659,6 +701,7 @@ nfs3_proc_mknod(struct inode *dir, struc
.fh = &fh,
.fattr = &fattr
};
+ mode_t mode;
int status;
switch (sattr->ia_mode & S_IFMT) {
@@ -669,6 +712,9 @@ nfs3_proc_mknod(struct inode *dir, struc
default: return -EINVAL;
}
+ mode = sattr->ia_mode;
+ sattr->ia_mode &= ~current->fs->umask;
+
dprintk("NFS call mknod %s %u:%u\n", dentry->d_name.name,
MAJOR(rdev), MINOR(rdev));
dir_attr.valid = 0;
@@ -678,6 +724,8 @@ nfs3_proc_mknod(struct inode *dir, struc
if (!status)
status = nfs_instantiate(dentry, &fh, &fattr);
dprintk("NFS reply mknod: %d\n", status);
+ if (!status)
+ status = nfs3_set_default_acl(dir, dentry->d_inode, mode);
return status;
}
Index: linux-2.6.11-rc5/fs/nfs/inode.c
===================================================================
--- linux-2.6.11-rc5.orig/fs/nfs/inode.c
+++ linux-2.6.11-rc5/fs/nfs/inode.c
@@ -485,6 +485,8 @@ nfs_fill_super(struct super_block *sb, s
server->client_acl = clnt;
/* Initially assume the nfsacl program is supported */
server->flags |= NFSACL;
+ /* The nfs client applies the umask itself when needed. */
+ sb->s_flags |= MS_POSIXACL;
}
#endif
if (server->flags & NFS_MOUNT_VER3) {
--
Andreas Gruenbacher <agruen@suse.de>
SUSE Labs, SUSE LINUX PRODUCTS GMBH
^ permalink raw reply [flat|nested] 21+ messages in thread
* [nfsacl v2 16/16] Cache acls on the nfs client side
2005-02-27 16:59 [nfsacl v2 00/16] NFSACL protocol extension for NFSv3 Andreas Gruenbacher
` (14 preceding siblings ...)
2005-02-27 17:00 ` [nfsacl v2 15/16] ACL umask handling workaround in nfs client Andreas Gruenbacher
@ 2005-02-27 17:00 ` Andreas Gruenbacher
15 siblings, 0 replies; 21+ messages in thread
From: Andreas Gruenbacher @ 2005-02-27 17:00 UTC (permalink / raw)
To: linux-kernel, Neil Brown, Trond Myklebust
Cc: Olaf Kirch, Andries E. Brouwer, Andrew Morton
[-- Attachment #1: nfsacl-cache-acls-on-the-nfs-client-side.patch --]
[-- Type: text/plain, Size: 8087 bytes --]
Attach acls to inodes in the icache to avoid unnecessary GETACL RPC
round-trips. As long as the client doesn't retrieve any acls itself, only the
default acls of exiting directories and the default and access acls of new
directories will end up in the cache, which preserves some memory compared to
always caching the access and default acl of all files.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Acked-by: Olaf Kirch <okir@suse.de>
Index: linux-2.6.11-rc5/fs/nfs/inode.c
===================================================================
--- linux-2.6.11-rc5.orig/fs/nfs/inode.c
+++ linux-2.6.11-rc5/fs/nfs/inode.c
@@ -64,6 +64,19 @@ static void nfs_umount_begin(struct supe
static int nfs_statfs(struct super_block *, struct kstatfs *);
static int nfs_show_options(struct seq_file *, struct vfsmount *);
+#ifdef CONFIG_NFS_ACL
+static void nfs_forget_cached_acls(struct inode *);
+static void __nfs_forget_cached_acls(struct nfs_inode *nfsi);
+#else
+static inline void nfs_forget_cached_acls(struct inode *inode)
+{
+}
+
+static inline void __nfs_forget_cached_acls(struct nfs_inode *nfsi)
+{
+}
+#endif
+
static struct super_operations nfs_sops = {
.alloc_inode = nfs_alloc_inode,
.destroy_inode = nfs_destroy_inode,
@@ -619,6 +632,7 @@ nfs_zap_caches(struct inode *inode)
nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA|NFS_INO_INVALID_ACCESS;
else
nfsi->flags |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS;
+ nfs_forget_cached_acls(inode);
}
/*
@@ -1161,6 +1175,81 @@ void nfs_end_data_update_defer(struct in
}
}
+#ifdef CONFIG_NFS_ACL
+static void __nfs_forget_cached_acls(struct nfs_inode *nfsi)
+{
+ if (nfsi->acl_access != ERR_PTR(-EAGAIN)) {
+ posix_acl_release(nfsi->acl_access);
+ nfsi->acl_access = ERR_PTR(-EAGAIN);
+ }
+ if (nfsi->acl_default != ERR_PTR(-EAGAIN)) {
+ posix_acl_release(nfsi->acl_default);
+ nfsi->acl_default = ERR_PTR(-EAGAIN);
+ }
+}
+#endif /* CONFIG_NFS_ACL */
+
+#ifdef CONFIG_NFS_ACL
+static void nfs_forget_cached_acls(struct inode *inode)
+{
+ dprintk("NFS: nfs_forget_cached_acls(%s/%ld)\n", inode->i_sb->s_id,
+ inode->i_ino);
+ spin_lock(&inode->i_lock);
+ __nfs_forget_cached_acls(NFS_I(inode));
+ spin_unlock(&inode->i_lock);
+}
+#endif
+
+#ifdef CONFIG_NFS_ACL
+struct posix_acl *nfs_get_cached_acl(struct inode *inode, int type)
+{
+ struct nfs_inode *nfsi = NFS_I(inode);
+ struct posix_acl *acl = ERR_PTR(-EAGAIN);
+
+ spin_lock(&inode->i_lock);
+ if (time_after(jiffies, nfsi->acl_timestamp + nfsi->attrtimeo)) {
+ __nfs_forget_cached_acls(nfsi);
+ nfsi->acl_timestamp = jiffies;
+ } else switch(type) {
+ case ACL_TYPE_ACCESS:
+ acl = nfsi->acl_access;
+ break;
+
+ case ACL_TYPE_DEFAULT:
+ acl = nfsi->acl_default;
+ break;
+
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+ if (acl == ERR_PTR(-EAGAIN))
+ acl = ERR_PTR(-EAGAIN);
+ else
+ acl = posix_acl_dup(acl);
+ spin_unlock(&inode->i_lock);
+ dprintk("NFS: nfs_get_cached_acl(%s/%ld, %d) = %p\n", inode->i_sb->s_id,
+ inode->i_ino, type, acl);
+ return acl;
+}
+#endif /* CONFIG_NFS_ACL */
+
+#ifdef CONFIG_NFS_ACL
+void nfs_cache_acls(struct inode *inode, struct posix_acl *acl,
+ struct posix_acl *dfacl)
+{
+ struct nfs_inode *nfsi = NFS_I(inode);
+
+ dprintk("nfs_cache_acls(%s/%ld, %p, %p)\n", inode->i_sb->s_id,
+ inode->i_ino, acl, dfacl);
+ spin_lock(&inode->i_lock);
+ __nfs_forget_cached_acls(NFS_I(inode));
+ nfsi->acl_access = posix_acl_dup(acl);
+ nfsi->acl_default = posix_acl_dup(dfacl);
+ nfsi->acl_timestamp = jiffies;
+ spin_unlock(&inode->i_lock);
+}
+#endif /* CONFIG_NFS_ACL */
+
/**
* nfs_refresh_inode - verify consistency of the inode attribute cache
* @inode - pointer to inode
@@ -1221,8 +1310,10 @@ int nfs_refresh_inode(struct inode *inod
/* Have any file permissions changed? */
if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO)
|| inode->i_uid != fattr->uid
- || inode->i_gid != fattr->gid)
+ || inode->i_gid != fattr->gid) {
nfsi->flags |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS;
+ nfs_forget_cached_acls(inode);
+ }
/* Has the link count changed? */
if (inode->i_nlink != fattr->nlink)
@@ -1339,8 +1430,10 @@ static int nfs_update_inode(struct inode
if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) ||
inode->i_uid != fattr->uid ||
- inode->i_gid != fattr->gid)
+ inode->i_gid != fattr->gid) {
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS;
+ nfs_forget_cached_acls(inode);
+ }
inode->i_mode = fattr->mode;
inode->i_nlink = fattr->nlink;
@@ -1912,6 +2005,7 @@ static struct inode *nfs_alloc_inode(str
static void nfs_destroy_inode(struct inode *inode)
{
+ __nfs_forget_cached_acls(NFS_I(inode));
kmem_cache_free(nfs_inode_cachep, NFS_I(inode));
}
@@ -1932,6 +2026,10 @@ static void init_once(void * foo, kmem_c
nfsi->ncommit = 0;
nfsi->npages = 0;
init_waitqueue_head(&nfsi->nfs_i_wait);
+#ifdef CONFIG_NFS_ACL
+ nfsi->acl_access = ERR_PTR(-EAGAIN);
+ nfsi->acl_default = ERR_PTR(-EAGAIN);
+#endif
nfs4_init_once(nfsi);
}
}
Index: linux-2.6.11-rc5/fs/nfs/nfs3proc.c
===================================================================
--- linux-2.6.11-rc5.orig/fs/nfs/nfs3proc.c
+++ linux-2.6.11-rc5/fs/nfs/nfs3proc.c
@@ -782,26 +782,29 @@ nfs3_proc_getacl(struct inode *inode, in
struct nfs3_getaclres res = {
.fattr = &fattr,
};
- struct posix_acl *acl = NULL;
+ struct posix_acl *acl;
int status, count;
if (!(server->flags & NFSACL) || (server->flags & NFS_MOUNT_NOACL))
return ERR_PTR(-EOPNOTSUPP);
- switch (type) {
- case ACL_TYPE_ACCESS:
- args.mask = NFS3_ACLCNT|NFS3_ACL;
- break;
-
- case ACL_TYPE_DEFAULT:
- if (!S_ISDIR(inode->i_mode))
- return NULL;
- args.mask = NFS3_DFACLCNT|NFS3_DFACL;
- break;
-
- default:
- return ERR_PTR(-EINVAL);
- }
+ acl = nfs_get_cached_acl(inode, type);
+ if (acl != ERR_PTR(-EAGAIN))
+ return acl;
+ acl = NULL;
+
+ /*
+ * Only get the access acl when explicitly requested: We don't
+ * need it for access decisions, and only some applications use
+ * it. Applications which request the access acl first are not
+ * penalized from this optimization.
+ */
+ if (type == ACL_TYPE_ACCESS)
+ args.mask |= NFS3_ACLCNT|NFS3_ACL;
+ if (S_ISDIR(inode->i_mode))
+ args.mask |= NFS3_DFACLCNT|NFS3_DFACL;
+ if (!args.mask)
+ return NULL;
args.fh = NFS_FH(inode);
dprintk("NFS call getacl\n");
@@ -834,6 +837,7 @@ nfs3_proc_getacl(struct inode *inode, in
res.acl_access = NULL;
}
}
+ nfs_cache_acls(inode, res.acl_access, res.acl_default);
switch(type) {
case ACL_TYPE_ACCESS:
@@ -925,6 +929,7 @@ nfs3_proc_setacls(struct inode *inode, s
acl = NULL;
}
}
+ nfs_cache_acls(inode, acl, dfacl);
status = nfs_refresh_inode(inode, &fattr);
}
Index: linux-2.6.11-rc5/include/linux/nfs_fs.h
===================================================================
--- linux-2.6.11-rc5.orig/include/linux/nfs_fs.h
+++ linux-2.6.11-rc5/include/linux/nfs_fs.h
@@ -104,6 +104,8 @@ struct nfs_open_context {
*/
struct nfs_delegation;
+struct posix_acl;
+
/*
* nfs fs inode data in memory
*/
@@ -158,6 +160,11 @@ struct nfs_inode {
atomic_t data_updates;
struct nfs_access_entry cache_access;
+#ifdef CONFIG_NFS_ACL
+ unsigned long acl_timestamp;
+ struct posix_acl *acl_access;
+ struct posix_acl *acl_default;
+#endif
/*
* This is the cookie verifier used for NFSv3 readdir
@@ -286,6 +293,8 @@ extern struct inode_operations nfs3_spec
extern void nfs_zap_caches(struct inode *);
extern struct inode *nfs_fhget(struct super_block *, struct nfs_fh *,
struct nfs_fattr *);
+extern struct posix_acl *nfs_get_cached_acl(struct inode *, int);
+extern void nfs_cache_acls(struct inode *, struct posix_acl *, struct posix_acl *);
extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
extern int nfs_getattr(struct vfsmount *, struct dentry *, struct kstat *);
extern int nfs_permission(struct inode *, int, struct nameidata *);
--
Andreas Gruenbacher <agruen@suse.de>
SUSE Labs, SUSE LINUX PRODUCTS GMBH
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [nfsacl v2 02/16] Qsort
2005-02-27 16:59 ` [nfsacl v2 02/16] Qsort Andreas Gruenbacher
@ 2005-02-27 22:54 ` Andreas Gruenbacher
0 siblings, 0 replies; 21+ messages in thread
From: Andreas Gruenbacher @ 2005-02-27 22:54 UTC (permalink / raw)
To: linux-kernel
Cc: Neil Brown, Trond Myklebust, Olaf Kirch, Andries E. Brouwer,
Andrew Morton
[-- Attachment #1: Type: text/plain, Size: 691 bytes --]
On Sunday 27 February 2005 17:59, Andreas Gruenbacher wrote:
> Add a quicksort from glibc as a kernel library function, and switch
> xfs over to using it. The implementations are equivalent. The nfsacl
> protocol also requires a sort function, so it makes more sense in
> the common code.
>
> The plan is to replace this by Matt Machall's heap sort implementation
> after it has been fixed.
My fault; I overlooked the existing fixes in Andrew's tree. So this patch
replaces qsort. I have rolled all the fixes into one patch.
A new "[10/16] Infrastructure and server side of nfsacl" patch will follow.
Regards,
--
Andreas Gruenbacher <agruen@suse.de>
SUSE Labs, SUSE LINUX PRODUCTS GMBH
[-- Attachment #2: lib-sort-heapsort-implementation-of-sort-2.patch --]
[-- Type: text/x-diff, Size: 8262 bytes --]
From: Matt Mackall <mpm@selenic.com>
Subject: heapsort
[Fixes added by agruen@suse.de.]
This patch adds a generic array sorting library routine. This is meant
to replace qsort, which has two problem areas for kernel use.
The first issue is quadratic worst-case performance. While quicksort
worst-case datasets are rarely encountered in normal scenarios, it is
in fact quite easy to construct worst cases for almost all quicksort
algorithms given source or access to an element comparison callback.
This could allow attackers to cause sorts that would otherwise take
less than a millisecond to take seconds and sorts that should take
less than a second to take weeks or months. Fixing this problem
requires randomizing pivot selection with a secure random number
generator, which is rather expensive.
The second is that quicksort's recursion tracking requires either
nontrivial amounts of stack space or dynamic memory allocation and out
of memory error handling.
By comparison, heapsort has both O(n log n) average and worst-case
performance and practically no extra storage requirements. This
version runs within 70-90% of the average performance of optimized
quicksort so it should be an acceptable replacement wherever quicksort
would be used in the kernel.
Note that this function has an extra parameter for passing in an
optimized swapping function. This is worth 10% or more over the
typical byte-by-byte exchange functions.
Benchmarks:
qsort: glibc variant 1189 bytes (+ 256/1024 stack)
qsort_3f: my simplified variant 459 bytes (+ 256/1024 stack)
heapsort: the version below 346 bytes
shellsort: an optimized shellsort 196 bytes
P4 1.8GHz Opteron 1.4GHz (32-bit)
size algorithm cycles relative cycles relative
100:
qsort: 38682 100.00% 27631 100.00%
qsort_3f: 36277 106.63% 22406 123.32%
heapsort: 43574 88.77% 30301 91.19%
shellsort: 39087 98.97% 25139 109.91%
200:
qsort: 86468 100.00% 61148 100.00%
qsort_3f: 78918 109.57% 48959 124.90%
heapsort: 98040 88.20% 68235 89.61%
shellsort: 95688 90.36% 62279 98.18%
400:
qsort: 187720 100.00% 131313 100.00%
qsort_3f: 174905 107.33% 107954 121.64%
heapsort: 223896 83.84% 154241 85.13%
shellsort: 223037 84.17% 148990 88.14%
800:
qsort: 407060 100.00% 287460 100.00%
qsort_3f: 385106 105.70% 239131 120.21%
heapsort: 484662 83.99% 340099 84.52%
shellsort: 537110 75.79% 354755 81.03%
1600:
qsort: 879596 100.00% 621331 100.00%
qsort_3f: 861568 102.09% 522013 119.03%
heapsort: 1079750 81.46% 746677 83.21%
shellsort: 1234243 71.27% 820782 75.70%
3200:
qsort: 1903902 100.00% 1342126 100.00%
qsort_3f: 1908816 99.74% 1131496 118.62%
heapsort: 2515493 75.69% 1630333 82.32%
shellsort: 2985339 63.78% 1964794 68.31%
6400:
qsort: 4046370 100.00% 2909215 100.00%
qsort_3f: 4164468 97.16% 2468393 117.86%
heapsort: 5150659 78.56% 3533585 82.33%
shellsort: 6650225 60.85% 4429849 65.67%
12800:
qsort: 8729730 100.00% 6185097 100.00%
qsort_3f: 8776885 99.46% 5288826 116.95%
heapsort: 11064224 78.90% 7603061 81.35%
shellsort: 15487905 56.36% 10305163 60.02%
25600:
qsort: 18357770 100.00% 13172205 100.00%
qsort_3f: 18687842 98.23% 11337115 116.19%
heapsort: 24121241 76.11% 16612122 79.29%
shellsort: 35552814 51.64% 24106987 54.64%
51200:
qsort: 38658883 100.00% 28008505 100.00%
qsort_3f: 39498463 97.87% 24339675 115.07%
heapsort: 50553552 76.47% 37013828 75.67%
shellsort: 82602416 46.80% 56201889 49.84%
102400:
qsort: 81197794 100.00% 58918933 100.00%
qsort_3f: 84257930 96.37% 51986219 113.34%
heapsort: 110540577 73.46% 81419675 72.36%
shellsort: 191303132 42.44% 129786472 45.40%
Signed-off-by: Matt Mackall <mpm@selenic.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Index: linux-2.6.11-rc5/include/linux/sort.h
===================================================================
--- /dev/null
+++ linux-2.6.11-rc5/include/linux/sort.h
@@ -0,0 +1,10 @@
+#ifndef _LINUX_SORT_H
+#define _LINUX_SORT_H
+
+#include <linux/types.h>
+
+void sort(void *base, size_t num, size_t size,
+ int (*cmp)(const void *, const void *),
+ void (*swap)(void *, void *, int));
+
+#endif
Index: linux-2.6.11-rc5/lib/Makefile
===================================================================
--- linux-2.6.11-rc5.orig/lib/Makefile
+++ linux-2.6.11-rc5/lib/Makefile
@@ -5,7 +5,7 @@
lib-y := errno.o ctype.o string.o vsprintf.o cmdline.o \
bust_spinlocks.o rbtree.o radix-tree.o dump_stack.o \
kobject.o kref.o idr.o div64.o parser.o int_sqrt.o \
- bitmap.o extable.o kobject_uevent.o prio_tree.o
+ bitmap.o extable.o kobject_uevent.o prio_tree.o sort.o
ifeq ($(CONFIG_DEBUG_KOBJECT),y)
CFLAGS_kobject.o += -DDEBUG
Index: linux-2.6.11-rc5/lib/sort.c
===================================================================
--- /dev/null
+++ linux-2.6.11-rc5/lib/sort.c
@@ -0,0 +1,119 @@
+/*
+ * A fast, small, non-recursive O(nlog n) sort for the Linux kernel
+ *
+ * Jan 23 2005 Matt Mackall <mpm@selenic.com>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+void u32_swap(void *a, void *b, int size)
+{
+ u32 t = *(u32 *)a;
+ *(u32 *)a = *(u32 *)b;
+ *(u32 *)b = t;
+}
+
+void generic_swap(void *a, void *b, int size)
+{
+ char t;
+
+ do {
+ t = *(char *)a;
+ *(char *)a++ = *(char *)b;
+ *(char *)b++ = t;
+ } while (--size > 0);
+}
+
+/*
+ * sort - sort an array of elements
+ * @base: pointer to data to sort
+ * @num: number of elements
+ * @size: size of each element
+ * @cmp: pointer to comparison function
+ * @swap: pointer to swap function or NULL
+ *
+ * This function does a heapsort on the given array. You may provide a
+ * swap function optimized to your element type.
+ *
+ * Sorting time is O(n log n) both on average and worst-case. While
+ * qsort is about 20% faster on average, it suffers from exploitable
+ * O(n*n) worst-case behavior and extra memory requirements that make
+ * it less suitable for kernel use.
+ */
+
+void sort(void *base, size_t num, size_t size,
+ int (*cmp)(const void *, const void *),
+ void (*swap)(void *, void *, int size))
+{
+ /* pre-scale counters for performance */
+ int i = (num/2) * size, n = num * size, c, r;
+
+ if (!swap)
+ swap = (size == 4 ? u32_swap : generic_swap);
+
+ /* heapify */
+ for ( ; i >= 0; i -= size) {
+ for (r = i; r * 2 < n; r = c) {
+ c = r * 2;
+ if (c < n - size && cmp(base + c, base + c + size) < 0)
+ c += size;
+ if (cmp(base + r, base + c) >= 0)
+ break;
+ swap(base + r, base + c, size);
+ }
+ }
+
+ /* sort */
+ for (i = n - size; i >= 0; i -= size) {
+ swap(base, base + i, size);
+ for (r = 0; r * 2 < i; r = c) {
+ c = r * 2;
+ if (c < i - size && cmp(base + c, base + c + size) < 0)
+ c += size;
+ if (cmp(base + r, base + c) >= 0)
+ break;
+ swap(base + r, base + c, size);
+ }
+ }
+}
+
+EXPORT_SYMBOL(sort);
+
+#if 0
+/* a simple boot-time regression test */
+
+int cmpint(const void *a, const void *b)
+{
+ return *(int *)a - *(int *)b;
+}
+
+static int sort_test(void)
+{
+ int *a, i, r = 0;
+
+ a = kmalloc(1000 * sizeof(int), GFP_KERNEL);
+ BUG_ON(!a);
+
+ printk("testing sort()\n");
+
+ for (i = 0; i < 1000; i++) {
+ r = (r * 725861) % 6599;
+ a[i] = r;
+ }
+
+ sort(a, 1000, sizeof(int), cmpint, NULL);
+
+ for (i = 0; i < 999; i++)
+ if (a[i] > a[i+1]) {
+ printk("sort() failed!\n");
+ break;
+ }
+
+ kfree(a);
+
+ return 0;
+}
+
+module_init(sort_test);
+#endif
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [nfsacl v2 10/16] Infrastructure and server side of nfsacl
2005-02-27 17:00 ` [nfsacl v2 10/16] Infrastructure and server side of nfsacl Andreas Gruenbacher
@ 2005-02-27 22:56 ` Andreas Gruenbacher
0 siblings, 0 replies; 21+ messages in thread
From: Andreas Gruenbacher @ 2005-02-27 22:56 UTC (permalink / raw)
To: linux-kernel
Cc: Neil Brown, Trond Myklebust, Olaf Kirch, Andries E. Brouwer,
Andrew Morton
[-- Attachment #1: Type: text/plain, Size: 374 bytes --]
On Sunday 27 February 2005 18:00, Andreas Gruenbacher wrote:
> This adds functions for encoding and decoding POSIX ACLs for the NFSACL
> protocol extension, and the GETACL and SETACL RPCs. The implementation is
> compatible with NFSACL in Solaris.
This patch now uses Matt's heapsort.
Regards,
--
Andreas Gruenbacher <agruen@suse.de>
SUSE Labs, SUSE LINUX PRODUCTS GMBH
[-- Attachment #2: nfsacl-infrastructure-and-server-side-of-nfsacl-2.patch --]
[-- Type: text/x-diff, Size: 28084 bytes --]
From: Andreas Gruenbacher <agruen@suse.de>
Subject: Infrastructure and server side of nfsacl
This adds functions for encoding and decoding POSIX ACLs for the NFSACL
protocol extension, and the GETACL and SETACL RPCs. The implementation is
compatible with NFSACL in Solaris.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Acked-by: Olaf Kirch <okir@suse.de>
Index: linux-2.6.11-rc5/fs/Kconfig
===================================================================
--- linux-2.6.11-rc5.orig/fs/Kconfig
+++ linux-2.6.11-rc5/fs/Kconfig
@@ -1435,6 +1435,20 @@ config NFSD_V3
If you would like to include the NFSv3 server as well as the NFSv2
server, say Y here. If unsure, say Y.
+config NFSD_ACL
+ bool "NFS_ACL protocol extension"
+ depends on NFSD_V3
+ select NFS_ACL_SUPPORT
+ help
+ Implement the NFS_ACL protocol extension for manipulating POSIX
+ Access Control Lists on exported file systems. The clients must
+ also implement the NFS_ACL protocol extension; see the
+ CONFIG_NFS_ACL option. If unsure, say N.
+
+config NFS_ACL_SUPPORT
+ bool
+ select FS_POSIX_ACL
+
config NFSD_V4
bool "Provide NFSv4 server support (EXPERIMENTAL)"
depends on NFSD_V3 && EXPERIMENTAL
Index: linux-2.6.11-rc5/fs/Makefile
===================================================================
--- linux-2.6.11-rc5.orig/fs/Makefile
+++ linux-2.6.11-rc5/fs/Makefile
@@ -31,6 +31,7 @@ obj-$(CONFIG_BINFMT_FLAT) += binfmt_flat
obj-$(CONFIG_FS_MBCACHE) += mbcache.o
obj-$(CONFIG_FS_POSIX_ACL) += posix_acl.o xattr_acl.o
+obj-$(CONFIG_NFS_ACL_SUPPORT) += nfsacl.o
obj-$(CONFIG_QUOTA) += dquot.o
obj-$(CONFIG_QFMT_V1) += quota_v1.o
Index: linux-2.6.11-rc5/fs/nfsacl.c
===================================================================
--- /dev/null
+++ linux-2.6.11-rc5/fs/nfsacl.c
@@ -0,0 +1,257 @@
+/*
+ * fs/nfsacl.c
+ *
+ * Copyright (C) 2002-2003 Andreas Gruenbacher <agruen@suse.de>
+ */
+
+/*
+ * The Solaris nfsacl protocol represents some ACLs slightly differently
+ * than POSIX 1003.1e draft 17 does (and we do):
+ *
+ * - Minimal ACLs always have an ACL_MASK entry, so they have
+ * four instead of three entries.
+ * - The ACL_MASK entry in such minimal ACLs always has the same
+ * permissions as the ACL_GROUP_OBJ entry. (In extended ACLs
+ * the ACL_MASK and ACL_GROUP_OBJ entries may differ.)
+ * - The identifier fields of the ACL_USER_OBJ and ACL_GROUP_OBJ
+ * entries contain the identifiers of the owner and owning group.
+ * (In POSIX ACLs we always set them to ACL_UNDEFINED_ID).
+ * - ACL entries in the kernel are kept sorted in ascending order
+ * of (e_tag, e_id). Solaris ACLs are unsorted.
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/sunrpc/xdr.h>
+#include <linux/nfsacl.h>
+#include <linux/nfs3.h>
+#include <linux/sort.h>
+
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(nfsacl_encode);
+EXPORT_SYMBOL(nfsacl_decode);
+
+struct nfsacl_encode_desc {
+ struct xdr_array2_desc desc;
+ unsigned int count;
+ struct posix_acl *acl;
+ int typeflag;
+ uid_t uid;
+ gid_t gid;
+};
+
+static int
+xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem)
+{
+ struct nfsacl_encode_desc *nfsacl_desc =
+ (struct nfsacl_encode_desc *) desc;
+ u32 *p = (u32 *) elem;
+
+ if (nfsacl_desc->count < nfsacl_desc->acl->a_count) {
+ struct posix_acl_entry *entry =
+ &nfsacl_desc->acl->a_entries[nfsacl_desc->count++];
+
+ *p++ = htonl(entry->e_tag | nfsacl_desc->typeflag);
+ switch(entry->e_tag) {
+ case ACL_USER_OBJ:
+ *p++ = htonl(nfsacl_desc->uid);
+ break;
+ case ACL_GROUP_OBJ:
+ *p++ = htonl(nfsacl_desc->gid);
+ break;
+ case ACL_USER:
+ case ACL_GROUP:
+ *p++ = htonl(entry->e_id);
+ break;
+ default: /* Solaris depends on that! */
+ *p++ = 0;
+ break;
+ }
+ *p++ = htonl(entry->e_perm & S_IRWXO);
+ } else {
+ const struct posix_acl_entry *pa, *pe;
+ int group_obj_perm = ACL_READ|ACL_WRITE|ACL_EXECUTE;
+
+ FOREACH_ACL_ENTRY(pa, nfsacl_desc->acl, pe) {
+ if (pa->e_tag == ACL_GROUP_OBJ) {
+ group_obj_perm = pa->e_perm & S_IRWXO;
+ break;
+ }
+ }
+ /* fake up ACL_MASK entry */
+ *p++ = htonl(ACL_MASK | nfsacl_desc->typeflag);
+ *p++ = htonl(0);
+ *p++ = htonl(group_obj_perm);
+ }
+
+ return 0;
+}
+
+unsigned int
+nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
+ struct posix_acl *acl, int encode_entries, int typeflag)
+{
+ int entries = (acl && acl->a_count) ? max_t(int, acl->a_count, 4) : 0;
+ struct nfsacl_encode_desc nfsacl_desc = {
+ .desc = {
+ .elem_size = 12,
+ .array_len = encode_entries ? entries : 0,
+ .xcode = xdr_nfsace_encode,
+ },
+ .acl = acl,
+ .typeflag = typeflag,
+ .uid = inode->i_uid,
+ .gid = inode->i_gid,
+ };
+ int err;
+
+ if (entries > NFS3_ACL_MAX_ENTRIES ||
+ xdr_encode_word(buf, base, entries))
+ return -EINVAL;
+ err = xdr_encode_array2(buf, base + 4, &nfsacl_desc.desc);
+ if (!err)
+ err = 8 + nfsacl_desc.desc.elem_size *
+ nfsacl_desc.desc.array_len;
+ return err;
+}
+
+struct nfsacl_decode_desc {
+ struct xdr_array2_desc desc;
+ unsigned int count;
+ struct posix_acl *acl;
+};
+
+static int
+xdr_nfsace_decode(struct xdr_array2_desc *desc, void *elem)
+{
+ struct nfsacl_decode_desc *nfsacl_desc =
+ (struct nfsacl_decode_desc *) desc;
+ u32 *p = (u32 *) elem;
+ struct posix_acl_entry *entry;
+
+ if (!nfsacl_desc->acl) {
+ if (desc->array_len > NFS3_ACL_MAX_ENTRIES)
+ return -EINVAL;
+ nfsacl_desc->acl = posix_acl_alloc(desc->array_len, GFP_KERNEL);
+ if (!nfsacl_desc->acl)
+ return -ENOMEM;
+ nfsacl_desc->count = 0;
+ }
+
+ entry = &nfsacl_desc->acl->a_entries[nfsacl_desc->count++];
+ entry->e_tag = ntohl(*p++) & ~NFS3_ACL_DEFAULT;
+ entry->e_id = ntohl(*p++);
+ entry->e_perm = ntohl(*p++);
+
+ switch(entry->e_tag) {
+ case ACL_USER_OBJ:
+ case ACL_USER:
+ case ACL_GROUP_OBJ:
+ case ACL_GROUP:
+ case ACL_OTHER:
+ if (entry->e_perm & ~S_IRWXO)
+ return -EINVAL;
+ break;
+ case ACL_MASK:
+ /* Solaris sometimes sets additonal bits in the mask */
+ entry->e_perm &= S_IRWXO;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int
+cmp_acl_entry(const void *x, const void *y)
+{
+ const struct posix_acl_entry *a = x, *b = y;
+
+ if (a->e_tag != b->e_tag)
+ return a->e_tag - b->e_tag;
+ else if (a->e_id > b->e_id)
+ return 1;
+ else if (a->e_id < b->e_id)
+ return -1;
+ else
+ return 0;
+}
+
+/*
+ * Convert from a Solaris ACL to a POSIX 1003.1e draft 17 ACL.
+ */
+static int
+posix_acl_from_nfsacl(struct posix_acl *acl)
+{
+ struct posix_acl_entry *pa, *pe,
+ *group_obj = NULL, *mask = NULL;
+
+ if (!acl)
+ return 0;
+
+ sort(acl->a_entries, acl->a_count, sizeof(struct posix_acl_entry),
+ cmp_acl_entry, NULL);
+
+ /* Clear undefined identifier fields and find the ACL_GROUP_OBJ
+ and ACL_MASK entries. */
+ FOREACH_ACL_ENTRY(pa, acl, pe) {
+ switch(pa->e_tag) {
+ case ACL_USER_OBJ:
+ pa->e_id = ACL_UNDEFINED_ID;
+ break;
+ case ACL_GROUP_OBJ:
+ pa->e_id = ACL_UNDEFINED_ID;
+ group_obj = pa;
+ break;
+ case ACL_MASK:
+ mask = pa;
+ /* fall through */
+ case ACL_OTHER:
+ pa->e_id = ACL_UNDEFINED_ID;
+ break;
+ }
+ }
+ if (acl->a_count == 4 && group_obj && mask &&
+ mask->e_perm == group_obj->e_perm) {
+ /* remove bogus ACL_MASK entry */
+ memmove(mask, mask+1, (3 - (mask - acl->a_entries)) *
+ sizeof(struct posix_acl_entry));
+ acl->a_count = 3;
+ }
+ return 0;
+}
+
+unsigned int
+nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt,
+ struct posix_acl **pacl)
+{
+ struct nfsacl_decode_desc nfsacl_desc = {
+ .desc = {
+ .elem_size = 12,
+ .xcode = pacl ? xdr_nfsace_decode : NULL,
+ },
+ };
+ u32 entries;
+ int err;
+
+ if (xdr_decode_word(buf, base, &entries) ||
+ entries > NFS3_ACL_MAX_ENTRIES)
+ return -EINVAL;
+ err = xdr_decode_array2(buf, base + 4, &nfsacl_desc.desc);
+ if (err)
+ return err;
+ if (pacl) {
+ if (entries != nfsacl_desc.desc.array_len ||
+ posix_acl_from_nfsacl(nfsacl_desc.acl) != 0) {
+ posix_acl_release(nfsacl_desc.acl);
+ return -EINVAL;
+ }
+ *pacl = nfsacl_desc.acl;
+ }
+ if (aclcnt)
+ *aclcnt = entries;
+ return 8 + nfsacl_desc.desc.elem_size *
+ nfsacl_desc.desc.array_len;
+}
Index: linux-2.6.11-rc5/fs/nfsd/nfs3proc.c
===================================================================
--- linux-2.6.11-rc5.orig/fs/nfsd/nfs3proc.c
+++ linux-2.6.11-rc5/fs/nfsd/nfs3proc.c
@@ -24,6 +24,7 @@
#include <linux/nfsd/cache.h>
#include <linux/nfsd/xdr3.h>
#include <linux/nfs3.h>
+#include <linux/nfsacl.h>
#define NFSDDBG_FACILITY NFSDDBG_PROC
@@ -630,6 +631,105 @@ nfsd3_proc_commit(struct svc_rqst * rqst
RETURN_STATUS(nfserr);
}
+#ifdef CONFIG_NFSD_ACL
+/*
+ * Get the Access and/or Default ACL of a file.
+ */
+static int
+nfsd3_proc_getacl(struct svc_rqst * rqstp, struct nfsd3_getaclargs *argp,
+ struct nfsd3_getaclres *resp)
+{
+ svc_fh *fh;
+ struct posix_acl *acl;
+ int nfserr = 0;
+
+ fh = fh_copy(&resp->fh, &argp->fh);
+ if ((nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP)))
+ RETURN_STATUS(nfserr_inval);
+
+ if (argp->mask & ~(NFS3_ACL|NFS3_ACLCNT|NFS3_DFACL|NFS3_DFACLCNT))
+ RETURN_STATUS(nfserr_inval);
+ resp->mask = argp->mask;
+
+ if (resp->mask & (NFS3_ACL|NFS3_ACLCNT)) {
+ acl = nfsd_get_posix_acl(fh, ACL_TYPE_ACCESS);
+ if (IS_ERR(acl)) {
+ int err = PTR_ERR(acl);
+
+ if (err == -ENODATA || err == -EOPNOTSUPP)
+ acl = NULL;
+ else {
+ nfserr = nfserrno(err);
+ goto fail;
+ }
+ }
+ if (acl == NULL) {
+ /* Solaris returns the inode's minimum ACL. */
+
+ struct inode *inode = fh->fh_dentry->d_inode;
+ acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
+ }
+ resp->acl_access = acl;
+ }
+ if (resp->mask & (NFS3_DFACL|NFS3_DFACLCNT)) {
+ /* Check how Solaris handles requests for the Default ACL
+ of a non-directory! */
+
+ acl = nfsd_get_posix_acl(fh, ACL_TYPE_DEFAULT);
+ if (IS_ERR(acl)) {
+ int err = PTR_ERR(acl);
+
+ if (err == -ENODATA || err == -EOPNOTSUPP)
+ acl = NULL;
+ else {
+ nfserr = nfserrno(err);
+ goto fail;
+ }
+ }
+ resp->acl_default = acl;
+ }
+
+ /* resp->acl_{access,default} are released in nfs3svc_release_getacl. */
+ RETURN_STATUS(0);
+
+fail:
+ posix_acl_release(resp->acl_access);
+ posix_acl_release(resp->acl_default);
+ RETURN_STATUS(nfserr);
+}
+#endif /* CONFIG_NFSD_ACL */
+
+#ifdef CONFIG_NFSD_ACL
+/*
+ * Set the Access and/or Default ACL of a file.
+ */
+static int
+nfsd3_proc_setacl(struct svc_rqst * rqstp, struct nfsd3_setaclargs *argp,
+ struct nfsd3_attrstat *resp)
+{
+ svc_fh *fh;
+ int nfserr = 0;
+
+ fh = fh_copy(&resp->fh, &argp->fh);
+ nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP);
+
+ if (!nfserr) {
+ nfserr = nfserrno( nfsd_set_posix_acl(
+ fh, ACL_TYPE_ACCESS, argp->acl_access) );
+ }
+ if (!nfserr) {
+ nfserr = nfserrno( nfsd_set_posix_acl(
+ fh, ACL_TYPE_DEFAULT, argp->acl_default) );
+ }
+
+ /* argp->acl_{access,default} may have been allocated in
+ nfs3svc_decode_setaclargs. */
+ posix_acl_release(argp->acl_access);
+ posix_acl_release(argp->acl_default);
+ RETURN_STATUS(nfserr);
+}
+#endif /* CONFIG_NFSD_ACL */
+
/*
* NFSv3 Server procedures.
@@ -647,6 +747,7 @@ nfsd3_proc_commit(struct svc_rqst * rqst
#define nfsd3_attrstatres nfsd3_attrstat
#define nfsd3_wccstatres nfsd3_attrstat
#define nfsd3_createres nfsd3_diropres
+#define nfsd3_setaclres nfsd3_attrstat
#define nfsd3_voidres nfsd3_voidargs
struct nfsd3_voidargs { int dummy; };
@@ -667,6 +768,7 @@ struct nfsd3_voidargs { int dummy; };
#define AT 21 /* attributes */
#define pAT (1+AT) /* post attributes - conditional */
#define WC (7+pAT) /* WCC attributes */
+#define ACL (1+NFS3_ACL_MAX_ENTRIES*3) /* Access Control List */
static struct svc_procedure nfsd_procedures3[22] = {
PROC(null, void, void, void, RC_NOCACHE, ST),
@@ -700,3 +802,19 @@ struct svc_version nfsd_version3 = {
.vs_dispatch = nfsd_dispatch,
.vs_xdrsize = NFS3_SVC_XDRSIZE,
};
+
+#ifdef CONFIG_NFSD_ACL
+struct svc_procedure nfsd_acl_procedures3[] = {
+ PROC(null, void, void, void, RC_NOCACHE, ST),
+ PROC(getacl, getacl, getacl, getacl, RC_NOCACHE, ST+1+2*(1+ACL)),
+ PROC(setacl, setacl, setacl, fhandle, RC_NOCACHE, ST+pAT),
+};
+
+struct svc_version nfsd_acl_version3 = {
+ .vs_vers = 3,
+ .vs_nproc = 3,
+ .vs_proc = nfsd_acl_procedures3,
+ .vs_dispatch = nfsd_dispatch,
+ .vs_xdrsize = NFS3_SVC_XDRSIZE,
+};
+#endif /* CONFIG_NFSD_ACL */
Index: linux-2.6.11-rc5/fs/nfsd/nfs3xdr.c
===================================================================
--- linux-2.6.11-rc5.orig/fs/nfsd/nfs3xdr.c
+++ linux-2.6.11-rc5/fs/nfsd/nfs3xdr.c
@@ -21,6 +21,7 @@
#include <linux/sunrpc/svc.h>
#include <linux/nfsd/nfsd.h>
#include <linux/nfsd/xdr3.h>
+#include <linux/nfsacl.h>
#define NFSDDBG_FACILITY NFSDDBG_XDR
@@ -583,6 +584,47 @@ nfs3svc_decode_commitargs(struct svc_rqs
return xdr_argsize_check(rqstp, p);
}
+#ifdef CONFIG_NFSD_ACL
+int
+nfs3svc_decode_getaclargs(struct svc_rqst *rqstp, u32 *p,
+ struct nfsd3_getaclargs *args)
+{
+ if (!(p = decode_fh(p, &args->fh)))
+ return 0;
+ args->mask = ntohl(*p); p++;
+
+ return xdr_argsize_check(rqstp, p);
+}
+#endif /* CONFIG_NFSD_ACL */
+
+#ifdef CONFIG_NFSD_ACL
+int
+nfs3svc_decode_setaclargs(struct svc_rqst *rqstp, u32 *p,
+ struct nfsd3_setaclargs *args)
+{
+ struct kvec *head = rqstp->rq_arg.head;
+ unsigned int base;
+ int n;
+
+ if (!(p = decode_fh(p, &args->fh)))
+ return 0;
+ args->mask = ntohl(*p++);
+ if (args->mask & ~(NFS3_ACL|NFS3_ACLCNT|NFS3_DFACL|NFS3_DFACLCNT) ||
+ !xdr_argsize_check(rqstp, p))
+ return 0;
+
+ base = (char *)p - (char *)head->iov_base;
+ n = nfsacl_decode(&rqstp->rq_arg, base, NULL,
+ (args->mask & NFS3_ACL) ?
+ &args->acl_access : NULL);
+ if (n > 0)
+ n = nfsacl_decode(&rqstp->rq_arg, base + n, NULL,
+ (args->mask & NFS3_DFACL) ?
+ &args->acl_default : NULL);
+ return (n > 0);
+}
+#endif /* CONFIG_NFSD_ACL */
+
/*
* XDR encode functions
*/
@@ -1066,6 +1108,66 @@ nfs3svc_encode_commitres(struct svc_rqst
return xdr_ressize_check(rqstp, p);
}
+#ifdef CONFIG_NFSD_ACL
+/* GETACL */
+int
+nfs3svc_encode_getaclres(struct svc_rqst *rqstp, u32 *p,
+ struct nfsd3_getaclres *resp)
+{
+ struct dentry *dentry = resp->fh.fh_dentry;
+
+ p = encode_post_op_attr(rqstp, p, &resp->fh);
+ if (resp->status == 0 && dentry && dentry->d_inode) {
+ struct inode *inode = dentry->d_inode;
+ int w = nfsacl_size(
+ (resp->mask & NFS3_ACL) ? resp->acl_access : NULL,
+ (resp->mask & NFS3_DFACL) ? resp->acl_default : NULL);
+ struct kvec *head = rqstp->rq_res.head;
+ unsigned int base;
+ int n;
+
+ *p++ = htonl(resp->mask);
+ if (!xdr_ressize_check(rqstp, p))
+ return 0;
+ base = (char *)p - (char *)head->iov_base;
+
+ rqstp->rq_res.page_len = w;
+ while (w > 0) {
+ if (!svc_take_res_page(rqstp))
+ return 0;
+ w -= PAGE_SIZE;
+ }
+
+ n = nfsacl_encode(&rqstp->rq_res, base, inode,
+ resp->acl_access,
+ resp->mask & NFS3_ACL, 0);
+ if (n > 0)
+ n = nfsacl_encode(&rqstp->rq_res, base + n, inode,
+ resp->acl_default,
+ resp->mask & NFS3_DFACL,
+ NFS3_ACL_DEFAULT);
+ if (n <= 0)
+ return 0;
+ } else
+ if (!xdr_ressize_check(rqstp, p))
+ return 0;
+
+ return 1;
+}
+#endif /* CONFIG_NFSD_ACL */
+
+#ifdef CONFIG_NFSD_ACL
+/* SETACL */
+int
+nfs3svc_encode_setaclres(struct svc_rqst *rqstp, u32 *p,
+ struct nfsd3_attrstat *resp)
+{
+ p = encode_post_op_attr(rqstp, p, &resp->fh);
+
+ return xdr_ressize_check(rqstp, p);
+}
+#endif /* CONFIG_NFSD_ACL */
+
/*
* XDR release functions
*/
@@ -1085,3 +1187,15 @@ nfs3svc_release_fhandle2(struct svc_rqst
fh_put(&resp->fh2);
return 1;
}
+
+#ifdef CONFIG_NFSD_ACL
+int
+nfs3svc_release_getacl(struct svc_rqst *rqstp, u32 *p,
+ struct nfsd3_getaclres *resp)
+{
+ fh_put(&resp->fh);
+ posix_acl_release(resp->acl_access);
+ posix_acl_release(resp->acl_default);
+ return 1;
+}
+#endif /* CONFIG_NFSD_ACL */
Index: linux-2.6.11-rc5/fs/nfsd/nfssvc.c
===================================================================
--- linux-2.6.11-rc5.orig/fs/nfsd/nfssvc.c
+++ linux-2.6.11-rc5/fs/nfsd/nfssvc.c
@@ -49,6 +49,9 @@
#define SIG_NOCLEAN SIGHUP
extern struct svc_program nfsd_program;
+#ifdef CONFIG_NFSD_ACL
+extern struct svc_program nfsd_acl_program;
+#endif
static void nfsd(struct svc_rqst *rqstp);
struct timeval nfssvc_boot;
static struct svc_serv *nfsd_serv;
@@ -370,8 +373,29 @@ static struct svc_version * nfsd_version
#endif
};
+#ifdef CONFIG_NFSD_ACL
+extern struct svc_version nfsd_acl_version3;
+
+static struct svc_version * nfsd_acl_version[] = {
+ [3] = &nfsd_acl_version3,
+};
+
+#define NFSD_ACL_NRVERS (sizeof(nfsd_acl_version)/sizeof(nfsd_acl_version[0]))
+struct svc_program nfsd_acl_program = {
+ .pg_prog = NFS3_ACL_PROGRAM,
+ .pg_nvers = NFSD_ACL_NRVERS,
+ .pg_vers = nfsd_acl_version,
+ .pg_name = "nfsd",
+ .pg_stats = &nfsd_acl_svcstats,
+};
+# define nfsd_acl_program_p &nfsd_acl_program
+#else
+# define nfsd_acl_program_p NULL
+#endif
+
#define NFSD_NRVERS (sizeof(nfsd_version)/sizeof(nfsd_version[0]))
struct svc_program nfsd_program = {
+ .pg_next = nfsd_acl_program_p,
.pg_prog = NFS_PROGRAM, /* program number */
.pg_nvers = NFSD_NRVERS, /* nr of entries in nfsd_version */
.pg_vers = nfsd_version, /* version table */
Index: linux-2.6.11-rc5/fs/nfsd/stats.c
===================================================================
--- linux-2.6.11-rc5.orig/fs/nfsd/stats.c
+++ linux-2.6.11-rc5/fs/nfsd/stats.c
@@ -40,6 +40,12 @@ struct svc_stat nfsd_svcstats = {
.program = &nfsd_program,
};
+#ifdef CONFIG_NFSD_ACL
+struct svc_stat nfsd_acl_svcstats = {
+ .program = &nfsd_acl_program,
+};
+#endif
+
static int nfsd_proc_show(struct seq_file *seq, void *v)
{
int i;
Index: linux-2.6.11-rc5/fs/nfsd/vfs.c
===================================================================
--- linux-2.6.11-rc5.orig/fs/nfsd/vfs.c
+++ linux-2.6.11-rc5/fs/nfsd/vfs.c
@@ -45,6 +45,7 @@
#include <linux/nfsd/nfsfh.h>
#include <linux/quotaops.h>
#include <linux/dnotify.h>
+#include <linux/xattr_acl.h>
#ifdef CONFIG_NFSD_V4
#include <linux/posix_acl.h>
#include <linux/posix_acl_xattr.h>
@@ -1817,3 +1818,109 @@ nfsd_racache_init(int cache_size)
nfsdstats.ra_size = cache_size;
return 0;
}
+
+#ifdef CONFIG_NFSD_ACL
+struct posix_acl *
+nfsd_get_posix_acl(struct svc_fh *fhp, int type)
+{
+ struct inode *inode = fhp->fh_dentry->d_inode;
+ char *name;
+ void *value = NULL;
+ ssize_t size;
+ struct posix_acl *acl;
+
+ if (!IS_POSIXACL(inode) || !inode->i_op || !inode->i_op->getxattr)
+ return ERR_PTR(-EOPNOTSUPP);
+ switch(type) {
+ case ACL_TYPE_ACCESS:
+ name = XATTR_NAME_ACL_ACCESS;
+ break;
+ case ACL_TYPE_DEFAULT:
+ name = XATTR_NAME_ACL_DEFAULT;
+ break;
+ default:
+ return ERR_PTR(-EOPNOTSUPP);
+ }
+
+ size = inode->i_op->getxattr(fhp->fh_dentry, name, NULL, 0);
+
+ if (size < 0) {
+ acl = ERR_PTR(size);
+ goto getout;
+ } else if (size > 0) {
+ value = kmalloc(size, GFP_KERNEL);
+ if (!value) {
+ acl = ERR_PTR(-ENOMEM);
+ goto getout;
+ }
+ size = inode->i_op->getxattr(fhp->fh_dentry, name, value, size);
+ if (size < 0) {
+ acl = ERR_PTR(size);
+ goto getout;
+ }
+ }
+ acl = posix_acl_from_xattr(value, size);
+
+getout:
+ kfree(value);
+ return acl;
+}
+#endif /* CONFIG_NFSD_ACL */
+
+#ifdef CONFIG_NFSD_ACL
+int
+nfsd_set_posix_acl(struct svc_fh *fhp, int type, struct posix_acl *acl)
+{
+ struct inode *inode = fhp->fh_dentry->d_inode;
+ char *name;
+ void *value = NULL;
+ size_t size;
+ int error;
+
+ if (!IS_POSIXACL(inode) || !inode->i_op ||
+ !inode->i_op->setxattr || !inode->i_op->removexattr)
+ return -EOPNOTSUPP;
+ switch(type) {
+ case ACL_TYPE_ACCESS:
+ name = XATTR_NAME_ACL_ACCESS;
+ break;
+ case ACL_TYPE_DEFAULT:
+ name = XATTR_NAME_ACL_DEFAULT;
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ if (acl && acl->a_count) {
+ size = xattr_acl_size(acl->a_count);
+ value = kmalloc(size, GFP_KERNEL);
+ if (!value)
+ return -ENOMEM;
+ size = posix_acl_to_xattr(acl, value, size);
+ if (size < 0) {
+ error = size;
+ goto getout;
+ }
+ } else
+ size = 0;
+
+ if (!fhp->fh_locked)
+ fh_lock(fhp); /* unlocking is done automatically */
+ if (size)
+ error = inode->i_op->setxattr(fhp->fh_dentry, name,
+ value, size, 0);
+ else {
+ if (!S_ISDIR(inode->i_mode) && type == ACL_TYPE_DEFAULT)
+ error = 0;
+ else {
+ error = inode->i_op->removexattr(fhp->fh_dentry, name);
+ if (error == -ENODATA)
+ error = 0;
+ }
+ }
+
+getout:
+ kfree(value);
+ return error;
+}
+#endif /* CONFIG_NFSD_ACL */
Index: linux-2.6.11-rc5/include/linux/nfs3.h
===================================================================
--- linux-2.6.11-rc5.orig/include/linux/nfs3.h
+++ linux-2.6.11-rc5/include/linux/nfs3.h
@@ -37,6 +37,15 @@ enum nfs3_createmode {
NFS3_CREATE_EXCLUSIVE = 2
};
+/* Flags for the getacl/setacl mode */
+#define NFS3_ACL 0x0001
+#define NFS3_ACLCNT 0x0002
+#define NFS3_DFACL 0x0004
+#define NFS3_DFACLCNT 0x0008
+
+/* Flag for Default ACL entries */
+#define NFS3_ACL_DEFAULT 0x1000
+
/* NFSv3 file system properties */
#define NFS3_FSF_LINK 0x0001
#define NFS3_FSF_SYMLINK 0x0002
@@ -88,6 +97,10 @@ struct nfs3_fh {
#define NFS3PROC_PATHCONF 20
#define NFS3PROC_COMMIT 21
+#define NFS3_ACL_PROGRAM 100227
+#define NFS3PROC_GETACL 1
+#define NFS3PROC_SETACL 2
+
#define NFS_MNT3_PROGRAM 100005
#define NFS_MNT3_VERSION 3
#define MOUNTPROC3_NULL 0
Index: linux-2.6.11-rc5/include/linux/nfsacl.h
===================================================================
--- /dev/null
+++ linux-2.6.11-rc5/include/linux/nfsacl.h
@@ -0,0 +1,37 @@
+/*
+ * File: linux/nfsacl.h
+ *
+ * (C) 2003 Andreas Gruenbacher <agruen@suse.de>
+ */
+
+
+#ifndef __LINUX_NFSACL_H
+#define __LINUX_NFSACL_H
+
+#include <linux/posix_acl.h>
+
+/* Maximum number of ACL entries over NFS */
+#define NFS3_ACL_MAX_ENTRIES 1024
+
+#define NFSACL_MAXWORDS (2*(2+3*NFS3_ACL_MAX_ENTRIES))
+#define NFSACL_MAXPAGES ((2*(8+12*NFS3_ACL_MAX_ENTRIES) + PAGE_SIZE-1) \
+ >> PAGE_SHIFT)
+
+static inline unsigned int
+nfsacl_size(struct posix_acl *acl_access, struct posix_acl *acl_default)
+{
+ unsigned int w = 16;
+ w += max(acl_access ? (int)acl_access->a_count : 3, 4) * 12;
+ if (acl_default)
+ w += max((int)acl_default->a_count, 4) * 12;
+ return w;
+}
+
+extern unsigned int
+nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
+ struct posix_acl *acl, int encode_entries, int typeflag);
+extern unsigned int
+nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt,
+ struct posix_acl **pacl);
+
+#endif /* __LINUX_NFSACL_H */
Index: linux-2.6.11-rc5/include/linux/nfsd/nfsd.h
===================================================================
--- linux-2.6.11-rc5.orig/include/linux/nfsd/nfsd.h
+++ linux-2.6.11-rc5/include/linux/nfsd/nfsd.h
@@ -15,6 +15,7 @@
#include <linux/unistd.h>
#include <linux/dirent.h>
#include <linux/fs.h>
+#include <linux/posix_acl.h>
#include <linux/mount.h>
#include <linux/nfsd/debug.h>
@@ -60,6 +61,8 @@ extern struct svc_program nfsd_program;
extern struct svc_version nfsd_version2, nfsd_version3,
nfsd_version4;
+extern struct svc_program nfsd_acl_program;
+extern struct svc_version nfsd_acl_version3;
/*
* Function prototypes.
*/
@@ -124,6 +127,22 @@ int nfsd_statfs(struct svc_rqst *, stru
int nfsd_notify_change(struct inode *, struct iattr *);
int nfsd_permission(struct svc_export *, struct dentry *, int);
+#ifdef CONFIG_NFSD_ACL
+struct posix_acl *nfsd_get_posix_acl(struct svc_fh *, int);
+int nfsd_set_posix_acl(struct svc_fh *, int, struct posix_acl *);
+#else
+static inline struct posix_acl *
+nfsd_get_posix_acl(struct svc_fh *fhp, int acl_type)
+{
+ return ERR_PTR(-EOPNOTSUPP);
+}
+static inline int
+nfsd_set_posix_acl(struct svc_fh *fhp, int type, struct posix_acl *acl)
+{
+ return -EOPNOTSUPP;
+}
+#endif
+
/*
* NFSv4 State
Index: linux-2.6.11-rc5/include/linux/nfsd/stats.h
===================================================================
--- linux-2.6.11-rc5.orig/include/linux/nfsd/stats.h
+++ linux-2.6.11-rc5/include/linux/nfsd/stats.h
@@ -36,6 +36,7 @@ struct nfsd_stats {
extern struct nfsd_stats nfsdstats;
extern struct svc_stat nfsd_svcstats;
+extern struct svc_stat nfsd_acl_svcstats;
void nfsd_stat_init(void);
void nfsd_stat_shutdown(void);
Index: linux-2.6.11-rc5/include/linux/nfsd/xdr3.h
===================================================================
--- linux-2.6.11-rc5.orig/include/linux/nfsd/xdr3.h
+++ linux-2.6.11-rc5/include/linux/nfsd/xdr3.h
@@ -10,6 +10,7 @@
#define _LINUX_NFSD_XDR3_H
#include <linux/nfsd/xdr.h>
+#include <linux/posix_acl.h>
struct nfsd3_sattrargs {
struct svc_fh fh;
@@ -110,6 +111,18 @@ struct nfsd3_commitargs {
__u32 count;
};
+struct nfsd3_getaclargs {
+ struct svc_fh fh;
+ int mask;
+};
+
+struct nfsd3_setaclargs {
+ struct svc_fh fh;
+ int mask;
+ struct posix_acl *acl_access;
+ struct posix_acl *acl_default;
+};
+
struct nfsd3_attrstat {
__u32 status;
struct svc_fh fh;
@@ -209,6 +222,14 @@ struct nfsd3_commitres {
struct svc_fh fh;
};
+struct nfsd3_getaclres {
+ __u32 status;
+ struct svc_fh fh;
+ int mask;
+ struct posix_acl *acl_access;
+ struct posix_acl *acl_default;
+};
+
/* dummy type for release */
struct nfsd3_fhandle_pair {
__u32 dummy;
@@ -241,6 +262,7 @@ union nfsd3_xdrstore {
struct nfsd3_fsinfores fsinfores;
struct nfsd3_pathconfres pathconfres;
struct nfsd3_commitres commitres;
+ struct nfsd3_getaclres getaclres;
};
#define NFS3_SVC_XDRSIZE sizeof(union nfsd3_xdrstore)
@@ -276,6 +298,10 @@ int nfs3svc_decode_readdirplusargs(struc
struct nfsd3_readdirargs *);
int nfs3svc_decode_commitargs(struct svc_rqst *, u32 *,
struct nfsd3_commitargs *);
+int nfs3svc_decode_getaclargs(struct svc_rqst *, u32 *,
+ struct nfsd3_getaclargs *);
+int nfs3svc_decode_setaclargs(struct svc_rqst *, u32 *,
+ struct nfsd3_setaclargs *);
int nfs3svc_encode_voidres(struct svc_rqst *, u32 *, void *);
int nfs3svc_encode_attrstat(struct svc_rqst *, u32 *,
struct nfsd3_attrstat *);
@@ -305,11 +331,17 @@ int nfs3svc_encode_pathconfres(struct sv
struct nfsd3_pathconfres *);
int nfs3svc_encode_commitres(struct svc_rqst *, u32 *,
struct nfsd3_commitres *);
+int nfs3svc_encode_getaclres(struct svc_rqst *, u32 *,
+ struct nfsd3_getaclres *);
+int nfs3svc_encode_setaclres(struct svc_rqst *, u32 *,
+ struct nfsd3_attrstat *);
int nfs3svc_release_fhandle(struct svc_rqst *, u32 *,
struct nfsd3_attrstat *);
int nfs3svc_release_fhandle2(struct svc_rqst *, u32 *,
struct nfsd3_fhandle_pair *);
+int nfs3svc_release_getacl(struct svc_rqst *rqstp, u32 *p,
+ struct nfsd3_getaclres *resp);
int nfs3svc_encode_entry(struct readdir_cd *, const char *name,
int namlen, loff_t offset, ino_t ino,
unsigned int);
Index: linux-2.6.11-rc5/include/linux/sunrpc/svc.h
===================================================================
--- linux-2.6.11-rc5.orig/include/linux/sunrpc/svc.h
+++ linux-2.6.11-rc5/include/linux/sunrpc/svc.h
@@ -185,6 +185,27 @@ xdr_ressize_check(struct svc_rqst *rqstp
return vec->iov_len <= PAGE_SIZE;
}
+#if 0
+static inline struct page *
+svc_take_arg_page(struct svc_rqst *rqstp)
+{
+ if (rqstp->rq_arghi <= rqstp->rq_argused)
+ return NULL;
+ return rqstp->rq_argpages[rqstp->rq_argused++];
+}
+#endif
+
+static inline struct page *
+svc_take_res_page(struct svc_rqst *rqstp)
+{
+ if (rqstp->rq_arghi <= rqstp->rq_argused)
+ return NULL;
+ rqstp->rq_arghi--;
+ rqstp->rq_respages[rqstp->rq_resused] =
+ rqstp->rq_argpages[rqstp->rq_arghi];
+ return rqstp->rq_respages[rqstp->rq_resused++];
+}
+
static inline int svc_take_page(struct svc_rqst *rqstp)
{
if (rqstp->rq_arghi <= rqstp->rq_argused)
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [nfsacl v2 15/16] ACL umask handling workaround in nfs client
2005-02-27 17:00 ` [nfsacl v2 15/16] ACL umask handling workaround in nfs client Andreas Gruenbacher
@ 2005-03-02 15:49 ` Andreas Gruenbacher
0 siblings, 0 replies; 21+ messages in thread
From: Andreas Gruenbacher @ 2005-03-02 15:49 UTC (permalink / raw)
To: linux-kernel
Cc: Neil Brown, Trond Myklebust, Olaf Kirch, Andries E. Brouwer,
Andrew Morton, Aurélien Francillon
[-- Attachment #1: Type: text/plain, Size: 673 bytes --]
Aurélien Francillon <aurel@naurel.org> found a bug in this patch. The
delta is:
Index: linux-2.6.11/fs/nfs/nfs3proc.c
===================================================================
--- linux-2.6.11.orig/fs/nfs/nfs3proc.c
+++ linux-2.6.11/fs/nfs/nfs3proc.c
@@ -423,6 +423,9 @@ exit:
if (!inode)
goto out;
status = nfs3_set_default_acl(dir, inode, mode);
+ if (status)
+ goto out;
+ return inode;
}
out:
return ERR_PTR(status);
Please find the fixed patch attached.
Regards,
--
Andreas Gruenbacher <agruen@suse.de>
SUSE Labs, SUSE LINUX GMBH
[-- Attachment #2: nfsacl-acl-umask-handling-workaround-in-nfs-client-3.patch --]
[-- Type: message/rfc822, Size: 4882 bytes --]
From: Andreas Gruenbacher <agruen@suse.de>
Subject: ACL umask handling workaround in nfs client
Date: Wed, 02 Mar 2005 16:47:48 +0100
Message-ID: <1109778468.22077.159.camel@winden.suse.de>
NFSv3 has no concept of a umask on the server side: The client applies
the umask locally, and sends the effective permissions to the server.
This behavior is wrong when files are created in a directory that has a
default ACL. In this case, the umask is supposed to be ignored, and
only the default ACL determines the file's effective permissions.
Usually its the server's task to conditionally apply the umask. But
since the server knows nothing about the umask, we have to do it on the
client side. This patch tries to fetch the parent directory's default
ACL before creating a new file, computes the appropriate create mode to
send to the server, and finally sets the new file's access and default
acl appropriately.
Many thanks to Buck Huppmann <buchk@pobox.com> for sending the initial
version of this patch, as well as for arguing why we need this change.
Signed-off-by: Andreas Gruenbacher <agruen@suse.de>
Acked-by: Olaf Kirch <okir@suse.de>
Index: linux-2.6.11/fs/nfs/nfs3proc.c
===================================================================
--- linux-2.6.11.orig/fs/nfs/nfs3proc.c
+++ linux-2.6.11/fs/nfs/nfs3proc.c
@@ -292,6 +292,38 @@ static int nfs3_proc_commit(struct nfs_w
return status;
}
+static int nfs3_set_default_acl(struct inode *dir, struct inode *inode,
+ mode_t mode)
+{
+#ifdef CONFIG_NFS_ACL
+ struct posix_acl *dfacl, *acl;
+ int error = 0;
+
+ dfacl = NFS_PROTO(dir)->getacl(dir, ACL_TYPE_DEFAULT);
+ if (IS_ERR(dfacl)) {
+ error = PTR_ERR(dfacl);
+ return (error == -EOPNOTSUPP) ? 0 : error;
+ }
+ if (!dfacl)
+ return 0;
+ acl = posix_acl_clone(dfacl, GFP_KERNEL);
+ error = -ENOMEM;
+ if (!acl)
+ goto out;
+ error = posix_acl_create_masq(acl, &mode);
+ if (error < 0)
+ goto out;
+ error = NFS_PROTO(inode)->setacls(inode, acl, S_ISDIR(inode->i_mode) ?
+ dfacl : NULL);
+out:
+ posix_acl_release(acl);
+ posix_acl_release(dfacl);
+ return error;
+#else
+ return 0;
+#endif
+}
+
/*
* Create a regular file.
* For now, we don't implement O_EXCL.
@@ -314,8 +346,12 @@ nfs3_proc_create(struct inode *dir, stru
.fh = &fhandle,
.fattr = &fattr
};
+ mode_t mode;
int status;
+ mode = sattr->ia_mode;
+ sattr->ia_mode &= ~current->fs->umask;
+
dprintk("NFS call create %s\n", dentry->d_name.name);
arg.createmode = NFS3_CREATE_UNCHECKED;
if (flags & O_EXCL) {
@@ -350,7 +386,6 @@ again:
exit:
dprintk("NFS reply create: %d\n", status);
-
if (status != 0)
goto out;
if (fhandle.size == 0 || !(fattr.valid & NFS_ATTR_FATTR)) {
@@ -384,9 +419,13 @@ exit:
if (status == 0) {
struct inode *inode;
inode = nfs_fhget(dir->i_sb, &fhandle, &fattr);
- if (inode)
- return inode;
status = -ENOMEM;
+ if (!inode)
+ goto out;
+ status = nfs3_set_default_acl(dir, inode, mode);
+ if (status)
+ goto out;
+ return inode;
}
out:
return ERR_PTR(status);
@@ -556,8 +595,12 @@ nfs3_proc_mkdir(struct inode *dir, struc
.fh = &fh,
.fattr = &fattr
};
+ mode_t mode;
int status;
+ mode = sattr->ia_mode;
+ sattr->ia_mode &= ~current->fs->umask;
+
dprintk("NFS call mkdir %s\n", dentry->d_name.name);
dir_attr.valid = 0;
fattr.valid = 0;
@@ -566,6 +609,8 @@ nfs3_proc_mkdir(struct inode *dir, struc
if (!status)
status = nfs_instantiate(dentry, &fh, &fattr);
dprintk("NFS reply mkdir: %d\n", status);
+ if (!status)
+ status = nfs3_set_default_acl(dir, dentry->d_inode, mode);
return status;
}
@@ -659,6 +704,7 @@ nfs3_proc_mknod(struct inode *dir, struc
.fh = &fh,
.fattr = &fattr
};
+ mode_t mode;
int status;
switch (sattr->ia_mode & S_IFMT) {
@@ -669,6 +715,9 @@ nfs3_proc_mknod(struct inode *dir, struc
default: return -EINVAL;
}
+ mode = sattr->ia_mode;
+ sattr->ia_mode &= ~current->fs->umask;
+
dprintk("NFS call mknod %s %u:%u\n", dentry->d_name.name,
MAJOR(rdev), MINOR(rdev));
dir_attr.valid = 0;
@@ -678,6 +727,8 @@ nfs3_proc_mknod(struct inode *dir, struc
if (!status)
status = nfs_instantiate(dentry, &fh, &fattr);
dprintk("NFS reply mknod: %d\n", status);
+ if (!status)
+ status = nfs3_set_default_acl(dir, dentry->d_inode, mode);
return status;
}
Index: linux-2.6.11/fs/nfs/inode.c
===================================================================
--- linux-2.6.11.orig/fs/nfs/inode.c
+++ linux-2.6.11/fs/nfs/inode.c
@@ -485,6 +485,8 @@ nfs_fill_super(struct super_block *sb, s
server->client_acl = clnt;
/* Initially assume the nfsacl program is supported */
server->flags |= NFSACL;
+ /* The nfs client applies the umask itself when needed. */
+ sb->s_flags |= MS_POSIXACL;
}
#endif
if (server->flags & NFS_MOUNT_VER3) {
^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [nfsacl v2 01/16] acl kconfig cleanup
[not found] ` <4225FAE8.80308@tomt.net>
@ 2005-03-02 17:49 ` Andreas Gruenbacher
0 siblings, 0 replies; 21+ messages in thread
From: Andreas Gruenbacher @ 2005-03-02 17:49 UTC (permalink / raw)
To: Andre Tomt; +Cc: linux-kernel
[-- Attachment #1: Type: text/plain, Size: 408 bytes --]
On Wed, 2005-03-02 at 18:42, Andre Tomt wrote:
> The Kconfig cleanup from Matt breaks compilation for me, on 2.6.11
> kernel.org release.
It's based on a patch by Matt, but all bugs are mine ;) The attached
patch went out privately before; I should have posted it here as well.
This should fix the problem.
Thanks for testing!
Regards,
--
Andreas Gruenbacher <agruen@suse.de>
SUSE Labs, SUSE LINUX GMBH
[-- Attachment #2: nfsacl-v2a-v3-delta.diff --]
[-- Type: text/x-patch, Size: 2680 bytes --]
diff -u linux-2.6.11-rc5/lib/Makefile linux-2.6.11-rc5/lib/Makefile
--- linux-2.6.11-rc5/lib/Makefile
+++ linux-2.6.11-rc5/lib/Makefile
@@ -5,7 +5,8 @@
lib-y := errno.o ctype.o string.o vsprintf.o cmdline.o \
bust_spinlocks.o rbtree.o radix-tree.o dump_stack.o \
kobject.o kref.o idr.o div64.o parser.o int_sqrt.o \
- bitmap.o extable.o kobject_uevent.o prio_tree.o sort.o
+ bitmap.o extable.o kobject_uevent.o prio_tree.o
+obj-y := sort.o
ifeq ($(CONFIG_DEBUG_KOBJECT),y)
CFLAGS_kobject.o += -DDEBUG
diff -u linux-2.6.11-rc5/fs/Kconfig linux-2.6.11-rc5/fs/Kconfig
--- linux-2.6.11-rc5/fs/Kconfig
+++ linux-2.6.11-rc5/fs/Kconfig
@@ -1405,6 +1405,7 @@
select LOCKD
select SUNRPC
select EXPORTFS
+ select NFS_ACL_SUPPORT if NFSD_ACL
help
If you want your Linux box to act as an NFS *server*, so that other
computers on your local network which support NFS can access certain
@@ -1438,7 +1439,6 @@
config NFSD_ACL
bool "NFS_ACL protocol extension"
depends on NFSD_V3
- select NFS_ACL_SUPPORT
help
Implement the NFS_ACL protocol extension for manipulating POSIX
Access Control Lists on exported file systems. The clients must
@@ -1446,7 +1446,7 @@
CONFIG_NFS_ACL option. If unsure, say N.
config NFS_ACL_SUPPORT
- bool
+ tristate
select FS_POSIX_ACL
config NFSD_V4
diff -u linux-2.6.11-rc5/fs/Kconfig linux-2.6.11-rc5/fs/Kconfig
--- linux-2.6.11-rc5/fs/Kconfig
+++ linux-2.6.11-rc5/fs/Kconfig
@@ -1320,6 +1320,7 @@
depends on INET
select LOCKD
select SUNRPC
+ select NFS_ACL_SUPPORT if NFS_ACL
help
If you are connected to some other (usually local) Unix computer
(using SLIP, PLIP, PPP or Ethernet) and want to mount files residing
@@ -1415,7 +1416,6 @@
select LOCKD
select SUNRPC
select EXPORTFS
- select NFS_ACL_SUPPORT if NFS_ACL
help
If you want your Linux box to act as an NFS *server*, so that other
computers on your local network which support NFS can access certain
diff -u linux-2.6.11-rc5/fs/nfs/nfs3proc.c linux-2.6.11-rc5/fs/nfs/nfs3proc.c
--- linux-2.6.11-rc5/fs/nfs/nfs3proc.c
+++ linux-2.6.11-rc5/fs/nfs/nfs3proc.c
@@ -1053,7 +1053,6 @@
.dentry_ops = &nfs_dentry_operations,
.file_inode_ops = &nfs3_file_inode_operations,
.dir_inode_ops = &nfs3_dir_inode_operations,
- .special_inode_ops = &nfs3_special_inode_operations,
.getroot = nfs3_proc_get_root,
.getattr = nfs3_proc_getattr,
.setattr = nfs3_proc_setattr,
@@ -1085,6 +1084,7 @@
.file_release = nfs_release,
.lock = nfs3_proc_lock,
#ifdef CONFIG_NFS_ACL
+ .special_inode_ops = &nfs3_special_inode_operations,
.getacl = nfs3_proc_getacl,
.setacl = nfs3_proc_setacl,
.setacls = nfs3_proc_setacls,
^ permalink raw reply [flat|nested] 21+ messages in thread
end of thread, other threads:[~2005-03-02 17:52 UTC | newest]
Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-02-27 16:59 [nfsacl v2 00/16] NFSACL protocol extension for NFSv3 Andreas Gruenbacher
2005-02-27 16:59 ` [nfsacl v2 01/16] acl kconfig cleanup Andreas Gruenbacher
[not found] ` <4225FAE8.80308@tomt.net>
2005-03-02 17:49 ` Andreas Gruenbacher
2005-02-27 16:59 ` [nfsacl v2 02/16] Qsort Andreas Gruenbacher
2005-02-27 22:54 ` Andreas Gruenbacher
2005-02-27 16:59 ` [nfsacl v2 03/16] Return -ENOSYS for RPC programs that are unavailable Andreas Gruenbacher
2005-02-27 16:59 ` [nfsacl v2 04/16] Add missing -EOPNOTSUPP => NFS3ERR_NOTSUPP mapping in nfsd Andreas Gruenbacher
2005-02-27 16:59 ` [nfsacl v2 05/16] Allow multiple programs to listen on the same port Andreas Gruenbacher
2005-02-27 17:00 ` [nfsacl v2 06/16] Allow multiple programs to share the same transport Andreas Gruenbacher
2005-02-27 17:00 ` [nfsacl v2 07/16] Lazy RPC receive buffer allocation Andreas Gruenbacher
2005-02-27 17:00 ` [nfsacl v2 08/16] Encode and decode arbitrary XDR arrays Andreas Gruenbacher
2005-02-27 17:00 ` [nfsacl v2 09/16] Add noacl nfs mount option Andreas Gruenbacher
2005-02-27 17:00 ` [nfsacl v2 10/16] Infrastructure and server side of nfsacl Andreas Gruenbacher
2005-02-27 22:56 ` Andreas Gruenbacher
2005-02-27 17:00 ` [nfsacl v2 11/16] Solaris nfsacl workaround Andreas Gruenbacher
2005-02-27 17:00 ` [nfsacl v2 12/16] nfs mknod cleanup Andreas Gruenbacher
2005-02-27 17:00 ` [nfsacl v2 13/16] nfs mkdir cleanup Andreas Gruenbacher
2005-02-27 17:00 ` [nfsacl v2 14/16] Client side of nfsacl Andreas Gruenbacher
2005-02-27 17:00 ` [nfsacl v2 15/16] ACL umask handling workaround in nfs client Andreas Gruenbacher
2005-03-02 15:49 ` Andreas Gruenbacher
2005-02-27 17:00 ` [nfsacl v2 16/16] Cache acls on the nfs client side Andreas Gruenbacher
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).