Commit 22c1ea44 authored by Andreas Gruenbacher's avatar Andreas Gruenbacher Committed by Linus Torvalds

[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: default avatarAndreas Gruenbacher <agruen@suse.de>
Acked-by: default avatarTrond Myklebust <trond.myklebust@fys.uio.no>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 19cba8ab
...@@ -48,7 +48,6 @@ xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem) ...@@ -48,7 +48,6 @@ xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem)
(struct nfsacl_encode_desc *) desc; (struct nfsacl_encode_desc *) desc;
u32 *p = (u32 *) elem; u32 *p = (u32 *) elem;
if (nfsacl_desc->count < nfsacl_desc->acl->a_count) {
struct posix_acl_entry *entry = struct posix_acl_entry *entry =
&nfsacl_desc->acl->a_entries[nfsacl_desc->count++]; &nfsacl_desc->acl->a_entries[nfsacl_desc->count++];
...@@ -69,22 +68,6 @@ xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem) ...@@ -69,22 +68,6 @@ xdr_nfsace_encode(struct xdr_array2_desc *desc, void *elem)
break; break;
} }
*p++ = htonl(entry->e_perm & S_IRWXO); *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; return 0;
} }
...@@ -105,11 +88,28 @@ nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode, ...@@ -105,11 +88,28 @@ nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode,
.gid = inode->i_gid, .gid = inode->i_gid,
}; };
int err; int err;
struct posix_acl *acl2 = NULL;
if (entries > NFS_ACL_MAX_ENTRIES || if (entries > NFS_ACL_MAX_ENTRIES ||
xdr_encode_word(buf, base, entries)) xdr_encode_word(buf, base, entries))
return -EINVAL; return -EINVAL;
if (encode_entries && acl && acl->a_count == 3) {
/* Fake up an ACL_MASK entry. */
acl2 = posix_acl_alloc(4, GFP_KERNEL);
if (!acl2)
return -ENOMEM;
/* Insert entries in canonical order: other orders seem
to confuse Solaris VxFS. */
acl2->a_entries[0] = acl->a_entries[0]; /* ACL_USER_OBJ */
acl2->a_entries[1] = acl->a_entries[1]; /* ACL_GROUP_OBJ */
acl2->a_entries[2] = acl->a_entries[1]; /* ACL_MASK */
acl2->a_entries[2].e_tag = ACL_MASK;
acl2->a_entries[3] = acl->a_entries[2]; /* ACL_OTHER */
nfsacl_desc.acl = acl2;
}
err = xdr_encode_array2(buf, base + 4, &nfsacl_desc.desc); err = xdr_encode_array2(buf, base + 4, &nfsacl_desc.desc);
if (acl2)
posix_acl_release(acl2);
if (!err) if (!err)
err = 8 + nfsacl_desc.desc.elem_size * err = 8 + nfsacl_desc.desc.elem_size *
nfsacl_desc.desc.array_len; nfsacl_desc.desc.array_len;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment