aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-03-16 11:58:09 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-03-16 11:58:09 -0400
commit26a992dbc24e34cbdd03621d1c97ce571ad74e65 (patch)
treecbb3171eb715b7c1ed28ed3ca29f1f03165e2faa
parentabab012a52237693ae48a655ece30cacb2ce4cf7 (diff)
parent7c9e592e1f6a994d2903c9b055e488ec90f58159 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs: (46 commits) fs/9p: Make the writeback_fid owned by root fs/9p: Writeback dirty data before setattr fs/9p: call vmtruncate before setattr 9p opeation fs/9p: Properly update inode attributes on link fs/9p: Prevent multiple inclusion of same header fs/9p: Workaround vfs rename rehash bug fs/9p: Mark directory inode invalid for many directory inode operations fs/9p: Add . and .. dentry revalidation flag fs/9p: mark inode attribute invalid on rename, unlink and setattr fs/9p: Add support for marking inode attribute invalid fs/9p: Initialize root inode number for dotl fs/9p: Update link count correctly on different file system operations fs/9p: Add drop_inode 9p callback fs/9p: Add direct IO support in cached mode fs/9p: Fix inode i_size update in file_write fs/9p: set default readahead pages in cached mode fs/9p: Move writeback fid to v9fs_inode fs/9p: Add v9fs_inode fs/9p: Don't set stat.st_blocks based on nrpages fs/9p: Add inode hashing ...
-rw-r--r--fs/9p/acl.c28
-rw-r--r--fs/9p/cache.c204
-rw-r--r--fs/9p/cache.h64
-rw-r--r--fs/9p/fid.c114
-rw-r--r--fs/9p/fid.h5
-rw-r--r--fs/9p/v9fs.c108
-rw-r--r--fs/9p/v9fs.h53
-rw-r--r--fs/9p/v9fs_vfs.h26
-rw-r--r--fs/9p/vfs_addr.c194
-rw-r--r--fs/9p/vfs_dentry.c47
-rw-r--r--fs/9p/vfs_dir.c1
-rw-r--r--fs/9p/vfs_file.c316
-rw-r--r--fs/9p/vfs_inode.c307
-rw-r--r--fs/9p/vfs_inode_dotl.c198
-rw-r--r--fs/9p/vfs_super.c65
-rw-r--r--include/net/9p/9p.h12
-rw-r--r--include/net/9p/client.h1
-rw-r--r--include/net/9p/transport.h9
-rw-r--r--net/9p/Makefile1
-rw-r--r--net/9p/client.c166
-rw-r--r--net/9p/protocol.c44
-rw-r--r--net/9p/trans_common.c97
-rw-r--r--net/9p/trans_common.h32
-rw-r--r--net/9p/trans_virtio.c129
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
27static struct posix_acl *__v9fs_get_acl(struct p9_fid *fid, char *name) 27static 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)
177int v9fs_set_create_acl(struct dentry *dentry, 187int 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
36struct kmem_cache *vcookie_cache;
37
38struct fscache_netfs v9fs_cache_netfs = { 36struct fscache_netfs v9fs_cache_netfs = {
39 .name = "9p", 37 .name = "9p",
40 .version = 0, 38 .version = 0,
41}; 39};
42 40
43static 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
58static 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
76static void v9fs_destroy_vcookiecache(void)
77{
78 kmem_cache_destroy(vcookie_cache);
79}
80
81int __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
91void __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
135const struct fscache_cookie_def v9fs_cache_session_index_def = { 79const 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
141void v9fs_cache_session_get_cookie(struct v9fs_session_info *v9ses) 85void 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)
163static uint16_t v9fs_cache_inode_get_key(const void *cookie_netfs_data, 107static 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
174static void v9fs_cache_inode_get_attr(const void *cookie_netfs_data, 118static 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
184static uint16_t v9fs_cache_inode_get_aux(const void *cookie_netfs_data, 128static 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
195static enum 139static 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
212static void v9fs_cache_inode_now_uncached(void *cookie_netfs_data) 156static 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
250void v9fs_cache_inode_get_cookie(struct inode *inode) 194void 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
271void v9fs_cache_inode_put_cookie(struct inode *inode) 215void 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
284void v9fs_cache_inode_flush_cookie(struct inode *inode) 228void 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
297void v9fs_cache_inode_set_cookie(struct inode *inode, struct file *filp) 241void 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
315void v9fs_cache_inode_reset_cookie(struct inode *inode) 259void 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
340int __v9fs_fscache_release_page(struct page *page, gfp_t gfp) 283int __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
350void __v9fs_fscache_invalidate_page(struct page *page) 293void __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,
380int __v9fs_readpage_from_fscache(struct inode *inode, struct page *page) 323int __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,
453void __v9fs_readpage_to_fscache(struct inode *inode, struct page *page) 396void __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 */
411void __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
28extern struct kmem_cache *vcookie_cache;
29
30struct v9fs_cookie {
31 spinlock_t lock;
32 struct inode inode;
33 struct fscache_cookie *fscache;
34 struct p9_qid *qid;
35};
36
37static inline struct v9fs_cookie *v9fs_inode2cookie(const struct inode *inode)
38{
39 return container_of(inode, struct v9fs_cookie, inode);
40}
41
42extern struct fscache_netfs v9fs_cache_netfs; 28extern struct fscache_netfs v9fs_cache_netfs;
43extern const struct fscache_cookie_def v9fs_cache_session_index_def; 29extern const struct fscache_cookie_def v9fs_cache_session_index_def;
44extern const struct fscache_cookie_def v9fs_cache_inode_index_def; 30extern 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);
66extern void __v9fs_readpage_to_fscache(struct inode *inode, struct page *page); 52extern void __v9fs_readpage_to_fscache(struct inode *inode, struct page *page);
67 53extern 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 */
72static 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 */
80static inline void v9fs_cache_unregister(void)
81{
82 __v9fs_cache_unregister();
83}
84 55
85static inline int v9fs_fscache_release_page(struct page *page, 56static 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
118static inline void v9fs_uncache_page(struct inode *inode, struct page *page) 89static 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
125static inline void v9fs_vcookie_set_qid(struct inode *inode, 96static 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 */ 105static inline void v9fs_fscache_wait_on_page_write(struct inode *inode,
135 106 struct page *page)
136static 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
141static inline void v9fs_cache_unregister(void) {} 111#else /* CONFIG_9P_FSCACHE */
142 112
143static inline int v9fs_fscache_release_page(struct page *page, 113static 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,
168static inline void v9fs_uncache_page(struct inode *inode, struct page *page) 138static inline void v9fs_uncache_page(struct inode *inode, struct page *page)
169{} 139{}
170 140
171static inline void v9fs_vcookie_set_qid(struct inode *inode, 141static 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/** 128static 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
138struct 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
234struct 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
253struct p9_fid *v9fs_fid_clone(struct dentry *dentry) 263struct 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
275static 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
287struct 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 }
307error_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 {
45struct p9_fid *v9fs_fid_lookup(struct dentry *dentry); 46struct p9_fid *v9fs_fid_lookup(struct dentry *dentry);
46struct p9_fid *v9fs_fid_clone(struct dentry *dentry); 47struct p9_fid *v9fs_fid_clone(struct dentry *dentry);
47int v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid); 48int v9fs_fid_add(struct dentry *dentry, struct p9_fid *fid);
49struct 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
40static DEFINE_SPINLOCK(v9fs_sessionlist_lock); 40static DEFINE_SPINLOCK(v9fs_sessionlist_lock);
41static LIST_HEAD(v9fs_sessionlist); 41static LIST_HEAD(v9fs_sessionlist);
42struct 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
485static 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 */
499static 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 */
516static void v9fs_destroy_inode_cache(void)
517{
518 kmem_cache_destroy(v9fs_inode_cache);
519}
520
521static 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
534static 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
41enum p9_session_flags { 47enum 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
125struct 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
136static inline struct v9fs_inode *V9FS_I(const struct inode *inode)
137{
138 return container_of(inode, struct v9fs_inode, vfs_inode);
139}
140
114struct p9_fid *v9fs_session_init(struct v9fs_session_info *, const char *, 141struct p9_fid *v9fs_session_init(struct v9fs_session_info *, const char *,
115 char *); 142 char *);
116extern void v9fs_session_close(struct v9fs_session_info *v9ses); 143extern 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);
125extern void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, 152extern void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd,
126 void *p); 153 void *p);
127extern struct inode *v9fs_inode(struct v9fs_session_info *v9ses, 154extern 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
131extern const struct inode_operations v9fs_dir_inode_operations_dotl; 157extern const struct inode_operations v9fs_dir_inode_operations_dotl;
132extern const struct inode_operations v9fs_file_inode_operations_dotl; 158extern const struct inode_operations v9fs_file_inode_operations_dotl;
133extern const struct inode_operations v9fs_symlink_inode_operations_dotl; 159extern const struct inode_operations v9fs_symlink_inode_operations_dotl;
134extern struct inode *v9fs_inode_dotl(struct v9fs_session_info *v9ses, 160extern 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 */
168static inline struct inode * 194static inline struct inode *
169v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid, 195v9fs_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
40extern struct file_system_type v9fs_fs_type; 43extern struct file_system_type v9fs_fs_type;
41extern const struct address_space_operations v9fs_addr_operations; 44extern const struct address_space_operations v9fs_addr_operations;
@@ -45,13 +48,15 @@ extern const struct file_operations v9fs_dir_operations;
45extern const struct file_operations v9fs_dir_operations_dotl; 48extern const struct file_operations v9fs_dir_operations_dotl;
46extern const struct dentry_operations v9fs_dentry_operations; 49extern const struct dentry_operations v9fs_dentry_operations;
47extern const struct dentry_operations v9fs_cached_dentry_operations; 50extern const struct dentry_operations v9fs_cached_dentry_operations;
51extern const struct file_operations v9fs_cached_file_operations;
52extern const struct file_operations v9fs_cached_file_operations_dotl;
53extern struct kmem_cache *v9fs_inode_cache;
48 54
49#ifdef CONFIG_9P_FSCACHE
50struct inode *v9fs_alloc_inode(struct super_block *sb); 55struct inode *v9fs_alloc_inode(struct super_block *sb);
51void v9fs_destroy_inode(struct inode *inode); 56void v9fs_destroy_inode(struct inode *inode);
52#endif
53
54struct inode *v9fs_get_inode(struct super_block *sb, int mode); 57struct inode *v9fs_get_inode(struct super_block *sb, int mode);
58int v9fs_init_inode(struct v9fs_session_info *v9ses,
59 struct inode *inode, int mode);
55void v9fs_evict_inode(struct inode *inode); 60void v9fs_evict_inode(struct inode *inode);
56ino_t v9fs_qid2ino(struct p9_qid *qid); 61ino_t v9fs_qid2ino(struct p9_qid *qid);
57void v9fs_stat2inode(struct p9_wstat *, struct inode *, struct super_block *); 62void v9fs_stat2inode(struct p9_wstat *, struct inode *, struct super_block *);
@@ -62,8 +67,19 @@ void v9fs_inode2stat(struct inode *inode, struct p9_wstat *stat);
62int v9fs_uflags2omode(int uflags, int extended); 67int v9fs_uflags2omode(int uflags, int extended);
63 68
64ssize_t v9fs_file_readn(struct file *, char *, char __user *, u32, u64); 69ssize_t v9fs_file_readn(struct file *, char *, char __user *, u32, u64);
70ssize_t v9fs_fid_readn(struct p9_fid *, char *, char __user *, u32, u64);
65void v9fs_blank_wstat(struct p9_wstat *wstat); 71void v9fs_blank_wstat(struct p9_wstat *wstat);
66int v9fs_vfs_setattr_dotl(struct dentry *, struct iattr *); 72int v9fs_vfs_setattr_dotl(struct dentry *, struct iattr *);
67int v9fs_file_fsync_dotl(struct file *filp, int datasync); 73int v9fs_file_fsync_dotl(struct file *filp, int datasync);
68 74ssize_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);
76int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode);
77int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode);
78static 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 51static int v9fs_fid_readpage(struct p9_fid *fid, struct page *page)
51static 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
97static 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
138static void v9fs_invalidate_page(struct page *page, unsigned long offset) 150static 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
160static 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
199static 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
152static int v9fs_launder_page(struct page *page) 224static 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 */
176ssize_t v9fs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, 257static ssize_t
177 loff_t pos, unsigned long nr_segs) 258v9fs_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
274static 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);
285start:
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;
302out:
303 *pagep = page;
304 return retval;
305}
306
307static 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
186const struct address_space_operations v9fs_addr_operations = { 342const 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
71static int v9fs_cached_dentry_delete(const struct dentry *dentry) 67static 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
103static 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 }
132out_valid:
133 return 1;
134}
135
108const struct dentry_operations v9fs_cached_dentry_operations = { 136const 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
47static const struct file_operations v9fs_cached_file_operations; 47static const struct vm_operations_struct v9fs_file_vm_ops;
48static 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;
57int v9fs_file_open(struct inode *inode, struct file *file) 56int 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;
113out_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
347ssize_t 357ssize_t
348v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count, 358v9fs_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 */
398ssize_t
399v9fs_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/** 437ssize_t
414 * v9fs_file_write - write to a file 438v9fs_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
422static ssize_t
423v9fs_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 */
488static ssize_t
489v9fs_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);
475out: 510out:
476 return retval; 511 return retval;
477} 512}
478 513
514
479static int v9fs_file_fsync(struct file *filp, int datasync) 515static 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
508static const struct file_operations v9fs_cached_file_operations = { 544static int
545v9fs_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
556static int
557v9fs_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;
577out_unlock:
578 unlock_page(page);
579 return VM_FAULT_NOPAGE;
580}
581
582static ssize_t
583v9fs_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 */
611static ssize_t
612v9fs_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
620static ssize_t
621v9fs_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);
663err_out:
664 mutex_unlock(&inode->i_mutex);
665 return retval;
666
667buff_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 */
680static ssize_t
681v9fs_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
690static const struct vm_operations_struct v9fs_file_vm_ops = {
691 .fault = filemap_fault,
692 .page_mkwrite = v9fs_vm_page_mkwrite,
693};
694
695
696const 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
520static const struct file_operations v9fs_cached_file_operations_dotl = { 709const 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
214struct inode *v9fs_alloc_inode(struct super_block *sb) 210struct 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
240void v9fs_destroy_inode(struct inode *inode) 239void 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/** 244int 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
253struct 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 }
326error:
327 return err;
338 328
339 return inode; 329}
340 330
341error: 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
338struct 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 */
404void v9fs_evict_inode(struct inode *inode) 417void 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
415struct inode * 435static struct inode *v9fs_qid_iget(struct super_block *sb,
416v9fs_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;
444error: 467error:
468 unlock_new_inode(inode);
469 iput(inode);
470 return ERR_PTR(retval);
471
472}
473
474struct inode *
475v9fs_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:
458static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir) 499static 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
747v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, 825v9fs_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
800clunk_newdir: 880clunk_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 }
1190clunk_fid: 1301clunk_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
1351int 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
1240static const struct inode_operations v9fs_dir_inode_operations_dotu = { 1377static 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
89static 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;
125error:
126 unlock_new_inode(inode);
127 iput(inode);
128 return ERR_PTR(retval);
129
130}
131
89struct inode * 132struct inode *
90v9fs_inode_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid, 133v9fs_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;
120error:
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
231error: 276error:
@@ -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);
331error: 377error:
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)
439void 490void
440v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode) 491v9fs_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
502static int 555static int
503v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry, 556v9fs_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
828int 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
785const struct inode_operations v9fs_dir_inode_operations_dotl = { 853const 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
201release_sb: 213release_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
288static 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
296static 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
279static const struct super_operations v9fs_super_ops = { 310static 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
290static const struct super_operations v9fs_super_ops_dotl = { 319static 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
141enum p9_msg_t { 141enum 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);
231int p9_client_clunk(struct p9_fid *fid); 231int p9_client_clunk(struct p9_fid *fid);
232int p9_client_fsync(struct p9_fid *fid, int datasync); 232int p9_client_fsync(struct p9_fid *fid, int datasync);
233int p9_client_sync_fs(struct p9_fid *fid);
233int p9_client_remove(struct p9_fid *fid); 234int p9_client_remove(struct p9_fid *fid);
234int p9_client_read(struct p9_fid *fid, char *data, char __user *udata, 235int 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
139pnet_virtio-objs := \ 149pnet_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}
1192EXPORT_SYMBOL(p9_client_fsync); 1221EXPORT_SYMBOL(p9_client_fsync);
1193 1222
1223int 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);
1239error:
1240 return err;
1241}
1242EXPORT_SYMBOL(p9_client_sync_fs);
1243
1194int p9_client_clunk(struct p9_fid *fid) 1244int 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
117static size_t
118pdu_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
128static size_t
129pdu_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
580int p9pdu_prepare(struct p9_fcall *pdu, int16_t tag, int8_t type) 619int 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
611int p9dirent_read(char *buf, int len, struct p9_dirent *dirent, 655int 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 */
26void
27p9_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}
36EXPORT_SYMBOL(p9_release_req_pages);
37
38/**
39 * p9_nr_pages - Return number of pages needed to accomodate the payload.
40 */
41int
42p9_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}
50EXPORT_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 */
61int
62p9_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}
97EXPORT_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 */
24struct trans_rpage_info {
25 u8 rp_alloc;
26 int rp_nr_pages;
27 struct page *rp_data[0];
28};
29
30void p9_release_req_pages(struct trans_rpage_info *);
31int p9_payload_gup(struct p9_req_t *, size_t *, int *, int, u8);
32int 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 */
223static int
224pack_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)
212static int 253static int
213p9_virtio_request(struct p9_client *client, struct p9_req_t *req) 254p9_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
223req_retry: 266req_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};