diff options
Diffstat (limited to 'fs/fuse')
-rw-r--r-- | fs/fuse/dir.c | 159 | ||||
-rw-r--r-- | fs/fuse/file.c | 21 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 3 | ||||
-rw-r--r-- | fs/fuse/inode.c | 15 |
4 files changed, 134 insertions, 64 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 8605155db1..c71a6c092a 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -138,6 +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 | struct fuse_req *forget_req; | ||
142 | struct dentry *parent; | ||
141 | 143 | ||
142 | /* Doesn't hurt to "reset" the validity timeout */ | 144 | /* Doesn't hurt to "reset" the validity timeout */ |
143 | fuse_invalidate_entry_cache(entry); | 145 | fuse_invalidate_entry_cache(entry); |
@@ -151,21 +153,33 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | |||
151 | if (IS_ERR(req)) | 153 | if (IS_ERR(req)) |
152 | return 0; | 154 | return 0; |
153 | 155 | ||
154 | fuse_lookup_init(req, entry->d_parent->d_inode, entry, &outarg); | 156 | forget_req = fuse_get_req(fc); |
157 | if (IS_ERR(forget_req)) { | ||
158 | fuse_put_request(fc, req); | ||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | parent = dget_parent(entry); | ||
163 | fuse_lookup_init(req, parent->d_inode, entry, &outarg); | ||
155 | request_send(fc, req); | 164 | request_send(fc, req); |
165 | dput(parent); | ||
156 | err = req->out.h.error; | 166 | err = req->out.h.error; |
167 | fuse_put_request(fc, req); | ||
157 | /* Zero nodeid is same as -ENOENT */ | 168 | /* Zero nodeid is same as -ENOENT */ |
158 | if (!err && !outarg.nodeid) | 169 | if (!err && !outarg.nodeid) |
159 | err = -ENOENT; | 170 | err = -ENOENT; |
160 | if (!err) { | 171 | if (!err) { |
161 | struct fuse_inode *fi = get_fuse_inode(inode); | 172 | struct fuse_inode *fi = get_fuse_inode(inode); |
162 | if (outarg.nodeid != get_node_id(inode)) { | 173 | if (outarg.nodeid != get_node_id(inode)) { |
163 | fuse_send_forget(fc, req, outarg.nodeid, 1); | 174 | fuse_send_forget(fc, forget_req, |
175 | outarg.nodeid, 1); | ||
164 | return 0; | 176 | return 0; |
165 | } | 177 | } |
178 | spin_lock(&fc->lock); | ||
166 | fi->nlookup ++; | 179 | fi->nlookup ++; |
180 | spin_unlock(&fc->lock); | ||
167 | } | 181 | } |
168 | fuse_put_request(fc, req); | 182 | fuse_put_request(fc, forget_req); |
169 | if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT) | 183 | if (err || (outarg.attr.mode ^ inode->i_mode) & S_IFMT) |
170 | return 0; | 184 | return 0; |
171 | 185 | ||
@@ -175,22 +189,6 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd) | |||
175 | return 1; | 189 | return 1; |
176 | } | 190 | } |
177 | 191 | ||
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) | 192 | static int invalid_nodeid(u64 nodeid) |
195 | { | 193 | { |
196 | return !nodeid || nodeid == FUSE_ROOT_ID; | 194 | return !nodeid || nodeid == FUSE_ROOT_ID; |
@@ -206,6 +204,24 @@ static int valid_mode(int m) | |||
206 | S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m); | 204 | S_ISBLK(m) || S_ISFIFO(m) || S_ISSOCK(m); |
207 | } | 205 | } |
208 | 206 | ||
207 | /* | ||
208 | * Add a directory inode to a dentry, ensuring that no other dentry | ||
209 | * refers to this inode. Called with fc->inst_mutex. | ||
210 | */ | ||
211 | static int fuse_d_add_directory(struct dentry *entry, struct inode *inode) | ||
212 | { | ||
213 | struct dentry *alias = d_find_alias(inode); | ||
214 | if (alias) { | ||
215 | /* This tries to shrink the subtree below alias */ | ||
216 | fuse_invalidate_entry(alias); | ||
217 | dput(alias); | ||
218 | if (!list_empty(&inode->i_dentry)) | ||
219 | return -EBUSY; | ||
220 | } | ||
221 | d_add(entry, inode); | ||
222 | return 0; | ||
223 | } | ||
224 | |||
209 | static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | 225 | static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, |
210 | struct nameidata *nd) | 226 | struct nameidata *nd) |
211 | { | 227 | { |
@@ -214,6 +230,7 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | |||
214 | struct inode *inode = NULL; | 230 | struct inode *inode = NULL; |
215 | struct fuse_conn *fc = get_fuse_conn(dir); | 231 | struct fuse_conn *fc = get_fuse_conn(dir); |
216 | struct fuse_req *req; | 232 | struct fuse_req *req; |
233 | struct fuse_req *forget_req; | ||
217 | 234 | ||
218 | if (entry->d_name.len > FUSE_NAME_MAX) | 235 | if (entry->d_name.len > FUSE_NAME_MAX) |
219 | return ERR_PTR(-ENAMETOOLONG); | 236 | return ERR_PTR(-ENAMETOOLONG); |
@@ -222,9 +239,16 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | |||
222 | if (IS_ERR(req)) | 239 | if (IS_ERR(req)) |
223 | return ERR_PTR(PTR_ERR(req)); | 240 | return ERR_PTR(PTR_ERR(req)); |
224 | 241 | ||
242 | forget_req = fuse_get_req(fc); | ||
243 | if (IS_ERR(forget_req)) { | ||
244 | fuse_put_request(fc, req); | ||
245 | return ERR_PTR(PTR_ERR(forget_req)); | ||
246 | } | ||
247 | |||
225 | fuse_lookup_init(req, dir, entry, &outarg); | 248 | fuse_lookup_init(req, dir, entry, &outarg); |
226 | request_send(fc, req); | 249 | request_send(fc, req); |
227 | err = req->out.h.error; | 250 | err = req->out.h.error; |
251 | fuse_put_request(fc, req); | ||
228 | /* Zero nodeid is same as -ENOENT, but with valid timeout */ | 252 | /* Zero nodeid is same as -ENOENT, but with valid timeout */ |
229 | if (!err && outarg.nodeid && | 253 | if (!err && outarg.nodeid && |
230 | (invalid_nodeid(outarg.nodeid) || !valid_mode(outarg.attr.mode))) | 254 | (invalid_nodeid(outarg.nodeid) || !valid_mode(outarg.attr.mode))) |
@@ -233,19 +257,25 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | |||
233 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, | 257 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, |
234 | &outarg.attr); | 258 | &outarg.attr); |
235 | if (!inode) { | 259 | if (!inode) { |
236 | fuse_send_forget(fc, req, outarg.nodeid, 1); | 260 | fuse_send_forget(fc, forget_req, outarg.nodeid, 1); |
237 | return ERR_PTR(-ENOMEM); | 261 | return ERR_PTR(-ENOMEM); |
238 | } | 262 | } |
239 | } | 263 | } |
240 | fuse_put_request(fc, req); | 264 | fuse_put_request(fc, forget_req); |
241 | if (err && err != -ENOENT) | 265 | if (err && err != -ENOENT) |
242 | return ERR_PTR(err); | 266 | return ERR_PTR(err); |
243 | 267 | ||
244 | if (inode && dir_alias(inode)) { | 268 | if (inode && S_ISDIR(inode->i_mode)) { |
245 | iput(inode); | 269 | mutex_lock(&fc->inst_mutex); |
246 | return ERR_PTR(-EIO); | 270 | err = fuse_d_add_directory(entry, inode); |
247 | } | 271 | mutex_unlock(&fc->inst_mutex); |
248 | d_add(entry, inode); | 272 | if (err) { |
273 | iput(inode); | ||
274 | return ERR_PTR(err); | ||
275 | } | ||
276 | } else | ||
277 | d_add(entry, inode); | ||
278 | |||
249 | entry->d_op = &fuse_dentry_operations; | 279 | entry->d_op = &fuse_dentry_operations; |
250 | if (!err) | 280 | if (!err) |
251 | fuse_change_timeout(entry, &outarg); | 281 | fuse_change_timeout(entry, &outarg); |
@@ -375,6 +405,13 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, | |||
375 | struct fuse_entry_out outarg; | 405 | struct fuse_entry_out outarg; |
376 | struct inode *inode; | 406 | struct inode *inode; |
377 | int err; | 407 | int err; |
408 | struct fuse_req *forget_req; | ||
409 | |||
410 | forget_req = fuse_get_req(fc); | ||
411 | if (IS_ERR(forget_req)) { | ||
412 | fuse_put_request(fc, req); | ||
413 | return PTR_ERR(forget_req); | ||
414 | } | ||
378 | 415 | ||
379 | req->in.h.nodeid = get_node_id(dir); | 416 | req->in.h.nodeid = get_node_id(dir); |
380 | req->out.numargs = 1; | 417 | req->out.numargs = 1; |
@@ -382,37 +419,47 @@ static int create_new_entry(struct fuse_conn *fc, struct fuse_req *req, | |||
382 | req->out.args[0].value = &outarg; | 419 | req->out.args[0].value = &outarg; |
383 | request_send(fc, req); | 420 | request_send(fc, req); |
384 | err = req->out.h.error; | 421 | err = req->out.h.error; |
385 | if (err) { | 422 | fuse_put_request(fc, req); |
386 | fuse_put_request(fc, req); | 423 | if (err) |
387 | return err; | 424 | goto out_put_forget_req; |
388 | } | 425 | |
389 | err = -EIO; | 426 | err = -EIO; |
390 | if (invalid_nodeid(outarg.nodeid)) | 427 | if (invalid_nodeid(outarg.nodeid)) |
391 | goto out_put_request; | 428 | goto out_put_forget_req; |
392 | 429 | ||
393 | if ((outarg.attr.mode ^ mode) & S_IFMT) | 430 | if ((outarg.attr.mode ^ mode) & S_IFMT) |
394 | goto out_put_request; | 431 | goto out_put_forget_req; |
395 | 432 | ||
396 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, | 433 | inode = fuse_iget(dir->i_sb, outarg.nodeid, outarg.generation, |
397 | &outarg.attr); | 434 | &outarg.attr); |
398 | if (!inode) { | 435 | if (!inode) { |
399 | fuse_send_forget(fc, req, outarg.nodeid, 1); | 436 | fuse_send_forget(fc, forget_req, outarg.nodeid, 1); |
400 | return -ENOMEM; | 437 | return -ENOMEM; |
401 | } | 438 | } |
402 | fuse_put_request(fc, req); | 439 | fuse_put_request(fc, forget_req); |
403 | 440 | ||
404 | if (dir_alias(inode)) { | 441 | if (S_ISDIR(inode->i_mode)) { |
405 | iput(inode); | 442 | struct dentry *alias; |
406 | return -EIO; | 443 | mutex_lock(&fc->inst_mutex); |
407 | } | 444 | alias = d_find_alias(inode); |
445 | if (alias) { | ||
446 | /* New directory must have moved since mkdir */ | ||
447 | mutex_unlock(&fc->inst_mutex); | ||
448 | dput(alias); | ||
449 | iput(inode); | ||
450 | return -EBUSY; | ||
451 | } | ||
452 | d_instantiate(entry, inode); | ||
453 | mutex_unlock(&fc->inst_mutex); | ||
454 | } else | ||
455 | d_instantiate(entry, inode); | ||
408 | 456 | ||
409 | d_instantiate(entry, inode); | ||
410 | fuse_change_timeout(entry, &outarg); | 457 | fuse_change_timeout(entry, &outarg); |
411 | fuse_invalidate_attr(dir); | 458 | fuse_invalidate_attr(dir); |
412 | return 0; | 459 | return 0; |
413 | 460 | ||
414 | out_put_request: | 461 | out_put_forget_req: |
415 | fuse_put_request(fc, req); | 462 | fuse_put_request(fc, forget_req); |
416 | return err; | 463 | return err; |
417 | } | 464 | } |
418 | 465 | ||
@@ -935,14 +982,30 @@ static void iattr_to_fattr(struct iattr *iattr, struct fuse_setattr_in *arg) | |||
935 | } | 982 | } |
936 | } | 983 | } |
937 | 984 | ||
985 | static void fuse_vmtruncate(struct inode *inode, loff_t offset) | ||
986 | { | ||
987 | struct fuse_conn *fc = get_fuse_conn(inode); | ||
988 | int need_trunc; | ||
989 | |||
990 | spin_lock(&fc->lock); | ||
991 | need_trunc = inode->i_size > offset; | ||
992 | i_size_write(inode, offset); | ||
993 | spin_unlock(&fc->lock); | ||
994 | |||
995 | if (need_trunc) { | ||
996 | struct address_space *mapping = inode->i_mapping; | ||
997 | unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); | ||
998 | truncate_inode_pages(mapping, offset); | ||
999 | } | ||
1000 | } | ||
1001 | |||
938 | /* | 1002 | /* |
939 | * Set attributes, and at the same time refresh them. | 1003 | * Set attributes, and at the same time refresh them. |
940 | * | 1004 | * |
941 | * Truncation is slightly complicated, because the 'truncate' request | 1005 | * Truncation is slightly complicated, because the 'truncate' request |
942 | * may fail, in which case we don't want to touch the mapping. | 1006 | * 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 | 1007 | * vmtruncate() doesn't allow for this case, so do the rlimit checking |
944 | * checking by hand and call vmtruncate() only after the file has | 1008 | * and the actual truncation by hand. |
945 | * actually been truncated. | ||
946 | */ | 1009 | */ |
947 | static int fuse_setattr(struct dentry *entry, struct iattr *attr) | 1010 | static int fuse_setattr(struct dentry *entry, struct iattr *attr) |
948 | { | 1011 | { |
@@ -993,12 +1056,8 @@ static int fuse_setattr(struct dentry *entry, struct iattr *attr) | |||
993 | make_bad_inode(inode); | 1056 | make_bad_inode(inode); |
994 | err = -EIO; | 1057 | err = -EIO; |
995 | } else { | 1058 | } else { |
996 | if (is_truncate) { | 1059 | if (is_truncate) |
997 | loff_t origsize = i_size_read(inode); | 1060 | 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); | 1061 | fuse_change_attributes(inode, &outarg.attr); |
1003 | fi->i_time = time_to_jiffies(outarg.attr_valid, | 1062 | fi->i_time = time_to_jiffies(outarg.attr_valid, |
1004 | outarg.attr_valid_nsec); | 1063 | outarg.attr_valid_nsec); |
diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 183626868e..763a50daf1 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c | |||
@@ -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); |
@@ -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); |
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index 69c7750d55..91edb8932d 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 | ||
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 7d0a9aee01..fc42035703 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
@@ -109,6 +109,7 @@ static int fuse_remount_fs(struct super_block *sb, int *flags, char *data) | |||
109 | 109 | ||
110 | void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr) | 110 | void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr) |
111 | { | 111 | { |
112 | struct fuse_conn *fc = get_fuse_conn(inode); | ||
112 | if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size) | 113 | if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size) |
113 | invalidate_inode_pages(inode->i_mapping); | 114 | invalidate_inode_pages(inode->i_mapping); |
114 | 115 | ||
@@ -117,7 +118,9 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr) | |||
117 | inode->i_nlink = attr->nlink; | 118 | inode->i_nlink = attr->nlink; |
118 | inode->i_uid = attr->uid; | 119 | inode->i_uid = attr->uid; |
119 | inode->i_gid = attr->gid; | 120 | inode->i_gid = attr->gid; |
121 | spin_lock(&fc->lock); | ||
120 | i_size_write(inode, attr->size); | 122 | i_size_write(inode, attr->size); |
123 | spin_unlock(&fc->lock); | ||
121 | inode->i_blocks = attr->blocks; | 124 | inode->i_blocks = attr->blocks; |
122 | inode->i_atime.tv_sec = attr->atime; | 125 | inode->i_atime.tv_sec = attr->atime; |
123 | inode->i_atime.tv_nsec = attr->atimensec; | 126 | inode->i_atime.tv_nsec = attr->atimensec; |
@@ -130,7 +133,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) | 133 | static void fuse_init_inode(struct inode *inode, struct fuse_attr *attr) |
131 | { | 134 | { |
132 | inode->i_mode = attr->mode & S_IFMT; | 135 | inode->i_mode = attr->mode & S_IFMT; |
133 | i_size_write(inode, attr->size); | 136 | inode->i_size = attr->size; |
134 | if (S_ISREG(inode->i_mode)) { | 137 | if (S_ISREG(inode->i_mode)) { |
135 | fuse_init_common(inode); | 138 | fuse_init_common(inode); |
136 | fuse_init_file_inode(inode); | 139 | fuse_init_file_inode(inode); |
@@ -169,7 +172,6 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, | |||
169 | struct inode *inode; | 172 | struct inode *inode; |
170 | struct fuse_inode *fi; | 173 | struct fuse_inode *fi; |
171 | struct fuse_conn *fc = get_fuse_conn_super(sb); | 174 | struct fuse_conn *fc = get_fuse_conn_super(sb); |
172 | int retried = 0; | ||
173 | 175 | ||
174 | retry: | 176 | retry: |
175 | inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid); | 177 | inode = iget5_locked(sb, nodeid, fuse_inode_eq, fuse_inode_set, &nodeid); |
@@ -183,16 +185,16 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, | |||
183 | fuse_init_inode(inode, attr); | 185 | fuse_init_inode(inode, attr); |
184 | unlock_new_inode(inode); | 186 | unlock_new_inode(inode); |
185 | } else if ((inode->i_mode ^ attr->mode) & S_IFMT) { | 187 | } 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 */ | 188 | /* Inode has changed type, any I/O on the old should fail */ |
188 | make_bad_inode(inode); | 189 | make_bad_inode(inode); |
189 | iput(inode); | 190 | iput(inode); |
190 | retried = 1; | ||
191 | goto retry; | 191 | goto retry; |
192 | } | 192 | } |
193 | 193 | ||
194 | fi = get_fuse_inode(inode); | 194 | fi = get_fuse_inode(inode); |
195 | spin_lock(&fc->lock); | ||
195 | fi->nlookup ++; | 196 | fi->nlookup ++; |
197 | spin_unlock(&fc->lock); | ||
196 | fuse_change_attributes(inode, attr); | 198 | fuse_change_attributes(inode, attr); |
197 | return inode; | 199 | return inode; |
198 | } | 200 | } |
@@ -377,6 +379,7 @@ static struct fuse_conn *new_conn(void) | |||
377 | fc = kzalloc(sizeof(*fc), GFP_KERNEL); | 379 | fc = kzalloc(sizeof(*fc), GFP_KERNEL); |
378 | if (fc) { | 380 | if (fc) { |
379 | spin_lock_init(&fc->lock); | 381 | spin_lock_init(&fc->lock); |
382 | mutex_init(&fc->inst_mutex); | ||
380 | atomic_set(&fc->count, 1); | 383 | atomic_set(&fc->count, 1); |
381 | init_waitqueue_head(&fc->waitq); | 384 | init_waitqueue_head(&fc->waitq); |
382 | init_waitqueue_head(&fc->blocked_waitq); | 385 | init_waitqueue_head(&fc->blocked_waitq); |
@@ -396,8 +399,10 @@ static struct fuse_conn *new_conn(void) | |||
396 | 399 | ||
397 | void fuse_conn_put(struct fuse_conn *fc) | 400 | void fuse_conn_put(struct fuse_conn *fc) |
398 | { | 401 | { |
399 | if (atomic_dec_and_test(&fc->count)) | 402 | if (atomic_dec_and_test(&fc->count)) { |
403 | mutex_destroy(&fc->inst_mutex); | ||
400 | kfree(fc); | 404 | kfree(fc); |
405 | } | ||
401 | } | 406 | } |
402 | 407 | ||
403 | struct fuse_conn *fuse_conn_get(struct fuse_conn *fc) | 408 | struct fuse_conn *fuse_conn_get(struct fuse_conn *fc) |