+ err = nfserrno(host_err);
+ goto out;
+}
+
+#if defined(CONFIG_NFSD_V2_ACL) || \
+ defined(CONFIG_NFSD_V3_ACL) || \
+ defined(CONFIG_NFSD_V4)
+static ssize_t nfsd_getxattr(struct dentry *dentry, char *key, void **buf)
+{
+ ssize_t buflen;
+
+ buflen = vfs_getxattr(dentry, key, NULL, 0);
+ if (buflen <= 0)
+ return buflen;
+
+ *buf = kmalloc(buflen, GFP_KERNEL);
+ if (!*buf)
+ return -ENOMEM;
+
+ return vfs_getxattr(dentry, key, *buf, buflen);
+}
+#endif
+
+#if defined(CONFIG_NFSD_V4)
+static int
+set_nfsv4_acl_one(struct dentry *dentry, struct posix_acl *pacl, char *key)
+{
+ int len;
+ size_t buflen;
+ char *buf = NULL;
+ int error = 0;
+
+ buflen = posix_acl_xattr_size(pacl->a_count);
+ buf = kmalloc(buflen, GFP_KERNEL);
+ error = -ENOMEM;
+ if (buf == NULL)
+ goto out;
+
+ len = posix_acl_to_xattr(pacl, buf, buflen);
+ if (len < 0) {
+ error = len;
+ goto out;
+ }
+
+ error = vfs_setxattr(dentry, key, buf, len, 0);
+out:
+ kfree(buf);
+ return error;
+}
+
+__be32
+nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
+ struct nfs4_acl *acl)
+{
+ __be32 error;
+ int host_error;
+ struct dentry *dentry;
+ struct inode *inode;
+ struct posix_acl *pacl = NULL, *dpacl = NULL;
+ unsigned int flags = 0;
+
+ /* Get inode */
+ error = fh_verify(rqstp, fhp, 0 /* S_IFREG */, MAY_SATTR);
+ if (error)
+ goto out;
+
+ dentry = fhp->fh_dentry;
+ inode = dentry->d_inode;
+ if (S_ISDIR(inode->i_mode))
+ flags = NFS4_ACL_DIR;
+
+ host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags);
+ if (host_error == -EINVAL) {
+ error = nfserr_attrnotsupp;
+ goto out;
+ } else if (host_error < 0)
+ goto out_nfserr;
+
+ host_error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS);
+ if (host_error < 0)
+ goto out_nfserr;
+
+ if (S_ISDIR(inode->i_mode)) {
+ host_error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT);
+ if (host_error < 0)
+ goto out_nfserr;
+ }
+
+ error = nfs_ok;
+
+out:
+ posix_acl_release(pacl);
+ posix_acl_release(dpacl);
+ return (error);
+out_nfserr:
+ error = nfserrno(host_error);