diff options
| -rw-r--r-- | Documentation/filesystems/9p.txt | 4 | ||||
| -rw-r--r-- | fs/9p/Kconfig | 13 | ||||
| -rw-r--r-- | fs/9p/Makefile | 1 | ||||
| -rw-r--r-- | fs/9p/acl.c | 392 | ||||
| -rw-r--r-- | fs/9p/acl.h | 49 | ||||
| -rw-r--r-- | fs/9p/fid.c | 1 | ||||
| -rw-r--r-- | fs/9p/v9fs.c | 22 | ||||
| -rw-r--r-- | fs/9p/v9fs.h | 10 | ||||
| -rw-r--r-- | fs/9p/v9fs_vfs.h | 4 | ||||
| -rw-r--r-- | fs/9p/vfs_addr.c | 30 | ||||
| -rw-r--r-- | fs/9p/vfs_dir.c | 4 | ||||
| -rw-r--r-- | fs/9p/vfs_file.c | 265 | ||||
| -rw-r--r-- | fs/9p/vfs_inode.c | 253 | ||||
| -rw-r--r-- | fs/9p/vfs_super.c | 14 | ||||
| -rw-r--r-- | fs/9p/xattr.c | 52 | ||||
| -rw-r--r-- | fs/9p/xattr.h | 6 | ||||
| -rw-r--r-- | include/linux/magic.h | 1 | ||||
| -rw-r--r-- | include/net/9p/9p.h | 54 | ||||
| -rw-r--r-- | include/net/9p/client.h | 4 | ||||
| -rw-r--r-- | net/9p/client.c | 178 | ||||
| -rw-r--r-- | net/9p/protocol.c | 5 | ||||
| -rw-r--r-- | net/9p/trans_virtio.c | 76 |
22 files changed, 1288 insertions, 150 deletions
diff --git a/Documentation/filesystems/9p.txt b/Documentation/filesystems/9p.txt index f9765e8cf086..b22abba78fed 100644 --- a/Documentation/filesystems/9p.txt +++ b/Documentation/filesystems/9p.txt | |||
| @@ -111,7 +111,7 @@ OPTIONS | |||
| 111 | This can be used to share devices/named pipes/sockets between | 111 | This can be used to share devices/named pipes/sockets between |
| 112 | hosts. This functionality will be expanded in later versions. | 112 | hosts. This functionality will be expanded in later versions. |
| 113 | 113 | ||
| 114 | access there are three access modes. | 114 | access there are four access modes. |
| 115 | user = if a user tries to access a file on v9fs | 115 | user = if a user tries to access a file on v9fs |
| 116 | filesystem for the first time, v9fs sends an | 116 | filesystem for the first time, v9fs sends an |
| 117 | attach command (Tattach) for that user. | 117 | attach command (Tattach) for that user. |
| @@ -120,6 +120,8 @@ OPTIONS | |||
| 120 | the files on the mounted filesystem | 120 | the files on the mounted filesystem |
| 121 | any = v9fs does single attach and performs all | 121 | any = v9fs does single attach and performs all |
| 122 | operations as one user | 122 | operations as one user |
| 123 | client = ACL based access check on the 9p client | ||
| 124 | side for access validation | ||
| 123 | 125 | ||
| 124 | cachetag cache tag to use the specified persistent cache. | 126 | cachetag cache tag to use the specified persistent cache. |
| 125 | cache tags for existing cache sessions can be listed at | 127 | cache tags for existing cache sessions can be listed at |
diff --git a/fs/9p/Kconfig b/fs/9p/Kconfig index 795233702a4e..7e0511476797 100644 --- a/fs/9p/Kconfig +++ b/fs/9p/Kconfig | |||
| @@ -17,3 +17,16 @@ config 9P_FSCACHE | |||
| 17 | Choose Y here to enable persistent, read-only local | 17 | Choose Y here to enable persistent, read-only local |
| 18 | caching support for 9p clients using FS-Cache | 18 | caching support for 9p clients using FS-Cache |
| 19 | 19 | ||
| 20 | |||
| 21 | config 9P_FS_POSIX_ACL | ||
| 22 | bool "9P POSIX Access Control Lists" | ||
| 23 | depends on 9P_FS | ||
| 24 | select FS_POSIX_ACL | ||
| 25 | help | ||
| 26 | POSIX Access Control Lists (ACLs) support permissions for users and | ||
| 27 | groups beyond the owner/group/world scheme. | ||
| 28 | |||
| 29 | To learn more about Access Control Lists, visit the POSIX ACLs for | ||
| 30 | Linux website <http://acl.bestbits.at/>. | ||
| 31 | |||
| 32 | If you don't know what Access Control Lists are, say N | ||
diff --git a/fs/9p/Makefile b/fs/9p/Makefile index 91fba025fcbe..f8ba37effd1b 100644 --- a/fs/9p/Makefile +++ b/fs/9p/Makefile | |||
| @@ -13,3 +13,4 @@ obj-$(CONFIG_9P_FS) := 9p.o | |||
| 13 | xattr_user.o | 13 | xattr_user.o |
| 14 | 14 | ||
| 15 | 9p-$(CONFIG_9P_FSCACHE) += cache.o | 15 | 9p-$(CONFIG_9P_FSCACHE) += cache.o |
| 16 | 9p-$(CONFIG_9P_FS_POSIX_ACL) += acl.o | ||
diff --git a/fs/9p/acl.c b/fs/9p/acl.c new file mode 100644 index 000000000000..12d602351dbe --- /dev/null +++ b/fs/9p/acl.c | |||
| @@ -0,0 +1,392 @@ | |||
| 1 | /* | ||
| 2 | * Copyright IBM Corporation, 2010 | ||
| 3 | * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms of version 2.1 of the GNU Lesser General Public License | ||
| 7 | * as published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it would be useful, but | ||
| 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
| 12 | * | ||
| 13 | */ | ||
| 14 | |||
| 15 | #include <linux/module.h> | ||
| 16 | #include <linux/fs.h> | ||
| 17 | #include <net/9p/9p.h> | ||
| 18 | #include <net/9p/client.h> | ||
| 19 | #include <linux/slab.h> | ||
| 20 | #include <linux/sched.h> | ||
| 21 | #include <linux/posix_acl_xattr.h> | ||
| 22 | #include "xattr.h" | ||
| 23 | #include "acl.h" | ||
| 24 | #include "v9fs_vfs.h" | ||
| 25 | #include "v9fs.h" | ||
| 26 | |||
| 27 | static struct posix_acl *__v9fs_get_acl(struct p9_fid *fid, char *name) | ||
| 28 | { | ||
| 29 | ssize_t size; | ||
| 30 | void *value = NULL; | ||
| 31 | struct posix_acl *acl = NULL;; | ||
| 32 | |||
| 33 | size = v9fs_fid_xattr_get(fid, name, NULL, 0); | ||
| 34 | if (size > 0) { | ||
| 35 | value = kzalloc(size, GFP_NOFS); | ||
| 36 | if (!value) | ||
| 37 | return ERR_PTR(-ENOMEM); | ||
| 38 | size = v9fs_fid_xattr_get(fid, name, value, size); | ||
| 39 | if (size > 0) { | ||
| 40 | acl = posix_acl_from_xattr(value, size); | ||
| 41 | if (IS_ERR(acl)) | ||
| 42 | goto err_out; | ||
| 43 | } | ||
| 44 | } else if (size == -ENODATA || size == 0 || | ||
| 45 | size == -ENOSYS || size == -EOPNOTSUPP) { | ||
| 46 | acl = NULL; | ||
| 47 | } else | ||
| 48 | acl = ERR_PTR(-EIO); | ||
| 49 | |||
| 50 | err_out: | ||
| 51 | kfree(value); | ||
| 52 | return acl; | ||
| 53 | } | ||
| 54 | |||
| 55 | int v9fs_get_acl(struct inode *inode, struct p9_fid *fid) | ||
| 56 | { | ||
| 57 | int retval = 0; | ||
| 58 | struct posix_acl *pacl, *dacl; | ||
| 59 | struct v9fs_session_info *v9ses; | ||
| 60 | |||
| 61 | v9ses = v9fs_inode2v9ses(inode); | ||
| 62 | if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) { | ||
| 63 | set_cached_acl(inode, ACL_TYPE_DEFAULT, NULL); | ||
| 64 | set_cached_acl(inode, ACL_TYPE_ACCESS, NULL); | ||
| 65 | return 0; | ||
| 66 | } | ||
| 67 | /* get the default/access acl values and cache them */ | ||
| 68 | dacl = __v9fs_get_acl(fid, POSIX_ACL_XATTR_DEFAULT); | ||
| 69 | pacl = __v9fs_get_acl(fid, POSIX_ACL_XATTR_ACCESS); | ||
| 70 | |||
| 71 | if (!IS_ERR(dacl) && !IS_ERR(pacl)) { | ||
| 72 | set_cached_acl(inode, ACL_TYPE_DEFAULT, dacl); | ||
| 73 | set_cached_acl(inode, ACL_TYPE_ACCESS, pacl); | ||
| 74 | posix_acl_release(dacl); | ||
| 75 | posix_acl_release(pacl); | ||
| 76 | } else | ||
| 77 | retval = -EIO; | ||
| 78 | |||
| 79 | return retval; | ||
| 80 | } | ||
| 81 | |||
| 82 | static struct posix_acl *v9fs_get_cached_acl(struct inode *inode, int type) | ||
| 83 | { | ||
| 84 | struct posix_acl *acl; | ||
| 85 | /* | ||
| 86 | * 9p Always cache the acl value when | ||
| 87 | * instantiating the inode (v9fs_inode_from_fid) | ||
| 88 | */ | ||
| 89 | acl = get_cached_acl(inode, type); | ||
| 90 | BUG_ON(acl == ACL_NOT_CACHED); | ||
| 91 | return acl; | ||
| 92 | } | ||
| 93 | |||
| 94 | int v9fs_check_acl(struct inode *inode, int mask) | ||
| 95 | { | ||
| 96 | struct posix_acl *acl; | ||
| 97 | struct v9fs_session_info *v9ses; | ||
| 98 | |||
| 99 | v9ses = v9fs_inode2v9ses(inode); | ||
| 100 | if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) { | ||
| 101 | /* | ||
| 102 | * On access = client mode get the acl | ||
| 103 | * values from the server | ||
| 104 | */ | ||
| 105 | return 0; | ||
| 106 | } | ||
| 107 | acl = v9fs_get_cached_acl(inode, ACL_TYPE_ACCESS); | ||
| 108 | |||
| 109 | if (IS_ERR(acl)) | ||
| 110 | return PTR_ERR(acl); | ||
| 111 | if (acl) { | ||
| 112 | int error = posix_acl_permission(inode, acl, mask); | ||
| 113 | posix_acl_release(acl); | ||
| 114 | return error; | ||
| 115 | } | ||
| 116 | return -EAGAIN; | ||
| 117 | } | ||
| 118 | |||
| 119 | static int v9fs_set_acl(struct dentry *dentry, int type, struct posix_acl *acl) | ||
| 120 | { | ||
| 121 | int retval; | ||
| 122 | char *name; | ||
| 123 | size_t size; | ||
| 124 | void *buffer; | ||
| 125 | struct inode *inode = dentry->d_inode; | ||
| 126 | |||
| 127 | set_cached_acl(inode, type, acl); | ||
| 128 | /* Set a setxattr request to server */ | ||
| 129 | size = posix_acl_xattr_size(acl->a_count); | ||
| 130 | buffer = kmalloc(size, GFP_KERNEL); | ||
| 131 | if (!buffer) | ||
| 132 | return -ENOMEM; | ||
| 133 | retval = posix_acl_to_xattr(acl, buffer, size); | ||
| 134 | if (retval < 0) | ||
| 135 | goto err_free_out; | ||
| 136 | switch (type) { | ||
| 137 | case ACL_TYPE_ACCESS: | ||
| 138 | name = POSIX_ACL_XATTR_ACCESS; | ||
| 139 | break; | ||
| 140 | case ACL_TYPE_DEFAULT: | ||
| 141 | name = POSIX_ACL_XATTR_DEFAULT; | ||
| 142 | break; | ||
| 143 | default: | ||
| 144 | BUG(); | ||
| 145 | } | ||
| 146 | retval = v9fs_xattr_set(dentry, name, buffer, size, 0); | ||
| 147 | err_free_out: | ||
| 148 | kfree(buffer); | ||
| 149 | return retval; | ||
| 150 | } | ||
| 151 | |||
| 152 | int v9fs_acl_chmod(struct dentry *dentry) | ||
| 153 | { | ||
| 154 | int retval = 0; | ||
| 155 | struct posix_acl *acl, *clone; | ||
| 156 | struct inode *inode = dentry->d_inode; | ||
| 157 | |||
| 158 | if (S_ISLNK(inode->i_mode)) | ||
| 159 | return -EOPNOTSUPP; | ||
| 160 | acl = v9fs_get_cached_acl(inode, ACL_TYPE_ACCESS); | ||
| 161 | if (acl) { | ||
| 162 | clone = posix_acl_clone(acl, GFP_KERNEL); | ||
| 163 | posix_acl_release(acl); | ||
| 164 | if (!clone) | ||
| 165 | return -ENOMEM; | ||
| 166 | retval = posix_acl_chmod_masq(clone, inode->i_mode); | ||
| 167 | if (!retval) | ||
| 168 | retval = v9fs_set_acl(dentry, ACL_TYPE_ACCESS, clone); | ||
| 169 | posix_acl_release(clone); | ||
| 170 | } | ||
| 171 | return retval; | ||
| 172 | } | ||
| 173 | |||
| 174 | int v9fs_set_create_acl(struct dentry *dentry, | ||
| 175 | struct posix_acl *dpacl, struct posix_acl *pacl) | ||
| 176 | { | ||
| 177 | if (dpacl) | ||
| 178 | v9fs_set_acl(dentry, ACL_TYPE_DEFAULT, dpacl); | ||
| 179 | if (pacl) | ||
| 180 | v9fs_set_acl(dentry, ACL_TYPE_ACCESS, pacl); | ||
| 181 | posix_acl_release(dpacl); | ||
| 182 | posix_acl_release(pacl); | ||
| 183 | return 0; | ||
| 184 | } | ||
| 185 | |||
| 186 | int v9fs_acl_mode(struct inode *dir, mode_t *modep, | ||
| 187 | struct posix_acl **dpacl, struct posix_acl **pacl) | ||
| 188 | { | ||
| 189 | int retval = 0; | ||
| 190 | mode_t mode = *modep; | ||
| 191 | struct posix_acl *acl = NULL; | ||
| 192 | |||
| 193 | if (!S_ISLNK(mode)) { | ||
| 194 | acl = v9fs_get_cached_acl(dir, ACL_TYPE_DEFAULT); | ||
| 195 | if (IS_ERR(acl)) | ||
| 196 | return PTR_ERR(acl); | ||
| 197 | if (!acl) | ||
| 198 | mode &= ~current_umask(); | ||
| 199 | } | ||
| 200 | if (acl) { | ||
| 201 | struct posix_acl *clone; | ||
| 202 | |||
| 203 | if (S_ISDIR(mode)) | ||
| 204 | *dpacl = acl; | ||
| 205 | clone = posix_acl_clone(acl, GFP_NOFS); | ||
| 206 | retval = -ENOMEM; | ||
| 207 | if (!clone) | ||
| 208 | goto cleanup; | ||
| 209 | |||
| 210 | retval = posix_acl_create_masq(clone, &mode); | ||
| 211 | if (retval < 0) { | ||
| 212 | posix_acl_release(clone); | ||
| 213 | goto cleanup; | ||
| 214 | } | ||
| 215 | if (retval > 0) | ||
| 216 | *pacl = clone; | ||
| 217 | } | ||
| 218 | *modep = mode; | ||
| 219 | return 0; | ||
| 220 | cleanup: | ||
| 221 | posix_acl_release(acl); | ||
| 222 | return retval; | ||
| 223 | |||
| 224 | } | ||
| 225 | |||
| 226 | static int v9fs_remote_get_acl(struct dentry *dentry, const char *name, | ||
| 227 | void *buffer, size_t size, int type) | ||
| 228 | { | ||
| 229 | char *full_name; | ||
| 230 | |||
| 231 | switch (type) { | ||
| 232 | case ACL_TYPE_ACCESS: | ||
| 233 | full_name = POSIX_ACL_XATTR_ACCESS; | ||
| 234 | break; | ||
| 235 | case ACL_TYPE_DEFAULT: | ||
| 236 | full_name = POSIX_ACL_XATTR_DEFAULT; | ||
| 237 | break; | ||
| 238 | default: | ||
| 239 | BUG(); | ||
| 240 | } | ||
| 241 | return v9fs_xattr_get(dentry, full_name, buffer, size); | ||
| 242 | } | ||
| 243 | |||
| 244 | static int v9fs_xattr_get_acl(struct dentry *dentry, const char *name, | ||
| 245 | void *buffer, size_t size, int type) | ||
| 246 | { | ||
| 247 | struct v9fs_session_info *v9ses; | ||
| 248 | struct posix_acl *acl; | ||
| 249 | int error; | ||
| 250 | |||
| 251 | if (strcmp(name, "") != 0) | ||
| 252 | return -EINVAL; | ||
| 253 | |||
| 254 | v9ses = v9fs_inode2v9ses(dentry->d_inode); | ||
| 255 | /* | ||
| 256 | * We allow set/get/list of acl when access=client is not specified | ||
| 257 | */ | ||
| 258 | if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) | ||
| 259 | return v9fs_remote_get_acl(dentry, name, buffer, size, type); | ||
| 260 | |||
| 261 | acl = v9fs_get_cached_acl(dentry->d_inode, type); | ||
| 262 | if (IS_ERR(acl)) | ||
| 263 | return PTR_ERR(acl); | ||
| 264 | if (acl == NULL) | ||
| 265 | return -ENODATA; | ||
| 266 | error = posix_acl_to_xattr(acl, buffer, size); | ||
| 267 | posix_acl_release(acl); | ||
| 268 | |||
| 269 | return error; | ||
| 270 | } | ||
| 271 | |||
| 272 | static int v9fs_remote_set_acl(struct dentry *dentry, const char *name, | ||
| 273 | const void *value, size_t size, | ||
| 274 | int flags, int type) | ||
| 275 | { | ||
| 276 | char *full_name; | ||
| 277 | |||
| 278 | switch (type) { | ||
| 279 | case ACL_TYPE_ACCESS: | ||
| 280 | full_name = POSIX_ACL_XATTR_ACCESS; | ||
| 281 | break; | ||
| 282 | case ACL_TYPE_DEFAULT: | ||
| 283 | full_name = POSIX_ACL_XATTR_DEFAULT; | ||
| 284 | break; | ||
| 285 | default: | ||
| 286 | BUG(); | ||
| 287 | } | ||
| 288 | return v9fs_xattr_set(dentry, full_name, value, size, flags); | ||
| 289 | } | ||
| 290 | |||
| 291 | |||
| 292 | static int v9fs_xattr_set_acl(struct dentry *dentry, const char *name, | ||
| 293 | const void *value, size_t size, | ||
| 294 | int flags, int type) | ||
| 295 | { | ||
| 296 | int retval; | ||
| 297 | struct posix_acl *acl; | ||
| 298 | struct v9fs_session_info *v9ses; | ||
| 299 | struct inode *inode = dentry->d_inode; | ||
| 300 | |||
| 301 | if (strcmp(name, "") != 0) | ||
| 302 | return -EINVAL; | ||
| 303 | |||
| 304 | v9ses = v9fs_inode2v9ses(dentry->d_inode); | ||
| 305 | /* | ||
| 306 | * set the attribute on the remote. Without even looking at the | ||
| 307 | * xattr value. We leave it to the server to validate | ||
| 308 | */ | ||
| 309 | if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) | ||
| 310 | return v9fs_remote_set_acl(dentry, name, | ||
| 311 | value, size, flags, type); | ||
| 312 | |||
| 313 | if (S_ISLNK(inode->i_mode)) | ||
| 314 | return -EOPNOTSUPP; | ||
| 315 | if (!is_owner_or_cap(inode)) | ||
| 316 | return -EPERM; | ||
| 317 | if (value) { | ||
| 318 | /* update the cached acl value */ | ||
| 319 | acl = posix_acl_from_xattr(value, size); | ||
| 320 | if (IS_ERR(acl)) | ||
| 321 | return PTR_ERR(acl); | ||
| 322 | else if (acl) { | ||
| 323 | retval = posix_acl_valid(acl); | ||
| 324 | if (retval) | ||
| 325 | goto err_out; | ||
| 326 | } | ||
| 327 | } else | ||
| 328 | acl = NULL; | ||
| 329 | |||
| 330 | switch (type) { | ||
| 331 | case ACL_TYPE_ACCESS: | ||
| 332 | name = POSIX_ACL_XATTR_ACCESS; | ||
| 333 | if (acl) { | ||
| 334 | mode_t mode = inode->i_mode; | ||
| 335 | retval = posix_acl_equiv_mode(acl, &mode); | ||
| 336 | if (retval < 0) | ||
| 337 | goto err_out; | ||
| 338 | else { | ||
| 339 | struct iattr iattr; | ||
| 340 | if (retval == 0) { | ||
| 341 | /* | ||
| 342 | * ACL can be represented | ||
| 343 | * by the mode bits. So don't | ||
| 344 | * update ACL. | ||
| 345 | */ | ||
| 346 | acl = NULL; | ||
| 347 | value = NULL; | ||
| 348 | size = 0; | ||
| 349 | } | ||
| 350 | /* Updte the mode bits */ | ||
| 351 | iattr.ia_mode = ((mode & S_IALLUGO) | | ||
| 352 | (inode->i_mode & ~S_IALLUGO)); | ||
| 353 | iattr.ia_valid = ATTR_MODE; | ||
| 354 | /* FIXME should we update ctime ? | ||
| 355 | * What is the following setxattr update the | ||
| 356 | * mode ? | ||
| 357 | */ | ||
| 358 | v9fs_vfs_setattr_dotl(dentry, &iattr); | ||
| 359 | } | ||
| 360 | } | ||
| 361 | break; | ||
| 362 | case ACL_TYPE_DEFAULT: | ||
| 363 | name = POSIX_ACL_XATTR_DEFAULT; | ||
| 364 | if (!S_ISDIR(inode->i_mode)) { | ||
| 365 | retval = -EINVAL; | ||
| 366 | goto err_out; | ||
| 367 | } | ||
| 368 | break; | ||
| 369 | default: | ||
| 370 | BUG(); | ||
| 371 | } | ||
| 372 | retval = v9fs_xattr_set(dentry, name, value, size, flags); | ||
| 373 | if (!retval) | ||
| 374 | set_cached_acl(inode, type, acl); | ||
| 375 | err_out: | ||
| 376 | posix_acl_release(acl); | ||
| 377 | return retval; | ||
| 378 | } | ||
| 379 | |||
| 380 | const struct xattr_handler v9fs_xattr_acl_access_handler = { | ||
| 381 | .prefix = POSIX_ACL_XATTR_ACCESS, | ||
| 382 | .flags = ACL_TYPE_ACCESS, | ||
| 383 | .get = v9fs_xattr_get_acl, | ||
| 384 | .set = v9fs_xattr_set_acl, | ||
| 385 | }; | ||
| 386 | |||
| 387 | const struct xattr_handler v9fs_xattr_acl_default_handler = { | ||
| 388 | .prefix = POSIX_ACL_XATTR_DEFAULT, | ||
| 389 | .flags = ACL_TYPE_DEFAULT, | ||
| 390 | .get = v9fs_xattr_get_acl, | ||
| 391 | .set = v9fs_xattr_set_acl, | ||
| 392 | }; | ||
diff --git a/fs/9p/acl.h b/fs/9p/acl.h new file mode 100644 index 000000000000..59e18c2e8c7e --- /dev/null +++ b/fs/9p/acl.h | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | /* | ||
| 2 | * Copyright IBM Corporation, 2010 | ||
| 3 | * Author Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms of version 2.1 of the GNU Lesser General Public License | ||
| 7 | * as published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it would be useful, but | ||
| 10 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | ||
| 12 | * | ||
| 13 | */ | ||
| 14 | #ifndef FS_9P_ACL_H | ||
| 15 | #define FS_9P_ACL_H | ||
| 16 | |||
| 17 | #ifdef CONFIG_9P_FS_POSIX_ACL | ||
| 18 | extern int v9fs_get_acl(struct inode *, struct p9_fid *); | ||
| 19 | extern int v9fs_check_acl(struct inode *inode, int mask); | ||
| 20 | extern int v9fs_acl_chmod(struct dentry *); | ||
| 21 | extern int v9fs_set_create_acl(struct dentry *, | ||
| 22 | struct posix_acl *, struct posix_acl *); | ||
| 23 | extern int v9fs_acl_mode(struct inode *dir, mode_t *modep, | ||
| 24 | struct posix_acl **dpacl, struct posix_acl **pacl); | ||
| 25 | #else | ||
| 26 | #define v9fs_check_acl NULL | ||
| 27 | static inline int v9fs_get_acl(struct inode *inode, struct p9_fid *fid) | ||
| 28 | { | ||
| 29 | return 0; | ||
| 30 | } | ||
| 31 | static inline int v9fs_acl_chmod(struct dentry *dentry) | ||
| 32 | { | ||
| 33 | return 0; | ||
| 34 | } | ||
| 35 | static inline int v9fs_set_create_acl(struct dentry *dentry, | ||
| 36 | struct posix_acl *dpacl, | ||
| 37 | struct posix_acl *pacl) | ||
| 38 | { | ||
| 39 | return 0; | ||
| 40 | } | ||
| 41 | static inline int v9fs_acl_mode(struct inode *dir, mode_t *modep, | ||
| 42 | struct posix_acl **dpacl, | ||
| 43 | struct posix_acl **pacl) | ||
| 44 | { | ||
| 45 | return 0; | ||
| 46 | } | ||
| 47 | |||
| 48 | #endif | ||
| 49 | #endif /* FS_9P_XATTR_H */ | ||
diff --git a/fs/9p/fid.c b/fs/9p/fid.c index 6406f896bf95..b00223c99d70 100644 --- a/fs/9p/fid.c +++ b/fs/9p/fid.c | |||
| @@ -149,6 +149,7 @@ struct p9_fid *v9fs_fid_lookup(struct dentry *dentry) | |||
| 149 | switch (access) { | 149 | switch (access) { |
| 150 | case V9FS_ACCESS_SINGLE: | 150 | case V9FS_ACCESS_SINGLE: |
| 151 | case V9FS_ACCESS_USER: | 151 | case V9FS_ACCESS_USER: |
| 152 | case V9FS_ACCESS_CLIENT: | ||
| 152 | uid = current_fsuid(); | 153 | uid = current_fsuid(); |
| 153 | any = 0; | 154 | any = 0; |
| 154 | break; | 155 | break; |
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 38dc0e067599..2f77cd33ba83 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c | |||
| @@ -193,7 +193,17 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts) | |||
| 193 | v9ses->flags |= V9FS_ACCESS_USER; | 193 | v9ses->flags |= V9FS_ACCESS_USER; |
| 194 | else if (strcmp(s, "any") == 0) | 194 | else if (strcmp(s, "any") == 0) |
| 195 | v9ses->flags |= V9FS_ACCESS_ANY; | 195 | v9ses->flags |= V9FS_ACCESS_ANY; |
| 196 | else { | 196 | else if (strcmp(s, "client") == 0) { |
| 197 | #ifdef CONFIG_9P_FS_POSIX_ACL | ||
| 198 | v9ses->flags |= V9FS_ACCESS_CLIENT; | ||
| 199 | #else | ||
| 200 | P9_DPRINTK(P9_DEBUG_ERROR, | ||
| 201 | "access=client option not supported\n"); | ||
| 202 | kfree(s); | ||
| 203 | ret = -EINVAL; | ||
| 204 | goto free_and_return; | ||
| 205 | #endif | ||
| 206 | } else { | ||
| 197 | v9ses->flags |= V9FS_ACCESS_SINGLE; | 207 | v9ses->flags |= V9FS_ACCESS_SINGLE; |
| 198 | v9ses->uid = simple_strtoul(s, &e, 10); | 208 | v9ses->uid = simple_strtoul(s, &e, 10); |
| 199 | if (*e != '\0') | 209 | if (*e != '\0') |
| @@ -278,6 +288,16 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, | |||
| 278 | 288 | ||
| 279 | v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ; | 289 | v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ; |
| 280 | 290 | ||
| 291 | if (!v9fs_proto_dotl(v9ses) && | ||
| 292 | ((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_CLIENT)) { | ||
| 293 | /* | ||
| 294 | * We support ACCESS_CLIENT only for dotl. | ||
| 295 | * Fall back to ACCESS_USER | ||
| 296 | */ | ||
| 297 | v9ses->flags &= ~V9FS_ACCESS_MASK; | ||
| 298 | v9ses->flags |= V9FS_ACCESS_USER; | ||
| 299 | } | ||
| 300 | /*FIXME !! */ | ||
| 281 | /* for legacy mode, fall back to V9FS_ACCESS_ANY */ | 301 | /* for legacy mode, fall back to V9FS_ACCESS_ANY */ |
| 282 | if (!(v9fs_proto_dotu(v9ses) || v9fs_proto_dotl(v9ses)) && | 302 | if (!(v9fs_proto_dotu(v9ses) || v9fs_proto_dotl(v9ses)) && |
| 283 | ((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) { | 303 | ((v9ses->flags&V9FS_ACCESS_MASK) == V9FS_ACCESS_USER)) { |
diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h index 4c963c9fc41f..cb6396855e2d 100644 --- a/fs/9p/v9fs.h +++ b/fs/9p/v9fs.h | |||
| @@ -33,13 +33,17 @@ | |||
| 33 | * | 33 | * |
| 34 | * Session flags reflect options selected by users at mount time | 34 | * Session flags reflect options selected by users at mount time |
| 35 | */ | 35 | */ |
| 36 | #define V9FS_ACCESS_ANY (V9FS_ACCESS_SINGLE | \ | ||
| 37 | V9FS_ACCESS_USER | \ | ||
| 38 | V9FS_ACCESS_CLIENT) | ||
| 39 | #define V9FS_ACCESS_MASK V9FS_ACCESS_ANY | ||
| 40 | |||
| 36 | enum p9_session_flags { | 41 | enum p9_session_flags { |
| 37 | V9FS_PROTO_2000U = 0x01, | 42 | V9FS_PROTO_2000U = 0x01, |
| 38 | V9FS_PROTO_2000L = 0x02, | 43 | V9FS_PROTO_2000L = 0x02, |
| 39 | V9FS_ACCESS_SINGLE = 0x04, | 44 | V9FS_ACCESS_SINGLE = 0x04, |
| 40 | V9FS_ACCESS_USER = 0x08, | 45 | V9FS_ACCESS_USER = 0x08, |
| 41 | V9FS_ACCESS_ANY = 0x0C, | 46 | V9FS_ACCESS_CLIENT = 0x10 |
| 42 | V9FS_ACCESS_MASK = 0x0C, | ||
| 43 | }; | 47 | }; |
| 44 | 48 | ||
| 45 | /* possible values of ->cache */ | 49 | /* possible values of ->cache */ |
| @@ -113,8 +117,6 @@ void v9fs_session_close(struct v9fs_session_info *v9ses); | |||
| 113 | void v9fs_session_cancel(struct v9fs_session_info *v9ses); | 117 | void v9fs_session_cancel(struct v9fs_session_info *v9ses); |
| 114 | void v9fs_session_begin_cancel(struct v9fs_session_info *v9ses); | 118 | void v9fs_session_begin_cancel(struct v9fs_session_info *v9ses); |
| 115 | 119 | ||
| 116 | #define V9FS_MAGIC 0x01021997 | ||
| 117 | |||
| 118 | /* other default globals */ | 120 | /* other default globals */ |
| 119 | #define V9FS_PORT 564 | 121 | #define V9FS_PORT 564 |
| 120 | #define V9FS_DEFUSER "nobody" | 122 | #define V9FS_DEFUSER "nobody" |
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h index 88418c419ea7..bab0eac873f4 100644 --- a/fs/9p/v9fs_vfs.h +++ b/fs/9p/v9fs_vfs.h | |||
| @@ -64,3 +64,7 @@ int v9fs_uflags2omode(int uflags, int extended); | |||
| 64 | 64 | ||
| 65 | ssize_t v9fs_file_readn(struct file *, char *, char __user *, u32, u64); | 65 | ssize_t v9fs_file_readn(struct file *, char *, char __user *, u32, u64); |
| 66 | void v9fs_blank_wstat(struct p9_wstat *wstat); | 66 | void v9fs_blank_wstat(struct p9_wstat *wstat); |
| 67 | int v9fs_vfs_setattr_dotl(struct dentry *, struct iattr *); | ||
| 68 | int v9fs_file_fsync_dotl(struct file *filp, int datasync); | ||
| 69 | |||
| 70 | #define P9_LOCK_TIMEOUT (30*HZ) | ||
diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c index 90e38449f4b3..b7f2a8e3863e 100644 --- a/fs/9p/vfs_addr.c +++ b/fs/9p/vfs_addr.c | |||
| @@ -154,10 +154,40 @@ static int v9fs_launder_page(struct page *page) | |||
| 154 | return 0; | 154 | return 0; |
| 155 | } | 155 | } |
| 156 | 156 | ||
| 157 | /** | ||
| 158 | * v9fs_direct_IO - 9P address space operation for direct I/O | ||
| 159 | * @rw: direction (read or write) | ||
| 160 | * @iocb: target I/O control block | ||
| 161 | * @iov: array of vectors that define I/O buffer | ||
| 162 | * @pos: offset in file to begin the operation | ||
| 163 | * @nr_segs: size of iovec array | ||
| 164 | * | ||
| 165 | * The presence of v9fs_direct_IO() in the address space ops vector | ||
| 166 | * allowes open() O_DIRECT flags which would have failed otherwise. | ||
| 167 | * | ||
| 168 | * In the non-cached mode, we shunt off direct read and write requests before | ||
| 169 | * the VFS gets them, so this method should never be called. | ||
| 170 | * | ||
| 171 | * Direct IO is not 'yet' supported in the cached mode. Hence when | ||
| 172 | * this routine is called through generic_file_aio_read(), the read/write fails | ||
| 173 | * with an error. | ||
| 174 | * | ||
| 175 | */ | ||
| 176 | ssize_t v9fs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, | ||
| 177 | loff_t pos, unsigned long nr_segs) | ||
| 178 | { | ||
| 179 | P9_DPRINTK(P9_DEBUG_VFS, "v9fs_direct_IO: v9fs_direct_IO (%s) " | ||
| 180 | "off/no(%lld/%lu) EINVAL\n", | ||
| 181 | iocb->ki_filp->f_path.dentry->d_name.name, | ||
| 182 | (long long) pos, nr_segs); | ||
| 183 | |||
| 184 | return -EINVAL; | ||
| 185 | } | ||
| 157 | const struct address_space_operations v9fs_addr_operations = { | 186 | const struct address_space_operations v9fs_addr_operations = { |
| 158 | .readpage = v9fs_vfs_readpage, | 187 | .readpage = v9fs_vfs_readpage, |
| 159 | .readpages = v9fs_vfs_readpages, | 188 | .readpages = v9fs_vfs_readpages, |
| 160 | .releasepage = v9fs_release_page, | 189 | .releasepage = v9fs_release_page, |
| 161 | .invalidatepage = v9fs_invalidate_page, | 190 | .invalidatepage = v9fs_invalidate_page, |
| 162 | .launder_page = v9fs_launder_page, | 191 | .launder_page = v9fs_launder_page, |
| 192 | .direct_IO = v9fs_direct_IO, | ||
| 163 | }; | 193 | }; |
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c index 899f168fd19c..b84ebe8cefed 100644 --- a/fs/9p/vfs_dir.c +++ b/fs/9p/vfs_dir.c | |||
| @@ -242,7 +242,8 @@ static int v9fs_dir_readdir_dotl(struct file *filp, void *dirent, | |||
| 242 | while (rdir->head < rdir->tail) { | 242 | while (rdir->head < rdir->tail) { |
| 243 | 243 | ||
| 244 | err = p9dirent_read(rdir->buf + rdir->head, | 244 | err = p9dirent_read(rdir->buf + rdir->head, |
| 245 | buflen - rdir->head, &curdirent, | 245 | rdir->tail - rdir->head, |
| 246 | &curdirent, | ||
| 246 | fid->clnt->proto_version); | 247 | fid->clnt->proto_version); |
| 247 | if (err < 0) { | 248 | if (err < 0) { |
| 248 | P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err); | 249 | P9_DPRINTK(P9_DEBUG_VFS, "returned %d\n", err); |
| @@ -314,4 +315,5 @@ const struct file_operations v9fs_dir_operations_dotl = { | |||
| 314 | .readdir = v9fs_dir_readdir_dotl, | 315 | .readdir = v9fs_dir_readdir_dotl, |
| 315 | .open = v9fs_file_open, | 316 | .open = v9fs_file_open, |
| 316 | .release = v9fs_dir_release, | 317 | .release = v9fs_dir_release, |
| 318 | .fsync = v9fs_file_fsync_dotl, | ||
| 317 | }; | 319 | }; |
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index e97c92bd6f16..240c30674396 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c | |||
| @@ -33,6 +33,7 @@ | |||
| 33 | #include <linux/inet.h> | 33 | #include <linux/inet.h> |
| 34 | #include <linux/list.h> | 34 | #include <linux/list.h> |
| 35 | #include <linux/pagemap.h> | 35 | #include <linux/pagemap.h> |
| 36 | #include <linux/utsname.h> | ||
| 36 | #include <asm/uaccess.h> | 37 | #include <asm/uaccess.h> |
| 37 | #include <linux/idr.h> | 38 | #include <linux/idr.h> |
| 38 | #include <net/9p/9p.h> | 39 | #include <net/9p/9p.h> |
| @@ -44,6 +45,7 @@ | |||
| 44 | #include "cache.h" | 45 | #include "cache.h" |
| 45 | 46 | ||
| 46 | static const struct file_operations v9fs_cached_file_operations; | 47 | static const struct file_operations v9fs_cached_file_operations; |
| 48 | static const struct file_operations v9fs_cached_file_operations_dotl; | ||
| 47 | 49 | ||
| 48 | /** | 50 | /** |
| 49 | * v9fs_file_open - open a file (or directory) | 51 | * v9fs_file_open - open a file (or directory) |
| @@ -92,6 +94,8 @@ int v9fs_file_open(struct inode *inode, struct file *file) | |||
| 92 | /* enable cached file options */ | 94 | /* enable cached file options */ |
| 93 | if(file->f_op == &v9fs_file_operations) | 95 | if(file->f_op == &v9fs_file_operations) |
| 94 | file->f_op = &v9fs_cached_file_operations; | 96 | file->f_op = &v9fs_cached_file_operations; |
| 97 | else if (file->f_op == &v9fs_file_operations_dotl) | ||
| 98 | file->f_op = &v9fs_cached_file_operations_dotl; | ||
| 95 | 99 | ||
| 96 | #ifdef CONFIG_9P_FSCACHE | 100 | #ifdef CONFIG_9P_FSCACHE |
| 97 | v9fs_cache_inode_set_cookie(inode, file); | 101 | 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) | |||
| 130 | return res; | 134 | return res; |
| 131 | } | 135 | } |
| 132 | 136 | ||
| 137 | static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl) | ||
| 138 | { | ||
| 139 | struct p9_flock flock; | ||
| 140 | struct p9_fid *fid; | ||
| 141 | uint8_t status; | ||
| 142 | int res = 0; | ||
| 143 | unsigned char fl_type; | ||
| 144 | |||
| 145 | fid = filp->private_data; | ||
| 146 | BUG_ON(fid == NULL); | ||
| 147 | |||
| 148 | if ((fl->fl_flags & FL_POSIX) != FL_POSIX) | ||
| 149 | BUG(); | ||
| 150 | |||
| 151 | res = posix_lock_file_wait(filp, fl); | ||
| 152 | if (res < 0) | ||
| 153 | goto out; | ||
| 154 | |||
| 155 | /* convert posix lock to p9 tlock args */ | ||
| 156 | memset(&flock, 0, sizeof(flock)); | ||
| 157 | flock.type = fl->fl_type; | ||
| 158 | flock.start = fl->fl_start; | ||
| 159 | if (fl->fl_end == OFFSET_MAX) | ||
| 160 | flock.length = 0; | ||
| 161 | else | ||
| 162 | flock.length = fl->fl_end - fl->fl_start + 1; | ||
| 163 | flock.proc_id = fl->fl_pid; | ||
| 164 | flock.client_id = utsname()->nodename; | ||
| 165 | if (IS_SETLKW(cmd)) | ||
| 166 | flock.flags = P9_LOCK_FLAGS_BLOCK; | ||
| 167 | |||
| 168 | /* | ||
| 169 | * if its a blocked request and we get P9_LOCK_BLOCKED as the status | ||
| 170 | * for lock request, keep on trying | ||
| 171 | */ | ||
| 172 | for (;;) { | ||
| 173 | res = p9_client_lock_dotl(fid, &flock, &status); | ||
| 174 | if (res < 0) | ||
| 175 | break; | ||
| 176 | |||
| 177 | if (status != P9_LOCK_BLOCKED) | ||
| 178 | break; | ||
| 179 | if (status == P9_LOCK_BLOCKED && !IS_SETLKW(cmd)) | ||
| 180 | break; | ||
| 181 | schedule_timeout_interruptible(P9_LOCK_TIMEOUT); | ||
| 182 | } | ||
| 183 | |||
| 184 | /* map 9p status to VFS status */ | ||
| 185 | switch (status) { | ||
| 186 | case P9_LOCK_SUCCESS: | ||
| 187 | res = 0; | ||
| 188 | break; | ||
| 189 | case P9_LOCK_BLOCKED: | ||
| 190 | res = -EAGAIN; | ||
| 191 | break; | ||
| 192 | case P9_LOCK_ERROR: | ||
| 193 | case P9_LOCK_GRACE: | ||
| 194 | res = -ENOLCK; | ||
| 195 | break; | ||
| 196 | default: | ||
| 197 | BUG(); | ||
| 198 | } | ||
| 199 | |||
| 200 | /* | ||
| 201 | * incase server returned error for lock request, revert | ||
| 202 | * it locally | ||
| 203 | */ | ||
| 204 | if (res < 0 && fl->fl_type != F_UNLCK) { | ||
| 205 | fl_type = fl->fl_type; | ||
| 206 | fl->fl_type = F_UNLCK; | ||
| 207 | res = posix_lock_file_wait(filp, fl); | ||
| 208 | fl->fl_type = fl_type; | ||
| 209 | } | ||
| 210 | out: | ||
| 211 | return res; | ||
| 212 | } | ||
| 213 | |||
| 214 | static int v9fs_file_getlock(struct file *filp, struct file_lock *fl) | ||
| 215 | { | ||
| 216 | struct p9_getlock glock; | ||
| 217 | struct p9_fid *fid; | ||
| 218 | int res = 0; | ||
| 219 | |||
| 220 | fid = filp->private_data; | ||
| 221 | BUG_ON(fid == NULL); | ||
| 222 | |||
| 223 | posix_test_lock(filp, fl); | ||
| 224 | /* | ||
| 225 | * if we have a conflicting lock locally, no need to validate | ||
| 226 | * with server | ||
| 227 | */ | ||
| 228 | if (fl->fl_type != F_UNLCK) | ||
| 229 | return res; | ||
| 230 | |||
| 231 | /* convert posix lock to p9 tgetlock args */ | ||
| 232 | memset(&glock, 0, sizeof(glock)); | ||
| 233 | glock.type = fl->fl_type; | ||
| 234 | glock.start = fl->fl_start; | ||
| 235 | if (fl->fl_end == OFFSET_MAX) | ||
| 236 | glock.length = 0; | ||
| 237 | else | ||
| 238 | glock.length = fl->fl_end - fl->fl_start + 1; | ||
| 239 | glock.proc_id = fl->fl_pid; | ||
| 240 | glock.client_id = utsname()->nodename; | ||
| 241 | |||
| 242 | res = p9_client_getlock_dotl(fid, &glock); | ||
| 243 | if (res < 0) | ||
| 244 | return res; | ||
| 245 | if (glock.type != F_UNLCK) { | ||
| 246 | fl->fl_type = glock.type; | ||
| 247 | fl->fl_start = glock.start; | ||
| 248 | if (glock.length == 0) | ||
| 249 | fl->fl_end = OFFSET_MAX; | ||
| 250 | else | ||
| 251 | fl->fl_end = glock.start + glock.length - 1; | ||
| 252 | fl->fl_pid = glock.proc_id; | ||
| 253 | } else | ||
| 254 | fl->fl_type = F_UNLCK; | ||
| 255 | |||
| 256 | return res; | ||
| 257 | } | ||
| 258 | |||
| 259 | /** | ||
| 260 | * v9fs_file_lock_dotl - lock a file (or directory) | ||
| 261 | * @filp: file to be locked | ||
| 262 | * @cmd: lock command | ||
| 263 | * @fl: file lock structure | ||
| 264 | * | ||
| 265 | */ | ||
| 266 | |||
| 267 | static int v9fs_file_lock_dotl(struct file *filp, int cmd, struct file_lock *fl) | ||
| 268 | { | ||
| 269 | struct inode *inode = filp->f_path.dentry->d_inode; | ||
| 270 | int ret = -ENOLCK; | ||
| 271 | |||
| 272 | P9_DPRINTK(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %s\n", filp, | ||
| 273 | cmd, fl, filp->f_path.dentry->d_name.name); | ||
| 274 | |||
| 275 | /* No mandatory locks */ | ||
| 276 | if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK) | ||
| 277 | goto out_err; | ||
| 278 | |||
| 279 | if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) { | ||
| 280 | filemap_write_and_wait(inode->i_mapping); | ||
| 281 | invalidate_mapping_pages(&inode->i_data, 0, -1); | ||
| 282 | } | ||
| 283 | |||
| 284 | if (IS_SETLK(cmd) || IS_SETLKW(cmd)) | ||
| 285 | ret = v9fs_file_do_lock(filp, cmd, fl); | ||
| 286 | else if (IS_GETLK(cmd)) | ||
| 287 | ret = v9fs_file_getlock(filp, fl); | ||
| 288 | else | ||
| 289 | ret = -EINVAL; | ||
| 290 | out_err: | ||
| 291 | return ret; | ||
| 292 | } | ||
| 293 | |||
| 294 | /** | ||
| 295 | * v9fs_file_flock_dotl - lock a file | ||
| 296 | * @filp: file to be locked | ||
| 297 | * @cmd: lock command | ||
| 298 | * @fl: file lock structure | ||
| 299 | * | ||
| 300 | */ | ||
| 301 | |||
| 302 | static int v9fs_file_flock_dotl(struct file *filp, int cmd, | ||
| 303 | struct file_lock *fl) | ||
| 304 | { | ||
| 305 | struct inode *inode = filp->f_path.dentry->d_inode; | ||
| 306 | int ret = -ENOLCK; | ||
| 307 | |||
| 308 | P9_DPRINTK(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %s\n", filp, | ||
| 309 | cmd, fl, filp->f_path.dentry->d_name.name); | ||
| 310 | |||
| 311 | /* No mandatory locks */ | ||
| 312 | if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK) | ||
| 313 | goto out_err; | ||
| 314 | |||
| 315 | if (!(fl->fl_flags & FL_FLOCK)) | ||
| 316 | goto out_err; | ||
| 317 | |||
| 318 | if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) { | ||
| 319 | filemap_write_and_wait(inode->i_mapping); | ||
| 320 | invalidate_mapping_pages(&inode->i_data, 0, -1); | ||
| 321 | } | ||
| 322 | /* Convert flock to posix lock */ | ||
| 323 | fl->fl_owner = (fl_owner_t)filp; | ||
| 324 | fl->fl_start = 0; | ||
| 325 | fl->fl_end = OFFSET_MAX; | ||
| 326 | fl->fl_flags |= FL_POSIX; | ||
| 327 | fl->fl_flags ^= FL_FLOCK; | ||
| 328 | |||
| 329 | if (IS_SETLK(cmd) | IS_SETLKW(cmd)) | ||
| 330 | ret = v9fs_file_do_lock(filp, cmd, fl); | ||
| 331 | else | ||
| 332 | ret = -EINVAL; | ||
| 333 | out_err: | ||
| 334 | return ret; | ||
| 335 | } | ||
| 336 | |||
| 133 | /** | 337 | /** |
| 134 | * v9fs_file_readn - read from a file | 338 | * v9fs_file_readn - read from a file |
| 135 | * @filp: file pointer to read | 339 | * @filp: file pointer to read |
| @@ -219,7 +423,9 @@ static ssize_t | |||
| 219 | v9fs_file_write(struct file *filp, const char __user * data, | 423 | v9fs_file_write(struct file *filp, const char __user * data, |
| 220 | size_t count, loff_t * offset) | 424 | size_t count, loff_t * offset) |
| 221 | { | 425 | { |
| 222 | int n, rsize, total = 0; | 426 | ssize_t retval; |
| 427 | size_t total = 0; | ||
| 428 | int n; | ||
| 223 | struct p9_fid *fid; | 429 | struct p9_fid *fid; |
| 224 | struct p9_client *clnt; | 430 | struct p9_client *clnt; |
| 225 | struct inode *inode = filp->f_path.dentry->d_inode; | 431 | struct inode *inode = filp->f_path.dentry->d_inode; |
| @@ -232,14 +438,19 @@ v9fs_file_write(struct file *filp, const char __user * data, | |||
| 232 | fid = filp->private_data; | 438 | fid = filp->private_data; |
| 233 | clnt = fid->clnt; | 439 | clnt = fid->clnt; |
| 234 | 440 | ||
| 235 | rsize = fid->iounit ? fid->iounit : clnt->msize - P9_IOHDRSZ; | 441 | retval = generic_write_checks(filp, &origin, &count, 0); |
| 442 | if (retval) | ||
| 443 | goto out; | ||
| 236 | 444 | ||
| 237 | do { | 445 | retval = -EINVAL; |
| 238 | if (count < rsize) | 446 | if ((ssize_t) count < 0) |
| 239 | rsize = count; | 447 | goto out; |
| 448 | retval = 0; | ||
| 449 | if (!count) | ||
| 450 | goto out; | ||
| 240 | 451 | ||
| 241 | n = p9_client_write(fid, NULL, data+total, origin+total, | 452 | do { |
| 242 | rsize); | 453 | n = p9_client_write(fid, NULL, data+total, origin+total, count); |
| 243 | if (n <= 0) | 454 | if (n <= 0) |
| 244 | break; | 455 | break; |
| 245 | count -= n; | 456 | count -= n; |
| @@ -258,9 +469,11 @@ v9fs_file_write(struct file *filp, const char __user * data, | |||
| 258 | } | 469 | } |
| 259 | 470 | ||
| 260 | if (n < 0) | 471 | if (n < 0) |
| 261 | return n; | 472 | retval = n; |
| 262 | 473 | else | |
| 263 | return total; | 474 | retval = total; |
| 475 | out: | ||
| 476 | return retval; | ||
| 264 | } | 477 | } |
| 265 | 478 | ||
| 266 | static int v9fs_file_fsync(struct file *filp, int datasync) | 479 | static int v9fs_file_fsync(struct file *filp, int datasync) |
| @@ -278,6 +491,20 @@ static int v9fs_file_fsync(struct file *filp, int datasync) | |||
| 278 | return retval; | 491 | return retval; |
| 279 | } | 492 | } |
| 280 | 493 | ||
| 494 | int v9fs_file_fsync_dotl(struct file *filp, int datasync) | ||
| 495 | { | ||
| 496 | struct p9_fid *fid; | ||
| 497 | int retval; | ||
| 498 | |||
| 499 | P9_DPRINTK(P9_DEBUG_VFS, "v9fs_file_fsync_dotl: filp %p datasync %x\n", | ||
| 500 | filp, datasync); | ||
| 501 | |||
| 502 | fid = filp->private_data; | ||
| 503 | |||
| 504 | retval = p9_client_fsync(fid, datasync); | ||
| 505 | return retval; | ||
| 506 | } | ||
| 507 | |||
| 281 | static const struct file_operations v9fs_cached_file_operations = { | 508 | static const struct file_operations v9fs_cached_file_operations = { |
| 282 | .llseek = generic_file_llseek, | 509 | .llseek = generic_file_llseek, |
| 283 | .read = do_sync_read, | 510 | .read = do_sync_read, |
| @@ -290,6 +517,19 @@ static const struct file_operations v9fs_cached_file_operations = { | |||
| 290 | .fsync = v9fs_file_fsync, | 517 | .fsync = v9fs_file_fsync, |
| 291 | }; | 518 | }; |
| 292 | 519 | ||
| 520 | static const struct file_operations v9fs_cached_file_operations_dotl = { | ||
| 521 | .llseek = generic_file_llseek, | ||
| 522 | .read = do_sync_read, | ||
| 523 | .aio_read = generic_file_aio_read, | ||
| 524 | .write = v9fs_file_write, | ||
| 525 | .open = v9fs_file_open, | ||
| 526 | .release = v9fs_dir_release, | ||
| 527 | .lock = v9fs_file_lock_dotl, | ||
| 528 | .flock = v9fs_file_flock_dotl, | ||
| 529 | .mmap = generic_file_readonly_mmap, | ||
| 530 | .fsync = v9fs_file_fsync_dotl, | ||
| 531 | }; | ||
| 532 | |||
| 293 | const struct file_operations v9fs_file_operations = { | 533 | const struct file_operations v9fs_file_operations = { |
| 294 | .llseek = generic_file_llseek, | 534 | .llseek = generic_file_llseek, |
| 295 | .read = v9fs_file_read, | 535 | .read = v9fs_file_read, |
| @@ -307,7 +547,8 @@ const struct file_operations v9fs_file_operations_dotl = { | |||
| 307 | .write = v9fs_file_write, | 547 | .write = v9fs_file_write, |
| 308 | .open = v9fs_file_open, | 548 | .open = v9fs_file_open, |
| 309 | .release = v9fs_dir_release, | 549 | .release = v9fs_dir_release, |
| 310 | .lock = v9fs_file_lock, | 550 | .lock = v9fs_file_lock_dotl, |
| 551 | .flock = v9fs_file_flock_dotl, | ||
| 311 | .mmap = generic_file_readonly_mmap, | 552 | .mmap = generic_file_readonly_mmap, |
| 312 | .fsync = v9fs_file_fsync, | 553 | .fsync = v9fs_file_fsync_dotl, |
| 313 | }; | 554 | }; |
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index ef5905f7c8a3..34bf71b56542 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c | |||
| @@ -36,6 +36,7 @@ | |||
| 36 | #include <linux/sched.h> | 36 | #include <linux/sched.h> |
| 37 | #include <linux/slab.h> | 37 | #include <linux/slab.h> |
| 38 | #include <linux/xattr.h> | 38 | #include <linux/xattr.h> |
| 39 | #include <linux/posix_acl.h> | ||
| 39 | #include <net/9p/9p.h> | 40 | #include <net/9p/9p.h> |
| 40 | #include <net/9p/client.h> | 41 | #include <net/9p/client.h> |
| 41 | 42 | ||
| @@ -44,6 +45,7 @@ | |||
| 44 | #include "fid.h" | 45 | #include "fid.h" |
| 45 | #include "cache.h" | 46 | #include "cache.h" |
| 46 | #include "xattr.h" | 47 | #include "xattr.h" |
| 48 | #include "acl.h" | ||
| 47 | 49 | ||
| 48 | static const struct inode_operations v9fs_dir_inode_operations; | 50 | static const struct inode_operations v9fs_dir_inode_operations; |
| 49 | static const struct inode_operations v9fs_dir_inode_operations_dotu; | 51 | static const struct inode_operations v9fs_dir_inode_operations_dotu; |
| @@ -53,6 +55,10 @@ static const struct inode_operations v9fs_file_inode_operations_dotl; | |||
| 53 | static const struct inode_operations v9fs_symlink_inode_operations; | 55 | static const struct inode_operations v9fs_symlink_inode_operations; |
| 54 | static const struct inode_operations v9fs_symlink_inode_operations_dotl; | 56 | static const struct inode_operations v9fs_symlink_inode_operations_dotl; |
| 55 | 57 | ||
| 58 | static int | ||
| 59 | v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode, | ||
| 60 | dev_t rdev); | ||
| 61 | |||
| 56 | /** | 62 | /** |
| 57 | * unixmode2p9mode - convert unix mode bits to plan 9 | 63 | * unixmode2p9mode - convert unix mode bits to plan 9 |
| 58 | * @v9ses: v9fs session information | 64 | * @v9ses: v9fs session information |
| @@ -500,6 +506,11 @@ v9fs_inode_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid, | |||
| 500 | v9fs_vcookie_set_qid(ret, &st->qid); | 506 | v9fs_vcookie_set_qid(ret, &st->qid); |
| 501 | v9fs_cache_inode_get_cookie(ret); | 507 | v9fs_cache_inode_get_cookie(ret); |
| 502 | #endif | 508 | #endif |
| 509 | err = v9fs_get_acl(ret, fid); | ||
| 510 | if (err) { | ||
| 511 | iput(ret); | ||
| 512 | goto error; | ||
| 513 | } | ||
| 503 | kfree(st); | 514 | kfree(st); |
| 504 | return ret; | 515 | return ret; |
| 505 | error: | 516 | error: |
| @@ -553,13 +564,6 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir) | |||
| 553 | return retval; | 564 | return retval; |
| 554 | } | 565 | } |
| 555 | 566 | ||
| 556 | static int | ||
| 557 | v9fs_open_created(struct inode *inode, struct file *file) | ||
| 558 | { | ||
| 559 | return 0; | ||
| 560 | } | ||
| 561 | |||
| 562 | |||
| 563 | /** | 567 | /** |
| 564 | * v9fs_create - Create a file | 568 | * v9fs_create - Create a file |
| 565 | * @v9ses: session information | 569 | * @v9ses: session information |
| @@ -655,29 +659,37 @@ error: | |||
| 655 | */ | 659 | */ |
| 656 | 660 | ||
| 657 | static int | 661 | static int |
| 658 | v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int mode, | 662 | v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode, |
| 659 | struct nameidata *nd) | 663 | struct nameidata *nd) |
| 660 | { | 664 | { |
| 661 | int err = 0; | 665 | int err = 0; |
| 662 | char *name = NULL; | 666 | char *name = NULL; |
| 663 | gid_t gid; | 667 | gid_t gid; |
| 664 | int flags; | 668 | int flags; |
| 669 | mode_t mode; | ||
| 665 | struct v9fs_session_info *v9ses; | 670 | struct v9fs_session_info *v9ses; |
| 666 | struct p9_fid *fid = NULL; | 671 | struct p9_fid *fid = NULL; |
| 667 | struct p9_fid *dfid, *ofid; | 672 | struct p9_fid *dfid, *ofid; |
| 668 | struct file *filp; | 673 | struct file *filp; |
| 669 | struct p9_qid qid; | 674 | struct p9_qid qid; |
| 670 | struct inode *inode; | 675 | struct inode *inode; |
| 676 | struct posix_acl *pacl = NULL, *dacl = NULL; | ||
| 671 | 677 | ||
| 672 | v9ses = v9fs_inode2v9ses(dir); | 678 | v9ses = v9fs_inode2v9ses(dir); |
| 673 | if (nd && nd->flags & LOOKUP_OPEN) | 679 | if (nd && nd->flags & LOOKUP_OPEN) |
| 674 | flags = nd->intent.open.flags - 1; | 680 | flags = nd->intent.open.flags - 1; |
| 675 | else | 681 | else { |
| 676 | flags = O_RDWR; | 682 | /* |
| 683 | * create call without LOOKUP_OPEN is due | ||
| 684 | * to mknod of regular files. So use mknod | ||
| 685 | * operation. | ||
| 686 | */ | ||
| 687 | return v9fs_vfs_mknod_dotl(dir, dentry, omode, 0); | ||
| 688 | } | ||
| 677 | 689 | ||
| 678 | name = (char *) dentry->d_name.name; | 690 | name = (char *) dentry->d_name.name; |
| 679 | P9_DPRINTK(P9_DEBUG_VFS, "v9fs_vfs_create_dotl: name:%s flags:0x%x " | 691 | P9_DPRINTK(P9_DEBUG_VFS, "v9fs_vfs_create_dotl: name:%s flags:0x%x " |
| 680 | "mode:0x%x\n", name, flags, mode); | 692 | "mode:0x%x\n", name, flags, omode); |
| 681 | 693 | ||
| 682 | dfid = v9fs_fid_lookup(dentry->d_parent); | 694 | dfid = v9fs_fid_lookup(dentry->d_parent); |
| 683 | if (IS_ERR(dfid)) { | 695 | if (IS_ERR(dfid)) { |
| @@ -695,6 +707,15 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int mode, | |||
| 695 | } | 707 | } |
| 696 | 708 | ||
| 697 | gid = v9fs_get_fsgid_for_create(dir); | 709 | gid = v9fs_get_fsgid_for_create(dir); |
| 710 | |||
| 711 | mode = omode; | ||
| 712 | /* Update mode based on ACL value */ | ||
| 713 | err = v9fs_acl_mode(dir, &mode, &dacl, &pacl); | ||
| 714 | if (err) { | ||
| 715 | P9_DPRINTK(P9_DEBUG_VFS, | ||
| 716 | "Failed to get acl values in creat %d\n", err); | ||
| 717 | goto error; | ||
| 718 | } | ||
| 698 | err = p9_client_create_dotl(ofid, name, flags, mode, gid, &qid); | 719 | err = p9_client_create_dotl(ofid, name, flags, mode, gid, &qid); |
| 699 | if (err < 0) { | 720 | if (err < 0) { |
| 700 | P9_DPRINTK(P9_DEBUG_VFS, | 721 | P9_DPRINTK(P9_DEBUG_VFS, |
| @@ -702,46 +723,52 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int mode, | |||
| 702 | err); | 723 | err); |
| 703 | goto error; | 724 | goto error; |
| 704 | } | 725 | } |
| 726 | /* instantiate inode and assign the unopened fid to the dentry */ | ||
| 727 | if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE || | ||
| 728 | (nd && nd->flags & LOOKUP_OPEN)) { | ||
| 729 | fid = p9_client_walk(dfid, 1, &name, 1); | ||
| 730 | if (IS_ERR(fid)) { | ||
| 731 | err = PTR_ERR(fid); | ||
| 732 | P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", | ||
| 733 | err); | ||
| 734 | fid = NULL; | ||
| 735 | goto error; | ||
| 736 | } | ||
| 705 | 737 | ||
| 706 | /* No need to populate the inode if we are not opening the file AND | 738 | inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb); |
| 707 | * not in cached mode. | 739 | if (IS_ERR(inode)) { |
| 708 | */ | 740 | err = PTR_ERR(inode); |
| 709 | if (!v9ses->cache && !(nd && nd->flags & LOOKUP_OPEN)) { | 741 | P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", |
| 710 | /* Not in cached mode. No need to populate inode with stat */ | 742 | err); |
| 711 | dentry->d_op = &v9fs_dentry_operations; | 743 | goto error; |
| 712 | p9_client_clunk(ofid); | 744 | } |
| 713 | d_instantiate(dentry, NULL); | ||
| 714 | return 0; | ||
| 715 | } | ||
| 716 | |||
| 717 | /* Now walk from the parent so we can get an unopened fid. */ | ||
| 718 | fid = p9_client_walk(dfid, 1, &name, 1); | ||
| 719 | if (IS_ERR(fid)) { | ||
| 720 | err = PTR_ERR(fid); | ||
| 721 | P9_DPRINTK(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err); | ||
| 722 | fid = NULL; | ||
| 723 | goto error; | ||
| 724 | } | ||
| 725 | |||
| 726 | /* instantiate inode and assign the unopened fid to dentry */ | ||
| 727 | inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb); | ||
| 728 | if (IS_ERR(inode)) { | ||
| 729 | err = PTR_ERR(inode); | ||
| 730 | P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err); | ||
| 731 | goto error; | ||
| 732 | } | ||
| 733 | if (v9ses->cache) | ||
| 734 | dentry->d_op = &v9fs_cached_dentry_operations; | 745 | dentry->d_op = &v9fs_cached_dentry_operations; |
| 735 | else | 746 | d_instantiate(dentry, inode); |
| 747 | err = v9fs_fid_add(dentry, fid); | ||
| 748 | if (err < 0) | ||
| 749 | goto error; | ||
| 750 | /* The fid would get clunked via a dput */ | ||
| 751 | fid = NULL; | ||
| 752 | } else { | ||
| 753 | /* | ||
| 754 | * Not in cached mode. No need to populate | ||
| 755 | * inode with stat. We need to get an inode | ||
| 756 | * so that we can set the acl with dentry | ||
| 757 | */ | ||
| 758 | inode = v9fs_get_inode(dir->i_sb, mode); | ||
| 759 | if (IS_ERR(inode)) { | ||
| 760 | err = PTR_ERR(inode); | ||
| 761 | goto error; | ||
| 762 | } | ||
| 736 | dentry->d_op = &v9fs_dentry_operations; | 763 | dentry->d_op = &v9fs_dentry_operations; |
| 737 | d_instantiate(dentry, inode); | 764 | d_instantiate(dentry, inode); |
| 738 | err = v9fs_fid_add(dentry, fid); | 765 | } |
| 739 | if (err < 0) | 766 | /* Now set the ACL based on the default value */ |
| 740 | goto error; | 767 | v9fs_set_create_acl(dentry, dacl, pacl); |
| 741 | 768 | ||
| 742 | /* if we are opening a file, assign the open fid to the file */ | 769 | /* if we are opening a file, assign the open fid to the file */ |
| 743 | if (nd && nd->flags & LOOKUP_OPEN) { | 770 | if (nd && nd->flags & LOOKUP_OPEN) { |
| 744 | filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created); | 771 | filp = lookup_instantiate_filp(nd, dentry, generic_file_open); |
| 745 | if (IS_ERR(filp)) { | 772 | if (IS_ERR(filp)) { |
| 746 | p9_client_clunk(ofid); | 773 | p9_client_clunk(ofid); |
| 747 | return PTR_ERR(filp); | 774 | return PTR_ERR(filp); |
| @@ -800,7 +827,7 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode, | |||
| 800 | 827 | ||
| 801 | /* if we are opening a file, assign the open fid to the file */ | 828 | /* if we are opening a file, assign the open fid to the file */ |
| 802 | if (nd && nd->flags & LOOKUP_OPEN) { | 829 | if (nd && nd->flags & LOOKUP_OPEN) { |
| 803 | filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created); | 830 | filp = lookup_instantiate_filp(nd, dentry, generic_file_open); |
| 804 | if (IS_ERR(filp)) { | 831 | if (IS_ERR(filp)) { |
| 805 | err = PTR_ERR(filp); | 832 | err = PTR_ERR(filp); |
| 806 | goto error; | 833 | goto error; |
| @@ -859,23 +886,28 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
| 859 | * | 886 | * |
| 860 | */ | 887 | */ |
| 861 | 888 | ||
| 862 | static int v9fs_vfs_mkdir_dotl(struct inode *dir, struct dentry *dentry, | 889 | static int v9fs_vfs_mkdir_dotl(struct inode *dir, |
| 863 | int mode) | 890 | struct dentry *dentry, int omode) |
| 864 | { | 891 | { |
| 865 | int err; | 892 | int err; |
| 866 | struct v9fs_session_info *v9ses; | 893 | struct v9fs_session_info *v9ses; |
| 867 | struct p9_fid *fid = NULL, *dfid = NULL; | 894 | struct p9_fid *fid = NULL, *dfid = NULL; |
| 868 | gid_t gid; | 895 | gid_t gid; |
| 869 | char *name; | 896 | char *name; |
| 897 | mode_t mode; | ||
| 870 | struct inode *inode; | 898 | struct inode *inode; |
| 871 | struct p9_qid qid; | 899 | struct p9_qid qid; |
| 872 | struct dentry *dir_dentry; | 900 | struct dentry *dir_dentry; |
| 901 | struct posix_acl *dacl = NULL, *pacl = NULL; | ||
| 873 | 902 | ||
| 874 | P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name); | 903 | P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name); |
| 875 | err = 0; | 904 | err = 0; |
| 876 | v9ses = v9fs_inode2v9ses(dir); | 905 | v9ses = v9fs_inode2v9ses(dir); |
| 877 | 906 | ||
| 878 | mode |= S_IFDIR; | 907 | omode |= S_IFDIR; |
| 908 | if (dir->i_mode & S_ISGID) | ||
| 909 | omode |= S_ISGID; | ||
| 910 | |||
| 879 | dir_dentry = v9fs_dentry_from_dir_inode(dir); | 911 | dir_dentry = v9fs_dentry_from_dir_inode(dir); |
| 880 | dfid = v9fs_fid_lookup(dir_dentry); | 912 | dfid = v9fs_fid_lookup(dir_dentry); |
| 881 | if (IS_ERR(dfid)) { | 913 | if (IS_ERR(dfid)) { |
| @@ -886,11 +918,14 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir, struct dentry *dentry, | |||
| 886 | } | 918 | } |
| 887 | 919 | ||
| 888 | gid = v9fs_get_fsgid_for_create(dir); | 920 | gid = v9fs_get_fsgid_for_create(dir); |
| 889 | if (gid < 0) { | 921 | mode = omode; |
| 890 | P9_DPRINTK(P9_DEBUG_VFS, "v9fs_get_fsgid_for_create failed\n"); | 922 | /* Update mode based on ACL value */ |
| 923 | err = v9fs_acl_mode(dir, &mode, &dacl, &pacl); | ||
| 924 | if (err) { | ||
| 925 | P9_DPRINTK(P9_DEBUG_VFS, | ||
| 926 | "Failed to get acl values in mkdir %d\n", err); | ||
| 891 | goto error; | 927 | goto error; |
| 892 | } | 928 | } |
| 893 | |||
| 894 | name = (char *) dentry->d_name.name; | 929 | name = (char *) dentry->d_name.name; |
| 895 | err = p9_client_mkdir_dotl(dfid, name, mode, gid, &qid); | 930 | err = p9_client_mkdir_dotl(dfid, name, mode, gid, &qid); |
| 896 | if (err < 0) | 931 | if (err < 0) |
| @@ -920,7 +955,23 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir, struct dentry *dentry, | |||
| 920 | if (err < 0) | 955 | if (err < 0) |
| 921 | goto error; | 956 | goto error; |
| 922 | fid = NULL; | 957 | fid = NULL; |
| 958 | } else { | ||
| 959 | /* | ||
| 960 | * Not in cached mode. No need to populate | ||
| 961 | * inode with stat. We need to get an inode | ||
| 962 | * so that we can set the acl with dentry | ||
| 963 | */ | ||
| 964 | inode = v9fs_get_inode(dir->i_sb, mode); | ||
| 965 | if (IS_ERR(inode)) { | ||
| 966 | err = PTR_ERR(inode); | ||
| 967 | goto error; | ||
| 968 | } | ||
| 969 | dentry->d_op = &v9fs_dentry_operations; | ||
| 970 | d_instantiate(dentry, inode); | ||
| 923 | } | 971 | } |
| 972 | /* Now set the ACL based on the default value */ | ||
| 973 | v9fs_set_create_acl(dentry, dacl, pacl); | ||
| 974 | |||
| 924 | error: | 975 | error: |
| 925 | if (fid) | 976 | if (fid) |
| 926 | p9_client_clunk(fid); | 977 | p9_client_clunk(fid); |
| @@ -979,7 +1030,7 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, | |||
| 979 | 1030 | ||
| 980 | result = v9fs_fid_add(dentry, fid); | 1031 | result = v9fs_fid_add(dentry, fid); |
| 981 | if (result < 0) | 1032 | if (result < 0) |
| 982 | goto error; | 1033 | goto error_iput; |
| 983 | 1034 | ||
| 984 | inst_out: | 1035 | inst_out: |
| 985 | if (v9ses->cache) | 1036 | if (v9ses->cache) |
| @@ -990,6 +1041,8 @@ inst_out: | |||
| 990 | d_add(dentry, inode); | 1041 | d_add(dentry, inode); |
| 991 | return NULL; | 1042 | return NULL; |
| 992 | 1043 | ||
| 1044 | error_iput: | ||
| 1045 | iput(inode); | ||
| 993 | error: | 1046 | error: |
| 994 | p9_client_clunk(fid); | 1047 | p9_client_clunk(fid); |
| 995 | 1048 | ||
| @@ -1237,7 +1290,7 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) | |||
| 1237 | * | 1290 | * |
| 1238 | */ | 1291 | */ |
| 1239 | 1292 | ||
| 1240 | static int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr) | 1293 | int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr) |
| 1241 | { | 1294 | { |
| 1242 | int retval; | 1295 | int retval; |
| 1243 | struct v9fs_session_info *v9ses; | 1296 | struct v9fs_session_info *v9ses; |
| @@ -1279,6 +1332,12 @@ static int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr) | |||
| 1279 | 1332 | ||
| 1280 | setattr_copy(dentry->d_inode, iattr); | 1333 | setattr_copy(dentry->d_inode, iattr); |
| 1281 | mark_inode_dirty(dentry->d_inode); | 1334 | mark_inode_dirty(dentry->d_inode); |
| 1335 | if (iattr->ia_valid & ATTR_MODE) { | ||
| 1336 | /* We also want to update ACL when we update mode bits */ | ||
| 1337 | retval = v9fs_acl_chmod(dentry); | ||
| 1338 | if (retval < 0) | ||
| 1339 | return retval; | ||
| 1340 | } | ||
| 1282 | return 0; | 1341 | return 0; |
| 1283 | } | 1342 | } |
| 1284 | 1343 | ||
| @@ -1473,7 +1532,7 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen) | |||
| 1473 | if (IS_ERR(fid)) | 1532 | if (IS_ERR(fid)) |
| 1474 | return PTR_ERR(fid); | 1533 | return PTR_ERR(fid); |
| 1475 | 1534 | ||
| 1476 | if (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses)) | 1535 | if (!v9fs_proto_dotu(v9ses)) |
| 1477 | return -EBADF; | 1536 | return -EBADF; |
| 1478 | 1537 | ||
| 1479 | st = p9_client_stat(fid); | 1538 | st = p9_client_stat(fid); |
| @@ -1616,11 +1675,6 @@ v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry, | |||
| 1616 | 1675 | ||
| 1617 | gid = v9fs_get_fsgid_for_create(dir); | 1676 | gid = v9fs_get_fsgid_for_create(dir); |
| 1618 | 1677 | ||
| 1619 | if (gid < 0) { | ||
| 1620 | P9_DPRINTK(P9_DEBUG_VFS, "v9fs_get_egid failed %d\n", gid); | ||
| 1621 | goto error; | ||
| 1622 | } | ||
| 1623 | |||
| 1624 | /* Server doesn't alter fid on TSYMLINK. Hence no need to clone it. */ | 1678 | /* Server doesn't alter fid on TSYMLINK. Hence no need to clone it. */ |
| 1625 | err = p9_client_symlink(dfid, name, (char *)symname, gid, &qid); | 1679 | err = p9_client_symlink(dfid, name, (char *)symname, gid, &qid); |
| 1626 | 1680 | ||
| @@ -1855,21 +1909,23 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) | |||
| 1855 | * | 1909 | * |
| 1856 | */ | 1910 | */ |
| 1857 | static int | 1911 | static int |
| 1858 | v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int mode, | 1912 | v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode, |
| 1859 | dev_t rdev) | 1913 | dev_t rdev) |
| 1860 | { | 1914 | { |
| 1861 | int err; | 1915 | int err; |
| 1862 | char *name; | 1916 | char *name; |
| 1917 | mode_t mode; | ||
| 1863 | struct v9fs_session_info *v9ses; | 1918 | struct v9fs_session_info *v9ses; |
| 1864 | struct p9_fid *fid = NULL, *dfid = NULL; | 1919 | struct p9_fid *fid = NULL, *dfid = NULL; |
| 1865 | struct inode *inode; | 1920 | struct inode *inode; |
| 1866 | gid_t gid; | 1921 | gid_t gid; |
| 1867 | struct p9_qid qid; | 1922 | struct p9_qid qid; |
| 1868 | struct dentry *dir_dentry; | 1923 | struct dentry *dir_dentry; |
| 1924 | struct posix_acl *dacl = NULL, *pacl = NULL; | ||
| 1869 | 1925 | ||
| 1870 | P9_DPRINTK(P9_DEBUG_VFS, | 1926 | P9_DPRINTK(P9_DEBUG_VFS, |
| 1871 | " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino, | 1927 | " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino, |
| 1872 | dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev)); | 1928 | dentry->d_name.name, omode, MAJOR(rdev), MINOR(rdev)); |
| 1873 | 1929 | ||
| 1874 | if (!new_valid_dev(rdev)) | 1930 | if (!new_valid_dev(rdev)) |
| 1875 | return -EINVAL; | 1931 | return -EINVAL; |
| @@ -1885,11 +1941,14 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int mode, | |||
| 1885 | } | 1941 | } |
| 1886 | 1942 | ||
| 1887 | gid = v9fs_get_fsgid_for_create(dir); | 1943 | gid = v9fs_get_fsgid_for_create(dir); |
| 1888 | if (gid < 0) { | 1944 | mode = omode; |
| 1889 | P9_DPRINTK(P9_DEBUG_VFS, "v9fs_get_fsgid_for_create failed\n"); | 1945 | /* Update mode based on ACL value */ |
| 1946 | err = v9fs_acl_mode(dir, &mode, &dacl, &pacl); | ||
| 1947 | if (err) { | ||
| 1948 | P9_DPRINTK(P9_DEBUG_VFS, | ||
| 1949 | "Failed to get acl values in mknod %d\n", err); | ||
| 1890 | goto error; | 1950 | goto error; |
| 1891 | } | 1951 | } |
| 1892 | |||
| 1893 | name = (char *) dentry->d_name.name; | 1952 | name = (char *) dentry->d_name.name; |
| 1894 | 1953 | ||
| 1895 | err = p9_client_mknod_dotl(dfid, name, mode, rdev, gid, &qid); | 1954 | 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, | |||
| 1933 | dentry->d_op = &v9fs_dentry_operations; | 1992 | dentry->d_op = &v9fs_dentry_operations; |
| 1934 | d_instantiate(dentry, inode); | 1993 | d_instantiate(dentry, inode); |
| 1935 | } | 1994 | } |
| 1936 | 1995 | /* Now set the ACL based on the default value */ | |
| 1996 | v9fs_set_create_acl(dentry, dacl, pacl); | ||
| 1937 | error: | 1997 | error: |
| 1938 | if (fid) | 1998 | if (fid) |
| 1939 | p9_client_clunk(fid); | 1999 | p9_client_clunk(fid); |
| 1940 | return err; | 2000 | return err; |
| 1941 | } | 2001 | } |
| 1942 | 2002 | ||
| 2003 | static int | ||
| 2004 | v9fs_vfs_readlink_dotl(struct dentry *dentry, char *buffer, int buflen) | ||
| 2005 | { | ||
| 2006 | int retval; | ||
| 2007 | struct p9_fid *fid; | ||
| 2008 | char *target = NULL; | ||
| 2009 | |||
| 2010 | P9_DPRINTK(P9_DEBUG_VFS, " %s\n", dentry->d_name.name); | ||
| 2011 | retval = -EPERM; | ||
| 2012 | fid = v9fs_fid_lookup(dentry); | ||
| 2013 | if (IS_ERR(fid)) | ||
| 2014 | return PTR_ERR(fid); | ||
| 2015 | |||
| 2016 | retval = p9_client_readlink(fid, &target); | ||
| 2017 | if (retval < 0) | ||
| 2018 | return retval; | ||
| 2019 | |||
| 2020 | strncpy(buffer, target, buflen); | ||
| 2021 | P9_DPRINTK(P9_DEBUG_VFS, "%s -> %s\n", dentry->d_name.name, buffer); | ||
| 2022 | |||
| 2023 | retval = strnlen(buffer, buflen); | ||
| 2024 | return retval; | ||
| 2025 | } | ||
| 2026 | |||
| 2027 | /** | ||
| 2028 | * v9fs_vfs_follow_link_dotl - follow a symlink path | ||
| 2029 | * @dentry: dentry for symlink | ||
| 2030 | * @nd: nameidata | ||
| 2031 | * | ||
| 2032 | */ | ||
| 2033 | |||
| 2034 | static void * | ||
| 2035 | v9fs_vfs_follow_link_dotl(struct dentry *dentry, struct nameidata *nd) | ||
| 2036 | { | ||
| 2037 | int len = 0; | ||
| 2038 | char *link = __getname(); | ||
| 2039 | |||
| 2040 | P9_DPRINTK(P9_DEBUG_VFS, "%s n", dentry->d_name.name); | ||
| 2041 | |||
| 2042 | if (!link) | ||
| 2043 | link = ERR_PTR(-ENOMEM); | ||
| 2044 | else { | ||
| 2045 | len = v9fs_vfs_readlink_dotl(dentry, link, PATH_MAX); | ||
| 2046 | if (len < 0) { | ||
| 2047 | __putname(link); | ||
| 2048 | link = ERR_PTR(len); | ||
| 2049 | } else | ||
| 2050 | link[min(len, PATH_MAX-1)] = 0; | ||
| 2051 | } | ||
| 2052 | nd_set_link(nd, link); | ||
| 2053 | |||
| 2054 | return NULL; | ||
| 2055 | } | ||
| 2056 | |||
| 1943 | static const struct inode_operations v9fs_dir_inode_operations_dotu = { | 2057 | static const struct inode_operations v9fs_dir_inode_operations_dotu = { |
| 1944 | .create = v9fs_vfs_create, | 2058 | .create = v9fs_vfs_create, |
| 1945 | .lookup = v9fs_vfs_lookup, | 2059 | .lookup = v9fs_vfs_lookup, |
| @@ -1970,7 +2084,7 @@ static const struct inode_operations v9fs_dir_inode_operations_dotl = { | |||
| 1970 | .getxattr = generic_getxattr, | 2084 | .getxattr = generic_getxattr, |
| 1971 | .removexattr = generic_removexattr, | 2085 | .removexattr = generic_removexattr, |
| 1972 | .listxattr = v9fs_listxattr, | 2086 | .listxattr = v9fs_listxattr, |
| 1973 | 2087 | .check_acl = v9fs_check_acl, | |
| 1974 | }; | 2088 | }; |
| 1975 | 2089 | ||
| 1976 | static const struct inode_operations v9fs_dir_inode_operations = { | 2090 | static const struct inode_operations v9fs_dir_inode_operations = { |
| @@ -1997,6 +2111,7 @@ static const struct inode_operations v9fs_file_inode_operations_dotl = { | |||
| 1997 | .getxattr = generic_getxattr, | 2111 | .getxattr = generic_getxattr, |
| 1998 | .removexattr = generic_removexattr, | 2112 | .removexattr = generic_removexattr, |
| 1999 | .listxattr = v9fs_listxattr, | 2113 | .listxattr = v9fs_listxattr, |
| 2114 | .check_acl = v9fs_check_acl, | ||
| 2000 | }; | 2115 | }; |
| 2001 | 2116 | ||
| 2002 | static const struct inode_operations v9fs_symlink_inode_operations = { | 2117 | static const struct inode_operations v9fs_symlink_inode_operations = { |
| @@ -2008,8 +2123,8 @@ static const struct inode_operations v9fs_symlink_inode_operations = { | |||
| 2008 | }; | 2123 | }; |
| 2009 | 2124 | ||
| 2010 | static const struct inode_operations v9fs_symlink_inode_operations_dotl = { | 2125 | static const struct inode_operations v9fs_symlink_inode_operations_dotl = { |
| 2011 | .readlink = generic_readlink, | 2126 | .readlink = v9fs_vfs_readlink_dotl, |
| 2012 | .follow_link = v9fs_vfs_follow_link, | 2127 | .follow_link = v9fs_vfs_follow_link_dotl, |
| 2013 | .put_link = v9fs_vfs_put_link, | 2128 | .put_link = v9fs_vfs_put_link, |
| 2014 | .getattr = v9fs_vfs_getattr_dotl, | 2129 | .getattr = v9fs_vfs_getattr_dotl, |
| 2015 | .setattr = v9fs_vfs_setattr_dotl, | 2130 | .setattr = v9fs_vfs_setattr_dotl, |
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index 1d12ba0ed3db..48d4215c60a8 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c | |||
| @@ -39,6 +39,7 @@ | |||
| 39 | #include <linux/sched.h> | 39 | #include <linux/sched.h> |
| 40 | #include <linux/slab.h> | 40 | #include <linux/slab.h> |
| 41 | #include <linux/statfs.h> | 41 | #include <linux/statfs.h> |
| 42 | #include <linux/magic.h> | ||
| 42 | #include <net/9p/9p.h> | 43 | #include <net/9p/9p.h> |
| 43 | #include <net/9p/client.h> | 44 | #include <net/9p/client.h> |
| 44 | 45 | ||
| @@ -46,6 +47,7 @@ | |||
| 46 | #include "v9fs_vfs.h" | 47 | #include "v9fs_vfs.h" |
| 47 | #include "fid.h" | 48 | #include "fid.h" |
| 48 | #include "xattr.h" | 49 | #include "xattr.h" |
| 50 | #include "acl.h" | ||
| 49 | 51 | ||
| 50 | static const struct super_operations v9fs_super_ops, v9fs_super_ops_dotl; | 52 | static const struct super_operations v9fs_super_ops, v9fs_super_ops_dotl; |
| 51 | 53 | ||
| @@ -88,6 +90,11 @@ v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses, | |||
| 88 | sb->s_flags = flags | MS_ACTIVE | MS_SYNCHRONOUS | MS_DIRSYNC | | 90 | sb->s_flags = flags | MS_ACTIVE | MS_SYNCHRONOUS | MS_DIRSYNC | |
| 89 | MS_NOATIME; | 91 | MS_NOATIME; |
| 90 | 92 | ||
| 93 | #ifdef CONFIG_9P_FS_POSIX_ACL | ||
| 94 | if ((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_CLIENT) | ||
| 95 | sb->s_flags |= MS_POSIXACL; | ||
| 96 | #endif | ||
| 97 | |||
| 91 | save_mount_options(sb, data); | 98 | save_mount_options(sb, data); |
| 92 | } | 99 | } |
| 93 | 100 | ||
| @@ -149,7 +156,6 @@ static int v9fs_get_sb(struct file_system_type *fs_type, int flags, | |||
| 149 | goto release_sb; | 156 | goto release_sb; |
| 150 | } | 157 | } |
| 151 | sb->s_root = root; | 158 | sb->s_root = root; |
| 152 | |||
| 153 | if (v9fs_proto_dotl(v9ses)) { | 159 | if (v9fs_proto_dotl(v9ses)) { |
| 154 | struct p9_stat_dotl *st = NULL; | 160 | struct p9_stat_dotl *st = NULL; |
| 155 | st = p9_client_getattr_dotl(fid, P9_STATS_BASIC); | 161 | 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, | |||
| 174 | p9stat_free(st); | 180 | p9stat_free(st); |
| 175 | kfree(st); | 181 | kfree(st); |
| 176 | } | 182 | } |
| 177 | 183 | retval = v9fs_get_acl(inode, fid); | |
| 184 | if (retval) | ||
| 185 | goto release_sb; | ||
| 178 | v9fs_fid_add(root, fid); | 186 | v9fs_fid_add(root, fid); |
| 179 | 187 | ||
| 180 | P9_DPRINTK(P9_DEBUG_VFS, " simple set mount, return 0\n"); | 188 | 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) | |||
| 249 | if (v9fs_proto_dotl(v9ses)) { | 257 | if (v9fs_proto_dotl(v9ses)) { |
| 250 | res = p9_client_statfs(fid, &rs); | 258 | res = p9_client_statfs(fid, &rs); |
| 251 | if (res == 0) { | 259 | if (res == 0) { |
| 252 | buf->f_type = rs.type; | 260 | buf->f_type = V9FS_MAGIC; |
| 253 | buf->f_bsize = rs.bsize; | 261 | buf->f_bsize = rs.bsize; |
| 254 | buf->f_blocks = rs.blocks; | 262 | buf->f_blocks = rs.blocks; |
| 255 | buf->f_bfree = rs.bfree; | 263 | buf->f_bfree = rs.bfree; |
diff --git a/fs/9p/xattr.c b/fs/9p/xattr.c index f88e5c2dc873..43ec7df84336 100644 --- a/fs/9p/xattr.c +++ b/fs/9p/xattr.c | |||
| @@ -21,30 +21,13 @@ | |||
| 21 | #include "fid.h" | 21 | #include "fid.h" |
| 22 | #include "xattr.h" | 22 | #include "xattr.h" |
| 23 | 23 | ||
| 24 | /* | 24 | ssize_t v9fs_fid_xattr_get(struct p9_fid *fid, const char *name, |
| 25 | * v9fs_xattr_get() | 25 | void *buffer, size_t buffer_size) |
| 26 | * | ||
| 27 | * Copy an extended attribute into the buffer | ||
| 28 | * provided, or compute the buffer size required. | ||
| 29 | * Buffer is NULL to compute the size of the buffer required. | ||
| 30 | * | ||
| 31 | * Returns a negative error number on failure, or the number of bytes | ||
| 32 | * used / required on success. | ||
| 33 | */ | ||
| 34 | ssize_t v9fs_xattr_get(struct dentry *dentry, const char *name, | ||
| 35 | void *buffer, size_t buffer_size) | ||
| 36 | { | 26 | { |
| 37 | ssize_t retval; | 27 | ssize_t retval; |
| 38 | int msize, read_count; | 28 | int msize, read_count; |
| 39 | u64 offset = 0, attr_size; | 29 | u64 offset = 0, attr_size; |
| 40 | struct p9_fid *fid, *attr_fid; | 30 | struct p9_fid *attr_fid; |
| 41 | |||
| 42 | P9_DPRINTK(P9_DEBUG_VFS, "%s: name = %s value_len = %zu\n", | ||
| 43 | __func__, name, buffer_size); | ||
| 44 | |||
| 45 | fid = v9fs_fid_lookup(dentry); | ||
| 46 | if (IS_ERR(fid)) | ||
| 47 | return PTR_ERR(fid); | ||
| 48 | 31 | ||
| 49 | attr_fid = p9_client_xattrwalk(fid, name, &attr_size); | 32 | attr_fid = p9_client_xattrwalk(fid, name, &attr_size); |
| 50 | if (IS_ERR(attr_fid)) { | 33 | if (IS_ERR(attr_fid)) { |
| @@ -88,6 +71,31 @@ error: | |||
| 88 | 71 | ||
| 89 | } | 72 | } |
| 90 | 73 | ||
| 74 | |||
| 75 | /* | ||
| 76 | * v9fs_xattr_get() | ||
| 77 | * | ||
| 78 | * Copy an extended attribute into the buffer | ||
| 79 | * provided, or compute the buffer size required. | ||
| 80 | * Buffer is NULL to compute the size of the buffer required. | ||
| 81 | * | ||
| 82 | * Returns a negative error number on failure, or the number of bytes | ||
| 83 | * used / required on success. | ||
| 84 | */ | ||
| 85 | ssize_t v9fs_xattr_get(struct dentry *dentry, const char *name, | ||
| 86 | void *buffer, size_t buffer_size) | ||
| 87 | { | ||
| 88 | struct p9_fid *fid; | ||
| 89 | |||
| 90 | P9_DPRINTK(P9_DEBUG_VFS, "%s: name = %s value_len = %zu\n", | ||
| 91 | __func__, name, buffer_size); | ||
| 92 | fid = v9fs_fid_lookup(dentry); | ||
| 93 | if (IS_ERR(fid)) | ||
| 94 | return PTR_ERR(fid); | ||
| 95 | |||
| 96 | return v9fs_fid_xattr_get(fid, name, buffer, buffer_size); | ||
| 97 | } | ||
| 98 | |||
| 91 | /* | 99 | /* |
| 92 | * v9fs_xattr_set() | 100 | * v9fs_xattr_set() |
| 93 | * | 101 | * |
| @@ -156,5 +164,9 @@ ssize_t v9fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size) | |||
| 156 | 164 | ||
| 157 | const struct xattr_handler *v9fs_xattr_handlers[] = { | 165 | const struct xattr_handler *v9fs_xattr_handlers[] = { |
| 158 | &v9fs_xattr_user_handler, | 166 | &v9fs_xattr_user_handler, |
| 167 | #ifdef CONFIG_9P_FS_POSIX_ACL | ||
| 168 | &v9fs_xattr_acl_access_handler, | ||
| 169 | &v9fs_xattr_acl_default_handler, | ||
| 170 | #endif | ||
| 159 | NULL | 171 | NULL |
| 160 | }; | 172 | }; |
diff --git a/fs/9p/xattr.h b/fs/9p/xattr.h index 9ddf672ae5c4..eaa837c53bd5 100644 --- a/fs/9p/xattr.h +++ b/fs/9p/xattr.h | |||
| @@ -15,10 +15,16 @@ | |||
| 15 | #define FS_9P_XATTR_H | 15 | #define FS_9P_XATTR_H |
| 16 | 16 | ||
| 17 | #include <linux/xattr.h> | 17 | #include <linux/xattr.h> |
| 18 | #include <net/9p/9p.h> | ||
| 19 | #include <net/9p/client.h> | ||
| 18 | 20 | ||
| 19 | extern const struct xattr_handler *v9fs_xattr_handlers[]; | 21 | extern const struct xattr_handler *v9fs_xattr_handlers[]; |
| 20 | extern struct xattr_handler v9fs_xattr_user_handler; | 22 | extern struct xattr_handler v9fs_xattr_user_handler; |
| 23 | extern const struct xattr_handler v9fs_xattr_acl_access_handler; | ||
| 24 | extern const struct xattr_handler v9fs_xattr_acl_default_handler; | ||
| 21 | 25 | ||
| 26 | extern ssize_t v9fs_fid_xattr_get(struct p9_fid *, const char *, | ||
| 27 | void *, size_t); | ||
| 22 | extern ssize_t v9fs_xattr_get(struct dentry *, const char *, | 28 | extern ssize_t v9fs_xattr_get(struct dentry *, const char *, |
| 23 | void *, size_t); | 29 | void *, size_t); |
| 24 | extern int v9fs_xattr_set(struct dentry *, const char *, | 30 | extern int v9fs_xattr_set(struct dentry *, const char *, |
diff --git a/include/linux/magic.h b/include/linux/magic.h index eb9800f05782..ff690d05f129 100644 --- a/include/linux/magic.h +++ b/include/linux/magic.h | |||
| @@ -57,5 +57,6 @@ | |||
| 57 | 57 | ||
| 58 | #define DEVPTS_SUPER_MAGIC 0x1cd1 | 58 | #define DEVPTS_SUPER_MAGIC 0x1cd1 |
| 59 | #define SOCKFS_MAGIC 0x534F434B | 59 | #define SOCKFS_MAGIC 0x534F434B |
| 60 | #define V9FS_MAGIC 0x01021997 | ||
| 60 | 61 | ||
| 61 | #endif /* __LINUX_MAGIC_H__ */ | 62 | #endif /* __LINUX_MAGIC_H__ */ |
diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h index a8de812ccbc8..071fd7a8d781 100644 --- a/include/net/9p/9p.h +++ b/include/net/9p/9p.h | |||
| @@ -86,6 +86,8 @@ do { \ | |||
| 86 | 86 | ||
| 87 | /** | 87 | /** |
| 88 | * enum p9_msg_t - 9P message types | 88 | * enum p9_msg_t - 9P message types |
| 89 | * @P9_TLERROR: not used | ||
| 90 | * @P9_RLERROR: response for any failed request for 9P2000.L | ||
| 89 | * @P9_TSTATFS: file system status request | 91 | * @P9_TSTATFS: file system status request |
| 90 | * @P9_RSTATFS: file system status response | 92 | * @P9_RSTATFS: file system status response |
| 91 | * @P9_TSYMLINK: make symlink request | 93 | * @P9_TSYMLINK: make symlink request |
| @@ -137,6 +139,8 @@ do { \ | |||
| 137 | */ | 139 | */ |
| 138 | 140 | ||
| 139 | enum p9_msg_t { | 141 | enum p9_msg_t { |
| 142 | P9_TLERROR = 6, | ||
| 143 | P9_RLERROR, | ||
| 140 | P9_TSTATFS = 8, | 144 | P9_TSTATFS = 8, |
| 141 | P9_RSTATFS, | 145 | P9_RSTATFS, |
| 142 | P9_TLOPEN = 12, | 146 | P9_TLOPEN = 12, |
| @@ -149,6 +153,8 @@ enum p9_msg_t { | |||
| 149 | P9_RMKNOD, | 153 | P9_RMKNOD, |
| 150 | P9_TRENAME = 20, | 154 | P9_TRENAME = 20, |
| 151 | P9_RRENAME, | 155 | P9_RRENAME, |
| 156 | P9_TREADLINK = 22, | ||
| 157 | P9_RREADLINK, | ||
| 152 | P9_TGETATTR = 24, | 158 | P9_TGETATTR = 24, |
| 153 | P9_RGETATTR, | 159 | P9_RGETATTR, |
| 154 | P9_TSETATTR = 26, | 160 | P9_TSETATTR = 26, |
| @@ -159,6 +165,12 @@ enum p9_msg_t { | |||
| 159 | P9_RXATTRCREATE, | 165 | P9_RXATTRCREATE, |
| 160 | P9_TREADDIR = 40, | 166 | P9_TREADDIR = 40, |
| 161 | P9_RREADDIR, | 167 | P9_RREADDIR, |
| 168 | P9_TFSYNC = 50, | ||
| 169 | P9_RFSYNC, | ||
| 170 | P9_TLOCK = 52, | ||
| 171 | P9_RLOCK, | ||
| 172 | P9_TGETLOCK = 54, | ||
| 173 | P9_RGETLOCK, | ||
| 162 | P9_TLINK = 70, | 174 | P9_TLINK = 70, |
| 163 | P9_RLINK, | 175 | P9_RLINK, |
| 164 | P9_TMKDIR = 72, | 176 | P9_TMKDIR = 72, |
| @@ -458,6 +470,48 @@ struct p9_iattr_dotl { | |||
| 458 | u64 mtime_nsec; | 470 | u64 mtime_nsec; |
| 459 | }; | 471 | }; |
| 460 | 472 | ||
| 473 | #define P9_LOCK_SUCCESS 0 | ||
| 474 | #define P9_LOCK_BLOCKED 1 | ||
| 475 | #define P9_LOCK_ERROR 2 | ||
| 476 | #define P9_LOCK_GRACE 3 | ||
| 477 | |||
| 478 | #define P9_LOCK_FLAGS_BLOCK 1 | ||
| 479 | #define P9_LOCK_FLAGS_RECLAIM 2 | ||
| 480 | |||
| 481 | /* struct p9_flock: POSIX lock structure | ||
| 482 | * @type - type of lock | ||
| 483 | * @flags - lock flags | ||
| 484 | * @start - starting offset of the lock | ||
| 485 | * @length - number of bytes | ||
| 486 | * @proc_id - process id which wants to take lock | ||
| 487 | * @client_id - client id | ||
| 488 | */ | ||
| 489 | |||
| 490 | struct p9_flock { | ||
| 491 | u8 type; | ||
| 492 | u32 flags; | ||
| 493 | u64 start; | ||
| 494 | u64 length; | ||
| 495 | u32 proc_id; | ||
| 496 | char *client_id; | ||
| 497 | }; | ||
| 498 | |||
| 499 | /* struct p9_getlock: getlock structure | ||
| 500 | * @type - type of lock | ||
| 501 | * @start - starting offset of the lock | ||
| 502 | * @length - number of bytes | ||
| 503 | * @proc_id - process id which wants to take lock | ||
| 504 | * @client_id - client id | ||
| 505 | */ | ||
| 506 | |||
| 507 | struct p9_getlock { | ||
| 508 | u8 type; | ||
| 509 | u64 start; | ||
| 510 | u64 length; | ||
| 511 | u32 proc_id; | ||
| 512 | char *client_id; | ||
| 513 | }; | ||
| 514 | |||
| 461 | /* Structures for Protocol Operations */ | 515 | /* Structures for Protocol Operations */ |
| 462 | struct p9_tstatfs { | 516 | struct p9_tstatfs { |
| 463 | u32 fid; | 517 | u32 fid; |
diff --git a/include/net/9p/client.h b/include/net/9p/client.h index 7f63d5ab7b44..83ba6a4d58a3 100644 --- a/include/net/9p/client.h +++ b/include/net/9p/client.h | |||
| @@ -229,6 +229,7 @@ int p9_client_symlink(struct p9_fid *fid, char *name, char *symname, gid_t gid, | |||
| 229 | int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode, | 229 | int p9_client_create_dotl(struct p9_fid *ofid, char *name, u32 flags, u32 mode, |
| 230 | gid_t gid, struct p9_qid *qid); | 230 | gid_t gid, struct p9_qid *qid); |
| 231 | int p9_client_clunk(struct p9_fid *fid); | 231 | int p9_client_clunk(struct p9_fid *fid); |
| 232 | int p9_client_fsync(struct p9_fid *fid, int datasync); | ||
| 232 | int p9_client_remove(struct p9_fid *fid); | 233 | int p9_client_remove(struct p9_fid *fid); |
| 233 | int p9_client_read(struct p9_fid *fid, char *data, char __user *udata, | 234 | int p9_client_read(struct p9_fid *fid, char *data, char __user *udata, |
| 234 | u64 offset, u32 count); | 235 | u64 offset, u32 count); |
| @@ -248,6 +249,8 @@ int p9_client_mknod_dotl(struct p9_fid *oldfid, char *name, int mode, | |||
| 248 | dev_t rdev, gid_t gid, struct p9_qid *); | 249 | dev_t rdev, gid_t gid, struct p9_qid *); |
| 249 | int p9_client_mkdir_dotl(struct p9_fid *fid, char *name, int mode, | 250 | int p9_client_mkdir_dotl(struct p9_fid *fid, char *name, int mode, |
| 250 | gid_t gid, struct p9_qid *); | 251 | gid_t gid, struct p9_qid *); |
| 252 | int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status); | ||
| 253 | int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *fl); | ||
| 251 | struct p9_req_t *p9_tag_lookup(struct p9_client *, u16); | 254 | struct p9_req_t *p9_tag_lookup(struct p9_client *, u16); |
| 252 | void p9_client_cb(struct p9_client *c, struct p9_req_t *req); | 255 | void p9_client_cb(struct p9_client *c, struct p9_req_t *req); |
| 253 | 256 | ||
| @@ -259,5 +262,6 @@ int p9_is_proto_dotu(struct p9_client *clnt); | |||
| 259 | int p9_is_proto_dotl(struct p9_client *clnt); | 262 | int p9_is_proto_dotl(struct p9_client *clnt); |
| 260 | struct p9_fid *p9_client_xattrwalk(struct p9_fid *, const char *, u64 *); | 263 | struct p9_fid *p9_client_xattrwalk(struct p9_fid *, const char *, u64 *); |
| 261 | int p9_client_xattrcreate(struct p9_fid *, const char *, u64, int); | 264 | int p9_client_xattrcreate(struct p9_fid *, const char *, u64, int); |
| 265 | int p9_client_readlink(struct p9_fid *fid, char **target); | ||
| 262 | 266 | ||
| 263 | #endif /* NET_9P_CLIENT_H */ | 267 | #endif /* NET_9P_CLIENT_H */ |
diff --git a/net/9p/client.c b/net/9p/client.c index 83bf0541d66f..a848bca9fbff 100644 --- a/net/9p/client.c +++ b/net/9p/client.c | |||
| @@ -450,32 +450,43 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req) | |||
| 450 | return err; | 450 | return err; |
| 451 | } | 451 | } |
| 452 | 452 | ||
| 453 | if (type == P9_RERROR) { | 453 | if (type == P9_RERROR || type == P9_RLERROR) { |
| 454 | int ecode; | 454 | int ecode; |
| 455 | char *ename; | ||
| 456 | 455 | ||
| 457 | err = p9pdu_readf(req->rc, c->proto_version, "s?d", | 456 | if (!p9_is_proto_dotl(c)) { |
| 458 | &ename, &ecode); | 457 | char *ename; |
| 459 | if (err) { | ||
| 460 | P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n", | ||
| 461 | err); | ||
| 462 | return err; | ||
| 463 | } | ||
| 464 | 458 | ||
| 465 | if (p9_is_proto_dotu(c) || | 459 | err = p9pdu_readf(req->rc, c->proto_version, "s?d", |
| 466 | p9_is_proto_dotl(c)) | 460 | &ename, &ecode); |
| 467 | err = -ecode; | 461 | if (err) |
| 462 | goto out_err; | ||
| 463 | |||
| 464 | if (p9_is_proto_dotu(c)) | ||
| 465 | err = -ecode; | ||
| 466 | |||
| 467 | if (!err || !IS_ERR_VALUE(err)) { | ||
| 468 | err = p9_errstr2errno(ename, strlen(ename)); | ||
| 469 | |||
| 470 | P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", -ecode, ename); | ||
| 468 | 471 | ||
| 469 | if (!err || !IS_ERR_VALUE(err)) | 472 | kfree(ename); |
| 470 | err = p9_errstr2errno(ename, strlen(ename)); | 473 | } |
| 474 | } else { | ||
| 475 | err = p9pdu_readf(req->rc, c->proto_version, "d", &ecode); | ||
| 476 | err = -ecode; | ||
| 471 | 477 | ||
| 472 | P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", -ecode, ename); | 478 | P9_DPRINTK(P9_DEBUG_9P, "<<< RLERROR (%d)\n", -ecode); |
| 479 | } | ||
| 473 | 480 | ||
| 474 | kfree(ename); | ||
| 475 | } else | 481 | } else |
| 476 | err = 0; | 482 | err = 0; |
| 477 | 483 | ||
| 478 | return err; | 484 | return err; |
| 485 | |||
| 486 | out_err: | ||
| 487 | P9_DPRINTK(P9_DEBUG_ERROR, "couldn't parse error%d\n", err); | ||
| 488 | |||
| 489 | return err; | ||
| 479 | } | 490 | } |
| 480 | 491 | ||
| 481 | /** | 492 | /** |
| @@ -568,11 +579,14 @@ p9_client_rpc(struct p9_client *c, int8_t type, const char *fmt, ...) | |||
| 568 | va_start(ap, fmt); | 579 | va_start(ap, fmt); |
| 569 | err = p9pdu_vwritef(req->tc, c->proto_version, fmt, ap); | 580 | err = p9pdu_vwritef(req->tc, c->proto_version, fmt, ap); |
| 570 | va_end(ap); | 581 | va_end(ap); |
| 582 | if (err) | ||
| 583 | goto reterr; | ||
| 571 | p9pdu_finalize(req->tc); | 584 | p9pdu_finalize(req->tc); |
| 572 | 585 | ||
| 573 | err = c->trans_mod->request(c, req); | 586 | err = c->trans_mod->request(c, req); |
| 574 | if (err < 0) { | 587 | if (err < 0) { |
| 575 | c->status = Disconnected; | 588 | if (err != -ERESTARTSYS) |
| 589 | c->status = Disconnected; | ||
| 576 | goto reterr; | 590 | goto reterr; |
| 577 | } | 591 | } |
| 578 | 592 | ||
| @@ -1151,12 +1165,44 @@ int p9_client_link(struct p9_fid *dfid, struct p9_fid *oldfid, char *newname) | |||
| 1151 | } | 1165 | } |
| 1152 | EXPORT_SYMBOL(p9_client_link); | 1166 | EXPORT_SYMBOL(p9_client_link); |
| 1153 | 1167 | ||
| 1168 | int p9_client_fsync(struct p9_fid *fid, int datasync) | ||
| 1169 | { | ||
| 1170 | int err; | ||
| 1171 | struct p9_client *clnt; | ||
| 1172 | struct p9_req_t *req; | ||
| 1173 | |||
| 1174 | P9_DPRINTK(P9_DEBUG_9P, ">>> TFSYNC fid %d datasync:%d\n", | ||
| 1175 | fid->fid, datasync); | ||
| 1176 | err = 0; | ||
| 1177 | clnt = fid->clnt; | ||
| 1178 | |||
| 1179 | req = p9_client_rpc(clnt, P9_TFSYNC, "dd", fid->fid, datasync); | ||
| 1180 | if (IS_ERR(req)) { | ||
| 1181 | err = PTR_ERR(req); | ||
| 1182 | goto error; | ||
| 1183 | } | ||
| 1184 | |||
| 1185 | P9_DPRINTK(P9_DEBUG_9P, "<<< RFSYNC fid %d\n", fid->fid); | ||
| 1186 | |||
| 1187 | p9_free_req(clnt, req); | ||
| 1188 | |||
| 1189 | error: | ||
| 1190 | return err; | ||
| 1191 | } | ||
| 1192 | EXPORT_SYMBOL(p9_client_fsync); | ||
| 1193 | |||
| 1154 | int p9_client_clunk(struct p9_fid *fid) | 1194 | int p9_client_clunk(struct p9_fid *fid) |
| 1155 | { | 1195 | { |
| 1156 | int err; | 1196 | int err; |
| 1157 | struct p9_client *clnt; | 1197 | struct p9_client *clnt; |
| 1158 | struct p9_req_t *req; | 1198 | struct p9_req_t *req; |
| 1159 | 1199 | ||
| 1200 | if (!fid) { | ||
| 1201 | P9_EPRINTK(KERN_WARNING, "Trying to clunk with NULL fid\n"); | ||
| 1202 | dump_stack(); | ||
| 1203 | return 0; | ||
| 1204 | } | ||
| 1205 | |||
| 1160 | P9_DPRINTK(P9_DEBUG_9P, ">>> TCLUNK fid %d\n", fid->fid); | 1206 | P9_DPRINTK(P9_DEBUG_9P, ">>> TCLUNK fid %d\n", fid->fid); |
| 1161 | err = 0; | 1207 | err = 0; |
| 1162 | clnt = fid->clnt; | 1208 | clnt = fid->clnt; |
| @@ -1240,16 +1286,13 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, | |||
| 1240 | 1286 | ||
| 1241 | if (data) { | 1287 | if (data) { |
| 1242 | memmove(data, dataptr, count); | 1288 | memmove(data, dataptr, count); |
| 1243 | } | 1289 | } else { |
| 1244 | |||
| 1245 | if (udata) { | ||
| 1246 | err = copy_to_user(udata, dataptr, count); | 1290 | err = copy_to_user(udata, dataptr, count); |
| 1247 | if (err) { | 1291 | if (err) { |
| 1248 | err = -EFAULT; | 1292 | err = -EFAULT; |
| 1249 | goto free_and_error; | 1293 | goto free_and_error; |
| 1250 | } | 1294 | } |
| 1251 | } | 1295 | } |
| 1252 | |||
| 1253 | p9_free_req(clnt, req); | 1296 | p9_free_req(clnt, req); |
| 1254 | return count; | 1297 | return count; |
| 1255 | 1298 | ||
| @@ -1761,3 +1804,96 @@ error: | |||
| 1761 | 1804 | ||
| 1762 | } | 1805 | } |
| 1763 | EXPORT_SYMBOL(p9_client_mkdir_dotl); | 1806 | EXPORT_SYMBOL(p9_client_mkdir_dotl); |
| 1807 | |||
| 1808 | int p9_client_lock_dotl(struct p9_fid *fid, struct p9_flock *flock, u8 *status) | ||
| 1809 | { | ||
| 1810 | int err; | ||
| 1811 | struct p9_client *clnt; | ||
| 1812 | struct p9_req_t *req; | ||
| 1813 | |||
| 1814 | err = 0; | ||
| 1815 | clnt = fid->clnt; | ||
| 1816 | P9_DPRINTK(P9_DEBUG_9P, ">>> TLOCK fid %d type %i flags %d " | ||
| 1817 | "start %lld length %lld proc_id %d client_id %s\n", | ||
| 1818 | fid->fid, flock->type, flock->flags, flock->start, | ||
| 1819 | flock->length, flock->proc_id, flock->client_id); | ||
| 1820 | |||
| 1821 | req = p9_client_rpc(clnt, P9_TLOCK, "dbdqqds", fid->fid, flock->type, | ||
| 1822 | flock->flags, flock->start, flock->length, | ||
| 1823 | flock->proc_id, flock->client_id); | ||
| 1824 | |||
| 1825 | if (IS_ERR(req)) | ||
| 1826 | return PTR_ERR(req); | ||
| 1827 | |||
| 1828 | err = p9pdu_readf(req->rc, clnt->proto_version, "b", status); | ||
| 1829 | if (err) { | ||
| 1830 | p9pdu_dump(1, req->rc); | ||
| 1831 | goto error; | ||
| 1832 | } | ||
| 1833 | P9_DPRINTK(P9_DEBUG_9P, "<<< RLOCK status %i\n", *status); | ||
| 1834 | error: | ||
| 1835 | p9_free_req(clnt, req); | ||
| 1836 | return err; | ||
| 1837 | |||
| 1838 | } | ||
| 1839 | EXPORT_SYMBOL(p9_client_lock_dotl); | ||
| 1840 | |||
| 1841 | int p9_client_getlock_dotl(struct p9_fid *fid, struct p9_getlock *glock) | ||
| 1842 | { | ||
| 1843 | int err; | ||
| 1844 | struct p9_client *clnt; | ||
| 1845 | struct p9_req_t *req; | ||
| 1846 | |||
| 1847 | err = 0; | ||
| 1848 | clnt = fid->clnt; | ||
| 1849 | P9_DPRINTK(P9_DEBUG_9P, ">>> TGETLOCK fid %d, type %i start %lld " | ||
| 1850 | "length %lld proc_id %d client_id %s\n", fid->fid, glock->type, | ||
| 1851 | glock->start, glock->length, glock->proc_id, glock->client_id); | ||
| 1852 | |||
| 1853 | req = p9_client_rpc(clnt, P9_TGETLOCK, "dbqqds", fid->fid, glock->type, | ||
| 1854 | glock->start, glock->length, glock->proc_id, glock->client_id); | ||
| 1855 | |||
| 1856 | if (IS_ERR(req)) | ||
| 1857 | return PTR_ERR(req); | ||
| 1858 | |||
| 1859 | err = p9pdu_readf(req->rc, clnt->proto_version, "bqqds", &glock->type, | ||
| 1860 | &glock->start, &glock->length, &glock->proc_id, | ||
| 1861 | &glock->client_id); | ||
| 1862 | if (err) { | ||
| 1863 | p9pdu_dump(1, req->rc); | ||
| 1864 | goto error; | ||
| 1865 | } | ||
| 1866 | P9_DPRINTK(P9_DEBUG_9P, "<<< RGETLOCK type %i start %lld length %lld " | ||
| 1867 | "proc_id %d client_id %s\n", glock->type, glock->start, | ||
| 1868 | glock->length, glock->proc_id, glock->client_id); | ||
| 1869 | error: | ||
| 1870 | p9_free_req(clnt, req); | ||
| 1871 | return err; | ||
| 1872 | } | ||
| 1873 | EXPORT_SYMBOL(p9_client_getlock_dotl); | ||
| 1874 | |||
| 1875 | int p9_client_readlink(struct p9_fid *fid, char **target) | ||
| 1876 | { | ||
| 1877 | int err; | ||
| 1878 | struct p9_client *clnt; | ||
| 1879 | struct p9_req_t *req; | ||
| 1880 | |||
| 1881 | err = 0; | ||
| 1882 | clnt = fid->clnt; | ||
| 1883 | P9_DPRINTK(P9_DEBUG_9P, ">>> TREADLINK fid %d\n", fid->fid); | ||
| 1884 | |||
| 1885 | req = p9_client_rpc(clnt, P9_TREADLINK, "d", fid->fid); | ||
| 1886 | if (IS_ERR(req)) | ||
| 1887 | return PTR_ERR(req); | ||
| 1888 | |||
| 1889 | err = p9pdu_readf(req->rc, clnt->proto_version, "s", target); | ||
| 1890 | if (err) { | ||
| 1891 | p9pdu_dump(1, req->rc); | ||
| 1892 | goto error; | ||
| 1893 | } | ||
| 1894 | P9_DPRINTK(P9_DEBUG_9P, "<<< RREADLINK target %s\n", *target); | ||
| 1895 | error: | ||
| 1896 | p9_free_req(clnt, req); | ||
| 1897 | return err; | ||
| 1898 | } | ||
| 1899 | EXPORT_SYMBOL(p9_client_readlink); | ||
diff --git a/net/9p/protocol.c b/net/9p/protocol.c index 3acd3afb20c8..45c15f491401 100644 --- a/net/9p/protocol.c +++ b/net/9p/protocol.c | |||
| @@ -122,9 +122,8 @@ static size_t | |||
| 122 | pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size) | 122 | pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size) |
| 123 | { | 123 | { |
| 124 | size_t len = MIN(pdu->capacity - pdu->size, size); | 124 | size_t len = MIN(pdu->capacity - pdu->size, size); |
| 125 | int err = copy_from_user(&pdu->sdata[pdu->size], udata, len); | 125 | if (copy_from_user(&pdu->sdata[pdu->size], udata, len)) |
| 126 | if (err) | 126 | len = 0; |
| 127 | printk(KERN_WARNING "pdu_write_u returning: %d\n", err); | ||
| 128 | 127 | ||
| 129 | pdu->size += len; | 128 | pdu->size += len; |
| 130 | return size - len; | 129 | return size - len; |
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index b88515936e4b..c8f3f72ab20e 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c | |||
| @@ -75,6 +75,8 @@ struct virtio_chan { | |||
| 75 | struct p9_client *client; | 75 | struct p9_client *client; |
| 76 | struct virtio_device *vdev; | 76 | struct virtio_device *vdev; |
| 77 | struct virtqueue *vq; | 77 | struct virtqueue *vq; |
| 78 | int ring_bufs_avail; | ||
| 79 | wait_queue_head_t *vc_wq; | ||
| 78 | 80 | ||
| 79 | /* Scatterlist: can be too big for stack. */ | 81 | /* Scatterlist: can be too big for stack. */ |
| 80 | struct scatterlist sg[VIRTQUEUE_NUM]; | 82 | struct scatterlist sg[VIRTQUEUE_NUM]; |
| @@ -134,16 +136,30 @@ static void req_done(struct virtqueue *vq) | |||
| 134 | struct p9_fcall *rc; | 136 | struct p9_fcall *rc; |
| 135 | unsigned int len; | 137 | unsigned int len; |
| 136 | struct p9_req_t *req; | 138 | struct p9_req_t *req; |
| 139 | unsigned long flags; | ||
| 137 | 140 | ||
| 138 | P9_DPRINTK(P9_DEBUG_TRANS, ": request done\n"); | 141 | P9_DPRINTK(P9_DEBUG_TRANS, ": request done\n"); |
| 139 | 142 | ||
| 140 | while ((rc = virtqueue_get_buf(chan->vq, &len)) != NULL) { | 143 | do { |
| 141 | P9_DPRINTK(P9_DEBUG_TRANS, ": rc %p\n", rc); | 144 | spin_lock_irqsave(&chan->lock, flags); |
| 142 | P9_DPRINTK(P9_DEBUG_TRANS, ": lookup tag %d\n", rc->tag); | 145 | rc = virtqueue_get_buf(chan->vq, &len); |
| 143 | req = p9_tag_lookup(chan->client, rc->tag); | 146 | |
| 144 | req->status = REQ_STATUS_RCVD; | 147 | if (rc != NULL) { |
| 145 | p9_client_cb(chan->client, req); | 148 | if (!chan->ring_bufs_avail) { |
| 146 | } | 149 | chan->ring_bufs_avail = 1; |
| 150 | wake_up(chan->vc_wq); | ||
| 151 | } | ||
| 152 | spin_unlock_irqrestore(&chan->lock, flags); | ||
| 153 | P9_DPRINTK(P9_DEBUG_TRANS, ": rc %p\n", rc); | ||
| 154 | P9_DPRINTK(P9_DEBUG_TRANS, ": lookup tag %d\n", | ||
| 155 | rc->tag); | ||
| 156 | req = p9_tag_lookup(chan->client, rc->tag); | ||
| 157 | req->status = REQ_STATUS_RCVD; | ||
| 158 | p9_client_cb(chan->client, req); | ||
| 159 | } else { | ||
| 160 | spin_unlock_irqrestore(&chan->lock, flags); | ||
| 161 | } | ||
| 162 | } while (rc != NULL); | ||
| 147 | } | 163 | } |
| 148 | 164 | ||
| 149 | /** | 165 | /** |
| @@ -199,23 +215,43 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req) | |||
| 199 | int in, out; | 215 | int in, out; |
| 200 | struct virtio_chan *chan = client->trans; | 216 | struct virtio_chan *chan = client->trans; |
| 201 | char *rdata = (char *)req->rc+sizeof(struct p9_fcall); | 217 | char *rdata = (char *)req->rc+sizeof(struct p9_fcall); |
| 218 | unsigned long flags; | ||
| 219 | int err; | ||
| 202 | 220 | ||
| 203 | P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request\n"); | 221 | P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request\n"); |
| 204 | 222 | ||
| 223 | req_retry: | ||
| 224 | req->status = REQ_STATUS_SENT; | ||
| 225 | |||
| 226 | spin_lock_irqsave(&chan->lock, flags); | ||
| 205 | out = pack_sg_list(chan->sg, 0, VIRTQUEUE_NUM, req->tc->sdata, | 227 | out = pack_sg_list(chan->sg, 0, VIRTQUEUE_NUM, req->tc->sdata, |
| 206 | req->tc->size); | 228 | req->tc->size); |
| 207 | in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM-out, rdata, | 229 | in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM-out, rdata, |
| 208 | client->msize); | 230 | client->msize); |
| 209 | 231 | ||
| 210 | req->status = REQ_STATUS_SENT; | 232 | err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc); |
| 211 | 233 | if (err < 0) { | |
| 212 | if (virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc) < 0) { | 234 | if (err == -ENOSPC) { |
| 213 | P9_DPRINTK(P9_DEBUG_TRANS, | 235 | chan->ring_bufs_avail = 0; |
| 214 | "9p debug: virtio rpc add_buf returned failure"); | 236 | spin_unlock_irqrestore(&chan->lock, flags); |
| 215 | return -EIO; | 237 | err = wait_event_interruptible(*chan->vc_wq, |
| 238 | chan->ring_bufs_avail); | ||
| 239 | if (err == -ERESTARTSYS) | ||
| 240 | return err; | ||
| 241 | |||
| 242 | P9_DPRINTK(P9_DEBUG_TRANS, "9p:Retry virtio request\n"); | ||
| 243 | goto req_retry; | ||
| 244 | } else { | ||
| 245 | spin_unlock_irqrestore(&chan->lock, flags); | ||
| 246 | P9_DPRINTK(P9_DEBUG_TRANS, | ||
| 247 | "9p debug: " | ||
| 248 | "virtio rpc add_buf returned failure"); | ||
| 249 | return -EIO; | ||
| 250 | } | ||
| 216 | } | 251 | } |
| 217 | 252 | ||
| 218 | virtqueue_kick(chan->vq); | 253 | virtqueue_kick(chan->vq); |
| 254 | spin_unlock_irqrestore(&chan->lock, flags); | ||
| 219 | 255 | ||
| 220 | P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request kicked\n"); | 256 | P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request kicked\n"); |
| 221 | return 0; | 257 | return 0; |
| @@ -290,14 +326,23 @@ static int p9_virtio_probe(struct virtio_device *vdev) | |||
| 290 | chan->tag_len = tag_len; | 326 | chan->tag_len = tag_len; |
| 291 | err = sysfs_create_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr); | 327 | err = sysfs_create_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr); |
| 292 | if (err) { | 328 | if (err) { |
| 293 | kfree(tag); | 329 | goto out_free_tag; |
| 294 | goto out_free_vq; | ||
| 295 | } | 330 | } |
| 331 | chan->vc_wq = kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL); | ||
| 332 | if (!chan->vc_wq) { | ||
| 333 | err = -ENOMEM; | ||
| 334 | goto out_free_tag; | ||
| 335 | } | ||
| 336 | init_waitqueue_head(chan->vc_wq); | ||
| 337 | chan->ring_bufs_avail = 1; | ||
| 338 | |||
| 296 | mutex_lock(&virtio_9p_lock); | 339 | mutex_lock(&virtio_9p_lock); |
| 297 | list_add_tail(&chan->chan_list, &virtio_chan_list); | 340 | list_add_tail(&chan->chan_list, &virtio_chan_list); |
| 298 | mutex_unlock(&virtio_9p_lock); | 341 | mutex_unlock(&virtio_9p_lock); |
| 299 | return 0; | 342 | return 0; |
| 300 | 343 | ||
| 344 | out_free_tag: | ||
| 345 | kfree(tag); | ||
| 301 | out_free_vq: | 346 | out_free_vq: |
| 302 | vdev->config->del_vqs(vdev); | 347 | vdev->config->del_vqs(vdev); |
| 303 | kfree(chan); | 348 | kfree(chan); |
| @@ -371,6 +416,7 @@ static void p9_virtio_remove(struct virtio_device *vdev) | |||
| 371 | mutex_unlock(&virtio_9p_lock); | 416 | mutex_unlock(&virtio_9p_lock); |
| 372 | sysfs_remove_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr); | 417 | sysfs_remove_file(&(vdev->dev.kobj), &dev_attr_mount_tag.attr); |
| 373 | kfree(chan->tag); | 418 | kfree(chan->tag); |
| 419 | kfree(chan->vc_wq); | ||
| 374 | kfree(chan); | 420 | kfree(chan); |
| 375 | 421 | ||
| 376 | } | 422 | } |
