Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/kyle/parisc-2.6
[pandora-kernel.git] / fs / 9p / xattr.c
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 <linux/sched.h>
18 #include <net/9p/9p.h>
19 #include <net/9p/client.h>
20
21 #include "fid.h"
22 #include "xattr.h"
23
24 /*
25  * v9fs_xattr_get()
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 {
37         ssize_t retval;
38         int msize, read_count;
39         u64 offset = 0, attr_size;
40         struct p9_fid *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
49         attr_fid = p9_client_xattrwalk(fid, name, &attr_size);
50         if (IS_ERR(attr_fid)) {
51                 retval = PTR_ERR(attr_fid);
52                 P9_DPRINTK(P9_DEBUG_VFS,
53                         "p9_client_attrwalk failed %zd\n", retval);
54                 attr_fid = NULL;
55                 goto error;
56         }
57         if (!buffer_size) {
58                 /* request to get the attr_size */
59                 retval = attr_size;
60                 goto error;
61         }
62         if (attr_size > buffer_size) {
63                 retval = -ERANGE;
64                 goto error;
65         }
66         msize = attr_fid->clnt->msize;
67         while (attr_size) {
68                 if (attr_size > (msize - P9_IOHDRSZ))
69                         read_count = msize - P9_IOHDRSZ;
70                 else
71                         read_count = attr_size;
72                 read_count = p9_client_read(attr_fid, ((char *)buffer)+offset,
73                                         NULL, offset, read_count);
74                 if (read_count < 0) {
75                         /* error in xattr read */
76                         retval = read_count;
77                         goto error;
78                 }
79                 offset += read_count;
80                 attr_size -= read_count;
81         }
82         /* Total read xattr bytes */
83         retval = offset;
84 error:
85         if (attr_fid)
86                 p9_client_clunk(attr_fid);
87         return retval;
88
89 }
90
91 /*
92  * v9fs_xattr_set()
93  *
94  * Create, replace or remove an extended attribute for this inode. Buffer
95  * is NULL to remove an existing extended attribute, and non-NULL to
96  * either replace an existing extended attribute, or create a new extended
97  * attribute. The flags XATTR_REPLACE and XATTR_CREATE
98  * specify that an extended attribute must exist and must not exist
99  * previous to the call, respectively.
100  *
101  * Returns 0, or a negative error number on failure.
102  */
103 int v9fs_xattr_set(struct dentry *dentry, const char *name,
104                    const void *value, size_t value_len, int flags)
105 {
106         u64 offset = 0;
107         int retval, msize, write_count;
108         struct p9_fid *fid = NULL;
109
110         P9_DPRINTK(P9_DEBUG_VFS, "%s: name = %s value_len = %zu flags = %d\n",
111                 __func__, name, value_len, flags);
112
113         fid = v9fs_fid_clone(dentry);
114         if (IS_ERR(fid)) {
115                 retval = PTR_ERR(fid);
116                 fid = NULL;
117                 goto error;
118         }
119         /*
120          * On success fid points to xattr
121          */
122         retval = p9_client_xattrcreate(fid, name, value_len, flags);
123         if (retval < 0) {
124                 P9_DPRINTK(P9_DEBUG_VFS,
125                         "p9_client_xattrcreate failed %d\n", retval);
126                 goto error;
127         }
128         msize = fid->clnt->msize;;
129         while (value_len) {
130                 if (value_len > (msize - P9_IOHDRSZ))
131                         write_count = msize - P9_IOHDRSZ;
132                 else
133                         write_count = value_len;
134                 write_count = p9_client_write(fid, ((char *)value)+offset,
135                                         NULL, offset, write_count);
136                 if (write_count < 0) {
137                         /* error in xattr write */
138                         retval = write_count;
139                         goto error;
140                 }
141                 offset += write_count;
142                 value_len -= write_count;
143         }
144         /* Total read xattr bytes */
145         retval = offset;
146 error:
147         if (fid)
148                 retval = p9_client_clunk(fid);
149         return retval;
150 }
151
152 ssize_t v9fs_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size)
153 {
154         return v9fs_xattr_get(dentry, NULL, buffer, buffer_size);
155 }
156
157 const struct xattr_handler *v9fs_xattr_handlers[] = {
158         &v9fs_xattr_user_handler,
159         NULL
160 };