diff options
-rw-r--r-- | fs/9p/acl.c | 28 | ||||
-rw-r--r-- | fs/9p/cache.c | 204 | ||||
-rw-r--r-- | fs/9p/cache.h | 64 | ||||
-rw-r--r-- | fs/9p/fid.c | 114 | ||||
-rw-r--r-- | fs/9p/fid.h | 5 | ||||
-rw-r--r-- | fs/9p/v9fs.c | 108 | ||||
-rw-r--r-- | fs/9p/v9fs.h | 53 | ||||
-rw-r--r-- | fs/9p/v9fs_vfs.h | 26 | ||||
-rw-r--r-- | fs/9p/vfs_addr.c | 194 | ||||
-rw-r--r-- | fs/9p/vfs_dentry.c | 47 | ||||
-rw-r--r-- | fs/9p/vfs_dir.c | 1 | ||||
-rw-r--r-- | fs/9p/vfs_file.c | 316 | ||||
-rw-r--r-- | fs/9p/vfs_inode.c | 307 | ||||
-rw-r--r-- | fs/9p/vfs_inode_dotl.c | 198 | ||||
-rw-r--r-- | fs/9p/vfs_super.c | 65 | ||||
-rw-r--r-- | include/net/9p/9p.h | 12 | ||||
-rw-r--r-- | include/net/9p/client.h | 1 | ||||
-rw-r--r-- | include/net/9p/transport.h | 9 | ||||
-rw-r--r-- | net/9p/Makefile | 1 | ||||
-rw-r--r-- | net/9p/client.c | 166 | ||||
-rw-r--r-- | net/9p/protocol.c | 44 | ||||
-rw-r--r-- | net/9p/trans_common.c | 97 | ||||
-rw-r--r-- | net/9p/trans_common.h | 32 | ||||
-rw-r--r-- | net/9p/trans_virtio.c | 129 |
24 files changed, 1660 insertions, 561 deletions
diff --git a/fs/9p/acl.c b/fs/9p/acl.c index 02a2cf616318..515455296378 100644 --- a/fs/9p/acl.c +++ b/fs/9p/acl.c | |||
@@ -21,8 +21,8 @@ | |||
21 | #include <linux/posix_acl_xattr.h> | 21 | #include <linux/posix_acl_xattr.h> |
22 | #include "xattr.h" | 22 | #include "xattr.h" |
23 | #include "acl.h" | 23 | #include "acl.h" |
24 | #include "v9fs_vfs.h" | ||
25 | #include "v9fs.h" | 24 | #include "v9fs.h" |
25 | #include "v9fs_vfs.h" | ||
26 | 26 | ||
27 | static struct posix_acl *__v9fs_get_acl(struct p9_fid *fid, char *name) | 27 | static struct posix_acl *__v9fs_get_acl(struct p9_fid *fid, char *name) |
28 | { | 28 | { |
@@ -59,7 +59,8 @@ int v9fs_get_acl(struct inode *inode, struct p9_fid *fid) | |||
59 | struct v9fs_session_info *v9ses; | 59 | struct v9fs_session_info *v9ses; |
60 | 60 | ||
61 | v9ses = v9fs_inode2v9ses(inode); | 61 | v9ses = v9fs_inode2v9ses(inode); |
62 | if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) { | 62 | if (((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) || |
63 | ((v9ses->flags & V9FS_ACL_MASK) != V9FS_POSIX_ACL)) { | ||
63 | set_cached_acl(inode, ACL_TYPE_DEFAULT, NULL); | 64 | set_cached_acl(inode, ACL_TYPE_DEFAULT, NULL); |
64 | set_cached_acl(inode, ACL_TYPE_ACCESS, NULL); | 65 | set_cached_acl(inode, ACL_TYPE_ACCESS, NULL); |
65 | return 0; | 66 | return 0; |
@@ -71,11 +72,15 @@ int v9fs_get_acl(struct inode *inode, struct p9_fid *fid) | |||
71 | if (!IS_ERR(dacl) && !IS_ERR(pacl)) { | 72 | if (!IS_ERR(dacl) && !IS_ERR(pacl)) { |
72 | set_cached_acl(inode, ACL_TYPE_DEFAULT, dacl); | 73 | set_cached_acl(inode, ACL_TYPE_DEFAULT, dacl); |
73 | set_cached_acl(inode, ACL_TYPE_ACCESS, pacl); | 74 | set_cached_acl(inode, ACL_TYPE_ACCESS, pacl); |
74 | posix_acl_release(dacl); | ||
75 | posix_acl_release(pacl); | ||
76 | } else | 75 | } else |
77 | retval = -EIO; | 76 | retval = -EIO; |
78 | 77 | ||
78 | if (!IS_ERR(dacl)) | ||
79 | posix_acl_release(dacl); | ||
80 | |||
81 | if (!IS_ERR(pacl)) | ||
82 | posix_acl_release(pacl); | ||
83 | |||
79 | return retval; | 84 | return retval; |
80 | } | 85 | } |
81 | 86 | ||
@@ -100,9 +105,10 @@ int v9fs_check_acl(struct inode *inode, int mask, unsigned int flags) | |||
100 | return -ECHILD; | 105 | return -ECHILD; |
101 | 106 | ||
102 | v9ses = v9fs_inode2v9ses(inode); | 107 | v9ses = v9fs_inode2v9ses(inode); |
103 | if ((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) { | 108 | if (((v9ses->flags & V9FS_ACCESS_MASK) != V9FS_ACCESS_CLIENT) || |
109 | ((v9ses->flags & V9FS_ACL_MASK) != V9FS_POSIX_ACL)) { | ||
104 | /* | 110 | /* |
105 | * On access = client mode get the acl | 111 | * On access = client and acl = on mode get the acl |
106 | * values from the server | 112 | * values from the server |
107 | */ | 113 | */ |
108 | return 0; | 114 | return 0; |
@@ -128,6 +134,10 @@ static int v9fs_set_acl(struct dentry *dentry, int type, struct posix_acl *acl) | |||
128 | struct inode *inode = dentry->d_inode; | 134 | struct inode *inode = dentry->d_inode; |
129 | 135 | ||
130 | set_cached_acl(inode, type, acl); | 136 | set_cached_acl(inode, type, acl); |
137 | |||
138 | if (!acl) | ||
139 | return 0; | ||
140 | |||
131 | /* Set a setxattr request to server */ | 141 | /* Set a setxattr request to server */ |
132 | size = posix_acl_xattr_size(acl->a_count); | 142 | size = posix_acl_xattr_size(acl->a_count); |
133 | buffer = kmalloc(size, GFP_KERNEL); | 143 | buffer = kmalloc(size, GFP_KERNEL); |
@@ -177,10 +187,8 @@ int v9fs_acl_chmod(struct dentry *dentry) | |||
177 | int v9fs_set_create_acl(struct dentry *dentry, | 187 | int v9fs_set_create_acl(struct dentry *dentry, |
178 | struct posix_acl *dpacl, struct posix_acl *pacl) | 188 | struct posix_acl *dpacl, struct posix_acl *pacl) |
179 | { | 189 | { |
180 | if (dpacl) | 190 | v9fs_set_acl(dentry, ACL_TYPE_DEFAULT, dpacl); |
181 | v9fs_set_acl(dentry, ACL_TYPE_DEFAULT, dpacl); | 191 | v9fs_set_acl(dentry, ACL_TYPE_ACCESS, pacl); |
182 | if (pacl) | ||
183 | v9fs_set_acl(dentry, ACL_TYPE_ACCESS, pacl); | ||
184 | posix_acl_release(dpacl); | 192 | posix_acl_release(dpacl); |
185 | posix_acl_release(pacl); | 193 | posix_acl_release(pacl); |
186 | return 0; | 194 | return 0; |
diff --git a/fs/9p/cache.c b/fs/9p/cache.c index 0dbe0d139ac2..5b335c5086a1 100644 --- a/fs/9p/cache.c +++ b/fs/9p/cache.c | |||
@@ -33,67 +33,11 @@ | |||
33 | 33 | ||
34 | #define CACHETAG_LEN 11 | 34 | #define CACHETAG_LEN 11 |
35 | 35 | ||
36 | struct kmem_cache *vcookie_cache; | ||
37 | |||
38 | struct fscache_netfs v9fs_cache_netfs = { | 36 | struct fscache_netfs v9fs_cache_netfs = { |
39 | .name = "9p", | 37 | .name = "9p", |
40 | .version = 0, | 38 | .version = 0, |
41 | }; | 39 | }; |
42 | 40 | ||
43 | static void init_once(void *foo) | ||
44 | { | ||
45 | struct v9fs_cookie *vcookie = (struct v9fs_cookie *) foo; | ||
46 | vcookie->fscache = NULL; | ||
47 | vcookie->qid = NULL; | ||
48 | inode_init_once(&vcookie->inode); | ||
49 | } | ||
50 | |||
51 | /** | ||
52 | * v9fs_init_vcookiecache - initialize a cache for vcookies to maintain | ||
53 | * vcookie to inode mapping | ||
54 | * | ||
55 | * Returns 0 on success. | ||
56 | */ | ||
57 | |||
58 | static int v9fs_init_vcookiecache(void) | ||
59 | { | ||
60 | vcookie_cache = kmem_cache_create("vcookie_cache", | ||
61 | sizeof(struct v9fs_cookie), | ||
62 | 0, (SLAB_RECLAIM_ACCOUNT| | ||
63 | SLAB_MEM_SPREAD), | ||
64 | init_once); | ||
65 | if (!vcookie_cache) | ||
66 | return -ENOMEM; | ||
67 | |||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | /** | ||
72 | * v9fs_destroy_vcookiecache - destroy the cache of vcookies | ||
73 | * | ||
74 | */ | ||
75 | |||
76 | static void v9fs_destroy_vcookiecache(void) | ||
77 | { | ||
78 | kmem_cache_destroy(vcookie_cache); | ||
79 | } | ||
80 | |||
81 | int __v9fs_cache_register(void) | ||
82 | { | ||
83 | int ret; | ||
84 | ret = v9fs_init_vcookiecache(); | ||
85 | if (ret < 0) | ||
86 | return ret; | ||
87 | |||
88 | return fscache_register_netfs(&v9fs_cache_netfs); | ||
89 | } | ||
90 | |||
91 | void __v9fs_cache_unregister(void) | ||
92 | { | ||
93 | v9fs_destroy_vcookiecache(); | ||
94 | fscache_unregister_netfs(&v9fs_cache_netfs); | ||
95 | } | ||
96 | |||
97 | /** | 41 | /** |
98 | * v9fs_random_cachetag - Generate a random tag to be associated | 42 | * v9fs_random_cachetag - Generate a random tag to be associated |
99 | * with a new cache session. | 43 | * with a new cache session. |
@@ -133,9 +77,9 @@ static uint16_t v9fs_cache_session_get_key(const void *cookie_netfs_data, | |||
133 | } | 77 | } |
134 | 78 | ||
135 | const struct fscache_cookie_def v9fs_cache_session_index_def = { | 79 | const struct fscache_cookie_def v9fs_cache_session_index_def = { |
136 | .name = "9P.session", | 80 | .name = "9P.session", |
137 | .type = FSCACHE_COOKIE_TYPE_INDEX, | 81 | .type = FSCACHE_COOKIE_TYPE_INDEX, |
138 | .get_key = v9fs_cache_session_get_key, | 82 | .get_key = v9fs_cache_session_get_key, |
139 | }; | 83 | }; |
140 | 84 | ||
141 | void v9fs_cache_session_get_cookie(struct v9fs_session_info *v9ses) | 85 | void v9fs_cache_session_get_cookie(struct v9fs_session_info *v9ses) |
@@ -163,33 +107,33 @@ void v9fs_cache_session_put_cookie(struct v9fs_session_info *v9ses) | |||
163 | static uint16_t v9fs_cache_inode_get_key(const void *cookie_netfs_data, | 107 | static uint16_t v9fs_cache_inode_get_key(const void *cookie_netfs_data, |
164 | void *buffer, uint16_t bufmax) | 108 | void *buffer, uint16_t bufmax) |
165 | { | 109 | { |
166 | const struct v9fs_cookie *vcookie = cookie_netfs_data; | 110 | const struct v9fs_inode *v9inode = cookie_netfs_data; |
167 | memcpy(buffer, &vcookie->qid->path, sizeof(vcookie->qid->path)); | 111 | memcpy(buffer, &v9inode->fscache_key->path, |
168 | 112 | sizeof(v9inode->fscache_key->path)); | |
169 | P9_DPRINTK(P9_DEBUG_FSC, "inode %p get key %llu", &vcookie->inode, | 113 | P9_DPRINTK(P9_DEBUG_FSC, "inode %p get key %llu", &v9inode->vfs_inode, |
170 | vcookie->qid->path); | 114 | v9inode->fscache_key->path); |
171 | return sizeof(vcookie->qid->path); | 115 | return sizeof(v9inode->fscache_key->path); |
172 | } | 116 | } |
173 | 117 | ||
174 | static void v9fs_cache_inode_get_attr(const void *cookie_netfs_data, | 118 | static void v9fs_cache_inode_get_attr(const void *cookie_netfs_data, |
175 | uint64_t *size) | 119 | uint64_t *size) |
176 | { | 120 | { |
177 | const struct v9fs_cookie *vcookie = cookie_netfs_data; | 121 | const struct v9fs_inode *v9inode = cookie_netfs_data; |
178 | *size = i_size_read(&vcookie->inode); | 122 | *size = i_size_read(&v9inode->vfs_inode); |
179 | 123 | ||
180 | P9_DPRINTK(P9_DEBUG_FSC, "inode %p get attr %llu", &vcookie->inode, | 124 | P9_DPRINTK(P9_DEBUG_FSC, "inode %p get attr %llu", &v9inode->vfs_inode, |
181 | *size); | 125 | *size); |
182 | } | 126 | } |
183 | 127 | ||
184 | static uint16_t v9fs_cache_inode_get_aux(const void *cookie_netfs_data, | 128 | static uint16_t v9fs_cache_inode_get_aux(const void *cookie_netfs_data, |
185 | void *buffer, uint16_t buflen) | 129 | void *buffer, uint16_t buflen) |
186 | { | 130 | { |
187 | const struct v9fs_cookie *vcookie = cookie_netfs_data; | 131 | const struct v9fs_inode *v9inode = cookie_netfs_data; |
188 | memcpy(buffer, &vcookie->qid->version, sizeof(vcookie->qid->version)); | 132 | memcpy(buffer, &v9inode->fscache_key->version, |
189 | 133 | sizeof(v9inode->fscache_key->version)); | |
190 | P9_DPRINTK(P9_DEBUG_FSC, "inode %p get aux %u", &vcookie->inode, | 134 | P9_DPRINTK(P9_DEBUG_FSC, "inode %p get aux %u", &v9inode->vfs_inode, |
191 | vcookie->qid->version); | 135 | v9inode->fscache_key->version); |
192 | return sizeof(vcookie->qid->version); | 136 | return sizeof(v9inode->fscache_key->version); |
193 | } | 137 | } |
194 | 138 | ||
195 | static enum | 139 | static enum |
@@ -197,13 +141,13 @@ fscache_checkaux v9fs_cache_inode_check_aux(void *cookie_netfs_data, | |||
197 | const void *buffer, | 141 | const void *buffer, |
198 | uint16_t buflen) | 142 | uint16_t buflen) |
199 | { | 143 | { |
200 | const struct v9fs_cookie *vcookie = cookie_netfs_data; | 144 | const struct v9fs_inode *v9inode = cookie_netfs_data; |
201 | 145 | ||
202 | if (buflen != sizeof(vcookie->qid->version)) | 146 | if (buflen != sizeof(v9inode->fscache_key->version)) |
203 | return FSCACHE_CHECKAUX_OBSOLETE; | 147 | return FSCACHE_CHECKAUX_OBSOLETE; |
204 | 148 | ||
205 | if (memcmp(buffer, &vcookie->qid->version, | 149 | if (memcmp(buffer, &v9inode->fscache_key->version, |
206 | sizeof(vcookie->qid->version))) | 150 | sizeof(v9inode->fscache_key->version))) |
207 | return FSCACHE_CHECKAUX_OBSOLETE; | 151 | return FSCACHE_CHECKAUX_OBSOLETE; |
208 | 152 | ||
209 | return FSCACHE_CHECKAUX_OKAY; | 153 | return FSCACHE_CHECKAUX_OKAY; |
@@ -211,7 +155,7 @@ fscache_checkaux v9fs_cache_inode_check_aux(void *cookie_netfs_data, | |||
211 | 155 | ||
212 | static void v9fs_cache_inode_now_uncached(void *cookie_netfs_data) | 156 | static void v9fs_cache_inode_now_uncached(void *cookie_netfs_data) |
213 | { | 157 | { |
214 | struct v9fs_cookie *vcookie = cookie_netfs_data; | 158 | struct v9fs_inode *v9inode = cookie_netfs_data; |
215 | struct pagevec pvec; | 159 | struct pagevec pvec; |
216 | pgoff_t first; | 160 | pgoff_t first; |
217 | int loop, nr_pages; | 161 | int loop, nr_pages; |
@@ -220,7 +164,7 @@ static void v9fs_cache_inode_now_uncached(void *cookie_netfs_data) | |||
220 | first = 0; | 164 | first = 0; |
221 | 165 | ||
222 | for (;;) { | 166 | for (;;) { |
223 | nr_pages = pagevec_lookup(&pvec, vcookie->inode.i_mapping, | 167 | nr_pages = pagevec_lookup(&pvec, v9inode->vfs_inode.i_mapping, |
224 | first, | 168 | first, |
225 | PAGEVEC_SIZE - pagevec_count(&pvec)); | 169 | PAGEVEC_SIZE - pagevec_count(&pvec)); |
226 | if (!nr_pages) | 170 | if (!nr_pages) |
@@ -249,115 +193,114 @@ const struct fscache_cookie_def v9fs_cache_inode_index_def = { | |||
249 | 193 | ||
250 | void v9fs_cache_inode_get_cookie(struct inode *inode) | 194 | void v9fs_cache_inode_get_cookie(struct inode *inode) |
251 | { | 195 | { |
252 | struct v9fs_cookie *vcookie; | 196 | struct v9fs_inode *v9inode; |
253 | struct v9fs_session_info *v9ses; | 197 | struct v9fs_session_info *v9ses; |
254 | 198 | ||
255 | if (!S_ISREG(inode->i_mode)) | 199 | if (!S_ISREG(inode->i_mode)) |
256 | return; | 200 | return; |
257 | 201 | ||
258 | vcookie = v9fs_inode2cookie(inode); | 202 | v9inode = V9FS_I(inode); |
259 | if (vcookie->fscache) | 203 | if (v9inode->fscache) |
260 | return; | 204 | return; |
261 | 205 | ||
262 | v9ses = v9fs_inode2v9ses(inode); | 206 | v9ses = v9fs_inode2v9ses(inode); |
263 | vcookie->fscache = fscache_acquire_cookie(v9ses->fscache, | 207 | v9inode->fscache = fscache_acquire_cookie(v9ses->fscache, |
264 | &v9fs_cache_inode_index_def, | 208 | &v9fs_cache_inode_index_def, |
265 | vcookie); | 209 | v9inode); |
266 | 210 | ||
267 | P9_DPRINTK(P9_DEBUG_FSC, "inode %p get cookie %p", inode, | 211 | P9_DPRINTK(P9_DEBUG_FSC, "inode %p get cookie %p", inode, |
268 | vcookie->fscache); | 212 | v9inode->fscache); |
269 | } | 213 | } |
270 | 214 | ||
271 | void v9fs_cache_inode_put_cookie(struct inode *inode) | 215 | void v9fs_cache_inode_put_cookie(struct inode *inode) |
272 | { | 216 | { |
273 | struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode); | 217 | struct v9fs_inode *v9inode = V9FS_I(inode); |
274 | 218 | ||
275 | if (!vcookie->fscache) | 219 | if (!v9inode->fscache) |
276 | return; | 220 | return; |
277 | P9_DPRINTK(P9_DEBUG_FSC, "inode %p put cookie %p", inode, | 221 | P9_DPRINTK(P9_DEBUG_FSC, "inode %p put cookie %p", inode, |
278 | vcookie->fscache); | 222 | v9inode->fscache); |
279 | 223 | ||
280 | fscache_relinquish_cookie(vcookie->fscache, 0); | 224 | fscache_relinquish_cookie(v9inode->fscache, 0); |
281 | vcookie->fscache = NULL; | 225 | v9inode->fscache = NULL; |
282 | } | 226 | } |
283 | 227 | ||
284 | void v9fs_cache_inode_flush_cookie(struct inode *inode) | 228 | void v9fs_cache_inode_flush_cookie(struct inode *inode) |
285 | { | 229 | { |
286 | struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode); | 230 | struct v9fs_inode *v9inode = V9FS_I(inode); |
287 | 231 | ||
288 | if (!vcookie->fscache) | 232 | if (!v9inode->fscache) |
289 | return; | 233 | return; |
290 | P9_DPRINTK(P9_DEBUG_FSC, "inode %p flush cookie %p", inode, | 234 | P9_DPRINTK(P9_DEBUG_FSC, "inode %p flush cookie %p", inode, |
291 | vcookie->fscache); | 235 | v9inode->fscache); |
292 | 236 | ||
293 | fscache_relinquish_cookie(vcookie->fscache, 1); | 237 | fscache_relinquish_cookie(v9inode->fscache, 1); |
294 | vcookie->fscache = NULL; | 238 | v9inode->fscache = NULL; |
295 | } | 239 | } |
296 | 240 | ||
297 | void v9fs_cache_inode_set_cookie(struct inode *inode, struct file *filp) | 241 | void v9fs_cache_inode_set_cookie(struct inode *inode, struct file *filp) |
298 | { | 242 | { |
299 | struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode); | 243 | struct v9fs_inode *v9inode = V9FS_I(inode); |
300 | struct p9_fid *fid; | 244 | struct p9_fid *fid; |
301 | 245 | ||
302 | if (!vcookie->fscache) | 246 | if (!v9inode->fscache) |
303 | return; | 247 | return; |
304 | 248 | ||
305 | spin_lock(&vcookie->lock); | 249 | spin_lock(&v9inode->fscache_lock); |
306 | fid = filp->private_data; | 250 | fid = filp->private_data; |
307 | if ((filp->f_flags & O_ACCMODE) != O_RDONLY) | 251 | if ((filp->f_flags & O_ACCMODE) != O_RDONLY) |
308 | v9fs_cache_inode_flush_cookie(inode); | 252 | v9fs_cache_inode_flush_cookie(inode); |
309 | else | 253 | else |
310 | v9fs_cache_inode_get_cookie(inode); | 254 | v9fs_cache_inode_get_cookie(inode); |
311 | 255 | ||
312 | spin_unlock(&vcookie->lock); | 256 | spin_unlock(&v9inode->fscache_lock); |
313 | } | 257 | } |
314 | 258 | ||
315 | void v9fs_cache_inode_reset_cookie(struct inode *inode) | 259 | void v9fs_cache_inode_reset_cookie(struct inode *inode) |
316 | { | 260 | { |
317 | struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode); | 261 | struct v9fs_inode *v9inode = V9FS_I(inode); |
318 | struct v9fs_session_info *v9ses; | 262 | struct v9fs_session_info *v9ses; |
319 | struct fscache_cookie *old; | 263 | struct fscache_cookie *old; |
320 | 264 | ||
321 | if (!vcookie->fscache) | 265 | if (!v9inode->fscache) |
322 | return; | 266 | return; |
323 | 267 | ||
324 | old = vcookie->fscache; | 268 | old = v9inode->fscache; |
325 | 269 | ||
326 | spin_lock(&vcookie->lock); | 270 | spin_lock(&v9inode->fscache_lock); |
327 | fscache_relinquish_cookie(vcookie->fscache, 1); | 271 | fscache_relinquish_cookie(v9inode->fscache, 1); |
328 | 272 | ||
329 | v9ses = v9fs_inode2v9ses(inode); | 273 | v9ses = v9fs_inode2v9ses(inode); |
330 | vcookie->fscache = fscache_acquire_cookie(v9ses->fscache, | 274 | v9inode->fscache = fscache_acquire_cookie(v9ses->fscache, |
331 | &v9fs_cache_inode_index_def, | 275 | &v9fs_cache_inode_index_def, |
332 | vcookie); | 276 | v9inode); |
333 | |||
334 | P9_DPRINTK(P9_DEBUG_FSC, "inode %p revalidating cookie old %p new %p", | 277 | P9_DPRINTK(P9_DEBUG_FSC, "inode %p revalidating cookie old %p new %p", |
335 | inode, old, vcookie->fscache); | 278 | inode, old, v9inode->fscache); |
336 | 279 | ||
337 | spin_unlock(&vcookie->lock); | 280 | spin_unlock(&v9inode->fscache_lock); |
338 | } | 281 | } |
339 | 282 | ||
340 | int __v9fs_fscache_release_page(struct page *page, gfp_t gfp) | 283 | int __v9fs_fscache_release_page(struct page *page, gfp_t gfp) |
341 | { | 284 | { |
342 | struct inode *inode = page->mapping->host; | 285 | struct inode *inode = page->mapping->host; |
343 | struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode); | 286 | struct v9fs_inode *v9inode = V9FS_I(inode); |
344 | 287 | ||
345 | BUG_ON(!vcookie->fscache); | 288 | BUG_ON(!v9inode->fscache); |
346 | 289 | ||
347 | return fscache_maybe_release_page(vcookie->fscache, page, gfp); | 290 | return fscache_maybe_release_page(v9inode->fscache, page, gfp); |
348 | } | 291 | } |
349 | 292 | ||
350 | void __v9fs_fscache_invalidate_page(struct page *page) | 293 | void __v9fs_fscache_invalidate_page(struct page *page) |
351 | { | 294 | { |
352 | struct inode *inode = page->mapping->host; | 295 | struct inode *inode = page->mapping->host; |
353 | struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode); | 296 | struct v9fs_inode *v9inode = V9FS_I(inode); |
354 | 297 | ||
355 | BUG_ON(!vcookie->fscache); | 298 | BUG_ON(!v9inode->fscache); |
356 | 299 | ||
357 | if (PageFsCache(page)) { | 300 | if (PageFsCache(page)) { |
358 | fscache_wait_on_page_write(vcookie->fscache, page); | 301 | fscache_wait_on_page_write(v9inode->fscache, page); |
359 | BUG_ON(!PageLocked(page)); | 302 | BUG_ON(!PageLocked(page)); |
360 | fscache_uncache_page(vcookie->fscache, page); | 303 | fscache_uncache_page(v9inode->fscache, page); |
361 | } | 304 | } |
362 | } | 305 | } |
363 | 306 | ||
@@ -380,13 +323,13 @@ static void v9fs_vfs_readpage_complete(struct page *page, void *data, | |||
380 | int __v9fs_readpage_from_fscache(struct inode *inode, struct page *page) | 323 | int __v9fs_readpage_from_fscache(struct inode *inode, struct page *page) |
381 | { | 324 | { |
382 | int ret; | 325 | int ret; |
383 | const struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode); | 326 | const struct v9fs_inode *v9inode = V9FS_I(inode); |
384 | 327 | ||
385 | P9_DPRINTK(P9_DEBUG_FSC, "inode %p page %p", inode, page); | 328 | P9_DPRINTK(P9_DEBUG_FSC, "inode %p page %p", inode, page); |
386 | if (!vcookie->fscache) | 329 | if (!v9inode->fscache) |
387 | return -ENOBUFS; | 330 | return -ENOBUFS; |
388 | 331 | ||
389 | ret = fscache_read_or_alloc_page(vcookie->fscache, | 332 | ret = fscache_read_or_alloc_page(v9inode->fscache, |
390 | page, | 333 | page, |
391 | v9fs_vfs_readpage_complete, | 334 | v9fs_vfs_readpage_complete, |
392 | NULL, | 335 | NULL, |
@@ -418,13 +361,13 @@ int __v9fs_readpages_from_fscache(struct inode *inode, | |||
418 | unsigned *nr_pages) | 361 | unsigned *nr_pages) |
419 | { | 362 | { |
420 | int ret; | 363 | int ret; |
421 | const struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode); | 364 | const struct v9fs_inode *v9inode = V9FS_I(inode); |
422 | 365 | ||
423 | P9_DPRINTK(P9_DEBUG_FSC, "inode %p pages %u", inode, *nr_pages); | 366 | P9_DPRINTK(P9_DEBUG_FSC, "inode %p pages %u", inode, *nr_pages); |
424 | if (!vcookie->fscache) | 367 | if (!v9inode->fscache) |
425 | return -ENOBUFS; | 368 | return -ENOBUFS; |
426 | 369 | ||
427 | ret = fscache_read_or_alloc_pages(vcookie->fscache, | 370 | ret = fscache_read_or_alloc_pages(v9inode->fscache, |
428 | mapping, pages, nr_pages, | 371 | mapping, pages, nr_pages, |
429 | v9fs_vfs_readpage_complete, | 372 | v9fs_vfs_readpage_complete, |
430 | NULL, | 373 | NULL, |
@@ -453,11 +396,22 @@ int __v9fs_readpages_from_fscache(struct inode *inode, | |||
453 | void __v9fs_readpage_to_fscache(struct inode *inode, struct page *page) | 396 | void __v9fs_readpage_to_fscache(struct inode *inode, struct page *page) |
454 | { | 397 | { |
455 | int ret; | 398 | int ret; |
456 | const struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode); | 399 | const struct v9fs_inode *v9inode = V9FS_I(inode); |
457 | 400 | ||
458 | P9_DPRINTK(P9_DEBUG_FSC, "inode %p page %p", inode, page); | 401 | P9_DPRINTK(P9_DEBUG_FSC, "inode %p page %p", inode, page); |
459 | ret = fscache_write_page(vcookie->fscache, page, GFP_KERNEL); | 402 | ret = fscache_write_page(v9inode->fscache, page, GFP_KERNEL); |
460 | P9_DPRINTK(P9_DEBUG_FSC, "ret = %d", ret); | 403 | P9_DPRINTK(P9_DEBUG_FSC, "ret = %d", ret); |
461 | if (ret != 0) | 404 | if (ret != 0) |
462 | v9fs_uncache_page(inode, page); | 405 | v9fs_uncache_page(inode, page); |
463 | } | 406 | } |
407 | |||
408 | /* | ||
409 | * wait for a page to complete writing to the cache | ||
410 | */ | ||
411 | void __v9fs_fscache_wait_on_page_write(struct inode *inode, struct page *page) | ||
412 | { | ||
413 | const struct v9fs_inode *v9inode = V9FS_I(inode); | ||
414 | P9_DPRINTK(P9_DEBUG_FSC, "inode %p page %p", inode, page); | ||
415 | if (PageFsCache(page)) | ||
416 | fscache_wait_on_page_write(v9inode->fscache, page); | ||
417 | } | ||
diff --git a/fs/9p/cache.h b/fs/9p/cache.h index a94192bfaee8..049507a5b01c 100644 --- a/fs/9p/cache.h +++ b/fs/9p/cache.h | |||
@@ -25,20 +25,6 @@ | |||
25 | #include <linux/fscache.h> | 25 | #include <linux/fscache.h> |
26 | #include <linux/spinlock.h> | 26 | #include <linux/spinlock.h> |
27 | 27 | ||
28 | extern struct kmem_cache *vcookie_cache; | ||
29 | |||
30 | struct v9fs_cookie { | ||
31 | spinlock_t lock; | ||
32 | struct inode inode; | ||
33 | struct fscache_cookie *fscache; | ||
34 | struct p9_qid *qid; | ||
35 | }; | ||
36 | |||
37 | static inline struct v9fs_cookie *v9fs_inode2cookie(const struct inode *inode) | ||
38 | { | ||
39 | return container_of(inode, struct v9fs_cookie, inode); | ||
40 | } | ||
41 | |||
42 | extern struct fscache_netfs v9fs_cache_netfs; | 28 | extern struct fscache_netfs v9fs_cache_netfs; |
43 | extern const struct fscache_cookie_def v9fs_cache_session_index_def; | 29 | extern const struct fscache_cookie_def v9fs_cache_session_index_def; |
44 | extern const struct fscache_cookie_def v9fs_cache_inode_index_def; | 30 | extern const struct fscache_cookie_def v9fs_cache_inode_index_def; |
@@ -64,23 +50,8 @@ extern int __v9fs_readpages_from_fscache(struct inode *inode, | |||
64 | struct list_head *pages, | 50 | struct list_head *pages, |
65 | unsigned *nr_pages); | 51 | unsigned *nr_pages); |
66 | extern void __v9fs_readpage_to_fscache(struct inode *inode, struct page *page); | 52 | extern void __v9fs_readpage_to_fscache(struct inode *inode, struct page *page); |
67 | 53 | extern void __v9fs_fscache_wait_on_page_write(struct inode *inode, | |
68 | 54 | struct page *page); | |
69 | /** | ||
70 | * v9fs_cache_register - Register v9fs file system with the cache | ||
71 | */ | ||
72 | static inline int v9fs_cache_register(void) | ||
73 | { | ||
74 | return __v9fs_cache_register(); | ||
75 | } | ||
76 | |||
77 | /** | ||
78 | * v9fs_cache_unregister - Unregister v9fs from the cache | ||
79 | */ | ||
80 | static inline void v9fs_cache_unregister(void) | ||
81 | { | ||
82 | __v9fs_cache_unregister(); | ||
83 | } | ||
84 | 55 | ||
85 | static inline int v9fs_fscache_release_page(struct page *page, | 56 | static inline int v9fs_fscache_release_page(struct page *page, |
86 | gfp_t gfp) | 57 | gfp_t gfp) |
@@ -117,28 +88,27 @@ static inline void v9fs_readpage_to_fscache(struct inode *inode, | |||
117 | 88 | ||
118 | static inline void v9fs_uncache_page(struct inode *inode, struct page *page) | 89 | static inline void v9fs_uncache_page(struct inode *inode, struct page *page) |
119 | { | 90 | { |
120 | struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode); | 91 | struct v9fs_inode *v9inode = V9FS_I(inode); |
121 | fscache_uncache_page(vcookie->fscache, page); | 92 | fscache_uncache_page(v9inode->fscache, page); |
122 | BUG_ON(PageFsCache(page)); | 93 | BUG_ON(PageFsCache(page)); |
123 | } | 94 | } |
124 | 95 | ||
125 | static inline void v9fs_vcookie_set_qid(struct inode *inode, | 96 | static inline void v9fs_fscache_set_key(struct inode *inode, |
126 | struct p9_qid *qid) | 97 | struct p9_qid *qid) |
127 | { | 98 | { |
128 | struct v9fs_cookie *vcookie = v9fs_inode2cookie(inode); | 99 | struct v9fs_inode *v9inode = V9FS_I(inode); |
129 | spin_lock(&vcookie->lock); | 100 | spin_lock(&v9inode->fscache_lock); |
130 | vcookie->qid = qid; | 101 | v9inode->fscache_key = qid; |
131 | spin_unlock(&vcookie->lock); | 102 | spin_unlock(&v9inode->fscache_lock); |
132 | } | 103 | } |
133 | 104 | ||
134 | #else /* CONFIG_9P_FSCACHE */ | 105 | static inline void v9fs_fscache_wait_on_page_write(struct inode *inode, |
135 | 106 | struct page *page) | |
136 | static inline int v9fs_cache_register(void) | ||
137 | { | 107 | { |
138 | return 1; | 108 | return __v9fs_fscache_wait_on_page_write(inode, page); |
139 | } | 109 | } |
140 | 110 | ||
141 | static inline void v9fs_cache_unregister(void) {} | 111 | #else /* CONFIG_9P_FSCACHE */ |
142 | 112 | ||
143 | static inline int v9fs_fscache_release_page(struct page *page, | 113 | static inline int v9fs_fscache_release_page(struct page *page, |
144 | gfp_t gfp) { | 114 | gfp_t gfp) { |
@@ -168,9 +138,11 @@ static inline void v9fs_readpage_to_fscache(struct inode *inode, | |||
168 | static inline void v9fs_uncache_page(struct inode *inode, struct page *page) | 138 | static inline void v9fs_uncache_page(struct inode *inode, struct page *page) |
169 | {} | 139 | {} |
170 | 140 | ||
171 | static inline void v9fs_vcookie_set_qid(struct inode *inode, | 141 | static inline void v9fs_fscache_wait_on_page_write(struct inode *inode, |
172 | struct p9_qid *qid) | 142 | struct page *page) |
173 | {} | 143 | { |
144 | return; | ||
145 | } | ||
174 | 146 | ||
175 | #endif /* CONFIG_9P_FSCACHE */ | 147 | #endif /* CONFIG_9P_FSCACHE */ |
176 | #endif /* _9P_CACHE_H */ | 148 | #endif /* _9P_CACHE_H */ |
diff --git a/fs/9p/fid.c b/fs/9p/fid.c index b00223c99d70..cd63e002d826 100644 --- a/fs/9p/fid.c +++ b/fs/9p/fid.c | |||
@@ -125,46 +125,17 @@ err_out: | |||
125 | return -ENOMEM; | 125 | return -ENOMEM; |
126 | } | 126 | } |
127 | 127 | ||
128 | /** | 128 | static struct p9_fid *v9fs_fid_lookup_with_uid(struct dentry *dentry, |
129 | * v9fs_fid_lookup - lookup for a fid, try to walk if not found | 129 | uid_t uid, int any) |
130 | * @dentry: dentry to look for fid in | ||
131 | * | ||
132 | * Look for a fid in the specified dentry for the current user. | ||
133 | * If no fid is found, try to create one walking from a fid from the parent | ||
134 | * dentry (if it has one), or the root dentry. If the user haven't accessed | ||
135 | * the fs yet, attach now and walk from the root. | ||
136 | */ | ||
137 | |||
138 | struct p9_fid *v9fs_fid_lookup(struct dentry *dentry) | ||
139 | { | 130 | { |
140 | int i, n, l, clone, any, access; | ||
141 | u32 uid; | ||
142 | struct p9_fid *fid, *old_fid = NULL; | ||
143 | struct dentry *ds; | 131 | struct dentry *ds; |
144 | struct v9fs_session_info *v9ses; | ||
145 | char **wnames, *uname; | 132 | char **wnames, *uname; |
133 | int i, n, l, clone, access; | ||
134 | struct v9fs_session_info *v9ses; | ||
135 | struct p9_fid *fid, *old_fid = NULL; | ||
146 | 136 | ||
147 | v9ses = v9fs_inode2v9ses(dentry->d_inode); | 137 | v9ses = v9fs_inode2v9ses(dentry->d_inode); |
148 | access = v9ses->flags & V9FS_ACCESS_MASK; | 138 | access = v9ses->flags & V9FS_ACCESS_MASK; |
149 | switch (access) { | ||
150 | case V9FS_ACCESS_SINGLE: | ||
151 | case V9FS_ACCESS_USER: | ||
152 | case V9FS_ACCESS_CLIENT: | ||
153 | uid = current_fsuid(); | ||
154 | any = 0; | ||
155 | break; | ||
156 | |||
157 | case V9FS_ACCESS_ANY: | ||
158 | uid = v9ses->uid; | ||
159 | any = 1; | ||
160 | break; | ||
161 | |||
162 | default: | ||
163 | uid = ~0; | ||
164 | any = 0; | ||
165 | break; | ||
166 | } | ||
167 | |||
168 | fid = v9fs_fid_find(dentry, uid, any); | 139 | fid = v9fs_fid_find(dentry, uid, any); |
169 | if (fid) | 140 | if (fid) |
170 | return fid; | 141 | return fid; |
@@ -250,6 +221,45 @@ err_out: | |||
250 | return fid; | 221 | return fid; |
251 | } | 222 | } |
252 | 223 | ||
224 | /** | ||
225 | * v9fs_fid_lookup - lookup for a fid, try to walk if not found | ||
226 | * @dentry: dentry to look for fid in | ||
227 | * | ||
228 | * Look for a fid in the specified dentry for the current user. | ||
229 | * If no fid is found, try to create one walking from a fid from the parent | ||
230 | * dentry (if it has one), or the root dentry. If the user haven't accessed | ||
231 | * the fs yet, attach now and walk from the root. | ||
232 | */ | ||
233 | |||
234 | struct p9_fid *v9fs_fid_lookup(struct dentry *dentry) | ||
235 | { | ||
236 | uid_t uid; | ||
237 | int any, access; | ||
238 | struct v9fs_session_info *v9ses; | ||
239 | |||
240 | v9ses = v9fs_inode2v9ses(dentry->d_inode); | ||
241 | access = v9ses->flags & V9FS_ACCESS_MASK; | ||
242 | switch (access) { | ||
243 | case V9FS_ACCESS_SINGLE: | ||
244 | case V9FS_ACCESS_USER: | ||
245 | case V9FS_ACCESS_CLIENT: | ||
246 | uid = current_fsuid(); | ||
247 | any = 0; | ||
248 | break; | ||
249 | |||
250 | case V9FS_ACCESS_ANY: | ||
251 | uid = v9ses->uid; | ||
252 | any = 1; | ||
253 | break; | ||
254 | |||
255 | default: | ||
256 | uid = ~0; | ||
257 | any = 0; | ||
258 | break; | ||
259 | } | ||
260 | return v9fs_fid_lookup_with_uid(dentry, uid, any); | ||
261 | } | ||
262 | |||
253 | struct p9_fid *v9fs_fid_clone(struct dentry *dentry) | 263 | struct p9_fid *v9fs_fid_clone(struct dentry *dentry) |
254 | { | 264 | { |
255 | struct p9_fid *fid, *ret; | 265 | struct p9_fid *fid, *ret; |
@@ -261,3 +271,39 @@ struct p9_fid *v9fs_fid_clone(struct dentry *dentry) | |||
261 | ret = p9_client_walk(fid, 0, NULL, 1); | 271 | ret = p9_client_walk(fid, 0, NULL, 1); |
262 | return ret; | 272 | return ret; |
263 | } | 273 | } |
274 | |||
275 | static struct p9_fid *v9fs_fid_clone_with_uid(struct dentry *dentry, uid_t uid) | ||
276 | { | ||
277 | struct p9_fid *fid, *ret; | ||
278 | |||
279 | fid = v9fs_fid_lookup_with_uid(dentry, uid, 0); | ||
280 | if (IS_ERR(fid)) | ||
281 | return fid; | ||
282 | |||
283 | ret = p9_client_walk(fid, 0, NULL, 1); | ||
284 | return ret; | ||
285 | } | ||
286 | |||
287 | struct p9_fid *v9fs_writeback_fid(struct dentry *dentry) | ||
288 | { | ||
289 | int err; | ||
290 | struct p9_fid *fid; | ||
291 | |||
292 | fid = v9fs_fid_clone_with_uid(dentry, 0); | ||
293 | if (IS_ERR(fid)) | ||
294 | goto error_out; | ||
295 | /* | ||
296 | * writeback fid will only be used to write back the | ||
297 | * dirty pages. We always request for the open fid in read-write | ||
298 | * mode so that a partial page write which result in page | ||
299 | * read can work. | ||
300 | */ | ||
301 | err = p9_client_open(fid, O_RDWR); | ||
302 | if (err < 0) { | ||
303 | p9_client_clunk(fid); | ||
304 | fid = ERR_PTR(err); | ||
305 | goto error_out; | ||
306 | } | ||
307 | error_out: | ||
308 | return fid; | ||
309 | } | ||
diff --git a/fs/9p/fid.h b/fs/9p/fid.h index c3bbd6af996d..bb0b6e7f58fc 100644 --- a/fs/9p/fid.h +++ b/fs/9p/fid.h | |||
@@ -19,7 +19,8 @@ | |||
19 | * Boston, MA 02111-1301 USA | 19 | * Boston, MA 02111-1301 USA |
20 | * | 20 | * |
21 | */ | 21 | */ |
22 | 22 | #ifndef FS_9P_FID_H | |
23 | #define FS_9P_FID_H | ||
23 | #include <linux/list.h> | 24 | #include <linux/list.h> |
24 | 25 | ||
25 | /** | 26 | /** |
@@ -45,3 +46,5 @@ struct v9fs_dentry { | |||
45 | struct p9_fid *v9fs_fid_lookup(struct dentry *dentry); | 46 | struct p9_fid *v9fs_fid_lookup(struct dentry *dentry); |
46 | struct p9_fid *v9fs_fid_clone(struct dentry *dentry); | 47 | struct p9_fid *v9fs_fid_clone(struct dentry *dentry); |
47 | int v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid); | 48 | int v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid); |
49 | struct p9_fid *v9fs_writeback_fid(struct dentry *dentry); | ||
50 | #endif | ||
diff --git a/fs/9p/v9fs.c b/fs/9p/v9fs.c index 2f77cd33ba83..c82b017f51f3 100644 --- a/fs/9p/v9fs.c +++ b/fs/9p/v9fs.c | |||
@@ -39,6 +39,7 @@ | |||
39 | 39 | ||
40 | static DEFINE_SPINLOCK(v9fs_sessionlist_lock); | 40 | static DEFINE_SPINLOCK(v9fs_sessionlist_lock); |
41 | static LIST_HEAD(v9fs_sessionlist); | 41 | static LIST_HEAD(v9fs_sessionlist); |
42 | struct kmem_cache *v9fs_inode_cache; | ||
42 | 43 | ||
43 | /* | 44 | /* |
44 | * Option Parsing (code inspired by NFS code) | 45 | * Option Parsing (code inspired by NFS code) |
@@ -55,7 +56,7 @@ enum { | |||
55 | /* Cache options */ | 56 | /* Cache options */ |
56 | Opt_cache_loose, Opt_fscache, | 57 | Opt_cache_loose, Opt_fscache, |
57 | /* Access options */ | 58 | /* Access options */ |
58 | Opt_access, | 59 | Opt_access, Opt_posixacl, |
59 | /* Error token */ | 60 | /* Error token */ |
60 | Opt_err | 61 | Opt_err |
61 | }; | 62 | }; |
@@ -73,6 +74,7 @@ static const match_table_t tokens = { | |||
73 | {Opt_fscache, "fscache"}, | 74 | {Opt_fscache, "fscache"}, |
74 | {Opt_cachetag, "cachetag=%s"}, | 75 | {Opt_cachetag, "cachetag=%s"}, |
75 | {Opt_access, "access=%s"}, | 76 | {Opt_access, "access=%s"}, |
77 | {Opt_posixacl, "posixacl"}, | ||
76 | {Opt_err, NULL} | 78 | {Opt_err, NULL} |
77 | }; | 79 | }; |
78 | 80 | ||
@@ -194,15 +196,7 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts) | |||
194 | else if (strcmp(s, "any") == 0) | 196 | else if (strcmp(s, "any") == 0) |
195 | v9ses->flags |= V9FS_ACCESS_ANY; | 197 | v9ses->flags |= V9FS_ACCESS_ANY; |
196 | else if (strcmp(s, "client") == 0) { | 198 | else if (strcmp(s, "client") == 0) { |
197 | #ifdef CONFIG_9P_FS_POSIX_ACL | ||
198 | v9ses->flags |= V9FS_ACCESS_CLIENT; | 199 | 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 { | 200 | } else { |
207 | v9ses->flags |= V9FS_ACCESS_SINGLE; | 201 | v9ses->flags |= V9FS_ACCESS_SINGLE; |
208 | v9ses->uid = simple_strtoul(s, &e, 10); | 202 | v9ses->uid = simple_strtoul(s, &e, 10); |
@@ -212,6 +206,16 @@ static int v9fs_parse_options(struct v9fs_session_info *v9ses, char *opts) | |||
212 | kfree(s); | 206 | kfree(s); |
213 | break; | 207 | break; |
214 | 208 | ||
209 | case Opt_posixacl: | ||
210 | #ifdef CONFIG_9P_FS_POSIX_ACL | ||
211 | v9ses->flags |= V9FS_POSIX_ACL; | ||
212 | #else | ||
213 | P9_DPRINTK(P9_DEBUG_ERROR, | ||
214 | "Not defined CONFIG_9P_FS_POSIX_ACL. " | ||
215 | "Ignoring posixacl option\n"); | ||
216 | #endif | ||
217 | break; | ||
218 | |||
215 | default: | 219 | default: |
216 | continue; | 220 | continue; |
217 | } | 221 | } |
@@ -260,19 +264,12 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, | |||
260 | list_add(&v9ses->slist, &v9fs_sessionlist); | 264 | list_add(&v9ses->slist, &v9fs_sessionlist); |
261 | spin_unlock(&v9fs_sessionlist_lock); | 265 | spin_unlock(&v9fs_sessionlist_lock); |
262 | 266 | ||
263 | v9ses->flags = V9FS_ACCESS_USER; | ||
264 | strcpy(v9ses->uname, V9FS_DEFUSER); | 267 | strcpy(v9ses->uname, V9FS_DEFUSER); |
265 | strcpy(v9ses->aname, V9FS_DEFANAME); | 268 | strcpy(v9ses->aname, V9FS_DEFANAME); |
266 | v9ses->uid = ~0; | 269 | v9ses->uid = ~0; |
267 | v9ses->dfltuid = V9FS_DEFUID; | 270 | v9ses->dfltuid = V9FS_DEFUID; |
268 | v9ses->dfltgid = V9FS_DEFGID; | 271 | v9ses->dfltgid = V9FS_DEFGID; |
269 | 272 | ||
270 | rc = v9fs_parse_options(v9ses, data); | ||
271 | if (rc < 0) { | ||
272 | retval = rc; | ||
273 | goto error; | ||
274 | } | ||
275 | |||
276 | v9ses->clnt = p9_client_create(dev_name, data); | 273 | v9ses->clnt = p9_client_create(dev_name, data); |
277 | if (IS_ERR(v9ses->clnt)) { | 274 | if (IS_ERR(v9ses->clnt)) { |
278 | retval = PTR_ERR(v9ses->clnt); | 275 | retval = PTR_ERR(v9ses->clnt); |
@@ -281,10 +278,20 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, | |||
281 | goto error; | 278 | goto error; |
282 | } | 279 | } |
283 | 280 | ||
284 | if (p9_is_proto_dotl(v9ses->clnt)) | 281 | v9ses->flags = V9FS_ACCESS_USER; |
282 | |||
283 | if (p9_is_proto_dotl(v9ses->clnt)) { | ||
284 | v9ses->flags = V9FS_ACCESS_CLIENT; | ||
285 | v9ses->flags |= V9FS_PROTO_2000L; | 285 | v9ses->flags |= V9FS_PROTO_2000L; |
286 | else if (p9_is_proto_dotu(v9ses->clnt)) | 286 | } else if (p9_is_proto_dotu(v9ses->clnt)) { |
287 | v9ses->flags |= V9FS_PROTO_2000U; | 287 | v9ses->flags |= V9FS_PROTO_2000U; |
288 | } | ||
289 | |||
290 | rc = v9fs_parse_options(v9ses, data); | ||
291 | if (rc < 0) { | ||
292 | retval = rc; | ||
293 | goto error; | ||
294 | } | ||
288 | 295 | ||
289 | v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ; | 296 | v9ses->maxdata = v9ses->clnt->msize - P9_IOHDRSZ; |
290 | 297 | ||
@@ -306,6 +313,14 @@ struct p9_fid *v9fs_session_init(struct v9fs_session_info *v9ses, | |||
306 | v9ses->flags |= V9FS_ACCESS_ANY; | 313 | v9ses->flags |= V9FS_ACCESS_ANY; |
307 | v9ses->uid = ~0; | 314 | v9ses->uid = ~0; |
308 | } | 315 | } |
316 | if (!v9fs_proto_dotl(v9ses) || | ||
317 | !((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_CLIENT)) { | ||
318 | /* | ||
319 | * We support ACL checks on clinet only if the protocol is | ||
320 | * 9P2000.L and access is V9FS_ACCESS_CLIENT. | ||
321 | */ | ||
322 | v9ses->flags &= ~V9FS_ACL_MASK; | ||
323 | } | ||
309 | 324 | ||
310 | fid = p9_client_attach(v9ses->clnt, NULL, v9ses->uname, ~0, | 325 | fid = p9_client_attach(v9ses->clnt, NULL, v9ses->uname, ~0, |
311 | v9ses->aname); | 326 | v9ses->aname); |
@@ -467,6 +482,63 @@ static void v9fs_sysfs_cleanup(void) | |||
467 | kobject_put(v9fs_kobj); | 482 | kobject_put(v9fs_kobj); |
468 | } | 483 | } |
469 | 484 | ||
485 | static void v9fs_inode_init_once(void *foo) | ||
486 | { | ||
487 | struct v9fs_inode *v9inode = (struct v9fs_inode *)foo; | ||
488 | #ifdef CONFIG_9P_FSCACHE | ||
489 | v9inode->fscache = NULL; | ||
490 | v9inode->fscache_key = NULL; | ||
491 | #endif | ||
492 | inode_init_once(&v9inode->vfs_inode); | ||
493 | } | ||
494 | |||
495 | /** | ||
496 | * v9fs_init_inode_cache - initialize a cache for 9P | ||
497 | * Returns 0 on success. | ||
498 | */ | ||
499 | static int v9fs_init_inode_cache(void) | ||
500 | { | ||
501 | v9fs_inode_cache = kmem_cache_create("v9fs_inode_cache", | ||
502 | sizeof(struct v9fs_inode), | ||
503 | 0, (SLAB_RECLAIM_ACCOUNT| | ||
504 | SLAB_MEM_SPREAD), | ||
505 | v9fs_inode_init_once); | ||
506 | if (!v9fs_inode_cache) | ||
507 | return -ENOMEM; | ||
508 | |||
509 | return 0; | ||
510 | } | ||
511 | |||
512 | /** | ||
513 | * v9fs_destroy_inode_cache - destroy the cache of 9P inode | ||
514 | * | ||
515 | */ | ||
516 | static void v9fs_destroy_inode_cache(void) | ||
517 | { | ||
518 | kmem_cache_destroy(v9fs_inode_cache); | ||
519 | } | ||
520 | |||
521 | static int v9fs_cache_register(void) | ||
522 | { | ||
523 | int ret; | ||
524 | ret = v9fs_init_inode_cache(); | ||
525 | if (ret < 0) | ||
526 | return ret; | ||
527 | #ifdef CONFIG_9P_FSCACHE | ||
528 | return fscache_register_netfs(&v9fs_cache_netfs); | ||
529 | #else | ||
530 | return ret; | ||
531 | #endif | ||
532 | } | ||
533 | |||
534 | static void v9fs_cache_unregister(void) | ||
535 | { | ||
536 | v9fs_destroy_inode_cache(); | ||
537 | #ifdef CONFIG_9P_FSCACHE | ||
538 | fscache_unregister_netfs(&v9fs_cache_netfs); | ||
539 | #endif | ||
540 | } | ||
541 | |||
470 | /** | 542 | /** |
471 | * init_v9fs - Initialize module | 543 | * init_v9fs - Initialize module |
472 | * | 544 | * |
diff --git a/fs/9p/v9fs.h b/fs/9p/v9fs.h index c4b5d8864f0d..bd8496db135b 100644 --- a/fs/9p/v9fs.h +++ b/fs/9p/v9fs.h | |||
@@ -20,6 +20,9 @@ | |||
20 | * Boston, MA 02111-1301 USA | 20 | * Boston, MA 02111-1301 USA |
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | #ifndef FS_9P_V9FS_H | ||
24 | #define FS_9P_V9FS_H | ||
25 | |||
23 | #include <linux/backing-dev.h> | 26 | #include <linux/backing-dev.h> |
24 | 27 | ||
25 | /** | 28 | /** |
@@ -28,8 +31,10 @@ | |||
28 | * @V9FS_PROTO_2000L: whether or not to use 9P2000.l extensions | 31 | * @V9FS_PROTO_2000L: whether or not to use 9P2000.l extensions |
29 | * @V9FS_ACCESS_SINGLE: only the mounting user can access the hierarchy | 32 | * @V9FS_ACCESS_SINGLE: only the mounting user can access the hierarchy |
30 | * @V9FS_ACCESS_USER: a new attach will be issued for every user (default) | 33 | * @V9FS_ACCESS_USER: a new attach will be issued for every user (default) |
34 | * @V9FS_ACCESS_CLIENT: Just like user, but access check is performed on client. | ||
31 | * @V9FS_ACCESS_ANY: use a single attach for all users | 35 | * @V9FS_ACCESS_ANY: use a single attach for all users |
32 | * @V9FS_ACCESS_MASK: bit mask of different ACCESS options | 36 | * @V9FS_ACCESS_MASK: bit mask of different ACCESS options |
37 | * @V9FS_POSIX_ACL: POSIX ACLs are enforced | ||
33 | * | 38 | * |
34 | * Session flags reflect options selected by users at mount time | 39 | * Session flags reflect options selected by users at mount time |
35 | */ | 40 | */ |
@@ -37,13 +42,15 @@ | |||
37 | V9FS_ACCESS_USER | \ | 42 | V9FS_ACCESS_USER | \ |
38 | V9FS_ACCESS_CLIENT) | 43 | V9FS_ACCESS_CLIENT) |
39 | #define V9FS_ACCESS_MASK V9FS_ACCESS_ANY | 44 | #define V9FS_ACCESS_MASK V9FS_ACCESS_ANY |
45 | #define V9FS_ACL_MASK V9FS_POSIX_ACL | ||
40 | 46 | ||
41 | enum p9_session_flags { | 47 | enum p9_session_flags { |
42 | V9FS_PROTO_2000U = 0x01, | 48 | V9FS_PROTO_2000U = 0x01, |
43 | V9FS_PROTO_2000L = 0x02, | 49 | V9FS_PROTO_2000L = 0x02, |
44 | V9FS_ACCESS_SINGLE = 0x04, | 50 | V9FS_ACCESS_SINGLE = 0x04, |
45 | V9FS_ACCESS_USER = 0x08, | 51 | V9FS_ACCESS_USER = 0x08, |
46 | V9FS_ACCESS_CLIENT = 0x10 | 52 | V9FS_ACCESS_CLIENT = 0x10, |
53 | V9FS_POSIX_ACL = 0x20 | ||
47 | }; | 54 | }; |
48 | 55 | ||
49 | /* possible values of ->cache */ | 56 | /* possible values of ->cache */ |
@@ -109,8 +116,28 @@ struct v9fs_session_info { | |||
109 | struct list_head slist; /* list of sessions registered with v9fs */ | 116 | struct list_head slist; /* list of sessions registered with v9fs */ |
110 | struct backing_dev_info bdi; | 117 | struct backing_dev_info bdi; |
111 | struct rw_semaphore rename_sem; | 118 | struct rw_semaphore rename_sem; |
119 | struct p9_fid *root_fid; /* Used for file system sync */ | ||
120 | }; | ||
121 | |||
122 | /* cache_validity flags */ | ||
123 | #define V9FS_INO_INVALID_ATTR 0x01 | ||
124 | |||
125 | struct v9fs_inode { | ||
126 | #ifdef CONFIG_9P_FSCACHE | ||
127 | spinlock_t fscache_lock; | ||
128 | struct fscache_cookie *fscache; | ||
129 | struct p9_qid *fscache_key; | ||
130 | #endif | ||
131 | unsigned int cache_validity; | ||
132 | struct p9_fid *writeback_fid; | ||
133 | struct inode vfs_inode; | ||
112 | }; | 134 | }; |
113 | 135 | ||
136 | static inline struct v9fs_inode *V9FS_I(const struct inode *inode) | ||
137 | { | ||
138 | return container_of(inode, struct v9fs_inode, vfs_inode); | ||
139 | } | ||
140 | |||
114 | struct p9_fid *v9fs_session_init(struct v9fs_session_info *, const char *, | 141 | struct p9_fid *v9fs_session_init(struct v9fs_session_info *, const char *, |
115 | char *); | 142 | char *); |
116 | extern void v9fs_session_close(struct v9fs_session_info *v9ses); | 143 | extern void v9fs_session_close(struct v9fs_session_info *v9ses); |
@@ -124,16 +151,15 @@ extern int v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
124 | struct inode *new_dir, struct dentry *new_dentry); | 151 | struct inode *new_dir, struct dentry *new_dentry); |
125 | extern void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, | 152 | extern void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, |
126 | void *p); | 153 | void *p); |
127 | extern struct inode *v9fs_inode(struct v9fs_session_info *v9ses, | 154 | extern struct inode *v9fs_inode_from_fid(struct v9fs_session_info *v9ses, |
128 | struct p9_fid *fid, | 155 | struct p9_fid *fid, |
129 | struct super_block *sb); | 156 | struct super_block *sb); |
130 | |||
131 | extern const struct inode_operations v9fs_dir_inode_operations_dotl; | 157 | extern const struct inode_operations v9fs_dir_inode_operations_dotl; |
132 | extern const struct inode_operations v9fs_file_inode_operations_dotl; | 158 | extern const struct inode_operations v9fs_file_inode_operations_dotl; |
133 | extern const struct inode_operations v9fs_symlink_inode_operations_dotl; | 159 | extern const struct inode_operations v9fs_symlink_inode_operations_dotl; |
134 | extern struct inode *v9fs_inode_dotl(struct v9fs_session_info *v9ses, | 160 | extern struct inode *v9fs_inode_from_fid_dotl(struct v9fs_session_info *v9ses, |
135 | struct p9_fid *fid, | 161 | struct p9_fid *fid, |
136 | struct super_block *sb); | 162 | struct super_block *sb); |
137 | 163 | ||
138 | /* other default globals */ | 164 | /* other default globals */ |
139 | #define V9FS_PORT 564 | 165 | #define V9FS_PORT 564 |
@@ -158,7 +184,7 @@ static inline int v9fs_proto_dotl(struct v9fs_session_info *v9ses) | |||
158 | } | 184 | } |
159 | 185 | ||
160 | /** | 186 | /** |
161 | * v9fs_inode_from_fid - Helper routine to populate an inode by | 187 | * v9fs_get_inode_from_fid - Helper routine to populate an inode by |
162 | * issuing a attribute request | 188 | * issuing a attribute request |
163 | * @v9ses: session information | 189 | * @v9ses: session information |
164 | * @fid: fid to issue attribute request for | 190 | * @fid: fid to issue attribute request for |
@@ -166,11 +192,12 @@ static inline int v9fs_proto_dotl(struct v9fs_session_info *v9ses) | |||
166 | * | 192 | * |
167 | */ | 193 | */ |
168 | static inline struct inode * | 194 | static inline struct inode * |
169 | v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid, | 195 | v9fs_get_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid, |
170 | struct super_block *sb) | 196 | struct super_block *sb) |
171 | { | 197 | { |
172 | if (v9fs_proto_dotl(v9ses)) | 198 | if (v9fs_proto_dotl(v9ses)) |
173 | return v9fs_inode_dotl(v9ses, fid, sb); | 199 | return v9fs_inode_from_fid_dotl(v9ses, fid, sb); |
174 | else | 200 | else |
175 | return v9fs_inode(v9ses, fid, sb); | 201 | return v9fs_inode_from_fid(v9ses, fid, sb); |
176 | } | 202 | } |
203 | #endif | ||
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h index b789f8e597ec..4014160903a9 100644 --- a/fs/9p/v9fs_vfs.h +++ b/fs/9p/v9fs_vfs.h | |||
@@ -20,6 +20,8 @@ | |||
20 | * Boston, MA 02111-1301 USA | 20 | * Boston, MA 02111-1301 USA |
21 | * | 21 | * |
22 | */ | 22 | */ |
23 | #ifndef FS_9P_V9FS_VFS_H | ||
24 | #define FS_9P_V9FS_VFS_H | ||
23 | 25 | ||
24 | /* plan9 semantics are that created files are implicitly opened. | 26 | /* plan9 semantics are that created files are implicitly opened. |
25 | * But linux semantics are that you call create, then open. | 27 | * But linux semantics are that you call create, then open. |
@@ -36,6 +38,7 @@ | |||
36 | * unlink calls remove, which is an implicit clunk. So we have to track | 38 | * unlink calls remove, which is an implicit clunk. So we have to track |
37 | * that kind of thing so that we don't try to clunk a dead fid. | 39 | * that kind of thing so that we don't try to clunk a dead fid. |
38 | */ | 40 | */ |
41 | #define P9_LOCK_TIMEOUT (30*HZ) | ||
39 | 42 | ||
40 | extern struct file_system_type v9fs_fs_type; | 43 | extern struct file_system_type v9fs_fs_type; |
41 | extern const struct address_space_operations v9fs_addr_operations; | 44 | extern const struct address_space_operations v9fs_addr_operations; |
@@ -45,13 +48,15 @@ extern const struct file_operations v9fs_dir_operations; | |||
45 | extern const struct file_operations v9fs_dir_operations_dotl; | 48 | extern const struct file_operations v9fs_dir_operations_dotl; |
46 | extern const struct dentry_operations v9fs_dentry_operations; | 49 | extern const struct dentry_operations v9fs_dentry_operations; |
47 | extern const struct dentry_operations v9fs_cached_dentry_operations; | 50 | extern const struct dentry_operations v9fs_cached_dentry_operations; |
51 | extern const struct file_operations v9fs_cached_file_operations; | ||
52 | extern const struct file_operations v9fs_cached_file_operations_dotl; | ||
53 | extern struct kmem_cache *v9fs_inode_cache; | ||
48 | 54 | ||
49 | #ifdef CONFIG_9P_FSCACHE | ||
50 | struct inode *v9fs_alloc_inode(struct super_block *sb); | 55 | struct inode *v9fs_alloc_inode(struct super_block *sb); |
51 | void v9fs_destroy_inode(struct inode *inode); | 56 | void v9fs_destroy_inode(struct inode *inode); |
52 | #endif | ||
53 | |||
54 | struct inode *v9fs_get_inode(struct super_block *sb, int mode); | 57 | struct inode *v9fs_get_inode(struct super_block *sb, int mode); |
58 | int v9fs_init_inode(struct v9fs_session_info *v9ses, | ||
59 | struct inode *inode, int mode); | ||
55 | void v9fs_evict_inode(struct inode *inode); | 60 | void v9fs_evict_inode(struct inode *inode); |
56 | ino_t v9fs_qid2ino(struct p9_qid *qid); | 61 | ino_t v9fs_qid2ino(struct p9_qid *qid); |
57 | void v9fs_stat2inode(struct p9_wstat *, struct inode *, struct super_block *); | 62 | void v9fs_stat2inode(struct p9_wstat *, struct inode *, struct super_block *); |
@@ -62,8 +67,19 @@ void v9fs_inode2stat(struct inode *inode, struct p9_wstat *stat); | |||
62 | int v9fs_uflags2omode(int uflags, int extended); | 67 | int v9fs_uflags2omode(int uflags, int extended); |
63 | 68 | ||
64 | ssize_t v9fs_file_readn(struct file *, char *, char __user *, u32, u64); | 69 | ssize_t v9fs_file_readn(struct file *, char *, char __user *, u32, u64); |
70 | ssize_t v9fs_fid_readn(struct p9_fid *, char *, char __user *, u32, u64); | ||
65 | void v9fs_blank_wstat(struct p9_wstat *wstat); | 71 | void v9fs_blank_wstat(struct p9_wstat *wstat); |
66 | int v9fs_vfs_setattr_dotl(struct dentry *, struct iattr *); | 72 | int v9fs_vfs_setattr_dotl(struct dentry *, struct iattr *); |
67 | int v9fs_file_fsync_dotl(struct file *filp, int datasync); | 73 | int v9fs_file_fsync_dotl(struct file *filp, int datasync); |
68 | 74 | ssize_t v9fs_file_write_internal(struct inode *, struct p9_fid *, | |
69 | #define P9_LOCK_TIMEOUT (30*HZ) | 75 | const char __user *, size_t, loff_t *, int); |
76 | int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode); | ||
77 | int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode); | ||
78 | static inline void v9fs_invalidate_inode_attr(struct inode *inode) | ||
79 | { | ||
80 | struct v9fs_inode *v9inode; | ||
81 | v9inode = V9FS_I(inode); | ||
82 | v9inode->cache_validity |= V9FS_INO_INVALID_ATTR; | ||
83 | return; | ||
84 | } | ||
85 | #endif | ||
diff --git a/fs/9p/vfs_addr.c b/fs/9p/vfs_addr.c index b7f2a8e3863e..2524e4cbb8ea 100644 --- a/fs/9p/vfs_addr.c +++ b/fs/9p/vfs_addr.c | |||
@@ -39,16 +39,16 @@ | |||
39 | #include "v9fs.h" | 39 | #include "v9fs.h" |
40 | #include "v9fs_vfs.h" | 40 | #include "v9fs_vfs.h" |
41 | #include "cache.h" | 41 | #include "cache.h" |
42 | #include "fid.h" | ||
42 | 43 | ||
43 | /** | 44 | /** |
44 | * v9fs_vfs_readpage - read an entire page in from 9P | 45 | * v9fs_fid_readpage - read an entire page in from 9P |
45 | * | 46 | * |
46 | * @filp: file being read | 47 | * @fid: fid being read |
47 | * @page: structure to page | 48 | * @page: structure to page |
48 | * | 49 | * |
49 | */ | 50 | */ |
50 | 51 | static int v9fs_fid_readpage(struct p9_fid *fid, struct page *page) | |
51 | static int v9fs_vfs_readpage(struct file *filp, struct page *page) | ||
52 | { | 52 | { |
53 | int retval; | 53 | int retval; |
54 | loff_t offset; | 54 | loff_t offset; |
@@ -67,7 +67,7 @@ static int v9fs_vfs_readpage(struct file *filp, struct page *page) | |||
67 | buffer = kmap(page); | 67 | buffer = kmap(page); |
68 | offset = page_offset(page); | 68 | offset = page_offset(page); |
69 | 69 | ||
70 | retval = v9fs_file_readn(filp, buffer, NULL, PAGE_CACHE_SIZE, offset); | 70 | retval = v9fs_fid_readn(fid, buffer, NULL, PAGE_CACHE_SIZE, offset); |
71 | if (retval < 0) { | 71 | if (retval < 0) { |
72 | v9fs_uncache_page(inode, page); | 72 | v9fs_uncache_page(inode, page); |
73 | goto done; | 73 | goto done; |
@@ -87,6 +87,19 @@ done: | |||
87 | } | 87 | } |
88 | 88 | ||
89 | /** | 89 | /** |
90 | * v9fs_vfs_readpage - read an entire page in from 9P | ||
91 | * | ||
92 | * @filp: file being read | ||
93 | * @page: structure to page | ||
94 | * | ||
95 | */ | ||
96 | |||
97 | static int v9fs_vfs_readpage(struct file *filp, struct page *page) | ||
98 | { | ||
99 | return v9fs_fid_readpage(filp->private_data, page); | ||
100 | } | ||
101 | |||
102 | /** | ||
90 | * v9fs_vfs_readpages - read a set of pages from 9P | 103 | * v9fs_vfs_readpages - read a set of pages from 9P |
91 | * | 104 | * |
92 | * @filp: file being read | 105 | * @filp: file being read |
@@ -124,7 +137,6 @@ static int v9fs_release_page(struct page *page, gfp_t gfp) | |||
124 | { | 137 | { |
125 | if (PagePrivate(page)) | 138 | if (PagePrivate(page)) |
126 | return 0; | 139 | return 0; |
127 | |||
128 | return v9fs_fscache_release_page(page, gfp); | 140 | return v9fs_fscache_release_page(page, gfp); |
129 | } | 141 | } |
130 | 142 | ||
@@ -137,20 +149,89 @@ static int v9fs_release_page(struct page *page, gfp_t gfp) | |||
137 | 149 | ||
138 | static void v9fs_invalidate_page(struct page *page, unsigned long offset) | 150 | static void v9fs_invalidate_page(struct page *page, unsigned long offset) |
139 | { | 151 | { |
152 | /* | ||
153 | * If called with zero offset, we should release | ||
154 | * the private state assocated with the page | ||
155 | */ | ||
140 | if (offset == 0) | 156 | if (offset == 0) |
141 | v9fs_fscache_invalidate_page(page); | 157 | v9fs_fscache_invalidate_page(page); |
142 | } | 158 | } |
143 | 159 | ||
160 | static int v9fs_vfs_writepage_locked(struct page *page) | ||
161 | { | ||
162 | char *buffer; | ||
163 | int retval, len; | ||
164 | loff_t offset, size; | ||
165 | mm_segment_t old_fs; | ||
166 | struct v9fs_inode *v9inode; | ||
167 | struct inode *inode = page->mapping->host; | ||
168 | |||
169 | v9inode = V9FS_I(inode); | ||
170 | size = i_size_read(inode); | ||
171 | if (page->index == size >> PAGE_CACHE_SHIFT) | ||
172 | len = size & ~PAGE_CACHE_MASK; | ||
173 | else | ||
174 | len = PAGE_CACHE_SIZE; | ||
175 | |||
176 | set_page_writeback(page); | ||
177 | |||
178 | buffer = kmap(page); | ||
179 | offset = page_offset(page); | ||
180 | |||
181 | old_fs = get_fs(); | ||
182 | set_fs(get_ds()); | ||
183 | /* We should have writeback_fid always set */ | ||
184 | BUG_ON(!v9inode->writeback_fid); | ||
185 | |||
186 | retval = v9fs_file_write_internal(inode, | ||
187 | v9inode->writeback_fid, | ||
188 | (__force const char __user *)buffer, | ||
189 | len, &offset, 0); | ||
190 | if (retval > 0) | ||
191 | retval = 0; | ||
192 | |||
193 | set_fs(old_fs); | ||
194 | kunmap(page); | ||
195 | end_page_writeback(page); | ||
196 | return retval; | ||
197 | } | ||
198 | |||
199 | static int v9fs_vfs_writepage(struct page *page, struct writeback_control *wbc) | ||
200 | { | ||
201 | int retval; | ||
202 | |||
203 | retval = v9fs_vfs_writepage_locked(page); | ||
204 | if (retval < 0) { | ||
205 | if (retval == -EAGAIN) { | ||
206 | redirty_page_for_writepage(wbc, page); | ||
207 | retval = 0; | ||
208 | } else { | ||
209 | SetPageError(page); | ||
210 | mapping_set_error(page->mapping, retval); | ||
211 | } | ||
212 | } else | ||
213 | retval = 0; | ||
214 | |||
215 | unlock_page(page); | ||
216 | return retval; | ||
217 | } | ||
218 | |||
144 | /** | 219 | /** |
145 | * v9fs_launder_page - Writeback a dirty page | 220 | * v9fs_launder_page - Writeback a dirty page |
146 | * Since the writes go directly to the server, we simply return a 0 | ||
147 | * here to indicate success. | ||
148 | * | ||
149 | * Returns 0 on success. | 221 | * Returns 0 on success. |
150 | */ | 222 | */ |
151 | 223 | ||
152 | static int v9fs_launder_page(struct page *page) | 224 | static int v9fs_launder_page(struct page *page) |
153 | { | 225 | { |
226 | int retval; | ||
227 | struct inode *inode = page->mapping->host; | ||
228 | |||
229 | v9fs_fscache_wait_on_page_write(inode, page); | ||
230 | if (clear_page_dirty_for_io(page)) { | ||
231 | retval = v9fs_vfs_writepage_locked(page); | ||
232 | if (retval) | ||
233 | return retval; | ||
234 | } | ||
154 | return 0; | 235 | return 0; |
155 | } | 236 | } |
156 | 237 | ||
@@ -173,9 +254,15 @@ static int v9fs_launder_page(struct page *page) | |||
173 | * with an error. | 254 | * with an error. |
174 | * | 255 | * |
175 | */ | 256 | */ |
176 | ssize_t v9fs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, | 257 | static ssize_t |
177 | loff_t pos, unsigned long nr_segs) | 258 | v9fs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, |
259 | loff_t pos, unsigned long nr_segs) | ||
178 | { | 260 | { |
261 | /* | ||
262 | * FIXME | ||
263 | * Now that we do caching with cache mode enabled, We need | ||
264 | * to support direct IO | ||
265 | */ | ||
179 | P9_DPRINTK(P9_DEBUG_VFS, "v9fs_direct_IO: v9fs_direct_IO (%s) " | 266 | P9_DPRINTK(P9_DEBUG_VFS, "v9fs_direct_IO: v9fs_direct_IO (%s) " |
180 | "off/no(%lld/%lu) EINVAL\n", | 267 | "off/no(%lld/%lu) EINVAL\n", |
181 | iocb->ki_filp->f_path.dentry->d_name.name, | 268 | iocb->ki_filp->f_path.dentry->d_name.name, |
@@ -183,11 +270,84 @@ ssize_t v9fs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, | |||
183 | 270 | ||
184 | return -EINVAL; | 271 | return -EINVAL; |
185 | } | 272 | } |
273 | |||
274 | static int v9fs_write_begin(struct file *filp, struct address_space *mapping, | ||
275 | loff_t pos, unsigned len, unsigned flags, | ||
276 | struct page **pagep, void **fsdata) | ||
277 | { | ||
278 | int retval = 0; | ||
279 | struct page *page; | ||
280 | struct v9fs_inode *v9inode; | ||
281 | pgoff_t index = pos >> PAGE_CACHE_SHIFT; | ||
282 | struct inode *inode = mapping->host; | ||
283 | |||
284 | v9inode = V9FS_I(inode); | ||
285 | start: | ||
286 | page = grab_cache_page_write_begin(mapping, index, flags); | ||
287 | if (!page) { | ||
288 | retval = -ENOMEM; | ||
289 | goto out; | ||
290 | } | ||
291 | BUG_ON(!v9inode->writeback_fid); | ||
292 | if (PageUptodate(page)) | ||
293 | goto out; | ||
294 | |||
295 | if (len == PAGE_CACHE_SIZE) | ||
296 | goto out; | ||
297 | |||
298 | retval = v9fs_fid_readpage(v9inode->writeback_fid, page); | ||
299 | page_cache_release(page); | ||
300 | if (!retval) | ||
301 | goto start; | ||
302 | out: | ||
303 | *pagep = page; | ||
304 | return retval; | ||
305 | } | ||
306 | |||
307 | static int v9fs_write_end(struct file *filp, struct address_space *mapping, | ||
308 | loff_t pos, unsigned len, unsigned copied, | ||
309 | struct page *page, void *fsdata) | ||
310 | { | ||
311 | loff_t last_pos = pos + copied; | ||
312 | struct inode *inode = page->mapping->host; | ||
313 | |||
314 | if (unlikely(copied < len)) { | ||
315 | /* | ||
316 | * zero out the rest of the area | ||
317 | */ | ||
318 | unsigned from = pos & (PAGE_CACHE_SIZE - 1); | ||
319 | |||
320 | zero_user(page, from + copied, len - copied); | ||
321 | flush_dcache_page(page); | ||
322 | } | ||
323 | |||
324 | if (!PageUptodate(page)) | ||
325 | SetPageUptodate(page); | ||
326 | /* | ||
327 | * No need to use i_size_read() here, the i_size | ||
328 | * cannot change under us because we hold the i_mutex. | ||
329 | */ | ||
330 | if (last_pos > inode->i_size) { | ||
331 | inode_add_bytes(inode, last_pos - inode->i_size); | ||
332 | i_size_write(inode, last_pos); | ||
333 | } | ||
334 | set_page_dirty(page); | ||
335 | unlock_page(page); | ||
336 | page_cache_release(page); | ||
337 | |||
338 | return copied; | ||
339 | } | ||
340 | |||
341 | |||
186 | const struct address_space_operations v9fs_addr_operations = { | 342 | const struct address_space_operations v9fs_addr_operations = { |
187 | .readpage = v9fs_vfs_readpage, | 343 | .readpage = v9fs_vfs_readpage, |
188 | .readpages = v9fs_vfs_readpages, | 344 | .readpages = v9fs_vfs_readpages, |
189 | .releasepage = v9fs_release_page, | 345 | .set_page_dirty = __set_page_dirty_nobuffers, |
190 | .invalidatepage = v9fs_invalidate_page, | 346 | .writepage = v9fs_vfs_writepage, |
191 | .launder_page = v9fs_launder_page, | 347 | .write_begin = v9fs_write_begin, |
192 | .direct_IO = v9fs_direct_IO, | 348 | .write_end = v9fs_write_end, |
349 | .releasepage = v9fs_release_page, | ||
350 | .invalidatepage = v9fs_invalidate_page, | ||
351 | .launder_page = v9fs_launder_page, | ||
352 | .direct_IO = v9fs_direct_IO, | ||
193 | }; | 353 | }; |
diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c index 233b7d4ffe5e..b6a3b9f7fe4d 100644 --- a/fs/9p/vfs_dentry.c +++ b/fs/9p/vfs_dentry.c | |||
@@ -63,20 +63,15 @@ static int v9fs_dentry_delete(const struct dentry *dentry) | |||
63 | * v9fs_cached_dentry_delete - called when dentry refcount equals 0 | 63 | * v9fs_cached_dentry_delete - called when dentry refcount equals 0 |
64 | * @dentry: dentry in question | 64 | * @dentry: dentry in question |
65 | * | 65 | * |
66 | * Only return 1 if our inode is invalid. Only non-synthetic files | ||
67 | * (ones without mtime == 0) should be calling this function. | ||
68 | * | ||
69 | */ | 66 | */ |
70 | |||
71 | static int v9fs_cached_dentry_delete(const struct dentry *dentry) | 67 | static int v9fs_cached_dentry_delete(const struct dentry *dentry) |
72 | { | 68 | { |
73 | struct inode *inode = dentry->d_inode; | 69 | P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", |
74 | P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_name.name, | 70 | dentry->d_name.name, dentry); |
75 | dentry); | ||
76 | 71 | ||
77 | if(!inode) | 72 | /* Don't cache negative dentries */ |
73 | if (!dentry->d_inode) | ||
78 | return 1; | 74 | return 1; |
79 | |||
80 | return 0; | 75 | return 0; |
81 | } | 76 | } |
82 | 77 | ||
@@ -105,7 +100,41 @@ static void v9fs_dentry_release(struct dentry *dentry) | |||
105 | } | 100 | } |
106 | } | 101 | } |
107 | 102 | ||
103 | static int v9fs_lookup_revalidate(struct dentry *dentry, struct nameidata *nd) | ||
104 | { | ||
105 | struct p9_fid *fid; | ||
106 | struct inode *inode; | ||
107 | struct v9fs_inode *v9inode; | ||
108 | |||
109 | if (nd->flags & LOOKUP_RCU) | ||
110 | return -ECHILD; | ||
111 | |||
112 | inode = dentry->d_inode; | ||
113 | if (!inode) | ||
114 | goto out_valid; | ||
115 | |||
116 | v9inode = V9FS_I(inode); | ||
117 | if (v9inode->cache_validity & V9FS_INO_INVALID_ATTR) { | ||
118 | int retval; | ||
119 | struct v9fs_session_info *v9ses; | ||
120 | fid = v9fs_fid_lookup(dentry); | ||
121 | if (IS_ERR(fid)) | ||
122 | return PTR_ERR(fid); | ||
123 | |||
124 | v9ses = v9fs_inode2v9ses(inode); | ||
125 | if (v9fs_proto_dotl(v9ses)) | ||
126 | retval = v9fs_refresh_inode_dotl(fid, inode); | ||
127 | else | ||
128 | retval = v9fs_refresh_inode(fid, inode); | ||
129 | if (retval <= 0) | ||
130 | return retval; | ||
131 | } | ||
132 | out_valid: | ||
133 | return 1; | ||
134 | } | ||
135 | |||
108 | const struct dentry_operations v9fs_cached_dentry_operations = { | 136 | const struct dentry_operations v9fs_cached_dentry_operations = { |
137 | .d_revalidate = v9fs_lookup_revalidate, | ||
109 | .d_delete = v9fs_cached_dentry_delete, | 138 | .d_delete = v9fs_cached_dentry_delete, |
110 | .d_release = v9fs_dentry_release, | 139 | .d_release = v9fs_dentry_release, |
111 | }; | 140 | }; |
diff --git a/fs/9p/vfs_dir.c b/fs/9p/vfs_dir.c index b84ebe8cefed..9c2bdda5cd9d 100644 --- a/fs/9p/vfs_dir.c +++ b/fs/9p/vfs_dir.c | |||
@@ -295,7 +295,6 @@ int v9fs_dir_release(struct inode *inode, struct file *filp) | |||
295 | P9_DPRINTK(P9_DEBUG_VFS, | 295 | P9_DPRINTK(P9_DEBUG_VFS, |
296 | "v9fs_dir_release: inode: %p filp: %p fid: %d\n", | 296 | "v9fs_dir_release: inode: %p filp: %p fid: %d\n", |
297 | inode, filp, fid ? fid->fid : -1); | 297 | inode, filp, fid ? fid->fid : -1); |
298 | filemap_write_and_wait(inode->i_mapping); | ||
299 | if (fid) | 298 | if (fid) |
300 | p9_client_clunk(fid); | 299 | p9_client_clunk(fid); |
301 | return 0; | 300 | return 0; |
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index 240c30674396..78bcb97c3425 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c | |||
@@ -44,8 +44,7 @@ | |||
44 | #include "fid.h" | 44 | #include "fid.h" |
45 | #include "cache.h" | 45 | #include "cache.h" |
46 | 46 | ||
47 | static const struct file_operations v9fs_cached_file_operations; | 47 | static const struct vm_operations_struct v9fs_file_vm_ops; |
48 | static const struct file_operations v9fs_cached_file_operations_dotl; | ||
49 | 48 | ||
50 | /** | 49 | /** |
51 | * v9fs_file_open - open a file (or directory) | 50 | * v9fs_file_open - open a file (or directory) |
@@ -57,11 +56,13 @@ static const struct file_operations v9fs_cached_file_operations_dotl; | |||
57 | int v9fs_file_open(struct inode *inode, struct file *file) | 56 | int v9fs_file_open(struct inode *inode, struct file *file) |
58 | { | 57 | { |
59 | int err; | 58 | int err; |
59 | struct v9fs_inode *v9inode; | ||
60 | struct v9fs_session_info *v9ses; | 60 | struct v9fs_session_info *v9ses; |
61 | struct p9_fid *fid; | 61 | struct p9_fid *fid; |
62 | int omode; | 62 | int omode; |
63 | 63 | ||
64 | P9_DPRINTK(P9_DEBUG_VFS, "inode: %p file: %p\n", inode, file); | 64 | P9_DPRINTK(P9_DEBUG_VFS, "inode: %p file: %p\n", inode, file); |
65 | v9inode = V9FS_I(inode); | ||
65 | v9ses = v9fs_inode2v9ses(inode); | 66 | v9ses = v9fs_inode2v9ses(inode); |
66 | if (v9fs_proto_dotl(v9ses)) | 67 | if (v9fs_proto_dotl(v9ses)) |
67 | omode = file->f_flags; | 68 | omode = file->f_flags; |
@@ -89,20 +90,30 @@ int v9fs_file_open(struct inode *inode, struct file *file) | |||
89 | } | 90 | } |
90 | 91 | ||
91 | file->private_data = fid; | 92 | file->private_data = fid; |
92 | if ((fid->qid.version) && (v9ses->cache)) { | 93 | if (v9ses->cache && !v9inode->writeback_fid) { |
93 | P9_DPRINTK(P9_DEBUG_VFS, "cached"); | 94 | /* |
94 | /* enable cached file options */ | 95 | * clone a fid and add it to writeback_fid |
95 | if(file->f_op == &v9fs_file_operations) | 96 | * we do it during open time instead of |
96 | file->f_op = &v9fs_cached_file_operations; | 97 | * page dirty time via write_begin/page_mkwrite |
97 | else if (file->f_op == &v9fs_file_operations_dotl) | 98 | * because we want write after unlink usecase |
98 | file->f_op = &v9fs_cached_file_operations_dotl; | 99 | * to work. |
99 | 100 | */ | |
101 | fid = v9fs_writeback_fid(file->f_path.dentry); | ||
102 | if (IS_ERR(fid)) { | ||
103 | err = PTR_ERR(fid); | ||
104 | goto out_error; | ||
105 | } | ||
106 | v9inode->writeback_fid = (void *) fid; | ||
107 | } | ||
100 | #ifdef CONFIG_9P_FSCACHE | 108 | #ifdef CONFIG_9P_FSCACHE |
109 | if (v9ses->cache) | ||
101 | v9fs_cache_inode_set_cookie(inode, file); | 110 | v9fs_cache_inode_set_cookie(inode, file); |
102 | #endif | 111 | #endif |
103 | } | ||
104 | |||
105 | return 0; | 112 | return 0; |
113 | out_error: | ||
114 | p9_client_clunk(file->private_data); | ||
115 | file->private_data = NULL; | ||
116 | return err; | ||
106 | } | 117 | } |
107 | 118 | ||
108 | /** | 119 | /** |
@@ -335,25 +346,22 @@ out_err: | |||
335 | } | 346 | } |
336 | 347 | ||
337 | /** | 348 | /** |
338 | * v9fs_file_readn - read from a file | 349 | * v9fs_fid_readn - read from a fid |
339 | * @filp: file pointer to read | 350 | * @fid: fid to read |
340 | * @data: data buffer to read data into | 351 | * @data: data buffer to read data into |
341 | * @udata: user data buffer to read data into | 352 | * @udata: user data buffer to read data into |
342 | * @count: size of buffer | 353 | * @count: size of buffer |
343 | * @offset: offset at which to read data | 354 | * @offset: offset at which to read data |
344 | * | 355 | * |
345 | */ | 356 | */ |
346 | |||
347 | ssize_t | 357 | ssize_t |
348 | v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count, | 358 | v9fs_fid_readn(struct p9_fid *fid, char *data, char __user *udata, u32 count, |
349 | u64 offset) | 359 | u64 offset) |
350 | { | 360 | { |
351 | int n, total, size; | 361 | int n, total, size; |
352 | struct p9_fid *fid = filp->private_data; | ||
353 | 362 | ||
354 | P9_DPRINTK(P9_DEBUG_VFS, "fid %d offset %llu count %d\n", fid->fid, | 363 | P9_DPRINTK(P9_DEBUG_VFS, "fid %d offset %llu count %d\n", fid->fid, |
355 | (long long unsigned) offset, count); | 364 | (long long unsigned) offset, count); |
356 | |||
357 | n = 0; | 365 | n = 0; |
358 | total = 0; | 366 | total = 0; |
359 | size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ; | 367 | size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ; |
@@ -379,6 +387,22 @@ v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count, | |||
379 | } | 387 | } |
380 | 388 | ||
381 | /** | 389 | /** |
390 | * v9fs_file_readn - read from a file | ||
391 | * @filp: file pointer to read | ||
392 | * @data: data buffer to read data into | ||
393 | * @udata: user data buffer to read data into | ||
394 | * @count: size of buffer | ||
395 | * @offset: offset at which to read data | ||
396 | * | ||
397 | */ | ||
398 | ssize_t | ||
399 | v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count, | ||
400 | u64 offset) | ||
401 | { | ||
402 | return v9fs_fid_readn(filp->private_data, data, udata, count, offset); | ||
403 | } | ||
404 | |||
405 | /** | ||
382 | * v9fs_file_read - read from a file | 406 | * v9fs_file_read - read from a file |
383 | * @filp: file pointer to read | 407 | * @filp: file pointer to read |
384 | * @udata: user data buffer to read data into | 408 | * @udata: user data buffer to read data into |
@@ -410,45 +434,22 @@ v9fs_file_read(struct file *filp, char __user *udata, size_t count, | |||
410 | return ret; | 434 | return ret; |
411 | } | 435 | } |
412 | 436 | ||
413 | /** | 437 | ssize_t |
414 | * v9fs_file_write - write to a file | 438 | v9fs_file_write_internal(struct inode *inode, struct p9_fid *fid, |
415 | * @filp: file pointer to write | 439 | const char __user *data, size_t count, |
416 | * @data: data buffer to write data from | 440 | loff_t *offset, int invalidate) |
417 | * @count: size of buffer | ||
418 | * @offset: offset at which to write data | ||
419 | * | ||
420 | */ | ||
421 | |||
422 | static ssize_t | ||
423 | v9fs_file_write(struct file *filp, const char __user * data, | ||
424 | size_t count, loff_t * offset) | ||
425 | { | 441 | { |
426 | ssize_t retval; | ||
427 | size_t total = 0; | ||
428 | int n; | 442 | int n; |
429 | struct p9_fid *fid; | 443 | loff_t i_size; |
444 | size_t total = 0; | ||
430 | struct p9_client *clnt; | 445 | struct p9_client *clnt; |
431 | struct inode *inode = filp->f_path.dentry->d_inode; | ||
432 | loff_t origin = *offset; | 446 | loff_t origin = *offset; |
433 | unsigned long pg_start, pg_end; | 447 | unsigned long pg_start, pg_end; |
434 | 448 | ||
435 | P9_DPRINTK(P9_DEBUG_VFS, "data %p count %d offset %x\n", data, | 449 | P9_DPRINTK(P9_DEBUG_VFS, "data %p count %d offset %x\n", data, |
436 | (int)count, (int)*offset); | 450 | (int)count, (int)*offset); |
437 | 451 | ||
438 | fid = filp->private_data; | ||
439 | clnt = fid->clnt; | 452 | clnt = fid->clnt; |
440 | |||
441 | retval = generic_write_checks(filp, &origin, &count, 0); | ||
442 | if (retval) | ||
443 | goto out; | ||
444 | |||
445 | retval = -EINVAL; | ||
446 | if ((ssize_t) count < 0) | ||
447 | goto out; | ||
448 | retval = 0; | ||
449 | if (!count) | ||
450 | goto out; | ||
451 | |||
452 | do { | 453 | do { |
453 | n = p9_client_write(fid, NULL, data+total, origin+total, count); | 454 | n = p9_client_write(fid, NULL, data+total, origin+total, count); |
454 | if (n <= 0) | 455 | if (n <= 0) |
@@ -457,25 +458,60 @@ v9fs_file_write(struct file *filp, const char __user * data, | |||
457 | total += n; | 458 | total += n; |
458 | } while (count > 0); | 459 | } while (count > 0); |
459 | 460 | ||
460 | if (total > 0) { | 461 | if (invalidate && (total > 0)) { |
461 | pg_start = origin >> PAGE_CACHE_SHIFT; | 462 | pg_start = origin >> PAGE_CACHE_SHIFT; |
462 | pg_end = (origin + total - 1) >> PAGE_CACHE_SHIFT; | 463 | pg_end = (origin + total - 1) >> PAGE_CACHE_SHIFT; |
463 | if (inode->i_mapping && inode->i_mapping->nrpages) | 464 | if (inode->i_mapping && inode->i_mapping->nrpages) |
464 | invalidate_inode_pages2_range(inode->i_mapping, | 465 | invalidate_inode_pages2_range(inode->i_mapping, |
465 | pg_start, pg_end); | 466 | pg_start, pg_end); |
466 | *offset += total; | 467 | *offset += total; |
467 | i_size_write(inode, i_size_read(inode) + total); | 468 | i_size = i_size_read(inode); |
468 | inode->i_blocks = (i_size_read(inode) + 512 - 1) >> 9; | 469 | if (*offset > i_size) { |
470 | inode_add_bytes(inode, *offset - i_size); | ||
471 | i_size_write(inode, *offset); | ||
472 | } | ||
469 | } | 473 | } |
470 | |||
471 | if (n < 0) | 474 | if (n < 0) |
472 | retval = n; | 475 | return n; |
473 | else | 476 | |
474 | retval = total; | 477 | return total; |
478 | } | ||
479 | |||
480 | /** | ||
481 | * v9fs_file_write - write to a file | ||
482 | * @filp: file pointer to write | ||
483 | * @data: data buffer to write data from | ||
484 | * @count: size of buffer | ||
485 | * @offset: offset at which to write data | ||
486 | * | ||
487 | */ | ||
488 | static ssize_t | ||
489 | v9fs_file_write(struct file *filp, const char __user * data, | ||
490 | size_t count, loff_t *offset) | ||
491 | { | ||
492 | ssize_t retval = 0; | ||
493 | loff_t origin = *offset; | ||
494 | |||
495 | |||
496 | retval = generic_write_checks(filp, &origin, &count, 0); | ||
497 | if (retval) | ||
498 | goto out; | ||
499 | |||
500 | retval = -EINVAL; | ||
501 | if ((ssize_t) count < 0) | ||
502 | goto out; | ||
503 | retval = 0; | ||
504 | if (!count) | ||
505 | goto out; | ||
506 | |||
507 | return v9fs_file_write_internal(filp->f_path.dentry->d_inode, | ||
508 | filp->private_data, | ||
509 | data, count, offset, 1); | ||
475 | out: | 510 | out: |
476 | return retval; | 511 | return retval; |
477 | } | 512 | } |
478 | 513 | ||
514 | |||
479 | static int v9fs_file_fsync(struct file *filp, int datasync) | 515 | static int v9fs_file_fsync(struct file *filp, int datasync) |
480 | { | 516 | { |
481 | struct p9_fid *fid; | 517 | struct p9_fid *fid; |
@@ -505,28 +541,182 @@ int v9fs_file_fsync_dotl(struct file *filp, int datasync) | |||
505 | return retval; | 541 | return retval; |
506 | } | 542 | } |
507 | 543 | ||
508 | static const struct file_operations v9fs_cached_file_operations = { | 544 | static int |
545 | v9fs_file_mmap(struct file *file, struct vm_area_struct *vma) | ||
546 | { | ||
547 | int retval; | ||
548 | |||
549 | retval = generic_file_mmap(file, vma); | ||
550 | if (!retval) | ||
551 | vma->vm_ops = &v9fs_file_vm_ops; | ||
552 | |||
553 | return retval; | ||
554 | } | ||
555 | |||
556 | static int | ||
557 | v9fs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) | ||
558 | { | ||
559 | struct v9fs_inode *v9inode; | ||
560 | struct page *page = vmf->page; | ||
561 | struct file *filp = vma->vm_file; | ||
562 | struct inode *inode = filp->f_path.dentry->d_inode; | ||
563 | |||
564 | |||
565 | P9_DPRINTK(P9_DEBUG_VFS, "page %p fid %lx\n", | ||
566 | page, (unsigned long)filp->private_data); | ||
567 | |||
568 | v9inode = V9FS_I(inode); | ||
569 | /* make sure the cache has finished storing the page */ | ||
570 | v9fs_fscache_wait_on_page_write(inode, page); | ||
571 | BUG_ON(!v9inode->writeback_fid); | ||
572 | lock_page(page); | ||
573 | if (page->mapping != inode->i_mapping) | ||
574 | goto out_unlock; | ||
575 | |||
576 | return VM_FAULT_LOCKED; | ||
577 | out_unlock: | ||
578 | unlock_page(page); | ||
579 | return VM_FAULT_NOPAGE; | ||
580 | } | ||
581 | |||
582 | static ssize_t | ||
583 | v9fs_direct_read(struct file *filp, char __user *udata, size_t count, | ||
584 | loff_t *offsetp) | ||
585 | { | ||
586 | loff_t size, offset; | ||
587 | struct inode *inode; | ||
588 | struct address_space *mapping; | ||
589 | |||
590 | offset = *offsetp; | ||
591 | mapping = filp->f_mapping; | ||
592 | inode = mapping->host; | ||
593 | if (!count) | ||
594 | return 0; | ||
595 | size = i_size_read(inode); | ||
596 | if (offset < size) | ||
597 | filemap_write_and_wait_range(mapping, offset, | ||
598 | offset + count - 1); | ||
599 | |||
600 | return v9fs_file_read(filp, udata, count, offsetp); | ||
601 | } | ||
602 | |||
603 | /** | ||
604 | * v9fs_cached_file_read - read from a file | ||
605 | * @filp: file pointer to read | ||
606 | * @udata: user data buffer to read data into | ||
607 | * @count: size of buffer | ||
608 | * @offset: offset at which to read data | ||
609 | * | ||
610 | */ | ||
611 | static ssize_t | ||
612 | v9fs_cached_file_read(struct file *filp, char __user *data, size_t count, | ||
613 | loff_t *offset) | ||
614 | { | ||
615 | if (filp->f_flags & O_DIRECT) | ||
616 | return v9fs_direct_read(filp, data, count, offset); | ||
617 | return do_sync_read(filp, data, count, offset); | ||
618 | } | ||
619 | |||
620 | static ssize_t | ||
621 | v9fs_direct_write(struct file *filp, const char __user * data, | ||
622 | size_t count, loff_t *offsetp) | ||
623 | { | ||
624 | loff_t offset; | ||
625 | ssize_t retval; | ||
626 | struct inode *inode; | ||
627 | struct address_space *mapping; | ||
628 | |||
629 | offset = *offsetp; | ||
630 | mapping = filp->f_mapping; | ||
631 | inode = mapping->host; | ||
632 | if (!count) | ||
633 | return 0; | ||
634 | |||
635 | mutex_lock(&inode->i_mutex); | ||
636 | retval = filemap_write_and_wait_range(mapping, offset, | ||
637 | offset + count - 1); | ||
638 | if (retval) | ||
639 | goto err_out; | ||
640 | /* | ||
641 | * After a write we want buffered reads to be sure to go to disk to get | ||
642 | * the new data. We invalidate clean cached page from the region we're | ||
643 | * about to write. We do this *before* the write so that if we fail | ||
644 | * here we fall back to buffered write | ||
645 | */ | ||
646 | if (mapping->nrpages) { | ||
647 | pgoff_t pg_start = offset >> PAGE_CACHE_SHIFT; | ||
648 | pgoff_t pg_end = (offset + count - 1) >> PAGE_CACHE_SHIFT; | ||
649 | |||
650 | retval = invalidate_inode_pages2_range(mapping, | ||
651 | pg_start, pg_end); | ||
652 | /* | ||
653 | * If a page can not be invalidated, fall back | ||
654 | * to buffered write. | ||
655 | */ | ||
656 | if (retval) { | ||
657 | if (retval == -EBUSY) | ||
658 | goto buff_write; | ||
659 | goto err_out; | ||
660 | } | ||
661 | } | ||
662 | retval = v9fs_file_write(filp, data, count, offsetp); | ||
663 | err_out: | ||
664 | mutex_unlock(&inode->i_mutex); | ||
665 | return retval; | ||
666 | |||
667 | buff_write: | ||
668 | mutex_unlock(&inode->i_mutex); | ||
669 | return do_sync_write(filp, data, count, offsetp); | ||
670 | } | ||
671 | |||
672 | /** | ||
673 | * v9fs_cached_file_write - write to a file | ||
674 | * @filp: file pointer to write | ||
675 | * @data: data buffer to write data from | ||
676 | * @count: size of buffer | ||
677 | * @offset: offset at which to write data | ||
678 | * | ||
679 | */ | ||
680 | static ssize_t | ||
681 | v9fs_cached_file_write(struct file *filp, const char __user * data, | ||
682 | size_t count, loff_t *offset) | ||
683 | { | ||
684 | |||
685 | if (filp->f_flags & O_DIRECT) | ||
686 | return v9fs_direct_write(filp, data, count, offset); | ||
687 | return do_sync_write(filp, data, count, offset); | ||
688 | } | ||
689 | |||
690 | static const struct vm_operations_struct v9fs_file_vm_ops = { | ||
691 | .fault = filemap_fault, | ||
692 | .page_mkwrite = v9fs_vm_page_mkwrite, | ||
693 | }; | ||
694 | |||
695 | |||
696 | const struct file_operations v9fs_cached_file_operations = { | ||
509 | .llseek = generic_file_llseek, | 697 | .llseek = generic_file_llseek, |
510 | .read = do_sync_read, | 698 | .read = v9fs_cached_file_read, |
699 | .write = v9fs_cached_file_write, | ||
511 | .aio_read = generic_file_aio_read, | 700 | .aio_read = generic_file_aio_read, |
512 | .write = v9fs_file_write, | 701 | .aio_write = generic_file_aio_write, |
513 | .open = v9fs_file_open, | 702 | .open = v9fs_file_open, |
514 | .release = v9fs_dir_release, | 703 | .release = v9fs_dir_release, |
515 | .lock = v9fs_file_lock, | 704 | .lock = v9fs_file_lock, |
516 | .mmap = generic_file_readonly_mmap, | 705 | .mmap = v9fs_file_mmap, |
517 | .fsync = v9fs_file_fsync, | 706 | .fsync = v9fs_file_fsync, |
518 | }; | 707 | }; |
519 | 708 | ||
520 | static const struct file_operations v9fs_cached_file_operations_dotl = { | 709 | const struct file_operations v9fs_cached_file_operations_dotl = { |
521 | .llseek = generic_file_llseek, | 710 | .llseek = generic_file_llseek, |
522 | .read = do_sync_read, | 711 | .read = v9fs_cached_file_read, |
712 | .write = v9fs_cached_file_write, | ||
523 | .aio_read = generic_file_aio_read, | 713 | .aio_read = generic_file_aio_read, |
524 | .write = v9fs_file_write, | 714 | .aio_write = generic_file_aio_write, |
525 | .open = v9fs_file_open, | 715 | .open = v9fs_file_open, |
526 | .release = v9fs_dir_release, | 716 | .release = v9fs_dir_release, |
527 | .lock = v9fs_file_lock_dotl, | 717 | .lock = v9fs_file_lock_dotl, |
528 | .flock = v9fs_file_flock_dotl, | 718 | .flock = v9fs_file_flock_dotl, |
529 | .mmap = generic_file_readonly_mmap, | 719 | .mmap = v9fs_file_mmap, |
530 | .fsync = v9fs_file_fsync_dotl, | 720 | .fsync = v9fs_file_fsync_dotl, |
531 | }; | 721 | }; |
532 | 722 | ||
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index b76a40bdf4c2..8a2c232f708a 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c | |||
@@ -203,26 +203,25 @@ v9fs_blank_wstat(struct p9_wstat *wstat) | |||
203 | wstat->extension = NULL; | 203 | wstat->extension = NULL; |
204 | } | 204 | } |
205 | 205 | ||
206 | #ifdef CONFIG_9P_FSCACHE | ||
207 | /** | 206 | /** |
208 | * v9fs_alloc_inode - helper function to allocate an inode | 207 | * v9fs_alloc_inode - helper function to allocate an inode |
209 | * This callback is executed before setting up the inode so that we | ||
210 | * can associate a vcookie with each inode. | ||
211 | * | 208 | * |
212 | */ | 209 | */ |
213 | |||
214 | struct inode *v9fs_alloc_inode(struct super_block *sb) | 210 | struct inode *v9fs_alloc_inode(struct super_block *sb) |
215 | { | 211 | { |
216 | struct v9fs_cookie *vcookie; | 212 | struct v9fs_inode *v9inode; |
217 | vcookie = (struct v9fs_cookie *)kmem_cache_alloc(vcookie_cache, | 213 | v9inode = (struct v9fs_inode *)kmem_cache_alloc(v9fs_inode_cache, |
218 | GFP_KERNEL); | 214 | GFP_KERNEL); |
219 | if (!vcookie) | 215 | if (!v9inode) |
220 | return NULL; | 216 | return NULL; |
221 | 217 | #ifdef CONFIG_9P_FSCACHE | |
222 | vcookie->fscache = NULL; | 218 | v9inode->fscache = NULL; |
223 | vcookie->qid = NULL; | 219 | v9inode->fscache_key = NULL; |
224 | spin_lock_init(&vcookie->lock); | 220 | spin_lock_init(&v9inode->fscache_lock); |
225 | return &vcookie->inode; | 221 | #endif |
222 | v9inode->writeback_fid = NULL; | ||
223 | v9inode->cache_validity = 0; | ||
224 | return &v9inode->vfs_inode; | ||
226 | } | 225 | } |
227 | 226 | ||
228 | /** | 227 | /** |
@@ -234,35 +233,18 @@ static void v9fs_i_callback(struct rcu_head *head) | |||
234 | { | 233 | { |
235 | struct inode *inode = container_of(head, struct inode, i_rcu); | 234 | struct inode *inode = container_of(head, struct inode, i_rcu); |
236 | INIT_LIST_HEAD(&inode->i_dentry); | 235 | INIT_LIST_HEAD(&inode->i_dentry); |
237 | kmem_cache_free(vcookie_cache, v9fs_inode2cookie(inode)); | 236 | kmem_cache_free(v9fs_inode_cache, V9FS_I(inode)); |
238 | } | 237 | } |
239 | 238 | ||
240 | void v9fs_destroy_inode(struct inode *inode) | 239 | void v9fs_destroy_inode(struct inode *inode) |
241 | { | 240 | { |
242 | call_rcu(&inode->i_rcu, v9fs_i_callback); | 241 | call_rcu(&inode->i_rcu, v9fs_i_callback); |
243 | } | 242 | } |
244 | #endif | ||
245 | 243 | ||
246 | /** | 244 | int v9fs_init_inode(struct v9fs_session_info *v9ses, |
247 | * v9fs_get_inode - helper function to setup an inode | 245 | struct inode *inode, int mode) |
248 | * @sb: superblock | ||
249 | * @mode: mode to setup inode with | ||
250 | * | ||
251 | */ | ||
252 | |||
253 | struct inode *v9fs_get_inode(struct super_block *sb, int mode) | ||
254 | { | 246 | { |
255 | int err; | 247 | int err = 0; |
256 | struct inode *inode; | ||
257 | struct v9fs_session_info *v9ses = sb->s_fs_info; | ||
258 | |||
259 | P9_DPRINTK(P9_DEBUG_VFS, "super block: %p mode: %o\n", sb, mode); | ||
260 | |||
261 | inode = new_inode(sb); | ||
262 | if (!inode) { | ||
263 | P9_EPRINTK(KERN_WARNING, "Problem allocating inode\n"); | ||
264 | return ERR_PTR(-ENOMEM); | ||
265 | } | ||
266 | 248 | ||
267 | inode_init_owner(inode, NULL, mode); | 249 | inode_init_owner(inode, NULL, mode); |
268 | inode->i_blocks = 0; | 250 | inode->i_blocks = 0; |
@@ -292,14 +274,20 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode) | |||
292 | case S_IFREG: | 274 | case S_IFREG: |
293 | if (v9fs_proto_dotl(v9ses)) { | 275 | if (v9fs_proto_dotl(v9ses)) { |
294 | inode->i_op = &v9fs_file_inode_operations_dotl; | 276 | inode->i_op = &v9fs_file_inode_operations_dotl; |
295 | inode->i_fop = &v9fs_file_operations_dotl; | 277 | if (v9ses->cache) |
278 | inode->i_fop = | ||
279 | &v9fs_cached_file_operations_dotl; | ||
280 | else | ||
281 | inode->i_fop = &v9fs_file_operations_dotl; | ||
296 | } else { | 282 | } else { |
297 | inode->i_op = &v9fs_file_inode_operations; | 283 | inode->i_op = &v9fs_file_inode_operations; |
298 | inode->i_fop = &v9fs_file_operations; | 284 | if (v9ses->cache) |
285 | inode->i_fop = &v9fs_cached_file_operations; | ||
286 | else | ||
287 | inode->i_fop = &v9fs_file_operations; | ||
299 | } | 288 | } |
300 | 289 | ||
301 | break; | 290 | break; |
302 | |||
303 | case S_IFLNK: | 291 | case S_IFLNK: |
304 | if (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses)) { | 292 | if (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses)) { |
305 | P9_DPRINTK(P9_DEBUG_ERROR, "extended modes used with " | 293 | P9_DPRINTK(P9_DEBUG_ERROR, "extended modes used with " |
@@ -335,12 +323,37 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode) | |||
335 | err = -EINVAL; | 323 | err = -EINVAL; |
336 | goto error; | 324 | goto error; |
337 | } | 325 | } |
326 | error: | ||
327 | return err; | ||
338 | 328 | ||
339 | return inode; | 329 | } |
340 | 330 | ||
341 | error: | 331 | /** |
342 | iput(inode); | 332 | * v9fs_get_inode - helper function to setup an inode |
343 | return ERR_PTR(err); | 333 | * @sb: superblock |
334 | * @mode: mode to setup inode with | ||
335 | * | ||
336 | */ | ||
337 | |||
338 | struct inode *v9fs_get_inode(struct super_block *sb, int mode) | ||
339 | { | ||
340 | int err; | ||
341 | struct inode *inode; | ||
342 | struct v9fs_session_info *v9ses = sb->s_fs_info; | ||
343 | |||
344 | P9_DPRINTK(P9_DEBUG_VFS, "super block: %p mode: %o\n", sb, mode); | ||
345 | |||
346 | inode = new_inode(sb); | ||
347 | if (!inode) { | ||
348 | P9_EPRINTK(KERN_WARNING, "Problem allocating inode\n"); | ||
349 | return ERR_PTR(-ENOMEM); | ||
350 | } | ||
351 | err = v9fs_init_inode(v9ses, inode, mode); | ||
352 | if (err) { | ||
353 | iput(inode); | ||
354 | return ERR_PTR(err); | ||
355 | } | ||
356 | return inode; | ||
344 | } | 357 | } |
345 | 358 | ||
346 | /* | 359 | /* |
@@ -403,6 +416,8 @@ error: | |||
403 | */ | 416 | */ |
404 | void v9fs_evict_inode(struct inode *inode) | 417 | void v9fs_evict_inode(struct inode *inode) |
405 | { | 418 | { |
419 | struct v9fs_inode *v9inode = V9FS_I(inode); | ||
420 | |||
406 | truncate_inode_pages(inode->i_mapping, 0); | 421 | truncate_inode_pages(inode->i_mapping, 0); |
407 | end_writeback(inode); | 422 | end_writeback(inode); |
408 | filemap_fdatawrite(inode->i_mapping); | 423 | filemap_fdatawrite(inode->i_mapping); |
@@ -410,41 +425,67 @@ void v9fs_evict_inode(struct inode *inode) | |||
410 | #ifdef CONFIG_9P_FSCACHE | 425 | #ifdef CONFIG_9P_FSCACHE |
411 | v9fs_cache_inode_put_cookie(inode); | 426 | v9fs_cache_inode_put_cookie(inode); |
412 | #endif | 427 | #endif |
428 | /* clunk the fid stashed in writeback_fid */ | ||
429 | if (v9inode->writeback_fid) { | ||
430 | p9_client_clunk(v9inode->writeback_fid); | ||
431 | v9inode->writeback_fid = NULL; | ||
432 | } | ||
413 | } | 433 | } |
414 | 434 | ||
415 | struct inode * | 435 | static struct inode *v9fs_qid_iget(struct super_block *sb, |
416 | v9fs_inode(struct v9fs_session_info *v9ses, struct p9_fid *fid, | 436 | struct p9_qid *qid, |
417 | struct super_block *sb) | 437 | struct p9_wstat *st) |
418 | { | 438 | { |
419 | int err, umode; | 439 | int retval, umode; |
420 | struct inode *ret = NULL; | 440 | unsigned long i_ino; |
421 | struct p9_wstat *st; | 441 | struct inode *inode; |
422 | 442 | struct v9fs_session_info *v9ses = sb->s_fs_info; | |
423 | st = p9_client_stat(fid); | ||
424 | if (IS_ERR(st)) | ||
425 | return ERR_CAST(st); | ||
426 | 443 | ||
444 | i_ino = v9fs_qid2ino(qid); | ||
445 | inode = iget_locked(sb, i_ino); | ||
446 | if (!inode) | ||
447 | return ERR_PTR(-ENOMEM); | ||
448 | if (!(inode->i_state & I_NEW)) | ||
449 | return inode; | ||
450 | /* | ||
451 | * initialize the inode with the stat info | ||
452 | * FIXME!! we may need support for stale inodes | ||
453 | * later. | ||
454 | */ | ||
427 | umode = p9mode2unixmode(v9ses, st->mode); | 455 | umode = p9mode2unixmode(v9ses, st->mode); |
428 | ret = v9fs_get_inode(sb, umode); | 456 | retval = v9fs_init_inode(v9ses, inode, umode); |
429 | if (IS_ERR(ret)) { | 457 | if (retval) |
430 | err = PTR_ERR(ret); | ||
431 | goto error; | 458 | goto error; |
432 | } | ||
433 | |||
434 | v9fs_stat2inode(st, ret, sb); | ||
435 | ret->i_ino = v9fs_qid2ino(&st->qid); | ||
436 | 459 | ||
460 | v9fs_stat2inode(st, inode, sb); | ||
437 | #ifdef CONFIG_9P_FSCACHE | 461 | #ifdef CONFIG_9P_FSCACHE |
438 | v9fs_vcookie_set_qid(ret, &st->qid); | 462 | v9fs_fscache_set_key(inode, &st->qid); |
439 | v9fs_cache_inode_get_cookie(ret); | 463 | v9fs_cache_inode_get_cookie(inode); |
440 | #endif | 464 | #endif |
441 | p9stat_free(st); | 465 | unlock_new_inode(inode); |
442 | kfree(st); | 466 | return inode; |
443 | return ret; | ||
444 | error: | 467 | error: |
468 | unlock_new_inode(inode); | ||
469 | iput(inode); | ||
470 | return ERR_PTR(retval); | ||
471 | |||
472 | } | ||
473 | |||
474 | struct inode * | ||
475 | v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid, | ||
476 | struct super_block *sb) | ||
477 | { | ||
478 | struct p9_wstat *st; | ||
479 | struct inode *inode = NULL; | ||
480 | |||
481 | st = p9_client_stat(fid); | ||
482 | if (IS_ERR(st)) | ||
483 | return ERR_CAST(st); | ||
484 | |||
485 | inode = v9fs_qid_iget(sb, &st->qid, st); | ||
445 | p9stat_free(st); | 486 | p9stat_free(st); |
446 | kfree(st); | 487 | kfree(st); |
447 | return ERR_PTR(err); | 488 | return inode; |
448 | } | 489 | } |
449 | 490 | ||
450 | /** | 491 | /** |
@@ -458,8 +499,8 @@ error: | |||
458 | static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir) | 499 | static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir) |
459 | { | 500 | { |
460 | int retval; | 501 | int retval; |
461 | struct inode *file_inode; | ||
462 | struct p9_fid *v9fid; | 502 | struct p9_fid *v9fid; |
503 | struct inode *file_inode; | ||
463 | 504 | ||
464 | P9_DPRINTK(P9_DEBUG_VFS, "inode: %p dentry: %p rmdir: %d\n", dir, file, | 505 | P9_DPRINTK(P9_DEBUG_VFS, "inode: %p dentry: %p rmdir: %d\n", dir, file, |
465 | rmdir); | 506 | rmdir); |
@@ -470,8 +511,20 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir) | |||
470 | return PTR_ERR(v9fid); | 511 | return PTR_ERR(v9fid); |
471 | 512 | ||
472 | retval = p9_client_remove(v9fid); | 513 | retval = p9_client_remove(v9fid); |
473 | if (!retval) | 514 | if (!retval) { |
474 | drop_nlink(file_inode); | 515 | /* |
516 | * directories on unlink should have zero | ||
517 | * link count | ||
518 | */ | ||
519 | if (rmdir) { | ||
520 | clear_nlink(file_inode); | ||
521 | drop_nlink(dir); | ||
522 | } else | ||
523 | drop_nlink(file_inode); | ||
524 | |||
525 | v9fs_invalidate_inode_attr(file_inode); | ||
526 | v9fs_invalidate_inode_attr(dir); | ||
527 | } | ||
475 | return retval; | 528 | return retval; |
476 | } | 529 | } |
477 | 530 | ||
@@ -531,7 +584,7 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir, | |||
531 | } | 584 | } |
532 | 585 | ||
533 | /* instantiate inode and assign the unopened fid to the dentry */ | 586 | /* instantiate inode and assign the unopened fid to the dentry */ |
534 | inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb); | 587 | inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb); |
535 | if (IS_ERR(inode)) { | 588 | if (IS_ERR(inode)) { |
536 | err = PTR_ERR(inode); | 589 | err = PTR_ERR(inode); |
537 | P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err); | 590 | P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err); |
@@ -570,9 +623,10 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode, | |||
570 | int err; | 623 | int err; |
571 | u32 perm; | 624 | u32 perm; |
572 | int flags; | 625 | int flags; |
573 | struct v9fs_session_info *v9ses; | ||
574 | struct p9_fid *fid; | ||
575 | struct file *filp; | 626 | struct file *filp; |
627 | struct v9fs_inode *v9inode; | ||
628 | struct v9fs_session_info *v9ses; | ||
629 | struct p9_fid *fid, *inode_fid; | ||
576 | 630 | ||
577 | err = 0; | 631 | err = 0; |
578 | fid = NULL; | 632 | fid = NULL; |
@@ -592,8 +646,25 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode, | |||
592 | goto error; | 646 | goto error; |
593 | } | 647 | } |
594 | 648 | ||
649 | v9fs_invalidate_inode_attr(dir); | ||
595 | /* if we are opening a file, assign the open fid to the file */ | 650 | /* if we are opening a file, assign the open fid to the file */ |
596 | if (nd && nd->flags & LOOKUP_OPEN) { | 651 | if (nd && nd->flags & LOOKUP_OPEN) { |
652 | v9inode = V9FS_I(dentry->d_inode); | ||
653 | if (v9ses->cache && !v9inode->writeback_fid) { | ||
654 | /* | ||
655 | * clone a fid and add it to writeback_fid | ||
656 | * we do it during open time instead of | ||
657 | * page dirty time via write_begin/page_mkwrite | ||
658 | * because we want write after unlink usecase | ||
659 | * to work. | ||
660 | */ | ||
661 | inode_fid = v9fs_writeback_fid(dentry); | ||
662 | if (IS_ERR(inode_fid)) { | ||
663 | err = PTR_ERR(inode_fid); | ||
664 | goto error; | ||
665 | } | ||
666 | v9inode->writeback_fid = (void *) inode_fid; | ||
667 | } | ||
597 | filp = lookup_instantiate_filp(nd, dentry, generic_file_open); | 668 | filp = lookup_instantiate_filp(nd, dentry, generic_file_open); |
598 | if (IS_ERR(filp)) { | 669 | if (IS_ERR(filp)) { |
599 | err = PTR_ERR(filp); | 670 | err = PTR_ERR(filp); |
@@ -601,6 +672,10 @@ v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode, | |||
601 | } | 672 | } |
602 | 673 | ||
603 | filp->private_data = fid; | 674 | filp->private_data = fid; |
675 | #ifdef CONFIG_9P_FSCACHE | ||
676 | if (v9ses->cache) | ||
677 | v9fs_cache_inode_set_cookie(dentry->d_inode, filp); | ||
678 | #endif | ||
604 | } else | 679 | } else |
605 | p9_client_clunk(fid); | 680 | p9_client_clunk(fid); |
606 | 681 | ||
@@ -625,8 +700,8 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
625 | { | 700 | { |
626 | int err; | 701 | int err; |
627 | u32 perm; | 702 | u32 perm; |
628 | struct v9fs_session_info *v9ses; | ||
629 | struct p9_fid *fid; | 703 | struct p9_fid *fid; |
704 | struct v9fs_session_info *v9ses; | ||
630 | 705 | ||
631 | P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name); | 706 | P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name); |
632 | err = 0; | 707 | err = 0; |
@@ -636,6 +711,9 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
636 | if (IS_ERR(fid)) { | 711 | if (IS_ERR(fid)) { |
637 | err = PTR_ERR(fid); | 712 | err = PTR_ERR(fid); |
638 | fid = NULL; | 713 | fid = NULL; |
714 | } else { | ||
715 | inc_nlink(dir); | ||
716 | v9fs_invalidate_inode_attr(dir); | ||
639 | } | 717 | } |
640 | 718 | ||
641 | if (fid) | 719 | if (fid) |
@@ -687,7 +765,7 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, | |||
687 | return ERR_PTR(result); | 765 | return ERR_PTR(result); |
688 | } | 766 | } |
689 | 767 | ||
690 | inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb); | 768 | inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb); |
691 | if (IS_ERR(inode)) { | 769 | if (IS_ERR(inode)) { |
692 | result = PTR_ERR(inode); | 770 | result = PTR_ERR(inode); |
693 | inode = NULL; | 771 | inode = NULL; |
@@ -747,17 +825,19 @@ int | |||
747 | v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | 825 | v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, |
748 | struct inode *new_dir, struct dentry *new_dentry) | 826 | struct inode *new_dir, struct dentry *new_dentry) |
749 | { | 827 | { |
828 | int retval; | ||
750 | struct inode *old_inode; | 829 | struct inode *old_inode; |
830 | struct inode *new_inode; | ||
751 | struct v9fs_session_info *v9ses; | 831 | struct v9fs_session_info *v9ses; |
752 | struct p9_fid *oldfid; | 832 | struct p9_fid *oldfid; |
753 | struct p9_fid *olddirfid; | 833 | struct p9_fid *olddirfid; |
754 | struct p9_fid *newdirfid; | 834 | struct p9_fid *newdirfid; |
755 | struct p9_wstat wstat; | 835 | struct p9_wstat wstat; |
756 | int retval; | ||
757 | 836 | ||
758 | P9_DPRINTK(P9_DEBUG_VFS, "\n"); | 837 | P9_DPRINTK(P9_DEBUG_VFS, "\n"); |
759 | retval = 0; | 838 | retval = 0; |
760 | old_inode = old_dentry->d_inode; | 839 | old_inode = old_dentry->d_inode; |
840 | new_inode = new_dentry->d_inode; | ||
761 | v9ses = v9fs_inode2v9ses(old_inode); | 841 | v9ses = v9fs_inode2v9ses(old_inode); |
762 | oldfid = v9fs_fid_lookup(old_dentry); | 842 | oldfid = v9fs_fid_lookup(old_dentry); |
763 | if (IS_ERR(oldfid)) | 843 | if (IS_ERR(oldfid)) |
@@ -798,9 +878,30 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
798 | retval = p9_client_wstat(oldfid, &wstat); | 878 | retval = p9_client_wstat(oldfid, &wstat); |
799 | 879 | ||
800 | clunk_newdir: | 880 | clunk_newdir: |
801 | if (!retval) | 881 | if (!retval) { |
882 | if (new_inode) { | ||
883 | if (S_ISDIR(new_inode->i_mode)) | ||
884 | clear_nlink(new_inode); | ||
885 | else | ||
886 | drop_nlink(new_inode); | ||
887 | /* | ||
888 | * Work around vfs rename rehash bug with | ||
889 | * FS_RENAME_DOES_D_MOVE | ||
890 | */ | ||
891 | v9fs_invalidate_inode_attr(new_inode); | ||
892 | } | ||
893 | if (S_ISDIR(old_inode->i_mode)) { | ||
894 | if (!new_inode) | ||
895 | inc_nlink(new_dir); | ||
896 | drop_nlink(old_dir); | ||
897 | } | ||
898 | v9fs_invalidate_inode_attr(old_inode); | ||
899 | v9fs_invalidate_inode_attr(old_dir); | ||
900 | v9fs_invalidate_inode_attr(new_dir); | ||
901 | |||
802 | /* successful rename */ | 902 | /* successful rename */ |
803 | d_move(old_dentry, new_dentry); | 903 | d_move(old_dentry, new_dentry); |
904 | } | ||
804 | up_write(&v9ses->rename_sem); | 905 | up_write(&v9ses->rename_sem); |
805 | p9_client_clunk(newdirfid); | 906 | p9_client_clunk(newdirfid); |
806 | 907 | ||
@@ -831,9 +932,10 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, | |||
831 | P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry); | 932 | P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry); |
832 | err = -EPERM; | 933 | err = -EPERM; |
833 | v9ses = v9fs_inode2v9ses(dentry->d_inode); | 934 | v9ses = v9fs_inode2v9ses(dentry->d_inode); |
834 | if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) | 935 | if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) { |
835 | return simple_getattr(mnt, dentry, stat); | 936 | generic_fillattr(dentry->d_inode, stat); |
836 | 937 | return 0; | |
938 | } | ||
837 | fid = v9fs_fid_lookup(dentry); | 939 | fid = v9fs_fid_lookup(dentry); |
838 | if (IS_ERR(fid)) | 940 | if (IS_ERR(fid)) |
839 | return PTR_ERR(fid); | 941 | return PTR_ERR(fid); |
@@ -891,17 +993,20 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) | |||
891 | if (iattr->ia_valid & ATTR_GID) | 993 | if (iattr->ia_valid & ATTR_GID) |
892 | wstat.n_gid = iattr->ia_gid; | 994 | wstat.n_gid = iattr->ia_gid; |
893 | } | 995 | } |
894 | |||
895 | retval = p9_client_wstat(fid, &wstat); | ||
896 | if (retval < 0) | ||
897 | return retval; | ||
898 | |||
899 | if ((iattr->ia_valid & ATTR_SIZE) && | 996 | if ((iattr->ia_valid & ATTR_SIZE) && |
900 | iattr->ia_size != i_size_read(dentry->d_inode)) { | 997 | iattr->ia_size != i_size_read(dentry->d_inode)) { |
901 | retval = vmtruncate(dentry->d_inode, iattr->ia_size); | 998 | retval = vmtruncate(dentry->d_inode, iattr->ia_size); |
902 | if (retval) | 999 | if (retval) |
903 | return retval; | 1000 | return retval; |
904 | } | 1001 | } |
1002 | /* Write all dirty data */ | ||
1003 | if (S_ISREG(dentry->d_inode->i_mode)) | ||
1004 | filemap_write_and_wait(dentry->d_inode->i_mapping); | ||
1005 | |||
1006 | retval = p9_client_wstat(fid, &wstat); | ||
1007 | if (retval < 0) | ||
1008 | return retval; | ||
1009 | v9fs_invalidate_inode_attr(dentry->d_inode); | ||
905 | 1010 | ||
906 | setattr_copy(dentry->d_inode, iattr); | 1011 | setattr_copy(dentry->d_inode, iattr); |
907 | mark_inode_dirty(dentry->d_inode); | 1012 | mark_inode_dirty(dentry->d_inode); |
@@ -924,6 +1029,7 @@ v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode, | |||
924 | char tag_name[14]; | 1029 | char tag_name[14]; |
925 | unsigned int i_nlink; | 1030 | unsigned int i_nlink; |
926 | struct v9fs_session_info *v9ses = sb->s_fs_info; | 1031 | struct v9fs_session_info *v9ses = sb->s_fs_info; |
1032 | struct v9fs_inode *v9inode = V9FS_I(inode); | ||
927 | 1033 | ||
928 | inode->i_nlink = 1; | 1034 | inode->i_nlink = 1; |
929 | 1035 | ||
@@ -983,6 +1089,7 @@ v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode, | |||
983 | 1089 | ||
984 | /* not real number of blocks, but 512 byte ones ... */ | 1090 | /* not real number of blocks, but 512 byte ones ... */ |
985 | inode->i_blocks = (i_size_read(inode) + 512 - 1) >> 9; | 1091 | inode->i_blocks = (i_size_read(inode) + 512 - 1) >> 9; |
1092 | v9inode->cache_validity &= ~V9FS_INO_INVALID_ATTR; | ||
986 | } | 1093 | } |
987 | 1094 | ||
988 | /** | 1095 | /** |
@@ -1115,8 +1222,8 @@ static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry, | |||
1115 | int mode, const char *extension) | 1222 | int mode, const char *extension) |
1116 | { | 1223 | { |
1117 | u32 perm; | 1224 | u32 perm; |
1118 | struct v9fs_session_info *v9ses; | ||
1119 | struct p9_fid *fid; | 1225 | struct p9_fid *fid; |
1226 | struct v9fs_session_info *v9ses; | ||
1120 | 1227 | ||
1121 | v9ses = v9fs_inode2v9ses(dir); | 1228 | v9ses = v9fs_inode2v9ses(dir); |
1122 | if (!v9fs_proto_dotu(v9ses)) { | 1229 | if (!v9fs_proto_dotu(v9ses)) { |
@@ -1130,6 +1237,7 @@ static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry, | |||
1130 | if (IS_ERR(fid)) | 1237 | if (IS_ERR(fid)) |
1131 | return PTR_ERR(fid); | 1238 | return PTR_ERR(fid); |
1132 | 1239 | ||
1240 | v9fs_invalidate_inode_attr(dir); | ||
1133 | p9_client_clunk(fid); | 1241 | p9_client_clunk(fid); |
1134 | return 0; | 1242 | return 0; |
1135 | } | 1243 | } |
@@ -1166,8 +1274,8 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir, | |||
1166 | struct dentry *dentry) | 1274 | struct dentry *dentry) |
1167 | { | 1275 | { |
1168 | int retval; | 1276 | int retval; |
1169 | struct p9_fid *oldfid; | ||
1170 | char *name; | 1277 | char *name; |
1278 | struct p9_fid *oldfid; | ||
1171 | 1279 | ||
1172 | P9_DPRINTK(P9_DEBUG_VFS, | 1280 | P9_DPRINTK(P9_DEBUG_VFS, |
1173 | " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, | 1281 | " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, |
@@ -1186,7 +1294,10 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir, | |||
1186 | sprintf(name, "%d\n", oldfid->fid); | 1294 | sprintf(name, "%d\n", oldfid->fid); |
1187 | retval = v9fs_vfs_mkspecial(dir, dentry, P9_DMLINK, name); | 1295 | retval = v9fs_vfs_mkspecial(dir, dentry, P9_DMLINK, name); |
1188 | __putname(name); | 1296 | __putname(name); |
1189 | 1297 | if (!retval) { | |
1298 | v9fs_refresh_inode(oldfid, old_dentry->d_inode); | ||
1299 | v9fs_invalidate_inode_attr(dir); | ||
1300 | } | ||
1190 | clunk_fid: | 1301 | clunk_fid: |
1191 | p9_client_clunk(oldfid); | 1302 | p9_client_clunk(oldfid); |
1192 | return retval; | 1303 | return retval; |
@@ -1237,6 +1348,32 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) | |||
1237 | return retval; | 1348 | return retval; |
1238 | } | 1349 | } |
1239 | 1350 | ||
1351 | int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode) | ||
1352 | { | ||
1353 | loff_t i_size; | ||
1354 | struct p9_wstat *st; | ||
1355 | struct v9fs_session_info *v9ses; | ||
1356 | |||
1357 | v9ses = v9fs_inode2v9ses(inode); | ||
1358 | st = p9_client_stat(fid); | ||
1359 | if (IS_ERR(st)) | ||
1360 | return PTR_ERR(st); | ||
1361 | |||
1362 | spin_lock(&inode->i_lock); | ||
1363 | /* | ||
1364 | * We don't want to refresh inode->i_size, | ||
1365 | * because we may have cached data | ||
1366 | */ | ||
1367 | i_size = inode->i_size; | ||
1368 | v9fs_stat2inode(st, inode, inode->i_sb); | ||
1369 | if (v9ses->cache) | ||
1370 | inode->i_size = i_size; | ||
1371 | spin_unlock(&inode->i_lock); | ||
1372 | p9stat_free(st); | ||
1373 | kfree(st); | ||
1374 | return 0; | ||
1375 | } | ||
1376 | |||
1240 | static const struct inode_operations v9fs_dir_inode_operations_dotu = { | 1377 | static const struct inode_operations v9fs_dir_inode_operations_dotu = { |
1241 | .create = v9fs_vfs_create, | 1378 | .create = v9fs_vfs_create, |
1242 | .lookup = v9fs_vfs_lookup, | 1379 | .lookup = v9fs_vfs_lookup, |
diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c index fe3ffa9aace4..67c138e94feb 100644 --- a/fs/9p/vfs_inode_dotl.c +++ b/fs/9p/vfs_inode_dotl.c | |||
@@ -86,40 +86,63 @@ static struct dentry *v9fs_dentry_from_dir_inode(struct inode *inode) | |||
86 | return dentry; | 86 | return dentry; |
87 | } | 87 | } |
88 | 88 | ||
89 | static struct inode *v9fs_qid_iget_dotl(struct super_block *sb, | ||
90 | struct p9_qid *qid, | ||
91 | struct p9_fid *fid, | ||
92 | struct p9_stat_dotl *st) | ||
93 | { | ||
94 | int retval; | ||
95 | unsigned long i_ino; | ||
96 | struct inode *inode; | ||
97 | struct v9fs_session_info *v9ses = sb->s_fs_info; | ||
98 | |||
99 | i_ino = v9fs_qid2ino(qid); | ||
100 | inode = iget_locked(sb, i_ino); | ||
101 | if (!inode) | ||
102 | return ERR_PTR(-ENOMEM); | ||
103 | if (!(inode->i_state & I_NEW)) | ||
104 | return inode; | ||
105 | /* | ||
106 | * initialize the inode with the stat info | ||
107 | * FIXME!! we may need support for stale inodes | ||
108 | * later. | ||
109 | */ | ||
110 | retval = v9fs_init_inode(v9ses, inode, st->st_mode); | ||
111 | if (retval) | ||
112 | goto error; | ||
113 | |||
114 | v9fs_stat2inode_dotl(st, inode); | ||
115 | #ifdef CONFIG_9P_FSCACHE | ||
116 | v9fs_fscache_set_key(inode, &st->qid); | ||
117 | v9fs_cache_inode_get_cookie(inode); | ||
118 | #endif | ||
119 | retval = v9fs_get_acl(inode, fid); | ||
120 | if (retval) | ||
121 | goto error; | ||
122 | |||
123 | unlock_new_inode(inode); | ||
124 | return inode; | ||
125 | error: | ||
126 | unlock_new_inode(inode); | ||
127 | iput(inode); | ||
128 | return ERR_PTR(retval); | ||
129 | |||
130 | } | ||
131 | |||
89 | struct inode * | 132 | struct inode * |
90 | v9fs_inode_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid, | 133 | v9fs_inode_from_fid_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid, |
91 | struct super_block *sb) | 134 | struct super_block *sb) |
92 | { | 135 | { |
93 | struct inode *ret = NULL; | ||
94 | int err; | ||
95 | struct p9_stat_dotl *st; | 136 | struct p9_stat_dotl *st; |
137 | struct inode *inode = NULL; | ||
96 | 138 | ||
97 | st = p9_client_getattr_dotl(fid, P9_STATS_BASIC); | 139 | st = p9_client_getattr_dotl(fid, P9_STATS_BASIC); |
98 | if (IS_ERR(st)) | 140 | if (IS_ERR(st)) |
99 | return ERR_CAST(st); | 141 | return ERR_CAST(st); |
100 | 142 | ||
101 | ret = v9fs_get_inode(sb, st->st_mode); | 143 | inode = v9fs_qid_iget_dotl(sb, &st->qid, fid, st); |
102 | if (IS_ERR(ret)) { | ||
103 | err = PTR_ERR(ret); | ||
104 | goto error; | ||
105 | } | ||
106 | |||
107 | v9fs_stat2inode_dotl(st, ret); | ||
108 | ret->i_ino = v9fs_qid2ino(&st->qid); | ||
109 | #ifdef CONFIG_9P_FSCACHE | ||
110 | v9fs_vcookie_set_qid(ret, &st->qid); | ||
111 | v9fs_cache_inode_get_cookie(ret); | ||
112 | #endif | ||
113 | err = v9fs_get_acl(ret, fid); | ||
114 | if (err) { | ||
115 | iput(ret); | ||
116 | goto error; | ||
117 | } | ||
118 | kfree(st); | ||
119 | return ret; | ||
120 | error: | ||
121 | kfree(st); | 144 | kfree(st); |
122 | return ERR_PTR(err); | 145 | return inode; |
123 | } | 146 | } |
124 | 147 | ||
125 | /** | 148 | /** |
@@ -136,16 +159,17 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode, | |||
136 | struct nameidata *nd) | 159 | struct nameidata *nd) |
137 | { | 160 | { |
138 | int err = 0; | 161 | int err = 0; |
139 | char *name = NULL; | ||
140 | gid_t gid; | 162 | gid_t gid; |
141 | int flags; | 163 | int flags; |
142 | mode_t mode; | 164 | mode_t mode; |
143 | struct v9fs_session_info *v9ses; | 165 | char *name = NULL; |
144 | struct p9_fid *fid = NULL; | ||
145 | struct p9_fid *dfid, *ofid; | ||
146 | struct file *filp; | 166 | struct file *filp; |
147 | struct p9_qid qid; | 167 | struct p9_qid qid; |
148 | struct inode *inode; | 168 | struct inode *inode; |
169 | struct p9_fid *fid = NULL; | ||
170 | struct v9fs_inode *v9inode; | ||
171 | struct p9_fid *dfid, *ofid, *inode_fid; | ||
172 | struct v9fs_session_info *v9ses; | ||
149 | struct posix_acl *pacl = NULL, *dacl = NULL; | 173 | struct posix_acl *pacl = NULL, *dacl = NULL; |
150 | 174 | ||
151 | v9ses = v9fs_inode2v9ses(dir); | 175 | v9ses = v9fs_inode2v9ses(dir); |
@@ -196,6 +220,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode, | |||
196 | err); | 220 | err); |
197 | goto error; | 221 | goto error; |
198 | } | 222 | } |
223 | v9fs_invalidate_inode_attr(dir); | ||
199 | 224 | ||
200 | /* instantiate inode and assign the unopened fid to the dentry */ | 225 | /* instantiate inode and assign the unopened fid to the dentry */ |
201 | fid = p9_client_walk(dfid, 1, &name, 1); | 226 | fid = p9_client_walk(dfid, 1, &name, 1); |
@@ -205,7 +230,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode, | |||
205 | fid = NULL; | 230 | fid = NULL; |
206 | goto error; | 231 | goto error; |
207 | } | 232 | } |
208 | inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb); | 233 | inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb); |
209 | if (IS_ERR(inode)) { | 234 | if (IS_ERR(inode)) { |
210 | err = PTR_ERR(inode); | 235 | err = PTR_ERR(inode); |
211 | P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err); | 236 | P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err); |
@@ -219,6 +244,22 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode, | |||
219 | /* Now set the ACL based on the default value */ | 244 | /* Now set the ACL based on the default value */ |
220 | v9fs_set_create_acl(dentry, dacl, pacl); | 245 | v9fs_set_create_acl(dentry, dacl, pacl); |
221 | 246 | ||
247 | v9inode = V9FS_I(inode); | ||
248 | if (v9ses->cache && !v9inode->writeback_fid) { | ||
249 | /* | ||
250 | * clone a fid and add it to writeback_fid | ||
251 | * we do it during open time instead of | ||
252 | * page dirty time via write_begin/page_mkwrite | ||
253 | * because we want write after unlink usecase | ||
254 | * to work. | ||
255 | */ | ||
256 | inode_fid = v9fs_writeback_fid(dentry); | ||
257 | if (IS_ERR(inode_fid)) { | ||
258 | err = PTR_ERR(inode_fid); | ||
259 | goto error; | ||
260 | } | ||
261 | v9inode->writeback_fid = (void *) inode_fid; | ||
262 | } | ||
222 | /* Since we are opening a file, assign the open fid to the file */ | 263 | /* Since we are opening a file, assign the open fid to the file */ |
223 | filp = lookup_instantiate_filp(nd, dentry, generic_file_open); | 264 | filp = lookup_instantiate_filp(nd, dentry, generic_file_open); |
224 | if (IS_ERR(filp)) { | 265 | if (IS_ERR(filp)) { |
@@ -226,6 +267,10 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode, | |||
226 | return PTR_ERR(filp); | 267 | return PTR_ERR(filp); |
227 | } | 268 | } |
228 | filp->private_data = ofid; | 269 | filp->private_data = ofid; |
270 | #ifdef CONFIG_9P_FSCACHE | ||
271 | if (v9ses->cache) | ||
272 | v9fs_cache_inode_set_cookie(inode, filp); | ||
273 | #endif | ||
229 | return 0; | 274 | return 0; |
230 | 275 | ||
231 | error: | 276 | error: |
@@ -300,7 +345,7 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir, | |||
300 | goto error; | 345 | goto error; |
301 | } | 346 | } |
302 | 347 | ||
303 | inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb); | 348 | inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb); |
304 | if (IS_ERR(inode)) { | 349 | if (IS_ERR(inode)) { |
305 | err = PTR_ERR(inode); | 350 | err = PTR_ERR(inode); |
306 | P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", | 351 | P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", |
@@ -327,7 +372,8 @@ static int v9fs_vfs_mkdir_dotl(struct inode *dir, | |||
327 | } | 372 | } |
328 | /* Now set the ACL based on the default value */ | 373 | /* Now set the ACL based on the default value */ |
329 | v9fs_set_create_acl(dentry, dacl, pacl); | 374 | v9fs_set_create_acl(dentry, dacl, pacl); |
330 | 375 | inc_nlink(dir); | |
376 | v9fs_invalidate_inode_attr(dir); | ||
331 | error: | 377 | error: |
332 | if (fid) | 378 | if (fid) |
333 | p9_client_clunk(fid); | 379 | p9_client_clunk(fid); |
@@ -346,9 +392,10 @@ v9fs_vfs_getattr_dotl(struct vfsmount *mnt, struct dentry *dentry, | |||
346 | P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry); | 392 | P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry); |
347 | err = -EPERM; | 393 | err = -EPERM; |
348 | v9ses = v9fs_inode2v9ses(dentry->d_inode); | 394 | v9ses = v9fs_inode2v9ses(dentry->d_inode); |
349 | if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) | 395 | if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) { |
350 | return simple_getattr(mnt, dentry, stat); | 396 | generic_fillattr(dentry->d_inode, stat); |
351 | 397 | return 0; | |
398 | } | ||
352 | fid = v9fs_fid_lookup(dentry); | 399 | fid = v9fs_fid_lookup(dentry); |
353 | if (IS_ERR(fid)) | 400 | if (IS_ERR(fid)) |
354 | return PTR_ERR(fid); | 401 | return PTR_ERR(fid); |
@@ -406,16 +453,20 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr) | |||
406 | if (IS_ERR(fid)) | 453 | if (IS_ERR(fid)) |
407 | return PTR_ERR(fid); | 454 | return PTR_ERR(fid); |
408 | 455 | ||
409 | retval = p9_client_setattr(fid, &p9attr); | ||
410 | if (retval < 0) | ||
411 | return retval; | ||
412 | |||
413 | if ((iattr->ia_valid & ATTR_SIZE) && | 456 | if ((iattr->ia_valid & ATTR_SIZE) && |
414 | iattr->ia_size != i_size_read(dentry->d_inode)) { | 457 | iattr->ia_size != i_size_read(dentry->d_inode)) { |
415 | retval = vmtruncate(dentry->d_inode, iattr->ia_size); | 458 | retval = vmtruncate(dentry->d_inode, iattr->ia_size); |
416 | if (retval) | 459 | if (retval) |
417 | return retval; | 460 | return retval; |
418 | } | 461 | } |
462 | /* Write all dirty data */ | ||
463 | if (S_ISREG(dentry->d_inode->i_mode)) | ||
464 | filemap_write_and_wait(dentry->d_inode->i_mapping); | ||
465 | |||
466 | retval = p9_client_setattr(fid, &p9attr); | ||
467 | if (retval < 0) | ||
468 | return retval; | ||
469 | v9fs_invalidate_inode_attr(dentry->d_inode); | ||
419 | 470 | ||
420 | setattr_copy(dentry->d_inode, iattr); | 471 | setattr_copy(dentry->d_inode, iattr); |
421 | mark_inode_dirty(dentry->d_inode); | 472 | mark_inode_dirty(dentry->d_inode); |
@@ -439,6 +490,7 @@ int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr) | |||
439 | void | 490 | void |
440 | v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode) | 491 | v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode) |
441 | { | 492 | { |
493 | struct v9fs_inode *v9inode = V9FS_I(inode); | ||
442 | 494 | ||
443 | if ((stat->st_result_mask & P9_STATS_BASIC) == P9_STATS_BASIC) { | 495 | if ((stat->st_result_mask & P9_STATS_BASIC) == P9_STATS_BASIC) { |
444 | inode->i_atime.tv_sec = stat->st_atime_sec; | 496 | inode->i_atime.tv_sec = stat->st_atime_sec; |
@@ -497,20 +549,21 @@ v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode) | |||
497 | /* Currently we don't support P9_STATS_BTIME and P9_STATS_DATA_VERSION | 549 | /* Currently we don't support P9_STATS_BTIME and P9_STATS_DATA_VERSION |
498 | * because the inode structure does not have fields for them. | 550 | * because the inode structure does not have fields for them. |
499 | */ | 551 | */ |
552 | v9inode->cache_validity &= ~V9FS_INO_INVALID_ATTR; | ||
500 | } | 553 | } |
501 | 554 | ||
502 | static int | 555 | static int |
503 | v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry, | 556 | v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry, |
504 | const char *symname) | 557 | const char *symname) |
505 | { | 558 | { |
506 | struct v9fs_session_info *v9ses; | ||
507 | struct p9_fid *dfid; | ||
508 | struct p9_fid *fid = NULL; | ||
509 | struct inode *inode; | ||
510 | struct p9_qid qid; | ||
511 | char *name; | ||
512 | int err; | 559 | int err; |
513 | gid_t gid; | 560 | gid_t gid; |
561 | char *name; | ||
562 | struct p9_qid qid; | ||
563 | struct inode *inode; | ||
564 | struct p9_fid *dfid; | ||
565 | struct p9_fid *fid = NULL; | ||
566 | struct v9fs_session_info *v9ses; | ||
514 | 567 | ||
515 | name = (char *) dentry->d_name.name; | 568 | name = (char *) dentry->d_name.name; |
516 | P9_DPRINTK(P9_DEBUG_VFS, "v9fs_vfs_symlink_dotl : %lu,%s,%s\n", | 569 | P9_DPRINTK(P9_DEBUG_VFS, "v9fs_vfs_symlink_dotl : %lu,%s,%s\n", |
@@ -534,6 +587,7 @@ v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry, | |||
534 | goto error; | 587 | goto error; |
535 | } | 588 | } |
536 | 589 | ||
590 | v9fs_invalidate_inode_attr(dir); | ||
537 | if (v9ses->cache) { | 591 | if (v9ses->cache) { |
538 | /* Now walk from the parent so we can get an unopened fid. */ | 592 | /* Now walk from the parent so we can get an unopened fid. */ |
539 | fid = p9_client_walk(dfid, 1, &name, 1); | 593 | fid = p9_client_walk(dfid, 1, &name, 1); |
@@ -546,7 +600,7 @@ v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry, | |||
546 | } | 600 | } |
547 | 601 | ||
548 | /* instantiate inode and assign the unopened fid to dentry */ | 602 | /* instantiate inode and assign the unopened fid to dentry */ |
549 | inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb); | 603 | inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb); |
550 | if (IS_ERR(inode)) { | 604 | if (IS_ERR(inode)) { |
551 | err = PTR_ERR(inode); | 605 | err = PTR_ERR(inode); |
552 | P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", | 606 | P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", |
@@ -588,10 +642,10 @@ v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir, | |||
588 | struct dentry *dentry) | 642 | struct dentry *dentry) |
589 | { | 643 | { |
590 | int err; | 644 | int err; |
591 | struct p9_fid *dfid, *oldfid; | ||
592 | char *name; | 645 | char *name; |
593 | struct v9fs_session_info *v9ses; | ||
594 | struct dentry *dir_dentry; | 646 | struct dentry *dir_dentry; |
647 | struct p9_fid *dfid, *oldfid; | ||
648 | struct v9fs_session_info *v9ses; | ||
595 | 649 | ||
596 | P9_DPRINTK(P9_DEBUG_VFS, "dir ino: %lu, old_name: %s, new_name: %s\n", | 650 | P9_DPRINTK(P9_DEBUG_VFS, "dir ino: %lu, old_name: %s, new_name: %s\n", |
597 | dir->i_ino, old_dentry->d_name.name, | 651 | dir->i_ino, old_dentry->d_name.name, |
@@ -616,29 +670,17 @@ v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir, | |||
616 | return err; | 670 | return err; |
617 | } | 671 | } |
618 | 672 | ||
673 | v9fs_invalidate_inode_attr(dir); | ||
619 | if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) { | 674 | if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) { |
620 | /* Get the latest stat info from server. */ | 675 | /* Get the latest stat info from server. */ |
621 | struct p9_fid *fid; | 676 | struct p9_fid *fid; |
622 | struct p9_stat_dotl *st; | ||
623 | |||
624 | fid = v9fs_fid_lookup(old_dentry); | 677 | fid = v9fs_fid_lookup(old_dentry); |
625 | if (IS_ERR(fid)) | 678 | if (IS_ERR(fid)) |
626 | return PTR_ERR(fid); | 679 | return PTR_ERR(fid); |
627 | 680 | ||
628 | st = p9_client_getattr_dotl(fid, P9_STATS_BASIC); | 681 | v9fs_refresh_inode_dotl(fid, old_dentry->d_inode); |
629 | if (IS_ERR(st)) | ||
630 | return PTR_ERR(st); | ||
631 | |||
632 | v9fs_stat2inode_dotl(st, old_dentry->d_inode); | ||
633 | |||
634 | kfree(st); | ||
635 | } else { | ||
636 | /* Caching disabled. No need to get upto date stat info. | ||
637 | * This dentry will be released immediately. So, just hold the | ||
638 | * inode | ||
639 | */ | ||
640 | ihold(old_dentry->d_inode); | ||
641 | } | 682 | } |
683 | ihold(old_dentry->d_inode); | ||
642 | d_instantiate(dentry, old_dentry->d_inode); | 684 | d_instantiate(dentry, old_dentry->d_inode); |
643 | 685 | ||
644 | return err; | 686 | return err; |
@@ -657,12 +699,12 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode, | |||
657 | dev_t rdev) | 699 | dev_t rdev) |
658 | { | 700 | { |
659 | int err; | 701 | int err; |
702 | gid_t gid; | ||
660 | char *name; | 703 | char *name; |
661 | mode_t mode; | 704 | mode_t mode; |
662 | struct v9fs_session_info *v9ses; | 705 | struct v9fs_session_info *v9ses; |
663 | struct p9_fid *fid = NULL, *dfid = NULL; | 706 | struct p9_fid *fid = NULL, *dfid = NULL; |
664 | struct inode *inode; | 707 | struct inode *inode; |
665 | gid_t gid; | ||
666 | struct p9_qid qid; | 708 | struct p9_qid qid; |
667 | struct dentry *dir_dentry; | 709 | struct dentry *dir_dentry; |
668 | struct posix_acl *dacl = NULL, *pacl = NULL; | 710 | struct posix_acl *dacl = NULL, *pacl = NULL; |
@@ -699,6 +741,7 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode, | |||
699 | if (err < 0) | 741 | if (err < 0) |
700 | goto error; | 742 | goto error; |
701 | 743 | ||
744 | v9fs_invalidate_inode_attr(dir); | ||
702 | /* instantiate inode and assign the unopened fid to the dentry */ | 745 | /* instantiate inode and assign the unopened fid to the dentry */ |
703 | if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) { | 746 | if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) { |
704 | fid = p9_client_walk(dfid, 1, &name, 1); | 747 | fid = p9_client_walk(dfid, 1, &name, 1); |
@@ -710,7 +753,7 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode, | |||
710 | goto error; | 753 | goto error; |
711 | } | 754 | } |
712 | 755 | ||
713 | inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb); | 756 | inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb); |
714 | if (IS_ERR(inode)) { | 757 | if (IS_ERR(inode)) { |
715 | err = PTR_ERR(inode); | 758 | err = PTR_ERR(inode); |
716 | P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", | 759 | P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", |
@@ -782,6 +825,31 @@ ndset: | |||
782 | return NULL; | 825 | return NULL; |
783 | } | 826 | } |
784 | 827 | ||
828 | int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode) | ||
829 | { | ||
830 | loff_t i_size; | ||
831 | struct p9_stat_dotl *st; | ||
832 | struct v9fs_session_info *v9ses; | ||
833 | |||
834 | v9ses = v9fs_inode2v9ses(inode); | ||
835 | st = p9_client_getattr_dotl(fid, P9_STATS_ALL); | ||
836 | if (IS_ERR(st)) | ||
837 | return PTR_ERR(st); | ||
838 | |||
839 | spin_lock(&inode->i_lock); | ||
840 | /* | ||
841 | * We don't want to refresh inode->i_size, | ||
842 | * because we may have cached data | ||
843 | */ | ||
844 | i_size = inode->i_size; | ||
845 | v9fs_stat2inode_dotl(st, inode); | ||
846 | if (v9ses->cache) | ||
847 | inode->i_size = i_size; | ||
848 | spin_unlock(&inode->i_lock); | ||
849 | kfree(st); | ||
850 | return 0; | ||
851 | } | ||
852 | |||
785 | const struct inode_operations v9fs_dir_inode_operations_dotl = { | 853 | const struct inode_operations v9fs_dir_inode_operations_dotl = { |
786 | .create = v9fs_vfs_create_dotl, | 854 | .create = v9fs_vfs_create_dotl, |
787 | .lookup = v9fs_vfs_lookup, | 855 | .lookup = v9fs_vfs_lookup, |
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index dbaabe3b8131..09fd08d1606f 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c | |||
@@ -86,12 +86,15 @@ v9fs_fill_super(struct super_block *sb, struct v9fs_session_info *v9ses, | |||
86 | } else | 86 | } else |
87 | sb->s_op = &v9fs_super_ops; | 87 | sb->s_op = &v9fs_super_ops; |
88 | sb->s_bdi = &v9ses->bdi; | 88 | sb->s_bdi = &v9ses->bdi; |
89 | if (v9ses->cache) | ||
90 | sb->s_bdi->ra_pages = (VM_MAX_READAHEAD * 1024)/PAGE_CACHE_SIZE; | ||
89 | 91 | ||
90 | sb->s_flags = flags | MS_ACTIVE | MS_SYNCHRONOUS | MS_DIRSYNC | | 92 | sb->s_flags = flags | MS_ACTIVE | MS_DIRSYNC | MS_NOATIME; |
91 | MS_NOATIME; | 93 | if (!v9ses->cache) |
94 | sb->s_flags |= MS_SYNCHRONOUS; | ||
92 | 95 | ||
93 | #ifdef CONFIG_9P_FS_POSIX_ACL | 96 | #ifdef CONFIG_9P_FS_POSIX_ACL |
94 | if ((v9ses->flags & V9FS_ACCESS_MASK) == V9FS_ACCESS_CLIENT) | 97 | if ((v9ses->flags & V9FS_ACL_MASK) == V9FS_POSIX_ACL) |
95 | sb->s_flags |= MS_POSIXACL; | 98 | sb->s_flags |= MS_POSIXACL; |
96 | #endif | 99 | #endif |
97 | 100 | ||
@@ -151,7 +154,6 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags, | |||
151 | retval = PTR_ERR(inode); | 154 | retval = PTR_ERR(inode); |
152 | goto release_sb; | 155 | goto release_sb; |
153 | } | 156 | } |
154 | |||
155 | root = d_alloc_root(inode); | 157 | root = d_alloc_root(inode); |
156 | if (!root) { | 158 | if (!root) { |
157 | iput(inode); | 159 | iput(inode); |
@@ -166,7 +168,7 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags, | |||
166 | retval = PTR_ERR(st); | 168 | retval = PTR_ERR(st); |
167 | goto release_sb; | 169 | goto release_sb; |
168 | } | 170 | } |
169 | 171 | root->d_inode->i_ino = v9fs_qid2ino(&st->qid); | |
170 | v9fs_stat2inode_dotl(st, root->d_inode); | 172 | v9fs_stat2inode_dotl(st, root->d_inode); |
171 | kfree(st); | 173 | kfree(st); |
172 | } else { | 174 | } else { |
@@ -183,10 +185,21 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags, | |||
183 | p9stat_free(st); | 185 | p9stat_free(st); |
184 | kfree(st); | 186 | kfree(st); |
185 | } | 187 | } |
188 | v9fs_fid_add(root, fid); | ||
186 | retval = v9fs_get_acl(inode, fid); | 189 | retval = v9fs_get_acl(inode, fid); |
187 | if (retval) | 190 | if (retval) |
188 | goto release_sb; | 191 | goto release_sb; |
189 | v9fs_fid_add(root, fid); | 192 | /* |
193 | * Add the root fid to session info. This is used | ||
194 | * for file system sync. We want a cloned fid here | ||
195 | * so that we can do a sync_filesystem after a | ||
196 | * shrink_dcache_for_umount | ||
197 | */ | ||
198 | v9ses->root_fid = v9fs_fid_clone(root); | ||
199 | if (IS_ERR(v9ses->root_fid)) { | ||
200 | retval = PTR_ERR(v9ses->root_fid); | ||
201 | goto release_sb; | ||
202 | } | ||
190 | 203 | ||
191 | P9_DPRINTK(P9_DEBUG_VFS, " simple set mount, return 0\n"); | 204 | P9_DPRINTK(P9_DEBUG_VFS, " simple set mount, return 0\n"); |
192 | return dget(sb->s_root); | 205 | return dget(sb->s_root); |
@@ -197,15 +210,11 @@ close_session: | |||
197 | v9fs_session_close(v9ses); | 210 | v9fs_session_close(v9ses); |
198 | kfree(v9ses); | 211 | kfree(v9ses); |
199 | return ERR_PTR(retval); | 212 | return ERR_PTR(retval); |
200 | |||
201 | release_sb: | 213 | release_sb: |
202 | /* | 214 | /* |
203 | * we will do the session_close and root dentry release | 215 | * we will do the session_close and root dentry |
204 | * in the below call. But we need to clunk fid, because we haven't | 216 | * release in the below call. |
205 | * attached the fid to dentry so it won't get clunked | ||
206 | * automatically. | ||
207 | */ | 217 | */ |
208 | p9_client_clunk(fid); | ||
209 | deactivate_locked_super(sb); | 218 | deactivate_locked_super(sb); |
210 | return ERR_PTR(retval); | 219 | return ERR_PTR(retval); |
211 | } | 220 | } |
@@ -223,7 +232,7 @@ static void v9fs_kill_super(struct super_block *s) | |||
223 | P9_DPRINTK(P9_DEBUG_VFS, " %p\n", s); | 232 | P9_DPRINTK(P9_DEBUG_VFS, " %p\n", s); |
224 | 233 | ||
225 | kill_anon_super(s); | 234 | kill_anon_super(s); |
226 | 235 | p9_client_clunk(v9ses->root_fid); | |
227 | v9fs_session_cancel(v9ses); | 236 | v9fs_session_cancel(v9ses); |
228 | v9fs_session_close(v9ses); | 237 | v9fs_session_close(v9ses); |
229 | kfree(v9ses); | 238 | kfree(v9ses); |
@@ -276,11 +285,31 @@ done: | |||
276 | return res; | 285 | return res; |
277 | } | 286 | } |
278 | 287 | ||
288 | static int v9fs_sync_fs(struct super_block *sb, int wait) | ||
289 | { | ||
290 | struct v9fs_session_info *v9ses = sb->s_fs_info; | ||
291 | |||
292 | P9_DPRINTK(P9_DEBUG_VFS, "v9fs_sync_fs: super_block %p\n", sb); | ||
293 | return p9_client_sync_fs(v9ses->root_fid); | ||
294 | } | ||
295 | |||
296 | static int v9fs_drop_inode(struct inode *inode) | ||
297 | { | ||
298 | struct v9fs_session_info *v9ses; | ||
299 | v9ses = v9fs_inode2v9ses(inode); | ||
300 | if (v9ses->cache) | ||
301 | return generic_drop_inode(inode); | ||
302 | /* | ||
303 | * in case of non cached mode always drop the | ||
304 | * the inode because we want the inode attribute | ||
305 | * to always match that on the server. | ||
306 | */ | ||
307 | return 1; | ||
308 | } | ||
309 | |||
279 | static const struct super_operations v9fs_super_ops = { | 310 | static const struct super_operations v9fs_super_ops = { |
280 | #ifdef CONFIG_9P_FSCACHE | ||
281 | .alloc_inode = v9fs_alloc_inode, | 311 | .alloc_inode = v9fs_alloc_inode, |
282 | .destroy_inode = v9fs_destroy_inode, | 312 | .destroy_inode = v9fs_destroy_inode, |
283 | #endif | ||
284 | .statfs = simple_statfs, | 313 | .statfs = simple_statfs, |
285 | .evict_inode = v9fs_evict_inode, | 314 | .evict_inode = v9fs_evict_inode, |
286 | .show_options = generic_show_options, | 315 | .show_options = generic_show_options, |
@@ -288,11 +317,11 @@ static const struct super_operations v9fs_super_ops = { | |||
288 | }; | 317 | }; |
289 | 318 | ||
290 | static const struct super_operations v9fs_super_ops_dotl = { | 319 | static const struct super_operations v9fs_super_ops_dotl = { |
291 | #ifdef CONFIG_9P_FSCACHE | ||
292 | .alloc_inode = v9fs_alloc_inode, | 320 | .alloc_inode = v9fs_alloc_inode, |
293 | .destroy_inode = v9fs_destroy_inode, | 321 | .destroy_inode = v9fs_destroy_inode, |
294 | #endif | 322 | .sync_fs = v9fs_sync_fs, |
295 | .statfs = v9fs_statfs, | 323 | .statfs = v9fs_statfs, |
324 | .drop_inode = v9fs_drop_inode, | ||
296 | .evict_inode = v9fs_evict_inode, | 325 | .evict_inode = v9fs_evict_inode, |
297 | .show_options = generic_show_options, | 326 | .show_options = generic_show_options, |
298 | .umount_begin = v9fs_umount_begin, | 327 | .umount_begin = v9fs_umount_begin, |
@@ -303,5 +332,5 @@ struct file_system_type v9fs_fs_type = { | |||
303 | .mount = v9fs_mount, | 332 | .mount = v9fs_mount, |
304 | .kill_sb = v9fs_kill_super, | 333 | .kill_sb = v9fs_kill_super, |
305 | .owner = THIS_MODULE, | 334 | .owner = THIS_MODULE, |
306 | .fs_flags = FS_RENAME_DOES_D_MOVE, | 335 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT, |
307 | }; | 336 | }; |
diff --git a/include/net/9p/9p.h b/include/net/9p/9p.h index 071fd7a8d781..6b75a6971346 100644 --- a/include/net/9p/9p.h +++ b/include/net/9p/9p.h | |||
@@ -139,6 +139,8 @@ do { \ | |||
139 | */ | 139 | */ |
140 | 140 | ||
141 | enum p9_msg_t { | 141 | enum p9_msg_t { |
142 | P9_TSYNCFS = 0, | ||
143 | P9_RSYNCFS, | ||
142 | P9_TLERROR = 6, | 144 | P9_TLERROR = 6, |
143 | P9_RLERROR, | 145 | P9_RLERROR, |
144 | P9_TSTATFS = 8, | 146 | P9_TSTATFS = 8, |
@@ -688,7 +690,11 @@ struct p9_rwstat { | |||
688 | * @id: protocol operating identifier of type &p9_msg_t | 690 | * @id: protocol operating identifier of type &p9_msg_t |
689 | * @tag: transaction id of the request | 691 | * @tag: transaction id of the request |
690 | * @offset: used by marshalling routines to track currentposition in buffer | 692 | * @offset: used by marshalling routines to track currentposition in buffer |
691 | * @capacity: used by marshalling routines to track total capacity | 693 | * @capacity: used by marshalling routines to track total malloc'd capacity |
694 | * @pubuf: Payload user buffer given by the caller | ||
695 | * @pubuf: Payload kernel buffer given by the caller | ||
696 | * @pbuf_size: pubuf/pkbuf(only one will be !NULL) size to be read/write. | ||
697 | * @private: For transport layer's use. | ||
692 | * @sdata: payload | 698 | * @sdata: payload |
693 | * | 699 | * |
694 | * &p9_fcall represents the structure for all 9P RPC | 700 | * &p9_fcall represents the structure for all 9P RPC |
@@ -705,6 +711,10 @@ struct p9_fcall { | |||
705 | 711 | ||
706 | size_t offset; | 712 | size_t offset; |
707 | size_t capacity; | 713 | size_t capacity; |
714 | char __user *pubuf; | ||
715 | char *pkbuf; | ||
716 | size_t pbuf_size; | ||
717 | void *private; | ||
708 | 718 | ||
709 | uint8_t *sdata; | 719 | uint8_t *sdata; |
710 | }; | 720 | }; |
diff --git a/include/net/9p/client.h b/include/net/9p/client.h index 83ba6a4d58a3..0a30977e3c1f 100644 --- a/include/net/9p/client.h +++ b/include/net/9p/client.h | |||
@@ -230,6 +230,7 @@ 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_fsync(struct p9_fid *fid, int datasync); |
233 | int p9_client_sync_fs(struct p9_fid *fid); | ||
233 | int p9_client_remove(struct p9_fid *fid); | 234 | int p9_client_remove(struct p9_fid *fid); |
234 | int p9_client_read(struct p9_fid *fid, char *data, char __user *udata, | 235 | int p9_client_read(struct p9_fid *fid, char *data, char __user *udata, |
235 | u64 offset, u32 count); | 236 | u64 offset, u32 count); |
diff --git a/include/net/9p/transport.h b/include/net/9p/transport.h index 6d5886efb102..82868f18c573 100644 --- a/include/net/9p/transport.h +++ b/include/net/9p/transport.h | |||
@@ -26,11 +26,19 @@ | |||
26 | #ifndef NET_9P_TRANSPORT_H | 26 | #ifndef NET_9P_TRANSPORT_H |
27 | #define NET_9P_TRANSPORT_H | 27 | #define NET_9P_TRANSPORT_H |
28 | 28 | ||
29 | #define P9_TRANS_PREF_PAYLOAD_MASK 0x1 | ||
30 | |||
31 | /* Default. Add Payload to PDU before sending it down to transport layer */ | ||
32 | #define P9_TRANS_PREF_PAYLOAD_DEF 0x0 | ||
33 | /* Send pay load seperately to transport layer along with PDU.*/ | ||
34 | #define P9_TRANS_PREF_PAYLOAD_SEP 0x1 | ||
35 | |||
29 | /** | 36 | /** |
30 | * struct p9_trans_module - transport module interface | 37 | * struct p9_trans_module - transport module interface |
31 | * @list: used to maintain a list of currently available transports | 38 | * @list: used to maintain a list of currently available transports |
32 | * @name: the human-readable name of the transport | 39 | * @name: the human-readable name of the transport |
33 | * @maxsize: transport provided maximum packet size | 40 | * @maxsize: transport provided maximum packet size |
41 | * @pref: Preferences of this transport | ||
34 | * @def: set if this transport should be considered the default | 42 | * @def: set if this transport should be considered the default |
35 | * @create: member function to create a new connection on this transport | 43 | * @create: member function to create a new connection on this transport |
36 | * @request: member function to issue a request to the transport | 44 | * @request: member function to issue a request to the transport |
@@ -47,6 +55,7 @@ struct p9_trans_module { | |||
47 | struct list_head list; | 55 | struct list_head list; |
48 | char *name; /* name of transport */ | 56 | char *name; /* name of transport */ |
49 | int maxsize; /* max message size of transport */ | 57 | int maxsize; /* max message size of transport */ |
58 | int pref; /* Preferences of this transport */ | ||
50 | int def; /* this transport should be default */ | 59 | int def; /* this transport should be default */ |
51 | struct module *owner; | 60 | struct module *owner; |
52 | int (*create)(struct p9_client *, const char *, char *); | 61 | int (*create)(struct p9_client *, const char *, char *); |
diff --git a/net/9p/Makefile b/net/9p/Makefile index 198a640d53a6..a0874cc1f718 100644 --- a/net/9p/Makefile +++ b/net/9p/Makefile | |||
@@ -9,6 +9,7 @@ obj-$(CONFIG_NET_9P_RDMA) += 9pnet_rdma.o | |||
9 | util.o \ | 9 | util.o \ |
10 | protocol.o \ | 10 | protocol.o \ |
11 | trans_fd.o \ | 11 | trans_fd.o \ |
12 | trans_common.o \ | ||
12 | 13 | ||
13 | 9pnet_virtio-objs := \ | 14 | 9pnet_virtio-objs := \ |
14 | trans_virtio.o \ | 15 | trans_virtio.o \ |
diff --git a/net/9p/client.c b/net/9p/client.c index a848bca9fbff..347ec0cd2718 100644 --- a/net/9p/client.c +++ b/net/9p/client.c | |||
@@ -229,10 +229,23 @@ static struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag) | |||
229 | return ERR_PTR(-ENOMEM); | 229 | return ERR_PTR(-ENOMEM); |
230 | } | 230 | } |
231 | init_waitqueue_head(req->wq); | 231 | init_waitqueue_head(req->wq); |
232 | req->tc = kmalloc(sizeof(struct p9_fcall)+c->msize, | 232 | if ((c->trans_mod->pref & P9_TRANS_PREF_PAYLOAD_MASK) == |
233 | GFP_KERNEL); | 233 | P9_TRANS_PREF_PAYLOAD_SEP) { |
234 | req->rc = kmalloc(sizeof(struct p9_fcall)+c->msize, | 234 | int alloc_msize = min(c->msize, 4096); |
235 | GFP_KERNEL); | 235 | req->tc = kmalloc(sizeof(struct p9_fcall)+alloc_msize, |
236 | GFP_KERNEL); | ||
237 | req->tc->capacity = alloc_msize; | ||
238 | req->rc = kmalloc(sizeof(struct p9_fcall)+alloc_msize, | ||
239 | GFP_KERNEL); | ||
240 | req->rc->capacity = alloc_msize; | ||
241 | } else { | ||
242 | req->tc = kmalloc(sizeof(struct p9_fcall)+c->msize, | ||
243 | GFP_KERNEL); | ||
244 | req->tc->capacity = c->msize; | ||
245 | req->rc = kmalloc(sizeof(struct p9_fcall)+c->msize, | ||
246 | GFP_KERNEL); | ||
247 | req->rc->capacity = c->msize; | ||
248 | } | ||
236 | if ((!req->tc) || (!req->rc)) { | 249 | if ((!req->tc) || (!req->rc)) { |
237 | printk(KERN_ERR "Couldn't grow tag array\n"); | 250 | printk(KERN_ERR "Couldn't grow tag array\n"); |
238 | kfree(req->tc); | 251 | kfree(req->tc); |
@@ -243,9 +256,7 @@ static struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag) | |||
243 | return ERR_PTR(-ENOMEM); | 256 | return ERR_PTR(-ENOMEM); |
244 | } | 257 | } |
245 | req->tc->sdata = (char *) req->tc + sizeof(struct p9_fcall); | 258 | req->tc->sdata = (char *) req->tc + sizeof(struct p9_fcall); |
246 | req->tc->capacity = c->msize; | ||
247 | req->rc->sdata = (char *) req->rc + sizeof(struct p9_fcall); | 259 | req->rc->sdata = (char *) req->rc + sizeof(struct p9_fcall); |
248 | req->rc->capacity = c->msize; | ||
249 | } | 260 | } |
250 | 261 | ||
251 | p9pdu_reset(req->tc); | 262 | p9pdu_reset(req->tc); |
@@ -443,6 +454,7 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req) | |||
443 | { | 454 | { |
444 | int8_t type; | 455 | int8_t type; |
445 | int err; | 456 | int err; |
457 | int ecode; | ||
446 | 458 | ||
447 | err = p9_parse_header(req->rc, NULL, &type, NULL, 0); | 459 | err = p9_parse_header(req->rc, NULL, &type, NULL, 0); |
448 | if (err) { | 460 | if (err) { |
@@ -450,36 +462,53 @@ static int p9_check_errors(struct p9_client *c, struct p9_req_t *req) | |||
450 | return err; | 462 | return err; |
451 | } | 463 | } |
452 | 464 | ||
453 | if (type == P9_RERROR || type == P9_RLERROR) { | 465 | if (type != P9_RERROR && type != P9_RLERROR) |
454 | int ecode; | 466 | return 0; |
455 | |||
456 | if (!p9_is_proto_dotl(c)) { | ||
457 | char *ename; | ||
458 | 467 | ||
459 | err = p9pdu_readf(req->rc, c->proto_version, "s?d", | 468 | if (!p9_is_proto_dotl(c)) { |
460 | &ename, &ecode); | 469 | char *ename; |
461 | if (err) | 470 | |
462 | goto out_err; | 471 | if (req->tc->pbuf_size) { |
472 | /* Handle user buffers */ | ||
473 | size_t len = req->rc->size - req->rc->offset; | ||
474 | if (req->tc->pubuf) { | ||
475 | /* User Buffer */ | ||
476 | err = copy_from_user( | ||
477 | &req->rc->sdata[req->rc->offset], | ||
478 | req->tc->pubuf, len); | ||
479 | if (err) { | ||
480 | err = -EFAULT; | ||
481 | goto out_err; | ||
482 | } | ||
483 | } else { | ||
484 | /* Kernel Buffer */ | ||
485 | memmove(&req->rc->sdata[req->rc->offset], | ||
486 | req->tc->pkbuf, len); | ||
487 | } | ||
488 | } | ||
489 | err = p9pdu_readf(req->rc, c->proto_version, "s?d", | ||
490 | &ename, &ecode); | ||
491 | if (err) | ||
492 | goto out_err; | ||
463 | 493 | ||
464 | if (p9_is_proto_dotu(c)) | 494 | if (p9_is_proto_dotu(c)) |
465 | err = -ecode; | 495 | err = -ecode; |
466 | 496 | ||
467 | if (!err || !IS_ERR_VALUE(err)) { | 497 | if (!err || !IS_ERR_VALUE(err)) { |
468 | err = p9_errstr2errno(ename, strlen(ename)); | 498 | err = p9_errstr2errno(ename, strlen(ename)); |
469 | 499 | ||
470 | P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", -ecode, ename); | 500 | P9_DPRINTK(P9_DEBUG_9P, "<<< RERROR (%d) %s\n", -ecode, |
501 | ename); | ||
471 | 502 | ||
472 | kfree(ename); | 503 | kfree(ename); |
473 | } | ||
474 | } else { | ||
475 | err = p9pdu_readf(req->rc, c->proto_version, "d", &ecode); | ||
476 | err = -ecode; | ||
477 | |||
478 | P9_DPRINTK(P9_DEBUG_9P, "<<< RLERROR (%d)\n", -ecode); | ||
479 | } | 504 | } |
505 | } else { | ||
506 | err = p9pdu_readf(req->rc, c->proto_version, "d", &ecode); | ||
507 | err = -ecode; | ||
508 | |||
509 | P9_DPRINTK(P9_DEBUG_9P, "<<< RLERROR (%d)\n", -ecode); | ||
510 | } | ||
480 | 511 | ||
481 | } else | ||
482 | err = 0; | ||
483 | 512 | ||
484 | return err; | 513 | return err; |
485 | 514 | ||
@@ -1191,6 +1220,27 @@ error: | |||
1191 | } | 1220 | } |
1192 | EXPORT_SYMBOL(p9_client_fsync); | 1221 | EXPORT_SYMBOL(p9_client_fsync); |
1193 | 1222 | ||
1223 | int p9_client_sync_fs(struct p9_fid *fid) | ||
1224 | { | ||
1225 | int err = 0; | ||
1226 | struct p9_req_t *req; | ||
1227 | struct p9_client *clnt; | ||
1228 | |||
1229 | P9_DPRINTK(P9_DEBUG_9P, ">>> TSYNC_FS fid %d\n", fid->fid); | ||
1230 | |||
1231 | clnt = fid->clnt; | ||
1232 | req = p9_client_rpc(clnt, P9_TSYNCFS, "d", fid->fid); | ||
1233 | if (IS_ERR(req)) { | ||
1234 | err = PTR_ERR(req); | ||
1235 | goto error; | ||
1236 | } | ||
1237 | P9_DPRINTK(P9_DEBUG_9P, "<<< RSYNCFS fid %d\n", fid->fid); | ||
1238 | p9_free_req(clnt, req); | ||
1239 | error: | ||
1240 | return err; | ||
1241 | } | ||
1242 | EXPORT_SYMBOL(p9_client_sync_fs); | ||
1243 | |||
1194 | int p9_client_clunk(struct p9_fid *fid) | 1244 | int p9_client_clunk(struct p9_fid *fid) |
1195 | { | 1245 | { |
1196 | int err; | 1246 | int err; |
@@ -1270,7 +1320,15 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, | |||
1270 | if (count < rsize) | 1320 | if (count < rsize) |
1271 | rsize = count; | 1321 | rsize = count; |
1272 | 1322 | ||
1273 | req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset, rsize); | 1323 | /* Don't bother zerocopy form small IO (< 1024) */ |
1324 | if (((clnt->trans_mod->pref & P9_TRANS_PREF_PAYLOAD_MASK) == | ||
1325 | P9_TRANS_PREF_PAYLOAD_SEP) && (rsize > 1024)) { | ||
1326 | req = p9_client_rpc(clnt, P9_TREAD, "dqE", fid->fid, offset, | ||
1327 | rsize, data, udata); | ||
1328 | } else { | ||
1329 | req = p9_client_rpc(clnt, P9_TREAD, "dqd", fid->fid, offset, | ||
1330 | rsize); | ||
1331 | } | ||
1274 | if (IS_ERR(req)) { | 1332 | if (IS_ERR(req)) { |
1275 | err = PTR_ERR(req); | 1333 | err = PTR_ERR(req); |
1276 | goto error; | 1334 | goto error; |
@@ -1284,13 +1342,15 @@ p9_client_read(struct p9_fid *fid, char *data, char __user *udata, u64 offset, | |||
1284 | 1342 | ||
1285 | P9_DPRINTK(P9_DEBUG_9P, "<<< RREAD count %d\n", count); | 1343 | P9_DPRINTK(P9_DEBUG_9P, "<<< RREAD count %d\n", count); |
1286 | 1344 | ||
1287 | if (data) { | 1345 | if (!req->tc->pbuf_size) { |
1288 | memmove(data, dataptr, count); | 1346 | if (data) { |
1289 | } else { | 1347 | memmove(data, dataptr, count); |
1290 | err = copy_to_user(udata, dataptr, count); | 1348 | } else { |
1291 | if (err) { | 1349 | err = copy_to_user(udata, dataptr, count); |
1292 | err = -EFAULT; | 1350 | if (err) { |
1293 | goto free_and_error; | 1351 | err = -EFAULT; |
1352 | goto free_and_error; | ||
1353 | } | ||
1294 | } | 1354 | } |
1295 | } | 1355 | } |
1296 | p9_free_req(clnt, req); | 1356 | p9_free_req(clnt, req); |
@@ -1323,12 +1383,21 @@ p9_client_write(struct p9_fid *fid, char *data, const char __user *udata, | |||
1323 | 1383 | ||
1324 | if (count < rsize) | 1384 | if (count < rsize) |
1325 | rsize = count; | 1385 | rsize = count; |
1326 | if (data) | 1386 | |
1327 | req = p9_client_rpc(clnt, P9_TWRITE, "dqD", fid->fid, offset, | 1387 | /* Don't bother zerocopy form small IO (< 1024) */ |
1328 | rsize, data); | 1388 | if (((clnt->trans_mod->pref & P9_TRANS_PREF_PAYLOAD_MASK) == |
1329 | else | 1389 | P9_TRANS_PREF_PAYLOAD_SEP) && (rsize > 1024)) { |
1330 | req = p9_client_rpc(clnt, P9_TWRITE, "dqU", fid->fid, offset, | 1390 | req = p9_client_rpc(clnt, P9_TWRITE, "dqE", fid->fid, offset, |
1331 | rsize, udata); | 1391 | rsize, data, udata); |
1392 | } else { | ||
1393 | |||
1394 | if (data) | ||
1395 | req = p9_client_rpc(clnt, P9_TWRITE, "dqD", fid->fid, | ||
1396 | offset, rsize, data); | ||
1397 | else | ||
1398 | req = p9_client_rpc(clnt, P9_TWRITE, "dqU", fid->fid, | ||
1399 | offset, rsize, udata); | ||
1400 | } | ||
1332 | if (IS_ERR(req)) { | 1401 | if (IS_ERR(req)) { |
1333 | err = PTR_ERR(req); | 1402 | err = PTR_ERR(req); |
1334 | goto error; | 1403 | goto error; |
@@ -1716,7 +1785,14 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) | |||
1716 | if (count < rsize) | 1785 | if (count < rsize) |
1717 | rsize = count; | 1786 | rsize = count; |
1718 | 1787 | ||
1719 | req = p9_client_rpc(clnt, P9_TREADDIR, "dqd", fid->fid, offset, rsize); | 1788 | if ((clnt->trans_mod->pref & P9_TRANS_PREF_PAYLOAD_MASK) == |
1789 | P9_TRANS_PREF_PAYLOAD_SEP) { | ||
1790 | req = p9_client_rpc(clnt, P9_TREADDIR, "dqF", fid->fid, | ||
1791 | offset, rsize, data); | ||
1792 | } else { | ||
1793 | req = p9_client_rpc(clnt, P9_TREADDIR, "dqd", fid->fid, | ||
1794 | offset, rsize); | ||
1795 | } | ||
1720 | if (IS_ERR(req)) { | 1796 | if (IS_ERR(req)) { |
1721 | err = PTR_ERR(req); | 1797 | err = PTR_ERR(req); |
1722 | goto error; | 1798 | goto error; |
@@ -1730,7 +1806,7 @@ int p9_client_readdir(struct p9_fid *fid, char *data, u32 count, u64 offset) | |||
1730 | 1806 | ||
1731 | P9_DPRINTK(P9_DEBUG_9P, "<<< RREADDIR count %d\n", count); | 1807 | P9_DPRINTK(P9_DEBUG_9P, "<<< RREADDIR count %d\n", count); |
1732 | 1808 | ||
1733 | if (data) | 1809 | if (!req->tc->pbuf_size && data) |
1734 | memmove(data, dataptr, count); | 1810 | memmove(data, dataptr, count); |
1735 | 1811 | ||
1736 | p9_free_req(clnt, req); | 1812 | p9_free_req(clnt, req); |
diff --git a/net/9p/protocol.c b/net/9p/protocol.c index 1e308f210928..2ce515b859b3 100644 --- a/net/9p/protocol.c +++ b/net/9p/protocol.c | |||
@@ -114,6 +114,26 @@ pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size) | |||
114 | return size - len; | 114 | return size - len; |
115 | } | 115 | } |
116 | 116 | ||
117 | static size_t | ||
118 | pdu_write_urw(struct p9_fcall *pdu, const char *kdata, const char __user *udata, | ||
119 | size_t size) | ||
120 | { | ||
121 | BUG_ON(pdu->size > P9_IOHDRSZ); | ||
122 | pdu->pubuf = (char __user *)udata; | ||
123 | pdu->pkbuf = (char *)kdata; | ||
124 | pdu->pbuf_size = size; | ||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static size_t | ||
129 | pdu_write_readdir(struct p9_fcall *pdu, const char *kdata, size_t size) | ||
130 | { | ||
131 | BUG_ON(pdu->size > P9_READDIRHDRSZ); | ||
132 | pdu->pkbuf = (char *)kdata; | ||
133 | pdu->pbuf_size = size; | ||
134 | return 0; | ||
135 | } | ||
136 | |||
117 | /* | 137 | /* |
118 | b - int8_t | 138 | b - int8_t |
119 | w - int16_t | 139 | w - int16_t |
@@ -445,6 +465,25 @@ p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt, | |||
445 | errcode = -EFAULT; | 465 | errcode = -EFAULT; |
446 | } | 466 | } |
447 | break; | 467 | break; |
468 | case 'E':{ | ||
469 | int32_t cnt = va_arg(ap, int32_t); | ||
470 | const char *k = va_arg(ap, const void *); | ||
471 | const char *u = va_arg(ap, const void *); | ||
472 | errcode = p9pdu_writef(pdu, proto_version, "d", | ||
473 | cnt); | ||
474 | if (!errcode && pdu_write_urw(pdu, k, u, cnt)) | ||
475 | errcode = -EFAULT; | ||
476 | } | ||
477 | break; | ||
478 | case 'F':{ | ||
479 | int32_t cnt = va_arg(ap, int32_t); | ||
480 | const char *k = va_arg(ap, const void *); | ||
481 | errcode = p9pdu_writef(pdu, proto_version, "d", | ||
482 | cnt); | ||
483 | if (!errcode && pdu_write_readdir(pdu, k, cnt)) | ||
484 | errcode = -EFAULT; | ||
485 | } | ||
486 | break; | ||
448 | case 'U':{ | 487 | case 'U':{ |
449 | int32_t count = va_arg(ap, int32_t); | 488 | int32_t count = va_arg(ap, int32_t); |
450 | const char __user *udata = | 489 | const char __user *udata = |
@@ -579,6 +618,7 @@ EXPORT_SYMBOL(p9stat_read); | |||
579 | 618 | ||
580 | int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type) | 619 | int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type) |
581 | { | 620 | { |
621 | pdu->id = type; | ||
582 | return p9pdu_writef(pdu, 0, "dbw", 0, type, tag); | 622 | return p9pdu_writef(pdu, 0, "dbw", 0, type, tag); |
583 | } | 623 | } |
584 | 624 | ||
@@ -606,6 +646,10 @@ void p9pdu_reset(struct p9_fcall *pdu) | |||
606 | { | 646 | { |
607 | pdu->offset = 0; | 647 | pdu->offset = 0; |
608 | pdu->size = 0; | 648 | pdu->size = 0; |
649 | pdu->private = NULL; | ||
650 | pdu->pubuf = NULL; | ||
651 | pdu->pkbuf = NULL; | ||
652 | pdu->pbuf_size = 0; | ||
609 | } | 653 | } |
610 | 654 | ||
611 | int p9dirent_read(char *buf, int len, struct p9_dirent *dirent, | 655 | int p9dirent_read(char *buf, int len, struct p9_dirent *dirent, |
diff --git a/net/9p/trans_common.c b/net/9p/trans_common.c new file mode 100644 index 000000000000..d62b9aa58df8 --- /dev/null +++ b/net/9p/trans_common.c | |||
@@ -0,0 +1,97 @@ | |||
1 | /* | ||
2 | * Copyright IBM Corporation, 2010 | ||
3 | * Author Venkateswararao Jujjuri <jvrao@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/slab.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <net/9p/9p.h> | ||
18 | #include <net/9p/client.h> | ||
19 | #include <linux/scatterlist.h> | ||
20 | #include "trans_common.h" | ||
21 | |||
22 | /** | ||
23 | * p9_release_req_pages - Release pages after the transaction. | ||
24 | * @*private: PDU's private page of struct trans_rpage_info | ||
25 | */ | ||
26 | void | ||
27 | p9_release_req_pages(struct trans_rpage_info *rpinfo) | ||
28 | { | ||
29 | int i = 0; | ||
30 | |||
31 | while (rpinfo->rp_data[i] && rpinfo->rp_nr_pages--) { | ||
32 | put_page(rpinfo->rp_data[i]); | ||
33 | i++; | ||
34 | } | ||
35 | } | ||
36 | EXPORT_SYMBOL(p9_release_req_pages); | ||
37 | |||
38 | /** | ||
39 | * p9_nr_pages - Return number of pages needed to accomodate the payload. | ||
40 | */ | ||
41 | int | ||
42 | p9_nr_pages(struct p9_req_t *req) | ||
43 | { | ||
44 | int start_page, end_page; | ||
45 | start_page = (unsigned long long)req->tc->pubuf >> PAGE_SHIFT; | ||
46 | end_page = ((unsigned long long)req->tc->pubuf + req->tc->pbuf_size + | ||
47 | PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
48 | return end_page - start_page; | ||
49 | } | ||
50 | EXPORT_SYMBOL(p9_nr_pages); | ||
51 | |||
52 | /** | ||
53 | * payload_gup - Translates user buffer into kernel pages and | ||
54 | * pins them either for read/write through get_user_pages_fast(). | ||
55 | * @req: Request to be sent to server. | ||
56 | * @pdata_off: data offset into the first page after translation (gup). | ||
57 | * @pdata_len: Total length of the IO. gup may not return requested # of pages. | ||
58 | * @nr_pages: number of pages to accomodate the payload | ||
59 | * @rw: Indicates if the pages are for read or write. | ||
60 | */ | ||
61 | int | ||
62 | p9_payload_gup(struct p9_req_t *req, size_t *pdata_off, int *pdata_len, | ||
63 | int nr_pages, u8 rw) | ||
64 | { | ||
65 | uint32_t first_page_bytes = 0; | ||
66 | uint32_t pdata_mapped_pages; | ||
67 | struct trans_rpage_info *rpinfo; | ||
68 | |||
69 | *pdata_off = (size_t)req->tc->pubuf & (PAGE_SIZE-1); | ||
70 | |||
71 | if (*pdata_off) | ||
72 | first_page_bytes = min((PAGE_SIZE - *pdata_off), | ||
73 | req->tc->pbuf_size); | ||
74 | |||
75 | rpinfo = req->tc->private; | ||
76 | pdata_mapped_pages = get_user_pages_fast((unsigned long)req->tc->pubuf, | ||
77 | nr_pages, rw, &rpinfo->rp_data[0]); | ||
78 | |||
79 | if (pdata_mapped_pages < 0) { | ||
80 | printk(KERN_ERR "get_user_pages_fast failed:%d udata:%p" | ||
81 | "nr_pages:%d\n", pdata_mapped_pages, | ||
82 | req->tc->pubuf, nr_pages); | ||
83 | pdata_mapped_pages = 0; | ||
84 | return -EIO; | ||
85 | } | ||
86 | rpinfo->rp_nr_pages = pdata_mapped_pages; | ||
87 | if (*pdata_off) { | ||
88 | *pdata_len = first_page_bytes; | ||
89 | *pdata_len += min((req->tc->pbuf_size - *pdata_len), | ||
90 | ((size_t)pdata_mapped_pages - 1) << PAGE_SHIFT); | ||
91 | } else { | ||
92 | *pdata_len = min(req->tc->pbuf_size, | ||
93 | (size_t)pdata_mapped_pages << PAGE_SHIFT); | ||
94 | } | ||
95 | return 0; | ||
96 | } | ||
97 | EXPORT_SYMBOL(p9_payload_gup); | ||
diff --git a/net/9p/trans_common.h b/net/9p/trans_common.h new file mode 100644 index 000000000000..76309223bb02 --- /dev/null +++ b/net/9p/trans_common.h | |||
@@ -0,0 +1,32 @@ | |||
1 | /* | ||
2 | * Copyright IBM Corporation, 2010 | ||
3 | * Author Venkateswararao Jujjuri <jvrao@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 | /* TRUE if it is user context */ | ||
16 | #define P9_IS_USER_CONTEXT (!segment_eq(get_fs(), KERNEL_DS)) | ||
17 | |||
18 | /** | ||
19 | * struct trans_rpage_info - To store mapped page information in PDU. | ||
20 | * @rp_alloc:Set if this structure is allocd, not a reuse unused space in pdu. | ||
21 | * @rp_nr_pages: Number of mapped pages | ||
22 | * @rp_data: Array of page pointers | ||
23 | */ | ||
24 | struct trans_rpage_info { | ||
25 | u8 rp_alloc; | ||
26 | int rp_nr_pages; | ||
27 | struct page *rp_data[0]; | ||
28 | }; | ||
29 | |||
30 | void p9_release_req_pages(struct trans_rpage_info *); | ||
31 | int p9_payload_gup(struct p9_req_t *, size_t *, int *, int, u8); | ||
32 | int p9_nr_pages(struct p9_req_t *); | ||
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c index c8f3f72ab20e..9b550ed9c711 100644 --- a/net/9p/trans_virtio.c +++ b/net/9p/trans_virtio.c | |||
@@ -45,6 +45,7 @@ | |||
45 | #include <linux/scatterlist.h> | 45 | #include <linux/scatterlist.h> |
46 | #include <linux/virtio.h> | 46 | #include <linux/virtio.h> |
47 | #include <linux/virtio_9p.h> | 47 | #include <linux/virtio_9p.h> |
48 | #include "trans_common.h" | ||
48 | 49 | ||
49 | #define VIRTQUEUE_NUM 128 | 50 | #define VIRTQUEUE_NUM 128 |
50 | 51 | ||
@@ -155,6 +156,14 @@ static void req_done(struct virtqueue *vq) | |||
155 | rc->tag); | 156 | rc->tag); |
156 | req = p9_tag_lookup(chan->client, rc->tag); | 157 | req = p9_tag_lookup(chan->client, rc->tag); |
157 | req->status = REQ_STATUS_RCVD; | 158 | req->status = REQ_STATUS_RCVD; |
159 | if (req->tc->private) { | ||
160 | struct trans_rpage_info *rp = req->tc->private; | ||
161 | /*Release pages */ | ||
162 | p9_release_req_pages(rp); | ||
163 | if (rp->rp_alloc) | ||
164 | kfree(rp); | ||
165 | req->tc->private = NULL; | ||
166 | } | ||
158 | p9_client_cb(chan->client, req); | 167 | p9_client_cb(chan->client, req); |
159 | } else { | 168 | } else { |
160 | spin_unlock_irqrestore(&chan->lock, flags); | 169 | spin_unlock_irqrestore(&chan->lock, flags); |
@@ -203,6 +212,38 @@ static int p9_virtio_cancel(struct p9_client *client, struct p9_req_t *req) | |||
203 | } | 212 | } |
204 | 213 | ||
205 | /** | 214 | /** |
215 | * pack_sg_list_p - Just like pack_sg_list. Instead of taking a buffer, | ||
216 | * this takes a list of pages. | ||
217 | * @sg: scatter/gather list to pack into | ||
218 | * @start: which segment of the sg_list to start at | ||
219 | * @pdata_off: Offset into the first page | ||
220 | * @**pdata: a list of pages to add into sg. | ||
221 | * @count: amount of data to pack into the scatter/gather list | ||
222 | */ | ||
223 | static int | ||
224 | pack_sg_list_p(struct scatterlist *sg, int start, int limit, size_t pdata_off, | ||
225 | struct page **pdata, int count) | ||
226 | { | ||
227 | int s; | ||
228 | int i = 0; | ||
229 | int index = start; | ||
230 | |||
231 | if (pdata_off) { | ||
232 | s = min((int)(PAGE_SIZE - pdata_off), count); | ||
233 | sg_set_page(&sg[index++], pdata[i++], s, pdata_off); | ||
234 | count -= s; | ||
235 | } | ||
236 | |||
237 | while (count) { | ||
238 | BUG_ON(index > limit); | ||
239 | s = min((int)PAGE_SIZE, count); | ||
240 | sg_set_page(&sg[index++], pdata[i++], s, 0); | ||
241 | count -= s; | ||
242 | } | ||
243 | return index-start; | ||
244 | } | ||
245 | |||
246 | /** | ||
206 | * p9_virtio_request - issue a request | 247 | * p9_virtio_request - issue a request |
207 | * @client: client instance issuing the request | 248 | * @client: client instance issuing the request |
208 | * @req: request to be issued | 249 | * @req: request to be issued |
@@ -212,22 +253,97 @@ static int p9_virtio_cancel(struct p9_client *client, struct p9_req_t *req) | |||
212 | static int | 253 | static int |
213 | p9_virtio_request(struct p9_client *client, struct p9_req_t *req) | 254 | p9_virtio_request(struct p9_client *client, struct p9_req_t *req) |
214 | { | 255 | { |
215 | int in, out; | 256 | int in, out, inp, outp; |
216 | struct virtio_chan *chan = client->trans; | 257 | struct virtio_chan *chan = client->trans; |
217 | char *rdata = (char *)req->rc+sizeof(struct p9_fcall); | 258 | char *rdata = (char *)req->rc+sizeof(struct p9_fcall); |
218 | unsigned long flags; | 259 | unsigned long flags; |
219 | int err; | 260 | size_t pdata_off = 0; |
261 | struct trans_rpage_info *rpinfo = NULL; | ||
262 | int err, pdata_len = 0; | ||
220 | 263 | ||
221 | P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request\n"); | 264 | P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request\n"); |
222 | 265 | ||
223 | req_retry: | 266 | req_retry: |
224 | req->status = REQ_STATUS_SENT; | 267 | req->status = REQ_STATUS_SENT; |
225 | 268 | ||
269 | if (req->tc->pbuf_size && (req->tc->pubuf && P9_IS_USER_CONTEXT)) { | ||
270 | int nr_pages = p9_nr_pages(req); | ||
271 | int rpinfo_size = sizeof(struct trans_rpage_info) + | ||
272 | sizeof(struct page *) * nr_pages; | ||
273 | |||
274 | if (rpinfo_size <= (req->tc->capacity - req->tc->size)) { | ||
275 | /* We can use sdata */ | ||
276 | req->tc->private = req->tc->sdata + req->tc->size; | ||
277 | rpinfo = (struct trans_rpage_info *)req->tc->private; | ||
278 | rpinfo->rp_alloc = 0; | ||
279 | } else { | ||
280 | req->tc->private = kmalloc(rpinfo_size, GFP_NOFS); | ||
281 | if (!req->tc->private) { | ||
282 | P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: " | ||
283 | "private kmalloc returned NULL"); | ||
284 | return -ENOMEM; | ||
285 | } | ||
286 | rpinfo = (struct trans_rpage_info *)req->tc->private; | ||
287 | rpinfo->rp_alloc = 1; | ||
288 | } | ||
289 | |||
290 | err = p9_payload_gup(req, &pdata_off, &pdata_len, nr_pages, | ||
291 | req->tc->id == P9_TREAD ? 1 : 0); | ||
292 | if (err < 0) { | ||
293 | if (rpinfo->rp_alloc) | ||
294 | kfree(rpinfo); | ||
295 | return err; | ||
296 | } | ||
297 | } | ||
298 | |||
226 | spin_lock_irqsave(&chan->lock, flags); | 299 | spin_lock_irqsave(&chan->lock, flags); |
300 | |||
301 | /* Handle out VirtIO ring buffers */ | ||
227 | out = pack_sg_list(chan->sg, 0, VIRTQUEUE_NUM, req->tc->sdata, | 302 | out = pack_sg_list(chan->sg, 0, VIRTQUEUE_NUM, req->tc->sdata, |
228 | req->tc->size); | 303 | req->tc->size); |
229 | in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM-out, rdata, | 304 | |
230 | client->msize); | 305 | if (req->tc->pbuf_size && (req->tc->id == P9_TWRITE)) { |
306 | /* We have additional write payload buffer to take care */ | ||
307 | if (req->tc->pubuf && P9_IS_USER_CONTEXT) { | ||
308 | outp = pack_sg_list_p(chan->sg, out, VIRTQUEUE_NUM, | ||
309 | pdata_off, rpinfo->rp_data, pdata_len); | ||
310 | } else { | ||
311 | char *pbuf = req->tc->pubuf ? req->tc->pubuf : | ||
312 | req->tc->pkbuf; | ||
313 | outp = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM, pbuf, | ||
314 | req->tc->pbuf_size); | ||
315 | } | ||
316 | out += outp; | ||
317 | } | ||
318 | |||
319 | /* Handle in VirtIO ring buffers */ | ||
320 | if (req->tc->pbuf_size && | ||
321 | ((req->tc->id == P9_TREAD) || (req->tc->id == P9_TREADDIR))) { | ||
322 | /* | ||
323 | * Take care of additional Read payload. | ||
324 | * 11 is the read/write header = PDU Header(7) + IO Size (4). | ||
325 | * Arrange in such a way that server places header in the | ||
326 | * alloced memory and payload onto the user buffer. | ||
327 | */ | ||
328 | inp = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM, rdata, 11); | ||
329 | /* | ||
330 | * Running executables in the filesystem may result in | ||
331 | * a read request with kernel buffer as opposed to user buffer. | ||
332 | */ | ||
333 | if (req->tc->pubuf && P9_IS_USER_CONTEXT) { | ||
334 | in = pack_sg_list_p(chan->sg, out+inp, VIRTQUEUE_NUM, | ||
335 | pdata_off, rpinfo->rp_data, pdata_len); | ||
336 | } else { | ||
337 | char *pbuf = req->tc->pubuf ? req->tc->pubuf : | ||
338 | req->tc->pkbuf; | ||
339 | in = pack_sg_list(chan->sg, out+inp, VIRTQUEUE_NUM, | ||
340 | pbuf, req->tc->pbuf_size); | ||
341 | } | ||
342 | in += inp; | ||
343 | } else { | ||
344 | in = pack_sg_list(chan->sg, out, VIRTQUEUE_NUM, rdata, | ||
345 | client->msize); | ||
346 | } | ||
231 | 347 | ||
232 | err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc); | 348 | err = virtqueue_add_buf(chan->vq, chan->sg, out, in, req->tc); |
233 | if (err < 0) { | 349 | if (err < 0) { |
@@ -246,6 +362,8 @@ req_retry: | |||
246 | P9_DPRINTK(P9_DEBUG_TRANS, | 362 | P9_DPRINTK(P9_DEBUG_TRANS, |
247 | "9p debug: " | 363 | "9p debug: " |
248 | "virtio rpc add_buf returned failure"); | 364 | "virtio rpc add_buf returned failure"); |
365 | if (rpinfo && rpinfo->rp_alloc) | ||
366 | kfree(rpinfo); | ||
249 | return -EIO; | 367 | return -EIO; |
250 | } | 368 | } |
251 | } | 369 | } |
@@ -448,6 +566,7 @@ static struct p9_trans_module p9_virtio_trans = { | |||
448 | .request = p9_virtio_request, | 566 | .request = p9_virtio_request, |
449 | .cancel = p9_virtio_cancel, | 567 | .cancel = p9_virtio_cancel, |
450 | .maxsize = PAGE_SIZE*16, | 568 | .maxsize = PAGE_SIZE*16, |
569 | .pref = P9_TRANS_PREF_PAYLOAD_SEP, | ||
451 | .def = 0, | 570 | .def = 0, |
452 | .owner = THIS_MODULE, | 571 | .owner = THIS_MODULE, |
453 | }; | 572 | }; |