diff options
author | Dave Jones <davej@redhat.com> | 2006-12-12 17:41:41 -0500 |
---|---|---|
committer | Dave Jones <davej@redhat.com> | 2006-12-12 17:41:41 -0500 |
commit | c4366889dda8110247be59ca41fddb82951a8c26 (patch) | |
tree | 705c1a996bed8fd48ce94ff33ec9fd00f9b94875 /fs/fuse | |
parent | db2fb9db5735cc532fd4fc55e94b9a3c3750378e (diff) | |
parent | e1036502e5263851259d147771226161e5ccc85a (diff) |
Merge ../linus
Conflicts:
drivers/cpufreq/cpufreq.c
Diffstat (limited to 'fs/fuse')
-rw-r--r-- | fs/fuse/control.c | 2 | ||||
-rw-r--r-- | fs/fuse/dev.c | 4 | ||||
-rw-r--r-- | fs/fuse/dir.c | 166 | ||||
-rw-r--r-- | fs/fuse/file.c | 76 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 12 | ||||
-rw-r--r-- | fs/fuse/inode.c | 138 |
6 files changed, 300 insertions, 98 deletions
diff --git a/fs/fuse/control.c b/fs/fuse/control.c index 16b39c053d..8c58bd4539 100644 --- a/fs/fuse/control.c +++ b/fs/fuse/control.c | |||
@@ -23,7 +23,7 @@ static struct fuse_conn *fuse_ctl_file_conn_get(struct file *file) | |||
23 | { | 23 | { |
24 | struct fuse_conn *fc; | 24 | struct fuse_conn *fc; |
25 | mutex_lock(&fuse_mutex); | 25 | mutex_lock(&fuse_mutex); |
26 | fc = file->f_dentry->d_inode->i_private; | 26 | fc = file->f_path.dentry->d_inode->i_private; |
27 | if (fc) | 27 | if (fc) |
28 | fc = fuse_conn_get(fc); | 28 | fc = fuse_conn_get(fc); |
29 | mutex_unlock(&fuse_mutex); | 29 | mutex_unlock(&fuse_mutex); |
diff --git a/fs/fuse/dev.c b/fs/fuse/dev.c index 66571eafbb..357764d85f 100644 --- a/fs/fuse/dev.c +++ b/fs/fuse/dev.c | |||
@@ -19,7 +19,7 @@ | |||
19 | 19 | ||
20 | MODULE_ALIAS_MISCDEV(FUSE_MINOR); | 20 | MODULE_ALIAS_MISCDEV(FUSE_MINOR); |
21 | 21 | ||
22 | static kmem_cache_t *fuse_req_cachep; | 22 | static struct kmem_cache *fuse_req_cachep; |
23 | 23 | ||
24 | static struct fuse_conn *fuse_get_conn(struct file *file) | 24 | static struct fuse_conn *fuse_get_conn(struct file *file) |
25 | { | 25 | { |
@@ -41,7 +41,7 @@ static void fuse_request_init(struct fuse_req *req) | |||
41 | 41 | ||
42 | struct fuse_req *fuse_request_alloc(void) | 42 | struct fuse_req *fuse_request_alloc(void) |
43 | { | 43 | { |
44 | struct fuse_req *req = kmem_cache_alloc(fuse_req_cachep, SLAB_KERNEL); | 44 | struct fuse_req *req = kmem_cache_alloc(fuse_req_cachep, GFP_KERNEL); |
45 | if (req) | 45 | if (req) |
46 | fuse_request_init(req); | 46 | fuse_request_init(req); |
47 | return req; | 47 | return req; |
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 8605155db1..40080477ce 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -138,9 +138,8 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | |||
138 | struct fuse_entry_out outarg; | 138 | struct fuse_entry_out outarg; |
139 | struct fuse_conn *fc; | 139 | struct fuse_conn *fc; |
140 | struct fuse_req *req; | 140 | struct fuse_req *req; |
141 | 141 | struct fuse_req *forget_req; | |
142 | /* Doesn't hurt to "reset" the validity timeout */ | 142 | struct dentry *parent; |
143 | fuse_invalidate_entry_cache(entry); | ||
144 | 143 | ||
145 | /* For negative dentries, always do a fresh lookup */ | 144 | /* For negative dentries, always do a fresh lookup */ |
146 | if (!inode) | 145 | if (!inode) |
@@ -151,21 +150,33 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | |||
151 | if (IS_ERR(req)) | 150 | if (IS_ERR(req)) |
152 | return 0; | 151 | return 0; |
153 | 152 | ||
154 | fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg); | 153 | forget_req = fuse_get_req(fc); |
154 | if (IS_ERR(forget_req)) { | ||
155 | fuse_put_request(fc, req); | ||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | parent = dget_parent(entry); | ||
160 | fuse_lookup_init(req, parent->d_inode, entry, &outarg); | ||
155 | request_send(fc, req); | 161 | request_send(fc, req); |
162 | dput(parent); | ||
156 | err = req->out.h.error; | 163 | err = req->out.h.error; |
164 | fuse_put_request(fc, req); | ||
157 | /* Zero nodeid is same as -ENOENT */ | 165 | /* Zero nodeid is same as -ENOENT */ |
158 | if (!err && !outarg.nodeid) | 166 | if (!err && !outarg.nodeid) |
159 | err = -ENOENT; | 167 | err = -ENOENT; |
160 | if (!err) { | 168 | if (!err) { |
161 | struct fuse_inode *fi = get_fuse_inode(inode); | 169 | struct fuse_inode *fi = get_fuse_inode(inode); |
162 | if (outarg.nodeid != get_node_id(inode)) { | 170 | if (outarg.nodeid != get_node_id(inode)) { |
163 | fuse_send_forget(fc, req, outarg.nodeid, 1); | 171 | fuse_send_forget(fc, forget_req, |
172 | outarg.nodeid, 1); | ||
164 | return 0; | 173 | return 0; |
165 | } | 174 | } |
175 | spin_lock(&fc->lock); | ||
166 | fi->nlookup ++; | 176 | fi->nlookup ++; |
177 | spin_unlock(&fc->lock); | ||
167 | } | 178 | } |
168 | fuse_put_request(fc, req); | 179 | fuse_put_request(fc, forget_req); |
169 | if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT) | 180 | if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT) |
170 | return 0; | 181 | return 0; |
171 | 182 | ||
@@ -175,22 +186,6 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | |||
175 | return 1; | 186 | return 1; |
176 | } | 187 | } |
177 | 188 | ||
178 | /* | ||
179 | * Check if there's already a hashed alias of this directory inode. | ||
180 | * If yes, then lookup and mkdir must not create a new alias. | ||
181 | */ | ||
182 | static int dir_alias(struct inode *inode) | ||
183 | { | ||
184 | if (S_ISDIR(inode->i_mode)) { | ||
185 | struct dentry *alias = d_find_alias(inode); | ||
186 | if (alias) { | ||
187 | dput(alias); | ||
188 | return 1; | ||
189 | } | ||
190 | } | ||
191 | return 0; | ||
192 | } | ||
193 | |||
194 | static int invalid_nodeid(u64 nodeid) | 189 | static int invalid_nodeid(u64 nodeid) |
195 | { | 190 | { |
196 | return !nodeid || nodeid == FUSE_ROOT_ID; | 191 | return !nodeid || nodeid == FUSE_ROOT_ID; |
@@ -206,6 +201,24 @@ static int valid_mode(int m) | |||
206 | S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m); | 201 | S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m); |
207 | } | 202 | } |
208 | 203 | ||
204 | /* | ||
205 | * Add a directory inode to a dentry, ensuring that no other dentry | ||
206 | * refers to this inode. Called with fc->inst_mutex. | ||
207 | */ | ||
208 | static int fuse_d_add_directory(struct dentry *entry, struct inode *inode) | ||
209 | { | ||
210 | struct dentry *alias = d_find_alias(inode); | ||
211 | if (alias) { | ||
212 | /* This tries to shrink the subtree below alias */ | ||
213 | fuse_invalidate_entry(alias); | ||
214 | dput(alias); | ||
215 | if (!list_empty(&inode->i_dentry)) | ||
216 | return -EBUSY; | ||
217 | } | ||
218 | d_add(entry, inode); | ||
219 | return 0; | ||
220 | } | ||
221 | |||
209 | static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | 222 | static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, |
210 | struct nameidata *nd) | 223 | struct nameidata *nd) |
211 | { | 224 | { |
@@ -214,6 +227,7 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | |||
214 | struct inode *inode = NULL; | 227 | struct inode *inode = NULL; |
215 | struct fuse_conn *fc = get_fuse_conn(dir); | 228 | struct fuse_conn *fc = get_fuse_conn(dir); |
216 | struct fuse_req *req; | 229 | struct fuse_req *req; |
230 | struct fuse_req *forget_req; | ||
217 | 231 | ||
218 | if (entry->d_name.len > FUSE_NAME_MAX) | 232 | if (entry->d_name.len > FUSE_NAME_MAX) |
219 | return ERR_PTR(-ENAMETOOLONG); | 233 | return ERR_PTR(-ENAMETOOLONG); |
@@ -222,9 +236,16 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | |||
222 | if (IS_ERR(req)) | 236 | if (IS_ERR(req)) |
223 | return ERR_PTR(PTR_ERR(req)); | 237 | return ERR_PTR(PTR_ERR(req)); |
224 | 238 | ||
239 | forget_req = fuse_get_req(fc); | ||
240 | if (IS_ERR(forget_req)) { | ||
241 | fuse_put_request(fc, req); | ||
242 | return ERR_PTR(PTR_ERR(forget_req)); | ||
243 | } | ||
244 | |||
225 | fuse_lookup_init(req, dir, entry, &outarg); | 245 | fuse_lookup_init(req, dir, entry, &outarg); |
226 | request_send(fc, req); | 246 | request_send(fc, req); |
227 | err = req->out.h.error; | 247 | err = req->out.h.error; |
248 | fuse_put_request(fc, req); | ||
228 | /* Zero nodeid is same as -ENOENT, but with valid timeout */ | 249 | /* Zero nodeid is same as -ENOENT, but with valid timeout */ |
229 | if (!err && outarg.nodeid && | 250 | if (!err && outarg.nodeid && |
230 | (invalid_nodeid(outarg.nodeid) || !valid_mode(outarg.attr.mode))) | 251 | (invalid_nodeid(outarg.nodeid) || !valid_mode(outarg.attr.mode))) |
@@ -233,19 +254,25 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | |||
233 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, | 254 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, |
234 | &outarg.attr); | 255 | &outarg.attr); |
235 | if (!inode) { | 256 | if (!inode) { |
236 | fuse_send_forget(fc, req, outarg.nodeid, 1); | 257 | fuse_send_forget(fc, forget_req, outarg.nodeid, 1); |
237 | return ERR_PTR(-ENOMEM); | 258 | return ERR_PTR(-ENOMEM); |
238 | } | 259 | } |
239 | } | 260 | } |
240 | fuse_put_request(fc, req); | 261 | fuse_put_request(fc, forget_req); |
241 | if (err && err != -ENOENT) | 262 | if (err && err != -ENOENT) |
242 | return ERR_PTR(err); | 263 | return ERR_PTR(err); |
243 | 264 | ||
244 | if (inode && dir_alias(inode)) { | 265 | if (inode && S_ISDIR(inode->i_mode)) { |
245 | iput(inode); | 266 | mutex_lock(&fc->inst_mutex); |
246 | return ERR_PTR(-EIO); | 267 | err = fuse_d_add_directory(entry, inode); |
247 | } | 268 | mutex_unlock(&fc->inst_mutex); |
248 | d_add(entry, inode); | 269 | if (err) { |
270 | iput(inode); | ||
271 | return ERR_PTR(err); | ||
272 | } | ||
273 | } else | ||
274 | d_add(entry, inode); | ||
275 | |||
249 | entry->d_op = &fuse_dentry_operations; | 276 | entry->d_op = &fuse_dentry_operations; |
250 | if (!err) | 277 | if (!err) |
251 | fuse_change_timeout(entry, &outarg); | 278 | fuse_change_timeout(entry, &outarg); |
@@ -375,6 +402,13 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, | |||
375 | struct fuse_entry_out outarg; | 402 | struct fuse_entry_out outarg; |
376 | struct inode *inode; | 403 | struct inode *inode; |
377 | int err; | 404 | int err; |
405 | struct fuse_req *forget_req; | ||
406 | |||
407 | forget_req = fuse_get_req(fc); | ||
408 | if (IS_ERR(forget_req)) { | ||
409 | fuse_put_request(fc, req); | ||
410 | return PTR_ERR(forget_req); | ||
411 | } | ||
378 | 412 | ||
379 | req->in.h.nodeid = get_node_id(dir); | 413 | req->in.h.nodeid = get_node_id(dir); |
380 | req->out.numargs = 1; | 414 | req->out.numargs = 1; |
@@ -382,37 +416,47 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, | |||
382 | req->out.args[0].value = &outarg; | 416 | req->out.args[0].value = &outarg; |
383 | request_send(fc, req); | 417 | request_send(fc, req); |
384 | err = req->out.h.error; | 418 | err = req->out.h.error; |
385 | if (err) { | 419 | fuse_put_request(fc, req); |
386 | fuse_put_request(fc, req); | 420 | if (err) |
387 | return err; | 421 | goto out_put_forget_req; |
388 | } | 422 | |
389 | err = -EIO; | 423 | err = -EIO; |
390 | if (invalid_nodeid(outarg.nodeid)) | 424 | if (invalid_nodeid(outarg.nodeid)) |
391 | goto out_put_request; | 425 | goto out_put_forget_req; |
392 | 426 | ||
393 | if ((outarg.attr.mode ^ mode) & S_IFMT) | 427 | if ((outarg.attr.mode ^ mode) & S_IFMT) |
394 | goto out_put_request; | 428 | goto out_put_forget_req; |
395 | 429 | ||
396 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, | 430 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, |
397 | &outarg.attr); | 431 | &outarg.attr); |
398 | if (!inode) { | 432 | if (!inode) { |
399 | fuse_send_forget(fc, req, outarg.nodeid, 1); | 433 | fuse_send_forget(fc, forget_req, outarg.nodeid, 1); |
400 | return -ENOMEM; | 434 | return -ENOMEM; |
401 | } | 435 | } |
402 | fuse_put_request(fc, req); | 436 | fuse_put_request(fc, forget_req); |
403 | 437 | ||
404 | if (dir_alias(inode)) { | 438 | if (S_ISDIR(inode->i_mode)) { |
405 | iput(inode); | 439 | struct dentry *alias; |
406 | return -EIO; | 440 | mutex_lock(&fc->inst_mutex); |
407 | } | 441 | alias = d_find_alias(inode); |
442 | if (alias) { | ||
443 | /* New directory must have moved since mkdir */ | ||
444 | mutex_unlock(&fc->inst_mutex); | ||
445 | dput(alias); | ||
446 | iput(inode); | ||
447 | return -EBUSY; | ||
448 | } | ||
449 | d_instantiate(entry, inode); | ||
450 | mutex_unlock(&fc->inst_mutex); | ||
451 | } else | ||
452 | d_instantiate(entry, inode); | ||
408 | 453 | ||
409 | d_instantiate(entry, inode); | ||
410 | fuse_change_timeout(entry, &outarg); | 454 | fuse_change_timeout(entry, &outarg); |
411 | fuse_invalidate_attr(dir); | 455 | fuse_invalidate_attr(dir); |
412 | return 0; | 456 | return 0; |
413 | 457 | ||
414 | out_put_request: | 458 | out_put_forget_req: |
415 | fuse_put_request(fc, req); | 459 | fuse_put_request(fc, forget_req); |
416 | return err; | 460 | return err; |
417 | } | 461 | } |
418 | 462 | ||
@@ -812,7 +856,7 @@ static int fuse_readdir(struct file *file, void *dstbuf, filldir_t filldir) | |||
812 | int err; | 856 | int err; |
813 | size_t nbytes; | 857 | size_t nbytes; |
814 | struct page *page; | 858 | struct page *page; |
815 | struct inode *inode = file->f_dentry->d_inode; | 859 | struct inode *inode = file->f_path.dentry->d_inode; |
816 | struct fuse_conn *fc = get_fuse_conn(inode); | 860 | struct fuse_conn *fc = get_fuse_conn(inode); |
817 | struct fuse_req *req; | 861 | struct fuse_req *req; |
818 | 862 | ||
@@ -935,14 +979,30 @@ static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg) | |||
935 | } | 979 | } |
936 | } | 980 | } |
937 | 981 | ||
982 | static void fuse_vmtruncate(struct inode *inode, loff_t offset) | ||
983 | { | ||
984 | struct fuse_conn *fc = get_fuse_conn(inode); | ||
985 | int need_trunc; | ||
986 | |||
987 | spin_lock(&fc->lock); | ||
988 | need_trunc = inode->i_size > offset; | ||
989 | i_size_write(inode, offset); | ||
990 | spin_unlock(&fc->lock); | ||
991 | |||
992 | if (need_trunc) { | ||
993 | struct address_space *mapping = inode->i_mapping; | ||
994 | unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); | ||
995 | truncate_inode_pages(mapping, offset); | ||
996 | } | ||
997 | } | ||
998 | |||
938 | /* | 999 | /* |
939 | * Set attributes, and at the same time refresh them. | 1000 | * Set attributes, and at the same time refresh them. |
940 | * | 1001 | * |
941 | * Truncation is slightly complicated, because the 'truncate' request | 1002 | * Truncation is slightly complicated, because the 'truncate' request |
942 | * may fail, in which case we don't want to touch the mapping. | 1003 | * may fail, in which case we don't want to touch the mapping. |
943 | * vmtruncate() doesn't allow for this case. So do the rlimit | 1004 | * vmtruncate() doesn't allow for this case, so do the rlimit checking |
944 | * checking by hand and call vmtruncate() only after the file has | 1005 | * and the actual truncation by hand. |
945 | * actually been truncated. | ||
946 | */ | 1006 | */ |
947 | static int fuse_setattr(struct dentry *entry, struct iattr *attr) | 1007 | static int fuse_setattr(struct dentry *entry, struct iattr *attr) |
948 | { | 1008 | { |
@@ -964,6 +1024,8 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr) | |||
964 | if (attr->ia_valid & ATTR_SIZE) { | 1024 | if (attr->ia_valid & ATTR_SIZE) { |
965 | unsigned long limit; | 1025 | unsigned long limit; |
966 | is_truncate = 1; | 1026 | is_truncate = 1; |
1027 | if (IS_SWAPFILE(inode)) | ||
1028 | return -ETXTBSY; | ||
967 | limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; | 1029 | limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; |
968 | if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) { | 1030 | if (limit != RLIM_INFINITY && attr->ia_size > (loff_t) limit) { |
969 | send_sig(SIGXFSZ, current, 0); | 1031 | send_sig(SIGXFSZ, current, 0); |
@@ -993,12 +1055,8 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr) | |||
993 | make_bad_inode(inode); | 1055 | make_bad_inode(inode); |
994 | err = -EIO; | 1056 | err = -EIO; |
995 | } else { | 1057 | } else { |
996 | if (is_truncate) { | 1058 | if (is_truncate) |
997 | loff_t origsize = i_size_read(inode); | 1059 | fuse_vmtruncate(inode, outarg.attr.size); |
998 | i_size_write(inode, outarg.attr.size); | ||
999 | if (origsize > outarg.attr.size) | ||
1000 | vmtruncate(inode, outarg.attr.size); | ||
1001 | } | ||
1002 | fuse_change_attributes(inode, &outarg.attr); | 1060 | fuse_change_attributes(inode, &outarg.attr); |
1003 | fi->i_time = time_to_jiffies(outarg.attr_valid, | 1061 | fi->i_time = time_to_jiffies(outarg.attr_valid, |
1004 | outarg.attr_valid_nsec); | 1062 | outarg.attr_valid_nsec); |
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 183626868e..1387749201 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -141,8 +141,8 @@ int fuse_release_common(struct inode *inode, struct file *file, int isdir) | |||
141 | isdir ? FUSE_RELEASEDIR : FUSE_RELEASE); | 141 | isdir ? FUSE_RELEASEDIR : FUSE_RELEASE); |
142 | 142 | ||
143 | /* Hold vfsmount and dentry until release is finished */ | 143 | /* Hold vfsmount and dentry until release is finished */ |
144 | req->vfsmount = mntget(file->f_vfsmnt); | 144 | req->vfsmount = mntget(file->f_path.mnt); |
145 | req->dentry = dget(file->f_dentry); | 145 | req->dentry = dget(file->f_path.dentry); |
146 | request_send_background(fc, req); | 146 | request_send_background(fc, req); |
147 | } | 147 | } |
148 | 148 | ||
@@ -184,7 +184,7 @@ static u64 fuse_lock_owner_id(struct fuse_conn *fc, fl_owner_t id) | |||
184 | 184 | ||
185 | static int fuse_flush(struct file *file, fl_owner_t id) | 185 | static int fuse_flush(struct file *file, fl_owner_t id) |
186 | { | 186 | { |
187 | struct inode *inode = file->f_dentry->d_inode; | 187 | struct inode *inode = file->f_path.dentry->d_inode; |
188 | struct fuse_conn *fc = get_fuse_conn(inode); | 188 | struct fuse_conn *fc = get_fuse_conn(inode); |
189 | struct fuse_file *ff = file->private_data; | 189 | struct fuse_file *ff = file->private_data; |
190 | struct fuse_req *req; | 190 | struct fuse_req *req; |
@@ -397,14 +397,14 @@ static int fuse_readpages(struct file *file, struct address_space *mapping, | |||
397 | 397 | ||
398 | err = -EIO; | 398 | err = -EIO; |
399 | if (is_bad_inode(inode)) | 399 | if (is_bad_inode(inode)) |
400 | goto clean_pages_up; | 400 | goto out; |
401 | 401 | ||
402 | data.file = file; | 402 | data.file = file; |
403 | data.inode = inode; | 403 | data.inode = inode; |
404 | data.req = fuse_get_req(fc); | 404 | data.req = fuse_get_req(fc); |
405 | err = PTR_ERR(data.req); | 405 | err = PTR_ERR(data.req); |
406 | if (IS_ERR(data.req)) | 406 | if (IS_ERR(data.req)) |
407 | goto clean_pages_up; | 407 | goto out; |
408 | 408 | ||
409 | err = read_cache_pages(mapping, pages, fuse_readpages_fill, &data); | 409 | err = read_cache_pages(mapping, pages, fuse_readpages_fill, &data); |
410 | if (!err) { | 410 | if (!err) { |
@@ -413,10 +413,7 @@ static int fuse_readpages(struct file *file, struct address_space *mapping, | |||
413 | else | 413 | else |
414 | fuse_put_request(fc, data.req); | 414 | fuse_put_request(fc, data.req); |
415 | } | 415 | } |
416 | return err; | 416 | out: |
417 | |||
418 | clean_pages_up: | ||
419 | put_pages_list(pages); | ||
420 | return err; | 417 | return err; |
421 | } | 418 | } |
422 | 419 | ||
@@ -481,8 +478,10 @@ static int fuse_commit_write(struct file *file, struct page *page, | |||
481 | err = -EIO; | 478 | err = -EIO; |
482 | if (!err) { | 479 | if (!err) { |
483 | pos += count; | 480 | pos += count; |
484 | if (pos > i_size_read(inode)) | 481 | spin_lock(&fc->lock); |
482 | if (pos > inode->i_size) | ||
485 | i_size_write(inode, pos); | 483 | i_size_write(inode, pos); |
484 | spin_unlock(&fc->lock); | ||
486 | 485 | ||
487 | if (offset == 0 && to == PAGE_CACHE_SIZE) { | 486 | if (offset == 0 && to == PAGE_CACHE_SIZE) { |
488 | clear_page_dirty(page); | 487 | clear_page_dirty(page); |
@@ -534,7 +533,7 @@ static int fuse_get_user_pages(struct fuse_req *req, const char __user *buf, | |||
534 | static ssize_t fuse_direct_io(struct file *file, const char __user *buf, | 533 | static ssize_t fuse_direct_io(struct file *file, const char __user *buf, |
535 | size_t count, loff_t *ppos, int write) | 534 | size_t count, loff_t *ppos, int write) |
536 | { | 535 | { |
537 | struct inode *inode = file->f_dentry->d_inode; | 536 | struct inode *inode = file->f_path.dentry->d_inode; |
538 | struct fuse_conn *fc = get_fuse_conn(inode); | 537 | struct fuse_conn *fc = get_fuse_conn(inode); |
539 | size_t nmax = write ? fc->max_write : fc->max_read; | 538 | size_t nmax = write ? fc->max_write : fc->max_read; |
540 | loff_t pos = *ppos; | 539 | loff_t pos = *ppos; |
@@ -586,8 +585,12 @@ static ssize_t fuse_direct_io(struct file *file, const char __user *buf, | |||
586 | } | 585 | } |
587 | fuse_put_request(fc, req); | 586 | fuse_put_request(fc, req); |
588 | if (res > 0) { | 587 | if (res > 0) { |
589 | if (write && pos > i_size_read(inode)) | 588 | if (write) { |
590 | i_size_write(inode, pos); | 589 | spin_lock(&fc->lock); |
590 | if (pos > inode->i_size) | ||
591 | i_size_write(inode, pos); | ||
592 | spin_unlock(&fc->lock); | ||
593 | } | ||
591 | *ppos = pos; | 594 | *ppos = pos; |
592 | } | 595 | } |
593 | fuse_invalidate_attr(inode); | 596 | fuse_invalidate_attr(inode); |
@@ -604,7 +607,7 @@ static ssize_t fuse_direct_read(struct file *file, char __user *buf, | |||
604 | static ssize_t fuse_direct_write(struct file *file, const char __user *buf, | 607 | static ssize_t fuse_direct_write(struct file *file, const char __user *buf, |
605 | size_t count, loff_t *ppos) | 608 | size_t count, loff_t *ppos) |
606 | { | 609 | { |
607 | struct inode *inode = file->f_dentry->d_inode; | 610 | struct inode *inode = file->f_path.dentry->d_inode; |
608 | ssize_t res; | 611 | ssize_t res; |
609 | /* Don't allow parallel writes to the same file */ | 612 | /* Don't allow parallel writes to the same file */ |
610 | mutex_lock(&inode->i_mutex); | 613 | mutex_lock(&inode->i_mutex); |
@@ -659,7 +662,7 @@ static int convert_fuse_file_lock(const struct fuse_file_lock *ffl, | |||
659 | static void fuse_lk_fill(struct fuse_req *req, struct file *file, | 662 | static void fuse_lk_fill(struct fuse_req *req, struct file *file, |
660 | const struct file_lock *fl, int opcode, pid_t pid) | 663 | const struct file_lock *fl, int opcode, pid_t pid) |
661 | { | 664 | { |
662 | struct inode *inode = file->f_dentry->d_inode; | 665 | struct inode *inode = file->f_path.dentry->d_inode; |
663 | struct fuse_conn *fc = get_fuse_conn(inode); | 666 | struct fuse_conn *fc = get_fuse_conn(inode); |
664 | struct fuse_file *ff = file->private_data; | 667 | struct fuse_file *ff = file->private_data; |
665 | struct fuse_lk_in *arg = &req->misc.lk_in; | 668 | struct fuse_lk_in *arg = &req->misc.lk_in; |
@@ -679,7 +682,7 @@ static void fuse_lk_fill(struct fuse_req *req, struct file *file, | |||
679 | 682 | ||
680 | static int fuse_getlk(struct file *file, struct file_lock *fl) | 683 | static int fuse_getlk(struct file *file, struct file_lock *fl) |
681 | { | 684 | { |
682 | struct inode *inode = file->f_dentry->d_inode; | 685 | struct inode *inode = file->f_path.dentry->d_inode; |
683 | struct fuse_conn *fc = get_fuse_conn(inode); | 686 | struct fuse_conn *fc = get_fuse_conn(inode); |
684 | struct fuse_req *req; | 687 | struct fuse_req *req; |
685 | struct fuse_lk_out outarg; | 688 | struct fuse_lk_out outarg; |
@@ -704,7 +707,7 @@ static int fuse_getlk(struct file *file, struct file_lock *fl) | |||
704 | 707 | ||
705 | static int fuse_setlk(struct file *file, struct file_lock *fl) | 708 | static int fuse_setlk(struct file *file, struct file_lock *fl) |
706 | { | 709 | { |
707 | struct inode *inode = file->f_dentry->d_inode; | 710 | struct inode *inode = file->f_path.dentry->d_inode; |
708 | struct fuse_conn *fc = get_fuse_conn(inode); | 711 | struct fuse_conn *fc = get_fuse_conn(inode); |
709 | struct fuse_req *req; | 712 | struct fuse_req *req; |
710 | int opcode = (fl->fl_flags & FL_SLEEP) ? FUSE_SETLKW : FUSE_SETLK; | 713 | int opcode = (fl->fl_flags & FL_SLEEP) ? FUSE_SETLKW : FUSE_SETLK; |
@@ -731,7 +734,7 @@ static int fuse_setlk(struct file *file, struct file_lock *fl) | |||
731 | 734 | ||
732 | static int fuse_file_lock(struct file *file, int cmd, struct file_lock *fl) | 735 | static int fuse_file_lock(struct file *file, int cmd, struct file_lock *fl) |
733 | { | 736 | { |
734 | struct inode *inode = file->f_dentry->d_inode; | 737 | struct inode *inode = file->f_path.dentry->d_inode; |
735 | struct fuse_conn *fc = get_fuse_conn(inode); | 738 | struct fuse_conn *fc = get_fuse_conn(inode); |
736 | int err; | 739 | int err; |
737 | 740 | ||
@@ -751,6 +754,42 @@ static int fuse_file_lock(struct file *file, int cmd, struct file_lock *fl) | |||
751 | return err; | 754 | return err; |
752 | } | 755 | } |
753 | 756 | ||
757 | static sector_t fuse_bmap(struct address_space *mapping, sector_t block) | ||
758 | { | ||
759 | struct inode *inode = mapping->host; | ||
760 | struct fuse_conn *fc = get_fuse_conn(inode); | ||
761 | struct fuse_req *req; | ||
762 | struct fuse_bmap_in inarg; | ||
763 | struct fuse_bmap_out outarg; | ||
764 | int err; | ||
765 | |||
766 | if (!inode->i_sb->s_bdev || fc->no_bmap) | ||
767 | return 0; | ||
768 | |||
769 | req = fuse_get_req(fc); | ||
770 | if (IS_ERR(req)) | ||
771 | return 0; | ||
772 | |||
773 | memset(&inarg, 0, sizeof(inarg)); | ||
774 | inarg.block = block; | ||
775 | inarg.blocksize = inode->i_sb->s_blocksize; | ||
776 | req->in.h.opcode = FUSE_BMAP; | ||
777 | req->in.h.nodeid = get_node_id(inode); | ||
778 | req->in.numargs = 1; | ||
779 | req->in.args[0].size = sizeof(inarg); | ||
780 | req->in.args[0].value = &inarg; | ||
781 | req->out.numargs = 1; | ||
782 | req->out.args[0].size = sizeof(outarg); | ||
783 | req->out.args[0].value = &outarg; | ||
784 | request_send(fc, req); | ||
785 | err = req->out.h.error; | ||
786 | fuse_put_request(fc, req); | ||
787 | if (err == -ENOSYS) | ||
788 | fc->no_bmap = 1; | ||
789 | |||
790 | return err ? 0 : outarg.block; | ||
791 | } | ||
792 | |||
754 | static const struct file_operations fuse_file_operations = { | 793 | static const struct file_operations fuse_file_operations = { |
755 | .llseek = generic_file_llseek, | 794 | .llseek = generic_file_llseek, |
756 | .read = do_sync_read, | 795 | .read = do_sync_read, |
@@ -784,6 +823,7 @@ static const struct address_space_operations fuse_file_aops = { | |||
784 | .commit_write = fuse_commit_write, | 823 | .commit_write = fuse_commit_write, |
785 | .readpages = fuse_readpages, | 824 | .readpages = fuse_readpages, |
786 | .set_page_dirty = fuse_set_page_dirty, | 825 | .set_page_dirty = fuse_set_page_dirty, |
826 | .bmap = fuse_bmap, | ||
787 | }; | 827 | }; |
788 | 828 | ||
789 | void fuse_init_file_inode(struct inode *inode) | 829 | void fuse_init_file_inode(struct inode *inode) |
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 69c7750d55..b98b20de74 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
@@ -239,6 +239,9 @@ struct fuse_conn { | |||
239 | /** Lock protecting accessess to members of this structure */ | 239 | /** Lock protecting accessess to members of this structure */ |
240 | spinlock_t lock; | 240 | spinlock_t lock; |
241 | 241 | ||
242 | /** Mutex protecting against directory alias creation */ | ||
243 | struct mutex inst_mutex; | ||
244 | |||
242 | /** Refcount */ | 245 | /** Refcount */ |
243 | atomic_t count; | 246 | atomic_t count; |
244 | 247 | ||
@@ -295,6 +298,9 @@ struct fuse_conn { | |||
295 | reply, before any other request, and never cleared */ | 298 | reply, before any other request, and never cleared */ |
296 | unsigned conn_error : 1; | 299 | unsigned conn_error : 1; |
297 | 300 | ||
301 | /** Connection successful. Only set in INIT */ | ||
302 | unsigned conn_init : 1; | ||
303 | |||
298 | /** Do readpages asynchronously? Only set in INIT */ | 304 | /** Do readpages asynchronously? Only set in INIT */ |
299 | unsigned async_read : 1; | 305 | unsigned async_read : 1; |
300 | 306 | ||
@@ -336,6 +342,9 @@ struct fuse_conn { | |||
336 | /** Is interrupt not implemented by fs? */ | 342 | /** Is interrupt not implemented by fs? */ |
337 | unsigned no_interrupt : 1; | 343 | unsigned no_interrupt : 1; |
338 | 344 | ||
345 | /** Is bmap not implemented by fs? */ | ||
346 | unsigned no_bmap : 1; | ||
347 | |||
339 | /** The number of requests waiting for completion */ | 348 | /** The number of requests waiting for completion */ |
340 | atomic_t num_waiting; | 349 | atomic_t num_waiting; |
341 | 350 | ||
@@ -362,6 +371,9 @@ struct fuse_conn { | |||
362 | 371 | ||
363 | /** Key for lock owner ID scrambling */ | 372 | /** Key for lock owner ID scrambling */ |
364 | u32 scramble_key[4]; | 373 | u32 scramble_key[4]; |
374 | |||
375 | /** Reserved request for the DESTROY message */ | ||
376 | struct fuse_req *destroy_req; | ||
365 | }; | 377 | }; |
366 | 378 | ||
367 | static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb) | 379 | static inline struct fuse_conn *get_fuse_conn_super(struct super_block *sb) |
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 7d0a9aee01..12450d2b32 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
@@ -22,7 +22,7 @@ MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>"); | |||
22 | MODULE_DESCRIPTION("Filesystem in Userspace"); | 22 | MODULE_DESCRIPTION("Filesystem in Userspace"); |
23 | MODULE_LICENSE("GPL"); | 23 | MODULE_LICENSE("GPL"); |
24 | 24 | ||
25 | static kmem_cache_t *fuse_inode_cachep; | 25 | static struct kmem_cache *fuse_inode_cachep; |
26 | struct list_head fuse_conn_list; | 26 | struct list_head fuse_conn_list; |
27 | DEFINE_MUTEX(fuse_mutex); | 27 | DEFINE_MUTEX(fuse_mutex); |
28 | 28 | ||
@@ -39,6 +39,7 @@ struct fuse_mount_data { | |||
39 | unsigned group_id_present : 1; | 39 | unsigned group_id_present : 1; |
40 | unsigned flags; | 40 | unsigned flags; |
41 | unsigned max_read; | 41 | unsigned max_read; |
42 | unsigned blksize; | ||
42 | }; | 43 | }; |
43 | 44 | ||
44 | static struct inode *fuse_alloc_inode(struct super_block *sb) | 45 | static struct inode *fuse_alloc_inode(struct super_block *sb) |
@@ -46,7 +47,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb) | |||
46 | struct inode *inode; | 47 | struct inode *inode; |
47 | struct fuse_inode *fi; | 48 | struct fuse_inode *fi; |
48 | 49 | ||
49 | inode = kmem_cache_alloc(fuse_inode_cachep, SLAB_KERNEL); | 50 | inode = kmem_cache_alloc(fuse_inode_cachep, GFP_KERNEL); |
50 | if (!inode) | 51 | if (!inode) |
51 | return NULL; | 52 | return NULL; |
52 | 53 | ||
@@ -109,6 +110,7 @@ static int fuse_remount_fs(struct super_block *sb, int *flags, char *data) | |||
109 | 110 | ||
110 | void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr) | 111 | void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr) |
111 | { | 112 | { |
113 | struct fuse_conn *fc = get_fuse_conn(inode); | ||
112 | if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size) | 114 | if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size) |
113 | invalidate_inode_pages(inode->i_mapping); | 115 | invalidate_inode_pages(inode->i_mapping); |
114 | 116 | ||
@@ -117,7 +119,9 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr) | |||
117 | inode->i_nlink = attr->nlink; | 119 | inode->i_nlink = attr->nlink; |
118 | inode->i_uid = attr->uid; | 120 | inode->i_uid = attr->uid; |
119 | inode->i_gid = attr->gid; | 121 | inode->i_gid = attr->gid; |
122 | spin_lock(&fc->lock); | ||
120 | i_size_write(inode, attr->size); | 123 | i_size_write(inode, attr->size); |
124 | spin_unlock(&fc->lock); | ||
121 | inode->i_blocks = attr->blocks; | 125 | inode->i_blocks = attr->blocks; |
122 | inode->i_atime.tv_sec = attr->atime; | 126 | inode->i_atime.tv_sec = attr->atime; |
123 | inode->i_atime.tv_nsec = attr->atimensec; | 127 | inode->i_atime.tv_nsec = attr->atimensec; |
@@ -130,7 +134,7 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr) | |||
130 | static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr) | 134 | static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr) |
131 | { | 135 | { |
132 | inode->i_mode = attr->mode & S_IFMT; | 136 | inode->i_mode = attr->mode & S_IFMT; |
133 | i_size_write(inode, attr->size); | 137 | inode->i_size = attr->size; |
134 | if (S_ISREG(inode->i_mode)) { | 138 | if (S_ISREG(inode->i_mode)) { |
135 | fuse_init_common(inode); | 139 | fuse_init_common(inode); |
136 | fuse_init_file_inode(inode); | 140 | fuse_init_file_inode(inode); |
@@ -169,7 +173,6 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, | |||
169 | struct inode *inode; | 173 | struct inode *inode; |
170 | struct fuse_inode *fi; | 174 | struct fuse_inode *fi; |
171 | struct fuse_conn *fc = get_fuse_conn_super(sb); | 175 | struct fuse_conn *fc = get_fuse_conn_super(sb); |
172 | int retried = 0; | ||
173 | 176 | ||
174 | retry: | 177 | retry: |
175 | inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid); | 178 | inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid); |
@@ -183,16 +186,16 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, | |||
183 | fuse_init_inode(inode, attr); | 186 | fuse_init_inode(inode, attr); |
184 | unlock_new_inode(inode); | 187 | unlock_new_inode(inode); |
185 | } else if ((inode->i_mode ^ attr->mode) & S_IFMT) { | 188 | } else if ((inode->i_mode ^ attr->mode) & S_IFMT) { |
186 | BUG_ON(retried); | ||
187 | /* Inode has changed type, any I/O on the old should fail */ | 189 | /* Inode has changed type, any I/O on the old should fail */ |
188 | make_bad_inode(inode); | 190 | make_bad_inode(inode); |
189 | iput(inode); | 191 | iput(inode); |
190 | retried = 1; | ||
191 | goto retry; | 192 | goto retry; |
192 | } | 193 | } |
193 | 194 | ||
194 | fi = get_fuse_inode(inode); | 195 | fi = get_fuse_inode(inode); |
196 | spin_lock(&fc->lock); | ||
195 | fi->nlookup ++; | 197 | fi->nlookup ++; |
198 | spin_unlock(&fc->lock); | ||
196 | fuse_change_attributes(inode, attr); | 199 | fuse_change_attributes(inode, attr); |
197 | return inode; | 200 | return inode; |
198 | } | 201 | } |
@@ -203,10 +206,23 @@ static void fuse_umount_begin(struct vfsmount *vfsmnt, int flags) | |||
203 | fuse_abort_conn(get_fuse_conn_super(vfsmnt->mnt_sb)); | 206 | fuse_abort_conn(get_fuse_conn_super(vfsmnt->mnt_sb)); |
204 | } | 207 | } |
205 | 208 | ||
209 | static void fuse_send_destroy(struct fuse_conn *fc) | ||
210 | { | ||
211 | struct fuse_req *req = fc->destroy_req; | ||
212 | if (req && fc->conn_init) { | ||
213 | fc->destroy_req = NULL; | ||
214 | req->in.h.opcode = FUSE_DESTROY; | ||
215 | req->force = 1; | ||
216 | request_send(fc, req); | ||
217 | fuse_put_request(fc, req); | ||
218 | } | ||
219 | } | ||
220 | |||
206 | static void fuse_put_super(struct super_block *sb) | 221 | static void fuse_put_super(struct super_block *sb) |
207 | { | 222 | { |
208 | struct fuse_conn *fc = get_fuse_conn_super(sb); | 223 | struct fuse_conn *fc = get_fuse_conn_super(sb); |
209 | 224 | ||
225 | fuse_send_destroy(fc); | ||
210 | spin_lock(&fc->lock); | 226 | spin_lock(&fc->lock); |
211 | fc->connected = 0; | 227 | fc->connected = 0; |
212 | fc->blocked = 0; | 228 | fc->blocked = 0; |
@@ -272,6 +288,7 @@ enum { | |||
272 | OPT_DEFAULT_PERMISSIONS, | 288 | OPT_DEFAULT_PERMISSIONS, |
273 | OPT_ALLOW_OTHER, | 289 | OPT_ALLOW_OTHER, |
274 | OPT_MAX_READ, | 290 | OPT_MAX_READ, |
291 | OPT_BLKSIZE, | ||
275 | OPT_ERR | 292 | OPT_ERR |
276 | }; | 293 | }; |
277 | 294 | ||
@@ -283,14 +300,16 @@ static match_table_t tokens = { | |||
283 | {OPT_DEFAULT_PERMISSIONS, "default_permissions"}, | 300 | {OPT_DEFAULT_PERMISSIONS, "default_permissions"}, |
284 | {OPT_ALLOW_OTHER, "allow_other"}, | 301 | {OPT_ALLOW_OTHER, "allow_other"}, |
285 | {OPT_MAX_READ, "max_read=%u"}, | 302 | {OPT_MAX_READ, "max_read=%u"}, |
303 | {OPT_BLKSIZE, "blksize=%u"}, | ||
286 | {OPT_ERR, NULL} | 304 | {OPT_ERR, NULL} |
287 | }; | 305 | }; |
288 | 306 | ||
289 | static int parse_fuse_opt(char *opt, struct fuse_mount_data *d) | 307 | static int parse_fuse_opt(char *opt, struct fuse_mount_data *d, int is_bdev) |
290 | { | 308 | { |
291 | char *p; | 309 | char *p; |
292 | memset(d, 0, sizeof(struct fuse_mount_data)); | 310 | memset(d, 0, sizeof(struct fuse_mount_data)); |
293 | d->max_read = ~0; | 311 | d->max_read = ~0; |
312 | d->blksize = 512; | ||
294 | 313 | ||
295 | while ((p = strsep(&opt, ",")) != NULL) { | 314 | while ((p = strsep(&opt, ",")) != NULL) { |
296 | int token; | 315 | int token; |
@@ -343,6 +362,12 @@ static int parse_fuse_opt(char *opt, struct fuse_mount_data *d) | |||
343 | d->max_read = value; | 362 | d->max_read = value; |
344 | break; | 363 | break; |
345 | 364 | ||
365 | case OPT_BLKSIZE: | ||
366 | if (!is_bdev || match_int(&args[0], &value)) | ||
367 | return 0; | ||
368 | d->blksize = value; | ||
369 | break; | ||
370 | |||
346 | default: | 371 | default: |
347 | return 0; | 372 | return 0; |
348 | } | 373 | } |
@@ -377,6 +402,7 @@ static struct fuse_conn *new_conn(void) | |||
377 | fc = kzalloc(sizeof(*fc), GFP_KERNEL); | 402 | fc = kzalloc(sizeof(*fc), GFP_KERNEL); |
378 | if (fc) { | 403 | if (fc) { |
379 | spin_lock_init(&fc->lock); | 404 | spin_lock_init(&fc->lock); |
405 | mutex_init(&fc->inst_mutex); | ||
380 | atomic_set(&fc->count, 1); | 406 | atomic_set(&fc->count, 1); |
381 | init_waitqueue_head(&fc->waitq); | 407 | init_waitqueue_head(&fc->waitq); |
382 | init_waitqueue_head(&fc->blocked_waitq); | 408 | init_waitqueue_head(&fc->blocked_waitq); |
@@ -396,8 +422,12 @@ static struct fuse_conn *new_conn(void) | |||
396 | 422 | ||
397 | void fuse_conn_put(struct fuse_conn *fc) | 423 | void fuse_conn_put(struct fuse_conn *fc) |
398 | { | 424 | { |
399 | if (atomic_dec_and_test(&fc->count)) | 425 | if (atomic_dec_and_test(&fc->count)) { |
426 | if (fc->destroy_req) | ||
427 | fuse_request_free(fc->destroy_req); | ||
428 | mutex_destroy(&fc->inst_mutex); | ||
400 | kfree(fc); | 429 | kfree(fc); |
430 | } | ||
401 | } | 431 | } |
402 | 432 | ||
403 | struct fuse_conn *fuse_conn_get(struct fuse_conn *fc) | 433 | struct fuse_conn *fuse_conn_get(struct fuse_conn *fc) |
@@ -451,6 +481,7 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) | |||
451 | fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages); | 481 | fc->bdi.ra_pages = min(fc->bdi.ra_pages, ra_pages); |
452 | fc->minor = arg->minor; | 482 | fc->minor = arg->minor; |
453 | fc->max_write = arg->minor < 5 ? 4096 : arg->max_write; | 483 | fc->max_write = arg->minor < 5 ? 4096 : arg->max_write; |
484 | fc->conn_init = 1; | ||
454 | } | 485 | } |
455 | fuse_put_request(fc, req); | 486 | fuse_put_request(fc, req); |
456 | fc->blocked = 0; | 487 | fc->blocked = 0; |
@@ -495,15 +526,23 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) | |||
495 | struct dentry *root_dentry; | 526 | struct dentry *root_dentry; |
496 | struct fuse_req *init_req; | 527 | struct fuse_req *init_req; |
497 | int err; | 528 | int err; |
529 | int is_bdev = sb->s_bdev != NULL; | ||
498 | 530 | ||
499 | if (sb->s_flags & MS_MANDLOCK) | 531 | if (sb->s_flags & MS_MANDLOCK) |
500 | return -EINVAL; | 532 | return -EINVAL; |
501 | 533 | ||
502 | if (!parse_fuse_opt((char *) data, &d)) | 534 | if (!parse_fuse_opt((char *) data, &d, is_bdev)) |
503 | return -EINVAL; | 535 | return -EINVAL; |
504 | 536 | ||
505 | sb->s_blocksize = PAGE_CACHE_SIZE; | 537 | if (is_bdev) { |
506 | sb->s_blocksize_bits = PAGE_CACHE_SHIFT; | 538 | #ifdef CONFIG_BLOCK |
539 | if (!sb_set_blocksize(sb, d.blksize)) | ||
540 | return -EINVAL; | ||
541 | #endif | ||
542 | } else { | ||
543 | sb->s_blocksize = PAGE_CACHE_SIZE; | ||
544 | sb->s_blocksize_bits = PAGE_CACHE_SHIFT; | ||
545 | } | ||
507 | sb->s_magic = FUSE_SUPER_MAGIC; | 546 | sb->s_magic = FUSE_SUPER_MAGIC; |
508 | sb->s_op = &fuse_super_operations; | 547 | sb->s_op = &fuse_super_operations; |
509 | sb->s_maxbytes = MAX_LFS_FILESIZE; | 548 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
@@ -542,6 +581,12 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) | |||
542 | if (!init_req) | 581 | if (!init_req) |
543 | goto err_put_root; | 582 | goto err_put_root; |
544 | 583 | ||
584 | if (is_bdev) { | ||
585 | fc->destroy_req = fuse_request_alloc(); | ||
586 | if (!fc->destroy_req) | ||
587 | goto err_put_root; | ||
588 | } | ||
589 | |||
545 | mutex_lock(&fuse_mutex); | 590 | mutex_lock(&fuse_mutex); |
546 | err = -EINVAL; | 591 | err = -EINVAL; |
547 | if (file->private_data) | 592 | if (file->private_data) |
@@ -593,10 +638,47 @@ static struct file_system_type fuse_fs_type = { | |||
593 | .kill_sb = kill_anon_super, | 638 | .kill_sb = kill_anon_super, |
594 | }; | 639 | }; |
595 | 640 | ||
641 | #ifdef CONFIG_BLOCK | ||
642 | static int fuse_get_sb_blk(struct file_system_type *fs_type, | ||
643 | int flags, const char *dev_name, | ||
644 | void *raw_data, struct vfsmount *mnt) | ||
645 | { | ||
646 | return get_sb_bdev(fs_type, flags, dev_name, raw_data, fuse_fill_super, | ||
647 | mnt); | ||
648 | } | ||
649 | |||
650 | static struct file_system_type fuseblk_fs_type = { | ||
651 | .owner = THIS_MODULE, | ||
652 | .name = "fuseblk", | ||
653 | .get_sb = fuse_get_sb_blk, | ||
654 | .kill_sb = kill_block_super, | ||
655 | .fs_flags = FS_REQUIRES_DEV, | ||
656 | }; | ||
657 | |||
658 | static inline int register_fuseblk(void) | ||
659 | { | ||
660 | return register_filesystem(&fuseblk_fs_type); | ||
661 | } | ||
662 | |||
663 | static inline void unregister_fuseblk(void) | ||
664 | { | ||
665 | unregister_filesystem(&fuseblk_fs_type); | ||
666 | } | ||
667 | #else | ||
668 | static inline int register_fuseblk(void) | ||
669 | { | ||
670 | return 0; | ||
671 | } | ||
672 | |||
673 | static inline void unregister_fuseblk(void) | ||
674 | { | ||
675 | } | ||
676 | #endif | ||
677 | |||
596 | static decl_subsys(fuse, NULL, NULL); | 678 | static decl_subsys(fuse, NULL, NULL); |
597 | static decl_subsys(connections, NULL, NULL); | 679 | static decl_subsys(connections, NULL, NULL); |
598 | 680 | ||
599 | static void fuse_inode_init_once(void *foo, kmem_cache_t *cachep, | 681 | static void fuse_inode_init_once(void *foo, struct kmem_cache *cachep, |
600 | unsigned long flags) | 682 | unsigned long flags) |
601 | { | 683 | { |
602 | struct inode * inode = foo; | 684 | struct inode * inode = foo; |
@@ -612,24 +694,34 @@ static int __init fuse_fs_init(void) | |||
612 | 694 | ||
613 | err = register_filesystem(&fuse_fs_type); | 695 | err = register_filesystem(&fuse_fs_type); |
614 | if (err) | 696 | if (err) |
615 | printk("fuse: failed to register filesystem\n"); | 697 | goto out; |
616 | else { | 698 | |
617 | fuse_inode_cachep = kmem_cache_create("fuse_inode", | 699 | err = register_fuseblk(); |
618 | sizeof(struct fuse_inode), | 700 | if (err) |
619 | 0, SLAB_HWCACHE_ALIGN, | 701 | goto out_unreg; |
620 | fuse_inode_init_once, NULL); | ||
621 | if (!fuse_inode_cachep) { | ||
622 | unregister_filesystem(&fuse_fs_type); | ||
623 | err = -ENOMEM; | ||
624 | } | ||
625 | } | ||
626 | 702 | ||
703 | fuse_inode_cachep = kmem_cache_create("fuse_inode", | ||
704 | sizeof(struct fuse_inode), | ||
705 | 0, SLAB_HWCACHE_ALIGN, | ||
706 | fuse_inode_init_once, NULL); | ||
707 | err = -ENOMEM; | ||
708 | if (!fuse_inode_cachep) | ||
709 | goto out_unreg2; | ||
710 | |||
711 | return 0; | ||
712 | |||
713 | out_unreg2: | ||
714 | unregister_fuseblk(); | ||
715 | out_unreg: | ||
716 | unregister_filesystem(&fuse_fs_type); | ||
717 | out: | ||
627 | return err; | 718 | return err; |
628 | } | 719 | } |
629 | 720 | ||
630 | static void fuse_fs_cleanup(void) | 721 | static void fuse_fs_cleanup(void) |
631 | { | 722 | { |
632 | unregister_filesystem(&fuse_fs_type); | 723 | unregister_filesystem(&fuse_fs_type); |
724 | unregister_fuseblk(); | ||
633 | kmem_cache_destroy(fuse_inode_cachep); | 725 | kmem_cache_destroy(fuse_inode_cachep); |
634 | } | 726 | } |
635 | 727 | ||