Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs: (28 commits) net/9p: Return error on read with NULL buffer 9p: Add datasync to client side TFSYNC/RFSYNC for dotl net/9p: Return error if we fail to encode protocol data fs/9p: Use generic_file_open with lookup_instantiate_filp fs/9p: Add missing iput in v9fs_vfs_lookup fs/9p: Use mknod 9p operation on create without open request net/9p: Add waitq to VirtIO transport. [net/9p]Serialize virtqueue operations to make VirtIO transport SMP safe. 9p: Implement TREADLINK operation for 9p2000.L 9p: Use V9FS_MAGIC in statfs 9p: Implement TGETLOCK 9p: Implement TLOCK [9p] Introduce client side TFSYNC/RFSYNC for dotl. [fs/9p] Add file_operations for cached mode in dotl protocol. fs/9p: Add access = client option to opt in acl evaluation. fs/9p: Implement create time inheritance fs/9p: Update ACL on chmod fs/9p: Implement setting posix acl fs/9p: Add xattr callbacks for POSIX ACL fs/9p: Implement POSIX ACL permission checking function ...
This commit is contained in:
@@ -111,7 +111,7 @@ OPTIONS
|
|||||||
This can be used to share devices/named pipes/sockets between
|
This can be used to share devices/named pipes/sockets between
|
||||||
hosts. This functionality will be expanded in later versions.
|
hosts. This functionality will be expanded in later versions.
|
||||||
|
|
||||||
access there are three access modes.
|
access there are four access modes.
|
||||||
user = if a user tries to access a file on v9fs
|
user = if a user tries to access a file on v9fs
|
||||||
filesystem for the first time, v9fs sends an
|
filesystem for the first time, v9fs sends an
|
||||||
attach command (Tattach) for that user.
|
attach command (Tattach) for that user.
|
||||||
@@ -120,6 +120,8 @@ OPTIONS
|
|||||||
the files on the mounted filesystem
|
the files on the mounted filesystem
|
||||||
any = v9fs does single attach and performs all
|
any = v9fs does single attach and performs all
|
||||||
operations as one user
|
operations as one user
|
||||||
|
client = ACL based access check on the 9p client
|
||||||
|
side for access validation
|
||||||
|
|
||||||
cachetag cache tag to use the specified persistent cache.
|
cachetag cache tag to use the specified persistent cache.
|
||||||
cache tags for existing cache sessions can be listed at
|
cache tags for existing cache sessions can be listed at
|
||||||
|
@@ -17,3 +17,16 @@ config 9P_FSCACHE
|
|||||||
Choose Y here to enable persistent, read-only local
|
Choose Y here to enable persistent, read-only local
|
||||||
caching support for 9p clients using FS-Cache
|
caching support for 9p clients using FS-Cache
|
||||||
|
|
||||||
|
|
||||||
|
config 9P_FS_POSIX_ACL
|
||||||
|
bool "9P POSIX Access Control Lists"
|
||||||
|
depends on 9P_FS
|
||||||
|
select FS_POSIX_ACL
|
||||||
|
help
|
||||||
|
POSIX Access Control Lists (ACLs) support permissions for users and
|
||||||
|
groups beyond the owner/group/world scheme.
|
||||||
|
|
||||||
|
To learn more about Access Control Lists, visit the POSIX ACLs for
|
||||||
|
Linux website <http://acl.bestbits.at/>.
|
||||||
|
|
||||||
|
If you don't know what Access Control Lists are, say N
|
||||||
|
@@ -13,3 +13,4 @@ obj-$(CONFIG_9P_FS) := 9p.o
|
|||||||
xattr_user.o
|
xattr_user.o
|
||||||
|
|
||||||
9p-$(CONFIG_9P_FSCACHE) += cache.o
|
9p-$(CONFIG_9P_FSCACHE) += cache.o
|
||||||
|
9p-$(CONFIG_9P_FS_POSIX_ACL) += acl.o
|
||||||
|
392
fs/9p/acl.c
Normal file
392
fs/9p/acl.c
Normal file
@@ -0,0 +1,392 @@
|
|||||||
|
/*
|
||||||
|
* Copyright IBM Corporation, 2010
|
||||||
|
* Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of version 2.1 of the GNU Lesser 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <net/9p/9p.h>
|
||||||
|
#include <net/9p/client.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/posix_acl_xattr.h>
|
||||||
|
#include "xattr.h"
|
||||||
|
#include "acl.h"
|
||||||
|
#include "v9fs_vfs.h"
|
||||||
|
#include "v9fs.h"
|
||||||
|
|
||||||
|
static struct posix_acl *__v9fs_get_acl(struct p9_fid *fid, char *name)
|
||||||
|
{
|
||||||
|
ssize_t size;
|
||||||
|
void *value = NULL;
|
||||||
|
struct posix_acl *acl = NULL;;
|
||||||
|
|
||||||
|
size = v9fs_fid_xattr_get(fid, name, NULL, 0);
|
||||||
|
if (size > 0) {
|
||||||
|
value = kzalloc(size, GFP_NOFS);
|
||||||
|
if (!value)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
size = v9fs_fid_xattr_get(fid, name, value, size);
|
||||||
|
if (size > 0) {
|
||||||
|
acl = posix_acl_from_xattr(value, size);
|
||||||
|
if (IS_ERR(acl))
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
} else if (size == -ENODATA || size == 0 ||
|
||||||
|
size == -ENOSYS || size == -EOPNOTSUPP) {
|
||||||
|
acl = NULL;
|
||||||
|
} else
|
||||||
|
acl = ERR_PTR(-EIO);
|
||||||
|
|
||||||
|
err_out:
|
||||||
|
kfree(value);
|
||||||
|
return acl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int v9fs_get_acl(struct inode *inode, struct p9_fid *fid)
|
||||||
|
{
|
||||||
|
int retval = 0;
|
||||||
|
struct posix_acl *pacl, *dacl;
|
||||||
|
struct v9fs_session_info *v9ses;
|
||||||
|
|
||||||
|
v9ses = v9fs_inode2v9ses(inode);
|
||||||
|
if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) {
|
||||||
|
set_cached_acl(inode, ACL_TYPE_DEFAULT, NULL);
|
||||||
|
set_cached_acl(inode, ACL_TYPE_ACCESS, NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/* get the default/access acl values and cache them */
|
||||||
|
dacl = __v9fs_get_acl(fid, POSIX_ACL_XATTR_DEFAULT);
|
||||||
|
pacl = __v9fs_get_acl(fid, POSIX_ACL_XATTR_ACCESS);
|
||||||
|
|
||||||
|
if (!IS_ERR(dacl) && !IS_ERR(pacl)) {
|
||||||
|
set_cached_acl(inode, ACL_TYPE_DEFAULT, dacl);
|
||||||
|
set_cached_acl(inode, ACL_TYPE_ACCESS, pacl);
|
||||||
|
posix_acl_release(dacl);
|
||||||
|
posix_acl_release(pacl);
|
||||||
|
} else
|
||||||
|
retval = -EIO;
|
||||||
|
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct posix_acl *v9fs_get_cached_acl(struct inode *inode, int type)
|
||||||
|
{
|
||||||
|
struct posix_acl *acl;
|
||||||
|
/*
|
||||||
|
* 9p Always cache the acl value when
|
||||||
|
* instantiating the inode (v9fs_inode_from_fid)
|
||||||
|
*/
|
||||||
|
acl = get_cached_acl(inode, type);
|
||||||
|
BUG_ON(acl == ACL_NOT_CACHED);
|
||||||
|
return acl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int v9fs_check_acl(struct inode *inode, int mask)
|
||||||
|
{
|
||||||
|
struct posix_acl *acl;
|
||||||
|
struct v9fs_session_info *v9ses;
|
||||||
|
|
||||||
|
v9ses = v9fs_inode2v9ses(inode);
|
||||||
|
if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) {
|
||||||
|
/*
|
||||||
|
* On access = client mode get the acl
|
||||||
|
* values from the server
|
||||||
|
*/
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
acl = v9fs_get_cached_acl(inode, ACL_TYPE_ACCESS);
|
||||||
|
|
||||||
|
if (IS_ERR(acl))
|
||||||
|
return PTR_ERR(acl);
|
||||||
|
if (acl) {
|
||||||
|
int error = posix_acl_permission(inode, acl, mask);
|
||||||
|
posix_acl_release(acl);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
return -EAGAIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int v9fs_set_acl(struct dentry *dentry, int type, struct posix_acl *acl)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
char *name;
|
||||||
|
size_t size;
|
||||||
|
void *buffer;
|
||||||
|
struct inode *inode = dentry->d_inode;
|
||||||
|
|
||||||
|
set_cached_acl(inode, type, acl);
|
||||||
|
/* Set a setxattr request to server */
|
||||||
|
size = posix_acl_xattr_size(acl->a_count);
|
||||||
|
buffer = kmalloc(size, GFP_KERNEL);
|
||||||
|
if (!buffer)
|
||||||
|
return -ENOMEM;
|
||||||
|
retval = posix_acl_to_xattr(acl, buffer, size);
|
||||||
|
if (retval < 0)
|
||||||
|
goto err_free_out;
|
||||||
|
switch (type) {
|
||||||
|
case ACL_TYPE_ACCESS:
|
||||||
|
name = POSIX_ACL_XATTR_ACCESS;
|
||||||
|
break;
|
||||||
|
case ACL_TYPE_DEFAULT:
|
||||||
|
name = POSIX_ACL_XATTR_DEFAULT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BUG();
|
||||||
|
}
|
||||||
|
retval = v9fs_xattr_set(dentry, name, buffer, size, 0);
|
||||||
|
err_free_out:
|
||||||
|
kfree(buffer);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int v9fs_acl_chmod(struct dentry *dentry)
|
||||||
|
{
|
||||||
|
int retval = 0;
|
||||||
|
struct posix_acl *acl, *clone;
|
||||||
|
struct inode *inode = dentry->d_inode;
|
||||||
|
|
||||||
|
if (S_ISLNK(inode->i_mode))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
acl = v9fs_get_cached_acl(inode, ACL_TYPE_ACCESS);
|
||||||
|
if (acl) {
|
||||||
|
clone = posix_acl_clone(acl, GFP_KERNEL);
|
||||||
|
posix_acl_release(acl);
|
||||||
|
if (!clone)
|
||||||
|
return -ENOMEM;
|
||||||
|
retval = posix_acl_chmod_masq(clone, inode->i_mode);
|
||||||
|
if (!retval)
|
||||||
|
retval = v9fs_set_acl(dentry, ACL_TYPE_ACCESS, clone);
|
||||||
|
posix_acl_release(clone);
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int v9fs_set_create_acl(struct dentry *dentry,
|
||||||
|
struct posix_acl *dpacl, struct posix_acl *pacl)
|
||||||
|
{
|
||||||
|
if (dpacl)
|
||||||
|
v9fs_set_acl(dentry, ACL_TYPE_DEFAULT, dpacl);
|
||||||
|
if (pacl)
|
||||||
|
v9fs_set_acl(dentry, ACL_TYPE_ACCESS, pacl);
|
||||||
|
posix_acl_release(dpacl);
|
||||||
|
posix_acl_release(pacl);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int v9fs_acl_mode(struct inode *dir, mode_t *modep,
|
||||||
|
struct posix_acl **dpacl, struct posix_acl **pacl)
|
||||||
|
{
|
||||||
|
int retval = 0;
|
||||||
|
mode_t mode = *modep;
|
||||||
|
struct posix_acl *acl = NULL;
|
||||||
|
|
||||||
|
if (!S_ISLNK(mode)) {
|
||||||
|
acl = v9fs_get_cached_acl(dir, ACL_TYPE_DEFAULT);
|
||||||
|
if (IS_ERR(acl))
|
||||||
|
return PTR_ERR(acl);
|
||||||
|
if (!acl)
|
||||||
|
mode &= ~current_umask();
|
||||||
|
}
|
||||||
|
if (acl) {
|
||||||
|
struct posix_acl *clone;
|
||||||
|
|
||||||
|
if (S_ISDIR(mode))
|
||||||
|
*dpacl = acl;
|
||||||
|
clone = posix_acl_clone(acl, GFP_NOFS);
|
||||||
|
retval = -ENOMEM;
|
||||||
|
if (!clone)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
retval = posix_acl_create_masq(clone, &mode);
|
||||||
|
if (retval < 0) {
|
||||||
|
posix_acl_release(clone);
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (retval > 0)
|
||||||
|
*pacl = clone;
|
||||||
|
}
|
||||||
|
*modep = mode;
|
||||||
|
return 0;
|
||||||
|
cleanup:
|
||||||
|
posix_acl_release(acl);
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static int v9fs_remote_get_acl(struct dentry *dentry, const char *name,
|
||||||
|
void *buffer, size_t size, int type)
|
||||||
|
{
|
||||||
|
char *full_name;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case ACL_TYPE_ACCESS:
|
||||||
|
full_name = POSIX_ACL_XATTR_ACCESS;
|
||||||
|
break;
|
||||||
|
case ACL_TYPE_DEFAULT:
|
||||||
|
full_name = POSIX_ACL_XATTR_DEFAULT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BUG();
|
||||||
|
}
|
||||||
|
return v9fs_xattr_get(dentry, full_name, buffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int v9fs_xattr_get_acl(struct dentry *dentry, const char *name,
|
||||||
|
void *buffer, size_t size, int type)
|
||||||
|
{
|
||||||
|
struct v9fs_session_info *v9ses;
|
||||||
|
struct posix_acl *acl;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
if (strcmp(name, "") != 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
v9ses = v9fs_inode2v9ses(dentry->d_inode);
|
||||||
|
/*
|
||||||
|
* We allow set/get/list of acl when access=client is not specified
|
||||||
|
*/
|
||||||
|
if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT)
|
||||||
|
return v9fs_remote_get_acl(dentry, name, buffer, size, type);
|
||||||
|
|
||||||
|
acl = v9fs_get_cached_acl(dentry->d_inode, type);
|
||||||
|
if (IS_ERR(acl))
|
||||||
|
return PTR_ERR(acl);
|
||||||
|
if (acl == NULL)
|
||||||
|
return -ENODATA;
|
||||||
|
error = posix_acl_to_xattr(acl, buffer, size);
|
||||||
|
posix_acl_release(acl);
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int v9fs_remote_set_acl(struct dentry *dentry, const char *name,
|
||||||
|
const void *value, size_t size,
|
||||||
|
int flags, int type)
|
||||||
|
{
|
||||||
|
char *full_name;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case ACL_TYPE_ACCESS:
|
||||||
|
full_name = POSIX_ACL_XATTR_ACCESS;
|
||||||
|
break;
|
||||||
|
case ACL_TYPE_DEFAULT:
|
||||||
|
full_name = POSIX_ACL_XATTR_DEFAULT;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BUG();
|
||||||
|
}
|
||||||
|
return v9fs_xattr_set(dentry, full_name, value, size, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int v9fs_xattr_set_acl(struct dentry *dentry, const char *name,
|
||||||
|
const void *value, size_t size,
|
||||||
|
int flags, int type)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
struct posix_acl *acl;
|
||||||
|
struct v9fs_session_info *v9ses;
|
||||||
|
struct inode *inode = dentry->d_inode;
|
||||||
|
|
||||||
|
if (strcmp(name, "") != 0)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
v9ses = v9fs_inode2v9ses(dentry->d_inode);
|
||||||
|
/*
|
||||||
|
* set the attribute on the remote. Without even looking at the
|
||||||
|
* xattr value. We leave it to the server to validate
|
||||||
|
*/
|
||||||
|
if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT)
|
||||||
|
return v9fs_remote_set_acl(dentry, name,
|
||||||
|
value, size, flags, type);
|
||||||
|
|
||||||
|
if (S_ISLNK(inode->i_mode))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
if (!is_owner_or_cap(inode))
|
||||||
|
return -EPERM;
|
||||||
|
if (value) {
|
||||||
|
/* update the cached acl value */
|
||||||
|
acl = posix_acl_from_xattr(value, size);
|
||||||
|
if (IS_ERR(acl))
|
||||||
|
return PTR_ERR(acl);
|
||||||
|
else if (acl) {
|
||||||
|
retval = posix_acl_valid(acl);
|
||||||
|
if (retval)
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
acl = NULL;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case ACL_TYPE_ACCESS:
|
||||||
|
name = POSIX_ACL_XATTR_ACCESS;
|
||||||
|
if (acl) {
|
||||||
|
mode_t mode = inode->i_mode;
|
||||||
|
retval = posix_acl_equiv_mode(acl, &mode);
|
||||||
|
if (retval < 0)
|
||||||
|
goto err_out;
|
||||||
|
else {
|
||||||
|
struct iattr iattr;
|
||||||
|
if (retval == 0) {
|
||||||
|
/*
|
||||||
|
* ACL can be represented
|
||||||
|
* by the mode bits. So don't
|
||||||
|
* update ACL.
|
||||||
|
*/
|
||||||
|
acl = NULL;
|
||||||
|
value = NULL;
|
||||||
|
size = 0;
|
||||||
|
}
|
||||||
|
/* Updte the mode bits */
|
||||||
|
iattr.ia_mode = ((mode & S_IALLUGO) |
|
||||||
|
(inode->i_mode & ~S_IALLUGO));
|
||||||
|
iattr.ia_valid = ATTR_MODE;
|
||||||
|
/* FIXME should we update ctime ?
|
||||||
|
* What is the following setxattr update the
|
||||||
|
* mode ?
|
||||||
|
*/
|
||||||
|
v9fs_vfs_setattr_dotl(dentry, &iattr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ACL_TYPE_DEFAULT:
|
||||||
|
name = POSIX_ACL_XATTR_DEFAULT;
|
||||||
|
if (!S_ISDIR(inode->i_mode)) {
|
||||||
|
retval = -EINVAL;
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BUG();
|
||||||
|
}
|
||||||
|
retval = v9fs_xattr_set(dentry, name, value, size, flags);
|
||||||
|
if (!retval)
|
||||||
|
set_cached_acl(inode, type, acl);
|
||||||
|
err_out:
|
||||||
|
posix_acl_release(acl);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct xattr_handler v9fs_xattr_acl_access_handler = {
|
||||||
|
.prefix = POSIX_ACL_XATTR_ACCESS,
|
||||||
|
.flags = ACL_TYPE_ACCESS,
|
||||||
|
.get = v9fs_xattr_get_acl,
|
||||||
|
.set = v9fs_xattr_set_acl,
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct xattr_handler v9fs_xattr_acl_default_handler = {
|
||||||
|
.prefix = POSIX_ACL_XATTR_DEFAULT,
|
||||||
|
.flags = ACL_TYPE_DEFAULT,
|
||||||
|
.get = v9fs_xattr_get_acl,
|
||||||
|
.set = v9fs_xattr_set_acl,
|
||||||
|
};
|
49
fs/9p/acl.h
Normal file
49
fs/9p/acl.h
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright IBM Corporation, 2010
|
||||||
|
* Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of version 2.1 of the GNU Lesser 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef FS_9P_ACL_H
|
||||||
|
#define FS_9P_ACL_H
|
||||||
|
|
||||||
|
#ifdef CONFIG_9P_FS_POSIX_ACL
|
||||||
|
extern int v9fs_get_acl(struct inode *, struct p9_fid *);
|
||||||
|
extern int v9fs_check_acl(struct inode *inode, int mask);
|
||||||
|
extern int v9fs_acl_chmod(struct dentry *);
|
||||||
|
extern int v9fs_set_create_acl(struct dentry *,
|
||||||
|
struct posix_acl *, struct posix_acl *);
|
||||||
|
extern int v9fs_acl_mode(struct inode *dir, mode_t *modep,
|
||||||
|
struct posix_acl **dpacl, struct posix_acl **pacl);
|
||||||
|
#else
|
||||||
|
#define v9fs_check_acl NULL
|
||||||
|
static inline int v9fs_get_acl(struct inode *inode, struct p9_fid *fid)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static inline int v9fs_acl_chmod(struct dentry *dentry)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static inline int v9fs_set_create_acl(struct dentry *dentry,
|
||||||
|
struct posix_acl *dpacl,
|
||||||
|
struct posix_acl *pacl)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
static inline int v9fs_acl_mode(struct inode *dir, mode_t *modep,
|
||||||
|
struct posix_acl **dpacl,
|
||||||
|
struct posix_acl **pacl)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
#endif /* FS_9P_XATTR_H */
|
@@ -149,6 +149,7 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry)
|
|||||||
switch (access) {
|
switch (access) {
|
||||||
case V9FS_ACCESS_SINGLE:
|
case V9FS_ACCESS_SINGLE:
|
||||||
case V9FS_ACCESS_USER:
|
case V9FS_ACCESS_USER:
|
||||||
|
case V9FS_ACCESS_CLIENT:
|
||||||
uid = current_fsuid();
|
uid = current_fsuid();
|
||||||
any = 0;
|
any = 0;
|
||||||
break;
|
break;
|
||||||
|
22
fs/9p/v9fs.c
22
fs/9p/v9fs.c
@@ -193,7 +193,17 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts)
|
|||||||
v9ses->flags |= V9FS_ACCESS_USER;
|
v9ses->flags |= V9FS_ACCESS_USER;
|
||||||
else if (strcmp(s, "any") == 0)
|
else if (strcmp(s, "any") == 0)
|
||||||
v9ses->flags |= V9FS_ACCESS_ANY;
|
v9ses->flags |= V9FS_ACCESS_ANY;
|
||||||
else {
|
else if (strcmp(s, "client") == 0) {
|
||||||
|
#ifdef CONFIG_9P_FS_POSIX_ACL
|
||||||
|
v9ses->flags |= V9FS_ACCESS_CLIENT;
|
||||||
|
#else
|
||||||
|
P9_DPRINTK(P9_DEBUG_ERROR,
|
||||||
|
"access=client option not supported\n");
|
||||||
|
kfree(s);
|
||||||
|
ret = -EINVAL;
|
||||||
|
goto free_and_return;
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
v9ses->flags |= V9FS_ACCESS_SINGLE;
|
v9ses->flags |= V9FS_ACCESS_SINGLE;
|
||||||
v9ses->uid = simple_strtoul(s, &e, 10);
|
v9ses->uid = simple_strtoul(s, &e, 10);
|
||||||
if (*e != '\0')
|
if (*e != '\0')
|
||||||
@@ -278,6 +288,16 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses,
|
|||||||
|
|
||||||
v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ;
|
v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ;
|
||||||
|
|
||||||
|
if (!v9fs_proto_dotl(v9ses) &&
|
||||||
|
((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_CLIENT)) {
|
||||||
|
/*
|
||||||
|
* We support ACCESS_CLIENT only for dotl.
|
||||||
|
* Fall back to ACCESS_USER
|
||||||
|
*/
|
||||||
|
v9ses->flags &= ~V9FS_ACCESS_MASK;
|
||||||
|
v9ses->flags |= V9FS_ACCESS_USER;
|
||||||
|
}
|
||||||
|
/*FIXME !! */
|
||||||
/* for legacy mode, fall back to V9FS_ACCESS_ANY */
|
/* for legacy mode, fall back to V9FS_ACCESS_ANY */
|
||||||
if (!(v9fs_proto_dotu(v9ses) || v9fs_proto_dotl(v9ses)) &&
|
if (!(v9fs_proto_dotu(v9ses) || v9fs_proto_dotl(v9ses)) &&
|
||||||
((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) {
|
((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) {
|
||||||
|
10
fs/9p/v9fs.h
10
fs/9p/v9fs.h
@@ -33,13 +33,17 @@
|
|||||||
*
|
*
|
||||||
* Session flags reflect options selected by users at mount time
|
* Session flags reflect options selected by users at mount time
|
||||||
*/
|
*/
|
||||||
|
#define V9FS_ACCESS_ANY (V9FS_ACCESS_SINGLE | \
|
||||||
|
V9FS_ACCESS_USER | \
|
||||||
|
V9FS_ACCESS_CLIENT)
|
||||||
|
#define V9FS_ACCESS_MASK V9FS_ACCESS_ANY
|
||||||
|
|
||||||
enum p9_session_flags {
|
enum p9_session_flags {
|
||||||
V9FS_PROTO_2000U = 0x01,
|
V9FS_PROTO_2000U = 0x01,
|
||||||
V9FS_PROTO_2000L = 0x02,
|
V9FS_PROTO_2000L = 0x02,
|
||||||
V9FS_ACCESS_SINGLE = 0x04,
|
V9FS_ACCESS_SINGLE = 0x04,
|
||||||
V9FS_ACCESS_USER = 0x08,
|
V9FS_ACCESS_USER = 0x08,
|
||||||
V9FS_ACCESS_ANY = 0x0C,
|
V9FS_ACCESS_CLIENT = 0x10
|
||||||
V9FS_ACCESS_MASK = 0x0C,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* possible values of ->cache */
|
/* possible values of ->cache */
|
||||||
@@ -113,8 +117,6 @@ void v9fs_session_close(struct v9fs_session_info *v9ses);
|
|||||||
void v9fs_session_cancel(struct v9fs_session_info *v9ses);
|
void v9fs_session_cancel(struct v9fs_session_info *v9ses);
|
||||||
void v9fs_session_begin_cancel(struct v9fs_session_info *v9ses);
|
void v9fs_session_begin_cancel(struct v9fs_session_info *v9ses);
|
||||||
|
|
||||||
#define V9FS_MAGIC 0x01021997
|
|
||||||
|
|
||||||
/* other default globals */
|
/* other default globals */
|
||||||
#define V9FS_PORT 564
|
#define V9FS_PORT 564
|
||||||
#define V9FS_DEFUSER "nobody"
|
#define V9FS_DEFUSER "nobody"
|
||||||
|
@@ -64,3 +64,7 @@ int v9fs_uflags2omode(int uflags, int extended);
|
|||||||
|
|
||||||
ssize_t v9fs_file_readn(struct file *, char *, char __user *, u32, u64);
|
ssize_t v9fs_file_readn(struct file *, char *, char __user *, u32, u64);
|
||||||
void v9fs_blank_wstat(struct p9_wstat *wstat);
|
void v9fs_blank_wstat(struct p9_wstat *wstat);
|
||||||
|
int v9fs_vfs_setattr_dotl(struct dentry *, struct iattr *);
|
||||||
|
int v9fs_file_fsync_dotl(struct file *filp, int datasync);
|
||||||
|
|
||||||
|
#define P9_LOCK_TIMEOUT (30*HZ)
|
||||||
|
@@ -154,10 +154,40 @@ static int v9fs_launder_page(struct page *page)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* v9fs_direct_IO - 9P address space operation for direct I/O
|
||||||
|
* @rw: direction (read or write)
|
||||||
|
* @iocb: target I/O control block
|
||||||
|
* @iov: array of vectors that define I/O buffer
|
||||||
|
* @pos: offset in file to begin the operation
|
||||||
|
* @nr_segs: size of iovec array
|
||||||
|
*
|
||||||
|
* The presence of v9fs_direct_IO() in the address space ops vector
|
||||||
|
* allowes open() O_DIRECT flags which would have failed otherwise.
|
||||||
|
*
|
||||||
|
* In the non-cached mode, we shunt off direct read and write requests before
|
||||||
|
* the VFS gets them, so this method should never be called.
|
||||||
|
*
|
||||||
|
* Direct IO is not 'yet' supported in the cached mode. Hence when
|
||||||
|
* this routine is called through generic_file_aio_read(), the read/write fails
|
||||||
|
* with an error.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
ssize_t v9fs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
|
||||||
|
loff_t pos, unsigned long nr_segs)
|
||||||
|
{
|
||||||
|
P9_DPRINTK(P9_DEBUG_VFS, "v9fs_direct_IO: v9fs_direct_IO (%s) "
|
||||||
|
"off/no(%lld/%lu) EINVAL\n",
|
||||||
|
iocb->ki_filp->f_path.dentry->d_name.name,
|
||||||
|
(long long) pos, nr_segs);
|
||||||
|
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
const struct address_space_operations v9fs_addr_operations = {
|
const struct address_space_operations v9fs_addr_operations = {
|
||||||
.readpage = v9fs_vfs_readpage,
|
.readpage = v9fs_vfs_readpage,
|
||||||
.readpages = v9fs_vfs_readpages,
|
.readpages = v9fs_vfs_readpages,
|
||||||
.releasepage = v9fs_release_page,
|
.releasepage = v9fs_release_page,
|
||||||
.invalidatepage = v9fs_invalidate_page,
|
.invalidatepage = v9fs_invalidate_page,
|
||||||
.launder_page = v9fs_launder_page,
|
.launder_page = v9fs_launder_page,
|
||||||
|
.direct_IO = v9fs_direct_IO,
|
||||||
};
|
};
|
||||||
|
@@ -242,7 +242,8 @@ static int v9fs_dir_readdir_dotl(struct file *filp, void *dirent,
|
|||||||
while (rdir->head < rdir->tail) {
|
while (rdir->head < rdir->tail) {
|
||||||
|
|
||||||
err = p9dirent_read(rdir->buf + rdir->head,
|
err = p9dirent_read(rdir->buf + rdir->head,
|
||||||
buflen - rdir->head, &curdirent,
|
rdir->tail - rdir->head,
|
||||||
|
&curdirent,
|
||||||
fid->clnt->proto_version);
|
fid->clnt->proto_version);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err);
|
P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err);
|
||||||
@@ -314,4 +315,5 @@ const struct file_operations v9fs_dir_operations_dotl = {
|
|||||||
.readdir = v9fs_dir_readdir_dotl,
|
.readdir = v9fs_dir_readdir_dotl,
|
||||||
.open = v9fs_file_open,
|
.open = v9fs_file_open,
|
||||||
.release = v9fs_dir_release,
|
.release = v9fs_dir_release,
|
||||||
|
.fsync = v9fs_file_fsync_dotl,
|
||||||
};
|
};
|
||||||
|
265
fs/9p/vfs_file.c
265
fs/9p/vfs_file.c
@@ -33,6 +33,7 @@
|
|||||||
#include <linux/inet.h>
|
#include <linux/inet.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/pagemap.h>
|
#include <linux/pagemap.h>
|
||||||
|
#include <linux/utsname.h>
|
||||||
#include <asm/uaccess.h>
|
#include <asm/uaccess.h>
|
||||||
#include <linux/idr.h>
|
#include <linux/idr.h>
|
||||||
#include <net/9p/9p.h>
|
#include <net/9p/9p.h>
|
||||||
@@ -44,6 +45,7 @@
|
|||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
|
|
||||||
static const struct file_operations v9fs_cached_file_operations;
|
static const struct file_operations v9fs_cached_file_operations;
|
||||||
|
static const struct file_operations v9fs_cached_file_operations_dotl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* v9fs_file_open - open a file (or directory)
|
* v9fs_file_open - open a file (or directory)
|
||||||
@@ -92,6 +94,8 @@ int v9fs_file_open(struct inode *inode, struct file *file)
|
|||||||
/* enable cached file options */
|
/* enable cached file options */
|
||||||
if(file->f_op == &v9fs_file_operations)
|
if(file->f_op == &v9fs_file_operations)
|
||||||
file->f_op = &v9fs_cached_file_operations;
|
file->f_op = &v9fs_cached_file_operations;
|
||||||
|
else if (file->f_op == &v9fs_file_operations_dotl)
|
||||||
|
file->f_op = &v9fs_cached_file_operations_dotl;
|
||||||
|
|
||||||
#ifdef CONFIG_9P_FSCACHE
|
#ifdef CONFIG_9P_FSCACHE
|
||||||
v9fs_cache_inode_set_cookie(inode, file);
|
v9fs_cache_inode_set_cookie(inode, file);
|
||||||
@@ -130,6 +134,206 @@ static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl)
|
||||||
|
{
|
||||||
|
struct p9_flock flock;
|
||||||
|
struct p9_fid *fid;
|
||||||
|
uint8_t status;
|
||||||
|
int res = 0;
|
||||||
|
unsigned char fl_type;
|
||||||
|
|
||||||
|
fid = filp->private_data;
|
||||||
|
BUG_ON(fid == NULL);
|
||||||
|
|
||||||
|
if ((fl->fl_flags & FL_POSIX) != FL_POSIX)
|
||||||
|
BUG();
|
||||||
|
|
||||||
|
res = posix_lock_file_wait(filp, fl);
|
||||||
|
if (res < 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* convert posix lock to p9 tlock args */
|
||||||
|
memset(&flock, 0, sizeof(flock));
|
||||||
|
flock.type = fl->fl_type;
|
||||||
|
flock.start = fl->fl_start;
|
||||||
|
if (fl->fl_end == OFFSET_MAX)
|
||||||
|
flock.length = 0;
|
||||||
|
else
|
||||||
|
flock.length = fl->fl_end - fl->fl_start + 1;
|
||||||
|
flock.proc_id = fl->fl_pid;
|
||||||
|
flock.client_id = utsname()->nodename;
|
||||||
|
if (IS_SETLKW(cmd))
|
||||||
|
flock.flags = P9_LOCK_FLAGS_BLOCK;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if its a blocked request and we get P9_LOCK_BLOCKED as the status
|
||||||
|
* for lock request, keep on trying
|
||||||
|
*/
|
||||||
|
for (;;) {
|
||||||
|
res = p9_client_lock_dotl(fid, &flock, &status);
|
||||||
|
if (res < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (status != P9_LOCK_BLOCKED)
|
||||||
|
break;
|
||||||
|
if (status == P9_LOCK_BLOCKED && !IS_SETLKW(cmd))
|
||||||
|
break;
|
||||||
|
schedule_timeout_interruptible(P9_LOCK_TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* map 9p status to VFS status */
|
||||||
|
switch (status) {
|
||||||
|
case P9_LOCK_SUCCESS:
|
||||||
|
res = 0;
|
||||||
|
break;
|
||||||
|
case P9_LOCK_BLOCKED:
|
||||||
|
res = -EAGAIN;
|
||||||
|
break;
|
||||||
|
case P9_LOCK_ERROR:
|
||||||
|
case P9_LOCK_GRACE:
|
||||||
|
res = -ENOLCK;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BUG();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* incase server returned error for lock request, revert
|
||||||
|
* it locally
|
||||||
|
*/
|
||||||
|
if (res < 0 && fl->fl_type != F_UNLCK) {
|
||||||
|
fl_type = fl->fl_type;
|
||||||
|
fl->fl_type = F_UNLCK;
|
||||||
|
res = posix_lock_file_wait(filp, fl);
|
||||||
|
fl->fl_type = fl_type;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int v9fs_file_getlock(struct file *filp, struct file_lock *fl)
|
||||||
|
{
|
||||||
|
struct p9_getlock glock;
|
||||||
|
struct p9_fid *fid;
|
||||||
|
int res = 0;
|
||||||
|
|
||||||
|
fid = filp->private_data;
|
||||||
|
BUG_ON(fid == NULL);
|
||||||
|
|
||||||
|
posix_test_lock(filp, fl);
|
||||||
|
/*
|
||||||
|
* if we have a conflicting lock locally, no need to validate
|
||||||
|
* with server
|
||||||
|
*/
|
||||||
|
if (fl->fl_type != F_UNLCK)
|
||||||
|
return res;
|
||||||
|
|
||||||
|
/* convert posix lock to p9 tgetlock args */
|
||||||
|
memset(&glock, 0, sizeof(glock));
|
||||||
|
glock.type = fl->fl_type;
|
||||||
|
glock.start = fl->fl_start;
|
||||||
|
if (fl->fl_end == OFFSET_MAX)
|
||||||
|
glock.length = 0;
|
||||||
|
else
|
||||||
|
glock.length = fl->fl_end - fl->fl_start + 1;
|
||||||
|
glock.proc_id = fl->fl_pid;
|
||||||
|
glock.client_id = utsname()->nodename;
|
||||||
|
|
||||||
|
res = p9_client_getlock_dotl(fid, &glock);
|
||||||
|
if (res < 0)
|
||||||
|
return res;
|
||||||
|
if (glock.type != F_UNLCK) {
|
||||||
|
fl->fl_type = glock.type;
|
||||||
|
fl->fl_start = glock.start;
|
||||||
|
if (glock.length == 0)
|
||||||
|
fl->fl_end = OFFSET_MAX;
|
||||||
|
else
|
||||||
|
fl->fl_end = glock.start + glock.length - 1;
|
||||||
|
fl->fl_pid = glock.proc_id;
|
||||||
|
} else
|
||||||
|
fl->fl_type = F_UNLCK;
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* v9fs_file_lock_dotl - lock a file (or directory)
|
||||||
|
* @filp: file to be locked
|
||||||
|
* @cmd: lock command
|
||||||
|
* @fl: file lock structure
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int v9fs_file_lock_dotl(struct file *filp, int cmd, struct file_lock *fl)
|
||||||
|
{
|
||||||
|
struct inode *inode = filp->f_path.dentry->d_inode;
|
||||||
|
int ret = -ENOLCK;
|
||||||
|
|
||||||
|
P9_DPRINTK(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %s\n", filp,
|
||||||
|
cmd, fl, filp->f_path.dentry->d_name.name);
|
||||||
|
|
||||||
|
/* No mandatory locks */
|
||||||
|
if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
|
||||||
|
goto out_err;
|
||||||
|
|
||||||
|
if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
|
||||||
|
filemap_write_and_wait(inode->i_mapping);
|
||||||
|
invalidate_mapping_pages(&inode->i_data, 0, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (IS_SETLK(cmd) || IS_SETLKW(cmd))
|
||||||
|
ret = v9fs_file_do_lock(filp, cmd, fl);
|
||||||
|
else if (IS_GETLK(cmd))
|
||||||
|
ret = v9fs_file_getlock(filp, fl);
|
||||||
|
else
|
||||||
|
ret = -EINVAL;
|
||||||
|
out_err:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* v9fs_file_flock_dotl - lock a file
|
||||||
|
* @filp: file to be locked
|
||||||
|
* @cmd: lock command
|
||||||
|
* @fl: file lock structure
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int v9fs_file_flock_dotl(struct file *filp, int cmd,
|
||||||
|
struct file_lock *fl)
|
||||||
|
{
|
||||||
|
struct inode *inode = filp->f_path.dentry->d_inode;
|
||||||
|
int ret = -ENOLCK;
|
||||||
|
|
||||||
|
P9_DPRINTK(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %s\n", filp,
|
||||||
|
cmd, fl, filp->f_path.dentry->d_name.name);
|
||||||
|
|
||||||
|
/* No mandatory locks */
|
||||||
|
if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
|
||||||
|
goto out_err;
|
||||||
|
|
||||||
|
if (!(fl->fl_flags & FL_FLOCK))
|
||||||
|
goto out_err;
|
||||||
|
|
||||||
|
if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
|
||||||
|
filemap_write_and_wait(inode->i_mapping);
|
||||||
|
invalidate_mapping_pages(&inode->i_data, 0, -1);
|
||||||
|
}
|
||||||
|
/* Convert flock to posix lock */
|
||||||
|
fl->fl_owner = (fl_owner_t)filp;
|
||||||
|
fl->fl_start = 0;
|
||||||
|
fl->fl_end = OFFSET_MAX;
|
||||||
|
fl->fl_flags |= FL_POSIX;
|
||||||
|
fl->fl_flags ^= FL_FLOCK;
|
||||||
|
|
||||||
|
if (IS_SETLK(cmd) | IS_SETLKW(cmd))
|
||||||
|
ret = v9fs_file_do_lock(filp, cmd, fl);
|
||||||
|
else
|
||||||
|
ret = -EINVAL;
|
||||||
|
out_err:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* v9fs_file_readn - read from a file
|
* v9fs_file_readn - read from a file
|
||||||
* @filp: file pointer to read
|
* @filp: file pointer to read
|
||||||
@@ -219,7 +423,9 @@ static ssize_t
|
|||||||
v9fs_file_write(struct file *filp, const char __user * data,
|
v9fs_file_write(struct file *filp, const char __user * data,
|
||||||
size_t count, loff_t * offset)
|
size_t count, loff_t * offset)
|
||||||
{
|
{
|
||||||
int n, rsize, total = 0;
|
ssize_t retval;
|
||||||
|
size_t total = 0;
|
||||||
|
int n;
|
||||||
struct p9_fid *fid;
|
struct p9_fid *fid;
|
||||||
struct p9_client *clnt;
|
struct p9_client *clnt;
|
||||||
struct inode *inode = filp->f_path.dentry->d_inode;
|
struct inode *inode = filp->f_path.dentry->d_inode;
|
||||||
@@ -232,14 +438,19 @@ v9fs_file_write(struct file *filp, const char __user * data,
|
|||||||
fid = filp->private_data;
|
fid = filp->private_data;
|
||||||
clnt = fid->clnt;
|
clnt = fid->clnt;
|
||||||
|
|
||||||
rsize = fid->iounit ? fid->iounit : clnt->msize - P9_IOHDRSZ;
|
retval = generic_write_checks(filp, &origin, &count, 0);
|
||||||
|
if (retval)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
retval = -EINVAL;
|
||||||
|
if ((ssize_t) count < 0)
|
||||||
|
goto out;
|
||||||
|
retval = 0;
|
||||||
|
if (!count)
|
||||||
|
goto out;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (count < rsize)
|
n = p9_client_write(fid, NULL, data+total, origin+total, count);
|
||||||
rsize = count;
|
|
||||||
|
|
||||||
n = p9_client_write(fid, NULL, data+total, origin+total,
|
|
||||||
rsize);
|
|
||||||
if (n <= 0)
|
if (n <= 0)
|
||||||
break;
|
break;
|
||||||
count -= n;
|
count -= n;
|
||||||
@@ -258,9 +469,11 @@ v9fs_file_write(struct file *filp, const char __user * data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (n < 0)
|
if (n < 0)
|
||||||
return n;
|
retval = n;
|
||||||
|
else
|
||||||
return total;
|
retval = total;
|
||||||
|
out:
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int v9fs_file_fsync(struct file *filp, int datasync)
|
static int v9fs_file_fsync(struct file *filp, int datasync)
|
||||||
@@ -278,6 +491,20 @@ static int v9fs_file_fsync(struct file *filp, int datasync)
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int v9fs_file_fsync_dotl(struct file *filp, int datasync)
|
||||||
|
{
|
||||||
|
struct p9_fid *fid;
|
||||||
|
int retval;
|
||||||
|
|
||||||
|
P9_DPRINTK(P9_DEBUG_VFS, "v9fs_file_fsync_dotl: filp %p datasync %x\n",
|
||||||
|
filp, datasync);
|
||||||
|
|
||||||
|
fid = filp->private_data;
|
||||||
|
|
||||||
|
retval = p9_client_fsync(fid, datasync);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct file_operations v9fs_cached_file_operations = {
|
static const struct file_operations v9fs_cached_file_operations = {
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
.read = do_sync_read,
|
.read = do_sync_read,
|
||||||
@@ -290,6 +517,19 @@ static const struct file_operations v9fs_cached_file_operations = {
|
|||||||
.fsync = v9fs_file_fsync,
|
.fsync = v9fs_file_fsync,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct file_operations v9fs_cached_file_operations_dotl = {
|
||||||
|
.llseek = generic_file_llseek,
|
||||||
|
.read = do_sync_read,
|
||||||
|
.aio_read = generic_file_aio_read,
|
||||||
|
.write = v9fs_file_write,
|
||||||
|
.open = v9fs_file_open,
|
||||||
|
.release = v9fs_dir_release,
|
||||||
|
.lock = v9fs_file_lock_dotl,
|
||||||
|
.flock = v9fs_file_flock_dotl,
|
||||||
|
.mmap = generic_file_readonly_mmap,
|
||||||
|
.fsync = v9fs_file_fsync_dotl,
|
||||||
|
};
|
||||||
|
|
||||||
const struct file_operations v9fs_file_operations = {
|
const struct file_operations v9fs_file_operations = {
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
.read = v9fs_file_read,
|
.read = v9fs_file_read,
|
||||||
@@ -307,7 +547,8 @@ const struct file_operations v9fs_file_operations_dotl = {
|
|||||||
.write = v9fs_file_write,
|
.write = v9fs_file_write,
|
||||||
.open = v9fs_file_open,
|
.open = v9fs_file_open,
|
||||||
.release = v9fs_dir_release,
|
.release = v9fs_dir_release,
|
||||||
.lock = v9fs_file_lock,
|
.lock = v9fs_file_lock_dotl,
|
||||||
|
.flock = v9fs_file_flock_dotl,
|
||||||
.mmap = generic_file_readonly_mmap,
|
.mmap = generic_file_readonly_mmap,
|
||||||
.fsync = v9fs_file_fsync,
|
.fsync = v9fs_file_fsync_dotl,
|
||||||
};
|
};
|
||||||
|
@@ -36,6 +36,7 @@
|
|||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/xattr.h>
|
#include <linux/xattr.h>
|
||||||
|
#include <linux/posix_acl.h>
|
||||||
#include <net/9p/9p.h>
|
#include <net/9p/9p.h>
|
||||||
#include <net/9p/client.h>
|
#include <net/9p/client.h>
|
||||||
|
|
||||||
@@ -44,6 +45,7 @@
|
|||||||
#include "fid.h"
|
#include "fid.h"
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "xattr.h"
|
#include "xattr.h"
|
||||||
|
#include "acl.h"
|
||||||
|
|
||||||
static const struct inode_operations v9fs_dir_inode_operations;
|
static const struct inode_operations v9fs_dir_inode_operations;
|
||||||
static const struct inode_operations v9fs_dir_inode_operations_dotu;
|
static const struct inode_operations v9fs_dir_inode_operations_dotu;
|
||||||
@@ -53,6 +55,10 @@ static const struct inode_operations v9fs_file_inode_operations_dotl;
|
|||||||
static const struct inode_operations v9fs_symlink_inode_operations;
|
static const struct inode_operations v9fs_symlink_inode_operations;
|
||||||
static const struct inode_operations v9fs_symlink_inode_operations_dotl;
|
static const struct inode_operations v9fs_symlink_inode_operations_dotl;
|
||||||
|
|
||||||
|
static int
|
||||||
|
v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode,
|
||||||
|
dev_t rdev);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* unixmode2p9mode - convert unix mode bits to plan 9
|
* unixmode2p9mode - convert unix mode bits to plan 9
|
||||||
* @v9ses: v9fs session information
|
* @v9ses: v9fs session information
|
||||||
@@ -500,6 +506,11 @@ v9fs_inode_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid,
|
|||||||
v9fs_vcookie_set_qid(ret, &st->qid);
|
v9fs_vcookie_set_qid(ret, &st->qid);
|
||||||
v9fs_cache_inode_get_cookie(ret);
|
v9fs_cache_inode_get_cookie(ret);
|
||||||
#endif
|
#endif
|
||||||
|
err = v9fs_get_acl(ret, fid);
|
||||||
|
if (err) {
|
||||||
|
iput(ret);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
kfree(st);
|
kfree(st);
|
||||||
return ret;
|
return ret;
|
||||||
error:
|
error:
|
||||||
@@ -553,13 +564,6 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir)
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
v9fs_open_created(struct inode *inode, struct file *file)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* v9fs_create - Create a file
|
* v9fs_create - Create a file
|
||||||
* @v9ses: session information
|
* @v9ses: session information
|
||||||
@@ -655,29 +659,37 @@ error:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
static int
|
static int
|
||||||
v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int mode,
|
v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode,
|
||||||
struct nameidata *nd)
|
struct nameidata *nd)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
char *name = NULL;
|
char *name = NULL;
|
||||||
gid_t gid;
|
gid_t gid;
|
||||||
int flags;
|
int flags;
|
||||||
|
mode_t mode;
|
||||||
struct v9fs_session_info *v9ses;
|
struct v9fs_session_info *v9ses;
|
||||||
struct p9_fid *fid = NULL;
|
struct p9_fid *fid = NULL;
|
||||||
struct p9_fid *dfid, *ofid;
|
struct p9_fid *dfid, *ofid;
|
||||||
struct file *filp;
|
struct file *filp;
|
||||||
struct p9_qid qid;
|
struct p9_qid qid;
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
|
struct posix_acl *pacl = NULL, *dacl = NULL;
|
||||||
|
|
||||||
v9ses = v9fs_inode2v9ses(dir);
|
v9ses = v9fs_inode2v9ses(dir);
|
||||||
if (nd && nd->flags & LOOKUP_OPEN)
|
if (nd && nd->flags & LOOKUP_OPEN)
|
||||||
flags = nd->intent.open.flags - 1;
|
flags = nd->intent.open.flags - 1;
|
||||||
else
|
else {
|
||||||
flags = O_RDWR;
|
/*
|
||||||
|
* create call without LOOKUP_OPEN is due
|
||||||
|
* to mknod of regular files. So use mknod
|
||||||
|
* operation.
|
||||||
|
*/
|
||||||
|
return v9fs_vfs_mknod_dotl(dir, dentry, omode, 0);
|
||||||
|
}
|
||||||
|
|
||||||
name = (char *) dentry->d_name.name;
|
name = (char *) dentry->d_name.name;
|
||||||
P9_DPRINTK(P9_DEBUG_VFS, "v9fs_vfs_create_dotl: name:%s flags:0x%x "
|
P9_DPRINTK(P9_DEBUG_VFS, "v9fs_vfs_create_dotl: name:%s flags:0x%x "
|
||||||
"mode:0x%x\n", name, flags, mode);
|
"mode:0x%x\n", name, flags, omode);
|
||||||
|
|
||||||
dfid = v9fs_fid_lookup(dentry->d_parent);
|
dfid = v9fs_fid_lookup(dentry->d_parent);
|
||||||
if (IS_ERR(dfid)) {
|
if (IS_ERR(dfid)) {
|
||||||
@@ -695,6 +707,15 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int mode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
gid = v9fs_get_fsgid_for_create(dir);
|
gid = v9fs_get_fsgid_for_create(dir);
|
||||||
|
|
||||||
|
mode = omode;
|
||||||
|
/* Update mode based on ACL value */
|
||||||
|
err = v9fs_acl_mode(dir, &mode, &dacl, &pacl);
|
||||||
|
if (err) {
|
||||||
|
P9_DPRINTK(P9_DEBUG_VFS,
|
||||||
|
"Failed to get acl values in creat %d\n", err);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
err = p9_client_create_dotl(ofid, name, flags, mode, gid, &qid);
|
err = p9_client_create_dotl(ofid, name, flags, mode, gid, &qid);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
P9_DPRINTK(P9_DEBUG_VFS,
|
P9_DPRINTK(P9_DEBUG_VFS,
|
||||||
@@ -702,46 +723,52 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int mode,
|
|||||||
err);
|
err);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
/* instantiate inode and assign the unopened fid to the dentry */
|
||||||
/* No need to populate the inode if we are not opening the file AND
|
if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE ||
|
||||||
* not in cached mode.
|
(nd && nd->flags & LOOKUP_OPEN)) {
|
||||||
*/
|
|
||||||
if (!v9ses->cache && !(nd && nd->flags & LOOKUP_OPEN)) {
|
|
||||||
/* Not in cached mode. No need to populate inode with stat */
|
|
||||||
dentry->d_op = &v9fs_dentry_operations;
|
|
||||||
p9_client_clunk(ofid);
|
|
||||||
d_instantiate(dentry, NULL);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Now walk from the parent so we can get an unopened fid. */
|
|
||||||
fid = p9_client_walk(dfid, 1, &name, 1);
|
fid = p9_client_walk(dfid, 1, &name, 1);
|
||||||
if (IS_ERR(fid)) {
|
if (IS_ERR(fid)) {
|
||||||
err = PTR_ERR(fid);
|
err = PTR_ERR(fid);
|
||||||
P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
|
P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n",
|
||||||
|
err);
|
||||||
fid = NULL;
|
fid = NULL;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* instantiate inode and assign the unopened fid to dentry */
|
|
||||||
inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
|
inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
|
||||||
if (IS_ERR(inode)) {
|
if (IS_ERR(inode)) {
|
||||||
err = PTR_ERR(inode);
|
err = PTR_ERR(inode);
|
||||||
P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err);
|
P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n",
|
||||||
|
err);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (v9ses->cache)
|
|
||||||
dentry->d_op = &v9fs_cached_dentry_operations;
|
dentry->d_op = &v9fs_cached_dentry_operations;
|
||||||
else
|
|
||||||
dentry->d_op = &v9fs_dentry_operations;
|
|
||||||
d_instantiate(dentry, inode);
|
d_instantiate(dentry, inode);
|
||||||
err = v9fs_fid_add(dentry, fid);
|
err = v9fs_fid_add(dentry, fid);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto error;
|
goto error;
|
||||||
|
/* The fid would get clunked via a dput */
|
||||||
|
fid = NULL;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Not in cached mode. No need to populate
|
||||||
|
* inode with stat. We need to get an inode
|
||||||
|
* so that we can set the acl with dentry
|
||||||
|
*/
|
||||||
|
inode = v9fs_get_inode(dir->i_sb, mode);
|
||||||
|
if (IS_ERR(inode)) {
|
||||||
|
err = PTR_ERR(inode);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
dentry->d_op = &v9fs_dentry_operations;
|
||||||
|
d_instantiate(dentry, inode);
|
||||||
|
}
|
||||||
|
/* Now set the ACL based on the default value */
|
||||||
|
v9fs_set_create_acl(dentry, dacl, pacl);
|
||||||
|
|
||||||
/* if we are opening a file, assign the open fid to the file */
|
/* if we are opening a file, assign the open fid to the file */
|
||||||
if (nd && nd->flags & LOOKUP_OPEN) {
|
if (nd && nd->flags & LOOKUP_OPEN) {
|
||||||
filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created);
|
filp = lookup_instantiate_filp(nd, dentry, generic_file_open);
|
||||||
if (IS_ERR(filp)) {
|
if (IS_ERR(filp)) {
|
||||||
p9_client_clunk(ofid);
|
p9_client_clunk(ofid);
|
||||||
return PTR_ERR(filp);
|
return PTR_ERR(filp);
|
||||||
@@ -800,7 +827,7 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode,
|
|||||||
|
|
||||||
/* if we are opening a file, assign the open fid to the file */
|
/* if we are opening a file, assign the open fid to the file */
|
||||||
if (nd && nd->flags & LOOKUP_OPEN) {
|
if (nd && nd->flags & LOOKUP_OPEN) {
|
||||||
filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created);
|
filp = lookup_instantiate_filp(nd, dentry, generic_file_open);
|
||||||
if (IS_ERR(filp)) {
|
if (IS_ERR(filp)) {
|
||||||
err = PTR_ERR(filp);
|
err = PTR_ERR(filp);
|
||||||
goto error;
|
goto error;
|
||||||
@@ -859,23 +886,28 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int v9fs_vfs_mkdir_dotl(struct inode *dir, struct dentry *dentry,
|
static int v9fs_vfs_mkdir_dotl(struct inode *dir,
|
||||||
int mode)
|
struct dentry *dentry, int omode)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
struct v9fs_session_info *v9ses;
|
struct v9fs_session_info *v9ses;
|
||||||
struct p9_fid *fid = NULL, *dfid = NULL;
|
struct p9_fid *fid = NULL, *dfid = NULL;
|
||||||
gid_t gid;
|
gid_t gid;
|
||||||
char *name;
|
char *name;
|
||||||
|
mode_t mode;
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
struct p9_qid qid;
|
struct p9_qid qid;
|
||||||
struct dentry *dir_dentry;
|
struct dentry *dir_dentry;
|
||||||
|
struct posix_acl *dacl = NULL, *pacl = NULL;
|
||||||
|
|
||||||
P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name);
|
P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name);
|
||||||
err = 0;
|
err = 0;
|
||||||
v9ses = v9fs_inode2v9ses(dir);
|
v9ses = v9fs_inode2v9ses(dir);
|
||||||
|
|
||||||
mode |= S_IFDIR;
|
omode |= S_IFDIR;
|
||||||
|
if (dir->i_mode & S_ISGID)
|
||||||
|
omode |= S_ISGID;
|
||||||
|
|
||||||
dir_dentry = v9fs_dentry_from_dir_inode(dir);
|
dir_dentry = v9fs_dentry_from_dir_inode(dir);
|
||||||
dfid = v9fs_fid_lookup(dir_dentry);
|
dfid = v9fs_fid_lookup(dir_dentry);
|
||||||
if (IS_ERR(dfid)) {
|
if (IS_ERR(dfid)) {
|
||||||
@@ -886,11 +918,14 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir, struct dentry *dentry,
|
|||||||
}
|
}
|
||||||
|
|
||||||
gid = v9fs_get_fsgid_for_create(dir);
|
gid = v9fs_get_fsgid_for_create(dir);
|
||||||
if (gid < 0) {
|
mode = omode;
|
||||||
P9_DPRINTK(P9_DEBUG_VFS, "v9fs_get_fsgid_for_create failed\n");
|
/* Update mode based on ACL value */
|
||||||
|
err = v9fs_acl_mode(dir, &mode, &dacl, &pacl);
|
||||||
|
if (err) {
|
||||||
|
P9_DPRINTK(P9_DEBUG_VFS,
|
||||||
|
"Failed to get acl values in mkdir %d\n", err);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
name = (char *) dentry->d_name.name;
|
name = (char *) dentry->d_name.name;
|
||||||
err = p9_client_mkdir_dotl(dfid, name, mode, gid, &qid);
|
err = p9_client_mkdir_dotl(dfid, name, mode, gid, &qid);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
@@ -920,7 +955,23 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir, struct dentry *dentry,
|
|||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto error;
|
goto error;
|
||||||
fid = NULL;
|
fid = NULL;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Not in cached mode. No need to populate
|
||||||
|
* inode with stat. We need to get an inode
|
||||||
|
* so that we can set the acl with dentry
|
||||||
|
*/
|
||||||
|
inode = v9fs_get_inode(dir->i_sb, mode);
|
||||||
|
if (IS_ERR(inode)) {
|
||||||
|
err = PTR_ERR(inode);
|
||||||
|
goto error;
|
||||||
}
|
}
|
||||||
|
dentry->d_op = &v9fs_dentry_operations;
|
||||||
|
d_instantiate(dentry, inode);
|
||||||
|
}
|
||||||
|
/* Now set the ACL based on the default value */
|
||||||
|
v9fs_set_create_acl(dentry, dacl, pacl);
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if (fid)
|
if (fid)
|
||||||
p9_client_clunk(fid);
|
p9_client_clunk(fid);
|
||||||
@@ -979,7 +1030,7 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
|
|||||||
|
|
||||||
result = v9fs_fid_add(dentry, fid);
|
result = v9fs_fid_add(dentry, fid);
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
goto error;
|
goto error_iput;
|
||||||
|
|
||||||
inst_out:
|
inst_out:
|
||||||
if (v9ses->cache)
|
if (v9ses->cache)
|
||||||
@@ -990,6 +1041,8 @@ inst_out:
|
|||||||
d_add(dentry, inode);
|
d_add(dentry, inode);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
error_iput:
|
||||||
|
iput(inode);
|
||||||
error:
|
error:
|
||||||
p9_client_clunk(fid);
|
p9_client_clunk(fid);
|
||||||
|
|
||||||
@@ -1237,7 +1290,7 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
|
int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
|
||||||
{
|
{
|
||||||
int retval;
|
int retval;
|
||||||
struct v9fs_session_info *v9ses;
|
struct v9fs_session_info *v9ses;
|
||||||
@@ -1279,6 +1332,12 @@ static int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
|
|||||||
|
|
||||||
setattr_copy(dentry->d_inode, iattr);
|
setattr_copy(dentry->d_inode, iattr);
|
||||||
mark_inode_dirty(dentry->d_inode);
|
mark_inode_dirty(dentry->d_inode);
|
||||||
|
if (iattr->ia_valid & ATTR_MODE) {
|
||||||
|
/* We also want to update ACL when we update mode bits */
|
||||||
|
retval = v9fs_acl_chmod(dentry);
|
||||||
|
if (retval < 0)
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1473,7 +1532,7 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
|
|||||||
if (IS_ERR(fid))
|
if (IS_ERR(fid))
|
||||||
return PTR_ERR(fid);
|
return PTR_ERR(fid);
|
||||||
|
|
||||||
if (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses))
|
if (!v9fs_proto_dotu(v9ses))
|
||||||
return -EBADF;
|
return -EBADF;
|
||||||
|
|
||||||
st = p9_client_stat(fid);
|
st = p9_client_stat(fid);
|
||||||
@@ -1616,11 +1675,6 @@ v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry,
|
|||||||
|
|
||||||
gid = v9fs_get_fsgid_for_create(dir);
|
gid = v9fs_get_fsgid_for_create(dir);
|
||||||
|
|
||||||
if (gid < 0) {
|
|
||||||
P9_DPRINTK(P9_DEBUG_VFS, "v9fs_get_egid failed %d\n", gid);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Server doesn't alter fid on TSYMLINK. Hence no need to clone it. */
|
/* Server doesn't alter fid on TSYMLINK. Hence no need to clone it. */
|
||||||
err = p9_client_symlink(dfid, name, (char *)symname, gid, &qid);
|
err = p9_client_symlink(dfid, name, (char *)symname, gid, &qid);
|
||||||
|
|
||||||
@@ -1855,21 +1909,23 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int mode,
|
v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode,
|
||||||
dev_t rdev)
|
dev_t rdev)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
char *name;
|
char *name;
|
||||||
|
mode_t mode;
|
||||||
struct v9fs_session_info *v9ses;
|
struct v9fs_session_info *v9ses;
|
||||||
struct p9_fid *fid = NULL, *dfid = NULL;
|
struct p9_fid *fid = NULL, *dfid = NULL;
|
||||||
struct inode *inode;
|
struct inode *inode;
|
||||||
gid_t gid;
|
gid_t gid;
|
||||||
struct p9_qid qid;
|
struct p9_qid qid;
|
||||||
struct dentry *dir_dentry;
|
struct dentry *dir_dentry;
|
||||||
|
struct posix_acl *dacl = NULL, *pacl = NULL;
|
||||||
|
|
||||||
P9_DPRINTK(P9_DEBUG_VFS,
|
P9_DPRINTK(P9_DEBUG_VFS,
|
||||||
" %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino,
|
" %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino,
|
||||||
dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev));
|
dentry->d_name.name, omode, MAJOR(rdev), MINOR(rdev));
|
||||||
|
|
||||||
if (!new_valid_dev(rdev))
|
if (!new_valid_dev(rdev))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -1885,11 +1941,14 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int mode,
|
|||||||
}
|
}
|
||||||
|
|
||||||
gid = v9fs_get_fsgid_for_create(dir);
|
gid = v9fs_get_fsgid_for_create(dir);
|
||||||
if (gid < 0) {
|
mode = omode;
|
||||||
P9_DPRINTK(P9_DEBUG_VFS, "v9fs_get_fsgid_for_create failed\n");
|
/* Update mode based on ACL value */
|
||||||
|
err = v9fs_acl_mode(dir, &mode, &dacl, &pacl);
|
||||||
|
if (err) {
|
||||||
|
P9_DPRINTK(P9_DEBUG_VFS,
|
||||||
|
"Failed to get acl values in mknod %d\n", err);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
name = (char *) dentry->d_name.name;
|
name = (char *) dentry->d_name.name;
|
||||||
|
|
||||||
err = p9_client_mknod_dotl(dfid, name, mode, rdev, gid, &qid);
|
err = p9_client_mknod_dotl(dfid, name, mode, rdev, gid, &qid);
|
||||||
@@ -1933,13 +1992,68 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int mode,
|
|||||||
dentry->d_op = &v9fs_dentry_operations;
|
dentry->d_op = &v9fs_dentry_operations;
|
||||||
d_instantiate(dentry, inode);
|
d_instantiate(dentry, inode);
|
||||||
}
|
}
|
||||||
|
/* Now set the ACL based on the default value */
|
||||||
|
v9fs_set_create_acl(dentry, dacl, pacl);
|
||||||
error:
|
error:
|
||||||
if (fid)
|
if (fid)
|
||||||
p9_client_clunk(fid);
|
p9_client_clunk(fid);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
v9fs_vfs_readlink_dotl(struct dentry *dentry, char *buffer, int buflen)
|
||||||
|
{
|
||||||
|
int retval;
|
||||||
|
struct p9_fid *fid;
|
||||||
|
char *target = NULL;
|
||||||
|
|
||||||
|
P9_DPRINTK(P9_DEBUG_VFS, " %s\n", dentry->d_name.name);
|
||||||
|
retval = -EPERM;
|
||||||
|
fid = v9fs_fid_lookup(dentry);
|
||||||
|
if (IS_ERR(fid))
|
||||||
|
return PTR_ERR(fid);
|
||||||
|
|
||||||
|
retval = p9_client_readlink(fid, &target);
|
||||||
|
if (retval < 0)
|
||||||
|
return retval;
|
||||||
|
|
||||||
|
strncpy(buffer, target, buflen);
|
||||||
|
P9_DPRINTK(P9_DEBUG_VFS, "%s -> %s\n", dentry->d_name.name, buffer);
|
||||||
|
|
||||||
|
retval = strnlen(buffer, buflen);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* v9fs_vfs_follow_link_dotl - follow a symlink path
|
||||||
|
* @dentry: dentry for symlink
|
||||||
|
* @nd: nameidata
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void *
|
||||||
|
v9fs_vfs_follow_link_dotl(struct dentry *dentry, struct nameidata *nd)
|
||||||
|
{
|
||||||
|
int len = 0;
|
||||||
|
char *link = __getname();
|
||||||
|
|
||||||
|
P9_DPRINTK(P9_DEBUG_VFS, "%s n", dentry->d_name.name);
|
||||||
|
|
||||||
|
if (!link)
|
||||||
|
link = ERR_PTR(-ENOMEM);
|
||||||
|
else {
|
||||||
|
len = v9fs_vfs_readlink_dotl(dentry, link, PATH_MAX);
|
||||||
|
if (len < 0) {
|
||||||
|
__putname(link);
|
||||||
|
link = ERR_PTR(len);
|
||||||
|
} else
|
||||||
|
link[min(len, PATH_MAX-1)] = 0;
|
||||||
|
}
|
||||||
|
nd_set_link(nd, link);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct inode_operations v9fs_dir_inode_operations_dotu = {
|
static const struct inode_operations v9fs_dir_inode_operations_dotu = {
|
||||||
.create = v9fs_vfs_create,
|
.create = v9fs_vfs_create,
|
||||||
.lookup = v9fs_vfs_lookup,
|
.lookup = v9fs_vfs_lookup,
|
||||||
@@ -1970,7 +2084,7 @@ static const struct inode_operations v9fs_dir_inode_operations_dotl = {
|
|||||||
.getxattr = generic_getxattr,
|
.getxattr = generic_getxattr,
|
||||||
.removexattr = generic_removexattr,
|
.removexattr = generic_removexattr,
|
||||||
.listxattr = v9fs_listxattr,
|
.listxattr = v9fs_listxattr,
|
||||||
|
.check_acl = v9fs_check_acl,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct inode_operations v9fs_dir_inode_operations = {
|
static const struct inode_operations v9fs_dir_inode_operations = {
|
||||||
@@ -1997,6 +2111,7 @@ static const struct inode_operations v9fs_file_inode_operations_dotl = {
|
|||||||
.getxattr = generic_getxattr,
|
.getxattr = generic_getxattr,
|
||||||
.removexattr = generic_removexattr,
|
.removexattr = generic_removexattr,
|
||||||
.listxattr = v9fs_listxattr,
|
.listxattr = v9fs_listxattr,
|
||||||
|
.check_acl = v9fs_check_acl,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct inode_operations v9fs_symlink_inode_operations = {
|
static const struct inode_operations v9fs_symlink_inode_operations = {
|
||||||
@@ -2008,8 +2123,8 @@ static const struct inode_operations v9fs_symlink_inode_operations = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const struct inode_operations v9fs_symlink_inode_operations_dotl = {
|
static const struct inode_operations v9fs_symlink_inode_operations_dotl = {
|
||||||
.readlink = generic_readlink,
|
.readlink = v9fs_vfs_readlink_dotl,
|
||||||
.follow_link = v9fs_vfs_follow_link,
|
.follow_link = v9fs_vfs_follow_link_dotl,
|
||||||
.put_link = v9fs_vfs_put_link,
|
.put_link = v9fs_vfs_put_link,
|
||||||
.getattr = v9fs_vfs_getattr_dotl,
|
.getattr = v9fs_vfs_getattr_dotl,
|
||||||
.setattr = v9fs_vfs_setattr_dotl,
|
.setattr = v9fs_vfs_setattr_dotl,
|
||||||
|
@@ -39,6 +39,7 @@
|
|||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/statfs.h>
|
#include <linux/statfs.h>
|
||||||
|
#include <linux/magic.h>
|
||||||
#include <net/9p/9p.h>
|
#include <net/9p/9p.h>
|
||||||
#include <net/9p/client.h>
|
#include <net/9p/client.h>
|
||||||
|
|
||||||
@@ -46,6 +47,7 @@
|
|||||||
#include "v9fs_vfs.h"
|
#include "v9fs_vfs.h"
|
||||||
#include "fid.h"
|
#include "fid.h"
|
||||||
#include "xattr.h"
|
#include "xattr.h"
|
||||||
|
#include "acl.h"
|
||||||
|
|
||||||
static const struct super_operations v9fs_super_ops, v9fs_super_ops_dotl;
|
static const struct super_operations v9fs_super_ops, v9fs_super_ops_dotl;
|
||||||
|
|
||||||
@@ -88,6 +90,11 @@ v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses,
|
|||||||
sb->s_flags = flags | MS_ACTIVE | MS_SYNCHRONOUS | MS_DIRSYNC |
|
sb->s_flags = flags | MS_ACTIVE | MS_SYNCHRONOUS | MS_DIRSYNC |
|
||||||
MS_NOATIME;
|
MS_NOATIME;
|
||||||
|
|
||||||
|
#ifdef CONFIG_9P_FS_POSIX_ACL
|
||||||
|
if ((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_CLIENT)
|
||||||
|
sb->s_flags |= MS_POSIXACL;
|
||||||
|
#endif
|
||||||
|
|
||||||
save_mount_options(sb, data);
|
save_mount_options(sb, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,7 +156,6 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
|
|||||||
goto release_sb;
|
goto release_sb;
|
||||||
}
|
}
|
||||||
sb->s_root = root;
|
sb->s_root = root;
|
||||||
|
|
||||||
if (v9fs_proto_dotl(v9ses)) {
|
if (v9fs_proto_dotl(v9ses)) {
|
||||||
struct p9_stat_dotl *st = NULL;
|
struct p9_stat_dotl *st = NULL;
|
||||||
st = p9_client_getattr_dotl(fid, P9_STATS_BASIC);
|
st = p9_client_getattr_dotl(fid, P9_STATS_BASIC);
|
||||||
@@ -174,7 +180,9 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags,
|
|||||||
p9stat_free(st);
|
p9stat_free(st);
|
||||||
kfree(st);
|
kfree(st);
|
||||||
}
|
}
|
||||||
|
retval = v9fs_get_acl(inode, fid);
|
||||||
|
if (retval)
|
||||||
|
goto release_sb;
|
||||||
v9fs_fid_add(root, fid);
|
v9fs_fid_add(root, fid);
|
||||||
|
|
||||||
P9_DPRINTK(P9_DEBUG_VFS, " simple set mount, return 0\n");
|
P9_DPRINTK(P9_DEBUG_VFS, " simple set mount, return 0\n");
|
||||||
@@ -249,7 +257,7 @@ static int v9fs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||||||
if (v9fs_proto_dotl(v9ses)) {
|
if (v9fs_proto_dotl(v9ses)) {
|
||||||
res = p9_client_statfs(fid, &rs);
|
res = p9_client_statfs(fid, &rs);
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
buf->f_type = rs.type;
|
buf->f_type = V9FS_MAGIC;
|
||||||
buf->f_bsize = rs.bsize;
|
buf->f_bsize = rs.bsize;
|
||||||
buf->f_blocks = rs.blocks;
|
buf->f_blocks = rs.blocks;
|
||||||
buf->f_bfree = rs.bfree;
|
buf->f_bfree = rs.bfree;
|
||||||
|
@@ -21,30 +21,13 @@
|
|||||||
#include "fid.h"
|
#include "fid.h"
|
||||||
#include "xattr.h"
|
#include "xattr.h"
|
||||||
|
|
||||||
/*
|
ssize_t v9fs_fid_xattr_get(struct p9_fid *fid, const char *name,
|
||||||
* v9fs_xattr_get()
|
|
||||||
*
|
|
||||||
* Copy an extended attribute into the buffer
|
|
||||||
* provided, or compute the buffer size required.
|
|
||||||
* Buffer is NULL to compute the size of the buffer required.
|
|
||||||
*
|
|
||||||
* Returns a negative error number on failure, or the number of bytes
|
|
||||||
* used / required on success.
|
|
||||||
*/
|
|
||||||
ssize_t v9fs_xattr_get(struct dentry *dentry, const char *name,
|
|
||||||
void *buffer, size_t buffer_size)
|
void *buffer, size_t buffer_size)
|
||||||
{
|
{
|
||||||
ssize_t retval;
|
ssize_t retval;
|
||||||
int msize, read_count;
|
int msize, read_count;
|
||||||
u64 offset = 0, attr_size;
|
u64 offset = 0, attr_size;
|
||||||
struct p9_fid *fid, *attr_fid;
|
struct p9_fid *attr_fid;
|
||||||
|
|
||||||
P9_DPRINTK(P9_DEBUG_VFS, "%s: name = %s value_len = %zu\n",
|
|
||||||
__func__, name, buffer_size);
|
|
||||||
|
|
||||||
fid = v9fs_fid_lookup(dentry);
|
|
||||||
if (IS_ERR(fid))
|
|
||||||
return PTR_ERR(fid);
|
|
||||||
|
|
||||||
attr_fid = p9_client_xattrwalk(fid, name, &attr_size);
|
attr_fid = p9_client_xattrwalk(fid, name, &attr_size);
|
||||||
if (IS_ERR(attr_fid)) {
|
if (IS_ERR(attr_fid)) {
|
||||||
@@ -88,6 +71,31 @@ error:
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* v9fs_xattr_get()
|
||||||
|
*
|
||||||
|
* Copy an extended attribute into the buffer
|
||||||
|
* provided, or compute the buffer size required.
|
||||||
|
* Buffer is NULL to compute the size of the buffer required.
|
||||||
|
*
|
||||||
|
* Returns a negative error number on failure, or the number of bytes
|
||||||
|
* used / required on success.
|
||||||
|
*/
|
||||||
|
ssize_t v9fs_xattr_get(struct dentry *dentry, const char *name,
|
||||||
|
void *buffer, size_t buffer_size)
|
||||||
|
{
|
||||||
|
struct p9_fid *fid;
|
||||||
|
|
||||||
|
P9_DPRINTK(P9_DEBUG_VFS, "%s: name = %s value_len = %zu\n",
|
||||||
|
__func__, name, buffer_size);
|
||||||
|
fid = v9fs_fid_lookup(dentry);
|
||||||
|
if (IS_ERR(fid))
|
||||||
|
return PTR_ERR(fid);
|
||||||
|
|
||||||
|
return v9fs_fid_xattr_get(fid, name, buffer, buffer_size);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* v9fs_xattr_set()
|
* v9fs_xattr_set()
|
||||||
*
|
*
|
||||||
@@ -156,5 +164,9 @@ ssize_t v9fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
|
|||||||
|
|
||||||
const struct xattr_handler *v9fs_xattr_handlers[] = {
|
const struct xattr_handler *v9fs_xattr_handlers[] = {
|
||||||
&v9fs_xattr_user_handler,
|
&v9fs_xattr_user_handler,
|
||||||
|
#ifdef CONFIG_9P_FS_POSIX_ACL
|
||||||
|
&v9fs_xattr_acl_access_handler,
|
||||||
|
&v9fs_xattr_acl_default_handler,
|
||||||
|
#endif
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
@@ -15,10 +15,16 @@
|
|||||||
#define FS_9P_XATTR_H
|
#define FS_9P_XATTR_H
|
||||||
|
|
||||||
#include <linux/xattr.h>
|
#include <linux/xattr.h>
|
||||||
|
#include <net/9p/9p.h>
|
||||||
|
#include <net/9p/client.h>
|
||||||
|
|
||||||
extern const struct xattr_handler *v9fs_xattr_handlers[];
|
extern const struct xattr_handler *v9fs_xattr_handlers[];
|
||||||
extern struct xattr_handler v9fs_xattr_user_handler;
|
extern struct xattr_handler v9fs_xattr_user_handler;
|
||||||
|
extern const struct xattr_handler v9fs_xattr_acl_access_handler;
|
||||||
|
extern const struct xattr_handler v9fs_xattr_acl_default_handler;
|
||||||
|
|
||||||
|
extern ssize_t v9fs_fid_xattr_get(struct p9_fid *, const char *,
|
||||||
|
void *, size_t);
|
||||||
extern ssize_t v9fs_xattr_get(struct dentry *, const char *,
|
extern ssize_t v9fs_xattr_get(struct dentry *, const char *,
|
||||||
void *, size_t);
|
void *, size_t);
|
||||||
extern int v9fs_xattr_set(struct dentry *, const char *,
|
extern int v9fs_xattr_set(struct dentry *, const char *,
|
||||||
|
@@ -57,5 +57,6 @@
|
|||||||
|
|
||||||
#define DEVPTS_SUPER_MAGIC 0x1cd1
|
#define DEVPTS_SUPER_MAGIC 0x1cd1
|
||||||
#define SOCKFS_MAGIC 0x534F434B
|
#define SOCKFS_MAGIC 0x534F434B
|
||||||
|
#define V9FS_MAGIC 0x01021997
|
||||||
|
|
||||||
#endif /* __LINUX_MAGIC_H__ */
|
#endif /* __LINUX_MAGIC_H__ */
|
||||||
|
@@ -86,6 +86,8 @@ do { \
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* enum p9_msg_t - 9P message types
|
* enum p9_msg_t - 9P message types
|
||||||
|
* @P9_TLERROR: not used
|
||||||
|
* @P9_RLERROR: response for any failed request for 9P2000.L
|
||||||
* @P9_TSTATFS: file system status request
|
* @P9_TSTATFS: file system status request
|
||||||
* @P9_RSTATFS: file system status response
|
* @P9_RSTATFS: file system status response
|
||||||
* @P9_TSYMLINK: make symlink request
|
* @P9_TSYMLINK: make symlink request
|
||||||
@@ -137,6 +139,8 @@ do { \
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
enum p9_msg_t {
|
enum p9_msg_t {
|
||||||
|
P9_TLERROR = 6,
|
||||||
|
P9_RLERROR,
|
||||||
P9_TSTATFS = 8,
|
P9_TSTATFS = 8,
|
||||||
P9_RSTATFS,
|
P9_RSTATFS,
|
||||||
P9_TLOPEN = 12,
|
P9_TLOPEN = 12,
|
||||||
@@ -149,6 +153,8 @@ enum p9_msg_t {
|
|||||||
P9_RMKNOD,
|
P9_RMKNOD,
|
||||||
P9_TRENAME = 20,
|
P9_TRENAME = 20,
|
||||||
P9_RRENAME,
|
P9_RRENAME,
|
||||||
|
P9_TREADLINK = 22,
|
||||||
|
P9_RREADLINK,
|
||||||
P9_TGETATTR = 24,
|
P9_TGETATTR = 24,
|
||||||
P9_RGETATTR,
|
P9_RGETATTR,
|
||||||
P9_TSETATTR = 26,
|
P9_TSETATTR = 26,
|
||||||
@@ -159,6 +165,12 @@ enum p9_msg_t {
|
|||||||
P9_RXATTRCREATE,
|
P9_RXATTRCREATE,
|
||||||
P9_TREADDIR = 40,
|
P9_TREADDIR = 40,
|
||||||
P9_RREADDIR,
|
P9_RREADDIR,
|
||||||
|
P9_TFSYNC = 50,
|
||||||
|
P9_RFSYNC,
|
||||||
|
P9_TLOCK = 52,
|
||||||
|
P9_RLOCK,
|
||||||
|
P9_TGETLOCK = 54,
|
||||||
|
P9_RGETLOCK,
|
||||||
P9_TLINK = 70,
|
P9_TLINK = 70,
|
||||||
P9_RLINK,
|
P9_RLINK,
|
||||||
P9_TMKDIR = 72,
|
P9_TMKDIR = 72,
|
||||||
@@ -458,6 +470,48 @@ struct p9_iattr_dotl {
|
|||||||
u64 mtime_nsec;
|
u64 mtime_nsec;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define P9_LOCK_SUCCESS 0
|
||||||
|
#define P9_LOCK_BLOCKED 1
|
||||||
|
#define P9_LOCK_ERROR 2
|
||||||
|
#define P9_LOCK_GRACE 3
|
||||||
|
|
||||||
|
#define P9_LOCK_FLAGS_BLOCK 1
|
||||||
|
#define P9_LOCK_FLAGS_RECLAIM 2
|
||||||
|
|
||||||
|
/* struct p9_flock: POSIX lock structure
|
||||||
|
* @type - type of lock
|
||||||
|
* @flags - lock flags
|
||||||
|
* @start - starting offset of the lock
|
||||||
|
* @length - number of bytes
|
||||||
|
* @proc_id - process id which wants to take lock
|
||||||
|
* @client_id - client id
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct p9_flock {
|
||||||
|
u8 type;
|
||||||
|
u32 flags;
|
||||||
|
u64 start;
|
||||||
|
u64 length;
|
||||||
|
u32 proc_id;
|
||||||
|
char *client_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* struct p9_getlock: getlock structure
|
||||||
|
* @type - type of lock
|
||||||
|
* @start - starting offset of the lock
|
||||||
|
* @length - number of bytes
|
||||||
|
* @proc_id - process id which wants to take lock
|
||||||
|
* @client_id - client id
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct p9_getlock {
|
||||||
|
u8 type;
|
||||||
|
u64 start;
|
||||||
|
u64 length;
|
||||||
|
u32 proc_id;
|
||||||
|
char *client_id;
|
||||||
|
};
|
||||||
|
|
||||||
/* Structures for Protocol Operations */
|
/* Structures for Protocol Operations */
|
||||||
struct p9_tstatfs {
|
struct p9_tstatfs {
|
||||||
u32 fid;
|
u32 fid;
|
||||||
|
@@ -229,6 +229,7 @@ int p9_client_symlink(struct p9_fid *fid, char *name, char *symname, gid_t gid,
|
|||||||
int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode,
|
int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode,
|
||||||
gid_t gid, struct p9_qid *qid);
|
gid_t gid, struct p9_qid *qid);
|
||||||
int p9_client_clunk(struct p9_fid *fid);
|
int p9_client_clunk(struct p9_fid *fid);
|
||||||
|
int p9_client_fsync(struct p9_fid *fid, int datasync);
|
||||||
int p9_client_remove(struct p9_fid *fid);
|
int p9_client_remove(struct p9_fid *fid);
|
||||||
int p9_client_read(struct p9_fid *fid, char *data, char __user *udata,
|
int p9_client_read(struct p9_fid *fid, char *data, char __user *udata,
|
||||||
u64 offset, u32 count);
|
u64 offset, u32 count);
|
||||||
@@ -248,6 +249,8 @@ int p9_client_mknod_dotl(struct p9_fid *oldfid, char *name, int mode,
|
|||||||
dev_t rdev, gid_t gid, struct p9_qid *);
|
dev_t rdev, gid_t gid, struct p9_qid *);
|
||||||
int p9_client_mkdir_dotl(struct p9_fid *fid, char *name, int mode,
|
int p9_client_mkdir_dotl(struct p9_fid *fid, char *name, int mode,
|
||||||
gid_t gid, struct p9_qid *);
|
gid_t gid, struct p9_qid *);
|
||||||
|
int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status);
|
||||||
|
int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *fl);
|
||||||
struct p9_req_t *p9_tag_lookup(struct p9_client *, u16);
|
struct p9_req_t *p9_tag_lookup(struct p9_client *, u16);
|
||||||
void p9_client_cb(struct p9_client *c, struct p9_req_t *req);
|
void p9_client_cb(struct p9_client *c, struct p9_req_t *req);
|
||||||
|
|
||||||
@@ -259,5 +262,6 @@ int p9_is_proto_dotu(struct p9_client *clnt);
|
|||||||
int p9_is_proto_dotl(struct p9_client *clnt);
|
int p9_is_proto_dotl(struct p9_client *clnt);
|
||||||
struct p9_fid *p9_client_xattrwalk(struct p9_fid *, const char *, u64 *);
|
struct p9_fid *p9_client_xattrwalk(struct p9_fid *, const char *, u64 *);
|
||||||
int p9_client_xattrcreate(struct p9_fid *, const char *, u64, int);
|
int p9_client_xattrcreate(struct p9_fid *, const char *, u64, int);
|
||||||
|
int p9_client_readlink(struct p9_fid *fid, char **target);
|
||||||
|
|
||||||
#endif /* NET_9P_CLIENT_H */
|
#endif /* NET_9P_CLIENT_H */
|
||||||
|
162
net/9p/client.c
162
net/9p/client.c
@@ -450,32 +450,43 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == P9_RERROR) {
|
if (type == P9_RERROR || type == P9_RLERROR) {
|
||||||
int ecode;
|
int ecode;
|
||||||
|
|
||||||
|
if (!p9_is_proto_dotl(c)) {
|
||||||
char *ename;
|
char *ename;
|
||||||
|
|
||||||
err = p9pdu_readf(req->rc, c->proto_version, "s?d",
|
err = p9pdu_readf(req->rc, c->proto_version, "s?d",
|
||||||
&ename, &ecode);
|
&ename, &ecode);
|
||||||
if (err) {
|
if (err)
|
||||||
P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n",
|
goto out_err;
|
||||||
err);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (p9_is_proto_dotu(c) ||
|
if (p9_is_proto_dotu(c))
|
||||||
p9_is_proto_dotl(c))
|
|
||||||
err = -ecode;
|
err = -ecode;
|
||||||
|
|
||||||
if (!err || !IS_ERR_VALUE(err))
|
if (!err || !IS_ERR_VALUE(err)) {
|
||||||
err = p9_errstr2errno(ename, strlen(ename));
|
err = p9_errstr2errno(ename, strlen(ename));
|
||||||
|
|
||||||
P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", -ecode, ename);
|
P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", -ecode, ename);
|
||||||
|
|
||||||
kfree(ename);
|
kfree(ename);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
err = p9pdu_readf(req->rc, c->proto_version, "d", &ecode);
|
||||||
|
err = -ecode;
|
||||||
|
|
||||||
|
P9_DPRINTK(P9_DEBUG_9P, "<<< RLERROR (%d)\n", -ecode);
|
||||||
|
}
|
||||||
|
|
||||||
} else
|
} else
|
||||||
err = 0;
|
err = 0;
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
out_err:
|
||||||
|
P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n", err);
|
||||||
|
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -568,10 +579,13 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...)
|
|||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
err = p9pdu_vwritef(req->tc, c->proto_version, fmt, ap);
|
err = p9pdu_vwritef(req->tc, c->proto_version, fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
if (err)
|
||||||
|
goto reterr;
|
||||||
p9pdu_finalize(req->tc);
|
p9pdu_finalize(req->tc);
|
||||||
|
|
||||||
err = c->trans_mod->request(c, req);
|
err = c->trans_mod->request(c, req);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
|
if (err != -ERESTARTSYS)
|
||||||
c->status = Disconnected;
|
c->status = Disconnected;
|
||||||
goto reterr;
|
goto reterr;
|
||||||
}
|
}
|
||||||
@@ -1151,12 +1165,44 @@ int p9_client_link(struct p9_fid *dfid, struct p9_fid *oldfid, char *newname)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(p9_client_link);
|
EXPORT_SYMBOL(p9_client_link);
|
||||||
|
|
||||||
|
int p9_client_fsync(struct p9_fid *fid, int datasync)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
struct p9_client *clnt;
|
||||||
|
struct p9_req_t *req;
|
||||||
|
|
||||||
|
P9_DPRINTK(P9_DEBUG_9P, ">>> TFSYNC fid %d datasync:%d\n",
|
||||||
|
fid->fid, datasync);
|
||||||
|
err = 0;
|
||||||
|
clnt = fid->clnt;
|
||||||
|
|
||||||
|
req = p9_client_rpc(clnt, P9_TFSYNC, "dd", fid->fid, datasync);
|
||||||
|
if (IS_ERR(req)) {
|
||||||
|
err = PTR_ERR(req);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
P9_DPRINTK(P9_DEBUG_9P, "<<< RFSYNC fid %d\n", fid->fid);
|
||||||
|
|
||||||
|
p9_free_req(clnt, req);
|
||||||
|
|
||||||
|
error:
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(p9_client_fsync);
|
||||||
|
|
||||||
int p9_client_clunk(struct p9_fid *fid)
|
int p9_client_clunk(struct p9_fid *fid)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
struct p9_client *clnt;
|
struct p9_client *clnt;
|
||||||
struct p9_req_t *req;
|
struct p9_req_t *req;
|
||||||
|
|
||||||
|
if (!fid) {
|
||||||
|
P9_EPRINTK(KERN_WARNING, "Trying to clunk with NULL fid\n");
|
||||||
|
dump_stack();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
P9_DPRINTK(P9_DEBUG_9P, ">>> TCLUNK fid %d\n", fid->fid);
|
P9_DPRINTK(P9_DEBUG_9P, ">>> TCLUNK fid %d\n", fid->fid);
|
||||||
err = 0;
|
err = 0;
|
||||||
clnt = fid->clnt;
|
clnt = fid->clnt;
|
||||||
@@ -1240,16 +1286,13 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset,
|
|||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
memmove(data, dataptr, count);
|
memmove(data, dataptr, count);
|
||||||
}
|
} else {
|
||||||
|
|
||||||
if (udata) {
|
|
||||||
err = copy_to_user(udata, dataptr, count);
|
err = copy_to_user(udata, dataptr, count);
|
||||||
if (err) {
|
if (err) {
|
||||||
err = -EFAULT;
|
err = -EFAULT;
|
||||||
goto free_and_error;
|
goto free_and_error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
p9_free_req(clnt, req);
|
p9_free_req(clnt, req);
|
||||||
return count;
|
return count;
|
||||||
|
|
||||||
@@ -1761,3 +1804,96 @@ error:
|
|||||||
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(p9_client_mkdir_dotl);
|
EXPORT_SYMBOL(p9_client_mkdir_dotl);
|
||||||
|
|
||||||
|
int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
struct p9_client *clnt;
|
||||||
|
struct p9_req_t *req;
|
||||||
|
|
||||||
|
err = 0;
|
||||||
|
clnt = fid->clnt;
|
||||||
|
P9_DPRINTK(P9_DEBUG_9P, ">>> TLOCK fid %d type %i flags %d "
|
||||||
|
"start %lld length %lld proc_id %d client_id %s\n",
|
||||||
|
fid->fid, flock->type, flock->flags, flock->start,
|
||||||
|
flock->length, flock->proc_id, flock->client_id);
|
||||||
|
|
||||||
|
req = p9_client_rpc(clnt, P9_TLOCK, "dbdqqds", fid->fid, flock->type,
|
||||||
|
flock->flags, flock->start, flock->length,
|
||||||
|
flock->proc_id, flock->client_id);
|
||||||
|
|
||||||
|
if (IS_ERR(req))
|
||||||
|
return PTR_ERR(req);
|
||||||
|
|
||||||
|
err = p9pdu_readf(req->rc, clnt->proto_version, "b", status);
|
||||||
|
if (err) {
|
||||||
|
p9pdu_dump(1, req->rc);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
P9_DPRINTK(P9_DEBUG_9P, "<<< RLOCK status %i\n", *status);
|
||||||
|
error:
|
||||||
|
p9_free_req(clnt, req);
|
||||||
|
return err;
|
||||||
|
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(p9_client_lock_dotl);
|
||||||
|
|
||||||
|
int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *glock)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
struct p9_client *clnt;
|
||||||
|
struct p9_req_t *req;
|
||||||
|
|
||||||
|
err = 0;
|
||||||
|
clnt = fid->clnt;
|
||||||
|
P9_DPRINTK(P9_DEBUG_9P, ">>> TGETLOCK fid %d, type %i start %lld "
|
||||||
|
"length %lld proc_id %d client_id %s\n", fid->fid, glock->type,
|
||||||
|
glock->start, glock->length, glock->proc_id, glock->client_id);
|
||||||
|
|
||||||
|
req = p9_client_rpc(clnt, P9_TGETLOCK, "dbqqds", fid->fid, glock->type,
|
||||||
|
glock->start, glock->length, glock->proc_id, glock->client_id);
|
||||||
|
|
||||||
|
if (IS_ERR(req))
|
||||||
|
return PTR_ERR(req);
|
||||||
|
|
||||||
|
err = p9pdu_readf(req->rc, clnt->proto_version, "bqqds", &glock->type,
|
||||||
|
&glock->start, &glock->length, &glock->proc_id,
|
||||||
|
&glock->client_id);
|
||||||
|
if (err) {
|
||||||
|
p9pdu_dump(1, req->rc);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
P9_DPRINTK(P9_DEBUG_9P, "<<< RGETLOCK type %i start %lld length %lld "
|
||||||
|
"proc_id %d client_id %s\n", glock->type, glock->start,
|
||||||
|
glock->length, glock->proc_id, glock->client_id);
|
||||||
|
error:
|
||||||
|
p9_free_req(clnt, req);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(p9_client_getlock_dotl);
|
||||||
|
|
||||||
|
int p9_client_readlink(struct p9_fid *fid, char **target)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
struct p9_client *clnt;
|
||||||
|
struct p9_req_t *req;
|
||||||
|
|
||||||
|
err = 0;
|
||||||
|
clnt = fid->clnt;
|
||||||
|
P9_DPRINTK(P9_DEBUG_9P, ">>> TREADLINK fid %d\n", fid->fid);
|
||||||
|
|
||||||
|
req = p9_client_rpc(clnt, P9_TREADLINK, "d", fid->fid);
|
||||||
|
if (IS_ERR(req))
|
||||||
|
return PTR_ERR(req);
|
||||||
|
|
||||||
|
err = p9pdu_readf(req->rc, clnt->proto_version, "s", target);
|
||||||
|
if (err) {
|
||||||
|
p9pdu_dump(1, req->rc);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
P9_DPRINTK(P9_DEBUG_9P, "<<< RREADLINK target %s\n", *target);
|
||||||
|
error:
|
||||||
|
p9_free_req(clnt, req);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(p9_client_readlink);
|
||||||
|
@@ -122,9 +122,8 @@ static size_t
|
|||||||
pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size)
|
pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size)
|
||||||
{
|
{
|
||||||
size_t len = MIN(pdu->capacity - pdu->size, size);
|
size_t len = MIN(pdu->capacity - pdu->size, size);
|
||||||
int err = copy_from_user(&pdu->sdata[pdu->size], udata, len);
|
if (copy_from_user(&pdu->sdata[pdu->size], udata, len))
|
||||||
if (err)
|
len = 0;
|
||||||
printk(KERN_WARNING "pdu_write_u returning: %d\n", err);
|
|
||||||
|
|
||||||
pdu->size += len;
|
pdu->size += len;
|
||||||
return size - len;
|
return size - len;
|
||||||
|
@@ -75,6 +75,8 @@ struct virtio_chan {
|
|||||||
struct p9_client *client;
|
struct p9_client *client;
|
||||||
struct virtio_device *vdev;
|
struct virtio_device *vdev;
|
||||||
struct virtqueue *vq;
|
struct virtqueue *vq;
|
||||||
|
int ring_bufs_avail;
|
||||||
|
wait_queue_head_t *vc_wq;
|
||||||
|
|
||||||
/* Scatterlist: can be too big for stack. */
|
/* Scatterlist: can be too big for stack. */
|
||||||
struct scatterlist sg[VIRTQUEUE_NUM];
|
struct scatterlist sg[VIRTQUEUE_NUM];
|
||||||
@@ -134,16 +136,30 @@ static void req_done(struct virtqueue *vq)
|
|||||||
struct p9_fcall *rc;
|
struct p9_fcall *rc;
|
||||||
unsigned int len;
|
unsigned int len;
|
||||||
struct p9_req_t *req;
|
struct p9_req_t *req;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
P9_DPRINTK(P9_DEBUG_TRANS, ": request done\n");
|
P9_DPRINTK(P9_DEBUG_TRANS, ": request done\n");
|
||||||
|
|
||||||
while ((rc = virtqueue_get_buf(chan->vq, &len)) != NULL) {
|
do {
|
||||||
|
spin_lock_irqsave(&chan->lock, flags);
|
||||||
|
rc = virtqueue_get_buf(chan->vq, &len);
|
||||||
|
|
||||||
|
if (rc != NULL) {
|
||||||
|
if (!chan->ring_bufs_avail) {
|
||||||
|
chan->ring_bufs_avail = 1;
|
||||||
|
wake_up(chan->vc_wq);
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&chan->lock, flags);
|
||||||
P9_DPRINTK(P9_DEBUG_TRANS, ": rc %p\n", rc);
|
P9_DPRINTK(P9_DEBUG_TRANS, ": rc %p\n", rc);
|
||||||
P9_DPRINTK(P9_DEBUG_TRANS, ": lookup tag %d\n", rc->tag);
|
P9_DPRINTK(P9_DEBUG_TRANS, ": lookup tag %d\n",
|
||||||
|
rc->tag);
|
||||||
req = p9_tag_lookup(chan->client, rc->tag);
|
req = p9_tag_lookup(chan->client, rc->tag);
|
||||||
req->status = REQ_STATUS_RCVD;
|
req->status = REQ_STATUS_RCVD;
|
||||||
p9_client_cb(chan->client, req);
|
p9_client_cb(chan->client, req);
|
||||||
|
} else {
|
||||||
|
spin_unlock_irqrestore(&chan->lock, flags);
|
||||||
}
|
}
|
||||||
|
} while (rc != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -199,23 +215,43 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req)
|
|||||||
int in, out;
|
int in, out;
|
||||||
struct virtio_chan *chan = client->trans;
|
struct virtio_chan *chan = client->trans;
|
||||||
char *rdata = (char *)req->rc+sizeof(struct p9_fcall);
|
char *rdata = (char *)req->rc+sizeof(struct p9_fcall);
|
||||||
|
unsigned long flags;
|
||||||
|
int err;
|
||||||
|
|
||||||
P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request\n");
|
P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request\n");
|
||||||
|
|
||||||
|
req_retry:
|
||||||
|
req->status = REQ_STATUS_SENT;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&chan->lock, flags);
|
||||||
out = pack_sg_list(chan->sg, 0, VIRTQUEUE_NUM, req->tc->sdata,
|
out = pack_sg_list(chan->sg, 0, VIRTQUEUE_NUM, req->tc->sdata,
|
||||||
req->tc->size);
|
req->tc->size);
|
||||||
in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM-out, rdata,
|
in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM-out, rdata,
|
||||||
client->msize);
|
client->msize);
|
||||||
|
|
||||||
req->status = REQ_STATUS_SENT;
|
err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc);
|
||||||
|
if (err < 0) {
|
||||||
|
if (err == -ENOSPC) {
|
||||||
|
chan->ring_bufs_avail = 0;
|
||||||
|
spin_unlock_irqrestore(&chan->lock, flags);
|
||||||
|
err = wait_event_interruptible(*chan->vc_wq,
|
||||||
|
chan->ring_bufs_avail);
|
||||||
|
if (err == -ERESTARTSYS)
|
||||||
|
return err;
|
||||||
|
|
||||||
if (virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc) < 0) {
|
P9_DPRINTK(P9_DEBUG_TRANS, "9p:Retry virtio request\n");
|
||||||
|
goto req_retry;
|
||||||
|
} else {
|
||||||
|
spin_unlock_irqrestore(&chan->lock, flags);
|
||||||
P9_DPRINTK(P9_DEBUG_TRANS,
|
P9_DPRINTK(P9_DEBUG_TRANS,
|
||||||
"9p debug: virtio rpc add_buf returned failure");
|
"9p debug: "
|
||||||
|
"virtio rpc add_buf returned failure");
|
||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
virtqueue_kick(chan->vq);
|
virtqueue_kick(chan->vq);
|
||||||
|
spin_unlock_irqrestore(&chan->lock, flags);
|
||||||
|
|
||||||
P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request kicked\n");
|
P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request kicked\n");
|
||||||
return 0;
|
return 0;
|
||||||
@@ -290,14 +326,23 @@ static int p9_virtio_probe(struct virtio_device *vdev)
|
|||||||
chan->tag_len = tag_len;
|
chan->tag_len = tag_len;
|
||||||
err = sysfs_create_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr);
|
err = sysfs_create_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr);
|
||||||
if (err) {
|
if (err) {
|
||||||
kfree(tag);
|
goto out_free_tag;
|
||||||
goto out_free_vq;
|
|
||||||
}
|
}
|
||||||
|
chan->vc_wq = kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL);
|
||||||
|
if (!chan->vc_wq) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
goto out_free_tag;
|
||||||
|
}
|
||||||
|
init_waitqueue_head(chan->vc_wq);
|
||||||
|
chan->ring_bufs_avail = 1;
|
||||||
|
|
||||||
mutex_lock(&virtio_9p_lock);
|
mutex_lock(&virtio_9p_lock);
|
||||||
list_add_tail(&chan->chan_list, &virtio_chan_list);
|
list_add_tail(&chan->chan_list, &virtio_chan_list);
|
||||||
mutex_unlock(&virtio_9p_lock);
|
mutex_unlock(&virtio_9p_lock);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
out_free_tag:
|
||||||
|
kfree(tag);
|
||||||
out_free_vq:
|
out_free_vq:
|
||||||
vdev->config->del_vqs(vdev);
|
vdev->config->del_vqs(vdev);
|
||||||
kfree(chan);
|
kfree(chan);
|
||||||
@@ -371,6 +416,7 @@ static void p9_virtio_remove(struct virtio_device *vdev)
|
|||||||
mutex_unlock(&virtio_9p_lock);
|
mutex_unlock(&virtio_9p_lock);
|
||||||
sysfs_remove_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr);
|
sysfs_remove_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr);
|
||||||
kfree(chan->tag);
|
kfree(chan->tag);
|
||||||
|
kfree(chan->vc_wq);
|
||||||
kfree(chan);
|
kfree(chan);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user