aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs_common/nfsacl.c
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruen@suse.de>2005-10-11 11:29:05 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-10-11 12:46:54 -0400
commit22c1ea44f0d33eda532883858b6cdabc5f265b66 (patch)
tree8af9c20a09e9ce9d497ec3db078d872b74a9c3ab /fs/nfs_common/nfsacl.c
parent19cba8abd6ca09527c194864ae651db65cbacfe1 (diff)
[PATCH] nfsacl: Solaris VxFS compatibility fix
Here is a compatibility fix between Linux and Solaris when used with VxFS filesystems: Solaris usually accepts acl entries in any order, but with VxFS it replies with NFSERR_INVAL when it sees a four-entry acl that is not in canonical form. It may also fail with other non-canonical acls -- I can't tell, because that case never triggers: We only send non-canonical acls when we fake up an ACL_MASK entry. Instead of adding fake ACL_MASK entries at the end, inserting them in the correct position makes Solaris+VxFS happy. The Linux client and server sides don't care about entry order. The three-entry-acl special case in which we need a fake ACL_MASK entry was handled in xdr_nfsace_encode. The patch moves this into nfsacl_encode. Signed-off-by: Andreas Gruenbacher <agruen@suse.de> Acked-by: Trond Myklebust <trond.myklebust@fys.uio.no> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/nfs_common/nfsacl.c')
-rw-r--r--fs/nfs_common/nfsacl.c70
1 files changed, 35 insertions, 35 deletions
diff --git a/fs/nfs_common/nfsacl.c b/fs/nfs_common/nfsacl.c
index 251e5a1bb1c4..0c2be8c0307d 100644
--- a/fs/nfs_common/nfsacl.c
+++ b/fs/nfs_common/nfsacl.c
@@ -48,43 +48,26 @@ xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem)
48 (struct nfsacl_encode_desc *) desc; 48 (struct nfsacl_encode_desc *) desc;
49 u32 *p = (u32 *) elem; 49 u32 *p = (u32 *) elem;
50 50
51 if (nfsacl_desc->count < nfsacl_desc->acl->a_count) { 51 struct posix_acl_entry *entry =
52 struct posix_acl_entry *entry = 52 &nfsacl_desc->acl->a_entries[nfsacl_desc->count++];
53 &nfsacl_desc->acl->a_entries[nfsacl_desc->count++];
54 53
55 *p++ = htonl(entry->e_tag | nfsacl_desc->typeflag); 54 *p++ = htonl(entry->e_tag | nfsacl_desc->typeflag);
56 switch(entry->e_tag) { 55 switch(entry->e_tag) {
57 case ACL_USER_OBJ: 56 case ACL_USER_OBJ:
58 *p++ = htonl(nfsacl_desc->uid); 57 *p++ = htonl(nfsacl_desc->uid);
59 break; 58 break;
60 case ACL_GROUP_OBJ: 59 case ACL_GROUP_OBJ:
61 *p++ = htonl(nfsacl_desc->gid); 60 *p++ = htonl(nfsacl_desc->gid);
62 break; 61 break;
63 case ACL_USER: 62 case ACL_USER:
64 case ACL_GROUP: 63 case ACL_GROUP:
65 *p++ = htonl(entry->e_id); 64 *p++ = htonl(entry->e_id);
66 break; 65 break;
67 default: /* Solaris depends on that! */ 66 default: /* Solaris depends on that! */
68 *p++ = 0; 67 *p++ = 0;
69 break; 68 break;
70 }
71 *p++ = htonl(entry->e_perm & S_IRWXO);
72 } else {
73 const struct posix_acl_entry *pa, *pe;
74 int group_obj_perm = ACL_READ|ACL_WRITE|ACL_EXECUTE;
75
76 FOREACH_ACL_ENTRY(pa, nfsacl_desc->acl, pe) {
77 if (pa->e_tag == ACL_GROUP_OBJ) {
78 group_obj_perm = pa->e_perm & S_IRWXO;
79 break;
80 }
81 }
82 /* fake up ACL_MASK entry */
83 *p++ = htonl(ACL_MASK | nfsacl_desc->typeflag);
84 *p++ = htonl(0);
85 *p++ = htonl(group_obj_perm);
86 } 69 }
87 70 *p++ = htonl(entry->e_perm & S_IRWXO);
88 return 0; 71 return 0;
89} 72}
90 73
@@ -105,11 +88,28 @@ nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
105 .gid = inode->i_gid, 88 .gid = inode->i_gid,
106 }; 89 };
107 int err; 90 int err;
91 struct posix_acl *acl2 = NULL;
108 92
109 if (entries > NFS_ACL_MAX_ENTRIES || 93 if (entries > NFS_ACL_MAX_ENTRIES ||
110 xdr_encode_word(buf, base, entries)) 94 xdr_encode_word(buf, base, entries))
111 return -EINVAL; 95 return -EINVAL;
96 if (encode_entries && acl && acl->a_count == 3) {
97 /* Fake up an ACL_MASK entry. */
98 acl2 = posix_acl_alloc(4, GFP_KERNEL);
99 if (!acl2)
100 return -ENOMEM;
101 /* Insert entries in canonical order: other orders seem
102 to confuse Solaris VxFS. */
103 acl2->a_entries[0] = acl->a_entries[0]; /* ACL_USER_OBJ */
104 acl2->a_entries[1] = acl->a_entries[1]; /* ACL_GROUP_OBJ */
105 acl2->a_entries[2] = acl->a_entries[1]; /* ACL_MASK */
106 acl2->a_entries[2].e_tag = ACL_MASK;
107 acl2->a_entries[3] = acl->a_entries[2]; /* ACL_OTHER */
108 nfsacl_desc.acl = acl2;
109 }
112 err = xdr_encode_array2(buf, base + 4, &nfsacl_desc.desc); 110 err = xdr_encode_array2(buf, base + 4, &nfsacl_desc.desc);
111 if (acl2)
112 posix_acl_release(acl2);
113 if (!err) 113 if (!err)
114 err = 8 + nfsacl_desc.desc.elem_size * 114 err = 8 + nfsacl_desc.desc.elem_size *
115 nfsacl_desc.desc.array_len; 115 nfsacl_desc.desc.array_len;