#include <linux/fsnotify.h>
 #include <linux/posix_acl.h>
 #include <linux/posix_acl_xattr.h>
-#ifdef CONFIG_NFSD_V4
 #include <linux/xattr.h>
+#ifdef CONFIG_NFSD_V4
 #include <linux/nfs4.h>
 #include <linux/nfs4_acl.h>
 #include <linux/nfsd_idmap.h>
        goto out;
 }
 
-#if defined(CONFIG_NFSD_V4)
+#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;
+       int error;
+
+       buflen = vfs_getxattr(dentry, key, NULL, 0);
+       if (buflen <= 0)
+               return buflen;
 
+       *buf = kmalloc(buflen, GFP_KERNEL);
+       if (!*buf)
+               return -ENOMEM;
+
+       error = vfs_getxattr(dentry, key, *buf, buflen);
+       if (error < 0)
+               return error;
+       return buflen;
+}
+#endif
+
+#if defined(CONFIG_NFSD_V4)
 static int
 set_nfsv4_acl_one(struct dentry *dentry, struct posix_acl *pacl, char *key)
 {
        size_t buflen;
        char *buf = NULL;
        int error = 0;
-       struct inode *inode = dentry->d_inode;
 
        buflen = posix_acl_xattr_size(pacl->a_count);
        buf = kmalloc(buflen, GFP_KERNEL);
                goto out;
        }
 
-       error = -EOPNOTSUPP;
-       if (inode->i_op && inode->i_op->setxattr) {
-               mutex_lock(&inode->i_mutex);
-               security_inode_setxattr(dentry, key, buf, len, 0);
-               error = inode->i_op->setxattr(dentry, key, buf, len, 0);
-               if (!error)
-                       security_inode_post_setxattr(dentry, key, buf, len, 0);
-               mutex_unlock(&inode->i_mutex);
-       }
+       error = vfs_setxattr(dentry, key, buf, len, 0);
 out:
        kfree(buf);
        return error;
 static struct posix_acl *
 _get_posix_acl(struct dentry *dentry, char *key)
 {
-       struct inode *inode = dentry->d_inode;
-       char *buf = NULL;
-       int buflen, error = 0;
+       void *buf = NULL;
        struct posix_acl *pacl = NULL;
+       int buflen;
 
-       error = -EOPNOTSUPP;
-       if (inode->i_op == NULL)
-               goto out_err;
-       if (inode->i_op->getxattr == NULL)
-               goto out_err;
-
-       error = security_inode_getxattr(dentry, key);
-       if (error)
-               goto out_err;
-
-       buflen = inode->i_op->getxattr(dentry, key, NULL, 0);
-       if (buflen <= 0) {
-               error = buflen < 0 ? buflen : -ENODATA;
-               goto out_err;
-       }
-
-       buf = kmalloc(buflen, GFP_KERNEL);
-       if (buf == NULL) {
-               error = -ENOMEM;
-               goto out_err;
-       }
-
-       error = inode->i_op->getxattr(dentry, key, buf, buflen);
-       if (error < 0)
-               goto out_err;
+       buflen = nfsd_getxattr(dentry, key, &buf);
+       if (!buflen)
+               buflen = -ENODATA;
+       if (buflen <= 0)
+               return ERR_PTR(buflen);
 
        pacl = posix_acl_from_xattr(buf, buflen);
- out:
        kfree(buf);
        return pacl;
- out_err:
-       pacl = ERR_PTR(error);
-       goto out;
 }
 
 int
        ssize_t size;
        struct posix_acl *acl;
 
-       if (!IS_POSIXACL(inode) || !inode->i_op || !inode->i_op->getxattr)
+       if (!IS_POSIXACL(inode))
+               return ERR_PTR(-EOPNOTSUPP);
+
+       switch (type) {
+       case ACL_TYPE_ACCESS:
+               name = POSIX_ACL_XATTR_ACCESS;
+               break;
+       case ACL_TYPE_DEFAULT:
+               name = POSIX_ACL_XATTR_DEFAULT;
+               break;
+       default:
                return ERR_PTR(-EOPNOTSUPP);
-       switch(type) {
-               case ACL_TYPE_ACCESS:
-                       name = POSIX_ACL_XATTR_ACCESS;
-                       break;
-               case ACL_TYPE_DEFAULT:
-                       name = POSIX_ACL_XATTR_DEFAULT;
-                       break;
-               default:
-                       return ERR_PTR(-EOPNOTSUPP);
        }
 
-       size = inode->i_op->getxattr(fhp->fh_dentry, name, NULL, 0);
+       size = nfsd_getxattr(fhp->fh_dentry, name, &value);
+       if (size < 0)
+               return ERR_PTR(size);
 
-       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;
 }
        } 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);
+               error = vfs_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);
+                       error = vfs_removexattr(fhp->fh_dentry, name);
                        if (error == -ENODATA)
                                error = 0;
                }
 
 #include <linux/fsnotify.h>
 #include <asm/uaccess.h>
 
