diff options
Diffstat (limited to 'fs/fuse/inode.c')
-rw-r--r-- | fs/fuse/inode.c | 39 |
1 files changed, 33 insertions, 6 deletions
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index fd0735715c14..9a68d6970845 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
@@ -56,6 +56,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb) | |||
56 | fi->i_time = 0; | 56 | fi->i_time = 0; |
57 | fi->nodeid = 0; | 57 | fi->nodeid = 0; |
58 | fi->nlookup = 0; | 58 | fi->nlookup = 0; |
59 | INIT_LIST_HEAD(&fi->write_files); | ||
59 | fi->forget_req = fuse_request_alloc(); | 60 | fi->forget_req = fuse_request_alloc(); |
60 | if (!fi->forget_req) { | 61 | if (!fi->forget_req) { |
61 | kmem_cache_free(fuse_inode_cachep, inode); | 62 | kmem_cache_free(fuse_inode_cachep, inode); |
@@ -68,6 +69,7 @@ static struct inode *fuse_alloc_inode(struct super_block *sb) | |||
68 | static void fuse_destroy_inode(struct inode *inode) | 69 | static void fuse_destroy_inode(struct inode *inode) |
69 | { | 70 | { |
70 | struct fuse_inode *fi = get_fuse_inode(inode); | 71 | struct fuse_inode *fi = get_fuse_inode(inode); |
72 | BUG_ON(!list_empty(&fi->write_files)); | ||
71 | if (fi->forget_req) | 73 | if (fi->forget_req) |
72 | fuse_request_free(fi->forget_req); | 74 | fuse_request_free(fi->forget_req); |
73 | kmem_cache_free(fuse_inode_cachep, inode); | 75 | kmem_cache_free(fuse_inode_cachep, inode); |
@@ -117,12 +119,22 @@ static void fuse_truncate(struct address_space *mapping, loff_t offset) | |||
117 | unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); | 119 | unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); |
118 | } | 120 | } |
119 | 121 | ||
120 | void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr) | 122 | |
123 | void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr, | ||
124 | u64 attr_valid, u64 attr_version) | ||
121 | { | 125 | { |
122 | struct fuse_conn *fc = get_fuse_conn(inode); | 126 | struct fuse_conn *fc = get_fuse_conn(inode); |
123 | struct fuse_inode *fi = get_fuse_inode(inode); | 127 | struct fuse_inode *fi = get_fuse_inode(inode); |
124 | loff_t oldsize; | 128 | loff_t oldsize; |
125 | 129 | ||
130 | spin_lock(&fc->lock); | ||
131 | if (attr_version != 0 && fi->attr_version > attr_version) { | ||
132 | spin_unlock(&fc->lock); | ||
133 | return; | ||
134 | } | ||
135 | fi->attr_version = ++fc->attr_version; | ||
136 | fi->i_time = attr_valid; | ||
137 | |||
126 | inode->i_ino = attr->ino; | 138 | inode->i_ino = attr->ino; |
127 | inode->i_mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777); | 139 | inode->i_mode = (inode->i_mode & S_IFMT) | (attr->mode & 07777); |
128 | inode->i_nlink = attr->nlink; | 140 | inode->i_nlink = attr->nlink; |
@@ -136,6 +148,11 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr) | |||
136 | inode->i_ctime.tv_sec = attr->ctime; | 148 | inode->i_ctime.tv_sec = attr->ctime; |
137 | inode->i_ctime.tv_nsec = attr->ctimensec; | 149 | inode->i_ctime.tv_nsec = attr->ctimensec; |
138 | 150 | ||
151 | if (attr->blksize != 0) | ||
152 | inode->i_blkbits = ilog2(attr->blksize); | ||
153 | else | ||
154 | inode->i_blkbits = inode->i_sb->s_blocksize_bits; | ||
155 | |||
139 | /* | 156 | /* |
140 | * Don't set the sticky bit in i_mode, unless we want the VFS | 157 | * Don't set the sticky bit in i_mode, unless we want the VFS |
141 | * to check permissions. This prevents failures due to the | 158 | * to check permissions. This prevents failures due to the |
@@ -145,7 +162,6 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr) | |||
145 | if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS)) | 162 | if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS)) |
146 | inode->i_mode &= ~S_ISVTX; | 163 | inode->i_mode &= ~S_ISVTX; |
147 | 164 | ||
148 | spin_lock(&fc->lock); | ||
149 | oldsize = inode->i_size; | 165 | oldsize = inode->i_size; |
150 | i_size_write(inode, attr->size); | 166 | i_size_write(inode, attr->size); |
151 | spin_unlock(&fc->lock); | 167 | spin_unlock(&fc->lock); |
@@ -194,7 +210,8 @@ static int fuse_inode_set(struct inode *inode, void *_nodeidp) | |||
194 | } | 210 | } |
195 | 211 | ||
196 | struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, | 212 | struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, |
197 | int generation, struct fuse_attr *attr) | 213 | int generation, struct fuse_attr *attr, |
214 | u64 attr_valid, u64 attr_version) | ||
198 | { | 215 | { |
199 | struct inode *inode; | 216 | struct inode *inode; |
200 | struct fuse_inode *fi; | 217 | struct fuse_inode *fi; |
@@ -222,7 +239,8 @@ struct inode *fuse_iget(struct super_block *sb, unsigned long nodeid, | |||
222 | spin_lock(&fc->lock); | 239 | spin_lock(&fc->lock); |
223 | fi->nlookup ++; | 240 | fi->nlookup ++; |
224 | spin_unlock(&fc->lock); | 241 | spin_unlock(&fc->lock); |
225 | fuse_change_attributes(inode, attr); | 242 | fuse_change_attributes(inode, attr, attr_valid, attr_version); |
243 | |||
226 | return inode; | 244 | return inode; |
227 | } | 245 | } |
228 | 246 | ||
@@ -287,6 +305,11 @@ static int fuse_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
287 | struct fuse_statfs_out outarg; | 305 | struct fuse_statfs_out outarg; |
288 | int err; | 306 | int err; |
289 | 307 | ||
308 | if (!fuse_allow_task(fc, current)) { | ||
309 | buf->f_type = FUSE_SUPER_MAGIC; | ||
310 | return 0; | ||
311 | } | ||
312 | |||
290 | req = fuse_get_req(fc); | 313 | req = fuse_get_req(fc); |
291 | if (IS_ERR(req)) | 314 | if (IS_ERR(req)) |
292 | return PTR_ERR(req); | 315 | return PTR_ERR(req); |
@@ -452,6 +475,7 @@ static struct fuse_conn *new_conn(void) | |||
452 | } | 475 | } |
453 | fc->reqctr = 0; | 476 | fc->reqctr = 0; |
454 | fc->blocked = 1; | 477 | fc->blocked = 1; |
478 | fc->attr_version = 1; | ||
455 | get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key)); | 479 | get_random_bytes(&fc->scramble_key, sizeof(fc->scramble_key)); |
456 | } | 480 | } |
457 | out: | 481 | out: |
@@ -483,7 +507,7 @@ static struct inode *get_root_inode(struct super_block *sb, unsigned mode) | |||
483 | attr.mode = mode; | 507 | attr.mode = mode; |
484 | attr.ino = FUSE_ROOT_ID; | 508 | attr.ino = FUSE_ROOT_ID; |
485 | attr.nlink = 1; | 509 | attr.nlink = 1; |
486 | return fuse_iget(sb, 1, 0, &attr); | 510 | return fuse_iget(sb, 1, 0, &attr, 0, 0); |
487 | } | 511 | } |
488 | 512 | ||
489 | static const struct super_operations fuse_super_operations = { | 513 | static const struct super_operations fuse_super_operations = { |
@@ -514,6 +538,8 @@ static void process_init_reply(struct fuse_conn *fc, struct fuse_req *req) | |||
514 | fc->async_read = 1; | 538 | fc->async_read = 1; |
515 | if (!(arg->flags & FUSE_POSIX_LOCKS)) | 539 | if (!(arg->flags & FUSE_POSIX_LOCKS)) |
516 | fc->no_lock = 1; | 540 | fc->no_lock = 1; |
541 | if (arg->flags & FUSE_ATOMIC_O_TRUNC) | ||
542 | fc->atomic_o_trunc = 1; | ||
517 | } else { | 543 | } else { |
518 | ra_pages = fc->max_read / PAGE_CACHE_SIZE; | 544 | ra_pages = fc->max_read / PAGE_CACHE_SIZE; |
519 | fc->no_lock = 1; | 545 | fc->no_lock = 1; |
@@ -536,7 +562,8 @@ static void fuse_send_init(struct fuse_conn *fc, struct fuse_req *req) | |||
536 | arg->major = FUSE_KERNEL_VERSION; | 562 | arg->major = FUSE_KERNEL_VERSION; |
537 | arg->minor = FUSE_KERNEL_MINOR_VERSION; | 563 | arg->minor = FUSE_KERNEL_MINOR_VERSION; |
538 | arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE; | 564 | arg->max_readahead = fc->bdi.ra_pages * PAGE_CACHE_SIZE; |
539 | arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS; | 565 | arg->flags |= FUSE_ASYNC_READ | FUSE_POSIX_LOCKS | FUSE_FILE_OPS | |
566 | FUSE_ATOMIC_O_TRUNC; | ||
540 | req->in.h.opcode = FUSE_INIT; | 567 | req->in.h.opcode = FUSE_INIT; |
541 | req->in.numargs = 1; | 568 | req->in.numargs = 1; |
542 | req->in.args[0].size = sizeof(*arg); | 569 | req->in.args[0].size = sizeof(*arg); |