+
+int
+vfs_setxattr(struct dentry *dentry, char *name, void *value,
+               size_t size, int flags)
+{
+       struct inode *inode = dentry->d_inode;
+       int error;
+
+       mutex_lock(&inode->i_mutex);
+       error = security_inode_setxattr(dentry, name, value, size, flags);
+       if (error)
+               goto out;
+       error = -EOPNOTSUPP;
+       if (inode->i_op->setxattr) {
+               error = inode->i_op->setxattr(dentry, name, value, size, flags);
+               if (!error) {
+                       fsnotify_xattr(dentry);
+                       security_inode_post_setxattr(dentry, name, value,
+                                                    size, flags);
+               }
+       } else if (!strncmp(name, XATTR_SECURITY_PREFIX,
+                               sizeof XATTR_SECURITY_PREFIX - 1)) {
+               const char *suffix = name + sizeof XATTR_SECURITY_PREFIX - 1;
+               error = security_inode_setsecurity(inode, suffix, value,
+                                                  size, flags);
+               if (!error)
+                       fsnotify_xattr(dentry);
+       }
+out:
+       mutex_unlock(&inode->i_mutex);
+       return error;
+}
+EXPORT_SYMBOL_GPL(vfs_setxattr);
+
+ssize_t
+vfs_getxattr(struct dentry *dentry, char *name, void *value, size_t size)
+{
+       struct inode *inode = dentry->d_inode;
+       int error;
+
+       error = security_inode_getxattr(dentry, name);
+       if (error)
+               return error;
+
+       if (inode->i_op->getxattr)
+               error = inode->i_op->getxattr(dentry, name, value, size);
+       else
+               error = -EOPNOTSUPP;
+
+       if (!strncmp(name, XATTR_SECURITY_PREFIX,
+                               sizeof XATTR_SECURITY_PREFIX - 1)) {
+               const char *suffix = name + sizeof XATTR_SECURITY_PREFIX - 1;
+               int ret = security_inode_getsecurity(inode, suffix, value,
+                                                    size, error);
+               /*
+                * Only overwrite the return value if a security module
+                * is actually active.
+                */
+               if (ret != -EOPNOTSUPP)
+                       error = ret;
+       }
+
+       return error;
+}
+EXPORT_SYMBOL_GPL(vfs_getxattr);
+
+int
+vfs_removexattr(struct dentry *dentry, char *name)
+{
+       struct inode *inode = dentry->d_inode;
+       int error;
+
+       if (!inode->i_op->removexattr)
+               return -EOPNOTSUPP;
+
+       error = security_inode_removexattr(dentry, name);
+       if (error)
+               return error;
+
+       mutex_lock(&inode->i_mutex);
+       error = inode->i_op->removexattr(dentry, name);
+       mutex_unlock(&inode->i_mutex);
+
+       if (!error)
+               fsnotify_xattr(dentry);
+       return error;
+}
+EXPORT_SYMBOL_GPL(vfs_removexattr);
+
+
 /*
  * Extended attribute SET operations
  */
                }
        }
 
-       mutex_lock(&d->d_inode->i_mutex);
-       error = security_inode_setxattr(d, kname, kvalue, size, flags);
-       if (error)
-               goto out;
-       error = -EOPNOTSUPP;
-       if (d->d_inode->i_op && d->d_inode->i_op->setxattr) {
-               error = d->d_inode->i_op->setxattr(d, kname, kvalue,
-                                                  size, flags);
-               if (!error) {
-                       fsnotify_xattr(d);
-                       security_inode_post_setxattr(d, kname, kvalue,
-                                                    size, flags);
-               }
-       } else if (!strncmp(kname, XATTR_SECURITY_PREFIX,
-                           sizeof XATTR_SECURITY_PREFIX - 1)) {
-               const char *suffix = kname + sizeof XATTR_SECURITY_PREFIX - 1;
-               error = security_inode_setsecurity(d->d_inode, suffix, kvalue,
-                                                  size, flags);
-               if (!error)
-                       fsnotify_xattr(d);
-       }
-out:
-       mutex_unlock(&d->d_inode->i_mutex);
+       error = vfs_setxattr(d, kname, kvalue, size, flags);
        kfree(kvalue);
        return error;
 }
                        return -ENOMEM;
        }
 
-       error = security_inode_getxattr(d, kname);
-       if (error)
-               goto out;
-       error = -EOPNOTSUPP;
-       if (d->d_inode->i_op && d->d_inode->i_op->getxattr)
-               error = d->d_inode->i_op->getxattr(d, kname, kvalue, size);
-
-       if (!strncmp(kname, XATTR_SECURITY_PREFIX,
-                    sizeof XATTR_SECURITY_PREFIX - 1)) {
-               const char *suffix = kname + sizeof XATTR_SECURITY_PREFIX - 1;
-               int rv = security_inode_getsecurity(d->d_inode, suffix, kvalue,
-                                                   size, error);
-               /* Security module active: overwrite error value */
-               if (rv != -EOPNOTSUPP)
-                       error = rv;
-       }
+       error = vfs_getxattr(d, kname, kvalue, size);
        if (error > 0) {
                if (size && copy_to_user(value, kvalue, error))
                        error = -EFAULT;
                   than XATTR_SIZE_MAX bytes. Not possible. */
                error = -E2BIG;
        }
-out:
        kfree(kvalue);
        return error;
 }
        if (error < 0)
                return error;
 
-       error = -EOPNOTSUPP;
-       if (d->d_inode->i_op && d->d_inode->i_op->removexattr) {
-               error = security_inode_removexattr(d, kname);
-               if (error)
-                       goto out;
-               mutex_lock(&d->d_inode->i_mutex);
-               error = d->d_inode->i_op->removexattr(d, kname);
-               mutex_unlock(&d->d_inode->i_mutex);
-               if (!error)
-                       fsnotify_xattr(d);
-       }
-out:
-       return error;
+       return vfs_removexattr(d, kname);
 }
 
 asmlinkage long