diff options
Diffstat (limited to 'fs')
332 files changed, 7635 insertions, 5377 deletions
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h index f47c6bbb01b3..88418c419ea7 100644 --- a/fs/9p/v9fs_vfs.h +++ b/fs/9p/v9fs_vfs.h | |||
| @@ -52,7 +52,7 @@ void v9fs_destroy_inode(struct inode *inode); | |||
| 52 | #endif | 52 | #endif |
| 53 | 53 | ||
| 54 | struct inode *v9fs_get_inode(struct super_block *sb, int mode); | 54 | struct inode *v9fs_get_inode(struct super_block *sb, int mode); |
| 55 | void v9fs_clear_inode(struct inode *inode); | 55 | void v9fs_evict_inode(struct inode *inode); |
| 56 | ino_t v9fs_qid2ino(struct p9_qid *qid); | 56 | ino_t v9fs_qid2ino(struct p9_qid *qid); |
| 57 | void v9fs_stat2inode(struct p9_wstat *, struct inode *, struct super_block *); | 57 | void v9fs_stat2inode(struct p9_wstat *, struct inode *, struct super_block *); |
| 58 | void v9fs_stat2inode_dotl(struct p9_stat_dotl *, struct inode *); | 58 | void v9fs_stat2inode_dotl(struct p9_stat_dotl *, struct inode *); |
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 6e94f3247cec..c7c23eab9440 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c | |||
| @@ -430,8 +430,10 @@ error: | |||
| 430 | * @inode: inode to release | 430 | * @inode: inode to release |
| 431 | * | 431 | * |
| 432 | */ | 432 | */ |
| 433 | void v9fs_clear_inode(struct inode *inode) | 433 | void v9fs_evict_inode(struct inode *inode) |
| 434 | { | 434 | { |
| 435 | truncate_inode_pages(inode->i_mapping, 0); | ||
| 436 | end_writeback(inode); | ||
| 435 | filemap_fdatawrite(inode->i_mapping); | 437 | filemap_fdatawrite(inode->i_mapping); |
| 436 | 438 | ||
| 437 | #ifdef CONFIG_9P_FSCACHE | 439 | #ifdef CONFIG_9P_FSCACHE |
| @@ -1209,10 +1211,19 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) | |||
| 1209 | } | 1211 | } |
| 1210 | 1212 | ||
| 1211 | retval = p9_client_wstat(fid, &wstat); | 1213 | retval = p9_client_wstat(fid, &wstat); |
| 1212 | if (retval >= 0) | 1214 | if (retval < 0) |
| 1213 | retval = inode_setattr(dentry->d_inode, iattr); | 1215 | return retval; |
| 1214 | 1216 | ||
| 1215 | return retval; | 1217 | if ((iattr->ia_valid & ATTR_SIZE) && |
| 1218 | iattr->ia_size != i_size_read(dentry->d_inode)) { | ||
| 1219 | retval = vmtruncate(dentry->d_inode, iattr->ia_size); | ||
| 1220 | if (retval) | ||
| 1221 | return retval; | ||
| 1222 | } | ||
| 1223 | |||
| 1224 | setattr_copy(dentry->d_inode, iattr); | ||
| 1225 | mark_inode_dirty(dentry->d_inode); | ||
| 1226 | return 0; | ||
| 1216 | } | 1227 | } |
| 1217 | 1228 | ||
| 1218 | /** | 1229 | /** |
| @@ -1252,10 +1263,19 @@ static int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr) | |||
| 1252 | return PTR_ERR(fid); | 1263 | return PTR_ERR(fid); |
| 1253 | 1264 | ||
| 1254 | retval = p9_client_setattr(fid, &p9attr); | 1265 | retval = p9_client_setattr(fid, &p9attr); |
| 1255 | if (retval >= 0) | 1266 | if (retval < 0) |
| 1256 | retval = inode_setattr(dentry->d_inode, iattr); | 1267 | return retval; |
| 1257 | 1268 | ||
| 1258 | return retval; | 1269 | if ((iattr->ia_valid & ATTR_SIZE) && |
| 1270 | iattr->ia_size != i_size_read(dentry->d_inode)) { | ||
| 1271 | retval = vmtruncate(dentry->d_inode, iattr->ia_size); | ||
| 1272 | if (retval) | ||
| 1273 | return retval; | ||
| 1274 | } | ||
| 1275 | |||
| 1276 | setattr_copy(dentry->d_inode, iattr); | ||
| 1277 | mark_inode_dirty(dentry->d_inode); | ||
| 1278 | return 0; | ||
| 1259 | } | 1279 | } |
| 1260 | 1280 | ||
| 1261 | /** | 1281 | /** |
diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index 4b9ede0b41b7..f9311077de68 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c | |||
| @@ -266,7 +266,7 @@ static const struct super_operations v9fs_super_ops = { | |||
| 266 | .destroy_inode = v9fs_destroy_inode, | 266 | .destroy_inode = v9fs_destroy_inode, |
| 267 | #endif | 267 | #endif |
| 268 | .statfs = simple_statfs, | 268 | .statfs = simple_statfs, |
| 269 | .clear_inode = v9fs_clear_inode, | 269 | .evict_inode = v9fs_evict_inode, |
| 270 | .show_options = generic_show_options, | 270 | .show_options = generic_show_options, |
| 271 | .umount_begin = v9fs_umount_begin, | 271 | .umount_begin = v9fs_umount_begin, |
| 272 | }; | 272 | }; |
| @@ -277,7 +277,7 @@ static const struct super_operations v9fs_super_ops_dotl = { | |||
| 277 | .destroy_inode = v9fs_destroy_inode, | 277 | .destroy_inode = v9fs_destroy_inode, |
| 278 | #endif | 278 | #endif |
| 279 | .statfs = v9fs_statfs, | 279 | .statfs = v9fs_statfs, |
| 280 | .clear_inode = v9fs_clear_inode, | 280 | .evict_inode = v9fs_evict_inode, |
| 281 | .show_options = generic_show_options, | 281 | .show_options = generic_show_options, |
| 282 | .umount_begin = v9fs_umount_begin, | 282 | .umount_begin = v9fs_umount_begin, |
| 283 | }; | 283 | }; |
diff --git a/fs/adfs/inode.c b/fs/adfs/inode.c index 6f850b06ab62..65794b8fe79e 100644 --- a/fs/adfs/inode.c +++ b/fs/adfs/inode.c | |||
| @@ -50,10 +50,19 @@ static int adfs_write_begin(struct file *file, struct address_space *mapping, | |||
| 50 | loff_t pos, unsigned len, unsigned flags, | 50 | loff_t pos, unsigned len, unsigned flags, |
| 51 | struct page **pagep, void **fsdata) | 51 | struct page **pagep, void **fsdata) |
| 52 | { | 52 | { |
| 53 | int ret; | ||
| 54 | |||
| 53 | *pagep = NULL; | 55 | *pagep = NULL; |
| 54 | return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, | 56 | ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, |
| 55 | adfs_get_block, | 57 | adfs_get_block, |
| 56 | &ADFS_I(mapping->host)->mmu_private); | 58 | &ADFS_I(mapping->host)->mmu_private); |
| 59 | if (unlikely(ret)) { | ||
| 60 | loff_t isize = mapping->host->i_size; | ||
| 61 | if (pos + len > isize) | ||
| 62 | vmtruncate(mapping->host, isize); | ||
| 63 | } | ||
| 64 | |||
| 65 | return ret; | ||
| 57 | } | 66 | } |
| 58 | 67 | ||
| 59 | static sector_t _adfs_bmap(struct address_space *mapping, sector_t block) | 68 | static sector_t _adfs_bmap(struct address_space *mapping, sector_t block) |
| @@ -324,10 +333,7 @@ adfs_notify_change(struct dentry *dentry, struct iattr *attr) | |||
| 324 | 333 | ||
| 325 | /* XXX: this is missing some actual on-disk truncation.. */ | 334 | /* XXX: this is missing some actual on-disk truncation.. */ |
| 326 | if (ia_valid & ATTR_SIZE) | 335 | if (ia_valid & ATTR_SIZE) |
| 327 | error = simple_setsize(inode, attr->ia_size); | 336 | truncate_setsize(inode, attr->ia_size); |
| 328 | |||
| 329 | if (error) | ||
| 330 | goto out; | ||
| 331 | 337 | ||
| 332 | if (ia_valid & ATTR_MTIME) { | 338 | if (ia_valid & ATTR_MTIME) { |
| 333 | inode->i_mtime = attr->ia_mtime; | 339 | inode->i_mtime = attr->ia_mtime; |
diff --git a/fs/affs/affs.h b/fs/affs/affs.h index f05b6155ccc8..a8cbdeb34025 100644 --- a/fs/affs/affs.h +++ b/fs/affs/affs.h | |||
| @@ -171,8 +171,7 @@ extern int affs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
| 171 | extern unsigned long affs_parent_ino(struct inode *dir); | 171 | extern unsigned long affs_parent_ino(struct inode *dir); |
| 172 | extern struct inode *affs_new_inode(struct inode *dir); | 172 | extern struct inode *affs_new_inode(struct inode *dir); |
| 173 | extern int affs_notify_change(struct dentry *dentry, struct iattr *attr); | 173 | extern int affs_notify_change(struct dentry *dentry, struct iattr *attr); |
| 174 | extern void affs_delete_inode(struct inode *inode); | 174 | extern void affs_evict_inode(struct inode *inode); |
| 175 | extern void affs_clear_inode(struct inode *inode); | ||
| 176 | extern struct inode *affs_iget(struct super_block *sb, | 175 | extern struct inode *affs_iget(struct super_block *sb, |
| 177 | unsigned long ino); | 176 | unsigned long ino); |
| 178 | extern int affs_write_inode(struct inode *inode, | 177 | extern int affs_write_inode(struct inode *inode, |
diff --git a/fs/affs/file.c b/fs/affs/file.c index 322710c3eedf..c4a9875bd1a6 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c | |||
| @@ -406,10 +406,19 @@ static int affs_write_begin(struct file *file, struct address_space *mapping, | |||
| 406 | loff_t pos, unsigned len, unsigned flags, | 406 | loff_t pos, unsigned len, unsigned flags, |
| 407 | struct page **pagep, void **fsdata) | 407 | struct page **pagep, void **fsdata) |
| 408 | { | 408 | { |
| 409 | int ret; | ||
| 410 | |||
| 409 | *pagep = NULL; | 411 | *pagep = NULL; |
| 410 | return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, | 412 | ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, |
| 411 | affs_get_block, | 413 | affs_get_block, |
| 412 | &AFFS_I(mapping->host)->mmu_private); | 414 | &AFFS_I(mapping->host)->mmu_private); |
| 415 | if (unlikely(ret)) { | ||
| 416 | loff_t isize = mapping->host->i_size; | ||
| 417 | if (pos + len > isize) | ||
| 418 | vmtruncate(mapping->host, isize); | ||
| 419 | } | ||
| 420 | |||
| 421 | return ret; | ||
| 413 | } | 422 | } |
| 414 | 423 | ||
| 415 | static sector_t _affs_bmap(struct address_space *mapping, sector_t block) | 424 | static sector_t _affs_bmap(struct address_space *mapping, sector_t block) |
diff --git a/fs/affs/inode.c b/fs/affs/inode.c index f4b2a4ee4f91..3a0fdec175ba 100644 --- a/fs/affs/inode.c +++ b/fs/affs/inode.c | |||
| @@ -235,31 +235,36 @@ affs_notify_change(struct dentry *dentry, struct iattr *attr) | |||
| 235 | goto out; | 235 | goto out; |
| 236 | } | 236 | } |
| 237 | 237 | ||
| 238 | error = inode_setattr(inode, attr); | 238 | if ((attr->ia_valid & ATTR_SIZE) && |
| 239 | if (!error && (attr->ia_valid & ATTR_MODE)) | 239 | attr->ia_size != i_size_read(inode)) { |
| 240 | error = vmtruncate(inode, attr->ia_size); | ||
| 241 | if (error) | ||
| 242 | return error; | ||
| 243 | } | ||
| 244 | |||
| 245 | setattr_copy(inode, attr); | ||
| 246 | mark_inode_dirty(inode); | ||
| 247 | |||
| 248 | if (attr->ia_valid & ATTR_MODE) | ||
| 240 | mode_to_prot(inode); | 249 | mode_to_prot(inode); |
| 241 | out: | 250 | out: |
| 242 | return error; | 251 | return error; |
| 243 | } | 252 | } |
| 244 | 253 | ||
| 245 | void | 254 | void |
| 246 | affs_delete_inode(struct inode *inode) | 255 | affs_evict_inode(struct inode *inode) |
| 247 | { | ||
| 248 | pr_debug("AFFS: delete_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink); | ||
| 249 | truncate_inode_pages(&inode->i_data, 0); | ||
| 250 | inode->i_size = 0; | ||
| 251 | affs_truncate(inode); | ||
| 252 | clear_inode(inode); | ||
| 253 | affs_free_block(inode->i_sb, inode->i_ino); | ||
| 254 | } | ||
| 255 | |||
| 256 | void | ||
| 257 | affs_clear_inode(struct inode *inode) | ||
| 258 | { | 256 | { |
| 259 | unsigned long cache_page; | 257 | unsigned long cache_page; |
| 258 | pr_debug("AFFS: evict_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink); | ||
| 259 | truncate_inode_pages(&inode->i_data, 0); | ||
| 260 | 260 | ||
| 261 | pr_debug("AFFS: clear_inode(ino=%lu, nlink=%u)\n", inode->i_ino, inode->i_nlink); | 261 | if (!inode->i_nlink) { |
| 262 | inode->i_size = 0; | ||
| 263 | affs_truncate(inode); | ||
| 264 | } | ||
| 262 | 265 | ||
| 266 | invalidate_inode_buffers(inode); | ||
| 267 | end_writeback(inode); | ||
| 263 | affs_free_prealloc(inode); | 268 | affs_free_prealloc(inode); |
| 264 | cache_page = (unsigned long)AFFS_I(inode)->i_lc; | 269 | cache_page = (unsigned long)AFFS_I(inode)->i_lc; |
| 265 | if (cache_page) { | 270 | if (cache_page) { |
| @@ -271,6 +276,9 @@ affs_clear_inode(struct inode *inode) | |||
| 271 | affs_brelse(AFFS_I(inode)->i_ext_bh); | 276 | affs_brelse(AFFS_I(inode)->i_ext_bh); |
| 272 | AFFS_I(inode)->i_ext_last = ~1; | 277 | AFFS_I(inode)->i_ext_last = ~1; |
| 273 | AFFS_I(inode)->i_ext_bh = NULL; | 278 | AFFS_I(inode)->i_ext_bh = NULL; |
| 279 | |||
| 280 | if (!inode->i_nlink) | ||
| 281 | affs_free_block(inode->i_sb, inode->i_ino); | ||
| 274 | } | 282 | } |
| 275 | 283 | ||
| 276 | struct inode * | 284 | struct inode * |
diff --git a/fs/affs/super.c b/fs/affs/super.c index 16a3e4765f68..33c4e7eef470 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c | |||
| @@ -26,7 +26,7 @@ static int affs_statfs(struct dentry *dentry, struct kstatfs *buf); | |||
| 26 | static int affs_remount (struct super_block *sb, int *flags, char *data); | 26 | static int affs_remount (struct super_block *sb, int *flags, char *data); |
| 27 | 27 | ||
| 28 | static void | 28 | static void |
| 29 | affs_commit_super(struct super_block *sb, int clean) | 29 | affs_commit_super(struct super_block *sb, int wait, int clean) |
| 30 | { | 30 | { |
| 31 | struct affs_sb_info *sbi = AFFS_SB(sb); | 31 | struct affs_sb_info *sbi = AFFS_SB(sb); |
| 32 | struct buffer_head *bh = sbi->s_root_bh; | 32 | struct buffer_head *bh = sbi->s_root_bh; |
| @@ -36,6 +36,8 @@ affs_commit_super(struct super_block *sb, int clean) | |||
| 36 | secs_to_datestamp(get_seconds(), &tail->disk_change); | 36 | secs_to_datestamp(get_seconds(), &tail->disk_change); |
| 37 | affs_fix_checksum(sb, bh); | 37 | affs_fix_checksum(sb, bh); |
| 38 | mark_buffer_dirty(bh); | 38 | mark_buffer_dirty(bh); |
| 39 | if (wait) | ||
| 40 | sync_dirty_buffer(bh); | ||
| 39 | } | 41 | } |
| 40 | 42 | ||
| 41 | static void | 43 | static void |
| @@ -46,8 +48,8 @@ affs_put_super(struct super_block *sb) | |||
| 46 | 48 | ||
| 47 | lock_kernel(); | 49 | lock_kernel(); |
| 48 | 50 | ||
| 49 | if (!(sb->s_flags & MS_RDONLY)) | 51 | if (!(sb->s_flags & MS_RDONLY) && sb->s_dirt) |
| 50 | affs_commit_super(sb, 1); | 52 | affs_commit_super(sb, 1, 1); |
| 51 | 53 | ||
| 52 | kfree(sbi->s_prefix); | 54 | kfree(sbi->s_prefix); |
| 53 | affs_free_bitmap(sb); | 55 | affs_free_bitmap(sb); |
| @@ -61,27 +63,20 @@ affs_put_super(struct super_block *sb) | |||
| 61 | static void | 63 | static void |
| 62 | affs_write_super(struct super_block *sb) | 64 | affs_write_super(struct super_block *sb) |
| 63 | { | 65 | { |
| 64 | int clean = 2; | ||
| 65 | |||
| 66 | lock_super(sb); | 66 | lock_super(sb); |
| 67 | if (!(sb->s_flags & MS_RDONLY)) { | 67 | if (!(sb->s_flags & MS_RDONLY)) |
| 68 | // if (sbi->s_bitmap[i].bm_bh) { | 68 | affs_commit_super(sb, 1, 2); |
| 69 | // if (buffer_dirty(sbi->s_bitmap[i].bm_bh)) { | 69 | sb->s_dirt = 0; |
| 70 | // clean = 0; | ||
| 71 | affs_commit_super(sb, clean); | ||
| 72 | sb->s_dirt = !clean; /* redo until bitmap synced */ | ||
| 73 | } else | ||
| 74 | sb->s_dirt = 0; | ||
| 75 | unlock_super(sb); | 70 | unlock_super(sb); |
| 76 | 71 | ||
| 77 | pr_debug("AFFS: write_super() at %lu, clean=%d\n", get_seconds(), clean); | 72 | pr_debug("AFFS: write_super() at %lu, clean=2\n", get_seconds()); |
| 78 | } | 73 | } |
| 79 | 74 | ||
| 80 | static int | 75 | static int |
| 81 | affs_sync_fs(struct super_block *sb, int wait) | 76 | affs_sync_fs(struct super_block *sb, int wait) |
| 82 | { | 77 | { |
| 83 | lock_super(sb); | 78 | lock_super(sb); |
| 84 | affs_commit_super(sb, 2); | 79 | affs_commit_super(sb, wait, 2); |
| 85 | sb->s_dirt = 0; | 80 | sb->s_dirt = 0; |
| 86 | unlock_super(sb); | 81 | unlock_super(sb); |
| 87 | return 0; | 82 | return 0; |
| @@ -140,8 +135,7 @@ static const struct super_operations affs_sops = { | |||
| 140 | .alloc_inode = affs_alloc_inode, | 135 | .alloc_inode = affs_alloc_inode, |
| 141 | .destroy_inode = affs_destroy_inode, | 136 | .destroy_inode = affs_destroy_inode, |
| 142 | .write_inode = affs_write_inode, | 137 | .write_inode = affs_write_inode, |
| 143 | .delete_inode = affs_delete_inode, | 138 | .evict_inode = affs_evict_inode, |
| 144 | .clear_inode = affs_clear_inode, | ||
| 145 | .put_super = affs_put_super, | 139 | .put_super = affs_put_super, |
| 146 | .write_super = affs_write_super, | 140 | .write_super = affs_write_super, |
| 147 | .sync_fs = affs_sync_fs, | 141 | .sync_fs = affs_sync_fs, |
| @@ -554,9 +548,7 @@ affs_remount(struct super_block *sb, int *flags, char *data) | |||
| 554 | return 0; | 548 | return 0; |
| 555 | } | 549 | } |
| 556 | if (*flags & MS_RDONLY) { | 550 | if (*flags & MS_RDONLY) { |
| 557 | sb->s_dirt = 1; | 551 | affs_write_super(sb); |
| 558 | while (sb->s_dirt) | ||
| 559 | affs_write_super(sb); | ||
| 560 | affs_free_bitmap(sb); | 552 | affs_free_bitmap(sb); |
| 561 | } else | 553 | } else |
| 562 | res = affs_init_bitmap(sb, flags); | 554 | res = affs_init_bitmap(sb, flags); |
diff --git a/fs/afs/cell.c b/fs/afs/cell.c index ffea35c63879..0d5eeadf6121 100644 --- a/fs/afs/cell.c +++ b/fs/afs/cell.c | |||
| @@ -31,21 +31,20 @@ static struct afs_cell *afs_cell_root; | |||
| 31 | * allocate a cell record and fill in its name, VL server address list and | 31 | * allocate a cell record and fill in its name, VL server address list and |
| 32 | * allocate an anonymous key | 32 | * allocate an anonymous key |
| 33 | */ | 33 | */ |
| 34 | static struct afs_cell *afs_cell_alloc(const char *name, char *vllist) | 34 | static struct afs_cell *afs_cell_alloc(const char *name, unsigned namelen, |
| 35 | char *vllist) | ||
| 35 | { | 36 | { |
| 36 | struct afs_cell *cell; | 37 | struct afs_cell *cell; |
| 37 | struct key *key; | 38 | struct key *key; |
| 38 | size_t namelen; | ||
| 39 | char keyname[4 + AFS_MAXCELLNAME + 1], *cp, *dp, *next; | 39 | char keyname[4 + AFS_MAXCELLNAME + 1], *cp, *dp, *next; |
| 40 | char *dvllist = NULL, *_vllist = NULL; | 40 | char *dvllist = NULL, *_vllist = NULL; |
| 41 | char delimiter = ':'; | 41 | char delimiter = ':'; |
| 42 | int ret; | 42 | int ret; |
| 43 | 43 | ||
| 44 | _enter("%s,%s", name, vllist); | 44 | _enter("%*.*s,%s", namelen, namelen, name ?: "", vllist); |
| 45 | 45 | ||
| 46 | BUG_ON(!name); /* TODO: want to look up "this cell" in the cache */ | 46 | BUG_ON(!name); /* TODO: want to look up "this cell" in the cache */ |
| 47 | 47 | ||
| 48 | namelen = strlen(name); | ||
| 49 | if (namelen > AFS_MAXCELLNAME) { | 48 | if (namelen > AFS_MAXCELLNAME) { |
| 50 | _leave(" = -ENAMETOOLONG"); | 49 | _leave(" = -ENAMETOOLONG"); |
| 51 | return ERR_PTR(-ENAMETOOLONG); | 50 | return ERR_PTR(-ENAMETOOLONG); |
| @@ -73,6 +72,10 @@ static struct afs_cell *afs_cell_alloc(const char *name, char *vllist) | |||
| 73 | if (!vllist || strlen(vllist) < 7) { | 72 | if (!vllist || strlen(vllist) < 7) { |
| 74 | ret = dns_query("afsdb", name, namelen, "ipv4", &dvllist, NULL); | 73 | ret = dns_query("afsdb", name, namelen, "ipv4", &dvllist, NULL); |
| 75 | if (ret < 0) { | 74 | if (ret < 0) { |
| 75 | if (ret == -ENODATA || ret == -EAGAIN || ret == -ENOKEY) | ||
| 76 | /* translate these errors into something | ||
| 77 | * userspace might understand */ | ||
| 78 | ret = -EDESTADDRREQ; | ||
| 76 | _leave(" = %d", ret); | 79 | _leave(" = %d", ret); |
| 77 | return ERR_PTR(ret); | 80 | return ERR_PTR(ret); |
| 78 | } | 81 | } |
| @@ -138,26 +141,29 @@ error: | |||
| 138 | } | 141 | } |
| 139 | 142 | ||
| 140 | /* | 143 | /* |
| 141 | * create a cell record | 144 | * afs_cell_crate() - create a cell record |
| 142 | * - "name" is the name of the cell | 145 | * @name: is the name of the cell. |
| 143 | * - "vllist" is a colon separated list of IP addresses in "a.b.c.d" format | 146 | * @namsesz: is the strlen of the cell name. |
| 147 | * @vllist: is a colon separated list of IP addresses in "a.b.c.d" format. | ||
| 148 | * @retref: is T to return the cell reference when the cell exists. | ||
| 144 | */ | 149 | */ |
| 145 | struct afs_cell *afs_cell_create(const char *name, char *vllist) | 150 | struct afs_cell *afs_cell_create(const char *name, unsigned namesz, |
| 151 | char *vllist, bool retref) | ||
| 146 | { | 152 | { |
| 147 | struct afs_cell *cell; | 153 | struct afs_cell *cell; |
| 148 | int ret; | 154 | int ret; |
| 149 | 155 | ||
| 150 | _enter("%s,%s", name, vllist); | 156 | _enter("%*.*s,%s", namesz, namesz, name ?: "", vllist); |
| 151 | 157 | ||
| 152 | down_write(&afs_cells_sem); | 158 | down_write(&afs_cells_sem); |
| 153 | read_lock(&afs_cells_lock); | 159 | read_lock(&afs_cells_lock); |
| 154 | list_for_each_entry(cell, &afs_cells, link) { | 160 | list_for_each_entry(cell, &afs_cells, link) { |
| 155 | if (strcasecmp(cell->name, name) == 0) | 161 | if (strncasecmp(cell->name, name, namesz) == 0) |
| 156 | goto duplicate_name; | 162 | goto duplicate_name; |
| 157 | } | 163 | } |
| 158 | read_unlock(&afs_cells_lock); | 164 | read_unlock(&afs_cells_lock); |
| 159 | 165 | ||
| 160 | cell = afs_cell_alloc(name, vllist); | 166 | cell = afs_cell_alloc(name, namesz, vllist); |
| 161 | if (IS_ERR(cell)) { | 167 | if (IS_ERR(cell)) { |
| 162 | _leave(" = %ld", PTR_ERR(cell)); | 168 | _leave(" = %ld", PTR_ERR(cell)); |
| 163 | up_write(&afs_cells_sem); | 169 | up_write(&afs_cells_sem); |
| @@ -197,8 +203,18 @@ error: | |||
| 197 | return ERR_PTR(ret); | 203 | return ERR_PTR(ret); |
| 198 | 204 | ||
| 199 | duplicate_name: | 205 | duplicate_name: |
| 206 | if (retref && !IS_ERR(cell)) | ||
| 207 | afs_get_cell(cell); | ||
| 208 | |||
| 200 | read_unlock(&afs_cells_lock); | 209 | read_unlock(&afs_cells_lock); |
| 201 | up_write(&afs_cells_sem); | 210 | up_write(&afs_cells_sem); |
| 211 | |||
| 212 | if (retref) { | ||
| 213 | _leave(" = %p", cell); | ||
| 214 | return cell; | ||
| 215 | } | ||
| 216 | |||
| 217 | _leave(" = -EEXIST"); | ||
| 202 | return ERR_PTR(-EEXIST); | 218 | return ERR_PTR(-EEXIST); |
| 203 | } | 219 | } |
| 204 | 220 | ||
| @@ -229,7 +245,7 @@ int afs_cell_init(char *rootcell) | |||
| 229 | *cp++ = 0; | 245 | *cp++ = 0; |
| 230 | 246 | ||
| 231 | /* allocate a cell record for the root cell */ | 247 | /* allocate a cell record for the root cell */ |
| 232 | new_root = afs_cell_create(rootcell, cp); | 248 | new_root = afs_cell_create(rootcell, strlen(rootcell), cp, false); |
| 233 | if (IS_ERR(new_root)) { | 249 | if (IS_ERR(new_root)) { |
| 234 | _leave(" = %ld", PTR_ERR(new_root)); | 250 | _leave(" = %ld", PTR_ERR(new_root)); |
| 235 | return PTR_ERR(new_root); | 251 | return PTR_ERR(new_root); |
| @@ -249,11 +265,12 @@ int afs_cell_init(char *rootcell) | |||
| 249 | /* | 265 | /* |
| 250 | * lookup a cell record | 266 | * lookup a cell record |
| 251 | */ | 267 | */ |
| 252 | struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz) | 268 | struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz, |
| 269 | bool dns_cell) | ||
| 253 | { | 270 | { |
| 254 | struct afs_cell *cell; | 271 | struct afs_cell *cell; |
| 255 | 272 | ||
| 256 | _enter("\"%*.*s\",", namesz, namesz, name ? name : ""); | 273 | _enter("\"%*.*s\",", namesz, namesz, name ?: ""); |
| 257 | 274 | ||
| 258 | down_read(&afs_cells_sem); | 275 | down_read(&afs_cells_sem); |
| 259 | read_lock(&afs_cells_lock); | 276 | read_lock(&afs_cells_lock); |
| @@ -267,6 +284,8 @@ struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz) | |||
| 267 | } | 284 | } |
| 268 | } | 285 | } |
| 269 | cell = ERR_PTR(-ENOENT); | 286 | cell = ERR_PTR(-ENOENT); |
| 287 | if (dns_cell) | ||
| 288 | goto create_cell; | ||
| 270 | found: | 289 | found: |
| 271 | ; | 290 | ; |
| 272 | } else { | 291 | } else { |
| @@ -289,6 +308,15 @@ struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz) | |||
| 289 | up_read(&afs_cells_sem); | 308 | up_read(&afs_cells_sem); |
| 290 | _leave(" = %p", cell); | 309 | _leave(" = %p", cell); |
| 291 | return cell; | 310 | return cell; |
| 311 | |||
| 312 | create_cell: | ||
| 313 | read_unlock(&afs_cells_lock); | ||
| 314 | up_read(&afs_cells_sem); | ||
| 315 | |||
| 316 | cell = afs_cell_create(name, namesz, NULL, true); | ||
| 317 | |||
| 318 | _leave(" = %p", cell); | ||
| 319 | return cell; | ||
| 292 | } | 320 | } |
| 293 | 321 | ||
| 294 | #if 0 | 322 | #if 0 |
diff --git a/fs/afs/dir.c b/fs/afs/dir.c index b42d5cc1d6d2..0d38c09bd55e 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c | |||
| @@ -477,6 +477,40 @@ static int afs_do_lookup(struct inode *dir, struct dentry *dentry, | |||
| 477 | } | 477 | } |
| 478 | 478 | ||
| 479 | /* | 479 | /* |
| 480 | * Try to auto mount the mountpoint with pseudo directory, if the autocell | ||
| 481 | * operation is setted. | ||
| 482 | */ | ||
| 483 | static struct inode *afs_try_auto_mntpt( | ||
| 484 | int ret, struct dentry *dentry, struct inode *dir, struct key *key, | ||
| 485 | struct afs_fid *fid) | ||
| 486 | { | ||
| 487 | const char *devname = dentry->d_name.name; | ||
| 488 | struct afs_vnode *vnode = AFS_FS_I(dir); | ||
| 489 | struct inode *inode; | ||
| 490 | |||
| 491 | _enter("%d, %p{%s}, {%x:%u}, %p", | ||
| 492 | ret, dentry, devname, vnode->fid.vid, vnode->fid.vnode, key); | ||
| 493 | |||
| 494 | if (ret != -ENOENT || | ||
| 495 | !test_bit(AFS_VNODE_AUTOCELL, &vnode->flags)) | ||
| 496 | goto out; | ||
| 497 | |||
| 498 | inode = afs_iget_autocell(dir, devname, strlen(devname), key); | ||
| 499 | if (IS_ERR(inode)) { | ||
| 500 | ret = PTR_ERR(inode); | ||
| 501 | goto out; | ||
| 502 | } | ||
| 503 | |||
| 504 | *fid = AFS_FS_I(inode)->fid; | ||
| 505 | _leave("= %p", inode); | ||
| 506 | return inode; | ||
| 507 | |||
| 508 | out: | ||
| 509 | _leave("= %d", ret); | ||
| 510 | return ERR_PTR(ret); | ||
| 511 | } | ||
| 512 | |||
| 513 | /* | ||
| 480 | * look up an entry in a directory | 514 | * look up an entry in a directory |
| 481 | */ | 515 | */ |
| 482 | static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, | 516 | static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, |
| @@ -520,6 +554,13 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, | |||
| 520 | 554 | ||
| 521 | ret = afs_do_lookup(dir, dentry, &fid, key); | 555 | ret = afs_do_lookup(dir, dentry, &fid, key); |
| 522 | if (ret < 0) { | 556 | if (ret < 0) { |
| 557 | inode = afs_try_auto_mntpt(ret, dentry, dir, key, &fid); | ||
| 558 | if (!IS_ERR(inode)) { | ||
| 559 | key_put(key); | ||
| 560 | goto success; | ||
| 561 | } | ||
| 562 | |||
| 563 | ret = PTR_ERR(inode); | ||
| 523 | key_put(key); | 564 | key_put(key); |
| 524 | if (ret == -ENOENT) { | 565 | if (ret == -ENOENT) { |
| 525 | d_add(dentry, NULL); | 566 | d_add(dentry, NULL); |
| @@ -539,6 +580,7 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, | |||
| 539 | return ERR_CAST(inode); | 580 | return ERR_CAST(inode); |
| 540 | } | 581 | } |
| 541 | 582 | ||
| 583 | success: | ||
| 542 | dentry->d_op = &afs_fs_dentry_operations; | 584 | dentry->d_op = &afs_fs_dentry_operations; |
| 543 | 585 | ||
| 544 | d_add(dentry, inode); | 586 | d_add(dentry, inode); |
| @@ -696,8 +738,9 @@ static int afs_d_delete(struct dentry *dentry) | |||
| 696 | goto zap; | 738 | goto zap; |
| 697 | 739 | ||
| 698 | if (dentry->d_inode && | 740 | if (dentry->d_inode && |
| 699 | test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dentry->d_inode)->flags)) | 741 | (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(dentry->d_inode)->flags) || |
| 700 | goto zap; | 742 | test_bit(AFS_VNODE_PSEUDODIR, &AFS_FS_I(dentry->d_inode)->flags))) |
| 743 | goto zap; | ||
| 701 | 744 | ||
| 702 | _leave(" = 0 [keep]"); | 745 | _leave(" = 0 [keep]"); |
| 703 | return 0; | 746 | return 0; |
diff --git a/fs/afs/inode.c b/fs/afs/inode.c index d00b312e3110..0747339011c3 100644 --- a/fs/afs/inode.c +++ b/fs/afs/inode.c | |||
| @@ -19,6 +19,8 @@ | |||
| 19 | #include <linux/fs.h> | 19 | #include <linux/fs.h> |
| 20 | #include <linux/pagemap.h> | 20 | #include <linux/pagemap.h> |
| 21 | #include <linux/sched.h> | 21 | #include <linux/sched.h> |
| 22 | #include <linux/mount.h> | ||
| 23 | #include <linux/namei.h> | ||
| 22 | #include "internal.h" | 24 | #include "internal.h" |
| 23 | 25 | ||
| 24 | struct afs_iget_data { | 26 | struct afs_iget_data { |
| @@ -102,6 +104,16 @@ static int afs_iget5_test(struct inode *inode, void *opaque) | |||
| 102 | } | 104 | } |
| 103 | 105 | ||
| 104 | /* | 106 | /* |
| 107 | * iget5() comparator for inode created by autocell operations | ||
| 108 | * | ||
| 109 | * These pseudo inodes don't match anything. | ||
| 110 | */ | ||
| 111 | static int afs_iget5_autocell_test(struct inode *inode, void *opaque) | ||
| 112 | { | ||
| 113 | return 0; | ||
| 114 | } | ||
| 115 | |||
| 116 | /* | ||
| 105 | * iget5() inode initialiser | 117 | * iget5() inode initialiser |
| 106 | */ | 118 | */ |
| 107 | static int afs_iget5_set(struct inode *inode, void *opaque) | 119 | static int afs_iget5_set(struct inode *inode, void *opaque) |
| @@ -118,6 +130,67 @@ static int afs_iget5_set(struct inode *inode, void *opaque) | |||
| 118 | } | 130 | } |
| 119 | 131 | ||
| 120 | /* | 132 | /* |
| 133 | * inode retrieval for autocell | ||
| 134 | */ | ||
| 135 | struct inode *afs_iget_autocell(struct inode *dir, const char *dev_name, | ||
| 136 | int namesz, struct key *key) | ||
| 137 | { | ||
| 138 | struct afs_iget_data data; | ||
| 139 | struct afs_super_info *as; | ||
| 140 | struct afs_vnode *vnode; | ||
| 141 | struct super_block *sb; | ||
| 142 | struct inode *inode; | ||
| 143 | static atomic_t afs_autocell_ino; | ||
| 144 | |||
| 145 | _enter("{%x:%u},%*.*s,", | ||
| 146 | AFS_FS_I(dir)->fid.vid, AFS_FS_I(dir)->fid.vnode, | ||
| 147 | namesz, namesz, dev_name ?: ""); | ||
| 148 | |||
| 149 | sb = dir->i_sb; | ||
| 150 | as = sb->s_fs_info; | ||
| 151 | data.volume = as->volume; | ||
| 152 | data.fid.vid = as->volume->vid; | ||
| 153 | data.fid.unique = 0; | ||
| 154 | data.fid.vnode = 0; | ||
| 155 | |||
| 156 | inode = iget5_locked(sb, atomic_inc_return(&afs_autocell_ino), | ||
| 157 | afs_iget5_autocell_test, afs_iget5_set, | ||
| 158 | &data); | ||
| 159 | if (!inode) { | ||
| 160 | _leave(" = -ENOMEM"); | ||
| 161 | return ERR_PTR(-ENOMEM); | ||
| 162 | } | ||
| 163 | |||
| 164 | _debug("GOT INODE %p { ino=%lu, vl=%x, vn=%x, u=%x }", | ||
| 165 | inode, inode->i_ino, data.fid.vid, data.fid.vnode, | ||
| 166 | data.fid.unique); | ||
| 167 | |||
| 168 | vnode = AFS_FS_I(inode); | ||
| 169 | |||
| 170 | /* there shouldn't be an existing inode */ | ||
| 171 | BUG_ON(!(inode->i_state & I_NEW)); | ||
| 172 | |||
| 173 | inode->i_size = 0; | ||
| 174 | inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; | ||
| 175 | inode->i_op = &afs_autocell_inode_operations; | ||
| 176 | inode->i_nlink = 2; | ||
| 177 | inode->i_uid = 0; | ||
| 178 | inode->i_gid = 0; | ||
| 179 | inode->i_ctime.tv_sec = get_seconds(); | ||
| 180 | inode->i_ctime.tv_nsec = 0; | ||
| 181 | inode->i_atime = inode->i_mtime = inode->i_ctime; | ||
| 182 | inode->i_blocks = 0; | ||
| 183 | inode->i_version = 0; | ||
| 184 | inode->i_generation = 0; | ||
| 185 | |||
| 186 | set_bit(AFS_VNODE_PSEUDODIR, &vnode->flags); | ||
| 187 | inode->i_flags |= S_NOATIME; | ||
| 188 | unlock_new_inode(inode); | ||
| 189 | _leave(" = %p", inode); | ||
| 190 | return inode; | ||
| 191 | } | ||
| 192 | |||
| 193 | /* | ||
| 121 | * inode retrieval | 194 | * inode retrieval |
| 122 | */ | 195 | */ |
| 123 | struct inode *afs_iget(struct super_block *sb, struct key *key, | 196 | struct inode *afs_iget(struct super_block *sb, struct key *key, |
| @@ -314,9 +387,22 @@ int afs_getattr(struct vfsmount *mnt, struct dentry *dentry, | |||
| 314 | } | 387 | } |
| 315 | 388 | ||
| 316 | /* | 389 | /* |
| 390 | * discard an AFS inode | ||
| 391 | */ | ||
| 392 | int afs_drop_inode(struct inode *inode) | ||
| 393 | { | ||
| 394 | _enter(""); | ||
| 395 | |||
| 396 | if (test_bit(AFS_VNODE_PSEUDODIR, &AFS_FS_I(inode)->flags)) | ||
| 397 | return generic_delete_inode(inode); | ||
| 398 | else | ||
| 399 | return generic_drop_inode(inode); | ||
| 400 | } | ||
| 401 | |||
| 402 | /* | ||
| 317 | * clear an AFS inode | 403 | * clear an AFS inode |
| 318 | */ | 404 | */ |
| 319 | void afs_clear_inode(struct inode *inode) | 405 | void afs_evict_inode(struct inode *inode) |
| 320 | { | 406 | { |
| 321 | struct afs_permits *permits; | 407 | struct afs_permits *permits; |
| 322 | struct afs_vnode *vnode; | 408 | struct afs_vnode *vnode; |
| @@ -335,6 +421,9 @@ void afs_clear_inode(struct inode *inode) | |||
| 335 | 421 | ||
| 336 | ASSERTCMP(inode->i_ino, ==, vnode->fid.vnode); | 422 | ASSERTCMP(inode->i_ino, ==, vnode->fid.vnode); |
| 337 | 423 | ||
| 424 | truncate_inode_pages(&inode->i_data, 0); | ||
| 425 | end_writeback(inode); | ||
| 426 | |||
| 338 | afs_give_up_callback(vnode); | 427 | afs_give_up_callback(vnode); |
| 339 | 428 | ||
| 340 | if (vnode->server) { | 429 | if (vnode->server) { |
diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 5f679b77ce24..cca8eef736fc 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h | |||
| @@ -42,6 +42,7 @@ typedef enum { | |||
| 42 | struct afs_mount_params { | 42 | struct afs_mount_params { |
| 43 | bool rwpath; /* T if the parent should be considered R/W */ | 43 | bool rwpath; /* T if the parent should be considered R/W */ |
| 44 | bool force; /* T to force cell type */ | 44 | bool force; /* T to force cell type */ |
| 45 | bool autocell; /* T if set auto mount operation */ | ||
| 45 | afs_voltype_t type; /* type of volume requested */ | 46 | afs_voltype_t type; /* type of volume requested */ |
| 46 | int volnamesz; /* size of volume name */ | 47 | int volnamesz; /* size of volume name */ |
| 47 | const char *volname; /* name of volume to mount */ | 48 | const char *volname; /* name of volume to mount */ |
| @@ -358,6 +359,8 @@ struct afs_vnode { | |||
| 358 | #define AFS_VNODE_READLOCKED 7 /* set if vnode is read-locked on the server */ | 359 | #define AFS_VNODE_READLOCKED 7 /* set if vnode is read-locked on the server */ |
| 359 | #define AFS_VNODE_WRITELOCKED 8 /* set if vnode is write-locked on the server */ | 360 | #define AFS_VNODE_WRITELOCKED 8 /* set if vnode is write-locked on the server */ |
| 360 | #define AFS_VNODE_UNLOCKING 9 /* set if vnode is being unlocked on the server */ | 361 | #define AFS_VNODE_UNLOCKING 9 /* set if vnode is being unlocked on the server */ |
| 362 | #define AFS_VNODE_AUTOCELL 10 /* set if Vnode is an auto mount point */ | ||
| 363 | #define AFS_VNODE_PSEUDODIR 11 /* set if Vnode is a pseudo directory */ | ||
| 361 | 364 | ||
| 362 | long acl_order; /* ACL check count (callback break count) */ | 365 | long acl_order; /* ACL check count (callback break count) */ |
| 363 | 366 | ||
| @@ -468,8 +471,8 @@ extern struct list_head afs_proc_cells; | |||
| 468 | 471 | ||
| 469 | #define afs_get_cell(C) do { atomic_inc(&(C)->usage); } while(0) | 472 | #define afs_get_cell(C) do { atomic_inc(&(C)->usage); } while(0) |
| 470 | extern int afs_cell_init(char *); | 473 | extern int afs_cell_init(char *); |
| 471 | extern struct afs_cell *afs_cell_create(const char *, char *); | 474 | extern struct afs_cell *afs_cell_create(const char *, unsigned, char *, bool); |
| 472 | extern struct afs_cell *afs_cell_lookup(const char *, unsigned); | 475 | extern struct afs_cell *afs_cell_lookup(const char *, unsigned, bool); |
| 473 | extern struct afs_cell *afs_grab_cell(struct afs_cell *); | 476 | extern struct afs_cell *afs_grab_cell(struct afs_cell *); |
| 474 | extern void afs_put_cell(struct afs_cell *); | 477 | extern void afs_put_cell(struct afs_cell *); |
| 475 | extern void afs_cell_purge(void); | 478 | extern void afs_cell_purge(void); |
| @@ -558,6 +561,8 @@ extern int afs_fs_release_lock(struct afs_server *, struct key *, | |||
| 558 | /* | 561 | /* |
| 559 | * inode.c | 562 | * inode.c |
| 560 | */ | 563 | */ |
| 564 | extern struct inode *afs_iget_autocell(struct inode *, const char *, int, | ||
| 565 | struct key *); | ||
| 561 | extern struct inode *afs_iget(struct super_block *, struct key *, | 566 | extern struct inode *afs_iget(struct super_block *, struct key *, |
| 562 | struct afs_fid *, struct afs_file_status *, | 567 | struct afs_fid *, struct afs_file_status *, |
| 563 | struct afs_callback *); | 568 | struct afs_callback *); |
| @@ -565,7 +570,8 @@ extern void afs_zap_data(struct afs_vnode *); | |||
| 565 | extern int afs_validate(struct afs_vnode *, struct key *); | 570 | extern int afs_validate(struct afs_vnode *, struct key *); |
| 566 | extern int afs_getattr(struct vfsmount *, struct dentry *, struct kstat *); | 571 | extern int afs_getattr(struct vfsmount *, struct dentry *, struct kstat *); |
| 567 | extern int afs_setattr(struct dentry *, struct iattr *); | 572 | extern int afs_setattr(struct dentry *, struct iattr *); |
| 568 | extern void afs_clear_inode(struct inode *); | 573 | extern void afs_evict_inode(struct inode *); |
| 574 | extern int afs_drop_inode(struct inode *); | ||
| 569 | 575 | ||
| 570 | /* | 576 | /* |
| 571 | * main.c | 577 | * main.c |
| @@ -581,6 +587,7 @@ extern int afs_abort_to_error(u32); | |||
| 581 | * mntpt.c | 587 | * mntpt.c |
| 582 | */ | 588 | */ |
| 583 | extern const struct inode_operations afs_mntpt_inode_operations; | 589 | extern const struct inode_operations afs_mntpt_inode_operations; |
| 590 | extern const struct inode_operations afs_autocell_inode_operations; | ||
| 584 | extern const struct file_operations afs_mntpt_file_operations; | 591 | extern const struct file_operations afs_mntpt_file_operations; |
| 585 | 592 | ||
| 586 | extern int afs_mntpt_check_symlink(struct afs_vnode *, struct key *); | 593 | extern int afs_mntpt_check_symlink(struct afs_vnode *, struct key *); |
| @@ -752,12 +759,6 @@ extern unsigned afs_debug; | |||
| 752 | #define dbgprintk(FMT,...) \ | 759 | #define dbgprintk(FMT,...) \ |
| 753 | printk("[%-6.6s] "FMT"\n", current->comm ,##__VA_ARGS__) | 760 | printk("[%-6.6s] "FMT"\n", current->comm ,##__VA_ARGS__) |
| 754 | 761 | ||
| 755 | /* make sure we maintain the format strings, even when debugging is disabled */ | ||
| 756 | static inline __attribute__((format(printf,1,2))) | ||
| 757 | void _dbprintk(const char *fmt, ...) | ||
| 758 | { | ||
| 759 | } | ||
| 760 | |||
| 761 | #define kenter(FMT,...) dbgprintk("==> %s("FMT")",__func__ ,##__VA_ARGS__) | 762 | #define kenter(FMT,...) dbgprintk("==> %s("FMT")",__func__ ,##__VA_ARGS__) |
| 762 | #define kleave(FMT,...) dbgprintk("<== %s()"FMT"",__func__ ,##__VA_ARGS__) | 763 | #define kleave(FMT,...) dbgprintk("<== %s()"FMT"",__func__ ,##__VA_ARGS__) |
| 763 | #define kdebug(FMT,...) dbgprintk(" "FMT ,##__VA_ARGS__) | 764 | #define kdebug(FMT,...) dbgprintk(" "FMT ,##__VA_ARGS__) |
| @@ -792,9 +793,9 @@ do { \ | |||
| 792 | } while (0) | 793 | } while (0) |
| 793 | 794 | ||
| 794 | #else | 795 | #else |
| 795 | #define _enter(FMT,...) _dbprintk("==> %s("FMT")",__func__ ,##__VA_ARGS__) | 796 | #define _enter(FMT,...) no_printk("==> %s("FMT")",__func__ ,##__VA_ARGS__) |
| 796 | #define _leave(FMT,...) _dbprintk("<== %s()"FMT"",__func__ ,##__VA_ARGS__) | 797 | #define _leave(FMT,...) no_printk("<== %s()"FMT"",__func__ ,##__VA_ARGS__) |
| 797 | #define _debug(FMT,...) _dbprintk(" "FMT ,##__VA_ARGS__) | 798 | #define _debug(FMT,...) no_printk(" "FMT ,##__VA_ARGS__) |
| 798 | #endif | 799 | #endif |
| 799 | 800 | ||
| 800 | /* | 801 | /* |
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c index a9e23039ea34..6d552686c498 100644 --- a/fs/afs/mntpt.c +++ b/fs/afs/mntpt.c | |||
| @@ -38,6 +38,11 @@ const struct inode_operations afs_mntpt_inode_operations = { | |||
| 38 | .getattr = afs_getattr, | 38 | .getattr = afs_getattr, |
| 39 | }; | 39 | }; |
| 40 | 40 | ||
| 41 | const struct inode_operations afs_autocell_inode_operations = { | ||
| 42 | .follow_link = afs_mntpt_follow_link, | ||
| 43 | .getattr = afs_getattr, | ||
| 44 | }; | ||
| 45 | |||
| 41 | static LIST_HEAD(afs_vfsmounts); | 46 | static LIST_HEAD(afs_vfsmounts); |
| 42 | static DECLARE_DELAYED_WORK(afs_mntpt_expiry_timer, afs_mntpt_expiry_timed_out); | 47 | static DECLARE_DELAYED_WORK(afs_mntpt_expiry_timer, afs_mntpt_expiry_timed_out); |
| 43 | 48 | ||
| @@ -136,20 +141,16 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt) | |||
| 136 | { | 141 | { |
| 137 | struct afs_super_info *super; | 142 | struct afs_super_info *super; |
| 138 | struct vfsmount *mnt; | 143 | struct vfsmount *mnt; |
| 144 | struct afs_vnode *vnode; | ||
| 139 | struct page *page; | 145 | struct page *page; |
| 140 | size_t size; | 146 | char *devname, *options; |
| 141 | char *buf, *devname, *options; | 147 | bool rwpath = false; |
| 142 | int ret; | 148 | int ret; |
| 143 | 149 | ||
| 144 | _enter("{%s}", mntpt->d_name.name); | 150 | _enter("{%s}", mntpt->d_name.name); |
| 145 | 151 | ||
| 146 | BUG_ON(!mntpt->d_inode); | 152 | BUG_ON(!mntpt->d_inode); |
| 147 | 153 | ||
| 148 | ret = -EINVAL; | ||
| 149 | size = mntpt->d_inode->i_size; | ||
| 150 | if (size > PAGE_SIZE - 1) | ||
| 151 | goto error_no_devname; | ||
| 152 | |||
| 153 | ret = -ENOMEM; | 154 | ret = -ENOMEM; |
| 154 | devname = (char *) get_zeroed_page(GFP_KERNEL); | 155 | devname = (char *) get_zeroed_page(GFP_KERNEL); |
| 155 | if (!devname) | 156 | if (!devname) |
| @@ -159,28 +160,59 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt) | |||
| 159 | if (!options) | 160 | if (!options) |
| 160 | goto error_no_options; | 161 | goto error_no_options; |
| 161 | 162 | ||
| 162 | /* read the contents of the AFS special symlink */ | 163 | vnode = AFS_FS_I(mntpt->d_inode); |
| 163 | page = read_mapping_page(mntpt->d_inode->i_mapping, 0, NULL); | 164 | if (test_bit(AFS_VNODE_PSEUDODIR, &vnode->flags)) { |
| 164 | if (IS_ERR(page)) { | 165 | /* if the directory is a pseudo directory, use the d_name */ |
| 165 | ret = PTR_ERR(page); | 166 | static const char afs_root_cell[] = ":root.cell."; |
| 166 | goto error_no_page; | 167 | unsigned size = mntpt->d_name.len; |
| 168 | |||
| 169 | ret = -ENOENT; | ||
| 170 | if (size < 2 || size > AFS_MAXCELLNAME) | ||
| 171 | goto error_no_page; | ||
| 172 | |||
| 173 | if (mntpt->d_name.name[0] == '.') { | ||
| 174 | devname[0] = '#'; | ||
| 175 | memcpy(devname + 1, mntpt->d_name.name, size - 1); | ||
| 176 | memcpy(devname + size, afs_root_cell, | ||
| 177 | sizeof(afs_root_cell)); | ||
| 178 | rwpath = true; | ||
| 179 | } else { | ||
| 180 | devname[0] = '%'; | ||
| 181 | memcpy(devname + 1, mntpt->d_name.name, size); | ||
| 182 | memcpy(devname + size + 1, afs_root_cell, | ||
| 183 | sizeof(afs_root_cell)); | ||
| 184 | } | ||
| 185 | } else { | ||
| 186 | /* read the contents of the AFS special symlink */ | ||
| 187 | loff_t size = i_size_read(mntpt->d_inode); | ||
| 188 | char *buf; | ||
| 189 | |||
| 190 | ret = -EINVAL; | ||
| 191 | if (size > PAGE_SIZE - 1) | ||
| 192 | goto error_no_page; | ||
| 193 | |||
| 194 | page = read_mapping_page(mntpt->d_inode->i_mapping, 0, NULL); | ||
| 195 | if (IS_ERR(page)) { | ||
| 196 | ret = PTR_ERR(page); | ||
| 197 | goto error_no_page; | ||
| 198 | } | ||
| 199 | |||
| 200 | ret = -EIO; | ||
| 201 | if (PageError(page)) | ||
| 202 | goto error; | ||
| 203 | |||
| 204 | buf = kmap_atomic(page, KM_USER0); | ||
| 205 | memcpy(devname, buf, size); | ||
| 206 | kunmap_atomic(buf, KM_USER0); | ||
| 207 | page_cache_release(page); | ||
| 208 | page = NULL; | ||
| 167 | } | 209 | } |
| 168 | 210 | ||
| 169 | ret = -EIO; | ||
| 170 | if (PageError(page)) | ||
| 171 | goto error; | ||
| 172 | |||
| 173 | buf = kmap_atomic(page, KM_USER0); | ||
| 174 | memcpy(devname, buf, size); | ||
| 175 | kunmap_atomic(buf, KM_USER0); | ||
| 176 | page_cache_release(page); | ||
| 177 | page = NULL; | ||
| 178 | |||
| 179 | /* work out what options we want */ | 211 | /* work out what options we want */ |
| 180 | super = AFS_FS_S(mntpt->d_sb); | 212 | super = AFS_FS_S(mntpt->d_sb); |
| 181 | memcpy(options, "cell=", 5); | 213 | memcpy(options, "cell=", 5); |
| 182 | strcpy(options + 5, super->volume->cell->name); | 214 | strcpy(options + 5, super->volume->cell->name); |
| 183 | if (super->volume->type == AFSVL_RWVOL) | 215 | if (super->volume->type == AFSVL_RWVOL || rwpath) |
| 184 | strcat(options, ",rwpath"); | 216 | strcat(options, ",rwpath"); |
| 185 | 217 | ||
| 186 | /* try and do the mount */ | 218 | /* try and do the mount */ |
diff --git a/fs/afs/proc.c b/fs/afs/proc.c index 852739d262a9..096b23f821a1 100644 --- a/fs/afs/proc.c +++ b/fs/afs/proc.c | |||
| @@ -294,7 +294,7 @@ static ssize_t afs_proc_cells_write(struct file *file, const char __user *buf, | |||
| 294 | if (strcmp(kbuf, "add") == 0) { | 294 | if (strcmp(kbuf, "add") == 0) { |
| 295 | struct afs_cell *cell; | 295 | struct afs_cell *cell; |
| 296 | 296 | ||
| 297 | cell = afs_cell_create(name, args); | 297 | cell = afs_cell_create(name, strlen(name), args, false); |
| 298 | if (IS_ERR(cell)) { | 298 | if (IS_ERR(cell)) { |
| 299 | ret = PTR_ERR(cell); | 299 | ret = PTR_ERR(cell); |
| 300 | goto done; | 300 | goto done; |
diff --git a/fs/afs/rxrpc.c b/fs/afs/rxrpc.c index 67cf810e0fd6..654d8fdbf01f 100644 --- a/fs/afs/rxrpc.c +++ b/fs/afs/rxrpc.c | |||
| @@ -100,6 +100,7 @@ int afs_open_socket(void) | |||
| 100 | ret = kernel_bind(socket, (struct sockaddr *) &srx, sizeof(srx)); | 100 | ret = kernel_bind(socket, (struct sockaddr *) &srx, sizeof(srx)); |
| 101 | if (ret < 0) { | 101 | if (ret < 0) { |
| 102 | sock_release(socket); | 102 | sock_release(socket); |
| 103 | destroy_workqueue(afs_async_calls); | ||
| 103 | _leave(" = %d [bind]", ret); | 104 | _leave(" = %d [bind]", ret); |
| 104 | return ret; | 105 | return ret; |
| 105 | } | 106 | } |
diff --git a/fs/afs/super.c b/fs/afs/super.c index e932e5a3a0c1..77e1e5a61154 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | 16 | ||
| 17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
| 18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
| 19 | #include <linux/mount.h> | ||
| 19 | #include <linux/init.h> | 20 | #include <linux/init.h> |
| 20 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
| 21 | #include <linux/smp_lock.h> | 22 | #include <linux/smp_lock.h> |
| @@ -48,8 +49,9 @@ struct file_system_type afs_fs_type = { | |||
| 48 | static const struct super_operations afs_super_ops = { | 49 | static const struct super_operations afs_super_ops = { |
| 49 | .statfs = afs_statfs, | 50 | .statfs = afs_statfs, |
| 50 | .alloc_inode = afs_alloc_inode, | 51 | .alloc_inode = afs_alloc_inode, |
| 52 | .drop_inode = afs_drop_inode, | ||
| 51 | .destroy_inode = afs_destroy_inode, | 53 | .destroy_inode = afs_destroy_inode, |
| 52 | .clear_inode = afs_clear_inode, | 54 | .evict_inode = afs_evict_inode, |
| 53 | .put_super = afs_put_super, | 55 | .put_super = afs_put_super, |
| 54 | .show_options = generic_show_options, | 56 | .show_options = generic_show_options, |
| 55 | }; | 57 | }; |
| @@ -62,12 +64,14 @@ enum { | |||
| 62 | afs_opt_cell, | 64 | afs_opt_cell, |
| 63 | afs_opt_rwpath, | 65 | afs_opt_rwpath, |
| 64 | afs_opt_vol, | 66 | afs_opt_vol, |
| 67 | afs_opt_autocell, | ||
| 65 | }; | 68 | }; |
| 66 | 69 | ||
| 67 | static const match_table_t afs_options_list = { | 70 | static const match_table_t afs_options_list = { |
| 68 | { afs_opt_cell, "cell=%s" }, | 71 | { afs_opt_cell, "cell=%s" }, |
| 69 | { afs_opt_rwpath, "rwpath" }, | 72 | { afs_opt_rwpath, "rwpath" }, |
| 70 | { afs_opt_vol, "vol=%s" }, | 73 | { afs_opt_vol, "vol=%s" }, |
| 74 | { afs_opt_autocell, "autocell" }, | ||
| 71 | { afs_no_opt, NULL }, | 75 | { afs_no_opt, NULL }, |
| 72 | }; | 76 | }; |
| 73 | 77 | ||
| @@ -151,7 +155,8 @@ static int afs_parse_options(struct afs_mount_params *params, | |||
| 151 | switch (token) { | 155 | switch (token) { |
| 152 | case afs_opt_cell: | 156 | case afs_opt_cell: |
| 153 | cell = afs_cell_lookup(args[0].from, | 157 | cell = afs_cell_lookup(args[0].from, |
| 154 | args[0].to - args[0].from); | 158 | args[0].to - args[0].from, |
| 159 | false); | ||
| 155 | if (IS_ERR(cell)) | 160 | if (IS_ERR(cell)) |
| 156 | return PTR_ERR(cell); | 161 | return PTR_ERR(cell); |
| 157 | afs_put_cell(params->cell); | 162 | afs_put_cell(params->cell); |
| @@ -166,6 +171,10 @@ static int afs_parse_options(struct afs_mount_params *params, | |||
| 166 | *devname = args[0].from; | 171 | *devname = args[0].from; |
| 167 | break; | 172 | break; |
| 168 | 173 | ||
| 174 | case afs_opt_autocell: | ||
| 175 | params->autocell = 1; | ||
| 176 | break; | ||
| 177 | |||
| 169 | default: | 178 | default: |
| 170 | printk(KERN_ERR "kAFS:" | 179 | printk(KERN_ERR "kAFS:" |
| 171 | " Unknown or invalid mount option: '%s'\n", p); | 180 | " Unknown or invalid mount option: '%s'\n", p); |
| @@ -252,10 +261,10 @@ static int afs_parse_device_name(struct afs_mount_params *params, | |||
| 252 | 261 | ||
| 253 | /* lookup the cell record */ | 262 | /* lookup the cell record */ |
| 254 | if (cellname || !params->cell) { | 263 | if (cellname || !params->cell) { |
| 255 | cell = afs_cell_lookup(cellname, cellnamesz); | 264 | cell = afs_cell_lookup(cellname, cellnamesz, true); |
| 256 | if (IS_ERR(cell)) { | 265 | if (IS_ERR(cell)) { |
| 257 | printk(KERN_ERR "kAFS: unable to lookup cell '%s'\n", | 266 | printk(KERN_ERR "kAFS: unable to lookup cell '%*.*s'\n", |
| 258 | cellname ?: ""); | 267 | cellnamesz, cellnamesz, cellname ?: ""); |
| 259 | return PTR_ERR(cell); | 268 | return PTR_ERR(cell); |
| 260 | } | 269 | } |
| 261 | afs_put_cell(params->cell); | 270 | afs_put_cell(params->cell); |
| @@ -321,6 +330,9 @@ static int afs_fill_super(struct super_block *sb, void *data) | |||
| 321 | if (IS_ERR(inode)) | 330 | if (IS_ERR(inode)) |
| 322 | goto error_inode; | 331 | goto error_inode; |
| 323 | 332 | ||
| 333 | if (params->autocell) | ||
| 334 | set_bit(AFS_VNODE_AUTOCELL, &AFS_FS_I(inode)->flags); | ||
| 335 | |||
| 324 | ret = -ENOMEM; | 336 | ret = -ENOMEM; |
| 325 | root = d_alloc_root(inode); | 337 | root = d_alloc_root(inode); |
| 326 | if (!root) | 338 | if (!root) |
| @@ -14,35 +14,53 @@ | |||
| 14 | #include <linux/fcntl.h> | 14 | #include <linux/fcntl.h> |
| 15 | #include <linux/security.h> | 15 | #include <linux/security.h> |
| 16 | 16 | ||
| 17 | /* Taken over from the old code... */ | 17 | /** |
| 18 | 18 | * inode_change_ok - check if attribute changes to an inode are allowed | |
| 19 | /* POSIX UID/GID verification for setting inode attributes. */ | 19 | * @inode: inode to check |
| 20 | * @attr: attributes to change | ||
| 21 | * | ||
| 22 | * Check if we are allowed to change the attributes contained in @attr | ||
| 23 | * in the given inode. This includes the normal unix access permission | ||
| 24 | * checks, as well as checks for rlimits and others. | ||
| 25 | * | ||
| 26 | * Should be called as the first thing in ->setattr implementations, | ||
| 27 | * possibly after taking additional locks. | ||
| 28 | */ | ||
| 20 | int inode_change_ok(const struct inode *inode, struct iattr *attr) | 29 | int inode_change_ok(const struct inode *inode, struct iattr *attr) |
| 21 | { | 30 | { |
| 22 | int retval = -EPERM; | ||
| 23 | unsigned int ia_valid = attr->ia_valid; | 31 | unsigned int ia_valid = attr->ia_valid; |
| 24 | 32 | ||
| 33 | /* | ||
| 34 | * First check size constraints. These can't be overriden using | ||
| 35 | * ATTR_FORCE. | ||
| 36 | */ | ||
| 37 | if (ia_valid & ATTR_SIZE) { | ||
| 38 | int error = inode_newsize_ok(inode, attr->ia_size); | ||
| 39 | if (error) | ||
| 40 | return error; | ||
| 41 | } | ||
| 42 | |||
| 25 | /* If force is set do it anyway. */ | 43 | /* If force is set do it anyway. */ |
| 26 | if (ia_valid & ATTR_FORCE) | 44 | if (ia_valid & ATTR_FORCE) |
| 27 | goto fine; | 45 | return 0; |
| 28 | 46 | ||
| 29 | /* Make sure a caller can chown. */ | 47 | /* Make sure a caller can chown. */ |
| 30 | if ((ia_valid & ATTR_UID) && | 48 | if ((ia_valid & ATTR_UID) && |
| 31 | (current_fsuid() != inode->i_uid || | 49 | (current_fsuid() != inode->i_uid || |
| 32 | attr->ia_uid != inode->i_uid) && !capable(CAP_CHOWN)) | 50 | attr->ia_uid != inode->i_uid) && !capable(CAP_CHOWN)) |
| 33 | goto error; | 51 | return -EPERM; |
| 34 | 52 | ||
| 35 | /* Make sure caller can chgrp. */ | 53 | /* Make sure caller can chgrp. */ |
| 36 | if ((ia_valid & ATTR_GID) && | 54 | if ((ia_valid & ATTR_GID) && |
| 37 | (current_fsuid() != inode->i_uid || | 55 | (current_fsuid() != inode->i_uid || |
| 38 | (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid)) && | 56 | (!in_group_p(attr->ia_gid) && attr->ia_gid != inode->i_gid)) && |
| 39 | !capable(CAP_CHOWN)) | 57 | !capable(CAP_CHOWN)) |
| 40 | goto error; | 58 | return -EPERM; |
| 41 | 59 | ||
| 42 | /* Make sure a caller can chmod. */ | 60 | /* Make sure a caller can chmod. */ |
| 43 | if (ia_valid & ATTR_MODE) { | 61 | if (ia_valid & ATTR_MODE) { |
| 44 | if (!is_owner_or_cap(inode)) | 62 | if (!is_owner_or_cap(inode)) |
| 45 | goto error; | 63 | return -EPERM; |
| 46 | /* Also check the setgid bit! */ | 64 | /* Also check the setgid bit! */ |
| 47 | if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid : | 65 | if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid : |
| 48 | inode->i_gid) && !capable(CAP_FSETID)) | 66 | inode->i_gid) && !capable(CAP_FSETID)) |
| @@ -52,12 +70,10 @@ int inode_change_ok(const struct inode *inode, struct iattr *attr) | |||
| 52 | /* Check for setting the inode time. */ | 70 | /* Check for setting the inode time. */ |
| 53 | if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) { | 71 | if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) { |
| 54 | if (!is_owner_or_cap(inode)) | 72 | if (!is_owner_or_cap(inode)) |
| 55 | goto error; | 73 | return -EPERM; |
| 56 | } | 74 | } |
| 57 | fine: | 75 | |
| 58 | retval = 0; | 76 | return 0; |
| 59 | error: | ||
| 60 | return retval; | ||
| 61 | } | 77 | } |
| 62 | EXPORT_SYMBOL(inode_change_ok); | 78 | EXPORT_SYMBOL(inode_change_ok); |
| 63 | 79 | ||
| @@ -105,21 +121,21 @@ out_big: | |||
| 105 | EXPORT_SYMBOL(inode_newsize_ok); | 121 | EXPORT_SYMBOL(inode_newsize_ok); |
| 106 | 122 | ||
| 107 | /** | 123 | /** |
| 108 | * generic_setattr - copy simple metadata updates into the generic inode | 124 | * setattr_copy - copy simple metadata updates into the generic inode |
| 109 | * @inode: the inode to be updated | 125 | * @inode: the inode to be updated |
| 110 | * @attr: the new attributes | 126 | * @attr: the new attributes |
| 111 | * | 127 | * |
| 112 | * generic_setattr must be called with i_mutex held. | 128 | * setattr_copy must be called with i_mutex held. |
| 113 | * | 129 | * |
| 114 | * generic_setattr updates the inode's metadata with that specified | 130 | * setattr_copy updates the inode's metadata with that specified |
| 115 | * in attr. Noticably missing is inode size update, which is more complex | 131 | * in attr. Noticably missing is inode size update, which is more complex |
| 116 | * as it requires pagecache updates. See simple_setsize. | 132 | * as it requires pagecache updates. |
| 117 | * | 133 | * |
| 118 | * The inode is not marked as dirty after this operation. The rationale is | 134 | * The inode is not marked as dirty after this operation. The rationale is |
| 119 | * that for "simple" filesystems, the struct inode is the inode storage. | 135 | * that for "simple" filesystems, the struct inode is the inode storage. |
| 120 | * The caller is free to mark the inode dirty afterwards if needed. | 136 | * The caller is free to mark the inode dirty afterwards if needed. |
| 121 | */ | 137 | */ |
| 122 | void generic_setattr(struct inode *inode, const struct iattr *attr) | 138 | void setattr_copy(struct inode *inode, const struct iattr *attr) |
| 123 | { | 139 | { |
| 124 | unsigned int ia_valid = attr->ia_valid; | 140 | unsigned int ia_valid = attr->ia_valid; |
| 125 | 141 | ||
| @@ -144,32 +160,7 @@ void generic_setattr(struct inode *inode, const struct iattr *attr) | |||
| 144 | inode->i_mode = mode; | 160 | inode->i_mode = mode; |
| 145 | } | 161 | } |
| 146 | } | 162 | } |
| 147 | EXPORT_SYMBOL(generic_setattr); | 163 | EXPORT_SYMBOL(setattr_copy); |
| 148 | |||
| 149 | /* | ||
| 150 | * note this function is deprecated, the new truncate sequence should be | ||
| 151 | * used instead -- see eg. simple_setsize, generic_setattr. | ||
| 152 | */ | ||
| 153 | int inode_setattr(struct inode *inode, const struct iattr *attr) | ||
| 154 | { | ||
| 155 | unsigned int ia_valid = attr->ia_valid; | ||
| 156 | |||
| 157 | if (ia_valid & ATTR_SIZE && | ||
| 158 | attr->ia_size != i_size_read(inode)) { | ||
| 159 | int error; | ||
| 160 | |||
| 161 | error = vmtruncate(inode, attr->ia_size); | ||
| 162 | if (error) | ||
| 163 | return error; | ||
| 164 | } | ||
| 165 | |||
| 166 | generic_setattr(inode, attr); | ||
| 167 | |||
| 168 | mark_inode_dirty(inode); | ||
| 169 | |||
| 170 | return 0; | ||
| 171 | } | ||
| 172 | EXPORT_SYMBOL(inode_setattr); | ||
| 173 | 164 | ||
| 174 | int notify_change(struct dentry * dentry, struct iattr * attr) | 165 | int notify_change(struct dentry * dentry, struct iattr * attr) |
| 175 | { | 166 | { |
| @@ -237,13 +228,10 @@ int notify_change(struct dentry * dentry, struct iattr * attr) | |||
| 237 | if (ia_valid & ATTR_SIZE) | 228 | if (ia_valid & ATTR_SIZE) |
| 238 | down_write(&dentry->d_inode->i_alloc_sem); | 229 | down_write(&dentry->d_inode->i_alloc_sem); |
| 239 | 230 | ||
| 240 | if (inode->i_op && inode->i_op->setattr) { | 231 | if (inode->i_op->setattr) |
| 241 | error = inode->i_op->setattr(dentry, attr); | 232 | error = inode->i_op->setattr(dentry, attr); |
| 242 | } else { | 233 | else |
| 243 | error = inode_change_ok(inode, attr); | 234 | error = simple_setattr(dentry, attr); |
| 244 | if (!error) | ||
| 245 | error = inode_setattr(inode, attr); | ||
| 246 | } | ||
| 247 | 235 | ||
| 248 | if (ia_valid & ATTR_SIZE) | 236 | if (ia_valid & ATTR_SIZE) |
| 249 | up_write(&dentry->d_inode->i_alloc_sem); | 237 | up_write(&dentry->d_inode->i_alloc_sem); |
diff --git a/fs/autofs/root.c b/fs/autofs/root.c index 9a0520b50663..11b1ea786d00 100644 --- a/fs/autofs/root.c +++ b/fs/autofs/root.c | |||
| @@ -16,6 +16,7 @@ | |||
| 16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
| 17 | #include <linux/param.h> | 17 | #include <linux/param.h> |
| 18 | #include <linux/time.h> | 18 | #include <linux/time.h> |
| 19 | #include <linux/compat.h> | ||
| 19 | #include <linux/smp_lock.h> | 20 | #include <linux/smp_lock.h> |
| 20 | #include "autofs_i.h" | 21 | #include "autofs_i.h" |
| 21 | 22 | ||
| @@ -25,13 +26,17 @@ static int autofs_root_symlink(struct inode *,struct dentry *,const char *); | |||
| 25 | static int autofs_root_unlink(struct inode *,struct dentry *); | 26 | static int autofs_root_unlink(struct inode *,struct dentry *); |
| 26 | static int autofs_root_rmdir(struct inode *,struct dentry *); | 27 | static int autofs_root_rmdir(struct inode *,struct dentry *); |
| 27 | static int autofs_root_mkdir(struct inode *,struct dentry *,int); | 28 | static int autofs_root_mkdir(struct inode *,struct dentry *,int); |
| 28 | static int autofs_root_ioctl(struct inode *, struct file *,unsigned int,unsigned long); | 29 | static long autofs_root_ioctl(struct file *,unsigned int,unsigned long); |
| 30 | static long autofs_root_compat_ioctl(struct file *,unsigned int,unsigned long); | ||
| 29 | 31 | ||
| 30 | const struct file_operations autofs_root_operations = { | 32 | const struct file_operations autofs_root_operations = { |
| 31 | .llseek = generic_file_llseek, | 33 | .llseek = generic_file_llseek, |
| 32 | .read = generic_read_dir, | 34 | .read = generic_read_dir, |
| 33 | .readdir = autofs_root_readdir, | 35 | .readdir = autofs_root_readdir, |
| 34 | .ioctl = autofs_root_ioctl, | 36 | .unlocked_ioctl = autofs_root_ioctl, |
| 37 | #ifdef CONFIG_COMPAT | ||
| 38 | .compat_ioctl = autofs_root_compat_ioctl, | ||
| 39 | #endif | ||
| 35 | }; | 40 | }; |
| 36 | 41 | ||
| 37 | const struct inode_operations autofs_root_inode_operations = { | 42 | const struct inode_operations autofs_root_inode_operations = { |
| @@ -492,6 +497,25 @@ static int autofs_root_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
| 492 | } | 497 | } |
| 493 | 498 | ||
| 494 | /* Get/set timeout ioctl() operation */ | 499 | /* Get/set timeout ioctl() operation */ |
| 500 | #ifdef CONFIG_COMPAT | ||
| 501 | static inline int autofs_compat_get_set_timeout(struct autofs_sb_info *sbi, | ||
| 502 | unsigned int __user *p) | ||
| 503 | { | ||
| 504 | unsigned long ntimeout; | ||
| 505 | |||
| 506 | if (get_user(ntimeout, p) || | ||
| 507 | put_user(sbi->exp_timeout / HZ, p)) | ||
| 508 | return -EFAULT; | ||
| 509 | |||
| 510 | if (ntimeout > UINT_MAX/HZ) | ||
| 511 | sbi->exp_timeout = 0; | ||
| 512 | else | ||
| 513 | sbi->exp_timeout = ntimeout * HZ; | ||
| 514 | |||
| 515 | return 0; | ||
| 516 | } | ||
| 517 | #endif | ||
| 518 | |||
| 495 | static inline int autofs_get_set_timeout(struct autofs_sb_info *sbi, | 519 | static inline int autofs_get_set_timeout(struct autofs_sb_info *sbi, |
| 496 | unsigned long __user *p) | 520 | unsigned long __user *p) |
| 497 | { | 521 | { |
| @@ -546,7 +570,7 @@ static inline int autofs_expire_run(struct super_block *sb, | |||
| 546 | * ioctl()'s on the root directory is the chief method for the daemon to | 570 | * ioctl()'s on the root directory is the chief method for the daemon to |
| 547 | * generate kernel reactions | 571 | * generate kernel reactions |
| 548 | */ | 572 | */ |
| 549 | static int autofs_root_ioctl(struct inode *inode, struct file *filp, | 573 | static int autofs_do_root_ioctl(struct inode *inode, struct file *filp, |
| 550 | unsigned int cmd, unsigned long arg) | 574 | unsigned int cmd, unsigned long arg) |
| 551 | { | 575 | { |
| 552 | struct autofs_sb_info *sbi = autofs_sbi(inode->i_sb); | 576 | struct autofs_sb_info *sbi = autofs_sbi(inode->i_sb); |
| @@ -571,6 +595,10 @@ static int autofs_root_ioctl(struct inode *inode, struct file *filp, | |||
| 571 | return 0; | 595 | return 0; |
| 572 | case AUTOFS_IOC_PROTOVER: /* Get protocol version */ | 596 | case AUTOFS_IOC_PROTOVER: /* Get protocol version */ |
| 573 | return autofs_get_protover(argp); | 597 | return autofs_get_protover(argp); |
| 598 | #ifdef CONFIG_COMPAT | ||
| 599 | case AUTOFS_IOC_SETTIMEOUT32: | ||
| 600 | return autofs_compat_get_set_timeout(sbi, argp); | ||
| 601 | #endif | ||
| 574 | case AUTOFS_IOC_SETTIMEOUT: | 602 | case AUTOFS_IOC_SETTIMEOUT: |
| 575 | return autofs_get_set_timeout(sbi, argp); | 603 | return autofs_get_set_timeout(sbi, argp); |
| 576 | case AUTOFS_IOC_EXPIRE: | 604 | case AUTOFS_IOC_EXPIRE: |
| @@ -579,4 +607,37 @@ static int autofs_root_ioctl(struct inode *inode, struct file *filp, | |||
| 579 | default: | 607 | default: |
| 580 | return -ENOSYS; | 608 | return -ENOSYS; |
| 581 | } | 609 | } |
| 610 | |||
| 611 | } | ||
| 612 | |||
| 613 | static long autofs_root_ioctl(struct file *filp, | ||
| 614 | unsigned int cmd, unsigned long arg) | ||
| 615 | { | ||
| 616 | int ret; | ||
| 617 | |||
| 618 | lock_kernel(); | ||
| 619 | ret = autofs_do_root_ioctl(filp->f_path.dentry->d_inode, | ||
| 620 | filp, cmd, arg); | ||
| 621 | unlock_kernel(); | ||
| 622 | |||
| 623 | return ret; | ||
| 624 | } | ||
| 625 | |||
| 626 | #ifdef CONFIG_COMPAT | ||
| 627 | static long autofs_root_compat_ioctl(struct file *filp, | ||
| 628 | unsigned int cmd, unsigned long arg) | ||
| 629 | { | ||
| 630 | struct inode *inode = filp->f_path.dentry->d_inode; | ||
| 631 | int ret; | ||
| 632 | |||
| 633 | lock_kernel(); | ||
| 634 | if (cmd == AUTOFS_IOC_READY || cmd == AUTOFS_IOC_FAIL) | ||
| 635 | ret = autofs_do_root_ioctl(inode, filp, cmd, arg); | ||
| 636 | else | ||
| 637 | ret = autofs_do_root_ioctl(inode, filp, cmd, | ||
| 638 | (unsigned long)compat_ptr(arg)); | ||
| 639 | unlock_kernel(); | ||
| 640 | |||
| 641 | return ret; | ||
| 582 | } | 642 | } |
| 643 | #endif | ||
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index db4117ed7803..cb1bd38dc08c 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c | |||
| @@ -18,7 +18,9 @@ | |||
| 18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
| 19 | #include <linux/param.h> | 19 | #include <linux/param.h> |
| 20 | #include <linux/time.h> | 20 | #include <linux/time.h> |
| 21 | #include <linux/compat.h> | ||
| 21 | #include <linux/smp_lock.h> | 22 | #include <linux/smp_lock.h> |
| 23 | |||
| 22 | #include "autofs_i.h" | 24 | #include "autofs_i.h" |
| 23 | 25 | ||
| 24 | static int autofs4_dir_symlink(struct inode *,struct dentry *,const char *); | 26 | static int autofs4_dir_symlink(struct inode *,struct dentry *,const char *); |
| @@ -26,6 +28,7 @@ static int autofs4_dir_unlink(struct inode *,struct dentry *); | |||
| 26 | static int autofs4_dir_rmdir(struct inode *,struct dentry *); | 28 | static int autofs4_dir_rmdir(struct inode *,struct dentry *); |
| 27 | static int autofs4_dir_mkdir(struct inode *,struct dentry *,int); | 29 | static int autofs4_dir_mkdir(struct inode *,struct dentry *,int); |
| 28 | static long autofs4_root_ioctl(struct file *,unsigned int,unsigned long); | 30 | static long autofs4_root_ioctl(struct file *,unsigned int,unsigned long); |
| 31 | static long autofs4_root_compat_ioctl(struct file *,unsigned int,unsigned long); | ||
| 29 | static int autofs4_dir_open(struct inode *inode, struct file *file); | 32 | static int autofs4_dir_open(struct inode *inode, struct file *file); |
| 30 | static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *); | 33 | static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *); |
| 31 | static void *autofs4_follow_link(struct dentry *, struct nameidata *); | 34 | static void *autofs4_follow_link(struct dentry *, struct nameidata *); |
| @@ -40,6 +43,9 @@ const struct file_operations autofs4_root_operations = { | |||
| 40 | .readdir = dcache_readdir, | 43 | .readdir = dcache_readdir, |
| 41 | .llseek = dcache_dir_lseek, | 44 | .llseek = dcache_dir_lseek, |
| 42 | .unlocked_ioctl = autofs4_root_ioctl, | 45 | .unlocked_ioctl = autofs4_root_ioctl, |
| 46 | #ifdef CONFIG_COMPAT | ||
| 47 | .compat_ioctl = autofs4_root_compat_ioctl, | ||
| 48 | #endif | ||
| 43 | }; | 49 | }; |
| 44 | 50 | ||
| 45 | const struct file_operations autofs4_dir_operations = { | 51 | const struct file_operations autofs4_dir_operations = { |
| @@ -198,8 +204,7 @@ static int try_to_fill_dentry(struct dentry *dentry, int flags) | |||
| 198 | } | 204 | } |
| 199 | 205 | ||
| 200 | /* Initialize expiry counter after successful mount */ | 206 | /* Initialize expiry counter after successful mount */ |
| 201 | if (ino) | 207 | ino->last_used = jiffies; |
| 202 | ino->last_used = jiffies; | ||
| 203 | 208 | ||
| 204 | spin_lock(&sbi->fs_lock); | 209 | spin_lock(&sbi->fs_lock); |
| 205 | ino->flags &= ~AUTOFS_INF_PENDING; | 210 | ino->flags &= ~AUTOFS_INF_PENDING; |
| @@ -840,6 +845,26 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
| 840 | } | 845 | } |
| 841 | 846 | ||
| 842 | /* Get/set timeout ioctl() operation */ | 847 | /* Get/set timeout ioctl() operation */ |
| 848 | #ifdef CONFIG_COMPAT | ||
| 849 | static inline int autofs4_compat_get_set_timeout(struct autofs_sb_info *sbi, | ||
| 850 | compat_ulong_t __user *p) | ||
| 851 | { | ||
| 852 | int rv; | ||
| 853 | unsigned long ntimeout; | ||
| 854 | |||
| 855 | if ((rv = get_user(ntimeout, p)) || | ||
| 856 | (rv = put_user(sbi->exp_timeout/HZ, p))) | ||
| 857 | return rv; | ||
| 858 | |||
| 859 | if (ntimeout > UINT_MAX/HZ) | ||
| 860 | sbi->exp_timeout = 0; | ||
| 861 | else | ||
| 862 | sbi->exp_timeout = ntimeout * HZ; | ||
| 863 | |||
| 864 | return 0; | ||
| 865 | } | ||
| 866 | #endif | ||
| 867 | |||
| 843 | static inline int autofs4_get_set_timeout(struct autofs_sb_info *sbi, | 868 | static inline int autofs4_get_set_timeout(struct autofs_sb_info *sbi, |
| 844 | unsigned long __user *p) | 869 | unsigned long __user *p) |
| 845 | { | 870 | { |
| @@ -933,6 +958,10 @@ static int autofs4_root_ioctl_unlocked(struct inode *inode, struct file *filp, | |||
| 933 | return autofs4_get_protosubver(sbi, p); | 958 | return autofs4_get_protosubver(sbi, p); |
| 934 | case AUTOFS_IOC_SETTIMEOUT: | 959 | case AUTOFS_IOC_SETTIMEOUT: |
| 935 | return autofs4_get_set_timeout(sbi, p); | 960 | return autofs4_get_set_timeout(sbi, p); |
| 961 | #ifdef CONFIG_COMPAT | ||
| 962 | case AUTOFS_IOC_SETTIMEOUT32: | ||
| 963 | return autofs4_compat_get_set_timeout(sbi, p); | ||
| 964 | #endif | ||
| 936 | 965 | ||
| 937 | case AUTOFS_IOC_ASKUMOUNT: | 966 | case AUTOFS_IOC_ASKUMOUNT: |
| 938 | return autofs4_ask_umount(filp->f_path.mnt, p); | 967 | return autofs4_ask_umount(filp->f_path.mnt, p); |
| @@ -961,3 +990,22 @@ static long autofs4_root_ioctl(struct file *filp, | |||
| 961 | 990 | ||
| 962 | return ret; | 991 | return ret; |
| 963 | } | 992 | } |
| 993 | |||
| 994 | #ifdef CONFIG_COMPAT | ||
| 995 | static long autofs4_root_compat_ioctl(struct file *filp, | ||
| 996 | unsigned int cmd, unsigned long arg) | ||
| 997 | { | ||
| 998 | struct inode *inode = filp->f_path.dentry->d_inode; | ||
| 999 | int ret; | ||
| 1000 | |||
| 1001 | lock_kernel(); | ||
| 1002 | if (cmd == AUTOFS_IOC_READY || cmd == AUTOFS_IOC_FAIL) | ||
| 1003 | ret = autofs4_root_ioctl_unlocked(inode, filp, cmd, arg); | ||
| 1004 | else | ||
| 1005 | ret = autofs4_root_ioctl_unlocked(inode, filp, cmd, | ||
| 1006 | (unsigned long)compat_ptr(arg)); | ||
| 1007 | unlock_kernel(); | ||
| 1008 | |||
| 1009 | return ret; | ||
| 1010 | } | ||
| 1011 | #endif | ||
diff --git a/fs/bad_inode.c b/fs/bad_inode.c index 52e59bf4aa5f..f024d8aaddef 100644 --- a/fs/bad_inode.c +++ b/fs/bad_inode.c | |||
| @@ -55,12 +55,6 @@ static unsigned int bad_file_poll(struct file *filp, poll_table *wait) | |||
| 55 | return POLLERR; | 55 | return POLLERR; |
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | static int bad_file_ioctl (struct inode *inode, struct file *filp, | ||
| 59 | unsigned int cmd, unsigned long arg) | ||
| 60 | { | ||
| 61 | return -EIO; | ||
| 62 | } | ||
| 63 | |||
| 64 | static long bad_file_unlocked_ioctl(struct file *file, unsigned cmd, | 58 | static long bad_file_unlocked_ioctl(struct file *file, unsigned cmd, |
| 65 | unsigned long arg) | 59 | unsigned long arg) |
| 66 | { | 60 | { |
| @@ -159,7 +153,6 @@ static const struct file_operations bad_file_ops = | |||
| 159 | .aio_write = bad_file_aio_write, | 153 | .aio_write = bad_file_aio_write, |
| 160 | .readdir = bad_file_readdir, | 154 | .readdir = bad_file_readdir, |
| 161 | .poll = bad_file_poll, | 155 | .poll = bad_file_poll, |
| 162 | .ioctl = bad_file_ioctl, | ||
| 163 | .unlocked_ioctl = bad_file_unlocked_ioctl, | 156 | .unlocked_ioctl = bad_file_unlocked_ioctl, |
| 164 | .compat_ioctl = bad_file_compat_ioctl, | 157 | .compat_ioctl = bad_file_compat_ioctl, |
| 165 | .mmap = bad_file_mmap, | 158 | .mmap = bad_file_mmap, |
diff --git a/fs/bfs/bfs.h b/fs/bfs/bfs.h index 7109e451abf7..f7f87e233dd9 100644 --- a/fs/bfs/bfs.h +++ b/fs/bfs/bfs.h | |||
| @@ -17,7 +17,6 @@ struct bfs_sb_info { | |||
| 17 | unsigned long si_lf_eblk; | 17 | unsigned long si_lf_eblk; |
| 18 | unsigned long si_lasti; | 18 | unsigned long si_lasti; |
| 19 | unsigned long *si_imap; | 19 | unsigned long *si_imap; |
| 20 | struct buffer_head *si_sbh; /* buffer header w/superblock */ | ||
| 21 | struct mutex bfs_lock; | 20 | struct mutex bfs_lock; |
| 22 | }; | 21 | }; |
| 23 | 22 | ||
diff --git a/fs/bfs/file.c b/fs/bfs/file.c index 88b9a3ff44e4..eb67edd0f8ea 100644 --- a/fs/bfs/file.c +++ b/fs/bfs/file.c | |||
| @@ -70,7 +70,6 @@ static int bfs_get_block(struct inode *inode, sector_t block, | |||
| 70 | struct super_block *sb = inode->i_sb; | 70 | struct super_block *sb = inode->i_sb; |
| 71 | struct bfs_sb_info *info = BFS_SB(sb); | 71 | struct bfs_sb_info *info = BFS_SB(sb); |
| 72 | struct bfs_inode_info *bi = BFS_I(inode); | 72 | struct bfs_inode_info *bi = BFS_I(inode); |
| 73 | struct buffer_head *sbh = info->si_sbh; | ||
| 74 | 73 | ||
| 75 | phys = bi->i_sblock + block; | 74 | phys = bi->i_sblock + block; |
| 76 | if (!create) { | 75 | if (!create) { |
| @@ -112,7 +111,6 @@ static int bfs_get_block(struct inode *inode, sector_t block, | |||
| 112 | info->si_freeb -= phys - bi->i_eblock; | 111 | info->si_freeb -= phys - bi->i_eblock; |
| 113 | info->si_lf_eblk = bi->i_eblock = phys; | 112 | info->si_lf_eblk = bi->i_eblock = phys; |
| 114 | mark_inode_dirty(inode); | 113 | mark_inode_dirty(inode); |
| 115 | mark_buffer_dirty(sbh); | ||
| 116 | err = 0; | 114 | err = 0; |
| 117 | goto out; | 115 | goto out; |
| 118 | } | 116 | } |
| @@ -147,7 +145,6 @@ static int bfs_get_block(struct inode *inode, sector_t block, | |||
| 147 | */ | 145 | */ |
| 148 | info->si_freeb -= bi->i_eblock - bi->i_sblock + 1 - inode->i_blocks; | 146 | info->si_freeb -= bi->i_eblock - bi->i_sblock + 1 - inode->i_blocks; |
| 149 | mark_inode_dirty(inode); | 147 | mark_inode_dirty(inode); |
| 150 | mark_buffer_dirty(sbh); | ||
| 151 | map_bh(bh_result, sb, phys); | 148 | map_bh(bh_result, sb, phys); |
| 152 | out: | 149 | out: |
| 153 | mutex_unlock(&info->bfs_lock); | 150 | mutex_unlock(&info->bfs_lock); |
| @@ -168,9 +165,17 @@ static int bfs_write_begin(struct file *file, struct address_space *mapping, | |||
| 168 | loff_t pos, unsigned len, unsigned flags, | 165 | loff_t pos, unsigned len, unsigned flags, |
| 169 | struct page **pagep, void **fsdata) | 166 | struct page **pagep, void **fsdata) |
| 170 | { | 167 | { |
| 171 | *pagep = NULL; | 168 | int ret; |
| 172 | return block_write_begin(file, mapping, pos, len, flags, | 169 | |
| 173 | pagep, fsdata, bfs_get_block); | 170 | ret = block_write_begin(mapping, pos, len, flags, pagep, |
| 171 | bfs_get_block); | ||
| 172 | if (unlikely(ret)) { | ||
| 173 | loff_t isize = mapping->host->i_size; | ||
| 174 | if (pos + len > isize) | ||
| 175 | vmtruncate(mapping->host, isize); | ||
| 176 | } | ||
| 177 | |||
| 178 | return ret; | ||
| 174 | } | 179 | } |
| 175 | 180 | ||
| 176 | static sector_t bfs_bmap(struct address_space *mapping, sector_t block) | 181 | static sector_t bfs_bmap(struct address_space *mapping, sector_t block) |
diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c index f22a7d3dc362..c4daf0f5fc02 100644 --- a/fs/bfs/inode.c +++ b/fs/bfs/inode.c | |||
| @@ -31,7 +31,6 @@ MODULE_LICENSE("GPL"); | |||
| 31 | #define dprintf(x...) | 31 | #define dprintf(x...) |
| 32 | #endif | 32 | #endif |
| 33 | 33 | ||
| 34 | static void bfs_write_super(struct super_block *s); | ||
| 35 | void dump_imap(const char *prefix, struct super_block *s); | 34 | void dump_imap(const char *prefix, struct super_block *s); |
| 36 | 35 | ||
| 37 | struct inode *bfs_iget(struct super_block *sb, unsigned long ino) | 36 | struct inode *bfs_iget(struct super_block *sb, unsigned long ino) |
| @@ -99,6 +98,24 @@ error: | |||
| 99 | return ERR_PTR(-EIO); | 98 | return ERR_PTR(-EIO); |
| 100 | } | 99 | } |
| 101 | 100 | ||
| 101 | static struct bfs_inode *find_inode(struct super_block *sb, u16 ino, struct buffer_head **p) | ||
| 102 | { | ||
| 103 | if ((ino < BFS_ROOT_INO) || (ino > BFS_SB(sb)->si_lasti)) { | ||
| 104 | printf("Bad inode number %s:%08x\n", sb->s_id, ino); | ||
| 105 | return ERR_PTR(-EIO); | ||
| 106 | } | ||
| 107 | |||
| 108 | ino -= BFS_ROOT_INO; | ||
| 109 | |||
| 110 | *p = sb_bread(sb, 1 + ino / BFS_INODES_PER_BLOCK); | ||
| 111 | if (!*p) { | ||
| 112 | printf("Unable to read inode %s:%08x\n", sb->s_id, ino); | ||
| 113 | return ERR_PTR(-EIO); | ||
| 114 | } | ||
| 115 | |||
| 116 | return (struct bfs_inode *)(*p)->b_data + ino % BFS_INODES_PER_BLOCK; | ||
| 117 | } | ||
| 118 | |||
| 102 | static int bfs_write_inode(struct inode *inode, struct writeback_control *wbc) | 119 | static int bfs_write_inode(struct inode *inode, struct writeback_control *wbc) |
| 103 | { | 120 | { |
| 104 | struct bfs_sb_info *info = BFS_SB(inode->i_sb); | 121 | struct bfs_sb_info *info = BFS_SB(inode->i_sb); |
| @@ -106,28 +123,15 @@ static int bfs_write_inode(struct inode *inode, struct writeback_control *wbc) | |||
| 106 | unsigned long i_sblock; | 123 | unsigned long i_sblock; |
| 107 | struct bfs_inode *di; | 124 | struct bfs_inode *di; |
| 108 | struct buffer_head *bh; | 125 | struct buffer_head *bh; |
| 109 | int block, off; | ||
| 110 | int err = 0; | 126 | int err = 0; |
| 111 | 127 | ||
| 112 | dprintf("ino=%08x\n", ino); | 128 | dprintf("ino=%08x\n", ino); |
| 113 | 129 | ||
| 114 | if ((ino < BFS_ROOT_INO) || (ino > BFS_SB(inode->i_sb)->si_lasti)) { | 130 | di = find_inode(inode->i_sb, ino, &bh); |
| 115 | printf("Bad inode number %s:%08x\n", inode->i_sb->s_id, ino); | 131 | if (IS_ERR(di)) |
| 116 | return -EIO; | 132 | return PTR_ERR(di); |
| 117 | } | ||
| 118 | 133 | ||
| 119 | mutex_lock(&info->bfs_lock); | 134 | mutex_lock(&info->bfs_lock); |
| 120 | block = (ino - BFS_ROOT_INO) / BFS_INODES_PER_BLOCK + 1; | ||
| 121 | bh = sb_bread(inode->i_sb, block); | ||
| 122 | if (!bh) { | ||
| 123 | printf("Unable to read inode %s:%08x\n", | ||
| 124 | inode->i_sb->s_id, ino); | ||
| 125 | mutex_unlock(&info->bfs_lock); | ||
| 126 | return -EIO; | ||
| 127 | } | ||
| 128 | |||
| 129 | off = (ino - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK; | ||
| 130 | di = (struct bfs_inode *)bh->b_data + off; | ||
| 131 | 135 | ||
| 132 | if (ino == BFS_ROOT_INO) | 136 | if (ino == BFS_ROOT_INO) |
| 133 | di->i_vtype = cpu_to_le32(BFS_VDIR); | 137 | di->i_vtype = cpu_to_le32(BFS_VDIR); |
| @@ -158,12 +162,11 @@ static int bfs_write_inode(struct inode *inode, struct writeback_control *wbc) | |||
| 158 | return err; | 162 | return err; |
| 159 | } | 163 | } |
| 160 | 164 | ||
| 161 | static void bfs_delete_inode(struct inode *inode) | 165 | static void bfs_evict_inode(struct inode *inode) |
| 162 | { | 166 | { |
| 163 | unsigned long ino = inode->i_ino; | 167 | unsigned long ino = inode->i_ino; |
| 164 | struct bfs_inode *di; | 168 | struct bfs_inode *di; |
| 165 | struct buffer_head *bh; | 169 | struct buffer_head *bh; |
| 166 | int block, off; | ||
| 167 | struct super_block *s = inode->i_sb; | 170 | struct super_block *s = inode->i_sb; |
| 168 | struct bfs_sb_info *info = BFS_SB(s); | 171 | struct bfs_sb_info *info = BFS_SB(s); |
| 169 | struct bfs_inode_info *bi = BFS_I(inode); | 172 | struct bfs_inode_info *bi = BFS_I(inode); |
| @@ -171,28 +174,19 @@ static void bfs_delete_inode(struct inode *inode) | |||
| 171 | dprintf("ino=%08lx\n", ino); | 174 | dprintf("ino=%08lx\n", ino); |
| 172 | 175 | ||
| 173 | truncate_inode_pages(&inode->i_data, 0); | 176 | truncate_inode_pages(&inode->i_data, 0); |
| 177 | invalidate_inode_buffers(inode); | ||
| 178 | end_writeback(inode); | ||
| 174 | 179 | ||
| 175 | if ((ino < BFS_ROOT_INO) || (ino > info->si_lasti)) { | 180 | if (inode->i_nlink) |
| 176 | printf("invalid ino=%08lx\n", ino); | ||
| 177 | return; | 181 | return; |
| 178 | } | ||
| 179 | |||
| 180 | inode->i_size = 0; | ||
| 181 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; | ||
| 182 | mutex_lock(&info->bfs_lock); | ||
| 183 | mark_inode_dirty(inode); | ||
| 184 | 182 | ||
| 185 | block = (ino - BFS_ROOT_INO) / BFS_INODES_PER_BLOCK + 1; | 183 | di = find_inode(s, inode->i_ino, &bh); |
| 186 | bh = sb_bread(s, block); | 184 | if (IS_ERR(di)) |
| 187 | if (!bh) { | ||
| 188 | printf("Unable to read inode %s:%08lx\n", | ||
| 189 | inode->i_sb->s_id, ino); | ||
| 190 | mutex_unlock(&info->bfs_lock); | ||
| 191 | return; | 185 | return; |
| 192 | } | 186 | |
| 193 | off = (ino - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK; | 187 | mutex_lock(&info->bfs_lock); |
| 194 | di = (struct bfs_inode *)bh->b_data + off; | 188 | /* clear on-disk inode */ |
| 195 | memset((void *)di, 0, sizeof(struct bfs_inode)); | 189 | memset(di, 0, sizeof(struct bfs_inode)); |
| 196 | mark_buffer_dirty(bh); | 190 | mark_buffer_dirty(bh); |
| 197 | brelse(bh); | 191 | brelse(bh); |
| 198 | 192 | ||
| @@ -209,32 +203,9 @@ static void bfs_delete_inode(struct inode *inode) | |||
| 209 | * "last block of the last file" even if there is no | 203 | * "last block of the last file" even if there is no |
| 210 | * real file there, saves us 1 gap. | 204 | * real file there, saves us 1 gap. |
| 211 | */ | 205 | */ |
| 212 | if (info->si_lf_eblk == bi->i_eblock) { | 206 | if (info->si_lf_eblk == bi->i_eblock) |
| 213 | info->si_lf_eblk = bi->i_sblock - 1; | 207 | info->si_lf_eblk = bi->i_sblock - 1; |
| 214 | mark_buffer_dirty(info->si_sbh); | ||
| 215 | } | ||
| 216 | mutex_unlock(&info->bfs_lock); | 208 | mutex_unlock(&info->bfs_lock); |
| 217 | clear_inode(inode); | ||
| 218 | } | ||
| 219 | |||
| 220 | static int bfs_sync_fs(struct super_block *sb, int wait) | ||
| 221 | { | ||
| 222 | struct bfs_sb_info *info = BFS_SB(sb); | ||
| 223 | |||
| 224 | mutex_lock(&info->bfs_lock); | ||
| 225 | mark_buffer_dirty(info->si_sbh); | ||
| 226 | sb->s_dirt = 0; | ||
| 227 | mutex_unlock(&info->bfs_lock); | ||
| 228 | |||
| 229 | return 0; | ||
| 230 | } | ||
| 231 | |||
| 232 | static void bfs_write_super(struct super_block *sb) | ||
| 233 | { | ||
| 234 | if (!(sb->s_flags & MS_RDONLY)) | ||
| 235 | bfs_sync_fs(sb, 1); | ||
| 236 | else | ||
| 237 | sb->s_dirt = 0; | ||
| 238 | } | 209 | } |
| 239 | 210 | ||
| 240 | static void bfs_put_super(struct super_block *s) | 211 | static void bfs_put_super(struct super_block *s) |
| @@ -246,10 +217,6 @@ static void bfs_put_super(struct super_block *s) | |||
| 246 | 217 | ||
| 247 | lock_kernel(); | 218 | lock_kernel(); |
| 248 | 219 | ||
| 249 | if (s->s_dirt) | ||
| 250 | bfs_write_super(s); | ||
| 251 | |||
| 252 | brelse(info->si_sbh); | ||
| 253 | mutex_destroy(&info->bfs_lock); | 220 | mutex_destroy(&info->bfs_lock); |
| 254 | kfree(info->si_imap); | 221 | kfree(info->si_imap); |
| 255 | kfree(info); | 222 | kfree(info); |
| @@ -319,10 +286,8 @@ static const struct super_operations bfs_sops = { | |||
| 319 | .alloc_inode = bfs_alloc_inode, | 286 | .alloc_inode = bfs_alloc_inode, |
| 320 | .destroy_inode = bfs_destroy_inode, | 287 | .destroy_inode = bfs_destroy_inode, |
| 321 | .write_inode = bfs_write_inode, | 288 | .write_inode = bfs_write_inode, |
| 322 | .delete_inode = bfs_delete_inode, | 289 | .evict_inode = bfs_evict_inode, |
| 323 | .put_super = bfs_put_super, | 290 | .put_super = bfs_put_super, |
| 324 | .write_super = bfs_write_super, | ||
| 325 | .sync_fs = bfs_sync_fs, | ||
| 326 | .statfs = bfs_statfs, | 291 | .statfs = bfs_statfs, |
| 327 | }; | 292 | }; |
| 328 | 293 | ||
| @@ -349,7 +314,7 @@ void dump_imap(const char *prefix, struct super_block *s) | |||
| 349 | 314 | ||
| 350 | static int bfs_fill_super(struct super_block *s, void *data, int silent) | 315 | static int bfs_fill_super(struct super_block *s, void *data, int silent) |
| 351 | { | 316 | { |
| 352 | struct buffer_head *bh; | 317 | struct buffer_head *bh, *sbh; |
| 353 | struct bfs_super_block *bfs_sb; | 318 | struct bfs_super_block *bfs_sb; |
| 354 | struct inode *inode; | 319 | struct inode *inode; |
| 355 | unsigned i, imap_len; | 320 | unsigned i, imap_len; |
| @@ -365,10 +330,10 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent) | |||
| 365 | 330 | ||
| 366 | sb_set_blocksize(s, BFS_BSIZE); | 331 | sb_set_blocksize(s, BFS_BSIZE); |
| 367 | 332 | ||
| 368 | info->si_sbh = sb_bread(s, 0); | 333 | sbh = sb_bread(s, 0); |
| 369 | if (!info->si_sbh) | 334 | if (!sbh) |
| 370 | goto out; | 335 | goto out; |
| 371 | bfs_sb = (struct bfs_super_block *)info->si_sbh->b_data; | 336 | bfs_sb = (struct bfs_super_block *)sbh->b_data; |
| 372 | if (le32_to_cpu(bfs_sb->s_magic) != BFS_MAGIC) { | 337 | if (le32_to_cpu(bfs_sb->s_magic) != BFS_MAGIC) { |
| 373 | if (!silent) | 338 | if (!silent) |
| 374 | printf("No BFS filesystem on %s (magic=%08x)\n", | 339 | printf("No BFS filesystem on %s (magic=%08x)\n", |
| @@ -472,10 +437,7 @@ static int bfs_fill_super(struct super_block *s, void *data, int silent) | |||
| 472 | info->si_lf_eblk = eblock; | 437 | info->si_lf_eblk = eblock; |
| 473 | } | 438 | } |
| 474 | brelse(bh); | 439 | brelse(bh); |
| 475 | if (!(s->s_flags & MS_RDONLY)) { | 440 | brelse(sbh); |
| 476 | mark_buffer_dirty(info->si_sbh); | ||
| 477 | s->s_dirt = 1; | ||
| 478 | } | ||
| 479 | dump_imap("read_super", s); | 441 | dump_imap("read_super", s); |
| 480 | return 0; | 442 | return 0; |
| 481 | 443 | ||
| @@ -485,7 +447,7 @@ out3: | |||
| 485 | out2: | 447 | out2: |
| 486 | kfree(info->si_imap); | 448 | kfree(info->si_imap); |
| 487 | out1: | 449 | out1: |
| 488 | brelse(info->si_sbh); | 450 | brelse(sbh); |
| 489 | out: | 451 | out: |
| 490 | mutex_destroy(&info->bfs_lock); | 452 | mutex_destroy(&info->bfs_lock); |
| 491 | kfree(info); | 453 | kfree(info); |
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index c4e83537ead7..9e60fd201716 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c | |||
| @@ -502,8 +502,9 @@ static struct inode *bm_get_inode(struct super_block *sb, int mode) | |||
| 502 | return inode; | 502 | return inode; |
| 503 | } | 503 | } |
| 504 | 504 | ||
| 505 | static void bm_clear_inode(struct inode *inode) | 505 | static void bm_evict_inode(struct inode *inode) |
| 506 | { | 506 | { |
| 507 | end_writeback(inode); | ||
| 507 | kfree(inode->i_private); | 508 | kfree(inode->i_private); |
| 508 | } | 509 | } |
| 509 | 510 | ||
| @@ -685,7 +686,7 @@ static const struct file_operations bm_status_operations = { | |||
| 685 | 686 | ||
| 686 | static const struct super_operations s_ops = { | 687 | static const struct super_operations s_ops = { |
| 687 | .statfs = simple_statfs, | 688 | .statfs = simple_statfs, |
| 688 | .clear_inode = bm_clear_inode, | 689 | .evict_inode = bm_evict_inode, |
| 689 | }; | 690 | }; |
| 690 | 691 | ||
| 691 | static int bm_fill_super(struct super_block * sb, void * data, int silent) | 692 | static int bm_fill_super(struct super_block * sb, void * data, int silent) |
| @@ -843,7 +843,8 @@ struct bio *bio_copy_user_iov(struct request_queue *q, | |||
| 843 | if (!bio) | 843 | if (!bio) |
| 844 | goto out_bmd; | 844 | goto out_bmd; |
| 845 | 845 | ||
| 846 | bio->bi_rw |= (!write_to_vm << BIO_RW); | 846 | if (!write_to_vm) |
| 847 | bio->bi_rw |= REQ_WRITE; | ||
| 847 | 848 | ||
| 848 | ret = 0; | 849 | ret = 0; |
| 849 | 850 | ||
| @@ -1024,7 +1025,7 @@ static struct bio *__bio_map_user_iov(struct request_queue *q, | |||
| 1024 | * set data direction, and check if mapped pages need bouncing | 1025 | * set data direction, and check if mapped pages need bouncing |
| 1025 | */ | 1026 | */ |
| 1026 | if (!write_to_vm) | 1027 | if (!write_to_vm) |
| 1027 | bio->bi_rw |= (1 << BIO_RW); | 1028 | bio->bi_rw |= REQ_WRITE; |
| 1028 | 1029 | ||
| 1029 | bio->bi_bdev = bdev; | 1030 | bio->bi_bdev = bdev; |
| 1030 | bio->bi_flags |= (1 << BIO_USER_MAPPED); | 1031 | bio->bi_flags |= (1 << BIO_USER_MAPPED); |
diff --git a/fs/block_dev.c b/fs/block_dev.c index b3171fb0dc9a..50e8c8582faa 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c | |||
| @@ -172,9 +172,8 @@ blkdev_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, | |||
| 172 | struct file *file = iocb->ki_filp; | 172 | struct file *file = iocb->ki_filp; |
| 173 | struct inode *inode = file->f_mapping->host; | 173 | struct inode *inode = file->f_mapping->host; |
| 174 | 174 | ||
| 175 | return blockdev_direct_IO_no_locking_newtrunc(rw, iocb, inode, | 175 | return __blockdev_direct_IO(rw, iocb, inode, I_BDEV(inode), iov, offset, |
| 176 | I_BDEV(inode), iov, offset, nr_segs, | 176 | nr_segs, blkdev_get_blocks, NULL, NULL, 0); |
| 177 | blkdev_get_blocks, NULL); | ||
| 178 | } | 177 | } |
| 179 | 178 | ||
| 180 | int __sync_blockdev(struct block_device *bdev, int wait) | 179 | int __sync_blockdev(struct block_device *bdev, int wait) |
| @@ -309,9 +308,8 @@ static int blkdev_write_begin(struct file *file, struct address_space *mapping, | |||
| 309 | loff_t pos, unsigned len, unsigned flags, | 308 | loff_t pos, unsigned len, unsigned flags, |
| 310 | struct page **pagep, void **fsdata) | 309 | struct page **pagep, void **fsdata) |
| 311 | { | 310 | { |
| 312 | *pagep = NULL; | 311 | return block_write_begin(mapping, pos, len, flags, pagep, |
| 313 | return block_write_begin_newtrunc(file, mapping, pos, len, flags, | 312 | blkdev_get_block); |
| 314 | pagep, fsdata, blkdev_get_block); | ||
| 315 | } | 313 | } |
| 316 | 314 | ||
| 317 | static int blkdev_write_end(struct file *file, struct address_space *mapping, | 315 | static int blkdev_write_end(struct file *file, struct address_space *mapping, |
| @@ -428,10 +426,13 @@ static inline void __bd_forget(struct inode *inode) | |||
| 428 | inode->i_mapping = &inode->i_data; | 426 | inode->i_mapping = &inode->i_data; |
| 429 | } | 427 | } |
| 430 | 428 | ||
| 431 | static void bdev_clear_inode(struct inode *inode) | 429 | static void bdev_evict_inode(struct inode *inode) |
| 432 | { | 430 | { |
| 433 | struct block_device *bdev = &BDEV_I(inode)->bdev; | 431 | struct block_device *bdev = &BDEV_I(inode)->bdev; |
| 434 | struct list_head *p; | 432 | struct list_head *p; |
| 433 | truncate_inode_pages(&inode->i_data, 0); | ||
| 434 | invalidate_inode_buffers(inode); /* is it needed here? */ | ||
| 435 | end_writeback(inode); | ||
| 435 | spin_lock(&bdev_lock); | 436 | spin_lock(&bdev_lock); |
| 436 | while ( (p = bdev->bd_inodes.next) != &bdev->bd_inodes ) { | 437 | while ( (p = bdev->bd_inodes.next) != &bdev->bd_inodes ) { |
| 437 | __bd_forget(list_entry(p, struct inode, i_devices)); | 438 | __bd_forget(list_entry(p, struct inode, i_devices)); |
| @@ -445,7 +446,7 @@ static const struct super_operations bdev_sops = { | |||
| 445 | .alloc_inode = bdev_alloc_inode, | 446 | .alloc_inode = bdev_alloc_inode, |
| 446 | .destroy_inode = bdev_destroy_inode, | 447 | .destroy_inode = bdev_destroy_inode, |
| 447 | .drop_inode = generic_delete_inode, | 448 | .drop_inode = generic_delete_inode, |
| 448 | .clear_inode = bdev_clear_inode, | 449 | .evict_inode = bdev_evict_inode, |
| 449 | }; | 450 | }; |
| 450 | 451 | ||
| 451 | static int bd_get_sb(struct file_system_type *fs_type, | 452 | static int bd_get_sb(struct file_system_type *fs_type, |
| @@ -1339,19 +1340,20 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) | |||
| 1339 | /* | 1340 | /* |
| 1340 | * hooks: /n/, see "layering violations". | 1341 | * hooks: /n/, see "layering violations". |
| 1341 | */ | 1342 | */ |
| 1342 | ret = devcgroup_inode_permission(bdev->bd_inode, perm); | 1343 | if (!for_part) { |
| 1343 | if (ret != 0) { | 1344 | ret = devcgroup_inode_permission(bdev->bd_inode, perm); |
| 1344 | bdput(bdev); | 1345 | if (ret != 0) { |
| 1345 | return ret; | 1346 | bdput(bdev); |
| 1347 | return ret; | ||
| 1348 | } | ||
| 1346 | } | 1349 | } |
| 1347 | 1350 | ||
| 1348 | lock_kernel(); | ||
| 1349 | restart: | 1351 | restart: |
| 1350 | 1352 | ||
| 1351 | ret = -ENXIO; | 1353 | ret = -ENXIO; |
| 1352 | disk = get_gendisk(bdev->bd_dev, &partno); | 1354 | disk = get_gendisk(bdev->bd_dev, &partno); |
| 1353 | if (!disk) | 1355 | if (!disk) |
| 1354 | goto out_unlock_kernel; | 1356 | goto out; |
| 1355 | 1357 | ||
| 1356 | mutex_lock_nested(&bdev->bd_mutex, for_part); | 1358 | mutex_lock_nested(&bdev->bd_mutex, for_part); |
| 1357 | if (!bdev->bd_openers) { | 1359 | if (!bdev->bd_openers) { |
| @@ -1431,7 +1433,6 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) | |||
| 1431 | if (for_part) | 1433 | if (for_part) |
| 1432 | bdev->bd_part_count++; | 1434 | bdev->bd_part_count++; |
| 1433 | mutex_unlock(&bdev->bd_mutex); | 1435 | mutex_unlock(&bdev->bd_mutex); |
| 1434 | unlock_kernel(); | ||
| 1435 | return 0; | 1436 | return 0; |
| 1436 | 1437 | ||
| 1437 | out_clear: | 1438 | out_clear: |
| @@ -1444,9 +1445,7 @@ static int __blkdev_get(struct block_device *bdev, fmode_t mode, int for_part) | |||
| 1444 | bdev->bd_contains = NULL; | 1445 | bdev->bd_contains = NULL; |
| 1445 | out_unlock_bdev: | 1446 | out_unlock_bdev: |
| 1446 | mutex_unlock(&bdev->bd_mutex); | 1447 | mutex_unlock(&bdev->bd_mutex); |
| 1447 | out_unlock_kernel: | 1448 | out: |
| 1448 | unlock_kernel(); | ||
| 1449 | |||
| 1450 | if (disk) | 1449 | if (disk) |
| 1451 | module_put(disk->fops->owner); | 1450 | module_put(disk->fops->owner); |
| 1452 | put_disk(disk); | 1451 | put_disk(disk); |
| @@ -1515,7 +1514,6 @@ static int __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part) | |||
| 1515 | struct block_device *victim = NULL; | 1514 | struct block_device *victim = NULL; |
| 1516 | 1515 | ||
| 1517 | mutex_lock_nested(&bdev->bd_mutex, for_part); | 1516 | mutex_lock_nested(&bdev->bd_mutex, for_part); |
| 1518 | lock_kernel(); | ||
| 1519 | if (for_part) | 1517 | if (for_part) |
| 1520 | bdev->bd_part_count--; | 1518 | bdev->bd_part_count--; |
| 1521 | 1519 | ||
| @@ -1540,7 +1538,6 @@ static int __blkdev_put(struct block_device *bdev, fmode_t mode, int for_part) | |||
| 1540 | victim = bdev->bd_contains; | 1538 | victim = bdev->bd_contains; |
| 1541 | bdev->bd_contains = NULL; | 1539 | bdev->bd_contains = NULL; |
| 1542 | } | 1540 | } |
| 1543 | unlock_kernel(); | ||
| 1544 | mutex_unlock(&bdev->bd_mutex); | 1541 | mutex_unlock(&bdev->bd_mutex); |
| 1545 | bdput(bdev); | 1542 | bdput(bdev); |
| 1546 | if (victim) | 1543 | if (victim) |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 29c20092847e..eaf286abad17 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
| @@ -2389,13 +2389,13 @@ unsigned long btrfs_force_ra(struct address_space *mapping, | |||
| 2389 | pgoff_t offset, pgoff_t last_index); | 2389 | pgoff_t offset, pgoff_t last_index); |
| 2390 | int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf); | 2390 | int btrfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf); |
| 2391 | int btrfs_readpage(struct file *file, struct page *page); | 2391 | int btrfs_readpage(struct file *file, struct page *page); |
| 2392 | void btrfs_delete_inode(struct inode *inode); | 2392 | void btrfs_evict_inode(struct inode *inode); |
| 2393 | void btrfs_put_inode(struct inode *inode); | 2393 | void btrfs_put_inode(struct inode *inode); |
| 2394 | int btrfs_write_inode(struct inode *inode, struct writeback_control *wbc); | 2394 | int btrfs_write_inode(struct inode *inode, struct writeback_control *wbc); |
| 2395 | void btrfs_dirty_inode(struct inode *inode); | 2395 | void btrfs_dirty_inode(struct inode *inode); |
| 2396 | struct inode *btrfs_alloc_inode(struct super_block *sb); | 2396 | struct inode *btrfs_alloc_inode(struct super_block *sb); |
| 2397 | void btrfs_destroy_inode(struct inode *inode); | 2397 | void btrfs_destroy_inode(struct inode *inode); |
| 2398 | void btrfs_drop_inode(struct inode *inode); | 2398 | int btrfs_drop_inode(struct inode *inode); |
| 2399 | int btrfs_init_cachep(void); | 2399 | int btrfs_init_cachep(void); |
| 2400 | void btrfs_destroy_cachep(void); | 2400 | void btrfs_destroy_cachep(void); |
| 2401 | long btrfs_ioctl_trans_end(struct file *file); | 2401 | long btrfs_ioctl_trans_end(struct file *file); |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index 34f7c375567e..64f10082f048 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
| @@ -480,7 +480,7 @@ static void end_workqueue_bio(struct bio *bio, int err) | |||
| 480 | end_io_wq->work.func = end_workqueue_fn; | 480 | end_io_wq->work.func = end_workqueue_fn; |
| 481 | end_io_wq->work.flags = 0; | 481 | end_io_wq->work.flags = 0; |
| 482 | 482 | ||
| 483 | if (bio->bi_rw & (1 << BIO_RW)) { | 483 | if (bio->bi_rw & REQ_WRITE) { |
| 484 | if (end_io_wq->metadata) | 484 | if (end_io_wq->metadata) |
| 485 | btrfs_queue_worker(&fs_info->endio_meta_write_workers, | 485 | btrfs_queue_worker(&fs_info->endio_meta_write_workers, |
| 486 | &end_io_wq->work); | 486 | &end_io_wq->work); |
| @@ -604,7 +604,7 @@ int btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct inode *inode, | |||
| 604 | 604 | ||
| 605 | atomic_inc(&fs_info->nr_async_submits); | 605 | atomic_inc(&fs_info->nr_async_submits); |
| 606 | 606 | ||
| 607 | if (rw & (1 << BIO_RW_SYNCIO)) | 607 | if (rw & REQ_SYNC) |
| 608 | btrfs_set_work_high_prio(&async->work); | 608 | btrfs_set_work_high_prio(&async->work); |
| 609 | 609 | ||
| 610 | btrfs_queue_worker(&fs_info->workers, &async->work); | 610 | btrfs_queue_worker(&fs_info->workers, &async->work); |
| @@ -668,7 +668,7 @@ static int btree_submit_bio_hook(struct inode *inode, int rw, struct bio *bio, | |||
| 668 | bio, 1); | 668 | bio, 1); |
| 669 | BUG_ON(ret); | 669 | BUG_ON(ret); |
| 670 | 670 | ||
| 671 | if (!(rw & (1 << BIO_RW))) { | 671 | if (!(rw & REQ_WRITE)) { |
| 672 | /* | 672 | /* |
| 673 | * called for a read, do the setup so that checksum validation | 673 | * called for a read, do the setup so that checksum validation |
| 674 | * can happen in the async kernel threads | 674 | * can happen in the async kernel threads |
| @@ -1427,7 +1427,7 @@ static void end_workqueue_fn(struct btrfs_work *work) | |||
| 1427 | * ram and up to date before trying to verify things. For | 1427 | * ram and up to date before trying to verify things. For |
| 1428 | * blocksize <= pagesize, it is basically a noop | 1428 | * blocksize <= pagesize, it is basically a noop |
| 1429 | */ | 1429 | */ |
| 1430 | if (!(bio->bi_rw & (1 << BIO_RW)) && end_io_wq->metadata && | 1430 | if (!(bio->bi_rw & REQ_WRITE) && end_io_wq->metadata && |
| 1431 | !bio_ready_for_csum(bio)) { | 1431 | !bio_ready_for_csum(bio)) { |
| 1432 | btrfs_queue_worker(&fs_info->endio_meta_workers, | 1432 | btrfs_queue_worker(&fs_info->endio_meta_workers, |
| 1433 | &end_io_wq->work); | 1433 | &end_io_wq->work); |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 1bff92ad4744..c03864406af3 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
| @@ -1429,7 +1429,7 @@ static int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio, | |||
| 1429 | ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0); | 1429 | ret = btrfs_bio_wq_end_io(root->fs_info, bio, 0); |
| 1430 | BUG_ON(ret); | 1430 | BUG_ON(ret); |
| 1431 | 1431 | ||
| 1432 | if (!(rw & (1 << BIO_RW))) { | 1432 | if (!(rw & REQ_WRITE)) { |
| 1433 | if (bio_flags & EXTENT_BIO_COMPRESSED) { | 1433 | if (bio_flags & EXTENT_BIO_COMPRESSED) { |
| 1434 | return btrfs_submit_compressed_read(inode, bio, | 1434 | return btrfs_submit_compressed_read(inode, bio, |
| 1435 | mirror_num, bio_flags); | 1435 | mirror_num, bio_flags); |
| @@ -1841,7 +1841,7 @@ static int btrfs_io_failed_hook(struct bio *failed_bio, | |||
| 1841 | bio->bi_size = 0; | 1841 | bio->bi_size = 0; |
| 1842 | 1842 | ||
| 1843 | bio_add_page(bio, page, failrec->len, start - page_offset(page)); | 1843 | bio_add_page(bio, page, failrec->len, start - page_offset(page)); |
| 1844 | if (failed_bio->bi_rw & (1 << BIO_RW)) | 1844 | if (failed_bio->bi_rw & REQ_WRITE) |
| 1845 | rw = WRITE; | 1845 | rw = WRITE; |
| 1846 | else | 1846 | else |
| 1847 | rw = READ; | 1847 | rw = READ; |
| @@ -2938,7 +2938,6 @@ int btrfs_unlink_subvol(struct btrfs_trans_handle *trans, | |||
| 2938 | dir->i_mtime = dir->i_ctime = CURRENT_TIME; | 2938 | dir->i_mtime = dir->i_ctime = CURRENT_TIME; |
| 2939 | ret = btrfs_update_inode(trans, root, dir); | 2939 | ret = btrfs_update_inode(trans, root, dir); |
| 2940 | BUG_ON(ret); | 2940 | BUG_ON(ret); |
| 2941 | dir->i_sb->s_dirt = 1; | ||
| 2942 | 2941 | ||
| 2943 | btrfs_free_path(path); | 2942 | btrfs_free_path(path); |
| 2944 | return 0; | 2943 | return 0; |
| @@ -3656,17 +3655,19 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 3656 | if (err) | 3655 | if (err) |
| 3657 | return err; | 3656 | return err; |
| 3658 | } | 3657 | } |
| 3659 | attr->ia_valid &= ~ATTR_SIZE; | ||
| 3660 | 3658 | ||
| 3661 | if (attr->ia_valid) | 3659 | if (attr->ia_valid) { |
| 3662 | err = inode_setattr(inode, attr); | 3660 | setattr_copy(inode, attr); |
| 3661 | mark_inode_dirty(inode); | ||
| 3662 | |||
| 3663 | if (attr->ia_valid & ATTR_MODE) | ||
| 3664 | err = btrfs_acl_chmod(inode); | ||
| 3665 | } | ||
| 3663 | 3666 | ||
| 3664 | if (!err && ((attr->ia_valid & ATTR_MODE))) | ||
| 3665 | err = btrfs_acl_chmod(inode); | ||
| 3666 | return err; | 3667 | return err; |
| 3667 | } | 3668 | } |
| 3668 | 3669 | ||
| 3669 | void btrfs_delete_inode(struct inode *inode) | 3670 | void btrfs_evict_inode(struct inode *inode) |
| 3670 | { | 3671 | { |
| 3671 | struct btrfs_trans_handle *trans; | 3672 | struct btrfs_trans_handle *trans; |
| 3672 | struct btrfs_root *root = BTRFS_I(inode)->root; | 3673 | struct btrfs_root *root = BTRFS_I(inode)->root; |
| @@ -3674,10 +3675,14 @@ void btrfs_delete_inode(struct inode *inode) | |||
| 3674 | int ret; | 3675 | int ret; |
| 3675 | 3676 | ||
| 3676 | truncate_inode_pages(&inode->i_data, 0); | 3677 | truncate_inode_pages(&inode->i_data, 0); |
| 3678 | if (inode->i_nlink && btrfs_root_refs(&root->root_item) != 0) | ||
| 3679 | goto no_delete; | ||
| 3680 | |||
| 3677 | if (is_bad_inode(inode)) { | 3681 | if (is_bad_inode(inode)) { |
| 3678 | btrfs_orphan_del(NULL, inode); | 3682 | btrfs_orphan_del(NULL, inode); |
| 3679 | goto no_delete; | 3683 | goto no_delete; |
| 3680 | } | 3684 | } |
| 3685 | /* do we really want it for ->i_nlink > 0 and zero btrfs_root_refs? */ | ||
| 3681 | btrfs_wait_ordered_range(inode, 0, (u64)-1); | 3686 | btrfs_wait_ordered_range(inode, 0, (u64)-1); |
| 3682 | 3687 | ||
| 3683 | if (root->fs_info->log_root_recovering) { | 3688 | if (root->fs_info->log_root_recovering) { |
| @@ -3727,7 +3732,7 @@ void btrfs_delete_inode(struct inode *inode) | |||
| 3727 | btrfs_end_transaction(trans, root); | 3732 | btrfs_end_transaction(trans, root); |
| 3728 | btrfs_btree_balance_dirty(root, nr); | 3733 | btrfs_btree_balance_dirty(root, nr); |
| 3729 | no_delete: | 3734 | no_delete: |
| 3730 | clear_inode(inode); | 3735 | end_writeback(inode); |
| 3731 | return; | 3736 | return; |
| 3732 | } | 3737 | } |
| 3733 | 3738 | ||
| @@ -3858,7 +3863,7 @@ again: | |||
| 3858 | p = &parent->rb_right; | 3863 | p = &parent->rb_right; |
| 3859 | else { | 3864 | else { |
| 3860 | WARN_ON(!(entry->vfs_inode.i_state & | 3865 | WARN_ON(!(entry->vfs_inode.i_state & |
| 3861 | (I_WILL_FREE | I_FREEING | I_CLEAR))); | 3866 | (I_WILL_FREE | I_FREEING))); |
| 3862 | rb_erase(parent, &root->inode_tree); | 3867 | rb_erase(parent, &root->inode_tree); |
| 3863 | RB_CLEAR_NODE(parent); | 3868 | RB_CLEAR_NODE(parent); |
| 3864 | spin_unlock(&root->inode_lock); | 3869 | spin_unlock(&root->inode_lock); |
| @@ -3937,7 +3942,7 @@ again: | |||
| 3937 | if (atomic_read(&inode->i_count) > 1) | 3942 | if (atomic_read(&inode->i_count) > 1) |
| 3938 | d_prune_aliases(inode); | 3943 | d_prune_aliases(inode); |
| 3939 | /* | 3944 | /* |
| 3940 | * btrfs_drop_inode will remove it from | 3945 | * btrfs_drop_inode will have it removed from |
| 3941 | * the inode cache when its usage count | 3946 | * the inode cache when its usage count |
| 3942 | * hits zero. | 3947 | * hits zero. |
| 3943 | */ | 3948 | */ |
| @@ -5642,7 +5647,7 @@ static void btrfs_submit_direct(int rw, struct bio *bio, struct inode *inode, | |||
| 5642 | struct bio_vec *bvec = bio->bi_io_vec; | 5647 | struct bio_vec *bvec = bio->bi_io_vec; |
| 5643 | u64 start; | 5648 | u64 start; |
| 5644 | int skip_sum; | 5649 | int skip_sum; |
| 5645 | int write = rw & (1 << BIO_RW); | 5650 | int write = rw & REQ_WRITE; |
| 5646 | int ret = 0; | 5651 | int ret = 0; |
| 5647 | 5652 | ||
| 5648 | skip_sum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; | 5653 | skip_sum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM; |
| @@ -6331,13 +6336,14 @@ free: | |||
| 6331 | kmem_cache_free(btrfs_inode_cachep, BTRFS_I(inode)); | 6336 | kmem_cache_free(btrfs_inode_cachep, BTRFS_I(inode)); |
| 6332 | } | 6337 | } |
| 6333 | 6338 | ||
| 6334 | void btrfs_drop_inode(struct inode *inode) | 6339 | int btrfs_drop_inode(struct inode *inode) |
| 6335 | { | 6340 | { |
| 6336 | struct btrfs_root *root = BTRFS_I(inode)->root; | 6341 | struct btrfs_root *root = BTRFS_I(inode)->root; |
| 6337 | if (inode->i_nlink > 0 && btrfs_root_refs(&root->root_item) == 0) | 6342 | |
| 6338 | generic_delete_inode(inode); | 6343 | if (btrfs_root_refs(&root->root_item) == 0) |
| 6344 | return 1; | ||
| 6339 | else | 6345 | else |
| 6340 | generic_drop_inode(inode); | 6346 | return generic_drop_inode(inode); |
| 6341 | } | 6347 | } |
| 6342 | 6348 | ||
| 6343 | static void init_once(void *foo) | 6349 | static void init_once(void *foo) |
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index f2393b390318..1776dbd8dc98 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
| @@ -797,7 +797,7 @@ static int btrfs_unfreeze(struct super_block *sb) | |||
| 797 | 797 | ||
| 798 | static const struct super_operations btrfs_super_ops = { | 798 | static const struct super_operations btrfs_super_ops = { |
| 799 | .drop_inode = btrfs_drop_inode, | 799 | .drop_inode = btrfs_drop_inode, |
| 800 | .delete_inode = btrfs_delete_inode, | 800 | .evict_inode = btrfs_evict_inode, |
| 801 | .put_super = btrfs_put_super, | 801 | .put_super = btrfs_put_super, |
| 802 | .sync_fs = btrfs_sync_fs, | 802 | .sync_fs = btrfs_sync_fs, |
| 803 | .show_options = btrfs_show_options, | 803 | .show_options = btrfs_show_options, |
diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c index d6e3af8be95b..dd318ff280b2 100644 --- a/fs/btrfs/volumes.c +++ b/fs/btrfs/volumes.c | |||
| @@ -258,7 +258,7 @@ loop_lock: | |||
| 258 | 258 | ||
| 259 | BUG_ON(atomic_read(&cur->bi_cnt) == 0); | 259 | BUG_ON(atomic_read(&cur->bi_cnt) == 0); |
| 260 | 260 | ||
| 261 | if (bio_rw_flagged(cur, BIO_RW_SYNCIO)) | 261 | if (cur->bi_rw & REQ_SYNC) |
| 262 | num_sync_run++; | 262 | num_sync_run++; |
| 263 | 263 | ||
| 264 | submit_bio(cur->bi_rw, cur); | 264 | submit_bio(cur->bi_rw, cur); |
| @@ -2651,7 +2651,7 @@ static int __btrfs_map_block(struct btrfs_mapping_tree *map_tree, int rw, | |||
| 2651 | int max_errors = 0; | 2651 | int max_errors = 0; |
| 2652 | struct btrfs_multi_bio *multi = NULL; | 2652 | struct btrfs_multi_bio *multi = NULL; |
| 2653 | 2653 | ||
| 2654 | if (multi_ret && !(rw & (1 << BIO_RW))) | 2654 | if (multi_ret && !(rw & REQ_WRITE)) |
| 2655 | stripes_allocated = 1; | 2655 | stripes_allocated = 1; |
| 2656 | again: | 2656 | again: |
| 2657 | if (multi_ret) { | 2657 | if (multi_ret) { |
| @@ -2687,7 +2687,7 @@ again: | |||
| 2687 | mirror_num = 0; | 2687 | mirror_num = 0; |
| 2688 | 2688 | ||
| 2689 | /* if our multi bio struct is too small, back off and try again */ | 2689 | /* if our multi bio struct is too small, back off and try again */ |
| 2690 | if (rw & (1 << BIO_RW)) { | 2690 | if (rw & REQ_WRITE) { |
| 2691 | if (map->type & (BTRFS_BLOCK_GROUP_RAID1 | | 2691 | if (map->type & (BTRFS_BLOCK_GROUP_RAID1 | |
| 2692 | BTRFS_BLOCK_GROUP_DUP)) { | 2692 | BTRFS_BLOCK_GROUP_DUP)) { |
| 2693 | stripes_required = map->num_stripes; | 2693 | stripes_required = map->num_stripes; |
| @@ -2697,7 +2697,7 @@ again: | |||
| 2697 | max_errors = 1; | 2697 | max_errors = 1; |
| 2698 | } | 2698 | } |
| 2699 | } | 2699 | } |
| 2700 | if (multi_ret && (rw & (1 << BIO_RW)) && | 2700 | if (multi_ret && (rw & REQ_WRITE) && |
| 2701 | stripes_allocated < stripes_required) { | 2701 | stripes_allocated < stripes_required) { |
| 2702 | stripes_allocated = map->num_stripes; | 2702 | stripes_allocated = map->num_stripes; |
| 2703 | free_extent_map(em); | 2703 | free_extent_map(em); |
| @@ -2733,7 +2733,7 @@ again: | |||
| 2733 | num_stripes = 1; | 2733 | num_stripes = 1; |
| 2734 | stripe_index = 0; | 2734 | stripe_index = 0; |
| 2735 | if (map->type & BTRFS_BLOCK_GROUP_RAID1) { | 2735 | if (map->type & BTRFS_BLOCK_GROUP_RAID1) { |
| 2736 | if (unplug_page || (rw & (1 << BIO_RW))) | 2736 | if (unplug_page || (rw & REQ_WRITE)) |
| 2737 | num_stripes = map->num_stripes; | 2737 | num_stripes = map->num_stripes; |
| 2738 | else if (mirror_num) | 2738 | else if (mirror_num) |
| 2739 | stripe_index = mirror_num - 1; | 2739 | stripe_index = mirror_num - 1; |
| @@ -2744,7 +2744,7 @@ again: | |||
| 2744 | } | 2744 | } |
| 2745 | 2745 | ||
| 2746 | } else if (map->type & BTRFS_BLOCK_GROUP_DUP) { | 2746 | } else if (map->type & BTRFS_BLOCK_GROUP_DUP) { |
| 2747 | if (rw & (1 << BIO_RW)) | 2747 | if (rw & REQ_WRITE) |
| 2748 | num_stripes = map->num_stripes; | 2748 | num_stripes = map->num_stripes; |
| 2749 | else if (mirror_num) | 2749 | else if (mirror_num) |
| 2750 | stripe_index = mirror_num - 1; | 2750 | stripe_index = mirror_num - 1; |
| @@ -2755,7 +2755,7 @@ again: | |||
| 2755 | stripe_index = do_div(stripe_nr, factor); | 2755 | stripe_index = do_div(stripe_nr, factor); |
| 2756 | stripe_index *= map->sub_stripes; | 2756 | stripe_index *= map->sub_stripes; |
| 2757 | 2757 | ||
| 2758 | if (unplug_page || (rw & (1 << BIO_RW))) | 2758 | if (unplug_page || (rw & REQ_WRITE)) |
| 2759 | num_stripes = map->sub_stripes; | 2759 | num_stripes = map->sub_stripes; |
| 2760 | else if (mirror_num) | 2760 | else if (mirror_num) |
| 2761 | stripe_index += mirror_num - 1; | 2761 | stripe_index += mirror_num - 1; |
| @@ -2945,7 +2945,7 @@ static noinline int schedule_bio(struct btrfs_root *root, | |||
| 2945 | struct btrfs_pending_bios *pending_bios; | 2945 | struct btrfs_pending_bios *pending_bios; |
| 2946 | 2946 | ||
| 2947 | /* don't bother with additional async steps for reads, right now */ | 2947 | /* don't bother with additional async steps for reads, right now */ |
| 2948 | if (!(rw & (1 << BIO_RW))) { | 2948 | if (!(rw & REQ_WRITE)) { |
| 2949 | bio_get(bio); | 2949 | bio_get(bio); |
| 2950 | submit_bio(rw, bio); | 2950 | submit_bio(rw, bio); |
| 2951 | bio_put(bio); | 2951 | bio_put(bio); |
| @@ -2964,7 +2964,7 @@ static noinline int schedule_bio(struct btrfs_root *root, | |||
| 2964 | bio->bi_rw |= rw; | 2964 | bio->bi_rw |= rw; |
| 2965 | 2965 | ||
| 2966 | spin_lock(&device->io_lock); | 2966 | spin_lock(&device->io_lock); |
| 2967 | if (bio_rw_flagged(bio, BIO_RW_SYNCIO)) | 2967 | if (bio->bi_rw & REQ_SYNC) |
| 2968 | pending_bios = &device->pending_sync_bios; | 2968 | pending_bios = &device->pending_sync_bios; |
| 2969 | else | 2969 | else |
| 2970 | pending_bios = &device->pending_bios; | 2970 | pending_bios = &device->pending_bios; |
diff --git a/fs/buffer.c b/fs/buffer.c index d54812b198e9..50efa339e051 100644 --- a/fs/buffer.c +++ b/fs/buffer.c | |||
| @@ -1833,9 +1833,10 @@ void page_zero_new_buffers(struct page *page, unsigned from, unsigned to) | |||
| 1833 | } | 1833 | } |
| 1834 | EXPORT_SYMBOL(page_zero_new_buffers); | 1834 | EXPORT_SYMBOL(page_zero_new_buffers); |
| 1835 | 1835 | ||
| 1836 | static int __block_prepare_write(struct inode *inode, struct page *page, | 1836 | int block_prepare_write(struct page *page, unsigned from, unsigned to, |
| 1837 | unsigned from, unsigned to, get_block_t *get_block) | 1837 | get_block_t *get_block) |
| 1838 | { | 1838 | { |
| 1839 | struct inode *inode = page->mapping->host; | ||
| 1839 | unsigned block_start, block_end; | 1840 | unsigned block_start, block_end; |
| 1840 | sector_t block; | 1841 | sector_t block; |
| 1841 | int err = 0; | 1842 | int err = 0; |
| @@ -1908,10 +1909,13 @@ static int __block_prepare_write(struct inode *inode, struct page *page, | |||
| 1908 | if (!buffer_uptodate(*wait_bh)) | 1909 | if (!buffer_uptodate(*wait_bh)) |
| 1909 | err = -EIO; | 1910 | err = -EIO; |
| 1910 | } | 1911 | } |
| 1911 | if (unlikely(err)) | 1912 | if (unlikely(err)) { |
| 1912 | page_zero_new_buffers(page, from, to); | 1913 | page_zero_new_buffers(page, from, to); |
| 1914 | ClearPageUptodate(page); | ||
| 1915 | } | ||
| 1913 | return err; | 1916 | return err; |
| 1914 | } | 1917 | } |
| 1918 | EXPORT_SYMBOL(block_prepare_write); | ||
| 1915 | 1919 | ||
| 1916 | static int __block_commit_write(struct inode *inode, struct page *page, | 1920 | static int __block_commit_write(struct inode *inode, struct page *page, |
| 1917 | unsigned from, unsigned to) | 1921 | unsigned from, unsigned to) |
| @@ -1948,90 +1952,41 @@ static int __block_commit_write(struct inode *inode, struct page *page, | |||
| 1948 | return 0; | 1952 | return 0; |
| 1949 | } | 1953 | } |
| 1950 | 1954 | ||
| 1951 | /* | 1955 | int __block_write_begin(struct page *page, loff_t pos, unsigned len, |
| 1952 | * Filesystems implementing the new truncate sequence should use the | 1956 | get_block_t *get_block) |
| 1953 | * _newtrunc postfix variant which won't incorrectly call vmtruncate. | ||
| 1954 | * The filesystem needs to handle block truncation upon failure. | ||
| 1955 | */ | ||
| 1956 | int block_write_begin_newtrunc(struct file *file, struct address_space *mapping, | ||
| 1957 | loff_t pos, unsigned len, unsigned flags, | ||
| 1958 | struct page **pagep, void **fsdata, | ||
| 1959 | get_block_t *get_block) | ||
| 1960 | { | 1957 | { |
| 1961 | struct inode *inode = mapping->host; | 1958 | unsigned start = pos & (PAGE_CACHE_SIZE - 1); |
| 1962 | int status = 0; | ||
| 1963 | struct page *page; | ||
| 1964 | pgoff_t index; | ||
| 1965 | unsigned start, end; | ||
| 1966 | int ownpage = 0; | ||
| 1967 | |||
| 1968 | index = pos >> PAGE_CACHE_SHIFT; | ||
| 1969 | start = pos & (PAGE_CACHE_SIZE - 1); | ||
| 1970 | end = start + len; | ||
| 1971 | |||
| 1972 | page = *pagep; | ||
| 1973 | if (page == NULL) { | ||
| 1974 | ownpage = 1; | ||
| 1975 | page = grab_cache_page_write_begin(mapping, index, flags); | ||
| 1976 | if (!page) { | ||
| 1977 | status = -ENOMEM; | ||
| 1978 | goto out; | ||
| 1979 | } | ||
| 1980 | *pagep = page; | ||
| 1981 | } else | ||
| 1982 | BUG_ON(!PageLocked(page)); | ||
| 1983 | |||
| 1984 | status = __block_prepare_write(inode, page, start, end, get_block); | ||
| 1985 | if (unlikely(status)) { | ||
| 1986 | ClearPageUptodate(page); | ||
| 1987 | 1959 | ||
| 1988 | if (ownpage) { | 1960 | return block_prepare_write(page, start, start + len, get_block); |
| 1989 | unlock_page(page); | ||
| 1990 | page_cache_release(page); | ||
| 1991 | *pagep = NULL; | ||
| 1992 | } | ||
| 1993 | } | ||
| 1994 | |||
| 1995 | out: | ||
| 1996 | return status; | ||
| 1997 | } | 1961 | } |
| 1998 | EXPORT_SYMBOL(block_write_begin_newtrunc); | 1962 | EXPORT_SYMBOL(__block_write_begin); |
| 1999 | 1963 | ||
| 2000 | /* | 1964 | /* |
| 2001 | * block_write_begin takes care of the basic task of block allocation and | 1965 | * block_write_begin takes care of the basic task of block allocation and |
| 2002 | * bringing partial write blocks uptodate first. | 1966 | * bringing partial write blocks uptodate first. |
| 2003 | * | 1967 | * |
| 2004 | * If *pagep is not NULL, then block_write_begin uses the locked page | 1968 | * The filesystem needs to handle block truncation upon failure. |
| 2005 | * at *pagep rather than allocating its own. In this case, the page will | ||
| 2006 | * not be unlocked or deallocated on failure. | ||
| 2007 | */ | 1969 | */ |
| 2008 | int block_write_begin(struct file *file, struct address_space *mapping, | 1970 | int block_write_begin(struct address_space *mapping, loff_t pos, unsigned len, |
| 2009 | loff_t pos, unsigned len, unsigned flags, | 1971 | unsigned flags, struct page **pagep, get_block_t *get_block) |
| 2010 | struct page **pagep, void **fsdata, | ||
| 2011 | get_block_t *get_block) | ||
| 2012 | { | 1972 | { |
| 2013 | int ret; | 1973 | pgoff_t index = pos >> PAGE_CACHE_SHIFT; |
| 1974 | struct page *page; | ||
| 1975 | int status; | ||
| 2014 | 1976 | ||
| 2015 | ret = block_write_begin_newtrunc(file, mapping, pos, len, flags, | 1977 | page = grab_cache_page_write_begin(mapping, index, flags); |
| 2016 | pagep, fsdata, get_block); | 1978 | if (!page) |
| 1979 | return -ENOMEM; | ||
| 2017 | 1980 | ||
| 2018 | /* | 1981 | status = __block_write_begin(page, pos, len, get_block); |
| 2019 | * prepare_write() may have instantiated a few blocks | 1982 | if (unlikely(status)) { |
| 2020 | * outside i_size. Trim these off again. Don't need | 1983 | unlock_page(page); |
| 2021 | * i_size_read because we hold i_mutex. | 1984 | page_cache_release(page); |
| 2022 | * | 1985 | page = NULL; |
| 2023 | * Filesystems which pass down their own page also cannot | ||
| 2024 | * call into vmtruncate here because it would lead to lock | ||
| 2025 | * inversion problems (*pagep is locked). This is a further | ||
| 2026 | * example of where the old truncate sequence is inadequate. | ||
| 2027 | */ | ||
| 2028 | if (unlikely(ret) && *pagep == NULL) { | ||
| 2029 | loff_t isize = mapping->host->i_size; | ||
| 2030 | if (pos + len > isize) | ||
| 2031 | vmtruncate(mapping->host, isize); | ||
| 2032 | } | 1986 | } |
| 2033 | 1987 | ||
| 2034 | return ret; | 1988 | *pagep = page; |
| 1989 | return status; | ||
| 2035 | } | 1990 | } |
| 2036 | EXPORT_SYMBOL(block_write_begin); | 1991 | EXPORT_SYMBOL(block_write_begin); |
| 2037 | 1992 | ||
| @@ -2351,7 +2306,7 @@ out: | |||
| 2351 | * For moronic filesystems that do not allow holes in file. | 2306 | * For moronic filesystems that do not allow holes in file. |
| 2352 | * We may have to extend the file. | 2307 | * We may have to extend the file. |
| 2353 | */ | 2308 | */ |
| 2354 | int cont_write_begin_newtrunc(struct file *file, struct address_space *mapping, | 2309 | int cont_write_begin(struct file *file, struct address_space *mapping, |
| 2355 | loff_t pos, unsigned len, unsigned flags, | 2310 | loff_t pos, unsigned len, unsigned flags, |
| 2356 | struct page **pagep, void **fsdata, | 2311 | struct page **pagep, void **fsdata, |
| 2357 | get_block_t *get_block, loff_t *bytes) | 2312 | get_block_t *get_block, loff_t *bytes) |
| @@ -2363,7 +2318,7 @@ int cont_write_begin_newtrunc(struct file *file, struct address_space *mapping, | |||
| 2363 | 2318 | ||
| 2364 | err = cont_expand_zero(file, mapping, pos, bytes); | 2319 | err = cont_expand_zero(file, mapping, pos, bytes); |
| 2365 | if (err) | 2320 | if (err) |
| 2366 | goto out; | 2321 | return err; |
| 2367 | 2322 | ||
| 2368 | zerofrom = *bytes & ~PAGE_CACHE_MASK; | 2323 | zerofrom = *bytes & ~PAGE_CACHE_MASK; |
| 2369 | if (pos+len > *bytes && zerofrom & (blocksize-1)) { | 2324 | if (pos+len > *bytes && zerofrom & (blocksize-1)) { |
| @@ -2371,44 +2326,10 @@ int cont_write_begin_newtrunc(struct file *file, struct address_space *mapping, | |||
| 2371 | (*bytes)++; | 2326 | (*bytes)++; |
| 2372 | } | 2327 | } |
| 2373 | 2328 | ||
| 2374 | *pagep = NULL; | 2329 | return block_write_begin(mapping, pos, len, flags, pagep, get_block); |
| 2375 | err = block_write_begin_newtrunc(file, mapping, pos, len, | ||
| 2376 | flags, pagep, fsdata, get_block); | ||
| 2377 | out: | ||
| 2378 | return err; | ||
| 2379 | } | ||
| 2380 | EXPORT_SYMBOL(cont_write_begin_newtrunc); | ||
| 2381 | |||
| 2382 | int cont_write_begin(struct file *file, struct address_space *mapping, | ||
| 2383 | loff_t pos, unsigned len, unsigned flags, | ||
| 2384 | struct page **pagep, void **fsdata, | ||
| 2385 | get_block_t *get_block, loff_t *bytes) | ||
| 2386 | { | ||
| 2387 | int ret; | ||
| 2388 | |||
| 2389 | ret = cont_write_begin_newtrunc(file, mapping, pos, len, flags, | ||
| 2390 | pagep, fsdata, get_block, bytes); | ||
| 2391 | if (unlikely(ret)) { | ||
| 2392 | loff_t isize = mapping->host->i_size; | ||
| 2393 | if (pos + len > isize) | ||
| 2394 | vmtruncate(mapping->host, isize); | ||
| 2395 | } | ||
| 2396 | |||
| 2397 | return ret; | ||
| 2398 | } | 2330 | } |
| 2399 | EXPORT_SYMBOL(cont_write_begin); | 2331 | EXPORT_SYMBOL(cont_write_begin); |
| 2400 | 2332 | ||
| 2401 | int block_prepare_write(struct page *page, unsigned from, unsigned to, | ||
| 2402 | get_block_t *get_block) | ||
| 2403 | { | ||
| 2404 | struct inode *inode = page->mapping->host; | ||
| 2405 | int err = __block_prepare_write(inode, page, from, to, get_block); | ||
| 2406 | if (err) | ||
| 2407 | ClearPageUptodate(page); | ||
| 2408 | return err; | ||
| 2409 | } | ||
| 2410 | EXPORT_SYMBOL(block_prepare_write); | ||
| 2411 | |||
| 2412 | int block_commit_write(struct page *page, unsigned from, unsigned to) | 2333 | int block_commit_write(struct page *page, unsigned from, unsigned to) |
| 2413 | { | 2334 | { |
| 2414 | struct inode *inode = page->mapping->host; | 2335 | struct inode *inode = page->mapping->host; |
| @@ -2510,11 +2431,11 @@ static void attach_nobh_buffers(struct page *page, struct buffer_head *head) | |||
| 2510 | } | 2431 | } |
| 2511 | 2432 | ||
| 2512 | /* | 2433 | /* |
| 2513 | * Filesystems implementing the new truncate sequence should use the | 2434 | * On entry, the page is fully not uptodate. |
| 2514 | * _newtrunc postfix variant which won't incorrectly call vmtruncate. | 2435 | * On exit the page is fully uptodate in the areas outside (from,to) |
| 2515 | * The filesystem needs to handle block truncation upon failure. | 2436 | * The filesystem needs to handle block truncation upon failure. |
| 2516 | */ | 2437 | */ |
| 2517 | int nobh_write_begin_newtrunc(struct file *file, struct address_space *mapping, | 2438 | int nobh_write_begin(struct address_space *mapping, |
| 2518 | loff_t pos, unsigned len, unsigned flags, | 2439 | loff_t pos, unsigned len, unsigned flags, |
| 2519 | struct page **pagep, void **fsdata, | 2440 | struct page **pagep, void **fsdata, |
| 2520 | get_block_t *get_block) | 2441 | get_block_t *get_block) |
| @@ -2547,8 +2468,8 @@ int nobh_write_begin_newtrunc(struct file *file, struct address_space *mapping, | |||
| 2547 | unlock_page(page); | 2468 | unlock_page(page); |
| 2548 | page_cache_release(page); | 2469 | page_cache_release(page); |
| 2549 | *pagep = NULL; | 2470 | *pagep = NULL; |
| 2550 | return block_write_begin_newtrunc(file, mapping, pos, len, | 2471 | return block_write_begin(mapping, pos, len, flags, pagep, |
| 2551 | flags, pagep, fsdata, get_block); | 2472 | get_block); |
| 2552 | } | 2473 | } |
| 2553 | 2474 | ||
| 2554 | if (PageMappedToDisk(page)) | 2475 | if (PageMappedToDisk(page)) |
| @@ -2654,35 +2575,6 @@ out_release: | |||
| 2654 | 2575 | ||
| 2655 | return ret; | 2576 | return ret; |
| 2656 | } | 2577 | } |
| 2657 | EXPORT_SYMBOL(nobh_write_begin_newtrunc); | ||
| 2658 | |||
| 2659 | /* | ||
| 2660 | * On entry, the page is fully not uptodate. | ||
| 2661 | * On exit the page is fully uptodate in the areas outside (from,to) | ||
| 2662 | */ | ||
| 2663 | int nobh_write_begin(struct file *file, struct address_space *mapping, | ||
| 2664 | loff_t pos, unsigned len, unsigned flags, | ||
| 2665 | struct page **pagep, void **fsdata, | ||
| 2666 | get_block_t *get_block) | ||
| 2667 | { | ||
| 2668 | int ret; | ||
| 2669 | |||
| 2670 | ret = nobh_write_begin_newtrunc(file, mapping, pos, len, flags, | ||
| 2671 | pagep, fsdata, get_block); | ||
| 2672 | |||
| 2673 | /* | ||
| 2674 | * prepare_write() may have instantiated a few blocks | ||
| 2675 | * outside i_size. Trim these off again. Don't need | ||
| 2676 | * i_size_read because we hold i_mutex. | ||
| 2677 | */ | ||
| 2678 | if (unlikely(ret)) { | ||
| 2679 | loff_t isize = mapping->host->i_size; | ||
| 2680 | if (pos + len > isize) | ||
| 2681 | vmtruncate(mapping->host, isize); | ||
| 2682 | } | ||
| 2683 | |||
| 2684 | return ret; | ||
| 2685 | } | ||
| 2686 | EXPORT_SYMBOL(nobh_write_begin); | 2578 | EXPORT_SYMBOL(nobh_write_begin); |
| 2687 | 2579 | ||
| 2688 | int nobh_write_end(struct file *file, struct address_space *mapping, | 2580 | int nobh_write_end(struct file *file, struct address_space *mapping, |
diff --git a/fs/cachefiles/bind.c b/fs/cachefiles/bind.c index 2906077ac798..a2603e7c0bb5 100644 --- a/fs/cachefiles/bind.c +++ b/fs/cachefiles/bind.c | |||
| @@ -146,7 +146,7 @@ static int cachefiles_daemon_add_cache(struct cachefiles_cache *cache) | |||
| 146 | goto error_unsupported; | 146 | goto error_unsupported; |
| 147 | 147 | ||
| 148 | /* get the cache size and blocksize */ | 148 | /* get the cache size and blocksize */ |
| 149 | ret = vfs_statfs(root, &stats); | 149 | ret = vfs_statfs(&path, &stats); |
| 150 | if (ret < 0) | 150 | if (ret < 0) |
| 151 | goto error_unsupported; | 151 | goto error_unsupported; |
| 152 | 152 | ||
diff --git a/fs/cachefiles/daemon.c b/fs/cachefiles/daemon.c index c2413561ea75..727caedcdd92 100644 --- a/fs/cachefiles/daemon.c +++ b/fs/cachefiles/daemon.c | |||
| @@ -552,8 +552,7 @@ static int cachefiles_daemon_tag(struct cachefiles_cache *cache, char *args) | |||
| 552 | */ | 552 | */ |
| 553 | static int cachefiles_daemon_cull(struct cachefiles_cache *cache, char *args) | 553 | static int cachefiles_daemon_cull(struct cachefiles_cache *cache, char *args) |
| 554 | { | 554 | { |
| 555 | struct fs_struct *fs; | 555 | struct path path; |
| 556 | struct dentry *dir; | ||
| 557 | const struct cred *saved_cred; | 556 | const struct cred *saved_cred; |
| 558 | int ret; | 557 | int ret; |
| 559 | 558 | ||
| @@ -573,24 +572,21 @@ static int cachefiles_daemon_cull(struct cachefiles_cache *cache, char *args) | |||
| 573 | } | 572 | } |
| 574 | 573 | ||
| 575 | /* extract the directory dentry from the cwd */ | 574 | /* extract the directory dentry from the cwd */ |
| 576 | fs = current->fs; | 575 | get_fs_pwd(current->fs, &path); |
| 577 | read_lock(&fs->lock); | ||
| 578 | dir = dget(fs->pwd.dentry); | ||
| 579 | read_unlock(&fs->lock); | ||
| 580 | 576 | ||
| 581 | if (!S_ISDIR(dir->d_inode->i_mode)) | 577 | if (!S_ISDIR(path.dentry->d_inode->i_mode)) |
| 582 | goto notdir; | 578 | goto notdir; |
| 583 | 579 | ||
| 584 | cachefiles_begin_secure(cache, &saved_cred); | 580 | cachefiles_begin_secure(cache, &saved_cred); |
| 585 | ret = cachefiles_cull(cache, dir, args); | 581 | ret = cachefiles_cull(cache, path.dentry, args); |
| 586 | cachefiles_end_secure(cache, saved_cred); | 582 | cachefiles_end_secure(cache, saved_cred); |
| 587 | 583 | ||
| 588 | dput(dir); | 584 | path_put(&path); |
| 589 | _leave(" = %d", ret); | 585 | _leave(" = %d", ret); |
| 590 | return ret; | 586 | return ret; |
| 591 | 587 | ||
| 592 | notdir: | 588 | notdir: |
| 593 | dput(dir); | 589 | path_put(&path); |
| 594 | kerror("cull command requires dirfd to be a directory"); | 590 | kerror("cull command requires dirfd to be a directory"); |
| 595 | return -ENOTDIR; | 591 | return -ENOTDIR; |
| 596 | 592 | ||
| @@ -628,8 +624,7 @@ inval: | |||
| 628 | */ | 624 | */ |
| 629 | static int cachefiles_daemon_inuse(struct cachefiles_cache *cache, char *args) | 625 | static int cachefiles_daemon_inuse(struct cachefiles_cache *cache, char *args) |
| 630 | { | 626 | { |
| 631 | struct fs_struct *fs; | 627 | struct path path; |
| 632 | struct dentry *dir; | ||
| 633 | const struct cred *saved_cred; | 628 | const struct cred *saved_cred; |
| 634 | int ret; | 629 | int ret; |
| 635 | 630 | ||
| @@ -649,24 +644,21 @@ static int cachefiles_daemon_inuse(struct cachefiles_cache *cache, char *args) | |||
| 649 | } | 644 | } |
| 650 | 645 | ||
| 651 | /* extract the directory dentry from the cwd */ | 646 | /* extract the directory dentry from the cwd */ |
| 652 | fs = current->fs; | 647 | get_fs_pwd(current->fs, &path); |
| 653 | read_lock(&fs->lock); | ||
| 654 | dir = dget(fs->pwd.dentry); | ||
| 655 | read_unlock(&fs->lock); | ||
| 656 | 648 | ||
| 657 | if (!S_ISDIR(dir->d_inode->i_mode)) | 649 | if (!S_ISDIR(path.dentry->d_inode->i_mode)) |
| 658 | goto notdir; | 650 | goto notdir; |
| 659 | 651 | ||
| 660 | cachefiles_begin_secure(cache, &saved_cred); | 652 | cachefiles_begin_secure(cache, &saved_cred); |
| 661 | ret = cachefiles_check_in_use(cache, dir, args); | 653 | ret = cachefiles_check_in_use(cache, path.dentry, args); |
| 662 | cachefiles_end_secure(cache, saved_cred); | 654 | cachefiles_end_secure(cache, saved_cred); |
| 663 | 655 | ||
| 664 | dput(dir); | 656 | path_put(&path); |
| 665 | //_leave(" = %d", ret); | 657 | //_leave(" = %d", ret); |
| 666 | return ret; | 658 | return ret; |
| 667 | 659 | ||
| 668 | notdir: | 660 | notdir: |
| 669 | dput(dir); | 661 | path_put(&path); |
| 670 | kerror("inuse command requires dirfd to be a directory"); | 662 | kerror("inuse command requires dirfd to be a directory"); |
| 671 | return -ENOTDIR; | 663 | return -ENOTDIR; |
| 672 | 664 | ||
| @@ -683,6 +675,10 @@ int cachefiles_has_space(struct cachefiles_cache *cache, | |||
| 683 | unsigned fnr, unsigned bnr) | 675 | unsigned fnr, unsigned bnr) |
| 684 | { | 676 | { |
| 685 | struct kstatfs stats; | 677 | struct kstatfs stats; |
| 678 | struct path path = { | ||
| 679 | .mnt = cache->mnt, | ||
| 680 | .dentry = cache->mnt->mnt_root, | ||
| 681 | }; | ||
| 686 | int ret; | 682 | int ret; |
| 687 | 683 | ||
| 688 | //_enter("{%llu,%llu,%llu,%llu,%llu,%llu},%u,%u", | 684 | //_enter("{%llu,%llu,%llu,%llu,%llu,%llu},%u,%u", |
| @@ -697,7 +693,7 @@ int cachefiles_has_space(struct cachefiles_cache *cache, | |||
| 697 | /* find out how many pages of blockdev are available */ | 693 | /* find out how many pages of blockdev are available */ |
| 698 | memset(&stats, 0, sizeof(stats)); | 694 | memset(&stats, 0, sizeof(stats)); |
| 699 | 695 | ||
| 700 | ret = vfs_statfs(cache->mnt->mnt_root, &stats); | 696 | ret = vfs_statfs(&path, &stats); |
| 701 | if (ret < 0) { | 697 | if (ret < 0) { |
| 702 | if (ret == -EIO) | 698 | if (ret == -EIO) |
| 703 | cachefiles_io_error(cache, "statfs failed"); | 699 | cachefiles_io_error(cache, "statfs failed"); |
diff --git a/fs/cachefiles/internal.h b/fs/cachefiles/internal.h index a8cd821226da..bd6bc1bde2d7 100644 --- a/fs/cachefiles/internal.h +++ b/fs/cachefiles/internal.h | |||
| @@ -267,13 +267,6 @@ do { \ | |||
| 267 | #define dbgprintk(FMT, ...) \ | 267 | #define dbgprintk(FMT, ...) \ |
| 268 | printk(KERN_DEBUG "[%-6.6s] "FMT"\n", current->comm, ##__VA_ARGS__) | 268 | printk(KERN_DEBUG "[%-6.6s] "FMT"\n", current->comm, ##__VA_ARGS__) |
| 269 | 269 | ||
| 270 | /* make sure we maintain the format strings, even when debugging is disabled */ | ||
| 271 | static inline void _dbprintk(const char *fmt, ...) | ||
| 272 | __attribute__((format(printf, 1, 2))); | ||
| 273 | static inline void _dbprintk(const char *fmt, ...) | ||
| 274 | { | ||
| 275 | } | ||
| 276 | |||
| 277 | #define kenter(FMT, ...) dbgprintk("==> %s("FMT")", __func__, ##__VA_ARGS__) | 270 | #define kenter(FMT, ...) dbgprintk("==> %s("FMT")", __func__, ##__VA_ARGS__) |
| 278 | #define kleave(FMT, ...) dbgprintk("<== %s()"FMT"", __func__, ##__VA_ARGS__) | 271 | #define kleave(FMT, ...) dbgprintk("<== %s()"FMT"", __func__, ##__VA_ARGS__) |
| 279 | #define kdebug(FMT, ...) dbgprintk(FMT, ##__VA_ARGS__) | 272 | #define kdebug(FMT, ...) dbgprintk(FMT, ##__VA_ARGS__) |
| @@ -304,9 +297,9 @@ do { \ | |||
| 304 | } while (0) | 297 | } while (0) |
| 305 | 298 | ||
| 306 | #else | 299 | #else |
| 307 | #define _enter(FMT, ...) _dbprintk("==> %s("FMT")", __func__, ##__VA_ARGS__) | 300 | #define _enter(FMT, ...) no_printk("==> %s("FMT")", __func__, ##__VA_ARGS__) |
| 308 | #define _leave(FMT, ...) _dbprintk("<== %s()"FMT"", __func__, ##__VA_ARGS__) | 301 | #define _leave(FMT, ...) no_printk("<== %s()"FMT"", __func__, ##__VA_ARGS__) |
| 309 | #define _debug(FMT, ...) _dbprintk(FMT, ##__VA_ARGS__) | 302 | #define _debug(FMT, ...) no_printk(FMT, ##__VA_ARGS__) |
| 310 | #endif | 303 | #endif |
| 311 | 304 | ||
| 312 | #if 1 /* defined(__KDEBUGALL) */ | 305 | #if 1 /* defined(__KDEBUGALL) */ |
diff --git a/fs/ceph/Makefile b/fs/ceph/Makefile index 6a660e610be8..278e1172600d 100644 --- a/fs/ceph/Makefile +++ b/fs/ceph/Makefile | |||
| @@ -6,7 +6,7 @@ ifneq ($(KERNELRELEASE),) | |||
| 6 | 6 | ||
| 7 | obj-$(CONFIG_CEPH_FS) += ceph.o | 7 | obj-$(CONFIG_CEPH_FS) += ceph.o |
| 8 | 8 | ||
| 9 | ceph-objs := super.o inode.o dir.o file.o addr.o ioctl.o \ | 9 | ceph-objs := super.o inode.o dir.o file.o locks.o addr.o ioctl.o \ |
| 10 | export.o caps.o snap.o xattr.o \ | 10 | export.o caps.o snap.o xattr.o \ |
| 11 | messenger.o msgpool.o buffer.o pagelist.o \ | 11 | messenger.o msgpool.o buffer.o pagelist.o \ |
| 12 | mds_client.o mdsmap.o \ | 12 | mds_client.o mdsmap.o \ |
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index d9c60b84949a..5598a0d02295 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c | |||
| @@ -309,7 +309,8 @@ static int ceph_readpages(struct file *file, struct address_space *mapping, | |||
| 309 | zero_user_segment(page, s, PAGE_CACHE_SIZE); | 309 | zero_user_segment(page, s, PAGE_CACHE_SIZE); |
| 310 | } | 310 | } |
| 311 | 311 | ||
| 312 | if (add_to_page_cache_lru(page, mapping, page->index, GFP_NOFS)) { | 312 | if (add_to_page_cache_lru(page, mapping, page->index, |
| 313 | GFP_NOFS)) { | ||
| 313 | page_cache_release(page); | 314 | page_cache_release(page); |
| 314 | dout("readpages %p add_to_page_cache failed %p\n", | 315 | dout("readpages %p add_to_page_cache failed %p\n", |
| 315 | inode, page); | 316 | inode, page); |
| @@ -552,7 +553,7 @@ static void writepages_finish(struct ceph_osd_request *req, | |||
| 552 | * page truncation thread, possibly losing some data that | 553 | * page truncation thread, possibly losing some data that |
| 553 | * raced its way in | 554 | * raced its way in |
| 554 | */ | 555 | */ |
| 555 | if ((issued & CEPH_CAP_FILE_CACHE) == 0) | 556 | if ((issued & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) == 0) |
| 556 | generic_error_remove_page(inode->i_mapping, page); | 557 | generic_error_remove_page(inode->i_mapping, page); |
| 557 | 558 | ||
| 558 | unlock_page(page); | 559 | unlock_page(page); |
| @@ -797,9 +798,12 @@ get_more_pages: | |||
| 797 | dout("%p will write page %p idx %lu\n", | 798 | dout("%p will write page %p idx %lu\n", |
| 798 | inode, page, page->index); | 799 | inode, page, page->index); |
| 799 | 800 | ||
| 800 | writeback_stat = atomic_long_inc_return(&client->writeback_count); | 801 | writeback_stat = |
| 801 | if (writeback_stat > CONGESTION_ON_THRESH(client->mount_args->congestion_kb)) { | 802 | atomic_long_inc_return(&client->writeback_count); |
| 802 | set_bdi_congested(&client->backing_dev_info, BLK_RW_ASYNC); | 803 | if (writeback_stat > CONGESTION_ON_THRESH( |
| 804 | client->mount_args->congestion_kb)) { | ||
| 805 | set_bdi_congested(&client->backing_dev_info, | ||
| 806 | BLK_RW_ASYNC); | ||
| 803 | } | 807 | } |
| 804 | 808 | ||
| 805 | set_page_writeback(page); | 809 | set_page_writeback(page); |
| @@ -1036,7 +1040,7 @@ static int ceph_write_begin(struct file *file, struct address_space *mapping, | |||
| 1036 | *pagep = page; | 1040 | *pagep = page; |
| 1037 | 1041 | ||
| 1038 | dout("write_begin file %p inode %p page %p %d~%d\n", file, | 1042 | dout("write_begin file %p inode %p page %p %d~%d\n", file, |
| 1039 | inode, page, (int)pos, (int)len); | 1043 | inode, page, (int)pos, (int)len); |
| 1040 | 1044 | ||
| 1041 | r = ceph_update_writeable_page(file, pos, len, page); | 1045 | r = ceph_update_writeable_page(file, pos, len, page); |
| 1042 | } while (r == -EAGAIN); | 1046 | } while (r == -EAGAIN); |
diff --git a/fs/ceph/armor.c b/fs/ceph/armor.c index 67b2c030924b..eb2a666b0be7 100644 --- a/fs/ceph/armor.c +++ b/fs/ceph/armor.c | |||
| @@ -1,11 +1,15 @@ | |||
| 1 | 1 | ||
| 2 | #include <linux/errno.h> | 2 | #include <linux/errno.h> |
| 3 | 3 | ||
| 4 | int ceph_armor(char *dst, const char *src, const char *end); | ||
| 5 | int ceph_unarmor(char *dst, const char *src, const char *end); | ||
| 6 | |||
| 4 | /* | 7 | /* |
| 5 | * base64 encode/decode. | 8 | * base64 encode/decode. |
| 6 | */ | 9 | */ |
| 7 | 10 | ||
| 8 | const char *pem_key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | 11 | static const char *pem_key = |
| 12 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | ||
| 9 | 13 | ||
| 10 | static int encode_bits(int c) | 14 | static int encode_bits(int c) |
| 11 | { | 15 | { |
diff --git a/fs/ceph/auth.c b/fs/ceph/auth.c index 89490beaf537..6d2e30600627 100644 --- a/fs/ceph/auth.c +++ b/fs/ceph/auth.c | |||
| @@ -20,7 +20,7 @@ static u32 supported_protocols[] = { | |||
| 20 | CEPH_AUTH_CEPHX | 20 | CEPH_AUTH_CEPHX |
| 21 | }; | 21 | }; |
| 22 | 22 | ||
| 23 | int ceph_auth_init_protocol(struct ceph_auth_client *ac, int protocol) | 23 | static int ceph_auth_init_protocol(struct ceph_auth_client *ac, int protocol) |
| 24 | { | 24 | { |
| 25 | switch (protocol) { | 25 | switch (protocol) { |
| 26 | case CEPH_AUTH_NONE: | 26 | case CEPH_AUTH_NONE: |
| @@ -133,8 +133,8 @@ bad: | |||
| 133 | return -ERANGE; | 133 | return -ERANGE; |
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | int ceph_build_auth_request(struct ceph_auth_client *ac, | 136 | static int ceph_build_auth_request(struct ceph_auth_client *ac, |
| 137 | void *msg_buf, size_t msg_len) | 137 | void *msg_buf, size_t msg_len) |
| 138 | { | 138 | { |
| 139 | struct ceph_mon_request_header *monhdr = msg_buf; | 139 | struct ceph_mon_request_header *monhdr = msg_buf; |
| 140 | void *p = monhdr + 1; | 140 | void *p = monhdr + 1; |
diff --git a/fs/ceph/auth_x.c b/fs/ceph/auth_x.c index 6d44053ecff1..582e0b2caf8a 100644 --- a/fs/ceph/auth_x.c +++ b/fs/ceph/auth_x.c | |||
| @@ -87,8 +87,8 @@ static int ceph_x_decrypt(struct ceph_crypto_key *secret, | |||
| 87 | /* | 87 | /* |
| 88 | * get existing (or insert new) ticket handler | 88 | * get existing (or insert new) ticket handler |
| 89 | */ | 89 | */ |
| 90 | struct ceph_x_ticket_handler *get_ticket_handler(struct ceph_auth_client *ac, | 90 | static struct ceph_x_ticket_handler * |
| 91 | int service) | 91 | get_ticket_handler(struct ceph_auth_client *ac, int service) |
| 92 | { | 92 | { |
| 93 | struct ceph_x_ticket_handler *th; | 93 | struct ceph_x_ticket_handler *th; |
| 94 | struct ceph_x_info *xi = ac->private; | 94 | struct ceph_x_info *xi = ac->private; |
| @@ -429,7 +429,7 @@ static int ceph_x_build_request(struct ceph_auth_client *ac, | |||
| 429 | auth->struct_v = 1; | 429 | auth->struct_v = 1; |
| 430 | auth->key = 0; | 430 | auth->key = 0; |
| 431 | for (u = (u64 *)tmp_enc; u + 1 <= (u64 *)(tmp_enc + ret); u++) | 431 | for (u = (u64 *)tmp_enc; u + 1 <= (u64 *)(tmp_enc + ret); u++) |
| 432 | auth->key ^= *u; | 432 | auth->key ^= *(__le64 *)u; |
| 433 | dout(" server_challenge %llx client_challenge %llx key %llx\n", | 433 | dout(" server_challenge %llx client_challenge %llx key %llx\n", |
| 434 | xi->server_challenge, le64_to_cpu(auth->client_challenge), | 434 | xi->server_challenge, le64_to_cpu(auth->client_challenge), |
| 435 | le64_to_cpu(auth->key)); | 435 | le64_to_cpu(auth->key)); |
diff --git a/fs/ceph/buffer.c b/fs/ceph/buffer.c index c67535d70aa6..cd39f17021de 100644 --- a/fs/ceph/buffer.c +++ b/fs/ceph/buffer.c | |||
| @@ -47,22 +47,6 @@ void ceph_buffer_release(struct kref *kref) | |||
| 47 | kfree(b); | 47 | kfree(b); |
| 48 | } | 48 | } |
| 49 | 49 | ||
| 50 | int ceph_buffer_alloc(struct ceph_buffer *b, int len, gfp_t gfp) | ||
| 51 | { | ||
| 52 | b->vec.iov_base = kmalloc(len, gfp | __GFP_NOWARN); | ||
| 53 | if (b->vec.iov_base) { | ||
| 54 | b->is_vmalloc = false; | ||
| 55 | } else { | ||
| 56 | b->vec.iov_base = __vmalloc(len, gfp, PAGE_KERNEL); | ||
| 57 | b->is_vmalloc = true; | ||
| 58 | } | ||
| 59 | if (!b->vec.iov_base) | ||
| 60 | return -ENOMEM; | ||
| 61 | b->alloc_len = len; | ||
| 62 | b->vec.iov_len = len; | ||
| 63 | return 0; | ||
| 64 | } | ||
| 65 | |||
| 66 | int ceph_decode_buffer(struct ceph_buffer **b, void **p, void *end) | 50 | int ceph_decode_buffer(struct ceph_buffer **b, void **p, void *end) |
| 67 | { | 51 | { |
| 68 | size_t len; | 52 | size_t len; |
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index b81be9a56487..7bf182b03973 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c | |||
| @@ -113,58 +113,41 @@ const char *ceph_cap_string(int caps) | |||
| 113 | return cap_str[i]; | 113 | return cap_str[i]; |
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | /* | 116 | void ceph_caps_init(struct ceph_mds_client *mdsc) |
| 117 | * Cap reservations | ||
| 118 | * | ||
| 119 | * Maintain a global pool of preallocated struct ceph_caps, referenced | ||
| 120 | * by struct ceph_caps_reservations. This ensures that we preallocate | ||
| 121 | * memory needed to successfully process an MDS response. (If an MDS | ||
| 122 | * sends us cap information and we fail to process it, we will have | ||
| 123 | * problems due to the client and MDS being out of sync.) | ||
| 124 | * | ||
| 125 | * Reservations are 'owned' by a ceph_cap_reservation context. | ||
| 126 | */ | ||
| 127 | static spinlock_t caps_list_lock; | ||
| 128 | static struct list_head caps_list; /* unused (reserved or unreserved) */ | ||
| 129 | static int caps_total_count; /* total caps allocated */ | ||
| 130 | static int caps_use_count; /* in use */ | ||
| 131 | static int caps_reserve_count; /* unused, reserved */ | ||
| 132 | static int caps_avail_count; /* unused, unreserved */ | ||
| 133 | static int caps_min_count; /* keep at least this many (unreserved) */ | ||
| 134 | |||
| 135 | void __init ceph_caps_init(void) | ||
| 136 | { | 117 | { |
| 137 | INIT_LIST_HEAD(&caps_list); | 118 | INIT_LIST_HEAD(&mdsc->caps_list); |
| 138 | spin_lock_init(&caps_list_lock); | 119 | spin_lock_init(&mdsc->caps_list_lock); |
| 139 | } | 120 | } |
| 140 | 121 | ||
| 141 | void ceph_caps_finalize(void) | 122 | void ceph_caps_finalize(struct ceph_mds_client *mdsc) |
| 142 | { | 123 | { |
| 143 | struct ceph_cap *cap; | 124 | struct ceph_cap *cap; |
| 144 | 125 | ||
| 145 | spin_lock(&caps_list_lock); | 126 | spin_lock(&mdsc->caps_list_lock); |
| 146 | while (!list_empty(&caps_list)) { | 127 | while (!list_empty(&mdsc->caps_list)) { |
| 147 | cap = list_first_entry(&caps_list, struct ceph_cap, caps_item); | 128 | cap = list_first_entry(&mdsc->caps_list, |
| 129 | struct ceph_cap, caps_item); | ||
| 148 | list_del(&cap->caps_item); | 130 | list_del(&cap->caps_item); |
| 149 | kmem_cache_free(ceph_cap_cachep, cap); | 131 | kmem_cache_free(ceph_cap_cachep, cap); |
| 150 | } | 132 | } |
| 151 | caps_total_count = 0; | 133 | mdsc->caps_total_count = 0; |
| 152 | caps_avail_count = 0; | 134 | mdsc->caps_avail_count = 0; |
| 153 | caps_use_count = 0; | 135 | mdsc->caps_use_count = 0; |
| 154 | caps_reserve_count = 0; | 136 | mdsc->caps_reserve_count = 0; |
| 155 | caps_min_count = 0; | 137 | mdsc->caps_min_count = 0; |
| 156 | spin_unlock(&caps_list_lock); | 138 | spin_unlock(&mdsc->caps_list_lock); |
| 157 | } | 139 | } |
| 158 | 140 | ||
| 159 | void ceph_adjust_min_caps(int delta) | 141 | void ceph_adjust_min_caps(struct ceph_mds_client *mdsc, int delta) |
| 160 | { | 142 | { |
| 161 | spin_lock(&caps_list_lock); | 143 | spin_lock(&mdsc->caps_list_lock); |
| 162 | caps_min_count += delta; | 144 | mdsc->caps_min_count += delta; |
| 163 | BUG_ON(caps_min_count < 0); | 145 | BUG_ON(mdsc->caps_min_count < 0); |
| 164 | spin_unlock(&caps_list_lock); | 146 | spin_unlock(&mdsc->caps_list_lock); |
| 165 | } | 147 | } |
| 166 | 148 | ||
| 167 | int ceph_reserve_caps(struct ceph_cap_reservation *ctx, int need) | 149 | int ceph_reserve_caps(struct ceph_mds_client *mdsc, |
| 150 | struct ceph_cap_reservation *ctx, int need) | ||
| 168 | { | 151 | { |
| 169 | int i; | 152 | int i; |
| 170 | struct ceph_cap *cap; | 153 | struct ceph_cap *cap; |
| @@ -176,16 +159,17 @@ int ceph_reserve_caps(struct ceph_cap_reservation *ctx, int need) | |||
| 176 | dout("reserve caps ctx=%p need=%d\n", ctx, need); | 159 | dout("reserve caps ctx=%p need=%d\n", ctx, need); |
| 177 | 160 | ||
| 178 | /* first reserve any caps that are already allocated */ | 161 | /* first reserve any caps that are already allocated */ |
| 179 | spin_lock(&caps_list_lock); | 162 | spin_lock(&mdsc->caps_list_lock); |
| 180 | if (caps_avail_count >= need) | 163 | if (mdsc->caps_avail_count >= need) |
| 181 | have = need; | 164 | have = need; |
| 182 | else | 165 | else |
| 183 | have = caps_avail_count; | 166 | have = mdsc->caps_avail_count; |
| 184 | caps_avail_count -= have; | 167 | mdsc->caps_avail_count -= have; |
| 185 | caps_reserve_count += have; | 168 | mdsc->caps_reserve_count += have; |
| 186 | BUG_ON(caps_total_count != caps_use_count + caps_reserve_count + | 169 | BUG_ON(mdsc->caps_total_count != mdsc->caps_use_count + |
| 187 | caps_avail_count); | 170 | mdsc->caps_reserve_count + |
| 188 | spin_unlock(&caps_list_lock); | 171 | mdsc->caps_avail_count); |
| 172 | spin_unlock(&mdsc->caps_list_lock); | ||
| 189 | 173 | ||
| 190 | for (i = have; i < need; i++) { | 174 | for (i = have; i < need; i++) { |
| 191 | cap = kmem_cache_alloc(ceph_cap_cachep, GFP_NOFS); | 175 | cap = kmem_cache_alloc(ceph_cap_cachep, GFP_NOFS); |
| @@ -198,19 +182,20 @@ int ceph_reserve_caps(struct ceph_cap_reservation *ctx, int need) | |||
| 198 | } | 182 | } |
| 199 | BUG_ON(have + alloc != need); | 183 | BUG_ON(have + alloc != need); |
| 200 | 184 | ||
| 201 | spin_lock(&caps_list_lock); | 185 | spin_lock(&mdsc->caps_list_lock); |
| 202 | caps_total_count += alloc; | 186 | mdsc->caps_total_count += alloc; |
| 203 | caps_reserve_count += alloc; | 187 | mdsc->caps_reserve_count += alloc; |
| 204 | list_splice(&newcaps, &caps_list); | 188 | list_splice(&newcaps, &mdsc->caps_list); |
| 205 | 189 | ||
| 206 | BUG_ON(caps_total_count != caps_use_count + caps_reserve_count + | 190 | BUG_ON(mdsc->caps_total_count != mdsc->caps_use_count + |
| 207 | caps_avail_count); | 191 | mdsc->caps_reserve_count + |
| 208 | spin_unlock(&caps_list_lock); | 192 | mdsc->caps_avail_count); |
| 193 | spin_unlock(&mdsc->caps_list_lock); | ||
| 209 | 194 | ||
| 210 | ctx->count = need; | 195 | ctx->count = need; |
| 211 | dout("reserve caps ctx=%p %d = %d used + %d resv + %d avail\n", | 196 | dout("reserve caps ctx=%p %d = %d used + %d resv + %d avail\n", |
| 212 | ctx, caps_total_count, caps_use_count, caps_reserve_count, | 197 | ctx, mdsc->caps_total_count, mdsc->caps_use_count, |
| 213 | caps_avail_count); | 198 | mdsc->caps_reserve_count, mdsc->caps_avail_count); |
| 214 | return 0; | 199 | return 0; |
| 215 | 200 | ||
| 216 | out_alloc_count: | 201 | out_alloc_count: |
| @@ -220,26 +205,29 @@ out_alloc_count: | |||
| 220 | return ret; | 205 | return ret; |
| 221 | } | 206 | } |
| 222 | 207 | ||
| 223 | int ceph_unreserve_caps(struct ceph_cap_reservation *ctx) | 208 | int ceph_unreserve_caps(struct ceph_mds_client *mdsc, |
| 209 | struct ceph_cap_reservation *ctx) | ||
| 224 | { | 210 | { |
| 225 | dout("unreserve caps ctx=%p count=%d\n", ctx, ctx->count); | 211 | dout("unreserve caps ctx=%p count=%d\n", ctx, ctx->count); |
| 226 | if (ctx->count) { | 212 | if (ctx->count) { |
| 227 | spin_lock(&caps_list_lock); | 213 | spin_lock(&mdsc->caps_list_lock); |
| 228 | BUG_ON(caps_reserve_count < ctx->count); | 214 | BUG_ON(mdsc->caps_reserve_count < ctx->count); |
| 229 | caps_reserve_count -= ctx->count; | 215 | mdsc->caps_reserve_count -= ctx->count; |
| 230 | caps_avail_count += ctx->count; | 216 | mdsc->caps_avail_count += ctx->count; |
| 231 | ctx->count = 0; | 217 | ctx->count = 0; |
| 232 | dout("unreserve caps %d = %d used + %d resv + %d avail\n", | 218 | dout("unreserve caps %d = %d used + %d resv + %d avail\n", |
| 233 | caps_total_count, caps_use_count, caps_reserve_count, | 219 | mdsc->caps_total_count, mdsc->caps_use_count, |
| 234 | caps_avail_count); | 220 | mdsc->caps_reserve_count, mdsc->caps_avail_count); |
| 235 | BUG_ON(caps_total_count != caps_use_count + caps_reserve_count + | 221 | BUG_ON(mdsc->caps_total_count != mdsc->caps_use_count + |
| 236 | caps_avail_count); | 222 | mdsc->caps_reserve_count + |
| 237 | spin_unlock(&caps_list_lock); | 223 | mdsc->caps_avail_count); |
| 224 | spin_unlock(&mdsc->caps_list_lock); | ||
| 238 | } | 225 | } |
| 239 | return 0; | 226 | return 0; |
| 240 | } | 227 | } |
| 241 | 228 | ||
| 242 | static struct ceph_cap *get_cap(struct ceph_cap_reservation *ctx) | 229 | static struct ceph_cap *get_cap(struct ceph_mds_client *mdsc, |
| 230 | struct ceph_cap_reservation *ctx) | ||
| 243 | { | 231 | { |
| 244 | struct ceph_cap *cap = NULL; | 232 | struct ceph_cap *cap = NULL; |
| 245 | 233 | ||
| @@ -247,71 +235,74 @@ static struct ceph_cap *get_cap(struct ceph_cap_reservation *ctx) | |||
| 247 | if (!ctx) { | 235 | if (!ctx) { |
| 248 | cap = kmem_cache_alloc(ceph_cap_cachep, GFP_NOFS); | 236 | cap = kmem_cache_alloc(ceph_cap_cachep, GFP_NOFS); |
| 249 | if (cap) { | 237 | if (cap) { |
| 250 | caps_use_count++; | 238 | mdsc->caps_use_count++; |
| 251 | caps_total_count++; | 239 | mdsc->caps_total_count++; |
| 252 | } | 240 | } |
| 253 | return cap; | 241 | return cap; |
| 254 | } | 242 | } |
| 255 | 243 | ||
| 256 | spin_lock(&caps_list_lock); | 244 | spin_lock(&mdsc->caps_list_lock); |
| 257 | dout("get_cap ctx=%p (%d) %d = %d used + %d resv + %d avail\n", | 245 | dout("get_cap ctx=%p (%d) %d = %d used + %d resv + %d avail\n", |
| 258 | ctx, ctx->count, caps_total_count, caps_use_count, | 246 | ctx, ctx->count, mdsc->caps_total_count, mdsc->caps_use_count, |
| 259 | caps_reserve_count, caps_avail_count); | 247 | mdsc->caps_reserve_count, mdsc->caps_avail_count); |
| 260 | BUG_ON(!ctx->count); | 248 | BUG_ON(!ctx->count); |
| 261 | BUG_ON(ctx->count > caps_reserve_count); | 249 | BUG_ON(ctx->count > mdsc->caps_reserve_count); |
| 262 | BUG_ON(list_empty(&caps_list)); | 250 | BUG_ON(list_empty(&mdsc->caps_list)); |
| 263 | 251 | ||
| 264 | ctx->count--; | 252 | ctx->count--; |
| 265 | caps_reserve_count--; | 253 | mdsc->caps_reserve_count--; |
| 266 | caps_use_count++; | 254 | mdsc->caps_use_count++; |
| 267 | 255 | ||
| 268 | cap = list_first_entry(&caps_list, struct ceph_cap, caps_item); | 256 | cap = list_first_entry(&mdsc->caps_list, struct ceph_cap, caps_item); |
| 269 | list_del(&cap->caps_item); | 257 | list_del(&cap->caps_item); |
| 270 | 258 | ||
| 271 | BUG_ON(caps_total_count != caps_use_count + caps_reserve_count + | 259 | BUG_ON(mdsc->caps_total_count != mdsc->caps_use_count + |
| 272 | caps_avail_count); | 260 | mdsc->caps_reserve_count + mdsc->caps_avail_count); |
| 273 | spin_unlock(&caps_list_lock); | 261 | spin_unlock(&mdsc->caps_list_lock); |
| 274 | return cap; | 262 | return cap; |
| 275 | } | 263 | } |
| 276 | 264 | ||
| 277 | void ceph_put_cap(struct ceph_cap *cap) | 265 | void ceph_put_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap) |
| 278 | { | 266 | { |
| 279 | spin_lock(&caps_list_lock); | 267 | spin_lock(&mdsc->caps_list_lock); |
| 280 | dout("put_cap %p %d = %d used + %d resv + %d avail\n", | 268 | dout("put_cap %p %d = %d used + %d resv + %d avail\n", |
| 281 | cap, caps_total_count, caps_use_count, | 269 | cap, mdsc->caps_total_count, mdsc->caps_use_count, |
| 282 | caps_reserve_count, caps_avail_count); | 270 | mdsc->caps_reserve_count, mdsc->caps_avail_count); |
| 283 | caps_use_count--; | 271 | mdsc->caps_use_count--; |
| 284 | /* | 272 | /* |
| 285 | * Keep some preallocated caps around (ceph_min_count), to | 273 | * Keep some preallocated caps around (ceph_min_count), to |
| 286 | * avoid lots of free/alloc churn. | 274 | * avoid lots of free/alloc churn. |
| 287 | */ | 275 | */ |
| 288 | if (caps_avail_count >= caps_reserve_count + caps_min_count) { | 276 | if (mdsc->caps_avail_count >= mdsc->caps_reserve_count + |
| 289 | caps_total_count--; | 277 | mdsc->caps_min_count) { |
| 278 | mdsc->caps_total_count--; | ||
| 290 | kmem_cache_free(ceph_cap_cachep, cap); | 279 | kmem_cache_free(ceph_cap_cachep, cap); |
| 291 | } else { | 280 | } else { |
| 292 | caps_avail_count++; | 281 | mdsc->caps_avail_count++; |
| 293 | list_add(&cap->caps_item, &caps_list); | 282 | list_add(&cap->caps_item, &mdsc->caps_list); |
| 294 | } | 283 | } |
| 295 | 284 | ||
| 296 | BUG_ON(caps_total_count != caps_use_count + caps_reserve_count + | 285 | BUG_ON(mdsc->caps_total_count != mdsc->caps_use_count + |
| 297 | caps_avail_count); | 286 | mdsc->caps_reserve_count + mdsc->caps_avail_count); |
| 298 | spin_unlock(&caps_list_lock); | 287 | spin_unlock(&mdsc->caps_list_lock); |
| 299 | } | 288 | } |
| 300 | 289 | ||
| 301 | void ceph_reservation_status(struct ceph_client *client, | 290 | void ceph_reservation_status(struct ceph_client *client, |
| 302 | int *total, int *avail, int *used, int *reserved, | 291 | int *total, int *avail, int *used, int *reserved, |
| 303 | int *min) | 292 | int *min) |
| 304 | { | 293 | { |
| 294 | struct ceph_mds_client *mdsc = &client->mdsc; | ||
| 295 | |||
| 305 | if (total) | 296 | if (total) |
| 306 | *total = caps_total_count; | 297 | *total = mdsc->caps_total_count; |
| 307 | if (avail) | 298 | if (avail) |
| 308 | *avail = caps_avail_count; | 299 | *avail = mdsc->caps_avail_count; |
| 309 | if (used) | 300 | if (used) |
| 310 | *used = caps_use_count; | 301 | *used = mdsc->caps_use_count; |
| 311 | if (reserved) | 302 | if (reserved) |
| 312 | *reserved = caps_reserve_count; | 303 | *reserved = mdsc->caps_reserve_count; |
| 313 | if (min) | 304 | if (min) |
| 314 | *min = caps_min_count; | 305 | *min = mdsc->caps_min_count; |
| 315 | } | 306 | } |
| 316 | 307 | ||
| 317 | /* | 308 | /* |
| @@ -336,22 +327,29 @@ static struct ceph_cap *__get_cap_for_mds(struct ceph_inode_info *ci, int mds) | |||
| 336 | return NULL; | 327 | return NULL; |
| 337 | } | 328 | } |
| 338 | 329 | ||
| 330 | struct ceph_cap *ceph_get_cap_for_mds(struct ceph_inode_info *ci, int mds) | ||
| 331 | { | ||
| 332 | struct ceph_cap *cap; | ||
| 333 | |||
| 334 | spin_lock(&ci->vfs_inode.i_lock); | ||
| 335 | cap = __get_cap_for_mds(ci, mds); | ||
| 336 | spin_unlock(&ci->vfs_inode.i_lock); | ||
| 337 | return cap; | ||
| 338 | } | ||
| 339 | |||
| 339 | /* | 340 | /* |
| 340 | * Return id of any MDS with a cap, preferably FILE_WR|WRBUFFER|EXCL, else | 341 | * Return id of any MDS with a cap, preferably FILE_WR|BUFFER|EXCL, else -1. |
| 341 | * -1. | ||
| 342 | */ | 342 | */ |
| 343 | static int __ceph_get_cap_mds(struct ceph_inode_info *ci, u32 *mseq) | 343 | static int __ceph_get_cap_mds(struct ceph_inode_info *ci) |
| 344 | { | 344 | { |
| 345 | struct ceph_cap *cap; | 345 | struct ceph_cap *cap; |
| 346 | int mds = -1; | 346 | int mds = -1; |
| 347 | struct rb_node *p; | 347 | struct rb_node *p; |
| 348 | 348 | ||
| 349 | /* prefer mds with WR|WRBUFFER|EXCL caps */ | 349 | /* prefer mds with WR|BUFFER|EXCL caps */ |
| 350 | for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) { | 350 | for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) { |
| 351 | cap = rb_entry(p, struct ceph_cap, ci_node); | 351 | cap = rb_entry(p, struct ceph_cap, ci_node); |
| 352 | mds = cap->mds; | 352 | mds = cap->mds; |
| 353 | if (mseq) | ||
| 354 | *mseq = cap->mseq; | ||
| 355 | if (cap->issued & (CEPH_CAP_FILE_WR | | 353 | if (cap->issued & (CEPH_CAP_FILE_WR | |
| 356 | CEPH_CAP_FILE_BUFFER | | 354 | CEPH_CAP_FILE_BUFFER | |
| 357 | CEPH_CAP_FILE_EXCL)) | 355 | CEPH_CAP_FILE_EXCL)) |
| @@ -364,7 +362,7 @@ int ceph_get_cap_mds(struct inode *inode) | |||
| 364 | { | 362 | { |
| 365 | int mds; | 363 | int mds; |
| 366 | spin_lock(&inode->i_lock); | 364 | spin_lock(&inode->i_lock); |
| 367 | mds = __ceph_get_cap_mds(ceph_inode(inode), NULL); | 365 | mds = __ceph_get_cap_mds(ceph_inode(inode)); |
| 368 | spin_unlock(&inode->i_lock); | 366 | spin_unlock(&inode->i_lock); |
| 369 | return mds; | 367 | return mds; |
| 370 | } | 368 | } |
| @@ -483,8 +481,8 @@ static void __check_cap_issue(struct ceph_inode_info *ci, struct ceph_cap *cap, | |||
| 483 | * Each time we receive FILE_CACHE anew, we increment | 481 | * Each time we receive FILE_CACHE anew, we increment |
| 484 | * i_rdcache_gen. | 482 | * i_rdcache_gen. |
| 485 | */ | 483 | */ |
| 486 | if ((issued & CEPH_CAP_FILE_CACHE) && | 484 | if ((issued & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) && |
| 487 | (had & CEPH_CAP_FILE_CACHE) == 0) | 485 | (had & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) == 0) |
| 488 | ci->i_rdcache_gen++; | 486 | ci->i_rdcache_gen++; |
| 489 | 487 | ||
| 490 | /* | 488 | /* |
| @@ -543,7 +541,7 @@ retry: | |||
| 543 | new_cap = NULL; | 541 | new_cap = NULL; |
| 544 | } else { | 542 | } else { |
| 545 | spin_unlock(&inode->i_lock); | 543 | spin_unlock(&inode->i_lock); |
| 546 | new_cap = get_cap(caps_reservation); | 544 | new_cap = get_cap(mdsc, caps_reservation); |
| 547 | if (new_cap == NULL) | 545 | if (new_cap == NULL) |
| 548 | return -ENOMEM; | 546 | return -ENOMEM; |
| 549 | goto retry; | 547 | goto retry; |
| @@ -588,6 +586,7 @@ retry: | |||
| 588 | } else { | 586 | } else { |
| 589 | pr_err("ceph_add_cap: couldn't find snap realm %llx\n", | 587 | pr_err("ceph_add_cap: couldn't find snap realm %llx\n", |
| 590 | realmino); | 588 | realmino); |
| 589 | WARN_ON(!realm); | ||
| 591 | } | 590 | } |
| 592 | } | 591 | } |
| 593 | 592 | ||
| @@ -831,7 +830,7 @@ int __ceph_caps_file_wanted(struct ceph_inode_info *ci) | |||
| 831 | { | 830 | { |
| 832 | int want = 0; | 831 | int want = 0; |
| 833 | int mode; | 832 | int mode; |
| 834 | for (mode = 0; mode < 4; mode++) | 833 | for (mode = 0; mode < CEPH_FILE_MODE_NUM; mode++) |
| 835 | if (ci->i_nr_by_mode[mode]) | 834 | if (ci->i_nr_by_mode[mode]) |
| 836 | want |= ceph_caps_for_mode(mode); | 835 | want |= ceph_caps_for_mode(mode); |
| 837 | return want; | 836 | return want; |
| @@ -901,7 +900,7 @@ void __ceph_remove_cap(struct ceph_cap *cap) | |||
| 901 | ci->i_auth_cap = NULL; | 900 | ci->i_auth_cap = NULL; |
| 902 | 901 | ||
| 903 | if (removed) | 902 | if (removed) |
| 904 | ceph_put_cap(cap); | 903 | ceph_put_cap(mdsc, cap); |
| 905 | 904 | ||
| 906 | if (!__ceph_is_any_caps(ci) && ci->i_snap_realm) { | 905 | if (!__ceph_is_any_caps(ci) && ci->i_snap_realm) { |
| 907 | struct ceph_snap_realm *realm = ci->i_snap_realm; | 906 | struct ceph_snap_realm *realm = ci->i_snap_realm; |
| @@ -1197,6 +1196,8 @@ static int __send_cap(struct ceph_mds_client *mdsc, struct ceph_cap *cap, | |||
| 1197 | */ | 1196 | */ |
| 1198 | void __ceph_flush_snaps(struct ceph_inode_info *ci, | 1197 | void __ceph_flush_snaps(struct ceph_inode_info *ci, |
| 1199 | struct ceph_mds_session **psession) | 1198 | struct ceph_mds_session **psession) |
| 1199 | __releases(ci->vfs_inode->i_lock) | ||
| 1200 | __acquires(ci->vfs_inode->i_lock) | ||
| 1200 | { | 1201 | { |
| 1201 | struct inode *inode = &ci->vfs_inode; | 1202 | struct inode *inode = &ci->vfs_inode; |
| 1202 | int mds; | 1203 | int mds; |
| @@ -1232,7 +1233,13 @@ retry: | |||
| 1232 | BUG_ON(capsnap->dirty == 0); | 1233 | BUG_ON(capsnap->dirty == 0); |
| 1233 | 1234 | ||
| 1234 | /* pick mds, take s_mutex */ | 1235 | /* pick mds, take s_mutex */ |
| 1235 | mds = __ceph_get_cap_mds(ci, &mseq); | 1236 | if (ci->i_auth_cap == NULL) { |
| 1237 | dout("no auth cap (migrating?), doing nothing\n"); | ||
| 1238 | goto out; | ||
| 1239 | } | ||
| 1240 | mds = ci->i_auth_cap->session->s_mds; | ||
| 1241 | mseq = ci->i_auth_cap->mseq; | ||
| 1242 | |||
| 1236 | if (session && session->s_mds != mds) { | 1243 | if (session && session->s_mds != mds) { |
| 1237 | dout("oops, wrong session %p mutex\n", session); | 1244 | dout("oops, wrong session %p mutex\n", session); |
| 1238 | mutex_unlock(&session->s_mutex); | 1245 | mutex_unlock(&session->s_mutex); |
| @@ -1251,8 +1258,8 @@ retry: | |||
| 1251 | } | 1258 | } |
| 1252 | /* | 1259 | /* |
| 1253 | * if session == NULL, we raced against a cap | 1260 | * if session == NULL, we raced against a cap |
| 1254 | * deletion. retry, and we'll get a better | 1261 | * deletion or migration. retry, and we'll |
| 1255 | * @mds value next time. | 1262 | * get a better @mds value next time. |
| 1256 | */ | 1263 | */ |
| 1257 | spin_lock(&inode->i_lock); | 1264 | spin_lock(&inode->i_lock); |
| 1258 | goto retry; | 1265 | goto retry; |
| @@ -1290,6 +1297,7 @@ retry: | |||
| 1290 | list_del_init(&ci->i_snap_flush_item); | 1297 | list_del_init(&ci->i_snap_flush_item); |
| 1291 | spin_unlock(&mdsc->snap_flush_lock); | 1298 | spin_unlock(&mdsc->snap_flush_lock); |
| 1292 | 1299 | ||
| 1300 | out: | ||
| 1293 | if (psession) | 1301 | if (psession) |
| 1294 | *psession = session; | 1302 | *psession = session; |
| 1295 | else if (session) { | 1303 | else if (session) { |
| @@ -1435,7 +1443,6 @@ static int try_nonblocking_invalidate(struct inode *inode) | |||
| 1435 | */ | 1443 | */ |
| 1436 | void ceph_check_caps(struct ceph_inode_info *ci, int flags, | 1444 | void ceph_check_caps(struct ceph_inode_info *ci, int flags, |
| 1437 | struct ceph_mds_session *session) | 1445 | struct ceph_mds_session *session) |
| 1438 | __releases(session->s_mutex) | ||
| 1439 | { | 1446 | { |
| 1440 | struct ceph_client *client = ceph_inode_to_client(&ci->vfs_inode); | 1447 | struct ceph_client *client = ceph_inode_to_client(&ci->vfs_inode); |
| 1441 | struct ceph_mds_client *mdsc = &client->mdsc; | 1448 | struct ceph_mds_client *mdsc = &client->mdsc; |
| @@ -1510,11 +1517,13 @@ retry_locked: | |||
| 1510 | ci->i_wrbuffer_ref == 0 && /* no dirty pages... */ | 1517 | ci->i_wrbuffer_ref == 0 && /* no dirty pages... */ |
| 1511 | ci->i_rdcache_gen && /* may have cached pages */ | 1518 | ci->i_rdcache_gen && /* may have cached pages */ |
| 1512 | (file_wanted == 0 || /* no open files */ | 1519 | (file_wanted == 0 || /* no open files */ |
| 1513 | (revoking & CEPH_CAP_FILE_CACHE)) && /* or revoking cache */ | 1520 | (revoking & (CEPH_CAP_FILE_CACHE| |
| 1521 | CEPH_CAP_FILE_LAZYIO))) && /* or revoking cache */ | ||
| 1514 | !tried_invalidate) { | 1522 | !tried_invalidate) { |
| 1515 | dout("check_caps trying to invalidate on %p\n", inode); | 1523 | dout("check_caps trying to invalidate on %p\n", inode); |
| 1516 | if (try_nonblocking_invalidate(inode) < 0) { | 1524 | if (try_nonblocking_invalidate(inode) < 0) { |
| 1517 | if (revoking & CEPH_CAP_FILE_CACHE) { | 1525 | if (revoking & (CEPH_CAP_FILE_CACHE| |
| 1526 | CEPH_CAP_FILE_LAZYIO)) { | ||
| 1518 | dout("check_caps queuing invalidate\n"); | 1527 | dout("check_caps queuing invalidate\n"); |
| 1519 | queue_invalidate = 1; | 1528 | queue_invalidate = 1; |
| 1520 | ci->i_rdcache_revoking = ci->i_rdcache_gen; | 1529 | ci->i_rdcache_revoking = ci->i_rdcache_gen; |
| @@ -2250,8 +2259,7 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, | |||
| 2250 | struct ceph_mds_session *session, | 2259 | struct ceph_mds_session *session, |
| 2251 | struct ceph_cap *cap, | 2260 | struct ceph_cap *cap, |
| 2252 | struct ceph_buffer *xattr_buf) | 2261 | struct ceph_buffer *xattr_buf) |
| 2253 | __releases(inode->i_lock) | 2262 | __releases(inode->i_lock) |
| 2254 | __releases(session->s_mutex) | ||
| 2255 | { | 2263 | { |
| 2256 | struct ceph_inode_info *ci = ceph_inode(inode); | 2264 | struct ceph_inode_info *ci = ceph_inode(inode); |
| 2257 | int mds = session->s_mds; | 2265 | int mds = session->s_mds; |
| @@ -2278,6 +2286,7 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, | |||
| 2278 | * will invalidate _after_ writeback.) | 2286 | * will invalidate _after_ writeback.) |
| 2279 | */ | 2287 | */ |
| 2280 | if (((cap->issued & ~newcaps) & CEPH_CAP_FILE_CACHE) && | 2288 | if (((cap->issued & ~newcaps) & CEPH_CAP_FILE_CACHE) && |
| 2289 | (newcaps & CEPH_CAP_FILE_LAZYIO) == 0 && | ||
| 2281 | !ci->i_wrbuffer_ref) { | 2290 | !ci->i_wrbuffer_ref) { |
| 2282 | if (try_nonblocking_invalidate(inode) == 0) { | 2291 | if (try_nonblocking_invalidate(inode) == 0) { |
| 2283 | revoked_rdcache = 1; | 2292 | revoked_rdcache = 1; |
| @@ -2369,15 +2378,22 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, | |||
| 2369 | 2378 | ||
| 2370 | /* revocation, grant, or no-op? */ | 2379 | /* revocation, grant, or no-op? */ |
| 2371 | if (cap->issued & ~newcaps) { | 2380 | if (cap->issued & ~newcaps) { |
| 2372 | dout("revocation: %s -> %s\n", ceph_cap_string(cap->issued), | 2381 | int revoking = cap->issued & ~newcaps; |
| 2373 | ceph_cap_string(newcaps)); | 2382 | |
| 2374 | if ((used & ~newcaps) & CEPH_CAP_FILE_BUFFER) | 2383 | dout("revocation: %s -> %s (revoking %s)\n", |
| 2375 | writeback = 1; /* will delay ack */ | 2384 | ceph_cap_string(cap->issued), |
| 2376 | else if (dirty & ~newcaps) | 2385 | ceph_cap_string(newcaps), |
| 2377 | check_caps = 1; /* initiate writeback in check_caps */ | 2386 | ceph_cap_string(revoking)); |
| 2378 | else if (((used & ~newcaps) & CEPH_CAP_FILE_CACHE) == 0 || | 2387 | if (revoking & used & CEPH_CAP_FILE_BUFFER) |
| 2379 | revoked_rdcache) | 2388 | writeback = 1; /* initiate writeback; will delay ack */ |
| 2380 | check_caps = 2; /* send revoke ack in check_caps */ | 2389 | else if (revoking == CEPH_CAP_FILE_CACHE && |
| 2390 | (newcaps & CEPH_CAP_FILE_LAZYIO) == 0 && | ||
| 2391 | queue_invalidate) | ||
| 2392 | ; /* do nothing yet, invalidation will be queued */ | ||
| 2393 | else if (cap == ci->i_auth_cap) | ||
| 2394 | check_caps = 1; /* check auth cap only */ | ||
| 2395 | else | ||
| 2396 | check_caps = 2; /* check all caps */ | ||
| 2381 | cap->issued = newcaps; | 2397 | cap->issued = newcaps; |
| 2382 | cap->implemented |= newcaps; | 2398 | cap->implemented |= newcaps; |
| 2383 | } else if (cap->issued == newcaps) { | 2399 | } else if (cap->issued == newcaps) { |
| @@ -2568,7 +2584,8 @@ static void handle_cap_trunc(struct inode *inode, | |||
| 2568 | * caller holds s_mutex | 2584 | * caller holds s_mutex |
| 2569 | */ | 2585 | */ |
| 2570 | static void handle_cap_export(struct inode *inode, struct ceph_mds_caps *ex, | 2586 | static void handle_cap_export(struct inode *inode, struct ceph_mds_caps *ex, |
| 2571 | struct ceph_mds_session *session) | 2587 | struct ceph_mds_session *session, |
| 2588 | int *open_target_sessions) | ||
| 2572 | { | 2589 | { |
| 2573 | struct ceph_inode_info *ci = ceph_inode(inode); | 2590 | struct ceph_inode_info *ci = ceph_inode(inode); |
| 2574 | int mds = session->s_mds; | 2591 | int mds = session->s_mds; |
| @@ -2600,6 +2617,12 @@ static void handle_cap_export(struct inode *inode, struct ceph_mds_caps *ex, | |||
| 2600 | ci->i_cap_exporting_mds = mds; | 2617 | ci->i_cap_exporting_mds = mds; |
| 2601 | ci->i_cap_exporting_mseq = mseq; | 2618 | ci->i_cap_exporting_mseq = mseq; |
| 2602 | ci->i_cap_exporting_issued = cap->issued; | 2619 | ci->i_cap_exporting_issued = cap->issued; |
| 2620 | |||
| 2621 | /* | ||
| 2622 | * make sure we have open sessions with all possible | ||
| 2623 | * export targets, so that we get the matching IMPORT | ||
| 2624 | */ | ||
| 2625 | *open_target_sessions = 1; | ||
| 2603 | } | 2626 | } |
| 2604 | __ceph_remove_cap(cap); | 2627 | __ceph_remove_cap(cap); |
| 2605 | } | 2628 | } |
| @@ -2675,6 +2698,10 @@ void ceph_handle_caps(struct ceph_mds_session *session, | |||
| 2675 | u64 size, max_size; | 2698 | u64 size, max_size; |
| 2676 | u64 tid; | 2699 | u64 tid; |
| 2677 | void *snaptrace; | 2700 | void *snaptrace; |
| 2701 | size_t snaptrace_len; | ||
| 2702 | void *flock; | ||
| 2703 | u32 flock_len; | ||
| 2704 | int open_target_sessions = 0; | ||
| 2678 | 2705 | ||
| 2679 | dout("handle_caps from mds%d\n", mds); | 2706 | dout("handle_caps from mds%d\n", mds); |
| 2680 | 2707 | ||
| @@ -2683,7 +2710,6 @@ void ceph_handle_caps(struct ceph_mds_session *session, | |||
| 2683 | if (msg->front.iov_len < sizeof(*h)) | 2710 | if (msg->front.iov_len < sizeof(*h)) |
| 2684 | goto bad; | 2711 | goto bad; |
| 2685 | h = msg->front.iov_base; | 2712 | h = msg->front.iov_base; |
| 2686 | snaptrace = h + 1; | ||
| 2687 | op = le32_to_cpu(h->op); | 2713 | op = le32_to_cpu(h->op); |
| 2688 | vino.ino = le64_to_cpu(h->ino); | 2714 | vino.ino = le64_to_cpu(h->ino); |
| 2689 | vino.snap = CEPH_NOSNAP; | 2715 | vino.snap = CEPH_NOSNAP; |
| @@ -2693,6 +2719,21 @@ void ceph_handle_caps(struct ceph_mds_session *session, | |||
| 2693 | size = le64_to_cpu(h->size); | 2719 | size = le64_to_cpu(h->size); |
| 2694 | max_size = le64_to_cpu(h->max_size); | 2720 | max_size = le64_to_cpu(h->max_size); |
| 2695 | 2721 | ||
| 2722 | snaptrace = h + 1; | ||
| 2723 | snaptrace_len = le32_to_cpu(h->snap_trace_len); | ||
| 2724 | |||
| 2725 | if (le16_to_cpu(msg->hdr.version) >= 2) { | ||
| 2726 | void *p, *end; | ||
| 2727 | |||
| 2728 | p = snaptrace + snaptrace_len; | ||
| 2729 | end = msg->front.iov_base + msg->front.iov_len; | ||
| 2730 | ceph_decode_32_safe(&p, end, flock_len, bad); | ||
| 2731 | flock = p; | ||
| 2732 | } else { | ||
| 2733 | flock = NULL; | ||
| 2734 | flock_len = 0; | ||
| 2735 | } | ||
| 2736 | |||
| 2696 | mutex_lock(&session->s_mutex); | 2737 | mutex_lock(&session->s_mutex); |
| 2697 | session->s_seq++; | 2738 | session->s_seq++; |
| 2698 | dout(" mds%d seq %lld cap seq %u\n", session->s_mds, session->s_seq, | 2739 | dout(" mds%d seq %lld cap seq %u\n", session->s_mds, session->s_seq, |
| @@ -2714,7 +2755,7 @@ void ceph_handle_caps(struct ceph_mds_session *session, | |||
| 2714 | * along for the mds (who clearly thinks we still have this | 2755 | * along for the mds (who clearly thinks we still have this |
| 2715 | * cap). | 2756 | * cap). |
| 2716 | */ | 2757 | */ |
| 2717 | ceph_add_cap_releases(mdsc, session, -1); | 2758 | ceph_add_cap_releases(mdsc, session); |
| 2718 | ceph_send_cap_releases(mdsc, session); | 2759 | ceph_send_cap_releases(mdsc, session); |
| 2719 | goto done; | 2760 | goto done; |
| 2720 | } | 2761 | } |
| @@ -2726,12 +2767,12 @@ void ceph_handle_caps(struct ceph_mds_session *session, | |||
| 2726 | goto done; | 2767 | goto done; |
| 2727 | 2768 | ||
| 2728 | case CEPH_CAP_OP_EXPORT: | 2769 | case CEPH_CAP_OP_EXPORT: |
| 2729 | handle_cap_export(inode, h, session); | 2770 | handle_cap_export(inode, h, session, &open_target_sessions); |
| 2730 | goto done; | 2771 | goto done; |
| 2731 | 2772 | ||
| 2732 | case CEPH_CAP_OP_IMPORT: | 2773 | case CEPH_CAP_OP_IMPORT: |
| 2733 | handle_cap_import(mdsc, inode, h, session, | 2774 | handle_cap_import(mdsc, inode, h, session, |
| 2734 | snaptrace, le32_to_cpu(h->snap_trace_len)); | 2775 | snaptrace, snaptrace_len); |
| 2735 | ceph_check_caps(ceph_inode(inode), CHECK_CAPS_NODELAY, | 2776 | ceph_check_caps(ceph_inode(inode), CHECK_CAPS_NODELAY, |
| 2736 | session); | 2777 | session); |
| 2737 | goto done_unlocked; | 2778 | goto done_unlocked; |
| @@ -2773,6 +2814,8 @@ done: | |||
| 2773 | done_unlocked: | 2814 | done_unlocked: |
| 2774 | if (inode) | 2815 | if (inode) |
| 2775 | iput(inode); | 2816 | iput(inode); |
| 2817 | if (open_target_sessions) | ||
| 2818 | ceph_mdsc_open_export_target_sessions(mdsc, session); | ||
| 2776 | return; | 2819 | return; |
| 2777 | 2820 | ||
| 2778 | bad: | 2821 | bad: |
diff --git a/fs/ceph/ceph_frag.h b/fs/ceph/ceph_frag.h index 793f50cb7c22..5babb8e95352 100644 --- a/fs/ceph/ceph_frag.h +++ b/fs/ceph/ceph_frag.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #ifndef _FS_CEPH_FRAG_H | 1 | #ifndef FS_CEPH_FRAG_H |
| 2 | #define _FS_CEPH_FRAG_H | 2 | #define FS_CEPH_FRAG_H |
| 3 | 3 | ||
| 4 | /* | 4 | /* |
| 5 | * "Frags" are a way to describe a subset of a 32-bit number space, | 5 | * "Frags" are a way to describe a subset of a 32-bit number space, |
diff --git a/fs/ceph/ceph_fs.c b/fs/ceph/ceph_fs.c index 79d76bc4303f..3ac6cc7c1156 100644 --- a/fs/ceph/ceph_fs.c +++ b/fs/ceph/ceph_fs.c | |||
| @@ -29,46 +29,44 @@ int ceph_file_layout_is_valid(const struct ceph_file_layout *layout) | |||
| 29 | 29 | ||
| 30 | int ceph_flags_to_mode(int flags) | 30 | int ceph_flags_to_mode(int flags) |
| 31 | { | 31 | { |
| 32 | int mode; | ||
| 33 | |||
| 32 | #ifdef O_DIRECTORY /* fixme */ | 34 | #ifdef O_DIRECTORY /* fixme */ |
| 33 | if ((flags & O_DIRECTORY) == O_DIRECTORY) | 35 | if ((flags & O_DIRECTORY) == O_DIRECTORY) |
| 34 | return CEPH_FILE_MODE_PIN; | 36 | return CEPH_FILE_MODE_PIN; |
| 35 | #endif | 37 | #endif |
| 38 | if ((flags & O_APPEND) == O_APPEND) | ||
| 39 | flags |= O_WRONLY; | ||
| 40 | |||
| 41 | if ((flags & O_ACCMODE) == O_RDWR) | ||
| 42 | mode = CEPH_FILE_MODE_RDWR; | ||
| 43 | else if ((flags & O_ACCMODE) == O_WRONLY) | ||
| 44 | mode = CEPH_FILE_MODE_WR; | ||
| 45 | else | ||
| 46 | mode = CEPH_FILE_MODE_RD; | ||
| 47 | |||
| 36 | #ifdef O_LAZY | 48 | #ifdef O_LAZY |
| 37 | if (flags & O_LAZY) | 49 | if (flags & O_LAZY) |
| 38 | return CEPH_FILE_MODE_LAZY; | 50 | mode |= CEPH_FILE_MODE_LAZY; |
| 39 | #endif | 51 | #endif |
| 40 | if ((flags & O_APPEND) == O_APPEND) | ||
| 41 | flags |= O_WRONLY; | ||
| 42 | 52 | ||
| 43 | flags &= O_ACCMODE; | 53 | return mode; |
| 44 | if ((flags & O_RDWR) == O_RDWR) | ||
| 45 | return CEPH_FILE_MODE_RDWR; | ||
| 46 | if ((flags & O_WRONLY) == O_WRONLY) | ||
| 47 | return CEPH_FILE_MODE_WR; | ||
| 48 | return CEPH_FILE_MODE_RD; | ||
| 49 | } | 54 | } |
| 50 | 55 | ||
| 51 | int ceph_caps_for_mode(int mode) | 56 | int ceph_caps_for_mode(int mode) |
| 52 | { | 57 | { |
| 53 | switch (mode) { | 58 | int caps = CEPH_CAP_PIN; |
| 54 | case CEPH_FILE_MODE_PIN: | 59 | |
| 55 | return CEPH_CAP_PIN; | 60 | if (mode & CEPH_FILE_MODE_RD) |
| 56 | case CEPH_FILE_MODE_RD: | 61 | caps |= CEPH_CAP_FILE_SHARED | |
| 57 | return CEPH_CAP_PIN | CEPH_CAP_FILE_SHARED | | ||
| 58 | CEPH_CAP_FILE_RD | CEPH_CAP_FILE_CACHE; | 62 | CEPH_CAP_FILE_RD | CEPH_CAP_FILE_CACHE; |
| 59 | case CEPH_FILE_MODE_RDWR: | 63 | if (mode & CEPH_FILE_MODE_WR) |
| 60 | return CEPH_CAP_PIN | CEPH_CAP_FILE_SHARED | | 64 | caps |= CEPH_CAP_FILE_EXCL | |
| 61 | CEPH_CAP_FILE_EXCL | | ||
| 62 | CEPH_CAP_FILE_RD | CEPH_CAP_FILE_CACHE | | ||
| 63 | CEPH_CAP_FILE_WR | CEPH_CAP_FILE_BUFFER | | ||
| 64 | CEPH_CAP_AUTH_SHARED | CEPH_CAP_AUTH_EXCL | | ||
| 65 | CEPH_CAP_XATTR_SHARED | CEPH_CAP_XATTR_EXCL; | ||
| 66 | case CEPH_FILE_MODE_WR: | ||
| 67 | return CEPH_CAP_PIN | CEPH_CAP_FILE_SHARED | | ||
| 68 | CEPH_CAP_FILE_EXCL | | ||
| 69 | CEPH_CAP_FILE_WR | CEPH_CAP_FILE_BUFFER | | 65 | CEPH_CAP_FILE_WR | CEPH_CAP_FILE_BUFFER | |
| 70 | CEPH_CAP_AUTH_SHARED | CEPH_CAP_AUTH_EXCL | | 66 | CEPH_CAP_AUTH_SHARED | CEPH_CAP_AUTH_EXCL | |
| 71 | CEPH_CAP_XATTR_SHARED | CEPH_CAP_XATTR_EXCL; | 67 | CEPH_CAP_XATTR_SHARED | CEPH_CAP_XATTR_EXCL; |
| 72 | } | 68 | if (mode & CEPH_FILE_MODE_LAZY) |
| 73 | return 0; | 69 | caps |= CEPH_CAP_FILE_LAZYIO; |
| 70 | |||
| 71 | return caps; | ||
| 74 | } | 72 | } |
diff --git a/fs/ceph/ceph_fs.h b/fs/ceph/ceph_fs.h index 2fa992eaf7da..d5619ac86711 100644 --- a/fs/ceph/ceph_fs.h +++ b/fs/ceph/ceph_fs.h | |||
| @@ -9,27 +9,13 @@ | |||
| 9 | * LGPL2 | 9 | * LGPL2 |
| 10 | */ | 10 | */ |
| 11 | 11 | ||
| 12 | #ifndef _FS_CEPH_CEPH_FS_H | 12 | #ifndef CEPH_FS_H |
| 13 | #define _FS_CEPH_CEPH_FS_H | 13 | #define CEPH_FS_H |
| 14 | 14 | ||
| 15 | #include "msgr.h" | 15 | #include "msgr.h" |
| 16 | #include "rados.h" | 16 | #include "rados.h" |
| 17 | 17 | ||
| 18 | /* | 18 | /* |
| 19 | * Ceph release version | ||
| 20 | */ | ||
| 21 | #define CEPH_VERSION_MAJOR 0 | ||
| 22 | #define CEPH_VERSION_MINOR 20 | ||
| 23 | #define CEPH_VERSION_PATCH 0 | ||
| 24 | |||
| 25 | #define _CEPH_STRINGIFY(x) #x | ||
| 26 | #define CEPH_STRINGIFY(x) _CEPH_STRINGIFY(x) | ||
| 27 | #define CEPH_MAKE_VERSION(x, y, z) CEPH_STRINGIFY(x) "." CEPH_STRINGIFY(y) \ | ||
| 28 | "." CEPH_STRINGIFY(z) | ||
| 29 | #define CEPH_VERSION CEPH_MAKE_VERSION(CEPH_VERSION_MAJOR, \ | ||
| 30 | CEPH_VERSION_MINOR, CEPH_VERSION_PATCH) | ||
| 31 | |||
| 32 | /* | ||
| 33 | * subprotocol versions. when specific messages types or high-level | 19 | * subprotocol versions. when specific messages types or high-level |
| 34 | * protocols change, bump the affected components. we keep rev | 20 | * protocols change, bump the affected components. we keep rev |
| 35 | * internal cluster protocols separately from the public, | 21 | * internal cluster protocols separately from the public, |
| @@ -53,18 +39,10 @@ | |||
| 53 | /* | 39 | /* |
| 54 | * feature bits | 40 | * feature bits |
| 55 | */ | 41 | */ |
| 56 | #define CEPH_FEATURE_UID 1 | 42 | #define CEPH_FEATURE_UID (1<<0) |
| 57 | #define CEPH_FEATURE_NOSRCADDR 2 | 43 | #define CEPH_FEATURE_NOSRCADDR (1<<1) |
| 58 | #define CEPH_FEATURE_FLOCK 4 | 44 | #define CEPH_FEATURE_MONCLOCKCHECK (1<<2) |
| 59 | 45 | #define CEPH_FEATURE_FLOCK (1<<3) | |
| 60 | #define CEPH_FEATURE_SUPPORTED_MON CEPH_FEATURE_UID|CEPH_FEATURE_NOSRCADDR | ||
| 61 | #define CEPH_FEATURE_REQUIRED_MON CEPH_FEATURE_UID | ||
| 62 | #define CEPH_FEATURE_SUPPORTED_MDS CEPH_FEATURE_UID|CEPH_FEATURE_NOSRCADDR|CEPH_FEATURE_FLOCK | ||
| 63 | #define CEPH_FEATURE_REQUIRED_MDS CEPH_FEATURE_UID | ||
| 64 | #define CEPH_FEATURE_SUPPORTED_OSD CEPH_FEATURE_UID|CEPH_FEATURE_NOSRCADDR | ||
| 65 | #define CEPH_FEATURE_REQUIRED_OSD CEPH_FEATURE_UID | ||
| 66 | #define CEPH_FEATURE_SUPPORTED_CLIENT CEPH_FEATURE_NOSRCADDR | ||
| 67 | #define CEPH_FEATURE_REQUIRED_CLIENT CEPH_FEATURE_NOSRCADDR | ||
| 68 | 46 | ||
| 69 | 47 | ||
| 70 | /* | 48 | /* |
| @@ -96,6 +74,8 @@ int ceph_file_layout_is_valid(const struct ceph_file_layout *layout); | |||
| 96 | #define CEPH_CRYPTO_NONE 0x0 | 74 | #define CEPH_CRYPTO_NONE 0x0 |
| 97 | #define CEPH_CRYPTO_AES 0x1 | 75 | #define CEPH_CRYPTO_AES 0x1 |
| 98 | 76 | ||
| 77 | #define CEPH_AES_IV "cephsageyudagreg" | ||
| 78 | |||
| 99 | /* security/authentication protocols */ | 79 | /* security/authentication protocols */ |
| 100 | #define CEPH_AUTH_UNKNOWN 0x0 | 80 | #define CEPH_AUTH_UNKNOWN 0x0 |
| 101 | #define CEPH_AUTH_NONE 0x1 | 81 | #define CEPH_AUTH_NONE 0x1 |
| @@ -275,6 +255,7 @@ extern const char *ceph_mds_state_name(int s); | |||
| 275 | #define CEPH_LOCK_IDFT 512 /* dir frag tree */ | 255 | #define CEPH_LOCK_IDFT 512 /* dir frag tree */ |
| 276 | #define CEPH_LOCK_INEST 1024 /* mds internal */ | 256 | #define CEPH_LOCK_INEST 1024 /* mds internal */ |
| 277 | #define CEPH_LOCK_IXATTR 2048 | 257 | #define CEPH_LOCK_IXATTR 2048 |
| 258 | #define CEPH_LOCK_IFLOCK 4096 /* advisory file locks */ | ||
| 278 | #define CEPH_LOCK_INO 8192 /* immutable inode bits; not a lock */ | 259 | #define CEPH_LOCK_INO 8192 /* immutable inode bits; not a lock */ |
| 279 | 260 | ||
| 280 | /* client_session ops */ | 261 | /* client_session ops */ |
| @@ -316,6 +297,8 @@ enum { | |||
| 316 | CEPH_MDS_OP_RMXATTR = 0x01106, | 297 | CEPH_MDS_OP_RMXATTR = 0x01106, |
| 317 | CEPH_MDS_OP_SETLAYOUT = 0x01107, | 298 | CEPH_MDS_OP_SETLAYOUT = 0x01107, |
| 318 | CEPH_MDS_OP_SETATTR = 0x01108, | 299 | CEPH_MDS_OP_SETATTR = 0x01108, |
| 300 | CEPH_MDS_OP_SETFILELOCK= 0x01109, | ||
| 301 | CEPH_MDS_OP_GETFILELOCK= 0x00110, | ||
| 319 | 302 | ||
| 320 | CEPH_MDS_OP_MKNOD = 0x01201, | 303 | CEPH_MDS_OP_MKNOD = 0x01201, |
| 321 | CEPH_MDS_OP_LINK = 0x01202, | 304 | CEPH_MDS_OP_LINK = 0x01202, |
| @@ -386,6 +369,15 @@ union ceph_mds_request_args { | |||
| 386 | struct { | 369 | struct { |
| 387 | struct ceph_file_layout layout; | 370 | struct ceph_file_layout layout; |
| 388 | } __attribute__ ((packed)) setlayout; | 371 | } __attribute__ ((packed)) setlayout; |
| 372 | struct { | ||
| 373 | __u8 rule; /* currently fcntl or flock */ | ||
| 374 | __u8 type; /* shared, exclusive, remove*/ | ||
| 375 | __le64 pid; /* process id requesting the lock */ | ||
| 376 | __le64 pid_namespace; | ||
| 377 | __le64 start; /* initial location to lock */ | ||
| 378 | __le64 length; /* num bytes to lock from start */ | ||
| 379 | __u8 wait; /* will caller wait for lock to become available? */ | ||
| 380 | } __attribute__ ((packed)) filelock_change; | ||
| 389 | } __attribute__ ((packed)); | 381 | } __attribute__ ((packed)); |
| 390 | 382 | ||
| 391 | #define CEPH_MDS_FLAG_REPLAY 1 /* this is a replayed op */ | 383 | #define CEPH_MDS_FLAG_REPLAY 1 /* this is a replayed op */ |
| @@ -480,6 +472,23 @@ struct ceph_mds_reply_dirfrag { | |||
| 480 | __le32 dist[]; | 472 | __le32 dist[]; |
| 481 | } __attribute__ ((packed)); | 473 | } __attribute__ ((packed)); |
| 482 | 474 | ||
| 475 | #define CEPH_LOCK_FCNTL 1 | ||
| 476 | #define CEPH_LOCK_FLOCK 2 | ||
| 477 | |||
| 478 | #define CEPH_LOCK_SHARED 1 | ||
| 479 | #define CEPH_LOCK_EXCL 2 | ||
| 480 | #define CEPH_LOCK_UNLOCK 4 | ||
| 481 | |||
| 482 | struct ceph_filelock { | ||
| 483 | __le64 start;/* file offset to start lock at */ | ||
| 484 | __le64 length; /* num bytes to lock; 0 for all following start */ | ||
| 485 | __le64 client; /* which client holds the lock */ | ||
| 486 | __le64 pid; /* process id holding the lock on the client */ | ||
| 487 | __le64 pid_namespace; | ||
| 488 | __u8 type; /* shared lock, exclusive lock, or unlock */ | ||
| 489 | } __attribute__ ((packed)); | ||
| 490 | |||
| 491 | |||
| 483 | /* file access modes */ | 492 | /* file access modes */ |
| 484 | #define CEPH_FILE_MODE_PIN 0 | 493 | #define CEPH_FILE_MODE_PIN 0 |
| 485 | #define CEPH_FILE_MODE_RD 1 | 494 | #define CEPH_FILE_MODE_RD 1 |
| @@ -508,9 +517,10 @@ int ceph_flags_to_mode(int flags); | |||
| 508 | #define CEPH_CAP_SAUTH 2 | 517 | #define CEPH_CAP_SAUTH 2 |
| 509 | #define CEPH_CAP_SLINK 4 | 518 | #define CEPH_CAP_SLINK 4 |
| 510 | #define CEPH_CAP_SXATTR 6 | 519 | #define CEPH_CAP_SXATTR 6 |
| 511 | #define CEPH_CAP_SFILE 8 /* goes at the end (uses >2 cap bits) */ | 520 | #define CEPH_CAP_SFILE 8 |
| 521 | #define CEPH_CAP_SFLOCK 20 | ||
| 512 | 522 | ||
| 513 | #define CEPH_CAP_BITS 16 | 523 | #define CEPH_CAP_BITS 22 |
| 514 | 524 | ||
| 515 | /* composed values */ | 525 | /* composed values */ |
| 516 | #define CEPH_CAP_AUTH_SHARED (CEPH_CAP_GSHARED << CEPH_CAP_SAUTH) | 526 | #define CEPH_CAP_AUTH_SHARED (CEPH_CAP_GSHARED << CEPH_CAP_SAUTH) |
| @@ -528,6 +538,9 @@ int ceph_flags_to_mode(int flags); | |||
| 528 | #define CEPH_CAP_FILE_BUFFER (CEPH_CAP_GBUFFER << CEPH_CAP_SFILE) | 538 | #define CEPH_CAP_FILE_BUFFER (CEPH_CAP_GBUFFER << CEPH_CAP_SFILE) |
| 529 | #define CEPH_CAP_FILE_WREXTEND (CEPH_CAP_GWREXTEND << CEPH_CAP_SFILE) | 539 | #define CEPH_CAP_FILE_WREXTEND (CEPH_CAP_GWREXTEND << CEPH_CAP_SFILE) |
| 530 | #define CEPH_CAP_FILE_LAZYIO (CEPH_CAP_GLAZYIO << CEPH_CAP_SFILE) | 540 | #define CEPH_CAP_FILE_LAZYIO (CEPH_CAP_GLAZYIO << CEPH_CAP_SFILE) |
| 541 | #define CEPH_CAP_FLOCK_SHARED (CEPH_CAP_GSHARED << CEPH_CAP_SFLOCK) | ||
| 542 | #define CEPH_CAP_FLOCK_EXCL (CEPH_CAP_GEXCL << CEPH_CAP_SFLOCK) | ||
| 543 | |||
| 531 | 544 | ||
| 532 | /* cap masks (for getattr) */ | 545 | /* cap masks (for getattr) */ |
| 533 | #define CEPH_STAT_CAP_INODE CEPH_CAP_PIN | 546 | #define CEPH_STAT_CAP_INODE CEPH_CAP_PIN |
| @@ -563,7 +576,8 @@ int ceph_flags_to_mode(int flags); | |||
| 563 | CEPH_CAP_FILE_EXCL) | 576 | CEPH_CAP_FILE_EXCL) |
| 564 | #define CEPH_CAP_ANY_WR (CEPH_CAP_ANY_EXCL | CEPH_CAP_ANY_FILE_WR) | 577 | #define CEPH_CAP_ANY_WR (CEPH_CAP_ANY_EXCL | CEPH_CAP_ANY_FILE_WR) |
| 565 | #define CEPH_CAP_ANY (CEPH_CAP_ANY_RD | CEPH_CAP_ANY_EXCL | \ | 578 | #define CEPH_CAP_ANY (CEPH_CAP_ANY_RD | CEPH_CAP_ANY_EXCL | \ |
| 566 | CEPH_CAP_ANY_FILE_WR | CEPH_CAP_PIN) | 579 | CEPH_CAP_ANY_FILE_WR | CEPH_CAP_FILE_LAZYIO | \ |
| 580 | CEPH_CAP_PIN) | ||
| 567 | 581 | ||
| 568 | #define CEPH_CAP_LOCKS (CEPH_LOCK_IFILE | CEPH_LOCK_IAUTH | CEPH_LOCK_ILINK | \ | 582 | #define CEPH_CAP_LOCKS (CEPH_LOCK_IFILE | CEPH_LOCK_IAUTH | CEPH_LOCK_ILINK | \ |
| 569 | CEPH_LOCK_IXATTR) | 583 | CEPH_LOCK_IXATTR) |
| @@ -653,12 +667,21 @@ struct ceph_mds_cap_reconnect { | |||
| 653 | __le64 cap_id; | 667 | __le64 cap_id; |
| 654 | __le32 wanted; | 668 | __le32 wanted; |
| 655 | __le32 issued; | 669 | __le32 issued; |
| 670 | __le64 snaprealm; | ||
| 671 | __le64 pathbase; /* base ino for our path to this ino */ | ||
| 672 | __le32 flock_len; /* size of flock state blob, if any */ | ||
| 673 | } __attribute__ ((packed)); | ||
| 674 | /* followed by flock blob */ | ||
| 675 | |||
| 676 | struct ceph_mds_cap_reconnect_v1 { | ||
| 677 | __le64 cap_id; | ||
| 678 | __le32 wanted; | ||
| 679 | __le32 issued; | ||
| 656 | __le64 size; | 680 | __le64 size; |
| 657 | struct ceph_timespec mtime, atime; | 681 | struct ceph_timespec mtime, atime; |
| 658 | __le64 snaprealm; | 682 | __le64 snaprealm; |
| 659 | __le64 pathbase; /* base ino for our path to this ino */ | 683 | __le64 pathbase; /* base ino for our path to this ino */ |
| 660 | } __attribute__ ((packed)); | 684 | } __attribute__ ((packed)); |
| 661 | /* followed by encoded string */ | ||
| 662 | 685 | ||
| 663 | struct ceph_mds_snaprealm_reconnect { | 686 | struct ceph_mds_snaprealm_reconnect { |
| 664 | __le64 ino; /* snap realm base */ | 687 | __le64 ino; /* snap realm base */ |
diff --git a/fs/ceph/ceph_hash.h b/fs/ceph/ceph_hash.h index 5ac470c433c9..d099c3f90236 100644 --- a/fs/ceph/ceph_hash.h +++ b/fs/ceph/ceph_hash.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #ifndef _FS_CEPH_HASH_H | 1 | #ifndef FS_CEPH_HASH_H |
| 2 | #define _FS_CEPH_HASH_H | 2 | #define FS_CEPH_HASH_H |
| 3 | 3 | ||
| 4 | #define CEPH_STR_HASH_LINUX 0x1 /* linux dcache hash */ | 4 | #define CEPH_STR_HASH_LINUX 0x1 /* linux dcache hash */ |
| 5 | #define CEPH_STR_HASH_RJENKINS 0x2 /* robert jenkins' */ | 5 | #define CEPH_STR_HASH_RJENKINS 0x2 /* robert jenkins' */ |
diff --git a/fs/ceph/ceph_strings.c b/fs/ceph/ceph_strings.c index 7503aee828ce..c6179d3a26a2 100644 --- a/fs/ceph/ceph_strings.c +++ b/fs/ceph/ceph_strings.c | |||
| @@ -28,6 +28,7 @@ const char *ceph_osd_op_name(int op) | |||
| 28 | case CEPH_OSD_OP_TRUNCATE: return "truncate"; | 28 | case CEPH_OSD_OP_TRUNCATE: return "truncate"; |
| 29 | case CEPH_OSD_OP_ZERO: return "zero"; | 29 | case CEPH_OSD_OP_ZERO: return "zero"; |
| 30 | case CEPH_OSD_OP_WRITEFULL: return "writefull"; | 30 | case CEPH_OSD_OP_WRITEFULL: return "writefull"; |
| 31 | case CEPH_OSD_OP_ROLLBACK: return "rollback"; | ||
| 31 | 32 | ||
| 32 | case CEPH_OSD_OP_APPEND: return "append"; | 33 | case CEPH_OSD_OP_APPEND: return "append"; |
| 33 | case CEPH_OSD_OP_STARTSYNC: return "startsync"; | 34 | case CEPH_OSD_OP_STARTSYNC: return "startsync"; |
| @@ -129,6 +130,8 @@ const char *ceph_mds_op_name(int op) | |||
| 129 | case CEPH_MDS_OP_LSSNAP: return "lssnap"; | 130 | case CEPH_MDS_OP_LSSNAP: return "lssnap"; |
| 130 | case CEPH_MDS_OP_MKSNAP: return "mksnap"; | 131 | case CEPH_MDS_OP_MKSNAP: return "mksnap"; |
| 131 | case CEPH_MDS_OP_RMSNAP: return "rmsnap"; | 132 | case CEPH_MDS_OP_RMSNAP: return "rmsnap"; |
| 133 | case CEPH_MDS_OP_SETFILELOCK: return "setfilelock"; | ||
| 134 | case CEPH_MDS_OP_GETFILELOCK: return "getfilelock"; | ||
| 132 | } | 135 | } |
| 133 | return "???"; | 136 | return "???"; |
| 134 | } | 137 | } |
diff --git a/fs/ceph/crush/crush.h b/fs/ceph/crush/crush.h index dcd7e7523700..97e435b191f4 100644 --- a/fs/ceph/crush/crush.h +++ b/fs/ceph/crush/crush.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #ifndef _CRUSH_CRUSH_H | 1 | #ifndef CEPH_CRUSH_CRUSH_H |
| 2 | #define _CRUSH_CRUSH_H | 2 | #define CEPH_CRUSH_CRUSH_H |
| 3 | 3 | ||
| 4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
| 5 | 5 | ||
diff --git a/fs/ceph/crush/hash.h b/fs/ceph/crush/hash.h index ff48e110e4bb..91e884230d5d 100644 --- a/fs/ceph/crush/hash.h +++ b/fs/ceph/crush/hash.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #ifndef _CRUSH_HASH_H | 1 | #ifndef CEPH_CRUSH_HASH_H |
| 2 | #define _CRUSH_HASH_H | 2 | #define CEPH_CRUSH_HASH_H |
| 3 | 3 | ||
| 4 | #define CRUSH_HASH_RJENKINS1 0 | 4 | #define CRUSH_HASH_RJENKINS1 0 |
| 5 | 5 | ||
diff --git a/fs/ceph/crush/mapper.h b/fs/ceph/crush/mapper.h index 98e90046fd9f..c46b99c18bb0 100644 --- a/fs/ceph/crush/mapper.h +++ b/fs/ceph/crush/mapper.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #ifndef _CRUSH_MAPPER_H | 1 | #ifndef CEPH_CRUSH_MAPPER_H |
| 2 | #define _CRUSH_MAPPER_H | 2 | #define CEPH_CRUSH_MAPPER_H |
| 3 | 3 | ||
| 4 | /* | 4 | /* |
| 5 | * CRUSH functions for find rules and then mapping an input to an | 5 | * CRUSH functions for find rules and then mapping an input to an |
diff --git a/fs/ceph/crypto.c b/fs/ceph/crypto.c index f704b3b62424..a3e627f63293 100644 --- a/fs/ceph/crypto.c +++ b/fs/ceph/crypto.c | |||
| @@ -75,10 +75,11 @@ static struct crypto_blkcipher *ceph_crypto_alloc_cipher(void) | |||
| 75 | return crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC); | 75 | return crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC); |
| 76 | } | 76 | } |
| 77 | 77 | ||
| 78 | const u8 *aes_iv = "cephsageyudagreg"; | 78 | static const u8 *aes_iv = (u8 *)CEPH_AES_IV; |
| 79 | 79 | ||
| 80 | int ceph_aes_encrypt(const void *key, int key_len, void *dst, size_t *dst_len, | 80 | static int ceph_aes_encrypt(const void *key, int key_len, |
| 81 | const void *src, size_t src_len) | 81 | void *dst, size_t *dst_len, |
| 82 | const void *src, size_t src_len) | ||
| 82 | { | 83 | { |
| 83 | struct scatterlist sg_in[2], sg_out[1]; | 84 | struct scatterlist sg_in[2], sg_out[1]; |
| 84 | struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher(); | 85 | struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher(); |
| @@ -126,9 +127,10 @@ int ceph_aes_encrypt(const void *key, int key_len, void *dst, size_t *dst_len, | |||
| 126 | return 0; | 127 | return 0; |
| 127 | } | 128 | } |
| 128 | 129 | ||
| 129 | int ceph_aes_encrypt2(const void *key, int key_len, void *dst, size_t *dst_len, | 130 | static int ceph_aes_encrypt2(const void *key, int key_len, void *dst, |
| 130 | const void *src1, size_t src1_len, | 131 | size_t *dst_len, |
| 131 | const void *src2, size_t src2_len) | 132 | const void *src1, size_t src1_len, |
| 133 | const void *src2, size_t src2_len) | ||
| 132 | { | 134 | { |
| 133 | struct scatterlist sg_in[3], sg_out[1]; | 135 | struct scatterlist sg_in[3], sg_out[1]; |
| 134 | struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher(); | 136 | struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher(); |
| @@ -179,8 +181,9 @@ int ceph_aes_encrypt2(const void *key, int key_len, void *dst, size_t *dst_len, | |||
| 179 | return 0; | 181 | return 0; |
| 180 | } | 182 | } |
| 181 | 183 | ||
| 182 | int ceph_aes_decrypt(const void *key, int key_len, void *dst, size_t *dst_len, | 184 | static int ceph_aes_decrypt(const void *key, int key_len, |
| 183 | const void *src, size_t src_len) | 185 | void *dst, size_t *dst_len, |
| 186 | const void *src, size_t src_len) | ||
| 184 | { | 187 | { |
| 185 | struct scatterlist sg_in[1], sg_out[2]; | 188 | struct scatterlist sg_in[1], sg_out[2]; |
| 186 | struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher(); | 189 | struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher(); |
| @@ -238,10 +241,10 @@ int ceph_aes_decrypt(const void *key, int key_len, void *dst, size_t *dst_len, | |||
| 238 | return 0; | 241 | return 0; |
| 239 | } | 242 | } |
| 240 | 243 | ||
| 241 | int ceph_aes_decrypt2(const void *key, int key_len, | 244 | static int ceph_aes_decrypt2(const void *key, int key_len, |
| 242 | void *dst1, size_t *dst1_len, | 245 | void *dst1, size_t *dst1_len, |
| 243 | void *dst2, size_t *dst2_len, | 246 | void *dst2, size_t *dst2_len, |
| 244 | const void *src, size_t src_len) | 247 | const void *src, size_t src_len) |
| 245 | { | 248 | { |
| 246 | struct scatterlist sg_in[1], sg_out[3]; | 249 | struct scatterlist sg_in[1], sg_out[3]; |
| 247 | struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher(); | 250 | struct crypto_blkcipher *tfm = ceph_crypto_alloc_cipher(); |
diff --git a/fs/ceph/crypto.h b/fs/ceph/crypto.h index 40b502e6bd89..bdf38607323c 100644 --- a/fs/ceph/crypto.h +++ b/fs/ceph/crypto.h | |||
| @@ -42,7 +42,7 @@ extern int ceph_encrypt2(struct ceph_crypto_key *secret, | |||
| 42 | const void *src2, size_t src2_len); | 42 | const void *src2, size_t src2_len); |
| 43 | 43 | ||
| 44 | /* armor.c */ | 44 | /* armor.c */ |
| 45 | extern int ceph_armor(char *dst, const void *src, const void *end); | 45 | extern int ceph_armor(char *dst, const char *src, const char *end); |
| 46 | extern int ceph_unarmor(void *dst, const char *src, const char *end); | 46 | extern int ceph_unarmor(char *dst, const char *src, const char *end); |
| 47 | 47 | ||
| 48 | #endif | 48 | #endif |
diff --git a/fs/ceph/debugfs.c b/fs/ceph/debugfs.c index f2f5332ddbba..360c4f22718d 100644 --- a/fs/ceph/debugfs.c +++ b/fs/ceph/debugfs.c | |||
| @@ -291,7 +291,7 @@ static int dentry_lru_show(struct seq_file *s, void *ptr) | |||
| 291 | return 0; | 291 | return 0; |
| 292 | } | 292 | } |
| 293 | 293 | ||
| 294 | #define DEFINE_SHOW_FUNC(name) \ | 294 | #define DEFINE_SHOW_FUNC(name) \ |
| 295 | static int name##_open(struct inode *inode, struct file *file) \ | 295 | static int name##_open(struct inode *inode, struct file *file) \ |
| 296 | { \ | 296 | { \ |
| 297 | struct seq_file *sf; \ | 297 | struct seq_file *sf; \ |
| @@ -361,8 +361,8 @@ int ceph_debugfs_client_init(struct ceph_client *client) | |||
| 361 | int ret = 0; | 361 | int ret = 0; |
| 362 | char name[80]; | 362 | char name[80]; |
| 363 | 363 | ||
| 364 | snprintf(name, sizeof(name), FSID_FORMAT ".client%lld", | 364 | snprintf(name, sizeof(name), "%pU.client%lld", &client->fsid, |
| 365 | PR_FSID(&client->fsid), client->monc.auth->global_id); | 365 | client->monc.auth->global_id); |
| 366 | 366 | ||
| 367 | client->debugfs_dir = debugfs_create_dir(name, ceph_debugfs_dir); | 367 | client->debugfs_dir = debugfs_create_dir(name, ceph_debugfs_dir); |
| 368 | if (!client->debugfs_dir) | 368 | if (!client->debugfs_dir) |
| @@ -432,11 +432,12 @@ int ceph_debugfs_client_init(struct ceph_client *client) | |||
| 432 | if (!client->debugfs_caps) | 432 | if (!client->debugfs_caps) |
| 433 | goto out; | 433 | goto out; |
| 434 | 434 | ||
| 435 | client->debugfs_congestion_kb = debugfs_create_file("writeback_congestion_kb", | 435 | client->debugfs_congestion_kb = |
| 436 | 0600, | 436 | debugfs_create_file("writeback_congestion_kb", |
| 437 | client->debugfs_dir, | 437 | 0600, |
| 438 | client, | 438 | client->debugfs_dir, |
| 439 | &congestion_kb_fops); | 439 | client, |
| 440 | &congestion_kb_fops); | ||
| 440 | if (!client->debugfs_congestion_kb) | 441 | if (!client->debugfs_congestion_kb) |
| 441 | goto out; | 442 | goto out; |
| 442 | 443 | ||
| @@ -466,7 +467,7 @@ void ceph_debugfs_client_cleanup(struct ceph_client *client) | |||
| 466 | debugfs_remove(client->debugfs_dir); | 467 | debugfs_remove(client->debugfs_dir); |
| 467 | } | 468 | } |
| 468 | 469 | ||
| 469 | #else // CONFIG_DEBUG_FS | 470 | #else /* CONFIG_DEBUG_FS */ |
| 470 | 471 | ||
| 471 | int __init ceph_debugfs_init(void) | 472 | int __init ceph_debugfs_init(void) |
| 472 | { | 473 | { |
| @@ -486,4 +487,4 @@ void ceph_debugfs_client_cleanup(struct ceph_client *client) | |||
| 486 | { | 487 | { |
| 487 | } | 488 | } |
| 488 | 489 | ||
| 489 | #endif // CONFIG_DEBUG_FS | 490 | #endif /* CONFIG_DEBUG_FS */ |
diff --git a/fs/ceph/decode.h b/fs/ceph/decode.h index 65b3e022eaf5..3d25415afe63 100644 --- a/fs/ceph/decode.h +++ b/fs/ceph/decode.h | |||
| @@ -99,11 +99,13 @@ static inline void ceph_encode_timespec(struct ceph_timespec *tv, | |||
| 99 | */ | 99 | */ |
| 100 | static inline void ceph_encode_addr(struct ceph_entity_addr *a) | 100 | static inline void ceph_encode_addr(struct ceph_entity_addr *a) |
| 101 | { | 101 | { |
| 102 | a->in_addr.ss_family = htons(a->in_addr.ss_family); | 102 | __be16 ss_family = htons(a->in_addr.ss_family); |
| 103 | a->in_addr.ss_family = *(__u16 *)&ss_family; | ||
| 103 | } | 104 | } |
| 104 | static inline void ceph_decode_addr(struct ceph_entity_addr *a) | 105 | static inline void ceph_decode_addr(struct ceph_entity_addr *a) |
| 105 | { | 106 | { |
| 106 | a->in_addr.ss_family = ntohs(a->in_addr.ss_family); | 107 | __be16 ss_family = *(__be16 *)&a->in_addr.ss_family; |
| 108 | a->in_addr.ss_family = ntohs(ss_family); | ||
| 107 | WARN_ON(a->in_addr.ss_family == 512); | 109 | WARN_ON(a->in_addr.ss_family == 512); |
| 108 | } | 110 | } |
| 109 | 111 | ||
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index f94ed3c7f6a5..67bbb41d5526 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c | |||
| @@ -27,7 +27,7 @@ | |||
| 27 | 27 | ||
| 28 | const struct inode_operations ceph_dir_iops; | 28 | const struct inode_operations ceph_dir_iops; |
| 29 | const struct file_operations ceph_dir_fops; | 29 | const struct file_operations ceph_dir_fops; |
| 30 | struct dentry_operations ceph_dentry_ops; | 30 | const struct dentry_operations ceph_dentry_ops; |
| 31 | 31 | ||
| 32 | /* | 32 | /* |
| 33 | * Initialize ceph dentry state. | 33 | * Initialize ceph dentry state. |
| @@ -94,6 +94,8 @@ static unsigned fpos_off(loff_t p) | |||
| 94 | */ | 94 | */ |
| 95 | static int __dcache_readdir(struct file *filp, | 95 | static int __dcache_readdir(struct file *filp, |
| 96 | void *dirent, filldir_t filldir) | 96 | void *dirent, filldir_t filldir) |
| 97 | __releases(inode->i_lock) | ||
| 98 | __acquires(inode->i_lock) | ||
| 97 | { | 99 | { |
| 98 | struct inode *inode = filp->f_dentry->d_inode; | 100 | struct inode *inode = filp->f_dentry->d_inode; |
| 99 | struct ceph_file_info *fi = filp->private_data; | 101 | struct ceph_file_info *fi = filp->private_data; |
| @@ -1239,16 +1241,16 @@ const struct inode_operations ceph_dir_iops = { | |||
| 1239 | .create = ceph_create, | 1241 | .create = ceph_create, |
| 1240 | }; | 1242 | }; |
| 1241 | 1243 | ||
| 1242 | struct dentry_operations ceph_dentry_ops = { | 1244 | const struct dentry_operations ceph_dentry_ops = { |
| 1243 | .d_revalidate = ceph_d_revalidate, | 1245 | .d_revalidate = ceph_d_revalidate, |
| 1244 | .d_release = ceph_dentry_release, | 1246 | .d_release = ceph_dentry_release, |
| 1245 | }; | 1247 | }; |
| 1246 | 1248 | ||
| 1247 | struct dentry_operations ceph_snapdir_dentry_ops = { | 1249 | const struct dentry_operations ceph_snapdir_dentry_ops = { |
| 1248 | .d_revalidate = ceph_snapdir_d_revalidate, | 1250 | .d_revalidate = ceph_snapdir_d_revalidate, |
| 1249 | .d_release = ceph_dentry_release, | 1251 | .d_release = ceph_dentry_release, |
| 1250 | }; | 1252 | }; |
| 1251 | 1253 | ||
| 1252 | struct dentry_operations ceph_snap_dentry_ops = { | 1254 | const struct dentry_operations ceph_snap_dentry_ops = { |
| 1253 | .d_release = ceph_dentry_release, | 1255 | .d_release = ceph_dentry_release, |
| 1254 | }; | 1256 | }; |
diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 7c08698fad3e..8c044a4f0457 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c | |||
| @@ -317,7 +317,7 @@ void ceph_release_page_vector(struct page **pages, int num_pages) | |||
| 317 | /* | 317 | /* |
| 318 | * allocate a vector new pages | 318 | * allocate a vector new pages |
| 319 | */ | 319 | */ |
| 320 | struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags) | 320 | static struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags) |
| 321 | { | 321 | { |
| 322 | struct page **pages; | 322 | struct page **pages; |
| 323 | int i; | 323 | int i; |
| @@ -665,7 +665,7 @@ more: | |||
| 665 | * throw out any page cache pages in this range. this | 665 | * throw out any page cache pages in this range. this |
| 666 | * may block. | 666 | * may block. |
| 667 | */ | 667 | */ |
| 668 | truncate_inode_pages_range(inode->i_mapping, pos, | 668 | truncate_inode_pages_range(inode->i_mapping, pos, |
| 669 | (pos+len) | (PAGE_CACHE_SIZE-1)); | 669 | (pos+len) | (PAGE_CACHE_SIZE-1)); |
| 670 | } else { | 670 | } else { |
| 671 | pages = ceph_alloc_page_vector(num_pages, GFP_NOFS); | 671 | pages = ceph_alloc_page_vector(num_pages, GFP_NOFS); |
| @@ -740,28 +740,32 @@ static ssize_t ceph_aio_read(struct kiocb *iocb, const struct iovec *iov, | |||
| 740 | unsigned long nr_segs, loff_t pos) | 740 | unsigned long nr_segs, loff_t pos) |
| 741 | { | 741 | { |
| 742 | struct file *filp = iocb->ki_filp; | 742 | struct file *filp = iocb->ki_filp; |
| 743 | struct ceph_file_info *fi = filp->private_data; | ||
| 743 | loff_t *ppos = &iocb->ki_pos; | 744 | loff_t *ppos = &iocb->ki_pos; |
| 744 | size_t len = iov->iov_len; | 745 | size_t len = iov->iov_len; |
| 745 | struct inode *inode = filp->f_dentry->d_inode; | 746 | struct inode *inode = filp->f_dentry->d_inode; |
| 746 | struct ceph_inode_info *ci = ceph_inode(inode); | 747 | struct ceph_inode_info *ci = ceph_inode(inode); |
| 747 | void *base = iov->iov_base; | 748 | void __user *base = iov->iov_base; |
| 748 | ssize_t ret; | 749 | ssize_t ret; |
| 749 | int got = 0; | 750 | int want, got = 0; |
| 750 | int checkeof = 0, read = 0; | 751 | int checkeof = 0, read = 0; |
| 751 | 752 | ||
| 752 | dout("aio_read %p %llx.%llx %llu~%u trying to get caps on %p\n", | 753 | dout("aio_read %p %llx.%llx %llu~%u trying to get caps on %p\n", |
| 753 | inode, ceph_vinop(inode), pos, (unsigned)len, inode); | 754 | inode, ceph_vinop(inode), pos, (unsigned)len, inode); |
| 754 | again: | 755 | again: |
| 755 | __ceph_do_pending_vmtruncate(inode); | 756 | __ceph_do_pending_vmtruncate(inode); |
| 756 | ret = ceph_get_caps(ci, CEPH_CAP_FILE_RD, CEPH_CAP_FILE_CACHE, | 757 | if (fi->fmode & CEPH_FILE_MODE_LAZY) |
| 757 | &got, -1); | 758 | want = CEPH_CAP_FILE_CACHE | CEPH_CAP_FILE_LAZYIO; |
| 759 | else | ||
| 760 | want = CEPH_CAP_FILE_CACHE; | ||
| 761 | ret = ceph_get_caps(ci, CEPH_CAP_FILE_RD, want, &got, -1); | ||
| 758 | if (ret < 0) | 762 | if (ret < 0) |
| 759 | goto out; | 763 | goto out; |
| 760 | dout("aio_read %p %llx.%llx %llu~%u got cap refs on %s\n", | 764 | dout("aio_read %p %llx.%llx %llu~%u got cap refs on %s\n", |
| 761 | inode, ceph_vinop(inode), pos, (unsigned)len, | 765 | inode, ceph_vinop(inode), pos, (unsigned)len, |
| 762 | ceph_cap_string(got)); | 766 | ceph_cap_string(got)); |
| 763 | 767 | ||
| 764 | if ((got & CEPH_CAP_FILE_CACHE) == 0 || | 768 | if ((got & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) == 0 || |
| 765 | (iocb->ki_filp->f_flags & O_DIRECT) || | 769 | (iocb->ki_filp->f_flags & O_DIRECT) || |
| 766 | (inode->i_sb->s_flags & MS_SYNCHRONOUS)) | 770 | (inode->i_sb->s_flags & MS_SYNCHRONOUS)) |
| 767 | /* hmm, this isn't really async... */ | 771 | /* hmm, this isn't really async... */ |
| @@ -807,11 +811,12 @@ static ssize_t ceph_aio_write(struct kiocb *iocb, const struct iovec *iov, | |||
| 807 | unsigned long nr_segs, loff_t pos) | 811 | unsigned long nr_segs, loff_t pos) |
| 808 | { | 812 | { |
| 809 | struct file *file = iocb->ki_filp; | 813 | struct file *file = iocb->ki_filp; |
| 814 | struct ceph_file_info *fi = file->private_data; | ||
| 810 | struct inode *inode = file->f_dentry->d_inode; | 815 | struct inode *inode = file->f_dentry->d_inode; |
| 811 | struct ceph_inode_info *ci = ceph_inode(inode); | 816 | struct ceph_inode_info *ci = ceph_inode(inode); |
| 812 | struct ceph_osd_client *osdc = &ceph_sb_to_client(inode->i_sb)->osdc; | 817 | struct ceph_osd_client *osdc = &ceph_sb_to_client(inode->i_sb)->osdc; |
| 813 | loff_t endoff = pos + iov->iov_len; | 818 | loff_t endoff = pos + iov->iov_len; |
| 814 | int got = 0; | 819 | int want, got = 0; |
| 815 | int ret, err; | 820 | int ret, err; |
| 816 | 821 | ||
| 817 | if (ceph_snap(inode) != CEPH_NOSNAP) | 822 | if (ceph_snap(inode) != CEPH_NOSNAP) |
| @@ -824,8 +829,11 @@ retry_snap: | |||
| 824 | dout("aio_write %p %llx.%llx %llu~%u getting caps. i_size %llu\n", | 829 | dout("aio_write %p %llx.%llx %llu~%u getting caps. i_size %llu\n", |
| 825 | inode, ceph_vinop(inode), pos, (unsigned)iov->iov_len, | 830 | inode, ceph_vinop(inode), pos, (unsigned)iov->iov_len, |
| 826 | inode->i_size); | 831 | inode->i_size); |
| 827 | ret = ceph_get_caps(ci, CEPH_CAP_FILE_WR, CEPH_CAP_FILE_BUFFER, | 832 | if (fi->fmode & CEPH_FILE_MODE_LAZY) |
| 828 | &got, endoff); | 833 | want = CEPH_CAP_FILE_BUFFER | CEPH_CAP_FILE_LAZYIO; |
| 834 | else | ||
| 835 | want = CEPH_CAP_FILE_BUFFER; | ||
| 836 | ret = ceph_get_caps(ci, CEPH_CAP_FILE_WR, want, &got, endoff); | ||
| 829 | if (ret < 0) | 837 | if (ret < 0) |
| 830 | goto out; | 838 | goto out; |
| 831 | 839 | ||
| @@ -833,7 +841,7 @@ retry_snap: | |||
| 833 | inode, ceph_vinop(inode), pos, (unsigned)iov->iov_len, | 841 | inode, ceph_vinop(inode), pos, (unsigned)iov->iov_len, |
| 834 | ceph_cap_string(got)); | 842 | ceph_cap_string(got)); |
| 835 | 843 | ||
| 836 | if ((got & CEPH_CAP_FILE_BUFFER) == 0 || | 844 | if ((got & (CEPH_CAP_FILE_BUFFER|CEPH_CAP_FILE_LAZYIO)) == 0 || |
| 837 | (iocb->ki_filp->f_flags & O_DIRECT) || | 845 | (iocb->ki_filp->f_flags & O_DIRECT) || |
| 838 | (inode->i_sb->s_flags & MS_SYNCHRONOUS)) { | 846 | (inode->i_sb->s_flags & MS_SYNCHRONOUS)) { |
| 839 | ret = ceph_sync_write(file, iov->iov_base, iov->iov_len, | 847 | ret = ceph_sync_write(file, iov->iov_base, iov->iov_len, |
| @@ -930,6 +938,8 @@ const struct file_operations ceph_file_fops = { | |||
| 930 | .aio_write = ceph_aio_write, | 938 | .aio_write = ceph_aio_write, |
| 931 | .mmap = ceph_mmap, | 939 | .mmap = ceph_mmap, |
| 932 | .fsync = ceph_fsync, | 940 | .fsync = ceph_fsync, |
| 941 | .lock = ceph_lock, | ||
| 942 | .flock = ceph_flock, | ||
| 933 | .splice_read = generic_file_splice_read, | 943 | .splice_read = generic_file_splice_read, |
| 934 | .splice_write = generic_file_splice_write, | 944 | .splice_write = generic_file_splice_write, |
| 935 | .unlocked_ioctl = ceph_ioctl, | 945 | .unlocked_ioctl = ceph_ioctl, |
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 389f9dbd9949..5d893d31e399 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c | |||
| @@ -442,8 +442,9 @@ int ceph_fill_file_size(struct inode *inode, int issued, | |||
| 442 | * the file is either opened or mmaped | 442 | * the file is either opened or mmaped |
| 443 | */ | 443 | */ |
| 444 | if ((issued & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_RD| | 444 | if ((issued & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_RD| |
| 445 | CEPH_CAP_FILE_WR|CEPH_CAP_FILE_BUFFER| | 445 | CEPH_CAP_FILE_WR|CEPH_CAP_FILE_BUFFER| |
| 446 | CEPH_CAP_FILE_EXCL)) || | 446 | CEPH_CAP_FILE_EXCL| |
| 447 | CEPH_CAP_FILE_LAZYIO)) || | ||
| 447 | mapping_mapped(inode->i_mapping) || | 448 | mapping_mapped(inode->i_mapping) || |
| 448 | __ceph_caps_file_wanted(ci)) { | 449 | __ceph_caps_file_wanted(ci)) { |
| 449 | ci->i_truncate_pending++; | 450 | ci->i_truncate_pending++; |
diff --git a/fs/ceph/ioctl.c b/fs/ceph/ioctl.c index d085f07756b4..76e307d2aba1 100644 --- a/fs/ceph/ioctl.c +++ b/fs/ceph/ioctl.c | |||
| @@ -143,6 +143,27 @@ static long ceph_ioctl_get_dataloc(struct file *file, void __user *arg) | |||
| 143 | return 0; | 143 | return 0; |
| 144 | } | 144 | } |
| 145 | 145 | ||
| 146 | static long ceph_ioctl_lazyio(struct file *file) | ||
| 147 | { | ||
| 148 | struct ceph_file_info *fi = file->private_data; | ||
| 149 | struct inode *inode = file->f_dentry->d_inode; | ||
| 150 | struct ceph_inode_info *ci = ceph_inode(inode); | ||
| 151 | |||
| 152 | if ((fi->fmode & CEPH_FILE_MODE_LAZY) == 0) { | ||
| 153 | spin_lock(&inode->i_lock); | ||
| 154 | ci->i_nr_by_mode[fi->fmode]--; | ||
| 155 | fi->fmode |= CEPH_FILE_MODE_LAZY; | ||
| 156 | ci->i_nr_by_mode[fi->fmode]++; | ||
| 157 | spin_unlock(&inode->i_lock); | ||
| 158 | dout("ioctl_layzio: file %p marked lazy\n", file); | ||
| 159 | |||
| 160 | ceph_check_caps(ci, 0, NULL); | ||
| 161 | } else { | ||
| 162 | dout("ioctl_layzio: file %p already lazy\n", file); | ||
| 163 | } | ||
| 164 | return 0; | ||
| 165 | } | ||
| 166 | |||
| 146 | long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 167 | long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
| 147 | { | 168 | { |
| 148 | dout("ioctl file %p cmd %u arg %lu\n", file, cmd, arg); | 169 | dout("ioctl file %p cmd %u arg %lu\n", file, cmd, arg); |
| @@ -155,6 +176,9 @@ long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
| 155 | 176 | ||
| 156 | case CEPH_IOC_GET_DATALOC: | 177 | case CEPH_IOC_GET_DATALOC: |
| 157 | return ceph_ioctl_get_dataloc(file, (void __user *)arg); | 178 | return ceph_ioctl_get_dataloc(file, (void __user *)arg); |
| 179 | |||
| 180 | case CEPH_IOC_LAZYIO: | ||
| 181 | return ceph_ioctl_lazyio(file); | ||
| 158 | } | 182 | } |
| 159 | return -ENOTTY; | 183 | return -ENOTTY; |
| 160 | } | 184 | } |
diff --git a/fs/ceph/ioctl.h b/fs/ceph/ioctl.h index 25e4f1a9d059..88451a3b6857 100644 --- a/fs/ceph/ioctl.h +++ b/fs/ceph/ioctl.h | |||
| @@ -37,4 +37,6 @@ struct ceph_ioctl_dataloc { | |||
| 37 | #define CEPH_IOC_GET_DATALOC _IOWR(CEPH_IOCTL_MAGIC, 3, \ | 37 | #define CEPH_IOC_GET_DATALOC _IOWR(CEPH_IOCTL_MAGIC, 3, \ |
| 38 | struct ceph_ioctl_dataloc) | 38 | struct ceph_ioctl_dataloc) |
| 39 | 39 | ||
| 40 | #define CEPH_IOC_LAZYIO _IO(CEPH_IOCTL_MAGIC, 4) | ||
| 41 | |||
| 40 | #endif | 42 | #endif |
diff --git a/fs/ceph/locks.c b/fs/ceph/locks.c new file mode 100644 index 000000000000..ae85af06454f --- /dev/null +++ b/fs/ceph/locks.c | |||
| @@ -0,0 +1,256 @@ | |||
| 1 | #include "ceph_debug.h" | ||
| 2 | |||
| 3 | #include <linux/file.h> | ||
| 4 | #include <linux/namei.h> | ||
| 5 | |||
| 6 | #include "super.h" | ||
| 7 | #include "mds_client.h" | ||
| 8 | #include "pagelist.h" | ||
| 9 | |||
| 10 | /** | ||
| 11 | * Implement fcntl and flock locking functions. | ||
| 12 | */ | ||
| 13 | static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file, | ||
| 14 | u64 pid, u64 pid_ns, | ||
| 15 | int cmd, u64 start, u64 length, u8 wait) | ||
| 16 | { | ||
| 17 | struct inode *inode = file->f_dentry->d_inode; | ||
| 18 | struct ceph_mds_client *mdsc = | ||
| 19 | &ceph_sb_to_client(inode->i_sb)->mdsc; | ||
| 20 | struct ceph_mds_request *req; | ||
| 21 | int err; | ||
| 22 | |||
| 23 | req = ceph_mdsc_create_request(mdsc, operation, USE_AUTH_MDS); | ||
| 24 | if (IS_ERR(req)) | ||
| 25 | return PTR_ERR(req); | ||
| 26 | req->r_inode = igrab(inode); | ||
| 27 | |||
| 28 | dout("ceph_lock_message: rule: %d, op: %d, pid: %llu, start: %llu, " | ||
| 29 | "length: %llu, wait: %d, type`: %d", (int)lock_type, | ||
| 30 | (int)operation, pid, start, length, wait, cmd); | ||
| 31 | |||
| 32 | req->r_args.filelock_change.rule = lock_type; | ||
| 33 | req->r_args.filelock_change.type = cmd; | ||
| 34 | req->r_args.filelock_change.pid = cpu_to_le64(pid); | ||
| 35 | /* This should be adjusted, but I'm not sure if | ||
| 36 | namespaces actually get id numbers*/ | ||
| 37 | req->r_args.filelock_change.pid_namespace = | ||
| 38 | cpu_to_le64((u64)pid_ns); | ||
| 39 | req->r_args.filelock_change.start = cpu_to_le64(start); | ||
| 40 | req->r_args.filelock_change.length = cpu_to_le64(length); | ||
| 41 | req->r_args.filelock_change.wait = wait; | ||
| 42 | |||
| 43 | err = ceph_mdsc_do_request(mdsc, inode, req); | ||
| 44 | ceph_mdsc_put_request(req); | ||
| 45 | dout("ceph_lock_message: rule: %d, op: %d, pid: %llu, start: %llu, " | ||
| 46 | "length: %llu, wait: %d, type`: %d err code %d", (int)lock_type, | ||
| 47 | (int)operation, pid, start, length, wait, cmd, err); | ||
| 48 | return err; | ||
| 49 | } | ||
| 50 | |||
| 51 | /** | ||
| 52 | * Attempt to set an fcntl lock. | ||
| 53 | * For now, this just goes away to the server. Later it may be more awesome. | ||
| 54 | */ | ||
| 55 | int ceph_lock(struct file *file, int cmd, struct file_lock *fl) | ||
| 56 | { | ||
| 57 | u64 length; | ||
| 58 | u8 lock_cmd; | ||
| 59 | int err; | ||
| 60 | u8 wait = 0; | ||
| 61 | u16 op = CEPH_MDS_OP_SETFILELOCK; | ||
| 62 | |||
| 63 | fl->fl_nspid = get_pid(task_tgid(current)); | ||
| 64 | dout("ceph_lock, fl_pid:%d", fl->fl_pid); | ||
| 65 | |||
| 66 | /* set wait bit as appropriate, then make command as Ceph expects it*/ | ||
| 67 | if (F_SETLKW == cmd) | ||
| 68 | wait = 1; | ||
| 69 | if (F_GETLK == cmd) | ||
| 70 | op = CEPH_MDS_OP_GETFILELOCK; | ||
| 71 | |||
| 72 | if (F_RDLCK == fl->fl_type) | ||
| 73 | lock_cmd = CEPH_LOCK_SHARED; | ||
| 74 | else if (F_WRLCK == fl->fl_type) | ||
| 75 | lock_cmd = CEPH_LOCK_EXCL; | ||
| 76 | else | ||
| 77 | lock_cmd = CEPH_LOCK_UNLOCK; | ||
| 78 | |||
| 79 | if (LLONG_MAX == fl->fl_end) | ||
| 80 | length = 0; | ||
| 81 | else | ||
| 82 | length = fl->fl_end - fl->fl_start + 1; | ||
| 83 | |||
| 84 | err = ceph_lock_message(CEPH_LOCK_FCNTL, op, file, | ||
| 85 | (u64)fl->fl_pid, (u64)fl->fl_nspid, | ||
| 86 | lock_cmd, fl->fl_start, | ||
| 87 | length, wait); | ||
| 88 | if (!err) { | ||
| 89 | dout("mds locked, locking locally"); | ||
| 90 | err = posix_lock_file(file, fl, NULL); | ||
| 91 | if (err && (CEPH_MDS_OP_SETFILELOCK == op)) { | ||
| 92 | /* undo! This should only happen if the kernel detects | ||
| 93 | * local deadlock. */ | ||
| 94 | ceph_lock_message(CEPH_LOCK_FCNTL, op, file, | ||
| 95 | (u64)fl->fl_pid, (u64)fl->fl_nspid, | ||
| 96 | CEPH_LOCK_UNLOCK, fl->fl_start, | ||
| 97 | length, 0); | ||
| 98 | dout("got %d on posix_lock_file, undid lock", err); | ||
| 99 | } | ||
| 100 | } else { | ||
| 101 | dout("mds returned error code %d", err); | ||
| 102 | } | ||
| 103 | return err; | ||
| 104 | } | ||
| 105 | |||
| 106 | int ceph_flock(struct file *file, int cmd, struct file_lock *fl) | ||
| 107 | { | ||
| 108 | u64 length; | ||
| 109 | u8 lock_cmd; | ||
| 110 | int err; | ||
| 111 | u8 wait = 1; | ||
| 112 | |||
| 113 | fl->fl_nspid = get_pid(task_tgid(current)); | ||
| 114 | dout("ceph_flock, fl_pid:%d", fl->fl_pid); | ||
| 115 | |||
| 116 | /* set wait bit, then clear it out of cmd*/ | ||
| 117 | if (cmd & LOCK_NB) | ||
| 118 | wait = 0; | ||
| 119 | cmd = cmd & (LOCK_SH | LOCK_EX | LOCK_UN); | ||
| 120 | /* set command sequence that Ceph wants to see: | ||
| 121 | shared lock, exclusive lock, or unlock */ | ||
| 122 | if (LOCK_SH == cmd) | ||
| 123 | lock_cmd = CEPH_LOCK_SHARED; | ||
| 124 | else if (LOCK_EX == cmd) | ||
| 125 | lock_cmd = CEPH_LOCK_EXCL; | ||
| 126 | else | ||
| 127 | lock_cmd = CEPH_LOCK_UNLOCK; | ||
| 128 | /* mds requires start and length rather than start and end */ | ||
| 129 | if (LLONG_MAX == fl->fl_end) | ||
| 130 | length = 0; | ||
| 131 | else | ||
| 132 | length = fl->fl_end - fl->fl_start + 1; | ||
| 133 | |||
| 134 | err = ceph_lock_message(CEPH_LOCK_FLOCK, CEPH_MDS_OP_SETFILELOCK, | ||
| 135 | file, (u64)fl->fl_pid, (u64)fl->fl_nspid, | ||
| 136 | lock_cmd, fl->fl_start, | ||
| 137 | length, wait); | ||
| 138 | if (!err) { | ||
| 139 | err = flock_lock_file_wait(file, fl); | ||
| 140 | if (err) { | ||
| 141 | ceph_lock_message(CEPH_LOCK_FLOCK, | ||
| 142 | CEPH_MDS_OP_SETFILELOCK, | ||
| 143 | file, (u64)fl->fl_pid, | ||
| 144 | (u64)fl->fl_nspid, | ||
| 145 | CEPH_LOCK_UNLOCK, fl->fl_start, | ||
| 146 | length, 0); | ||
| 147 | dout("got %d on flock_lock_file_wait, undid lock", err); | ||
| 148 | } | ||
| 149 | } else { | ||
| 150 | dout("mds error code %d", err); | ||
| 151 | } | ||
| 152 | return err; | ||
| 153 | } | ||
| 154 | |||
| 155 | /** | ||
| 156 | * Must be called with BKL already held. Fills in the passed | ||
| 157 | * counter variables, so you can prepare pagelist metadata before calling | ||
| 158 | * ceph_encode_locks. | ||
| 159 | */ | ||
| 160 | void ceph_count_locks(struct inode *inode, int *fcntl_count, int *flock_count) | ||
| 161 | { | ||
| 162 | struct file_lock *lock; | ||
| 163 | |||
| 164 | *fcntl_count = 0; | ||
| 165 | *flock_count = 0; | ||
| 166 | |||
| 167 | for (lock = inode->i_flock; lock != NULL; lock = lock->fl_next) { | ||
| 168 | if (lock->fl_flags & FL_POSIX) | ||
| 169 | ++(*fcntl_count); | ||
| 170 | else if (lock->fl_flags & FL_FLOCK) | ||
| 171 | ++(*flock_count); | ||
| 172 | } | ||
| 173 | dout("counted %d flock locks and %d fcntl locks", | ||
| 174 | *flock_count, *fcntl_count); | ||
| 175 | } | ||
| 176 | |||
| 177 | /** | ||
| 178 | * Encode the flock and fcntl locks for the given inode into the pagelist. | ||
| 179 | * Format is: #fcntl locks, sequential fcntl locks, #flock locks, | ||
| 180 | * sequential flock locks. | ||
| 181 | * Must be called with BLK already held, and the lock numbers should have | ||
| 182 | * been gathered under the same lock holding window. | ||
| 183 | */ | ||
| 184 | int ceph_encode_locks(struct inode *inode, struct ceph_pagelist *pagelist, | ||
| 185 | int num_fcntl_locks, int num_flock_locks) | ||
| 186 | { | ||
| 187 | struct file_lock *lock; | ||
| 188 | struct ceph_filelock cephlock; | ||
| 189 | int err = 0; | ||
| 190 | |||
| 191 | dout("encoding %d flock and %d fcntl locks", num_flock_locks, | ||
| 192 | num_fcntl_locks); | ||
| 193 | err = ceph_pagelist_append(pagelist, &num_fcntl_locks, sizeof(u32)); | ||
| 194 | if (err) | ||
| 195 | goto fail; | ||
| 196 | for (lock = inode->i_flock; lock != NULL; lock = lock->fl_next) { | ||
| 197 | if (lock->fl_flags & FL_POSIX) { | ||
| 198 | err = lock_to_ceph_filelock(lock, &cephlock); | ||
| 199 | if (err) | ||
| 200 | goto fail; | ||
| 201 | err = ceph_pagelist_append(pagelist, &cephlock, | ||
| 202 | sizeof(struct ceph_filelock)); | ||
| 203 | } | ||
| 204 | if (err) | ||
| 205 | goto fail; | ||
| 206 | } | ||
| 207 | |||
| 208 | err = ceph_pagelist_append(pagelist, &num_flock_locks, sizeof(u32)); | ||
| 209 | if (err) | ||
| 210 | goto fail; | ||
| 211 | for (lock = inode->i_flock; lock != NULL; lock = lock->fl_next) { | ||
| 212 | if (lock->fl_flags & FL_FLOCK) { | ||
| 213 | err = lock_to_ceph_filelock(lock, &cephlock); | ||
| 214 | if (err) | ||
| 215 | goto fail; | ||
| 216 | err = ceph_pagelist_append(pagelist, &cephlock, | ||
| 217 | sizeof(struct ceph_filelock)); | ||
| 218 | } | ||
| 219 | if (err) | ||
| 220 | goto fail; | ||
| 221 | } | ||
| 222 | fail: | ||
| 223 | return err; | ||
| 224 | } | ||
| 225 | |||
| 226 | /* | ||
| 227 | * Given a pointer to a lock, convert it to a ceph filelock | ||
| 228 | */ | ||
| 229 | int lock_to_ceph_filelock(struct file_lock *lock, | ||
| 230 | struct ceph_filelock *cephlock) | ||
| 231 | { | ||
| 232 | int err = 0; | ||
| 233 | |||
| 234 | cephlock->start = cpu_to_le64(lock->fl_start); | ||
| 235 | cephlock->length = cpu_to_le64(lock->fl_end - lock->fl_start + 1); | ||
| 236 | cephlock->client = cpu_to_le64(0); | ||
| 237 | cephlock->pid = cpu_to_le64(lock->fl_pid); | ||
| 238 | cephlock->pid_namespace = cpu_to_le64((u64)lock->fl_nspid); | ||
| 239 | |||
| 240 | switch (lock->fl_type) { | ||
| 241 | case F_RDLCK: | ||
| 242 | cephlock->type = CEPH_LOCK_SHARED; | ||
| 243 | break; | ||
| 244 | case F_WRLCK: | ||
| 245 | cephlock->type = CEPH_LOCK_EXCL; | ||
| 246 | break; | ||
| 247 | case F_UNLCK: | ||
| 248 | cephlock->type = CEPH_LOCK_UNLOCK; | ||
| 249 | break; | ||
| 250 | default: | ||
| 251 | dout("Have unknown lock type %d", lock->fl_type); | ||
| 252 | err = -EINVAL; | ||
| 253 | } | ||
| 254 | |||
| 255 | return err; | ||
| 256 | } | ||
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c index dd440bd438a9..a75ddbf9fe37 100644 --- a/fs/ceph/mds_client.c +++ b/fs/ceph/mds_client.c | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | #include <linux/wait.h> | 3 | #include <linux/wait.h> |
| 4 | #include <linux/slab.h> | 4 | #include <linux/slab.h> |
| 5 | #include <linux/sched.h> | 5 | #include <linux/sched.h> |
| 6 | #include <linux/smp_lock.h> | ||
| 6 | 7 | ||
| 7 | #include "mds_client.h" | 8 | #include "mds_client.h" |
| 8 | #include "mon_client.h" | 9 | #include "mon_client.h" |
| @@ -37,6 +38,11 @@ | |||
| 37 | * are no longer valid. | 38 | * are no longer valid. |
| 38 | */ | 39 | */ |
| 39 | 40 | ||
| 41 | struct ceph_reconnect_state { | ||
| 42 | struct ceph_pagelist *pagelist; | ||
| 43 | bool flock; | ||
| 44 | }; | ||
| 45 | |||
| 40 | static void __wake_requests(struct ceph_mds_client *mdsc, | 46 | static void __wake_requests(struct ceph_mds_client *mdsc, |
| 41 | struct list_head *head); | 47 | struct list_head *head); |
| 42 | 48 | ||
| @@ -449,7 +455,7 @@ void ceph_mdsc_release_request(struct kref *kref) | |||
| 449 | kfree(req->r_path1); | 455 | kfree(req->r_path1); |
| 450 | kfree(req->r_path2); | 456 | kfree(req->r_path2); |
| 451 | put_request_session(req); | 457 | put_request_session(req); |
| 452 | ceph_unreserve_caps(&req->r_caps_reservation); | 458 | ceph_unreserve_caps(req->r_mdsc, &req->r_caps_reservation); |
| 453 | kfree(req); | 459 | kfree(req); |
| 454 | } | 460 | } |
| 455 | 461 | ||
| @@ -512,7 +518,8 @@ static void __register_request(struct ceph_mds_client *mdsc, | |||
| 512 | { | 518 | { |
| 513 | req->r_tid = ++mdsc->last_tid; | 519 | req->r_tid = ++mdsc->last_tid; |
| 514 | if (req->r_num_caps) | 520 | if (req->r_num_caps) |
| 515 | ceph_reserve_caps(&req->r_caps_reservation, req->r_num_caps); | 521 | ceph_reserve_caps(mdsc, &req->r_caps_reservation, |
| 522 | req->r_num_caps); | ||
| 516 | dout("__register_request %p tid %lld\n", req, req->r_tid); | 523 | dout("__register_request %p tid %lld\n", req, req->r_tid); |
| 517 | ceph_mdsc_get_request(req); | 524 | ceph_mdsc_get_request(req); |
| 518 | __insert_request(mdsc, req); | 525 | __insert_request(mdsc, req); |
| @@ -704,6 +711,51 @@ static int __open_session(struct ceph_mds_client *mdsc, | |||
| 704 | } | 711 | } |
| 705 | 712 | ||
| 706 | /* | 713 | /* |
| 714 | * open sessions for any export targets for the given mds | ||
| 715 | * | ||
| 716 | * called under mdsc->mutex | ||
| 717 | */ | ||
| 718 | static void __open_export_target_sessions(struct ceph_mds_client *mdsc, | ||
| 719 | struct ceph_mds_session *session) | ||
| 720 | { | ||
| 721 | struct ceph_mds_info *mi; | ||
| 722 | struct ceph_mds_session *ts; | ||
| 723 | int i, mds = session->s_mds; | ||
| 724 | int target; | ||
| 725 | |||
| 726 | if (mds >= mdsc->mdsmap->m_max_mds) | ||
| 727 | return; | ||
| 728 | mi = &mdsc->mdsmap->m_info[mds]; | ||
| 729 | dout("open_export_target_sessions for mds%d (%d targets)\n", | ||
| 730 | session->s_mds, mi->num_export_targets); | ||
| 731 | |||
| 732 | for (i = 0; i < mi->num_export_targets; i++) { | ||
| 733 | target = mi->export_targets[i]; | ||
| 734 | ts = __ceph_lookup_mds_session(mdsc, target); | ||
| 735 | if (!ts) { | ||
| 736 | ts = register_session(mdsc, target); | ||
| 737 | if (IS_ERR(ts)) | ||
| 738 | return; | ||
| 739 | } | ||
| 740 | if (session->s_state == CEPH_MDS_SESSION_NEW || | ||
| 741 | session->s_state == CEPH_MDS_SESSION_CLOSING) | ||
| 742 | __open_session(mdsc, session); | ||
| 743 | else | ||
| 744 | dout(" mds%d target mds%d %p is %s\n", session->s_mds, | ||
| 745 | i, ts, session_state_name(ts->s_state)); | ||
| 746 | ceph_put_mds_session(ts); | ||
| 747 | } | ||
| 748 | } | ||
| 749 | |||
| 750 | void ceph_mdsc_open_export_target_sessions(struct ceph_mds_client *mdsc, | ||
| 751 | struct ceph_mds_session *session) | ||
| 752 | { | ||
| 753 | mutex_lock(&mdsc->mutex); | ||
| 754 | __open_export_target_sessions(mdsc, session); | ||
| 755 | mutex_unlock(&mdsc->mutex); | ||
| 756 | } | ||
| 757 | |||
| 758 | /* | ||
| 707 | * session caps | 759 | * session caps |
| 708 | */ | 760 | */ |
| 709 | 761 | ||
| @@ -764,7 +816,7 @@ static int iterate_session_caps(struct ceph_mds_session *session, | |||
| 764 | last_inode = NULL; | 816 | last_inode = NULL; |
| 765 | } | 817 | } |
| 766 | if (old_cap) { | 818 | if (old_cap) { |
| 767 | ceph_put_cap(old_cap); | 819 | ceph_put_cap(session->s_mdsc, old_cap); |
| 768 | old_cap = NULL; | 820 | old_cap = NULL; |
| 769 | } | 821 | } |
| 770 | 822 | ||
| @@ -793,7 +845,7 @@ out: | |||
| 793 | if (last_inode) | 845 | if (last_inode) |
| 794 | iput(last_inode); | 846 | iput(last_inode); |
| 795 | if (old_cap) | 847 | if (old_cap) |
| 796 | ceph_put_cap(old_cap); | 848 | ceph_put_cap(session->s_mdsc, old_cap); |
| 797 | 849 | ||
| 798 | return ret; | 850 | return ret; |
| 799 | } | 851 | } |
| @@ -1067,15 +1119,16 @@ static int trim_caps(struct ceph_mds_client *mdsc, | |||
| 1067 | * Called under s_mutex. | 1119 | * Called under s_mutex. |
| 1068 | */ | 1120 | */ |
| 1069 | int ceph_add_cap_releases(struct ceph_mds_client *mdsc, | 1121 | int ceph_add_cap_releases(struct ceph_mds_client *mdsc, |
| 1070 | struct ceph_mds_session *session, | 1122 | struct ceph_mds_session *session) |
| 1071 | int extra) | ||
| 1072 | { | 1123 | { |
| 1073 | struct ceph_msg *msg; | 1124 | struct ceph_msg *msg, *partial = NULL; |
| 1074 | struct ceph_mds_cap_release *head; | 1125 | struct ceph_mds_cap_release *head; |
| 1075 | int err = -ENOMEM; | 1126 | int err = -ENOMEM; |
| 1127 | int extra = mdsc->client->mount_args->cap_release_safety; | ||
| 1128 | int num; | ||
| 1076 | 1129 | ||
| 1077 | if (extra < 0) | 1130 | dout("add_cap_releases %p mds%d extra %d\n", session, session->s_mds, |
| 1078 | extra = mdsc->client->mount_args->cap_release_safety; | 1131 | extra); |
| 1079 | 1132 | ||
| 1080 | spin_lock(&session->s_cap_lock); | 1133 | spin_lock(&session->s_cap_lock); |
| 1081 | 1134 | ||
| @@ -1084,9 +1137,14 @@ int ceph_add_cap_releases(struct ceph_mds_client *mdsc, | |||
| 1084 | struct ceph_msg, | 1137 | struct ceph_msg, |
| 1085 | list_head); | 1138 | list_head); |
| 1086 | head = msg->front.iov_base; | 1139 | head = msg->front.iov_base; |
| 1087 | extra += CEPH_CAPS_PER_RELEASE - le32_to_cpu(head->num); | 1140 | num = le32_to_cpu(head->num); |
| 1141 | if (num) { | ||
| 1142 | dout(" partial %p with (%d/%d)\n", msg, num, | ||
| 1143 | (int)CEPH_CAPS_PER_RELEASE); | ||
| 1144 | extra += CEPH_CAPS_PER_RELEASE - num; | ||
| 1145 | partial = msg; | ||
| 1146 | } | ||
| 1088 | } | 1147 | } |
| 1089 | |||
| 1090 | while (session->s_num_cap_releases < session->s_nr_caps + extra) { | 1148 | while (session->s_num_cap_releases < session->s_nr_caps + extra) { |
| 1091 | spin_unlock(&session->s_cap_lock); | 1149 | spin_unlock(&session->s_cap_lock); |
| 1092 | msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPRELEASE, PAGE_CACHE_SIZE, | 1150 | msg = ceph_msg_new(CEPH_MSG_CLIENT_CAPRELEASE, PAGE_CACHE_SIZE, |
| @@ -1103,19 +1161,14 @@ int ceph_add_cap_releases(struct ceph_mds_client *mdsc, | |||
| 1103 | session->s_num_cap_releases += CEPH_CAPS_PER_RELEASE; | 1161 | session->s_num_cap_releases += CEPH_CAPS_PER_RELEASE; |
| 1104 | } | 1162 | } |
| 1105 | 1163 | ||
| 1106 | if (!list_empty(&session->s_cap_releases)) { | 1164 | if (partial) { |
| 1107 | msg = list_first_entry(&session->s_cap_releases, | 1165 | head = partial->front.iov_base; |
| 1108 | struct ceph_msg, | 1166 | num = le32_to_cpu(head->num); |
| 1109 | list_head); | 1167 | dout(" queueing partial %p with %d/%d\n", partial, num, |
| 1110 | head = msg->front.iov_base; | 1168 | (int)CEPH_CAPS_PER_RELEASE); |
| 1111 | if (head->num) { | 1169 | list_move_tail(&partial->list_head, |
| 1112 | dout(" queueing non-full %p (%d)\n", msg, | 1170 | &session->s_cap_releases_done); |
| 1113 | le32_to_cpu(head->num)); | 1171 | session->s_num_cap_releases -= CEPH_CAPS_PER_RELEASE - num; |
| 1114 | list_move_tail(&msg->list_head, | ||
| 1115 | &session->s_cap_releases_done); | ||
| 1116 | session->s_num_cap_releases -= | ||
| 1117 | CEPH_CAPS_PER_RELEASE - le32_to_cpu(head->num); | ||
| 1118 | } | ||
| 1119 | } | 1172 | } |
| 1120 | err = 0; | 1173 | err = 0; |
| 1121 | spin_unlock(&session->s_cap_lock); | 1174 | spin_unlock(&session->s_cap_lock); |
| @@ -1250,6 +1303,7 @@ ceph_mdsc_create_request(struct ceph_mds_client *mdsc, int op, int mode) | |||
| 1250 | return ERR_PTR(-ENOMEM); | 1303 | return ERR_PTR(-ENOMEM); |
| 1251 | 1304 | ||
| 1252 | mutex_init(&req->r_fill_mutex); | 1305 | mutex_init(&req->r_fill_mutex); |
| 1306 | req->r_mdsc = mdsc; | ||
| 1253 | req->r_started = jiffies; | 1307 | req->r_started = jiffies; |
| 1254 | req->r_resend_mds = -1; | 1308 | req->r_resend_mds = -1; |
| 1255 | INIT_LIST_HEAD(&req->r_unsafe_dir_item); | 1309 | INIT_LIST_HEAD(&req->r_unsafe_dir_item); |
| @@ -1580,6 +1634,15 @@ static int __prepare_send_request(struct ceph_mds_client *mdsc, | |||
| 1580 | 1634 | ||
| 1581 | req->r_mds = mds; | 1635 | req->r_mds = mds; |
| 1582 | req->r_attempts++; | 1636 | req->r_attempts++; |
| 1637 | if (req->r_inode) { | ||
| 1638 | struct ceph_cap *cap = | ||
| 1639 | ceph_get_cap_for_mds(ceph_inode(req->r_inode), mds); | ||
| 1640 | |||
| 1641 | if (cap) | ||
| 1642 | req->r_sent_on_mseq = cap->mseq; | ||
| 1643 | else | ||
| 1644 | req->r_sent_on_mseq = -1; | ||
| 1645 | } | ||
| 1583 | dout("prepare_send_request %p tid %lld %s (attempt %d)\n", req, | 1646 | dout("prepare_send_request %p tid %lld %s (attempt %d)\n", req, |
| 1584 | req->r_tid, ceph_mds_op_name(req->r_op), req->r_attempts); | 1647 | req->r_tid, ceph_mds_op_name(req->r_op), req->r_attempts); |
| 1585 | 1648 | ||
| @@ -1914,21 +1977,40 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg) | |||
| 1914 | result = le32_to_cpu(head->result); | 1977 | result = le32_to_cpu(head->result); |
| 1915 | 1978 | ||
| 1916 | /* | 1979 | /* |
| 1917 | * Tolerate 2 consecutive ESTALEs from the same mds. | 1980 | * Handle an ESTALE |
| 1918 | * FIXME: we should be looking at the cap migrate_seq. | 1981 | * if we're not talking to the authority, send to them |
| 1982 | * if the authority has changed while we weren't looking, | ||
| 1983 | * send to new authority | ||
| 1984 | * Otherwise we just have to return an ESTALE | ||
| 1919 | */ | 1985 | */ |
| 1920 | if (result == -ESTALE) { | 1986 | if (result == -ESTALE) { |
| 1921 | req->r_direct_mode = USE_AUTH_MDS; | 1987 | dout("got ESTALE on request %llu", req->r_tid); |
| 1922 | req->r_num_stale++; | 1988 | if (!req->r_inode) { |
| 1923 | if (req->r_num_stale <= 2) { | 1989 | /* do nothing; not an authority problem */ |
| 1990 | } else if (req->r_direct_mode != USE_AUTH_MDS) { | ||
| 1991 | dout("not using auth, setting for that now"); | ||
| 1992 | req->r_direct_mode = USE_AUTH_MDS; | ||
| 1924 | __do_request(mdsc, req); | 1993 | __do_request(mdsc, req); |
| 1925 | mutex_unlock(&mdsc->mutex); | 1994 | mutex_unlock(&mdsc->mutex); |
| 1926 | goto out; | 1995 | goto out; |
| 1996 | } else { | ||
| 1997 | struct ceph_inode_info *ci = ceph_inode(req->r_inode); | ||
| 1998 | struct ceph_cap *cap = | ||
| 1999 | ceph_get_cap_for_mds(ci, req->r_mds);; | ||
| 2000 | |||
| 2001 | dout("already using auth"); | ||
| 2002 | if ((!cap || cap != ci->i_auth_cap) || | ||
| 2003 | (cap->mseq != req->r_sent_on_mseq)) { | ||
| 2004 | dout("but cap changed, so resending"); | ||
| 2005 | __do_request(mdsc, req); | ||
| 2006 | mutex_unlock(&mdsc->mutex); | ||
| 2007 | goto out; | ||
| 2008 | } | ||
| 1927 | } | 2009 | } |
| 1928 | } else { | 2010 | dout("have to return ESTALE on request %llu", req->r_tid); |
| 1929 | req->r_num_stale = 0; | ||
| 1930 | } | 2011 | } |
| 1931 | 2012 | ||
| 2013 | |||
| 1932 | if (head->safe) { | 2014 | if (head->safe) { |
| 1933 | req->r_got_safe = true; | 2015 | req->r_got_safe = true; |
| 1934 | __unregister_request(mdsc, req); | 2016 | __unregister_request(mdsc, req); |
| @@ -1985,7 +2067,7 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg) | |||
| 1985 | if (err == 0) { | 2067 | if (err == 0) { |
| 1986 | if (result == 0 && rinfo->dir_nr) | 2068 | if (result == 0 && rinfo->dir_nr) |
| 1987 | ceph_readdir_prepopulate(req, req->r_session); | 2069 | ceph_readdir_prepopulate(req, req->r_session); |
| 1988 | ceph_unreserve_caps(&req->r_caps_reservation); | 2070 | ceph_unreserve_caps(mdsc, &req->r_caps_reservation); |
| 1989 | } | 2071 | } |
| 1990 | mutex_unlock(&req->r_fill_mutex); | 2072 | mutex_unlock(&req->r_fill_mutex); |
| 1991 | 2073 | ||
| @@ -2005,7 +2087,7 @@ out_err: | |||
| 2005 | } | 2087 | } |
| 2006 | mutex_unlock(&mdsc->mutex); | 2088 | mutex_unlock(&mdsc->mutex); |
| 2007 | 2089 | ||
| 2008 | ceph_add_cap_releases(mdsc, req->r_session, -1); | 2090 | ceph_add_cap_releases(mdsc, req->r_session); |
| 2009 | mutex_unlock(&session->s_mutex); | 2091 | mutex_unlock(&session->s_mutex); |
| 2010 | 2092 | ||
| 2011 | /* kick calling process */ | 2093 | /* kick calling process */ |
| @@ -2193,9 +2275,14 @@ static void replay_unsafe_requests(struct ceph_mds_client *mdsc, | |||
| 2193 | static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap, | 2275 | static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap, |
| 2194 | void *arg) | 2276 | void *arg) |
| 2195 | { | 2277 | { |
| 2196 | struct ceph_mds_cap_reconnect rec; | 2278 | union { |
| 2279 | struct ceph_mds_cap_reconnect v2; | ||
| 2280 | struct ceph_mds_cap_reconnect_v1 v1; | ||
| 2281 | } rec; | ||
| 2282 | size_t reclen; | ||
| 2197 | struct ceph_inode_info *ci; | 2283 | struct ceph_inode_info *ci; |
| 2198 | struct ceph_pagelist *pagelist = arg; | 2284 | struct ceph_reconnect_state *recon_state = arg; |
| 2285 | struct ceph_pagelist *pagelist = recon_state->pagelist; | ||
| 2199 | char *path; | 2286 | char *path; |
| 2200 | int pathlen, err; | 2287 | int pathlen, err; |
| 2201 | u64 pathbase; | 2288 | u64 pathbase; |
| @@ -2228,17 +2315,44 @@ static int encode_caps_cb(struct inode *inode, struct ceph_cap *cap, | |||
| 2228 | spin_lock(&inode->i_lock); | 2315 | spin_lock(&inode->i_lock); |
| 2229 | cap->seq = 0; /* reset cap seq */ | 2316 | cap->seq = 0; /* reset cap seq */ |
| 2230 | cap->issue_seq = 0; /* and issue_seq */ | 2317 | cap->issue_seq = 0; /* and issue_seq */ |
| 2231 | rec.cap_id = cpu_to_le64(cap->cap_id); | 2318 | |
| 2232 | rec.pathbase = cpu_to_le64(pathbase); | 2319 | if (recon_state->flock) { |
| 2233 | rec.wanted = cpu_to_le32(__ceph_caps_wanted(ci)); | 2320 | rec.v2.cap_id = cpu_to_le64(cap->cap_id); |
| 2234 | rec.issued = cpu_to_le32(cap->issued); | 2321 | rec.v2.wanted = cpu_to_le32(__ceph_caps_wanted(ci)); |
| 2235 | rec.size = cpu_to_le64(inode->i_size); | 2322 | rec.v2.issued = cpu_to_le32(cap->issued); |
| 2236 | ceph_encode_timespec(&rec.mtime, &inode->i_mtime); | 2323 | rec.v2.snaprealm = cpu_to_le64(ci->i_snap_realm->ino); |
| 2237 | ceph_encode_timespec(&rec.atime, &inode->i_atime); | 2324 | rec.v2.pathbase = cpu_to_le64(pathbase); |
| 2238 | rec.snaprealm = cpu_to_le64(ci->i_snap_realm->ino); | 2325 | rec.v2.flock_len = 0; |
| 2326 | reclen = sizeof(rec.v2); | ||
| 2327 | } else { | ||
| 2328 | rec.v1.cap_id = cpu_to_le64(cap->cap_id); | ||
| 2329 | rec.v1.wanted = cpu_to_le32(__ceph_caps_wanted(ci)); | ||
| 2330 | rec.v1.issued = cpu_to_le32(cap->issued); | ||
| 2331 | rec.v1.size = cpu_to_le64(inode->i_size); | ||
| 2332 | ceph_encode_timespec(&rec.v1.mtime, &inode->i_mtime); | ||
| 2333 | ceph_encode_timespec(&rec.v1.atime, &inode->i_atime); | ||
| 2334 | rec.v1.snaprealm = cpu_to_le64(ci->i_snap_realm->ino); | ||
| 2335 | rec.v1.pathbase = cpu_to_le64(pathbase); | ||
| 2336 | reclen = sizeof(rec.v1); | ||
| 2337 | } | ||
| 2239 | spin_unlock(&inode->i_lock); | 2338 | spin_unlock(&inode->i_lock); |
| 2240 | 2339 | ||
| 2241 | err = ceph_pagelist_append(pagelist, &rec, sizeof(rec)); | 2340 | if (recon_state->flock) { |
| 2341 | int num_fcntl_locks, num_flock_locks; | ||
| 2342 | |||
| 2343 | lock_kernel(); | ||
| 2344 | ceph_count_locks(inode, &num_fcntl_locks, &num_flock_locks); | ||
| 2345 | rec.v2.flock_len = (2*sizeof(u32) + | ||
| 2346 | (num_fcntl_locks+num_flock_locks) * | ||
| 2347 | sizeof(struct ceph_filelock)); | ||
| 2348 | |||
| 2349 | err = ceph_pagelist_append(pagelist, &rec, reclen); | ||
| 2350 | if (!err) | ||
| 2351 | err = ceph_encode_locks(inode, pagelist, | ||
| 2352 | num_fcntl_locks, | ||
| 2353 | num_flock_locks); | ||
| 2354 | unlock_kernel(); | ||
| 2355 | } | ||
| 2242 | 2356 | ||
| 2243 | out: | 2357 | out: |
| 2244 | kfree(path); | 2358 | kfree(path); |
| @@ -2267,6 +2381,7 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc, | |||
| 2267 | int mds = session->s_mds; | 2381 | int mds = session->s_mds; |
| 2268 | int err = -ENOMEM; | 2382 | int err = -ENOMEM; |
| 2269 | struct ceph_pagelist *pagelist; | 2383 | struct ceph_pagelist *pagelist; |
| 2384 | struct ceph_reconnect_state recon_state; | ||
| 2270 | 2385 | ||
| 2271 | pr_info("mds%d reconnect start\n", mds); | 2386 | pr_info("mds%d reconnect start\n", mds); |
| 2272 | 2387 | ||
| @@ -2301,7 +2416,10 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc, | |||
| 2301 | err = ceph_pagelist_encode_32(pagelist, session->s_nr_caps); | 2416 | err = ceph_pagelist_encode_32(pagelist, session->s_nr_caps); |
| 2302 | if (err) | 2417 | if (err) |
| 2303 | goto fail; | 2418 | goto fail; |
| 2304 | err = iterate_session_caps(session, encode_caps_cb, pagelist); | 2419 | |
| 2420 | recon_state.pagelist = pagelist; | ||
| 2421 | recon_state.flock = session->s_con.peer_features & CEPH_FEATURE_FLOCK; | ||
| 2422 | err = iterate_session_caps(session, encode_caps_cb, &recon_state); | ||
| 2305 | if (err < 0) | 2423 | if (err < 0) |
| 2306 | goto fail; | 2424 | goto fail; |
| 2307 | 2425 | ||
| @@ -2326,6 +2444,8 @@ static void send_mds_reconnect(struct ceph_mds_client *mdsc, | |||
| 2326 | } | 2444 | } |
| 2327 | 2445 | ||
| 2328 | reply->pagelist = pagelist; | 2446 | reply->pagelist = pagelist; |
| 2447 | if (recon_state.flock) | ||
| 2448 | reply->hdr.version = cpu_to_le16(2); | ||
| 2329 | reply->hdr.data_len = cpu_to_le32(pagelist->length); | 2449 | reply->hdr.data_len = cpu_to_le32(pagelist->length); |
| 2330 | reply->nr_pages = calc_pages_for(0, pagelist->length); | 2450 | reply->nr_pages = calc_pages_for(0, pagelist->length); |
| 2331 | ceph_con_send(&session->s_con, reply); | 2451 | ceph_con_send(&session->s_con, reply); |
| @@ -2376,9 +2496,11 @@ static void check_new_map(struct ceph_mds_client *mdsc, | |||
| 2376 | oldstate = ceph_mdsmap_get_state(oldmap, i); | 2496 | oldstate = ceph_mdsmap_get_state(oldmap, i); |
| 2377 | newstate = ceph_mdsmap_get_state(newmap, i); | 2497 | newstate = ceph_mdsmap_get_state(newmap, i); |
| 2378 | 2498 | ||
| 2379 | dout("check_new_map mds%d state %s -> %s (session %s)\n", | 2499 | dout("check_new_map mds%d state %s%s -> %s%s (session %s)\n", |
| 2380 | i, ceph_mds_state_name(oldstate), | 2500 | i, ceph_mds_state_name(oldstate), |
| 2501 | ceph_mdsmap_is_laggy(oldmap, i) ? " (laggy)" : "", | ||
| 2381 | ceph_mds_state_name(newstate), | 2502 | ceph_mds_state_name(newstate), |
| 2503 | ceph_mdsmap_is_laggy(newmap, i) ? " (laggy)" : "", | ||
| 2382 | session_state_name(s->s_state)); | 2504 | session_state_name(s->s_state)); |
| 2383 | 2505 | ||
| 2384 | if (memcmp(ceph_mdsmap_get_addr(oldmap, i), | 2506 | if (memcmp(ceph_mdsmap_get_addr(oldmap, i), |
| @@ -2428,6 +2550,21 @@ static void check_new_map(struct ceph_mds_client *mdsc, | |||
| 2428 | wake_up_session_caps(s, 1); | 2550 | wake_up_session_caps(s, 1); |
| 2429 | } | 2551 | } |
| 2430 | } | 2552 | } |
| 2553 | |||
| 2554 | for (i = 0; i < newmap->m_max_mds && i < mdsc->max_sessions; i++) { | ||
| 2555 | s = mdsc->sessions[i]; | ||
| 2556 | if (!s) | ||
| 2557 | continue; | ||
| 2558 | if (!ceph_mdsmap_is_laggy(newmap, i)) | ||
| 2559 | continue; | ||
| 2560 | if (s->s_state == CEPH_MDS_SESSION_OPEN || | ||
| 2561 | s->s_state == CEPH_MDS_SESSION_HUNG || | ||
| 2562 | s->s_state == CEPH_MDS_SESSION_CLOSING) { | ||
| 2563 | dout(" connecting to export targets of laggy mds%d\n", | ||
| 2564 | i); | ||
| 2565 | __open_export_target_sessions(mdsc, s); | ||
| 2566 | } | ||
| 2567 | } | ||
| 2431 | } | 2568 | } |
| 2432 | 2569 | ||
| 2433 | 2570 | ||
| @@ -2715,7 +2852,7 @@ static void delayed_work(struct work_struct *work) | |||
| 2715 | send_renew_caps(mdsc, s); | 2852 | send_renew_caps(mdsc, s); |
| 2716 | else | 2853 | else |
| 2717 | ceph_con_keepalive(&s->s_con); | 2854 | ceph_con_keepalive(&s->s_con); |
| 2718 | ceph_add_cap_releases(mdsc, s, -1); | 2855 | ceph_add_cap_releases(mdsc, s); |
| 2719 | if (s->s_state == CEPH_MDS_SESSION_OPEN || | 2856 | if (s->s_state == CEPH_MDS_SESSION_OPEN || |
| 2720 | s->s_state == CEPH_MDS_SESSION_HUNG) | 2857 | s->s_state == CEPH_MDS_SESSION_HUNG) |
| 2721 | ceph_send_cap_releases(mdsc, s); | 2858 | ceph_send_cap_releases(mdsc, s); |
| @@ -2764,6 +2901,9 @@ int ceph_mdsc_init(struct ceph_mds_client *mdsc, struct ceph_client *client) | |||
| 2764 | spin_lock_init(&mdsc->dentry_lru_lock); | 2901 | spin_lock_init(&mdsc->dentry_lru_lock); |
| 2765 | INIT_LIST_HEAD(&mdsc->dentry_lru); | 2902 | INIT_LIST_HEAD(&mdsc->dentry_lru); |
| 2766 | 2903 | ||
| 2904 | ceph_caps_init(mdsc); | ||
| 2905 | ceph_adjust_min_caps(mdsc, client->min_caps); | ||
| 2906 | |||
| 2767 | return 0; | 2907 | return 0; |
| 2768 | } | 2908 | } |
| 2769 | 2909 | ||
| @@ -2959,6 +3099,7 @@ void ceph_mdsc_stop(struct ceph_mds_client *mdsc) | |||
| 2959 | if (mdsc->mdsmap) | 3099 | if (mdsc->mdsmap) |
| 2960 | ceph_mdsmap_destroy(mdsc->mdsmap); | 3100 | ceph_mdsmap_destroy(mdsc->mdsmap); |
| 2961 | kfree(mdsc->sessions); | 3101 | kfree(mdsc->sessions); |
| 3102 | ceph_caps_finalize(mdsc); | ||
| 2962 | } | 3103 | } |
| 2963 | 3104 | ||
| 2964 | 3105 | ||
diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h index 952410c60d09..ab7e89f5e344 100644 --- a/fs/ceph/mds_client.h +++ b/fs/ceph/mds_client.h | |||
| @@ -151,6 +151,7 @@ typedef void (*ceph_mds_request_callback_t) (struct ceph_mds_client *mdsc, | |||
| 151 | struct ceph_mds_request { | 151 | struct ceph_mds_request { |
| 152 | u64 r_tid; /* transaction id */ | 152 | u64 r_tid; /* transaction id */ |
| 153 | struct rb_node r_node; | 153 | struct rb_node r_node; |
| 154 | struct ceph_mds_client *r_mdsc; | ||
| 154 | 155 | ||
| 155 | int r_op; /* mds op code */ | 156 | int r_op; /* mds op code */ |
| 156 | int r_mds; | 157 | int r_mds; |
| @@ -207,8 +208,8 @@ struct ceph_mds_request { | |||
| 207 | 208 | ||
| 208 | int r_attempts; /* resend attempts */ | 209 | int r_attempts; /* resend attempts */ |
| 209 | int r_num_fwd; /* number of forward attempts */ | 210 | int r_num_fwd; /* number of forward attempts */ |
| 210 | int r_num_stale; | ||
| 211 | int r_resend_mds; /* mds to resend to next, if any*/ | 211 | int r_resend_mds; /* mds to resend to next, if any*/ |
| 212 | u32 r_sent_on_mseq; /* cap mseq request was sent at*/ | ||
| 212 | 213 | ||
| 213 | struct kref r_kref; | 214 | struct kref r_kref; |
| 214 | struct list_head r_wait; | 215 | struct list_head r_wait; |
| @@ -267,6 +268,27 @@ struct ceph_mds_client { | |||
| 267 | spinlock_t cap_dirty_lock; /* protects above items */ | 268 | spinlock_t cap_dirty_lock; /* protects above items */ |
| 268 | wait_queue_head_t cap_flushing_wq; | 269 | wait_queue_head_t cap_flushing_wq; |
| 269 | 270 | ||
| 271 | /* | ||
| 272 | * Cap reservations | ||
| 273 | * | ||
| 274 | * Maintain a global pool of preallocated struct ceph_caps, referenced | ||
| 275 | * by struct ceph_caps_reservations. This ensures that we preallocate | ||
| 276 | * memory needed to successfully process an MDS response. (If an MDS | ||
| 277 | * sends us cap information and we fail to process it, we will have | ||
| 278 | * problems due to the client and MDS being out of sync.) | ||
| 279 | * | ||
| 280 | * Reservations are 'owned' by a ceph_cap_reservation context. | ||
| 281 | */ | ||
| 282 | spinlock_t caps_list_lock; | ||
| 283 | struct list_head caps_list; /* unused (reserved or | ||
| 284 | unreserved) */ | ||
| 285 | int caps_total_count; /* total caps allocated */ | ||
| 286 | int caps_use_count; /* in use */ | ||
| 287 | int caps_reserve_count; /* unused, reserved */ | ||
| 288 | int caps_avail_count; /* unused, unreserved */ | ||
| 289 | int caps_min_count; /* keep at least this many | ||
| 290 | (unreserved) */ | ||
| 291 | |||
| 270 | #ifdef CONFIG_DEBUG_FS | 292 | #ifdef CONFIG_DEBUG_FS |
| 271 | struct dentry *debugfs_file; | 293 | struct dentry *debugfs_file; |
| 272 | #endif | 294 | #endif |
| @@ -324,8 +346,7 @@ static inline void ceph_mdsc_put_request(struct ceph_mds_request *req) | |||
| 324 | } | 346 | } |
| 325 | 347 | ||
| 326 | extern int ceph_add_cap_releases(struct ceph_mds_client *mdsc, | 348 | extern int ceph_add_cap_releases(struct ceph_mds_client *mdsc, |
| 327 | struct ceph_mds_session *session, | 349 | struct ceph_mds_session *session); |
| 328 | int extra); | ||
| 329 | extern void ceph_send_cap_releases(struct ceph_mds_client *mdsc, | 350 | extern void ceph_send_cap_releases(struct ceph_mds_client *mdsc, |
| 330 | struct ceph_mds_session *session); | 351 | struct ceph_mds_session *session); |
| 331 | 352 | ||
| @@ -343,4 +364,7 @@ extern void ceph_mdsc_lease_send_msg(struct ceph_mds_session *session, | |||
| 343 | extern void ceph_mdsc_handle_map(struct ceph_mds_client *mdsc, | 364 | extern void ceph_mdsc_handle_map(struct ceph_mds_client *mdsc, |
| 344 | struct ceph_msg *msg); | 365 | struct ceph_msg *msg); |
| 345 | 366 | ||
| 367 | extern void ceph_mdsc_open_export_target_sessions(struct ceph_mds_client *mdsc, | ||
| 368 | struct ceph_mds_session *session); | ||
| 369 | |||
| 346 | #endif | 370 | #endif |
diff --git a/fs/ceph/mdsmap.c b/fs/ceph/mdsmap.c index c4c498e6dfef..040be6d1150b 100644 --- a/fs/ceph/mdsmap.c +++ b/fs/ceph/mdsmap.c | |||
| @@ -85,6 +85,7 @@ struct ceph_mdsmap *ceph_mdsmap_decode(void **p, void *end) | |||
| 85 | struct ceph_entity_addr addr; | 85 | struct ceph_entity_addr addr; |
| 86 | u32 num_export_targets; | 86 | u32 num_export_targets; |
| 87 | void *pexport_targets = NULL; | 87 | void *pexport_targets = NULL; |
| 88 | struct ceph_timespec laggy_since; | ||
| 88 | 89 | ||
| 89 | ceph_decode_need(p, end, sizeof(u64)*2 + 1 + sizeof(u32), bad); | 90 | ceph_decode_need(p, end, sizeof(u64)*2 + 1 + sizeof(u32), bad); |
| 90 | global_id = ceph_decode_64(p); | 91 | global_id = ceph_decode_64(p); |
| @@ -103,7 +104,7 @@ struct ceph_mdsmap *ceph_mdsmap_decode(void **p, void *end) | |||
| 103 | state_seq = ceph_decode_64(p); | 104 | state_seq = ceph_decode_64(p); |
| 104 | ceph_decode_copy(p, &addr, sizeof(addr)); | 105 | ceph_decode_copy(p, &addr, sizeof(addr)); |
| 105 | ceph_decode_addr(&addr); | 106 | ceph_decode_addr(&addr); |
| 106 | *p += sizeof(struct ceph_timespec); | 107 | ceph_decode_copy(p, &laggy_since, sizeof(laggy_since)); |
| 107 | *p += sizeof(u32); | 108 | *p += sizeof(u32); |
| 108 | ceph_decode_32_safe(p, end, namelen, bad); | 109 | ceph_decode_32_safe(p, end, namelen, bad); |
| 109 | *p += namelen; | 110 | *p += namelen; |
| @@ -122,6 +123,9 @@ struct ceph_mdsmap *ceph_mdsmap_decode(void **p, void *end) | |||
| 122 | m->m_info[mds].global_id = global_id; | 123 | m->m_info[mds].global_id = global_id; |
| 123 | m->m_info[mds].state = state; | 124 | m->m_info[mds].state = state; |
| 124 | m->m_info[mds].addr = addr; | 125 | m->m_info[mds].addr = addr; |
| 126 | m->m_info[mds].laggy = | ||
| 127 | (laggy_since.tv_sec != 0 || | ||
| 128 | laggy_since.tv_nsec != 0); | ||
| 125 | m->m_info[mds].num_export_targets = num_export_targets; | 129 | m->m_info[mds].num_export_targets = num_export_targets; |
| 126 | if (num_export_targets) { | 130 | if (num_export_targets) { |
| 127 | m->m_info[mds].export_targets = | 131 | m->m_info[mds].export_targets = |
diff --git a/fs/ceph/mdsmap.h b/fs/ceph/mdsmap.h index eacc131aa5cb..4c5cb0880bba 100644 --- a/fs/ceph/mdsmap.h +++ b/fs/ceph/mdsmap.h | |||
| @@ -13,6 +13,7 @@ struct ceph_mds_info { | |||
| 13 | struct ceph_entity_addr addr; | 13 | struct ceph_entity_addr addr; |
| 14 | s32 state; | 14 | s32 state; |
| 15 | int num_export_targets; | 15 | int num_export_targets; |
| 16 | bool laggy; | ||
| 16 | u32 *export_targets; | 17 | u32 *export_targets; |
| 17 | }; | 18 | }; |
| 18 | 19 | ||
| @@ -47,6 +48,13 @@ static inline int ceph_mdsmap_get_state(struct ceph_mdsmap *m, int w) | |||
| 47 | return m->m_info[w].state; | 48 | return m->m_info[w].state; |
| 48 | } | 49 | } |
| 49 | 50 | ||
| 51 | static inline bool ceph_mdsmap_is_laggy(struct ceph_mdsmap *m, int w) | ||
| 52 | { | ||
| 53 | if (w >= 0 && w < m->m_max_mds) | ||
| 54 | return m->m_info[w].laggy; | ||
| 55 | return false; | ||
| 56 | } | ||
| 57 | |||
| 50 | extern int ceph_mdsmap_get_random_mds(struct ceph_mdsmap *m); | 58 | extern int ceph_mdsmap_get_random_mds(struct ceph_mdsmap *m); |
| 51 | extern struct ceph_mdsmap *ceph_mdsmap_decode(void **p, void *end); | 59 | extern struct ceph_mdsmap *ceph_mdsmap_decode(void **p, void *end); |
| 52 | extern void ceph_mdsmap_destroy(struct ceph_mdsmap *m); | 60 | extern void ceph_mdsmap_destroy(struct ceph_mdsmap *m); |
diff --git a/fs/ceph/messenger.c b/fs/ceph/messenger.c index 15167b2daa55..2502d76fcec1 100644 --- a/fs/ceph/messenger.c +++ b/fs/ceph/messenger.c | |||
| @@ -108,7 +108,7 @@ void ceph_msgr_exit(void) | |||
| 108 | destroy_workqueue(ceph_msgr_wq); | 108 | destroy_workqueue(ceph_msgr_wq); |
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | void ceph_msgr_flush() | 111 | void ceph_msgr_flush(void) |
| 112 | { | 112 | { |
| 113 | flush_workqueue(ceph_msgr_wq); | 113 | flush_workqueue(ceph_msgr_wq); |
| 114 | } | 114 | } |
| @@ -647,7 +647,7 @@ static void prepare_write_connect(struct ceph_messenger *msgr, | |||
| 647 | dout("prepare_write_connect %p cseq=%d gseq=%d proto=%d\n", con, | 647 | dout("prepare_write_connect %p cseq=%d gseq=%d proto=%d\n", con, |
| 648 | con->connect_seq, global_seq, proto); | 648 | con->connect_seq, global_seq, proto); |
| 649 | 649 | ||
| 650 | con->out_connect.features = cpu_to_le64(CEPH_FEATURE_SUPPORTED_CLIENT); | 650 | con->out_connect.features = cpu_to_le64(CEPH_FEATURE_SUPPORTED); |
| 651 | con->out_connect.host_type = cpu_to_le32(CEPH_ENTITY_TYPE_CLIENT); | 651 | con->out_connect.host_type = cpu_to_le32(CEPH_ENTITY_TYPE_CLIENT); |
| 652 | con->out_connect.connect_seq = cpu_to_le32(con->connect_seq); | 652 | con->out_connect.connect_seq = cpu_to_le32(con->connect_seq); |
| 653 | con->out_connect.global_seq = cpu_to_le32(global_seq); | 653 | con->out_connect.global_seq = cpu_to_le32(global_seq); |
| @@ -1081,11 +1081,11 @@ static int process_banner(struct ceph_connection *con) | |||
| 1081 | sizeof(con->peer_addr)) != 0 && | 1081 | sizeof(con->peer_addr)) != 0 && |
| 1082 | !(addr_is_blank(&con->actual_peer_addr.in_addr) && | 1082 | !(addr_is_blank(&con->actual_peer_addr.in_addr) && |
| 1083 | con->actual_peer_addr.nonce == con->peer_addr.nonce)) { | 1083 | con->actual_peer_addr.nonce == con->peer_addr.nonce)) { |
| 1084 | pr_warning("wrong peer, want %s/%lld, got %s/%lld\n", | 1084 | pr_warning("wrong peer, want %s/%d, got %s/%d\n", |
| 1085 | pr_addr(&con->peer_addr.in_addr), | 1085 | pr_addr(&con->peer_addr.in_addr), |
| 1086 | le64_to_cpu(con->peer_addr.nonce), | 1086 | (int)le32_to_cpu(con->peer_addr.nonce), |
| 1087 | pr_addr(&con->actual_peer_addr.in_addr), | 1087 | pr_addr(&con->actual_peer_addr.in_addr), |
| 1088 | le64_to_cpu(con->actual_peer_addr.nonce)); | 1088 | (int)le32_to_cpu(con->actual_peer_addr.nonce)); |
| 1089 | con->error_msg = "wrong peer at address"; | 1089 | con->error_msg = "wrong peer at address"; |
| 1090 | return -1; | 1090 | return -1; |
| 1091 | } | 1091 | } |
| @@ -1123,8 +1123,8 @@ static void fail_protocol(struct ceph_connection *con) | |||
| 1123 | 1123 | ||
| 1124 | static int process_connect(struct ceph_connection *con) | 1124 | static int process_connect(struct ceph_connection *con) |
| 1125 | { | 1125 | { |
| 1126 | u64 sup_feat = CEPH_FEATURE_SUPPORTED_CLIENT; | 1126 | u64 sup_feat = CEPH_FEATURE_SUPPORTED; |
| 1127 | u64 req_feat = CEPH_FEATURE_REQUIRED_CLIENT; | 1127 | u64 req_feat = CEPH_FEATURE_REQUIRED; |
| 1128 | u64 server_feat = le64_to_cpu(con->in_reply.features); | 1128 | u64 server_feat = le64_to_cpu(con->in_reply.features); |
| 1129 | 1129 | ||
| 1130 | dout("process_connect on %p tag %d\n", con, (int)con->in_tag); | 1130 | dout("process_connect on %p tag %d\n", con, (int)con->in_tag); |
| @@ -1302,8 +1302,8 @@ static void process_ack(struct ceph_connection *con) | |||
| 1302 | 1302 | ||
| 1303 | 1303 | ||
| 1304 | static int read_partial_message_section(struct ceph_connection *con, | 1304 | static int read_partial_message_section(struct ceph_connection *con, |
| 1305 | struct kvec *section, unsigned int sec_len, | 1305 | struct kvec *section, |
| 1306 | u32 *crc) | 1306 | unsigned int sec_len, u32 *crc) |
| 1307 | { | 1307 | { |
| 1308 | int left; | 1308 | int left; |
| 1309 | int ret; | 1309 | int ret; |
| @@ -1434,7 +1434,8 @@ static int read_partial_message(struct ceph_connection *con) | |||
| 1434 | 1434 | ||
| 1435 | /* middle */ | 1435 | /* middle */ |
| 1436 | if (m->middle) { | 1436 | if (m->middle) { |
| 1437 | ret = read_partial_message_section(con, &m->middle->vec, middle_len, | 1437 | ret = read_partial_message_section(con, &m->middle->vec, |
| 1438 | middle_len, | ||
| 1438 | &con->in_middle_crc); | 1439 | &con->in_middle_crc); |
| 1439 | if (ret <= 0) | 1440 | if (ret <= 0) |
| 1440 | return ret; | 1441 | return ret; |
| @@ -1920,7 +1921,7 @@ out: | |||
| 1920 | /* | 1921 | /* |
| 1921 | * in case we faulted due to authentication, invalidate our | 1922 | * in case we faulted due to authentication, invalidate our |
| 1922 | * current tickets so that we can get new ones. | 1923 | * current tickets so that we can get new ones. |
| 1923 | */ | 1924 | */ |
| 1924 | if (con->auth_retry && con->ops->invalidate_authorizer) { | 1925 | if (con->auth_retry && con->ops->invalidate_authorizer) { |
| 1925 | dout("calling invalidate_authorizer()\n"); | 1926 | dout("calling invalidate_authorizer()\n"); |
| 1926 | con->ops->invalidate_authorizer(con); | 1927 | con->ops->invalidate_authorizer(con); |
diff --git a/fs/ceph/mon_client.c b/fs/ceph/mon_client.c index 54fe01c50706..b2a5a3e4a671 100644 --- a/fs/ceph/mon_client.c +++ b/fs/ceph/mon_client.c | |||
| @@ -349,7 +349,7 @@ out: | |||
| 349 | } | 349 | } |
| 350 | 350 | ||
| 351 | /* | 351 | /* |
| 352 | * statfs | 352 | * generic requests (e.g., statfs, poolop) |
| 353 | */ | 353 | */ |
| 354 | static struct ceph_mon_generic_request *__lookup_generic_req( | 354 | static struct ceph_mon_generic_request *__lookup_generic_req( |
| 355 | struct ceph_mon_client *monc, u64 tid) | 355 | struct ceph_mon_client *monc, u64 tid) |
| @@ -442,6 +442,35 @@ static struct ceph_msg *get_generic_reply(struct ceph_connection *con, | |||
| 442 | return m; | 442 | return m; |
| 443 | } | 443 | } |
| 444 | 444 | ||
| 445 | static int do_generic_request(struct ceph_mon_client *monc, | ||
| 446 | struct ceph_mon_generic_request *req) | ||
| 447 | { | ||
| 448 | int err; | ||
| 449 | |||
| 450 | /* register request */ | ||
| 451 | mutex_lock(&monc->mutex); | ||
| 452 | req->tid = ++monc->last_tid; | ||
| 453 | req->request->hdr.tid = cpu_to_le64(req->tid); | ||
| 454 | __insert_generic_request(monc, req); | ||
| 455 | monc->num_generic_requests++; | ||
| 456 | ceph_con_send(monc->con, ceph_msg_get(req->request)); | ||
| 457 | mutex_unlock(&monc->mutex); | ||
| 458 | |||
| 459 | err = wait_for_completion_interruptible(&req->completion); | ||
| 460 | |||
| 461 | mutex_lock(&monc->mutex); | ||
| 462 | rb_erase(&req->node, &monc->generic_request_tree); | ||
| 463 | monc->num_generic_requests--; | ||
| 464 | mutex_unlock(&monc->mutex); | ||
| 465 | |||
| 466 | if (!err) | ||
| 467 | err = req->result; | ||
| 468 | return err; | ||
| 469 | } | ||
| 470 | |||
| 471 | /* | ||
| 472 | * statfs | ||
| 473 | */ | ||
| 445 | static void handle_statfs_reply(struct ceph_mon_client *monc, | 474 | static void handle_statfs_reply(struct ceph_mon_client *monc, |
| 446 | struct ceph_msg *msg) | 475 | struct ceph_msg *msg) |
| 447 | { | 476 | { |
| @@ -468,7 +497,7 @@ static void handle_statfs_reply(struct ceph_mon_client *monc, | |||
| 468 | return; | 497 | return; |
| 469 | 498 | ||
| 470 | bad: | 499 | bad: |
| 471 | pr_err("corrupt generic reply, no tid\n"); | 500 | pr_err("corrupt generic reply, tid %llu\n", tid); |
| 472 | ceph_msg_dump(msg); | 501 | ceph_msg_dump(msg); |
| 473 | } | 502 | } |
| 474 | 503 | ||
| @@ -487,6 +516,7 @@ int ceph_monc_do_statfs(struct ceph_mon_client *monc, struct ceph_statfs *buf) | |||
| 487 | 516 | ||
| 488 | kref_init(&req->kref); | 517 | kref_init(&req->kref); |
| 489 | req->buf = buf; | 518 | req->buf = buf; |
| 519 | req->buf_len = sizeof(*buf); | ||
| 490 | init_completion(&req->completion); | 520 | init_completion(&req->completion); |
| 491 | 521 | ||
| 492 | err = -ENOMEM; | 522 | err = -ENOMEM; |
| @@ -504,33 +534,134 @@ int ceph_monc_do_statfs(struct ceph_mon_client *monc, struct ceph_statfs *buf) | |||
| 504 | h->monhdr.session_mon_tid = 0; | 534 | h->monhdr.session_mon_tid = 0; |
| 505 | h->fsid = monc->monmap->fsid; | 535 | h->fsid = monc->monmap->fsid; |
| 506 | 536 | ||
| 507 | /* register request */ | 537 | err = do_generic_request(monc, req); |
| 508 | mutex_lock(&monc->mutex); | ||
| 509 | req->tid = ++monc->last_tid; | ||
| 510 | req->request->hdr.tid = cpu_to_le64(req->tid); | ||
| 511 | __insert_generic_request(monc, req); | ||
| 512 | monc->num_generic_requests++; | ||
| 513 | mutex_unlock(&monc->mutex); | ||
| 514 | 538 | ||
| 515 | /* send request and wait */ | 539 | out: |
| 516 | ceph_con_send(monc->con, ceph_msg_get(req->request)); | 540 | kref_put(&req->kref, release_generic_request); |
| 517 | err = wait_for_completion_interruptible(&req->completion); | 541 | return err; |
| 542 | } | ||
| 543 | |||
| 544 | /* | ||
| 545 | * pool ops | ||
| 546 | */ | ||
| 547 | static int get_poolop_reply_buf(const char *src, size_t src_len, | ||
| 548 | char *dst, size_t dst_len) | ||
| 549 | { | ||
| 550 | u32 buf_len; | ||
| 551 | |||
| 552 | if (src_len != sizeof(u32) + dst_len) | ||
| 553 | return -EINVAL; | ||
| 554 | |||
| 555 | buf_len = le32_to_cpu(*(u32 *)src); | ||
| 556 | if (buf_len != dst_len) | ||
| 557 | return -EINVAL; | ||
| 558 | |||
| 559 | memcpy(dst, src + sizeof(u32), dst_len); | ||
| 560 | return 0; | ||
| 561 | } | ||
| 562 | |||
| 563 | static void handle_poolop_reply(struct ceph_mon_client *monc, | ||
| 564 | struct ceph_msg *msg) | ||
| 565 | { | ||
| 566 | struct ceph_mon_generic_request *req; | ||
| 567 | struct ceph_mon_poolop_reply *reply = msg->front.iov_base; | ||
| 568 | u64 tid = le64_to_cpu(msg->hdr.tid); | ||
| 569 | |||
| 570 | if (msg->front.iov_len < sizeof(*reply)) | ||
| 571 | goto bad; | ||
| 572 | dout("handle_poolop_reply %p tid %llu\n", msg, tid); | ||
| 518 | 573 | ||
| 519 | mutex_lock(&monc->mutex); | 574 | mutex_lock(&monc->mutex); |
| 520 | rb_erase(&req->node, &monc->generic_request_tree); | 575 | req = __lookup_generic_req(monc, tid); |
| 521 | monc->num_generic_requests--; | 576 | if (req) { |
| 577 | if (req->buf_len && | ||
| 578 | get_poolop_reply_buf(msg->front.iov_base + sizeof(*reply), | ||
| 579 | msg->front.iov_len - sizeof(*reply), | ||
| 580 | req->buf, req->buf_len) < 0) { | ||
| 581 | mutex_unlock(&monc->mutex); | ||
| 582 | goto bad; | ||
| 583 | } | ||
| 584 | req->result = le32_to_cpu(reply->reply_code); | ||
| 585 | get_generic_request(req); | ||
| 586 | } | ||
| 522 | mutex_unlock(&monc->mutex); | 587 | mutex_unlock(&monc->mutex); |
| 588 | if (req) { | ||
| 589 | complete(&req->completion); | ||
| 590 | put_generic_request(req); | ||
| 591 | } | ||
| 592 | return; | ||
| 523 | 593 | ||
| 524 | if (!err) | 594 | bad: |
| 525 | err = req->result; | 595 | pr_err("corrupt generic reply, tid %llu\n", tid); |
| 596 | ceph_msg_dump(msg); | ||
| 597 | } | ||
| 598 | |||
| 599 | /* | ||
| 600 | * Do a synchronous pool op. | ||
| 601 | */ | ||
| 602 | int ceph_monc_do_poolop(struct ceph_mon_client *monc, u32 op, | ||
| 603 | u32 pool, u64 snapid, | ||
| 604 | char *buf, int len) | ||
| 605 | { | ||
| 606 | struct ceph_mon_generic_request *req; | ||
| 607 | struct ceph_mon_poolop *h; | ||
| 608 | int err; | ||
| 609 | |||
| 610 | req = kzalloc(sizeof(*req), GFP_NOFS); | ||
| 611 | if (!req) | ||
| 612 | return -ENOMEM; | ||
| 613 | |||
| 614 | kref_init(&req->kref); | ||
| 615 | req->buf = buf; | ||
| 616 | req->buf_len = len; | ||
| 617 | init_completion(&req->completion); | ||
| 618 | |||
| 619 | err = -ENOMEM; | ||
| 620 | req->request = ceph_msg_new(CEPH_MSG_POOLOP, sizeof(*h), GFP_NOFS); | ||
| 621 | if (!req->request) | ||
| 622 | goto out; | ||
| 623 | req->reply = ceph_msg_new(CEPH_MSG_POOLOP_REPLY, 1024, GFP_NOFS); | ||
| 624 | if (!req->reply) | ||
| 625 | goto out; | ||
| 626 | |||
| 627 | /* fill out request */ | ||
| 628 | req->request->hdr.version = cpu_to_le16(2); | ||
| 629 | h = req->request->front.iov_base; | ||
| 630 | h->monhdr.have_version = 0; | ||
| 631 | h->monhdr.session_mon = cpu_to_le16(-1); | ||
| 632 | h->monhdr.session_mon_tid = 0; | ||
| 633 | h->fsid = monc->monmap->fsid; | ||
| 634 | h->pool = cpu_to_le32(pool); | ||
| 635 | h->op = cpu_to_le32(op); | ||
| 636 | h->auid = 0; | ||
| 637 | h->snapid = cpu_to_le64(snapid); | ||
| 638 | h->name_len = 0; | ||
| 639 | |||
| 640 | err = do_generic_request(monc, req); | ||
| 526 | 641 | ||
| 527 | out: | 642 | out: |
| 528 | kref_put(&req->kref, release_generic_request); | 643 | kref_put(&req->kref, release_generic_request); |
| 529 | return err; | 644 | return err; |
| 530 | } | 645 | } |
| 531 | 646 | ||
| 647 | int ceph_monc_create_snapid(struct ceph_mon_client *monc, | ||
| 648 | u32 pool, u64 *snapid) | ||
| 649 | { | ||
| 650 | return ceph_monc_do_poolop(monc, POOL_OP_CREATE_UNMANAGED_SNAP, | ||
| 651 | pool, 0, (char *)snapid, sizeof(*snapid)); | ||
| 652 | |||
| 653 | } | ||
| 654 | |||
| 655 | int ceph_monc_delete_snapid(struct ceph_mon_client *monc, | ||
| 656 | u32 pool, u64 snapid) | ||
| 657 | { | ||
| 658 | return ceph_monc_do_poolop(monc, POOL_OP_CREATE_UNMANAGED_SNAP, | ||
| 659 | pool, snapid, 0, 0); | ||
| 660 | |||
| 661 | } | ||
| 662 | |||
| 532 | /* | 663 | /* |
| 533 | * Resend pending statfs requests. | 664 | * Resend pending generic requests. |
| 534 | */ | 665 | */ |
| 535 | static void __resend_generic_request(struct ceph_mon_client *monc) | 666 | static void __resend_generic_request(struct ceph_mon_client *monc) |
| 536 | { | 667 | { |
| @@ -783,6 +914,10 @@ static void dispatch(struct ceph_connection *con, struct ceph_msg *msg) | |||
| 783 | handle_statfs_reply(monc, msg); | 914 | handle_statfs_reply(monc, msg); |
| 784 | break; | 915 | break; |
| 785 | 916 | ||
| 917 | case CEPH_MSG_POOLOP_REPLY: | ||
| 918 | handle_poolop_reply(monc, msg); | ||
| 919 | break; | ||
| 920 | |||
| 786 | case CEPH_MSG_MON_MAP: | 921 | case CEPH_MSG_MON_MAP: |
| 787 | ceph_monc_handle_map(monc, msg); | 922 | ceph_monc_handle_map(monc, msg); |
| 788 | break; | 923 | break; |
| @@ -820,6 +955,7 @@ static struct ceph_msg *mon_alloc_msg(struct ceph_connection *con, | |||
| 820 | case CEPH_MSG_MON_SUBSCRIBE_ACK: | 955 | case CEPH_MSG_MON_SUBSCRIBE_ACK: |
| 821 | m = ceph_msg_get(monc->m_subscribe_ack); | 956 | m = ceph_msg_get(monc->m_subscribe_ack); |
| 822 | break; | 957 | break; |
| 958 | case CEPH_MSG_POOLOP_REPLY: | ||
| 823 | case CEPH_MSG_STATFS_REPLY: | 959 | case CEPH_MSG_STATFS_REPLY: |
| 824 | return get_generic_reply(con, hdr, skip); | 960 | return get_generic_reply(con, hdr, skip); |
| 825 | case CEPH_MSG_AUTH_REPLY: | 961 | case CEPH_MSG_AUTH_REPLY: |
diff --git a/fs/ceph/mon_client.h b/fs/ceph/mon_client.h index 174d794321d0..8e396f2c0963 100644 --- a/fs/ceph/mon_client.h +++ b/fs/ceph/mon_client.h | |||
| @@ -50,6 +50,7 @@ struct ceph_mon_generic_request { | |||
| 50 | struct rb_node node; | 50 | struct rb_node node; |
| 51 | int result; | 51 | int result; |
| 52 | void *buf; | 52 | void *buf; |
| 53 | int buf_len; | ||
| 53 | struct completion completion; | 54 | struct completion completion; |
| 54 | struct ceph_msg *request; /* original request */ | 55 | struct ceph_msg *request; /* original request */ |
| 55 | struct ceph_msg *reply; /* and reply */ | 56 | struct ceph_msg *reply; /* and reply */ |
| @@ -111,6 +112,10 @@ extern int ceph_monc_open_session(struct ceph_mon_client *monc); | |||
| 111 | 112 | ||
| 112 | extern int ceph_monc_validate_auth(struct ceph_mon_client *monc); | 113 | extern int ceph_monc_validate_auth(struct ceph_mon_client *monc); |
| 113 | 114 | ||
| 115 | extern int ceph_monc_create_snapid(struct ceph_mon_client *monc, | ||
| 116 | u32 pool, u64 *snapid); | ||
| 114 | 117 | ||
| 118 | extern int ceph_monc_delete_snapid(struct ceph_mon_client *monc, | ||
| 119 | u32 pool, u64 snapid); | ||
| 115 | 120 | ||
| 116 | #endif | 121 | #endif |
diff --git a/fs/ceph/msgr.h b/fs/ceph/msgr.h index 892a0298dfdf..680d3d648cac 100644 --- a/fs/ceph/msgr.h +++ b/fs/ceph/msgr.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #ifndef __MSGR_H | 1 | #ifndef CEPH_MSGR_H |
| 2 | #define __MSGR_H | 2 | #define CEPH_MSGR_H |
| 3 | 3 | ||
| 4 | /* | 4 | /* |
| 5 | * Data types for message passing layer used by Ceph. | 5 | * Data types for message passing layer used by Ceph. |
diff --git a/fs/ceph/osd_client.c b/fs/ceph/osd_client.c index e38522347898..bed6391e52c7 100644 --- a/fs/ceph/osd_client.c +++ b/fs/ceph/osd_client.c | |||
| @@ -1276,8 +1276,6 @@ int ceph_osdc_readpages(struct ceph_osd_client *osdc, | |||
| 1276 | 1276 | ||
| 1277 | /* it may be a short read due to an object boundary */ | 1277 | /* it may be a short read due to an object boundary */ |
| 1278 | req->r_pages = pages; | 1278 | req->r_pages = pages; |
| 1279 | num_pages = calc_pages_for(off, *plen); | ||
| 1280 | req->r_num_pages = num_pages; | ||
| 1281 | 1279 | ||
| 1282 | dout("readpages final extent is %llu~%llu (%d pages)\n", | 1280 | dout("readpages final extent is %llu~%llu (%d pages)\n", |
| 1283 | off, *plen, req->r_num_pages); | 1281 | off, *plen, req->r_num_pages); |
| @@ -1319,7 +1317,6 @@ int ceph_osdc_writepages(struct ceph_osd_client *osdc, struct ceph_vino vino, | |||
| 1319 | 1317 | ||
| 1320 | /* it may be a short write due to an object boundary */ | 1318 | /* it may be a short write due to an object boundary */ |
| 1321 | req->r_pages = pages; | 1319 | req->r_pages = pages; |
| 1322 | req->r_num_pages = calc_pages_for(off, len); | ||
| 1323 | dout("writepages %llu~%llu (%d pages)\n", off, len, | 1320 | dout("writepages %llu~%llu (%d pages)\n", off, len, |
| 1324 | req->r_num_pages); | 1321 | req->r_num_pages); |
| 1325 | 1322 | ||
| @@ -1476,8 +1473,8 @@ static void put_osd_con(struct ceph_connection *con) | |||
| 1476 | * authentication | 1473 | * authentication |
| 1477 | */ | 1474 | */ |
| 1478 | static int get_authorizer(struct ceph_connection *con, | 1475 | static int get_authorizer(struct ceph_connection *con, |
| 1479 | void **buf, int *len, int *proto, | 1476 | void **buf, int *len, int *proto, |
| 1480 | void **reply_buf, int *reply_len, int force_new) | 1477 | void **reply_buf, int *reply_len, int force_new) |
| 1481 | { | 1478 | { |
| 1482 | struct ceph_osd *o = con->private; | 1479 | struct ceph_osd *o = con->private; |
| 1483 | struct ceph_osd_client *osdc = o->o_osdc; | 1480 | struct ceph_osd_client *osdc = o->o_osdc; |
| @@ -1497,7 +1494,7 @@ static int get_authorizer(struct ceph_connection *con, | |||
| 1497 | &o->o_authorizer_reply_buf, | 1494 | &o->o_authorizer_reply_buf, |
| 1498 | &o->o_authorizer_reply_buf_len); | 1495 | &o->o_authorizer_reply_buf_len); |
| 1499 | if (ret) | 1496 | if (ret) |
| 1500 | return ret; | 1497 | return ret; |
| 1501 | } | 1498 | } |
| 1502 | 1499 | ||
| 1503 | *proto = ac->protocol; | 1500 | *proto = ac->protocol; |
diff --git a/fs/ceph/osdmap.c b/fs/ceph/osdmap.c index 416d46adbf87..e31f118f1392 100644 --- a/fs/ceph/osdmap.c +++ b/fs/ceph/osdmap.c | |||
| @@ -424,12 +424,30 @@ static void __remove_pg_pool(struct rb_root *root, struct ceph_pg_pool_info *pi) | |||
| 424 | kfree(pi); | 424 | kfree(pi); |
| 425 | } | 425 | } |
| 426 | 426 | ||
| 427 | void __decode_pool(void **p, struct ceph_pg_pool_info *pi) | 427 | static int __decode_pool(void **p, void *end, struct ceph_pg_pool_info *pi) |
| 428 | { | 428 | { |
| 429 | unsigned n, m; | ||
| 430 | |||
| 429 | ceph_decode_copy(p, &pi->v, sizeof(pi->v)); | 431 | ceph_decode_copy(p, &pi->v, sizeof(pi->v)); |
| 430 | calc_pg_masks(pi); | 432 | calc_pg_masks(pi); |
| 431 | *p += le32_to_cpu(pi->v.num_snaps) * sizeof(u64); | 433 | |
| 434 | /* num_snaps * snap_info_t */ | ||
| 435 | n = le32_to_cpu(pi->v.num_snaps); | ||
| 436 | while (n--) { | ||
| 437 | ceph_decode_need(p, end, sizeof(u64) + 1 + sizeof(u64) + | ||
| 438 | sizeof(struct ceph_timespec), bad); | ||
| 439 | *p += sizeof(u64) + /* key */ | ||
| 440 | 1 + sizeof(u64) + /* u8, snapid */ | ||
| 441 | sizeof(struct ceph_timespec); | ||
| 442 | m = ceph_decode_32(p); /* snap name */ | ||
| 443 | *p += m; | ||
| 444 | } | ||
| 445 | |||
| 432 | *p += le32_to_cpu(pi->v.num_removed_snap_intervals) * sizeof(u64) * 2; | 446 | *p += le32_to_cpu(pi->v.num_removed_snap_intervals) * sizeof(u64) * 2; |
| 447 | return 0; | ||
| 448 | |||
| 449 | bad: | ||
| 450 | return -EINVAL; | ||
| 433 | } | 451 | } |
| 434 | 452 | ||
| 435 | static int __decode_pool_names(void **p, void *end, struct ceph_osdmap *map) | 453 | static int __decode_pool_names(void **p, void *end, struct ceph_osdmap *map) |
| @@ -571,7 +589,9 @@ struct ceph_osdmap *osdmap_decode(void **p, void *end) | |||
| 571 | kfree(pi); | 589 | kfree(pi); |
| 572 | goto bad; | 590 | goto bad; |
| 573 | } | 591 | } |
| 574 | __decode_pool(p, pi); | 592 | err = __decode_pool(p, end, pi); |
| 593 | if (err < 0) | ||
| 594 | goto bad; | ||
| 575 | __insert_pg_pool(&map->pg_pools, pi); | 595 | __insert_pg_pool(&map->pg_pools, pi); |
| 576 | } | 596 | } |
| 577 | 597 | ||
| @@ -760,7 +780,9 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end, | |||
| 760 | pi->id = pool; | 780 | pi->id = pool; |
| 761 | __insert_pg_pool(&map->pg_pools, pi); | 781 | __insert_pg_pool(&map->pg_pools, pi); |
| 762 | } | 782 | } |
| 763 | __decode_pool(p, pi); | 783 | err = __decode_pool(p, end, pi); |
| 784 | if (err < 0) | ||
| 785 | goto bad; | ||
| 764 | } | 786 | } |
| 765 | if (version >= 5 && __decode_pool_names(p, end, map) < 0) | 787 | if (version >= 5 && __decode_pool_names(p, end, map) < 0) |
| 766 | goto bad; | 788 | goto bad; |
| @@ -833,7 +855,7 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end, | |||
| 833 | node)->pgid, pgid) <= 0) { | 855 | node)->pgid, pgid) <= 0) { |
| 834 | struct ceph_pg_mapping *cur = | 856 | struct ceph_pg_mapping *cur = |
| 835 | rb_entry(rbp, struct ceph_pg_mapping, node); | 857 | rb_entry(rbp, struct ceph_pg_mapping, node); |
| 836 | 858 | ||
| 837 | rbp = rb_next(rbp); | 859 | rbp = rb_next(rbp); |
| 838 | dout(" removed pg_temp %llx\n", *(u64 *)&cur->pgid); | 860 | dout(" removed pg_temp %llx\n", *(u64 *)&cur->pgid); |
| 839 | rb_erase(&cur->node, &map->pg_temp); | 861 | rb_erase(&cur->node, &map->pg_temp); |
| @@ -1026,8 +1048,9 @@ static int *calc_pg_raw(struct ceph_osdmap *osdmap, struct ceph_pg pgid, | |||
| 1026 | ruleno = crush_find_rule(osdmap->crush, pool->v.crush_ruleset, | 1048 | ruleno = crush_find_rule(osdmap->crush, pool->v.crush_ruleset, |
| 1027 | pool->v.type, pool->v.size); | 1049 | pool->v.type, pool->v.size); |
| 1028 | if (ruleno < 0) { | 1050 | if (ruleno < 0) { |
| 1029 | pr_err("no crush rule pool %d type %d size %d\n", | 1051 | pr_err("no crush rule pool %d ruleset %d type %d size %d\n", |
| 1030 | poolid, pool->v.type, pool->v.size); | 1052 | poolid, pool->v.crush_ruleset, pool->v.type, |
| 1053 | pool->v.size); | ||
| 1031 | return NULL; | 1054 | return NULL; |
| 1032 | } | 1055 | } |
| 1033 | 1056 | ||
diff --git a/fs/ceph/rados.h b/fs/ceph/rados.h index 8fcc023056c7..6d5247f2e81b 100644 --- a/fs/ceph/rados.h +++ b/fs/ceph/rados.h | |||
| @@ -1,5 +1,5 @@ | |||
| 1 | #ifndef __RADOS_H | 1 | #ifndef CEPH_RADOS_H |
| 2 | #define __RADOS_H | 2 | #define CEPH_RADOS_H |
| 3 | 3 | ||
| 4 | /* | 4 | /* |
| 5 | * Data types for the Ceph distributed object storage layer RADOS | 5 | * Data types for the Ceph distributed object storage layer RADOS |
| @@ -203,6 +203,7 @@ enum { | |||
| 203 | CEPH_OSD_OP_TMAPGET = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 12, | 203 | CEPH_OSD_OP_TMAPGET = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 12, |
| 204 | 204 | ||
| 205 | CEPH_OSD_OP_CREATE = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 13, | 205 | CEPH_OSD_OP_CREATE = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 13, |
| 206 | CEPH_OSD_OP_ROLLBACK= CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 14, | ||
| 206 | 207 | ||
| 207 | /** attrs **/ | 208 | /** attrs **/ |
| 208 | /* read */ | 209 | /* read */ |
| @@ -272,6 +273,10 @@ static inline int ceph_osd_op_mode_modify(int op) | |||
| 272 | return (op & CEPH_OSD_OP_MODE) == CEPH_OSD_OP_MODE_WR; | 273 | return (op & CEPH_OSD_OP_MODE) == CEPH_OSD_OP_MODE_WR; |
| 273 | } | 274 | } |
| 274 | 275 | ||
| 276 | /* | ||
| 277 | * note that the following tmap stuff is also defined in the ceph librados.h | ||
| 278 | * any modification here needs to be updated there | ||
| 279 | */ | ||
| 275 | #define CEPH_OSD_TMAP_HDR 'h' | 280 | #define CEPH_OSD_TMAP_HDR 'h' |
| 276 | #define CEPH_OSD_TMAP_SET 's' | 281 | #define CEPH_OSD_TMAP_SET 's' |
| 277 | #define CEPH_OSD_TMAP_RM 'r' | 282 | #define CEPH_OSD_TMAP_RM 'r' |
| @@ -297,6 +302,7 @@ enum { | |||
| 297 | CEPH_OSD_FLAG_PARALLELEXEC = 512, /* execute op in parallel */ | 302 | CEPH_OSD_FLAG_PARALLELEXEC = 512, /* execute op in parallel */ |
| 298 | CEPH_OSD_FLAG_PGOP = 1024, /* pg op, no object */ | 303 | CEPH_OSD_FLAG_PGOP = 1024, /* pg op, no object */ |
| 299 | CEPH_OSD_FLAG_EXEC = 2048, /* op may exec */ | 304 | CEPH_OSD_FLAG_EXEC = 2048, /* op may exec */ |
| 305 | CEPH_OSD_FLAG_EXEC_PUBLIC = 4096, /* op may exec (public) */ | ||
| 300 | }; | 306 | }; |
| 301 | 307 | ||
| 302 | enum { | 308 | enum { |
| @@ -350,6 +356,9 @@ struct ceph_osd_op { | |||
| 350 | struct { | 356 | struct { |
| 351 | __le64 cookie, count; | 357 | __le64 cookie, count; |
| 352 | } __attribute__ ((packed)) pgls; | 358 | } __attribute__ ((packed)) pgls; |
| 359 | struct { | ||
| 360 | __le64 snapid; | ||
| 361 | } __attribute__ ((packed)) snap; | ||
| 353 | }; | 362 | }; |
| 354 | __le32 payload_len; | 363 | __le32 payload_len; |
| 355 | } __attribute__ ((packed)); | 364 | } __attribute__ ((packed)); |
diff --git a/fs/ceph/super.c b/fs/ceph/super.c index fa87f51e38e1..9922628532b2 100644 --- a/fs/ceph/super.c +++ b/fs/ceph/super.c | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | #include "ceph_debug.h" | 2 | #include "ceph_debug.h" |
| 3 | 3 | ||
| 4 | #include <linux/backing-dev.h> | 4 | #include <linux/backing-dev.h> |
| 5 | #include <linux/ctype.h> | ||
| 5 | #include <linux/fs.h> | 6 | #include <linux/fs.h> |
| 6 | #include <linux/inet.h> | 7 | #include <linux/inet.h> |
| 7 | #include <linux/in6.h> | 8 | #include <linux/in6.h> |
| @@ -101,12 +102,21 @@ static int ceph_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
| 101 | } | 102 | } |
| 102 | 103 | ||
| 103 | 104 | ||
| 104 | static int ceph_syncfs(struct super_block *sb, int wait) | 105 | static int ceph_sync_fs(struct super_block *sb, int wait) |
| 105 | { | 106 | { |
| 106 | dout("sync_fs %d\n", wait); | 107 | struct ceph_client *client = ceph_sb_to_client(sb); |
| 108 | |||
| 109 | if (!wait) { | ||
| 110 | dout("sync_fs (non-blocking)\n"); | ||
| 111 | ceph_flush_dirty_caps(&client->mdsc); | ||
| 112 | dout("sync_fs (non-blocking) done\n"); | ||
| 113 | return 0; | ||
| 114 | } | ||
| 115 | |||
| 116 | dout("sync_fs (blocking)\n"); | ||
| 107 | ceph_osdc_sync(&ceph_sb_to_client(sb)->osdc); | 117 | ceph_osdc_sync(&ceph_sb_to_client(sb)->osdc); |
| 108 | ceph_mdsc_sync(&ceph_sb_to_client(sb)->mdsc); | 118 | ceph_mdsc_sync(&ceph_sb_to_client(sb)->mdsc); |
| 109 | dout("sync_fs %d done\n", wait); | 119 | dout("sync_fs (blocking) done\n"); |
| 110 | return 0; | 120 | return 0; |
| 111 | } | 121 | } |
| 112 | 122 | ||
| @@ -150,9 +160,7 @@ static int ceph_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
| 150 | struct ceph_mount_args *args = client->mount_args; | 160 | struct ceph_mount_args *args = client->mount_args; |
| 151 | 161 | ||
| 152 | if (args->flags & CEPH_OPT_FSID) | 162 | if (args->flags & CEPH_OPT_FSID) |
| 153 | seq_printf(m, ",fsidmajor=%llu,fsidminor%llu", | 163 | seq_printf(m, ",fsid=%pU", &args->fsid); |
| 154 | le64_to_cpu(*(__le64 *)&args->fsid.fsid[0]), | ||
| 155 | le64_to_cpu(*(__le64 *)&args->fsid.fsid[8])); | ||
| 156 | if (args->flags & CEPH_OPT_NOSHARE) | 164 | if (args->flags & CEPH_OPT_NOSHARE) |
| 157 | seq_puts(m, ",noshare"); | 165 | seq_puts(m, ",noshare"); |
| 158 | if (args->flags & CEPH_OPT_DIRSTAT) | 166 | if (args->flags & CEPH_OPT_DIRSTAT) |
| @@ -279,7 +287,7 @@ static const struct super_operations ceph_super_ops = { | |||
| 279 | .alloc_inode = ceph_alloc_inode, | 287 | .alloc_inode = ceph_alloc_inode, |
| 280 | .destroy_inode = ceph_destroy_inode, | 288 | .destroy_inode = ceph_destroy_inode, |
| 281 | .write_inode = ceph_write_inode, | 289 | .write_inode = ceph_write_inode, |
| 282 | .sync_fs = ceph_syncfs, | 290 | .sync_fs = ceph_sync_fs, |
| 283 | .put_super = ceph_put_super, | 291 | .put_super = ceph_put_super, |
| 284 | .show_options = ceph_show_options, | 292 | .show_options = ceph_show_options, |
| 285 | .statfs = ceph_statfs, | 293 | .statfs = ceph_statfs, |
| @@ -322,9 +330,6 @@ const char *ceph_msg_type_name(int type) | |||
| 322 | * mount options | 330 | * mount options |
| 323 | */ | 331 | */ |
| 324 | enum { | 332 | enum { |
| 325 | Opt_fsidmajor, | ||
| 326 | Opt_fsidminor, | ||
| 327 | Opt_monport, | ||
| 328 | Opt_wsize, | 333 | Opt_wsize, |
| 329 | Opt_rsize, | 334 | Opt_rsize, |
| 330 | Opt_osdtimeout, | 335 | Opt_osdtimeout, |
| @@ -339,6 +344,7 @@ enum { | |||
| 339 | Opt_congestion_kb, | 344 | Opt_congestion_kb, |
| 340 | Opt_last_int, | 345 | Opt_last_int, |
| 341 | /* int args above */ | 346 | /* int args above */ |
| 347 | Opt_fsid, | ||
| 342 | Opt_snapdirname, | 348 | Opt_snapdirname, |
| 343 | Opt_name, | 349 | Opt_name, |
| 344 | Opt_secret, | 350 | Opt_secret, |
| @@ -355,9 +361,6 @@ enum { | |||
| 355 | }; | 361 | }; |
| 356 | 362 | ||
| 357 | static match_table_t arg_tokens = { | 363 | static match_table_t arg_tokens = { |
| 358 | {Opt_fsidmajor, "fsidmajor=%ld"}, | ||
| 359 | {Opt_fsidminor, "fsidminor=%ld"}, | ||
| 360 | {Opt_monport, "monport=%d"}, | ||
| 361 | {Opt_wsize, "wsize=%d"}, | 364 | {Opt_wsize, "wsize=%d"}, |
| 362 | {Opt_rsize, "rsize=%d"}, | 365 | {Opt_rsize, "rsize=%d"}, |
| 363 | {Opt_osdtimeout, "osdtimeout=%d"}, | 366 | {Opt_osdtimeout, "osdtimeout=%d"}, |
| @@ -371,6 +374,7 @@ static match_table_t arg_tokens = { | |||
| 371 | {Opt_readdir_max_bytes, "readdir_max_bytes=%d"}, | 374 | {Opt_readdir_max_bytes, "readdir_max_bytes=%d"}, |
| 372 | {Opt_congestion_kb, "write_congestion_kb=%d"}, | 375 | {Opt_congestion_kb, "write_congestion_kb=%d"}, |
| 373 | /* int args above */ | 376 | /* int args above */ |
| 377 | {Opt_fsid, "fsid=%s"}, | ||
| 374 | {Opt_snapdirname, "snapdirname=%s"}, | 378 | {Opt_snapdirname, "snapdirname=%s"}, |
| 375 | {Opt_name, "name=%s"}, | 379 | {Opt_name, "name=%s"}, |
| 376 | {Opt_secret, "secret=%s"}, | 380 | {Opt_secret, "secret=%s"}, |
| @@ -386,6 +390,36 @@ static match_table_t arg_tokens = { | |||
| 386 | {-1, NULL} | 390 | {-1, NULL} |
| 387 | }; | 391 | }; |
| 388 | 392 | ||
| 393 | static int parse_fsid(const char *str, struct ceph_fsid *fsid) | ||
| 394 | { | ||
| 395 | int i = 0; | ||
| 396 | char tmp[3]; | ||
| 397 | int err = -EINVAL; | ||
| 398 | int d; | ||
| 399 | |||
| 400 | dout("parse_fsid '%s'\n", str); | ||
| 401 | tmp[2] = 0; | ||
| 402 | while (*str && i < 16) { | ||
| 403 | if (ispunct(*str)) { | ||
| 404 | str++; | ||
| 405 | continue; | ||
| 406 | } | ||
| 407 | if (!isxdigit(str[0]) || !isxdigit(str[1])) | ||
| 408 | break; | ||
| 409 | tmp[0] = str[0]; | ||
| 410 | tmp[1] = str[1]; | ||
| 411 | if (sscanf(tmp, "%x", &d) < 1) | ||
| 412 | break; | ||
| 413 | fsid->fsid[i] = d & 0xff; | ||
| 414 | i++; | ||
| 415 | str += 2; | ||
| 416 | } | ||
| 417 | |||
| 418 | if (i == 16) | ||
| 419 | err = 0; | ||
| 420 | dout("parse_fsid ret %d got fsid %pU", err, fsid); | ||
| 421 | return err; | ||
| 422 | } | ||
| 389 | 423 | ||
| 390 | static struct ceph_mount_args *parse_mount_args(int flags, char *options, | 424 | static struct ceph_mount_args *parse_mount_args(int flags, char *options, |
| 391 | const char *dev_name, | 425 | const char *dev_name, |
| @@ -469,12 +503,6 @@ static struct ceph_mount_args *parse_mount_args(int flags, char *options, | |||
| 469 | dout("got token %d\n", token); | 503 | dout("got token %d\n", token); |
| 470 | } | 504 | } |
| 471 | switch (token) { | 505 | switch (token) { |
| 472 | case Opt_fsidmajor: | ||
| 473 | *(__le64 *)&args->fsid.fsid[0] = cpu_to_le64(intval); | ||
| 474 | break; | ||
| 475 | case Opt_fsidminor: | ||
| 476 | *(__le64 *)&args->fsid.fsid[8] = cpu_to_le64(intval); | ||
| 477 | break; | ||
| 478 | case Opt_ip: | 506 | case Opt_ip: |
| 479 | err = ceph_parse_ips(argstr[0].from, | 507 | err = ceph_parse_ips(argstr[0].from, |
| 480 | argstr[0].to, | 508 | argstr[0].to, |
| @@ -485,6 +513,11 @@ static struct ceph_mount_args *parse_mount_args(int flags, char *options, | |||
| 485 | args->flags |= CEPH_OPT_MYIP; | 513 | args->flags |= CEPH_OPT_MYIP; |
| 486 | break; | 514 | break; |
| 487 | 515 | ||
| 516 | case Opt_fsid: | ||
| 517 | err = parse_fsid(argstr[0].from, &args->fsid); | ||
| 518 | if (err == 0) | ||
| 519 | args->flags |= CEPH_OPT_FSID; | ||
| 520 | break; | ||
| 488 | case Opt_snapdirname: | 521 | case Opt_snapdirname: |
| 489 | kfree(args->snapdir_name); | 522 | kfree(args->snapdir_name); |
| 490 | args->snapdir_name = kstrndup(argstr[0].from, | 523 | args->snapdir_name = kstrndup(argstr[0].from, |
| @@ -515,6 +548,9 @@ static struct ceph_mount_args *parse_mount_args(int flags, char *options, | |||
| 515 | case Opt_osdkeepalivetimeout: | 548 | case Opt_osdkeepalivetimeout: |
| 516 | args->osd_keepalive_timeout = intval; | 549 | args->osd_keepalive_timeout = intval; |
| 517 | break; | 550 | break; |
| 551 | case Opt_osd_idle_ttl: | ||
| 552 | args->osd_idle_ttl = intval; | ||
| 553 | break; | ||
| 518 | case Opt_mount_timeout: | 554 | case Opt_mount_timeout: |
| 519 | args->mount_timeout = intval; | 555 | args->mount_timeout = intval; |
| 520 | break; | 556 | break; |
| @@ -630,7 +666,6 @@ static struct ceph_client *ceph_create_client(struct ceph_mount_args *args) | |||
| 630 | 666 | ||
| 631 | /* caps */ | 667 | /* caps */ |
| 632 | client->min_caps = args->max_readdir; | 668 | client->min_caps = args->max_readdir; |
| 633 | ceph_adjust_min_caps(client->min_caps); | ||
| 634 | 669 | ||
| 635 | /* subsystems */ | 670 | /* subsystems */ |
| 636 | err = ceph_monc_init(&client->monc, client); | 671 | err = ceph_monc_init(&client->monc, client); |
| @@ -680,8 +715,6 @@ static void ceph_destroy_client(struct ceph_client *client) | |||
| 680 | 715 | ||
| 681 | ceph_monc_stop(&client->monc); | 716 | ceph_monc_stop(&client->monc); |
| 682 | 717 | ||
| 683 | ceph_adjust_min_caps(-client->min_caps); | ||
| 684 | |||
| 685 | ceph_debugfs_client_cleanup(client); | 718 | ceph_debugfs_client_cleanup(client); |
| 686 | destroy_workqueue(client->wb_wq); | 719 | destroy_workqueue(client->wb_wq); |
| 687 | destroy_workqueue(client->pg_inv_wq); | 720 | destroy_workqueue(client->pg_inv_wq); |
| @@ -706,13 +739,13 @@ int ceph_check_fsid(struct ceph_client *client, struct ceph_fsid *fsid) | |||
| 706 | { | 739 | { |
| 707 | if (client->have_fsid) { | 740 | if (client->have_fsid) { |
| 708 | if (ceph_fsid_compare(&client->fsid, fsid)) { | 741 | if (ceph_fsid_compare(&client->fsid, fsid)) { |
| 709 | pr_err("bad fsid, had " FSID_FORMAT " got " FSID_FORMAT, | 742 | pr_err("bad fsid, had %pU got %pU", |
| 710 | PR_FSID(&client->fsid), PR_FSID(fsid)); | 743 | &client->fsid, fsid); |
| 711 | return -1; | 744 | return -1; |
| 712 | } | 745 | } |
| 713 | } else { | 746 | } else { |
| 714 | pr_info("client%lld fsid " FSID_FORMAT "\n", | 747 | pr_info("client%lld fsid %pU\n", client->monc.auth->global_id, |
| 715 | client->monc.auth->global_id, PR_FSID(fsid)); | 748 | fsid); |
| 716 | memcpy(&client->fsid, fsid, sizeof(*fsid)); | 749 | memcpy(&client->fsid, fsid, sizeof(*fsid)); |
| 717 | ceph_debugfs_client_init(client); | 750 | ceph_debugfs_client_init(client); |
| 718 | client->have_fsid = true; | 751 | client->have_fsid = true; |
| @@ -1043,8 +1076,6 @@ static int __init init_ceph(void) | |||
| 1043 | if (ret) | 1076 | if (ret) |
| 1044 | goto out_msgr; | 1077 | goto out_msgr; |
| 1045 | 1078 | ||
| 1046 | ceph_caps_init(); | ||
| 1047 | |||
| 1048 | ret = register_filesystem(&ceph_fs_type); | 1079 | ret = register_filesystem(&ceph_fs_type); |
| 1049 | if (ret) | 1080 | if (ret) |
| 1050 | goto out_icache; | 1081 | goto out_icache; |
| @@ -1069,7 +1100,6 @@ static void __exit exit_ceph(void) | |||
| 1069 | { | 1100 | { |
| 1070 | dout("exit_ceph\n"); | 1101 | dout("exit_ceph\n"); |
| 1071 | unregister_filesystem(&ceph_fs_type); | 1102 | unregister_filesystem(&ceph_fs_type); |
| 1072 | ceph_caps_finalize(); | ||
| 1073 | destroy_caches(); | 1103 | destroy_caches(); |
| 1074 | ceph_msgr_exit(); | 1104 | ceph_msgr_exit(); |
| 1075 | ceph_debugfs_cleanup(); | 1105 | ceph_debugfs_cleanup(); |
diff --git a/fs/ceph/super.h b/fs/ceph/super.h index 10a4a406e887..2482d696f0de 100644 --- a/fs/ceph/super.h +++ b/fs/ceph/super.h | |||
| @@ -31,6 +31,12 @@ | |||
| 31 | #define CEPH_BLOCK (1 << CEPH_BLOCK_SHIFT) | 31 | #define CEPH_BLOCK (1 << CEPH_BLOCK_SHIFT) |
| 32 | 32 | ||
| 33 | /* | 33 | /* |
| 34 | * Supported features | ||
| 35 | */ | ||
| 36 | #define CEPH_FEATURE_SUPPORTED CEPH_FEATURE_NOSRCADDR | CEPH_FEATURE_FLOCK | ||
| 37 | #define CEPH_FEATURE_REQUIRED CEPH_FEATURE_NOSRCADDR | ||
| 38 | |||
| 39 | /* | ||
| 34 | * mount options | 40 | * mount options |
| 35 | */ | 41 | */ |
| 36 | #define CEPH_OPT_FSID (1<<0) | 42 | #define CEPH_OPT_FSID (1<<0) |
| @@ -560,11 +566,13 @@ static inline int __ceph_caps_wanted(struct ceph_inode_info *ci) | |||
| 560 | /* what the mds thinks we want */ | 566 | /* what the mds thinks we want */ |
| 561 | extern int __ceph_caps_mds_wanted(struct ceph_inode_info *ci); | 567 | extern int __ceph_caps_mds_wanted(struct ceph_inode_info *ci); |
| 562 | 568 | ||
| 563 | extern void ceph_caps_init(void); | 569 | extern void ceph_caps_init(struct ceph_mds_client *mdsc); |
| 564 | extern void ceph_caps_finalize(void); | 570 | extern void ceph_caps_finalize(struct ceph_mds_client *mdsc); |
| 565 | extern void ceph_adjust_min_caps(int delta); | 571 | extern void ceph_adjust_min_caps(struct ceph_mds_client *mdsc, int delta); |
| 566 | extern int ceph_reserve_caps(struct ceph_cap_reservation *ctx, int need); | 572 | extern int ceph_reserve_caps(struct ceph_mds_client *mdsc, |
| 567 | extern int ceph_unreserve_caps(struct ceph_cap_reservation *ctx); | 573 | struct ceph_cap_reservation *ctx, int need); |
| 574 | extern int ceph_unreserve_caps(struct ceph_mds_client *mdsc, | ||
| 575 | struct ceph_cap_reservation *ctx); | ||
| 568 | extern void ceph_reservation_status(struct ceph_client *client, | 576 | extern void ceph_reservation_status(struct ceph_client *client, |
| 569 | int *total, int *avail, int *used, | 577 | int *total, int *avail, int *used, |
| 570 | int *reserved, int *min); | 578 | int *reserved, int *min); |
| @@ -738,13 +746,6 @@ extern struct kmem_cache *ceph_file_cachep; | |||
| 738 | extern const char *ceph_msg_type_name(int type); | 746 | extern const char *ceph_msg_type_name(int type); |
| 739 | extern int ceph_check_fsid(struct ceph_client *client, struct ceph_fsid *fsid); | 747 | extern int ceph_check_fsid(struct ceph_client *client, struct ceph_fsid *fsid); |
| 740 | 748 | ||
| 741 | #define FSID_FORMAT "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-" \ | ||
| 742 | "%02x%02x%02x%02x%02x%02x" | ||
| 743 | #define PR_FSID(f) (f)->fsid[0], (f)->fsid[1], (f)->fsid[2], (f)->fsid[3], \ | ||
| 744 | (f)->fsid[4], (f)->fsid[5], (f)->fsid[6], (f)->fsid[7], \ | ||
| 745 | (f)->fsid[8], (f)->fsid[9], (f)->fsid[10], (f)->fsid[11], \ | ||
| 746 | (f)->fsid[12], (f)->fsid[13], (f)->fsid[14], (f)->fsid[15] | ||
| 747 | |||
| 748 | /* inode.c */ | 749 | /* inode.c */ |
| 749 | extern const struct inode_operations ceph_file_iops; | 750 | extern const struct inode_operations ceph_file_iops; |
| 750 | 751 | ||
| @@ -806,13 +807,16 @@ static inline void ceph_remove_cap(struct ceph_cap *cap) | |||
| 806 | __ceph_remove_cap(cap); | 807 | __ceph_remove_cap(cap); |
| 807 | spin_unlock(&inode->i_lock); | 808 | spin_unlock(&inode->i_lock); |
| 808 | } | 809 | } |
| 809 | extern void ceph_put_cap(struct ceph_cap *cap); | 810 | extern void ceph_put_cap(struct ceph_mds_client *mdsc, |
| 811 | struct ceph_cap *cap); | ||
| 810 | 812 | ||
| 811 | extern void ceph_queue_caps_release(struct inode *inode); | 813 | extern void ceph_queue_caps_release(struct inode *inode); |
| 812 | extern int ceph_write_inode(struct inode *inode, struct writeback_control *wbc); | 814 | extern int ceph_write_inode(struct inode *inode, struct writeback_control *wbc); |
| 813 | extern int ceph_fsync(struct file *file, int datasync); | 815 | extern int ceph_fsync(struct file *file, int datasync); |
| 814 | extern void ceph_kick_flushing_caps(struct ceph_mds_client *mdsc, | 816 | extern void ceph_kick_flushing_caps(struct ceph_mds_client *mdsc, |
| 815 | struct ceph_mds_session *session); | 817 | struct ceph_mds_session *session); |
| 818 | extern struct ceph_cap *ceph_get_cap_for_mds(struct ceph_inode_info *ci, | ||
| 819 | int mds); | ||
| 816 | extern int ceph_get_cap_mds(struct inode *inode); | 820 | extern int ceph_get_cap_mds(struct inode *inode); |
| 817 | extern void ceph_get_cap_refs(struct ceph_inode_info *ci, int caps); | 821 | extern void ceph_get_cap_refs(struct ceph_inode_info *ci, int caps); |
| 818 | extern void ceph_put_cap_refs(struct ceph_inode_info *ci, int had); | 822 | extern void ceph_put_cap_refs(struct ceph_inode_info *ci, int had); |
| @@ -857,7 +861,7 @@ extern void ceph_release_page_vector(struct page **pages, int num_pages); | |||
| 857 | /* dir.c */ | 861 | /* dir.c */ |
| 858 | extern const struct file_operations ceph_dir_fops; | 862 | extern const struct file_operations ceph_dir_fops; |
| 859 | extern const struct inode_operations ceph_dir_iops; | 863 | extern const struct inode_operations ceph_dir_iops; |
| 860 | extern struct dentry_operations ceph_dentry_ops, ceph_snap_dentry_ops, | 864 | extern const struct dentry_operations ceph_dentry_ops, ceph_snap_dentry_ops, |
| 861 | ceph_snapdir_dentry_ops; | 865 | ceph_snapdir_dentry_ops; |
| 862 | 866 | ||
| 863 | extern int ceph_handle_notrace_create(struct inode *dir, struct dentry *dentry); | 867 | extern int ceph_handle_notrace_create(struct inode *dir, struct dentry *dentry); |
| @@ -888,6 +892,14 @@ extern void ceph_debugfs_cleanup(void); | |||
| 888 | extern int ceph_debugfs_client_init(struct ceph_client *client); | 892 | extern int ceph_debugfs_client_init(struct ceph_client *client); |
| 889 | extern void ceph_debugfs_client_cleanup(struct ceph_client *client); | 893 | extern void ceph_debugfs_client_cleanup(struct ceph_client *client); |
| 890 | 894 | ||
| 895 | /* locks.c */ | ||
| 896 | extern int ceph_lock(struct file *file, int cmd, struct file_lock *fl); | ||
| 897 | extern int ceph_flock(struct file *file, int cmd, struct file_lock *fl); | ||
| 898 | extern void ceph_count_locks(struct inode *inode, int *p_num, int *f_num); | ||
| 899 | extern int ceph_encode_locks(struct inode *i, struct ceph_pagelist *p, | ||
| 900 | int p_locks, int f_locks); | ||
| 901 | extern int lock_to_ceph_filelock(struct file_lock *fl, struct ceph_filelock *c); | ||
| 902 | |||
| 891 | static inline struct inode *get_dentry_parent_inode(struct dentry *dentry) | 903 | static inline struct inode *get_dentry_parent_inode(struct dentry *dentry) |
| 892 | { | 904 | { |
| 893 | if (dentry && dentry->d_parent) | 905 | if (dentry && dentry->d_parent) |
diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c index 68aeebc69681..097a2654c00f 100644 --- a/fs/ceph/xattr.c +++ b/fs/ceph/xattr.c | |||
| @@ -337,6 +337,8 @@ void __ceph_destroy_xattrs(struct ceph_inode_info *ci) | |||
| 337 | } | 337 | } |
| 338 | 338 | ||
| 339 | static int __build_xattrs(struct inode *inode) | 339 | static int __build_xattrs(struct inode *inode) |
| 340 | __releases(inode->i_lock) | ||
| 341 | __acquires(inode->i_lock) | ||
| 340 | { | 342 | { |
| 341 | u32 namelen; | 343 | u32 namelen; |
| 342 | u32 numattr = 0; | 344 | u32 numattr = 0; |
diff --git a/fs/cifs/README b/fs/cifs/README index a7081eeeb85d..7099a526f775 100644 --- a/fs/cifs/README +++ b/fs/cifs/README | |||
| @@ -301,6 +301,16 @@ A partial list of the supported mount options follows: | |||
| 301 | gid Set the default gid for inodes (similar to above). | 301 | gid Set the default gid for inodes (similar to above). |
| 302 | file_mode If CIFS Unix extensions are not supported by the server | 302 | file_mode If CIFS Unix extensions are not supported by the server |
| 303 | this overrides the default mode for file inodes. | 303 | this overrides the default mode for file inodes. |
| 304 | fsc Enable local disk caching using FS-Cache (off by default). This | ||
| 305 | option could be useful to improve performance on a slow link, | ||
| 306 | heavily loaded server and/or network where reading from the | ||
| 307 | disk is faster than reading from the server (over the network). | ||
| 308 | This could also impact scalability positively as the | ||
| 309 | number of calls to the server are reduced. However, local | ||
| 310 | caching is not suitable for all workloads for e.g. read-once | ||
| 311 | type workloads. So, you need to consider carefully your | ||
| 312 | workload/scenario before using this option. Currently, local | ||
| 313 | disk caching is functional for CIFS files opened as read-only. | ||
| 304 | dir_mode If CIFS Unix extensions are not supported by the server | 314 | dir_mode If CIFS Unix extensions are not supported by the server |
| 305 | this overrides the default mode for directory inodes. | 315 | this overrides the default mode for directory inodes. |
| 306 | port attempt to contact the server on this tcp port, before | 316 | port attempt to contact the server on this tcp port, before |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index a5ed10c9afef..b7431afdd76d 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
| @@ -329,8 +329,10 @@ cifs_destroy_inode(struct inode *inode) | |||
| 329 | } | 329 | } |
| 330 | 330 | ||
| 331 | static void | 331 | static void |
| 332 | cifs_clear_inode(struct inode *inode) | 332 | cifs_evict_inode(struct inode *inode) |
| 333 | { | 333 | { |
| 334 | truncate_inode_pages(&inode->i_data, 0); | ||
| 335 | end_writeback(inode); | ||
| 334 | cifs_fscache_release_inode_cookie(inode); | 336 | cifs_fscache_release_inode_cookie(inode); |
| 335 | } | 337 | } |
| 336 | 338 | ||
| @@ -479,14 +481,13 @@ static int cifs_remount(struct super_block *sb, int *flags, char *data) | |||
| 479 | return 0; | 481 | return 0; |
| 480 | } | 482 | } |
| 481 | 483 | ||
| 482 | void cifs_drop_inode(struct inode *inode) | 484 | static int cifs_drop_inode(struct inode *inode) |
| 483 | { | 485 | { |
| 484 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 486 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
| 485 | 487 | ||
| 486 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) | 488 | /* no serverino => unconditional eviction */ |
| 487 | return generic_drop_inode(inode); | 489 | return !(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) || |
| 488 | 490 | generic_drop_inode(inode); | |
| 489 | return generic_delete_inode(inode); | ||
| 490 | } | 491 | } |
| 491 | 492 | ||
| 492 | static const struct super_operations cifs_super_ops = { | 493 | static const struct super_operations cifs_super_ops = { |
| @@ -495,7 +496,7 @@ static const struct super_operations cifs_super_ops = { | |||
| 495 | .alloc_inode = cifs_alloc_inode, | 496 | .alloc_inode = cifs_alloc_inode, |
| 496 | .destroy_inode = cifs_destroy_inode, | 497 | .destroy_inode = cifs_destroy_inode, |
| 497 | .drop_inode = cifs_drop_inode, | 498 | .drop_inode = cifs_drop_inode, |
| 498 | .clear_inode = cifs_clear_inode, | 499 | .evict_inode = cifs_evict_inode, |
| 499 | /* .delete_inode = cifs_delete_inode, */ /* Do not need above | 500 | /* .delete_inode = cifs_delete_inode, */ /* Do not need above |
| 500 | function unless later we add lazy close of inodes or unless the | 501 | function unless later we add lazy close of inodes or unless the |
| 501 | kernel forgets to call us with the same number of releases (closes) | 502 | kernel forgets to call us with the same number of releases (closes) |
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index dc4c47ab9588..4bc47e5b5f29 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c | |||
| @@ -1698,26 +1698,16 @@ static int cifs_truncate_page(struct address_space *mapping, loff_t from) | |||
| 1698 | return rc; | 1698 | return rc; |
| 1699 | } | 1699 | } |
| 1700 | 1700 | ||
| 1701 | static int cifs_vmtruncate(struct inode *inode, loff_t offset) | 1701 | static void cifs_setsize(struct inode *inode, loff_t offset) |
| 1702 | { | 1702 | { |
| 1703 | loff_t oldsize; | 1703 | loff_t oldsize; |
| 1704 | int err; | ||
| 1705 | 1704 | ||
| 1706 | spin_lock(&inode->i_lock); | 1705 | spin_lock(&inode->i_lock); |
| 1707 | err = inode_newsize_ok(inode, offset); | ||
| 1708 | if (err) { | ||
| 1709 | spin_unlock(&inode->i_lock); | ||
| 1710 | goto out; | ||
| 1711 | } | ||
| 1712 | |||
| 1713 | oldsize = inode->i_size; | 1706 | oldsize = inode->i_size; |
| 1714 | i_size_write(inode, offset); | 1707 | i_size_write(inode, offset); |
| 1715 | spin_unlock(&inode->i_lock); | 1708 | spin_unlock(&inode->i_lock); |
| 1709 | |||
| 1716 | truncate_pagecache(inode, oldsize, offset); | 1710 | truncate_pagecache(inode, oldsize, offset); |
| 1717 | if (inode->i_op->truncate) | ||
| 1718 | inode->i_op->truncate(inode); | ||
| 1719 | out: | ||
| 1720 | return err; | ||
| 1721 | } | 1711 | } |
| 1722 | 1712 | ||
| 1723 | static int | 1713 | static int |
| @@ -1790,7 +1780,7 @@ cifs_set_file_size(struct inode *inode, struct iattr *attrs, | |||
| 1790 | 1780 | ||
| 1791 | if (rc == 0) { | 1781 | if (rc == 0) { |
| 1792 | cifsInode->server_eof = attrs->ia_size; | 1782 | cifsInode->server_eof = attrs->ia_size; |
| 1793 | rc = cifs_vmtruncate(inode, attrs->ia_size); | 1783 | cifs_setsize(inode, attrs->ia_size); |
| 1794 | cifs_truncate_page(inode->i_mapping, inode->i_size); | 1784 | cifs_truncate_page(inode->i_mapping, inode->i_size); |
| 1795 | } | 1785 | } |
| 1796 | 1786 | ||
| @@ -1815,14 +1805,12 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) | |||
| 1815 | 1805 | ||
| 1816 | xid = GetXid(); | 1806 | xid = GetXid(); |
| 1817 | 1807 | ||
| 1818 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) { | 1808 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) |
| 1819 | /* check if we have permission to change attrs */ | 1809 | attrs->ia_valid |= ATTR_FORCE; |
| 1820 | rc = inode_change_ok(inode, attrs); | 1810 | |
| 1821 | if (rc < 0) | 1811 | rc = inode_change_ok(inode, attrs); |
| 1822 | goto out; | 1812 | if (rc < 0) |
| 1823 | else | 1813 | goto out; |
| 1824 | rc = 0; | ||
| 1825 | } | ||
| 1826 | 1814 | ||
| 1827 | full_path = build_path_from_dentry(direntry); | 1815 | full_path = build_path_from_dentry(direntry); |
| 1828 | if (full_path == NULL) { | 1816 | if (full_path == NULL) { |
| @@ -1908,18 +1896,24 @@ cifs_setattr_unix(struct dentry *direntry, struct iattr *attrs) | |||
| 1908 | CIFS_MOUNT_MAP_SPECIAL_CHR); | 1896 | CIFS_MOUNT_MAP_SPECIAL_CHR); |
| 1909 | } | 1897 | } |
| 1910 | 1898 | ||
| 1911 | if (!rc) { | 1899 | if (rc) |
| 1912 | rc = inode_setattr(inode, attrs); | 1900 | goto out; |
| 1913 | 1901 | ||
| 1914 | /* force revalidate when any of these times are set since some | 1902 | if ((attrs->ia_valid & ATTR_SIZE) && |
| 1915 | of the fs types (eg ext3, fat) do not have fine enough | 1903 | attrs->ia_size != i_size_read(inode)) |
| 1916 | time granularity to match protocol, and we do not have a | 1904 | truncate_setsize(inode, attrs->ia_size); |
| 1917 | a way (yet) to query the server fs's time granularity (and | 1905 | |
| 1918 | whether it rounds times down). | 1906 | setattr_copy(inode, attrs); |
| 1919 | */ | 1907 | mark_inode_dirty(inode); |
| 1920 | if (!rc && (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME))) | 1908 | |
| 1921 | cifsInode->time = 0; | 1909 | /* force revalidate when any of these times are set since some |
| 1922 | } | 1910 | of the fs types (eg ext3, fat) do not have fine enough |
| 1911 | time granularity to match protocol, and we do not have a | ||
| 1912 | a way (yet) to query the server fs's time granularity (and | ||
| 1913 | whether it rounds times down). | ||
| 1914 | */ | ||
| 1915 | if (attrs->ia_valid & (ATTR_MTIME | ATTR_CTIME)) | ||
| 1916 | cifsInode->time = 0; | ||
| 1923 | out: | 1917 | out: |
| 1924 | kfree(args); | 1918 | kfree(args); |
| 1925 | kfree(full_path); | 1919 | kfree(full_path); |
| @@ -1944,14 +1938,13 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) | |||
| 1944 | cFYI(1, "setattr on file %s attrs->iavalid 0x%x", | 1938 | cFYI(1, "setattr on file %s attrs->iavalid 0x%x", |
| 1945 | direntry->d_name.name, attrs->ia_valid); | 1939 | direntry->d_name.name, attrs->ia_valid); |
| 1946 | 1940 | ||
| 1947 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) { | 1941 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) |
| 1948 | /* check if we have permission to change attrs */ | 1942 | attrs->ia_valid |= ATTR_FORCE; |
| 1949 | rc = inode_change_ok(inode, attrs); | 1943 | |
| 1950 | if (rc < 0) { | 1944 | rc = inode_change_ok(inode, attrs); |
| 1951 | FreeXid(xid); | 1945 | if (rc < 0) { |
| 1952 | return rc; | 1946 | FreeXid(xid); |
| 1953 | } else | 1947 | return rc; |
| 1954 | rc = 0; | ||
| 1955 | } | 1948 | } |
| 1956 | 1949 | ||
| 1957 | full_path = build_path_from_dentry(direntry); | 1950 | full_path = build_path_from_dentry(direntry); |
| @@ -2059,8 +2052,17 @@ cifs_setattr_nounix(struct dentry *direntry, struct iattr *attrs) | |||
| 2059 | 2052 | ||
| 2060 | /* do not need local check to inode_check_ok since the server does | 2053 | /* do not need local check to inode_check_ok since the server does |
| 2061 | that */ | 2054 | that */ |
| 2062 | if (!rc) | 2055 | if (rc) |
| 2063 | rc = inode_setattr(inode, attrs); | 2056 | goto cifs_setattr_exit; |
| 2057 | |||
| 2058 | if ((attrs->ia_valid & ATTR_SIZE) && | ||
| 2059 | attrs->ia_size != i_size_read(inode)) | ||
| 2060 | truncate_setsize(inode, attrs->ia_size); | ||
| 2061 | |||
| 2062 | setattr_copy(inode, attrs); | ||
| 2063 | mark_inode_dirty(inode); | ||
| 2064 | return 0; | ||
| 2065 | |||
| 2064 | cifs_setattr_exit: | 2066 | cifs_setattr_exit: |
| 2065 | kfree(full_path); | 2067 | kfree(full_path); |
| 2066 | FreeXid(xid); | 2068 | FreeXid(xid); |
diff --git a/fs/coda/inode.c b/fs/coda/inode.c index d97f9935a028..6526e6f21ecf 100644 --- a/fs/coda/inode.c +++ b/fs/coda/inode.c | |||
| @@ -35,7 +35,7 @@ | |||
| 35 | #include "coda_int.h" | 35 | #include "coda_int.h" |
| 36 | 36 | ||
| 37 | /* VFS super_block ops */ | 37 | /* VFS super_block ops */ |
| 38 | static void coda_clear_inode(struct inode *); | 38 | static void coda_evict_inode(struct inode *); |
| 39 | static void coda_put_super(struct super_block *); | 39 | static void coda_put_super(struct super_block *); |
| 40 | static int coda_statfs(struct dentry *dentry, struct kstatfs *buf); | 40 | static int coda_statfs(struct dentry *dentry, struct kstatfs *buf); |
| 41 | 41 | ||
| @@ -93,7 +93,7 @@ static const struct super_operations coda_super_operations = | |||
| 93 | { | 93 | { |
| 94 | .alloc_inode = coda_alloc_inode, | 94 | .alloc_inode = coda_alloc_inode, |
| 95 | .destroy_inode = coda_destroy_inode, | 95 | .destroy_inode = coda_destroy_inode, |
| 96 | .clear_inode = coda_clear_inode, | 96 | .evict_inode = coda_evict_inode, |
| 97 | .put_super = coda_put_super, | 97 | .put_super = coda_put_super, |
| 98 | .statfs = coda_statfs, | 98 | .statfs = coda_statfs, |
| 99 | .remount_fs = coda_remount, | 99 | .remount_fs = coda_remount, |
| @@ -224,8 +224,10 @@ static void coda_put_super(struct super_block *sb) | |||
| 224 | printk("Coda: Bye bye.\n"); | 224 | printk("Coda: Bye bye.\n"); |
| 225 | } | 225 | } |
| 226 | 226 | ||
| 227 | static void coda_clear_inode(struct inode *inode) | 227 | static void coda_evict_inode(struct inode *inode) |
| 228 | { | 228 | { |
| 229 | truncate_inode_pages(&inode->i_data, 0); | ||
| 230 | end_writeback(inode); | ||
| 229 | coda_cache_clear_inode(inode); | 231 | coda_cache_clear_inode(inode); |
| 230 | } | 232 | } |
| 231 | 233 | ||
diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c index 66b9cf79c5ba..de89645777c7 100644 --- a/fs/coda/psdev.c +++ b/fs/coda/psdev.c | |||
| @@ -177,7 +177,7 @@ static ssize_t coda_psdev_write(struct file *file, const char __user *buf, | |||
| 177 | nbytes = req->uc_outSize; /* don't have more space! */ | 177 | nbytes = req->uc_outSize; /* don't have more space! */ |
| 178 | } | 178 | } |
| 179 | if (copy_from_user(req->uc_data, buf, nbytes)) { | 179 | if (copy_from_user(req->uc_data, buf, nbytes)) { |
| 180 | req->uc_flags |= REQ_ABORT; | 180 | req->uc_flags |= CODA_REQ_ABORT; |
| 181 | wake_up(&req->uc_sleep); | 181 | wake_up(&req->uc_sleep); |
| 182 | retval = -EFAULT; | 182 | retval = -EFAULT; |
| 183 | goto out; | 183 | goto out; |
| @@ -254,8 +254,8 @@ static ssize_t coda_psdev_read(struct file * file, char __user * buf, | |||
| 254 | retval = -EFAULT; | 254 | retval = -EFAULT; |
| 255 | 255 | ||
| 256 | /* If request was not a signal, enqueue and don't free */ | 256 | /* If request was not a signal, enqueue and don't free */ |
| 257 | if (!(req->uc_flags & REQ_ASYNC)) { | 257 | if (!(req->uc_flags & CODA_REQ_ASYNC)) { |
| 258 | req->uc_flags |= REQ_READ; | 258 | req->uc_flags |= CODA_REQ_READ; |
| 259 | list_add_tail(&(req->uc_chain), &vcp->vc_processing); | 259 | list_add_tail(&(req->uc_chain), &vcp->vc_processing); |
| 260 | goto out; | 260 | goto out; |
| 261 | } | 261 | } |
| @@ -315,19 +315,19 @@ static int coda_psdev_release(struct inode * inode, struct file * file) | |||
| 315 | list_del(&req->uc_chain); | 315 | list_del(&req->uc_chain); |
| 316 | 316 | ||
| 317 | /* Async requests need to be freed here */ | 317 | /* Async requests need to be freed here */ |
| 318 | if (req->uc_flags & REQ_ASYNC) { | 318 | if (req->uc_flags & CODA_REQ_ASYNC) { |
| 319 | CODA_FREE(req->uc_data, sizeof(struct coda_in_hdr)); | 319 | CODA_FREE(req->uc_data, sizeof(struct coda_in_hdr)); |
| 320 | kfree(req); | 320 | kfree(req); |
| 321 | continue; | 321 | continue; |
| 322 | } | 322 | } |
| 323 | req->uc_flags |= REQ_ABORT; | 323 | req->uc_flags |= CODA_REQ_ABORT; |
| 324 | wake_up(&req->uc_sleep); | 324 | wake_up(&req->uc_sleep); |
| 325 | } | 325 | } |
| 326 | 326 | ||
| 327 | list_for_each_entry_safe(req, tmp, &vcp->vc_processing, uc_chain) { | 327 | list_for_each_entry_safe(req, tmp, &vcp->vc_processing, uc_chain) { |
| 328 | list_del(&req->uc_chain); | 328 | list_del(&req->uc_chain); |
| 329 | 329 | ||
| 330 | req->uc_flags |= REQ_ABORT; | 330 | req->uc_flags |= CODA_REQ_ABORT; |
| 331 | wake_up(&req->uc_sleep); | 331 | wake_up(&req->uc_sleep); |
| 332 | } | 332 | } |
| 333 | 333 | ||
diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c index f09c5ed76f6c..b8893ab6f9e6 100644 --- a/fs/coda/upcall.c +++ b/fs/coda/upcall.c | |||
| @@ -604,7 +604,7 @@ static void coda_unblock_signals(sigset_t *old) | |||
| 604 | (((r)->uc_opcode != CODA_CLOSE && \ | 604 | (((r)->uc_opcode != CODA_CLOSE && \ |
| 605 | (r)->uc_opcode != CODA_STORE && \ | 605 | (r)->uc_opcode != CODA_STORE && \ |
| 606 | (r)->uc_opcode != CODA_RELEASE) || \ | 606 | (r)->uc_opcode != CODA_RELEASE) || \ |
| 607 | (r)->uc_flags & REQ_READ)) | 607 | (r)->uc_flags & CODA_REQ_READ)) |
| 608 | 608 | ||
| 609 | static inline void coda_waitfor_upcall(struct upc_req *req) | 609 | static inline void coda_waitfor_upcall(struct upc_req *req) |
| 610 | { | 610 | { |
| @@ -624,7 +624,7 @@ static inline void coda_waitfor_upcall(struct upc_req *req) | |||
| 624 | set_current_state(TASK_UNINTERRUPTIBLE); | 624 | set_current_state(TASK_UNINTERRUPTIBLE); |
| 625 | 625 | ||
| 626 | /* got a reply */ | 626 | /* got a reply */ |
| 627 | if (req->uc_flags & (REQ_WRITE | REQ_ABORT)) | 627 | if (req->uc_flags & (CODA_REQ_WRITE | CODA_REQ_ABORT)) |
| 628 | break; | 628 | break; |
| 629 | 629 | ||
| 630 | if (blocked && time_after(jiffies, timeout) && | 630 | if (blocked && time_after(jiffies, timeout) && |
| @@ -708,7 +708,7 @@ static int coda_upcall(struct venus_comm *vcp, | |||
| 708 | coda_waitfor_upcall(req); | 708 | coda_waitfor_upcall(req); |
| 709 | 709 | ||
| 710 | /* Op went through, interrupt or not... */ | 710 | /* Op went through, interrupt or not... */ |
| 711 | if (req->uc_flags & REQ_WRITE) { | 711 | if (req->uc_flags & CODA_REQ_WRITE) { |
| 712 | out = (union outputArgs *)req->uc_data; | 712 | out = (union outputArgs *)req->uc_data; |
| 713 | /* here we map positive Venus errors to kernel errors */ | 713 | /* here we map positive Venus errors to kernel errors */ |
| 714 | error = -out->oh.result; | 714 | error = -out->oh.result; |
| @@ -717,13 +717,13 @@ static int coda_upcall(struct venus_comm *vcp, | |||
| 717 | } | 717 | } |
| 718 | 718 | ||
| 719 | error = -EINTR; | 719 | error = -EINTR; |
| 720 | if ((req->uc_flags & REQ_ABORT) || !signal_pending(current)) { | 720 | if ((req->uc_flags & CODA_REQ_ABORT) || !signal_pending(current)) { |
| 721 | printk(KERN_WARNING "coda: Unexpected interruption.\n"); | 721 | printk(KERN_WARNING "coda: Unexpected interruption.\n"); |
| 722 | goto exit; | 722 | goto exit; |
| 723 | } | 723 | } |
| 724 | 724 | ||
| 725 | /* Interrupted before venus read it. */ | 725 | /* Interrupted before venus read it. */ |
| 726 | if (!(req->uc_flags & REQ_READ)) | 726 | if (!(req->uc_flags & CODA_REQ_READ)) |
| 727 | goto exit; | 727 | goto exit; |
| 728 | 728 | ||
| 729 | /* Venus saw the upcall, make sure we can send interrupt signal */ | 729 | /* Venus saw the upcall, make sure we can send interrupt signal */ |
| @@ -747,7 +747,7 @@ static int coda_upcall(struct venus_comm *vcp, | |||
| 747 | sig_inputArgs->ih.opcode = CODA_SIGNAL; | 747 | sig_inputArgs->ih.opcode = CODA_SIGNAL; |
| 748 | sig_inputArgs->ih.unique = req->uc_unique; | 748 | sig_inputArgs->ih.unique = req->uc_unique; |
| 749 | 749 | ||
| 750 | sig_req->uc_flags = REQ_ASYNC; | 750 | sig_req->uc_flags = CODA_REQ_ASYNC; |
| 751 | sig_req->uc_opcode = sig_inputArgs->ih.opcode; | 751 | sig_req->uc_opcode = sig_inputArgs->ih.opcode; |
| 752 | sig_req->uc_unique = sig_inputArgs->ih.unique; | 752 | sig_req->uc_unique = sig_inputArgs->ih.unique; |
| 753 | sig_req->uc_inSize = sizeof(struct coda_in_hdr); | 753 | sig_req->uc_inSize = sizeof(struct coda_in_hdr); |
diff --git a/fs/compat.c b/fs/compat.c index 5976bad85f65..718c7062aec1 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
| @@ -77,7 +77,8 @@ int compat_printk(const char *fmt, ...) | |||
| 77 | * Not all architectures have sys_utime, so implement this in terms | 77 | * Not all architectures have sys_utime, so implement this in terms |
| 78 | * of sys_utimes. | 78 | * of sys_utimes. |
| 79 | */ | 79 | */ |
| 80 | asmlinkage long compat_sys_utime(char __user *filename, struct compat_utimbuf __user *t) | 80 | asmlinkage long compat_sys_utime(const char __user *filename, |
| 81 | struct compat_utimbuf __user *t) | ||
| 81 | { | 82 | { |
| 82 | struct timespec tv[2]; | 83 | struct timespec tv[2]; |
| 83 | 84 | ||
| @@ -91,7 +92,7 @@ asmlinkage long compat_sys_utime(char __user *filename, struct compat_utimbuf __ | |||
| 91 | return do_utimes(AT_FDCWD, filename, t ? tv : NULL, 0); | 92 | return do_utimes(AT_FDCWD, filename, t ? tv : NULL, 0); |
| 92 | } | 93 | } |
| 93 | 94 | ||
| 94 | asmlinkage long compat_sys_utimensat(unsigned int dfd, char __user *filename, struct compat_timespec __user *t, int flags) | 95 | asmlinkage long compat_sys_utimensat(unsigned int dfd, const char __user *filename, struct compat_timespec __user *t, int flags) |
| 95 | { | 96 | { |
| 96 | struct timespec tv[2]; | 97 | struct timespec tv[2]; |
| 97 | 98 | ||
| @@ -106,7 +107,7 @@ asmlinkage long compat_sys_utimensat(unsigned int dfd, char __user *filename, st | |||
| 106 | return do_utimes(dfd, filename, t ? tv : NULL, flags); | 107 | return do_utimes(dfd, filename, t ? tv : NULL, flags); |
| 107 | } | 108 | } |
| 108 | 109 | ||
| 109 | asmlinkage long compat_sys_futimesat(unsigned int dfd, char __user *filename, struct compat_timeval __user *t) | 110 | asmlinkage long compat_sys_futimesat(unsigned int dfd, const char __user *filename, struct compat_timeval __user *t) |
| 110 | { | 111 | { |
| 111 | struct timespec tv[2]; | 112 | struct timespec tv[2]; |
| 112 | 113 | ||
| @@ -125,7 +126,7 @@ asmlinkage long compat_sys_futimesat(unsigned int dfd, char __user *filename, st | |||
| 125 | return do_utimes(dfd, filename, t ? tv : NULL, 0); | 126 | return do_utimes(dfd, filename, t ? tv : NULL, 0); |
| 126 | } | 127 | } |
| 127 | 128 | ||
| 128 | asmlinkage long compat_sys_utimes(char __user *filename, struct compat_timeval __user *t) | 129 | asmlinkage long compat_sys_utimes(const char __user *filename, struct compat_timeval __user *t) |
| 129 | { | 130 | { |
| 130 | return compat_sys_futimesat(AT_FDCWD, filename, t); | 131 | return compat_sys_futimesat(AT_FDCWD, filename, t); |
| 131 | } | 132 | } |
| @@ -169,7 +170,7 @@ static int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf) | |||
| 169 | return err; | 170 | return err; |
| 170 | } | 171 | } |
| 171 | 172 | ||
| 172 | asmlinkage long compat_sys_newstat(char __user * filename, | 173 | asmlinkage long compat_sys_newstat(const char __user * filename, |
| 173 | struct compat_stat __user *statbuf) | 174 | struct compat_stat __user *statbuf) |
| 174 | { | 175 | { |
| 175 | struct kstat stat; | 176 | struct kstat stat; |
| @@ -181,7 +182,7 @@ asmlinkage long compat_sys_newstat(char __user * filename, | |||
| 181 | return cp_compat_stat(&stat, statbuf); | 182 | return cp_compat_stat(&stat, statbuf); |
| 182 | } | 183 | } |
| 183 | 184 | ||
| 184 | asmlinkage long compat_sys_newlstat(char __user * filename, | 185 | asmlinkage long compat_sys_newlstat(const char __user * filename, |
| 185 | struct compat_stat __user *statbuf) | 186 | struct compat_stat __user *statbuf) |
| 186 | { | 187 | { |
| 187 | struct kstat stat; | 188 | struct kstat stat; |
| @@ -194,7 +195,8 @@ asmlinkage long compat_sys_newlstat(char __user * filename, | |||
| 194 | } | 195 | } |
| 195 | 196 | ||
| 196 | #ifndef __ARCH_WANT_STAT64 | 197 | #ifndef __ARCH_WANT_STAT64 |
| 197 | asmlinkage long compat_sys_newfstatat(unsigned int dfd, char __user *filename, | 198 | asmlinkage long compat_sys_newfstatat(unsigned int dfd, |
| 199 | const char __user *filename, | ||
| 198 | struct compat_stat __user *statbuf, int flag) | 200 | struct compat_stat __user *statbuf, int flag) |
| 199 | { | 201 | { |
| 200 | struct kstat stat; | 202 | struct kstat stat; |
| @@ -267,7 +269,7 @@ asmlinkage long compat_sys_statfs(const char __user *pathname, struct compat_sta | |||
| 267 | error = user_path(pathname, &path); | 269 | error = user_path(pathname, &path); |
| 268 | if (!error) { | 270 | if (!error) { |
| 269 | struct kstatfs tmp; | 271 | struct kstatfs tmp; |
| 270 | error = vfs_statfs(path.dentry, &tmp); | 272 | error = vfs_statfs(&path, &tmp); |
| 271 | if (!error) | 273 | if (!error) |
| 272 | error = put_compat_statfs(buf, &tmp); | 274 | error = put_compat_statfs(buf, &tmp); |
| 273 | path_put(&path); | 275 | path_put(&path); |
| @@ -285,7 +287,7 @@ asmlinkage long compat_sys_fstatfs(unsigned int fd, struct compat_statfs __user | |||
| 285 | file = fget(fd); | 287 | file = fget(fd); |
| 286 | if (!file) | 288 | if (!file) |
| 287 | goto out; | 289 | goto out; |
| 288 | error = vfs_statfs(file->f_path.dentry, &tmp); | 290 | error = vfs_statfs(&file->f_path, &tmp); |
| 289 | if (!error) | 291 | if (!error) |
| 290 | error = put_compat_statfs(buf, &tmp); | 292 | error = put_compat_statfs(buf, &tmp); |
| 291 | fput(file); | 293 | fput(file); |
| @@ -335,7 +337,7 @@ asmlinkage long compat_sys_statfs64(const char __user *pathname, compat_size_t s | |||
| 335 | error = user_path(pathname, &path); | 337 | error = user_path(pathname, &path); |
| 336 | if (!error) { | 338 | if (!error) { |
| 337 | struct kstatfs tmp; | 339 | struct kstatfs tmp; |
| 338 | error = vfs_statfs(path.dentry, &tmp); | 340 | error = vfs_statfs(&path, &tmp); |
| 339 | if (!error) | 341 | if (!error) |
| 340 | error = put_compat_statfs64(buf, &tmp); | 342 | error = put_compat_statfs64(buf, &tmp); |
| 341 | path_put(&path); | 343 | path_put(&path); |
| @@ -356,7 +358,7 @@ asmlinkage long compat_sys_fstatfs64(unsigned int fd, compat_size_t sz, struct c | |||
| 356 | file = fget(fd); | 358 | file = fget(fd); |
| 357 | if (!file) | 359 | if (!file) |
| 358 | goto out; | 360 | goto out; |
| 359 | error = vfs_statfs(file->f_path.dentry, &tmp); | 361 | error = vfs_statfs(&file->f_path, &tmp); |
| 360 | if (!error) | 362 | if (!error) |
| 361 | error = put_compat_statfs64(buf, &tmp); | 363 | error = put_compat_statfs64(buf, &tmp); |
| 362 | fput(file); | 364 | fput(file); |
| @@ -379,7 +381,7 @@ asmlinkage long compat_sys_ustat(unsigned dev, struct compat_ustat __user *u) | |||
| 379 | sb = user_get_super(new_decode_dev(dev)); | 381 | sb = user_get_super(new_decode_dev(dev)); |
| 380 | if (!sb) | 382 | if (!sb) |
| 381 | return -EINVAL; | 383 | return -EINVAL; |
| 382 | err = vfs_statfs(sb->s_root, &sbuf); | 384 | err = statfs_by_dentry(sb->s_root, &sbuf); |
| 383 | drop_super(sb); | 385 | drop_super(sb); |
| 384 | if (err) | 386 | if (err) |
| 385 | return err; | 387 | return err; |
| @@ -837,9 +839,10 @@ static int do_nfs4_super_data_conv(void *raw_data) | |||
| 837 | #define NCPFS_NAME "ncpfs" | 839 | #define NCPFS_NAME "ncpfs" |
| 838 | #define NFS4_NAME "nfs4" | 840 | #define NFS4_NAME "nfs4" |
| 839 | 841 | ||
| 840 | asmlinkage long compat_sys_mount(char __user * dev_name, char __user * dir_name, | 842 | asmlinkage long compat_sys_mount(const char __user * dev_name, |
| 841 | char __user * type, unsigned long flags, | 843 | const char __user * dir_name, |
| 842 | void __user * data) | 844 | const char __user * type, unsigned long flags, |
| 845 | const void __user * data) | ||
| 843 | { | 846 | { |
| 844 | char *kernel_type; | 847 | char *kernel_type; |
| 845 | unsigned long data_page; | 848 | unsigned long data_page; |
| @@ -1193,11 +1196,10 @@ out: | |||
| 1193 | if (iov != iovstack) | 1196 | if (iov != iovstack) |
| 1194 | kfree(iov); | 1197 | kfree(iov); |
| 1195 | if ((ret + (type == READ)) > 0) { | 1198 | if ((ret + (type == READ)) > 0) { |
| 1196 | struct dentry *dentry = file->f_path.dentry; | ||
| 1197 | if (type == READ) | 1199 | if (type == READ) |
| 1198 | fsnotify_access(dentry); | 1200 | fsnotify_access(file); |
| 1199 | else | 1201 | else |
| 1200 | fsnotify_modify(dentry); | 1202 | fsnotify_modify(file); |
| 1201 | } | 1203 | } |
| 1202 | return ret; | 1204 | return ret; |
| 1203 | } | 1205 | } |
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c index 63ae85831464..03e59aa318eb 100644 --- a/fs/compat_ioctl.c +++ b/fs/compat_ioctl.c | |||
| @@ -131,23 +131,6 @@ static int w_long(unsigned int fd, unsigned int cmd, | |||
| 131 | return err; | 131 | return err; |
| 132 | } | 132 | } |
| 133 | 133 | ||
| 134 | static int rw_long(unsigned int fd, unsigned int cmd, | ||
| 135 | compat_ulong_t __user *argp) | ||
| 136 | { | ||
| 137 | mm_segment_t old_fs = get_fs(); | ||
| 138 | int err; | ||
| 139 | unsigned long val; | ||
| 140 | |||
| 141 | if(get_user(val, argp)) | ||
| 142 | return -EFAULT; | ||
| 143 | set_fs (KERNEL_DS); | ||
| 144 | err = sys_ioctl(fd, cmd, (unsigned long)&val); | ||
| 145 | set_fs (old_fs); | ||
| 146 | if (!err && put_user(val, argp)) | ||
| 147 | return -EFAULT; | ||
| 148 | return err; | ||
| 149 | } | ||
| 150 | |||
| 151 | struct compat_video_event { | 134 | struct compat_video_event { |
| 152 | int32_t type; | 135 | int32_t type; |
| 153 | compat_time_t timestamp; | 136 | compat_time_t timestamp; |
| @@ -594,12 +577,6 @@ static int do_smb_getmountuid(unsigned int fd, unsigned int cmd, | |||
| 594 | return err; | 577 | return err; |
| 595 | } | 578 | } |
| 596 | 579 | ||
| 597 | static int ioc_settimeout(unsigned int fd, unsigned int cmd, | ||
| 598 | compat_ulong_t __user *argp) | ||
| 599 | { | ||
| 600 | return rw_long(fd, AUTOFS_IOC_SETTIMEOUT, argp); | ||
| 601 | } | ||
| 602 | |||
| 603 | /* Bluetooth ioctls */ | 580 | /* Bluetooth ioctls */ |
| 604 | #define HCIUARTSETPROTO _IOW('U', 200, int) | 581 | #define HCIUARTSETPROTO _IOW('U', 200, int) |
| 605 | #define HCIUARTGETPROTO _IOR('U', 201, int) | 582 | #define HCIUARTGETPROTO _IOR('U', 201, int) |
| @@ -969,6 +946,7 @@ COMPATIBLE_IOCTL(TIOCGPGRP) | |||
| 969 | COMPATIBLE_IOCTL(TIOCGPTN) | 946 | COMPATIBLE_IOCTL(TIOCGPTN) |
| 970 | COMPATIBLE_IOCTL(TIOCSPTLCK) | 947 | COMPATIBLE_IOCTL(TIOCSPTLCK) |
| 971 | COMPATIBLE_IOCTL(TIOCSERGETLSR) | 948 | COMPATIBLE_IOCTL(TIOCSERGETLSR) |
| 949 | COMPATIBLE_IOCTL(TIOCSIG) | ||
| 972 | #ifdef TCGETS2 | 950 | #ifdef TCGETS2 |
| 973 | COMPATIBLE_IOCTL(TCGETS2) | 951 | COMPATIBLE_IOCTL(TCGETS2) |
| 974 | COMPATIBLE_IOCTL(TCSETS2) | 952 | COMPATIBLE_IOCTL(TCSETS2) |
| @@ -1284,13 +1262,6 @@ COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE5) | |||
| 1284 | COMPATIBLE_IOCTL(SOUND_MIXER_GETLEVELS) | 1262 | COMPATIBLE_IOCTL(SOUND_MIXER_GETLEVELS) |
| 1285 | COMPATIBLE_IOCTL(SOUND_MIXER_SETLEVELS) | 1263 | COMPATIBLE_IOCTL(SOUND_MIXER_SETLEVELS) |
| 1286 | COMPATIBLE_IOCTL(OSS_GETVERSION) | 1264 | COMPATIBLE_IOCTL(OSS_GETVERSION) |
| 1287 | /* AUTOFS */ | ||
| 1288 | COMPATIBLE_IOCTL(AUTOFS_IOC_CATATONIC) | ||
| 1289 | COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER) | ||
| 1290 | COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE) | ||
| 1291 | COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE_MULTI) | ||
| 1292 | COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOSUBVER) | ||
| 1293 | COMPATIBLE_IOCTL(AUTOFS_IOC_ASKUMOUNT) | ||
| 1294 | /* Raw devices */ | 1265 | /* Raw devices */ |
| 1295 | COMPATIBLE_IOCTL(RAW_SETBIND) | 1266 | COMPATIBLE_IOCTL(RAW_SETBIND) |
| 1296 | COMPATIBLE_IOCTL(RAW_GETBIND) | 1267 | COMPATIBLE_IOCTL(RAW_GETBIND) |
| @@ -1557,9 +1528,6 @@ static long do_ioctl_trans(int fd, unsigned int cmd, | |||
| 1557 | case RAW_GETBIND: | 1528 | case RAW_GETBIND: |
| 1558 | return raw_ioctl(fd, cmd, argp); | 1529 | return raw_ioctl(fd, cmd, argp); |
| 1559 | #endif | 1530 | #endif |
| 1560 | #define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int) | ||
| 1561 | case AUTOFS_IOC_SETTIMEOUT32: | ||
| 1562 | return ioc_settimeout(fd, cmd, argp); | ||
| 1563 | /* One SMB ioctl needs translations. */ | 1531 | /* One SMB ioctl needs translations. */ |
| 1564 | #define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, compat_uid_t) | 1532 | #define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, compat_uid_t) |
| 1565 | case SMB_IOC_GETMOUNTUID_32: | 1533 | case SMB_IOC_GETMOUNTUID_32: |
| @@ -1614,9 +1582,6 @@ static long do_ioctl_trans(int fd, unsigned int cmd, | |||
| 1614 | case KDSKBMETA: | 1582 | case KDSKBMETA: |
| 1615 | case KDSKBLED: | 1583 | case KDSKBLED: |
| 1616 | case KDSETLED: | 1584 | case KDSETLED: |
| 1617 | /* AUTOFS */ | ||
| 1618 | case AUTOFS_IOC_READY: | ||
| 1619 | case AUTOFS_IOC_FAIL: | ||
| 1620 | /* NBD */ | 1585 | /* NBD */ |
| 1621 | case NBD_SET_SOCK: | 1586 | case NBD_SET_SOCK: |
| 1622 | case NBD_SET_BLKSIZE: | 1587 | case NBD_SET_BLKSIZE: |
| @@ -1734,8 +1699,7 @@ asmlinkage long compat_sys_ioctl(unsigned int fd, unsigned int cmd, | |||
| 1734 | goto out_fput; | 1699 | goto out_fput; |
| 1735 | } | 1700 | } |
| 1736 | 1701 | ||
| 1737 | if (!filp->f_op || | 1702 | if (!filp->f_op || !filp->f_op->unlocked_ioctl) |
| 1738 | (!filp->f_op->ioctl && !filp->f_op->unlocked_ioctl)) | ||
| 1739 | goto do_ioctl; | 1703 | goto do_ioctl; |
| 1740 | break; | 1704 | break; |
| 1741 | } | 1705 | } |
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index dd3634e4c967..a53b130b366c 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c | |||
| @@ -39,66 +39,55 @@ static DEFINE_MUTEX(read_mutex); | |||
| 39 | #define CRAMINO(x) (((x)->offset && (x)->size)?(x)->offset<<2:1) | 39 | #define CRAMINO(x) (((x)->offset && (x)->size)?(x)->offset<<2:1) |
| 40 | #define OFFSET(x) ((x)->i_ino) | 40 | #define OFFSET(x) ((x)->i_ino) |
| 41 | 41 | ||
| 42 | 42 | static void setup_inode(struct inode *inode, struct cramfs_inode * cramfs_inode) | |
| 43 | static int cramfs_iget5_test(struct inode *inode, void *opaque) | ||
| 44 | { | ||
| 45 | struct cramfs_inode *cramfs_inode = opaque; | ||
| 46 | return inode->i_ino == CRAMINO(cramfs_inode) && inode->i_ino != 1; | ||
| 47 | } | ||
| 48 | |||
| 49 | static int cramfs_iget5_set(struct inode *inode, void *opaque) | ||
| 50 | { | 43 | { |
| 51 | struct cramfs_inode *cramfs_inode = opaque; | 44 | static struct timespec zerotime; |
| 52 | inode->i_ino = CRAMINO(cramfs_inode); | 45 | inode->i_mode = cramfs_inode->mode; |
| 53 | return 0; | 46 | inode->i_uid = cramfs_inode->uid; |
| 47 | inode->i_size = cramfs_inode->size; | ||
| 48 | inode->i_blocks = (cramfs_inode->size - 1) / 512 + 1; | ||
| 49 | inode->i_gid = cramfs_inode->gid; | ||
| 50 | /* Struct copy intentional */ | ||
| 51 | inode->i_mtime = inode->i_atime = inode->i_ctime = zerotime; | ||
| 52 | /* inode->i_nlink is left 1 - arguably wrong for directories, | ||
| 53 | but it's the best we can do without reading the directory | ||
| 54 | contents. 1 yields the right result in GNU find, even | ||
| 55 | without -noleaf option. */ | ||
| 56 | if (S_ISREG(inode->i_mode)) { | ||
| 57 | inode->i_fop = &generic_ro_fops; | ||
| 58 | inode->i_data.a_ops = &cramfs_aops; | ||
| 59 | } else if (S_ISDIR(inode->i_mode)) { | ||
| 60 | inode->i_op = &cramfs_dir_inode_operations; | ||
| 61 | inode->i_fop = &cramfs_directory_operations; | ||
| 62 | } else if (S_ISLNK(inode->i_mode)) { | ||
| 63 | inode->i_op = &page_symlink_inode_operations; | ||
| 64 | inode->i_data.a_ops = &cramfs_aops; | ||
| 65 | } else { | ||
| 66 | init_special_inode(inode, inode->i_mode, | ||
| 67 | old_decode_dev(cramfs_inode->size)); | ||
| 68 | } | ||
| 54 | } | 69 | } |
| 55 | 70 | ||
| 56 | static struct inode *get_cramfs_inode(struct super_block *sb, | 71 | static struct inode *get_cramfs_inode(struct super_block *sb, |
| 57 | struct cramfs_inode * cramfs_inode) | 72 | struct cramfs_inode * cramfs_inode) |
| 58 | { | 73 | { |
| 59 | struct inode *inode = iget5_locked(sb, CRAMINO(cramfs_inode), | 74 | struct inode *inode; |
| 60 | cramfs_iget5_test, cramfs_iget5_set, | 75 | if (CRAMINO(cramfs_inode) == 1) { |
| 61 | cramfs_inode); | 76 | inode = new_inode(sb); |
| 62 | static struct timespec zerotime; | 77 | if (inode) { |
| 63 | 78 | inode->i_ino = 1; | |
| 64 | if (inode && (inode->i_state & I_NEW)) { | 79 | setup_inode(inode, cramfs_inode); |
| 65 | inode->i_mode = cramfs_inode->mode; | 80 | } |
| 66 | inode->i_uid = cramfs_inode->uid; | 81 | } else { |
| 67 | inode->i_size = cramfs_inode->size; | 82 | inode = iget_locked(sb, CRAMINO(cramfs_inode)); |
| 68 | inode->i_blocks = (cramfs_inode->size - 1) / 512 + 1; | 83 | if (inode) { |
| 69 | inode->i_gid = cramfs_inode->gid; | 84 | setup_inode(inode, cramfs_inode); |
| 70 | /* Struct copy intentional */ | 85 | unlock_new_inode(inode); |
| 71 | inode->i_mtime = inode->i_atime = inode->i_ctime = zerotime; | ||
| 72 | /* inode->i_nlink is left 1 - arguably wrong for directories, | ||
| 73 | but it's the best we can do without reading the directory | ||
| 74 | contents. 1 yields the right result in GNU find, even | ||
| 75 | without -noleaf option. */ | ||
| 76 | if (S_ISREG(inode->i_mode)) { | ||
| 77 | inode->i_fop = &generic_ro_fops; | ||
| 78 | inode->i_data.a_ops = &cramfs_aops; | ||
| 79 | } else if (S_ISDIR(inode->i_mode)) { | ||
| 80 | inode->i_op = &cramfs_dir_inode_operations; | ||
| 81 | inode->i_fop = &cramfs_directory_operations; | ||
| 82 | } else if (S_ISLNK(inode->i_mode)) { | ||
| 83 | inode->i_op = &page_symlink_inode_operations; | ||
| 84 | inode->i_data.a_ops = &cramfs_aops; | ||
| 85 | } else { | ||
| 86 | init_special_inode(inode, inode->i_mode, | ||
| 87 | old_decode_dev(cramfs_inode->size)); | ||
| 88 | } | 86 | } |
| 89 | unlock_new_inode(inode); | ||
| 90 | } | 87 | } |
| 91 | return inode; | 88 | return inode; |
| 92 | } | 89 | } |
| 93 | 90 | ||
| 94 | static void cramfs_drop_inode(struct inode *inode) | ||
| 95 | { | ||
| 96 | if (inode->i_ino == 1) | ||
| 97 | generic_delete_inode(inode); | ||
| 98 | else | ||
| 99 | generic_drop_inode(inode); | ||
| 100 | } | ||
| 101 | |||
| 102 | /* | 91 | /* |
| 103 | * We have our own block cache: don't fill up the buffer cache | 92 | * We have our own block cache: don't fill up the buffer cache |
| 104 | * with the rom-image, because the way the filesystem is set | 93 | * with the rom-image, because the way the filesystem is set |
| @@ -542,7 +531,6 @@ static const struct super_operations cramfs_ops = { | |||
| 542 | .put_super = cramfs_put_super, | 531 | .put_super = cramfs_put_super, |
| 543 | .remount_fs = cramfs_remount, | 532 | .remount_fs = cramfs_remount, |
| 544 | .statfs = cramfs_statfs, | 533 | .statfs = cramfs_statfs, |
| 545 | .drop_inode = cramfs_drop_inode, | ||
| 546 | }; | 534 | }; |
| 547 | 535 | ||
| 548 | static int cramfs_get_sb(struct file_system_type *fs_type, | 536 | static int cramfs_get_sb(struct file_system_type *fs_type, |
diff --git a/fs/dcache.c b/fs/dcache.c index 86d4db15473e..166d35d56868 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
| @@ -536,7 +536,7 @@ restart: | |||
| 536 | */ | 536 | */ |
| 537 | static void prune_dcache(int count) | 537 | static void prune_dcache(int count) |
| 538 | { | 538 | { |
| 539 | struct super_block *sb, *n; | 539 | struct super_block *sb, *p = NULL; |
| 540 | int w_count; | 540 | int w_count; |
| 541 | int unused = dentry_stat.nr_unused; | 541 | int unused = dentry_stat.nr_unused; |
| 542 | int prune_ratio; | 542 | int prune_ratio; |
| @@ -550,7 +550,7 @@ static void prune_dcache(int count) | |||
| 550 | else | 550 | else |
| 551 | prune_ratio = unused / count; | 551 | prune_ratio = unused / count; |
| 552 | spin_lock(&sb_lock); | 552 | spin_lock(&sb_lock); |
| 553 | list_for_each_entry_safe(sb, n, &super_blocks, s_list) { | 553 | list_for_each_entry(sb, &super_blocks, s_list) { |
| 554 | if (list_empty(&sb->s_instances)) | 554 | if (list_empty(&sb->s_instances)) |
| 555 | continue; | 555 | continue; |
| 556 | if (sb->s_nr_dentry_unused == 0) | 556 | if (sb->s_nr_dentry_unused == 0) |
| @@ -590,14 +590,16 @@ static void prune_dcache(int count) | |||
| 590 | up_read(&sb->s_umount); | 590 | up_read(&sb->s_umount); |
| 591 | } | 591 | } |
| 592 | spin_lock(&sb_lock); | 592 | spin_lock(&sb_lock); |
| 593 | /* lock was dropped, must reset next */ | 593 | if (p) |
| 594 | list_safe_reset_next(sb, n, s_list); | 594 | __put_super(p); |
| 595 | count -= pruned; | 595 | count -= pruned; |
| 596 | __put_super(sb); | 596 | p = sb; |
| 597 | /* more work left to do? */ | 597 | /* more work left to do? */ |
| 598 | if (count <= 0) | 598 | if (count <= 0) |
| 599 | break; | 599 | break; |
| 600 | } | 600 | } |
| 601 | if (p) | ||
| 602 | __put_super(p); | ||
| 601 | spin_unlock(&sb_lock); | 603 | spin_unlock(&sb_lock); |
| 602 | spin_unlock(&dcache_lock); | 604 | spin_unlock(&dcache_lock); |
| 603 | } | 605 | } |
| @@ -1903,48 +1905,30 @@ static int prepend_name(char **buffer, int *buflen, struct qstr *name) | |||
| 1903 | } | 1905 | } |
| 1904 | 1906 | ||
| 1905 | /** | 1907 | /** |
| 1906 | * __d_path - return the path of a dentry | 1908 | * Prepend path string to a buffer |
| 1909 | * | ||
| 1907 | * @path: the dentry/vfsmount to report | 1910 | * @path: the dentry/vfsmount to report |
| 1908 | * @root: root vfsmnt/dentry (may be modified by this function) | 1911 | * @root: root vfsmnt/dentry (may be modified by this function) |
| 1909 | * @buffer: buffer to return value in | 1912 | * @buffer: pointer to the end of the buffer |
| 1910 | * @buflen: buffer length | 1913 | * @buflen: pointer to buffer length |
| 1911 | * | ||
| 1912 | * Convert a dentry into an ASCII path name. If the entry has been deleted | ||
| 1913 | * the string " (deleted)" is appended. Note that this is ambiguous. | ||
| 1914 | * | 1914 | * |
| 1915 | * Returns a pointer into the buffer or an error code if the | 1915 | * Caller holds the dcache_lock. |
| 1916 | * path was too long. | ||
| 1917 | * | ||
| 1918 | * "buflen" should be positive. Caller holds the dcache_lock. | ||
| 1919 | * | 1916 | * |
| 1920 | * If path is not reachable from the supplied root, then the value of | 1917 | * If path is not reachable from the supplied root, then the value of |
| 1921 | * root is changed (without modifying refcounts). | 1918 | * root is changed (without modifying refcounts). |
| 1922 | */ | 1919 | */ |
| 1923 | char *__d_path(const struct path *path, struct path *root, | 1920 | static int prepend_path(const struct path *path, struct path *root, |
| 1924 | char *buffer, int buflen) | 1921 | char **buffer, int *buflen) |
| 1925 | { | 1922 | { |
| 1926 | struct dentry *dentry = path->dentry; | 1923 | struct dentry *dentry = path->dentry; |
| 1927 | struct vfsmount *vfsmnt = path->mnt; | 1924 | struct vfsmount *vfsmnt = path->mnt; |
| 1928 | char *end = buffer + buflen; | 1925 | bool slash = false; |
| 1929 | char *retval; | 1926 | int error = 0; |
| 1930 | 1927 | ||
| 1931 | spin_lock(&vfsmount_lock); | 1928 | spin_lock(&vfsmount_lock); |
| 1932 | prepend(&end, &buflen, "\0", 1); | 1929 | while (dentry != root->dentry || vfsmnt != root->mnt) { |
| 1933 | if (d_unlinked(dentry) && | ||
| 1934 | (prepend(&end, &buflen, " (deleted)", 10) != 0)) | ||
| 1935 | goto Elong; | ||
| 1936 | |||
| 1937 | if (buflen < 1) | ||
| 1938 | goto Elong; | ||
| 1939 | /* Get '/' right */ | ||
| 1940 | retval = end-1; | ||
| 1941 | *retval = '/'; | ||
| 1942 | |||
| 1943 | for (;;) { | ||
| 1944 | struct dentry * parent; | 1930 | struct dentry * parent; |
| 1945 | 1931 | ||
| 1946 | if (dentry == root->dentry && vfsmnt == root->mnt) | ||
| 1947 | break; | ||
| 1948 | if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { | 1932 | if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { |
| 1949 | /* Global root? */ | 1933 | /* Global root? */ |
| 1950 | if (vfsmnt->mnt_parent == vfsmnt) { | 1934 | if (vfsmnt->mnt_parent == vfsmnt) { |
| @@ -1956,28 +1940,88 @@ char *__d_path(const struct path *path, struct path *root, | |||
| 1956 | } | 1940 | } |
| 1957 | parent = dentry->d_parent; | 1941 | parent = dentry->d_parent; |
| 1958 | prefetch(parent); | 1942 | prefetch(parent); |
| 1959 | if ((prepend_name(&end, &buflen, &dentry->d_name) != 0) || | 1943 | error = prepend_name(buffer, buflen, &dentry->d_name); |
| 1960 | (prepend(&end, &buflen, "/", 1) != 0)) | 1944 | if (!error) |
| 1961 | goto Elong; | 1945 | error = prepend(buffer, buflen, "/", 1); |
| 1962 | retval = end; | 1946 | if (error) |
| 1947 | break; | ||
| 1948 | |||
| 1949 | slash = true; | ||
| 1963 | dentry = parent; | 1950 | dentry = parent; |
| 1964 | } | 1951 | } |
| 1965 | 1952 | ||
| 1966 | out: | 1953 | out: |
| 1954 | if (!error && !slash) | ||
| 1955 | error = prepend(buffer, buflen, "/", 1); | ||
| 1956 | |||
| 1967 | spin_unlock(&vfsmount_lock); | 1957 | spin_unlock(&vfsmount_lock); |
| 1968 | return retval; | 1958 | return error; |
| 1969 | 1959 | ||
| 1970 | global_root: | 1960 | global_root: |
| 1971 | retval += 1; /* hit the slash */ | 1961 | /* |
| 1972 | if (prepend_name(&retval, &buflen, &dentry->d_name) != 0) | 1962 | * Filesystems needing to implement special "root names" |
| 1973 | goto Elong; | 1963 | * should do so with ->d_dname() |
| 1964 | */ | ||
| 1965 | if (IS_ROOT(dentry) && | ||
| 1966 | (dentry->d_name.len != 1 || dentry->d_name.name[0] != '/')) { | ||
| 1967 | WARN(1, "Root dentry has weird name <%.*s>\n", | ||
| 1968 | (int) dentry->d_name.len, dentry->d_name.name); | ||
| 1969 | } | ||
| 1974 | root->mnt = vfsmnt; | 1970 | root->mnt = vfsmnt; |
| 1975 | root->dentry = dentry; | 1971 | root->dentry = dentry; |
| 1976 | goto out; | 1972 | goto out; |
| 1973 | } | ||
| 1977 | 1974 | ||
| 1978 | Elong: | 1975 | /** |
| 1979 | retval = ERR_PTR(-ENAMETOOLONG); | 1976 | * __d_path - return the path of a dentry |
| 1980 | goto out; | 1977 | * @path: the dentry/vfsmount to report |
| 1978 | * @root: root vfsmnt/dentry (may be modified by this function) | ||
| 1979 | * @buffer: buffer to return value in | ||
| 1980 | * @buflen: buffer length | ||
| 1981 | * | ||
| 1982 | * Convert a dentry into an ASCII path name. | ||
| 1983 | * | ||
| 1984 | * Returns a pointer into the buffer or an error code if the | ||
| 1985 | * path was too long. | ||
| 1986 | * | ||
| 1987 | * "buflen" should be positive. Caller holds the dcache_lock. | ||
| 1988 | * | ||
| 1989 | * If path is not reachable from the supplied root, then the value of | ||
| 1990 | * root is changed (without modifying refcounts). | ||
| 1991 | */ | ||
| 1992 | char *__d_path(const struct path *path, struct path *root, | ||
| 1993 | char *buf, int buflen) | ||
| 1994 | { | ||
| 1995 | char *res = buf + buflen; | ||
| 1996 | int error; | ||
| 1997 | |||
| 1998 | prepend(&res, &buflen, "\0", 1); | ||
| 1999 | error = prepend_path(path, root, &res, &buflen); | ||
| 2000 | if (error) | ||
| 2001 | return ERR_PTR(error); | ||
| 2002 | |||
| 2003 | return res; | ||
| 2004 | } | ||
| 2005 | |||
| 2006 | /* | ||
| 2007 | * same as __d_path but appends "(deleted)" for unlinked files. | ||
| 2008 | */ | ||
| 2009 | static int path_with_deleted(const struct path *path, struct path *root, | ||
| 2010 | char **buf, int *buflen) | ||
| 2011 | { | ||
| 2012 | prepend(buf, buflen, "\0", 1); | ||
| 2013 | if (d_unlinked(path->dentry)) { | ||
| 2014 | int error = prepend(buf, buflen, " (deleted)", 10); | ||
| 2015 | if (error) | ||
| 2016 | return error; | ||
| 2017 | } | ||
| 2018 | |||
| 2019 | return prepend_path(path, root, buf, buflen); | ||
| 2020 | } | ||
| 2021 | |||
| 2022 | static int prepend_unreachable(char **buffer, int *buflen) | ||
| 2023 | { | ||
| 2024 | return prepend(buffer, buflen, "(unreachable)", 13); | ||
| 1981 | } | 2025 | } |
| 1982 | 2026 | ||
| 1983 | /** | 2027 | /** |
| @@ -1998,9 +2042,10 @@ Elong: | |||
| 1998 | */ | 2042 | */ |
| 1999 | char *d_path(const struct path *path, char *buf, int buflen) | 2043 | char *d_path(const struct path *path, char *buf, int buflen) |
| 2000 | { | 2044 | { |
| 2001 | char *res; | 2045 | char *res = buf + buflen; |
| 2002 | struct path root; | 2046 | struct path root; |
| 2003 | struct path tmp; | 2047 | struct path tmp; |
| 2048 | int error; | ||
| 2004 | 2049 | ||
| 2005 | /* | 2050 | /* |
| 2006 | * We have various synthetic filesystems that never get mounted. On | 2051 | * We have various synthetic filesystems that never get mounted. On |
| @@ -2012,19 +2057,51 @@ char *d_path(const struct path *path, char *buf, int buflen) | |||
| 2012 | if (path->dentry->d_op && path->dentry->d_op->d_dname) | 2057 | if (path->dentry->d_op && path->dentry->d_op->d_dname) |
| 2013 | return path->dentry->d_op->d_dname(path->dentry, buf, buflen); | 2058 | return path->dentry->d_op->d_dname(path->dentry, buf, buflen); |
| 2014 | 2059 | ||
| 2015 | read_lock(¤t->fs->lock); | 2060 | get_fs_root(current->fs, &root); |
| 2016 | root = current->fs->root; | ||
| 2017 | path_get(&root); | ||
| 2018 | read_unlock(¤t->fs->lock); | ||
| 2019 | spin_lock(&dcache_lock); | 2061 | spin_lock(&dcache_lock); |
| 2020 | tmp = root; | 2062 | tmp = root; |
| 2021 | res = __d_path(path, &tmp, buf, buflen); | 2063 | error = path_with_deleted(path, &tmp, &res, &buflen); |
| 2064 | if (error) | ||
| 2065 | res = ERR_PTR(error); | ||
| 2022 | spin_unlock(&dcache_lock); | 2066 | spin_unlock(&dcache_lock); |
| 2023 | path_put(&root); | 2067 | path_put(&root); |
| 2024 | return res; | 2068 | return res; |
| 2025 | } | 2069 | } |
| 2026 | EXPORT_SYMBOL(d_path); | 2070 | EXPORT_SYMBOL(d_path); |
| 2027 | 2071 | ||
| 2072 | /** | ||
| 2073 | * d_path_with_unreachable - return the path of a dentry | ||
| 2074 | * @path: path to report | ||
| 2075 | * @buf: buffer to return value in | ||
| 2076 | * @buflen: buffer length | ||
| 2077 | * | ||
| 2078 | * The difference from d_path() is that this prepends "(unreachable)" | ||
| 2079 | * to paths which are unreachable from the current process' root. | ||
| 2080 | */ | ||
| 2081 | char *d_path_with_unreachable(const struct path *path, char *buf, int buflen) | ||
| 2082 | { | ||
| 2083 | char *res = buf + buflen; | ||
| 2084 | struct path root; | ||
| 2085 | struct path tmp; | ||
| 2086 | int error; | ||
| 2087 | |||
| 2088 | if (path->dentry->d_op && path->dentry->d_op->d_dname) | ||
| 2089 | return path->dentry->d_op->d_dname(path->dentry, buf, buflen); | ||
| 2090 | |||
| 2091 | get_fs_root(current->fs, &root); | ||
| 2092 | spin_lock(&dcache_lock); | ||
| 2093 | tmp = root; | ||
| 2094 | error = path_with_deleted(path, &tmp, &res, &buflen); | ||
| 2095 | if (!error && !path_equal(&tmp, &root)) | ||
| 2096 | error = prepend_unreachable(&res, &buflen); | ||
| 2097 | spin_unlock(&dcache_lock); | ||
| 2098 | path_put(&root); | ||
| 2099 | if (error) | ||
| 2100 | res = ERR_PTR(error); | ||
| 2101 | |||
| 2102 | return res; | ||
| 2103 | } | ||
| 2104 | |||
| 2028 | /* | 2105 | /* |
| 2029 | * Helper function for dentry_operations.d_dname() members | 2106 | * Helper function for dentry_operations.d_dname() members |
| 2030 | */ | 2107 | */ |
| @@ -2049,16 +2126,12 @@ char *dynamic_dname(struct dentry *dentry, char *buffer, int buflen, | |||
| 2049 | /* | 2126 | /* |
| 2050 | * Write full pathname from the root of the filesystem into the buffer. | 2127 | * Write full pathname from the root of the filesystem into the buffer. |
| 2051 | */ | 2128 | */ |
| 2052 | char *dentry_path(struct dentry *dentry, char *buf, int buflen) | 2129 | char *__dentry_path(struct dentry *dentry, char *buf, int buflen) |
| 2053 | { | 2130 | { |
| 2054 | char *end = buf + buflen; | 2131 | char *end = buf + buflen; |
| 2055 | char *retval; | 2132 | char *retval; |
| 2056 | 2133 | ||
| 2057 | spin_lock(&dcache_lock); | ||
| 2058 | prepend(&end, &buflen, "\0", 1); | 2134 | prepend(&end, &buflen, "\0", 1); |
| 2059 | if (d_unlinked(dentry) && | ||
| 2060 | (prepend(&end, &buflen, "//deleted", 9) != 0)) | ||
| 2061 | goto Elong; | ||
| 2062 | if (buflen < 1) | 2135 | if (buflen < 1) |
| 2063 | goto Elong; | 2136 | goto Elong; |
| 2064 | /* Get '/' right */ | 2137 | /* Get '/' right */ |
| @@ -2076,7 +2149,28 @@ char *dentry_path(struct dentry *dentry, char *buf, int buflen) | |||
| 2076 | retval = end; | 2149 | retval = end; |
| 2077 | dentry = parent; | 2150 | dentry = parent; |
| 2078 | } | 2151 | } |
| 2152 | return retval; | ||
| 2153 | Elong: | ||
| 2154 | return ERR_PTR(-ENAMETOOLONG); | ||
| 2155 | } | ||
| 2156 | EXPORT_SYMBOL(__dentry_path); | ||
| 2157 | |||
| 2158 | char *dentry_path(struct dentry *dentry, char *buf, int buflen) | ||
| 2159 | { | ||
| 2160 | char *p = NULL; | ||
| 2161 | char *retval; | ||
| 2162 | |||
| 2163 | spin_lock(&dcache_lock); | ||
| 2164 | if (d_unlinked(dentry)) { | ||
| 2165 | p = buf + buflen; | ||
| 2166 | if (prepend(&p, &buflen, "//deleted", 10) != 0) | ||
| 2167 | goto Elong; | ||
| 2168 | buflen++; | ||
| 2169 | } | ||
| 2170 | retval = __dentry_path(dentry, buf, buflen); | ||
| 2079 | spin_unlock(&dcache_lock); | 2171 | spin_unlock(&dcache_lock); |
| 2172 | if (!IS_ERR(retval) && p) | ||
| 2173 | *p = '/'; /* restore '/' overriden with '\0' */ | ||
| 2080 | return retval; | 2174 | return retval; |
| 2081 | Elong: | 2175 | Elong: |
| 2082 | spin_unlock(&dcache_lock); | 2176 | spin_unlock(&dcache_lock); |
| @@ -2110,27 +2204,30 @@ SYSCALL_DEFINE2(getcwd, char __user *, buf, unsigned long, size) | |||
| 2110 | if (!page) | 2204 | if (!page) |
| 2111 | return -ENOMEM; | 2205 | return -ENOMEM; |
| 2112 | 2206 | ||
| 2113 | read_lock(¤t->fs->lock); | 2207 | get_fs_root_and_pwd(current->fs, &root, &pwd); |
| 2114 | pwd = current->fs->pwd; | ||
| 2115 | path_get(&pwd); | ||
| 2116 | root = current->fs->root; | ||
| 2117 | path_get(&root); | ||
| 2118 | read_unlock(¤t->fs->lock); | ||
| 2119 | 2208 | ||
| 2120 | error = -ENOENT; | 2209 | error = -ENOENT; |
| 2121 | spin_lock(&dcache_lock); | 2210 | spin_lock(&dcache_lock); |
| 2122 | if (!d_unlinked(pwd.dentry)) { | 2211 | if (!d_unlinked(pwd.dentry)) { |
| 2123 | unsigned long len; | 2212 | unsigned long len; |
| 2124 | struct path tmp = root; | 2213 | struct path tmp = root; |
| 2125 | char * cwd; | 2214 | char *cwd = page + PAGE_SIZE; |
| 2215 | int buflen = PAGE_SIZE; | ||
| 2126 | 2216 | ||
| 2127 | cwd = __d_path(&pwd, &tmp, page, PAGE_SIZE); | 2217 | prepend(&cwd, &buflen, "\0", 1); |
| 2218 | error = prepend_path(&pwd, &tmp, &cwd, &buflen); | ||
| 2128 | spin_unlock(&dcache_lock); | 2219 | spin_unlock(&dcache_lock); |
| 2129 | 2220 | ||
| 2130 | error = PTR_ERR(cwd); | 2221 | if (error) |
| 2131 | if (IS_ERR(cwd)) | ||
| 2132 | goto out; | 2222 | goto out; |
| 2133 | 2223 | ||
| 2224 | /* Unreachable from current root */ | ||
| 2225 | if (!path_equal(&tmp, &root)) { | ||
| 2226 | error = prepend_unreachable(&cwd, &buflen); | ||
| 2227 | if (error) | ||
| 2228 | goto out; | ||
| 2229 | } | ||
| 2230 | |||
| 2134 | error = -ERANGE; | 2231 | error = -ERANGE; |
| 2135 | len = PAGE_SIZE + page - cwd; | 2232 | len = PAGE_SIZE + page - cwd; |
| 2136 | if (len <= size) { | 2233 | if (len <= size) { |
diff --git a/fs/direct-io.c b/fs/direct-io.c index a10cb91cadea..51f270b479b6 100644 --- a/fs/direct-io.c +++ b/fs/direct-io.c | |||
| @@ -1136,8 +1136,27 @@ direct_io_worker(int rw, struct kiocb *iocb, struct inode *inode, | |||
| 1136 | return ret; | 1136 | return ret; |
| 1137 | } | 1137 | } |
| 1138 | 1138 | ||
| 1139 | /* | ||
| 1140 | * This is a library function for use by filesystem drivers. | ||
| 1141 | * | ||
| 1142 | * The locking rules are governed by the flags parameter: | ||
| 1143 | * - if the flags value contains DIO_LOCKING we use a fancy locking | ||
| 1144 | * scheme for dumb filesystems. | ||
| 1145 | * For writes this function is called under i_mutex and returns with | ||
| 1146 | * i_mutex held, for reads, i_mutex is not held on entry, but it is | ||
| 1147 | * taken and dropped again before returning. | ||
| 1148 | * For reads and writes i_alloc_sem is taken in shared mode and released | ||
| 1149 | * on I/O completion (which may happen asynchronously after returning to | ||
| 1150 | * the caller). | ||
| 1151 | * | ||
| 1152 | * - if the flags value does NOT contain DIO_LOCKING we don't use any | ||
| 1153 | * internal locking but rather rely on the filesystem to synchronize | ||
| 1154 | * direct I/O reads/writes versus each other and truncate. | ||
| 1155 | * For reads and writes both i_mutex and i_alloc_sem are not held on | ||
| 1156 | * entry and are never taken. | ||
| 1157 | */ | ||
| 1139 | ssize_t | 1158 | ssize_t |
| 1140 | __blockdev_direct_IO_newtrunc(int rw, struct kiocb *iocb, struct inode *inode, | 1159 | __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, |
| 1141 | struct block_device *bdev, const struct iovec *iov, loff_t offset, | 1160 | struct block_device *bdev, const struct iovec *iov, loff_t offset, |
| 1142 | unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io, | 1161 | unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io, |
| 1143 | dio_submit_t submit_io, int flags) | 1162 | dio_submit_t submit_io, int flags) |
| @@ -1233,57 +1252,4 @@ __blockdev_direct_IO_newtrunc(int rw, struct kiocb *iocb, struct inode *inode, | |||
| 1233 | out: | 1252 | out: |
| 1234 | return retval; | 1253 | return retval; |
| 1235 | } | 1254 | } |
| 1236 | EXPORT_SYMBOL(__blockdev_direct_IO_newtrunc); | ||
| 1237 | |||
| 1238 | /* | ||
| 1239 | * This is a library function for use by filesystem drivers. | ||
| 1240 | * | ||
| 1241 | * The locking rules are governed by the flags parameter: | ||
| 1242 | * - if the flags value contains DIO_LOCKING we use a fancy locking | ||
| 1243 | * scheme for dumb filesystems. | ||
| 1244 | * For writes this function is called under i_mutex and returns with | ||
| 1245 | * i_mutex held, for reads, i_mutex is not held on entry, but it is | ||
| 1246 | * taken and dropped again before returning. | ||
| 1247 | * For reads and writes i_alloc_sem is taken in shared mode and released | ||
| 1248 | * on I/O completion (which may happen asynchronously after returning to | ||
| 1249 | * the caller). | ||
| 1250 | * | ||
| 1251 | * - if the flags value does NOT contain DIO_LOCKING we don't use any | ||
| 1252 | * internal locking but rather rely on the filesystem to synchronize | ||
| 1253 | * direct I/O reads/writes versus each other and truncate. | ||
| 1254 | * For reads and writes both i_mutex and i_alloc_sem are not held on | ||
| 1255 | * entry and are never taken. | ||
| 1256 | */ | ||
| 1257 | ssize_t | ||
| 1258 | __blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode, | ||
| 1259 | struct block_device *bdev, const struct iovec *iov, loff_t offset, | ||
| 1260 | unsigned long nr_segs, get_block_t get_block, dio_iodone_t end_io, | ||
| 1261 | dio_submit_t submit_io, int flags) | ||
| 1262 | { | ||
| 1263 | ssize_t retval; | ||
| 1264 | |||
| 1265 | retval = __blockdev_direct_IO_newtrunc(rw, iocb, inode, bdev, iov, | ||
| 1266 | offset, nr_segs, get_block, end_io, submit_io, flags); | ||
| 1267 | /* | ||
| 1268 | * In case of error extending write may have instantiated a few | ||
| 1269 | * blocks outside i_size. Trim these off again for DIO_LOCKING. | ||
| 1270 | * NOTE: DIO_NO_LOCK/DIO_OWN_LOCK callers have to handle this in | ||
| 1271 | * their own manner. This is a further example of where the old | ||
| 1272 | * truncate sequence is inadequate. | ||
| 1273 | * | ||
| 1274 | * NOTE: filesystems with their own locking have to handle this | ||
| 1275 | * on their own. | ||
| 1276 | */ | ||
| 1277 | if (flags & DIO_LOCKING) { | ||
| 1278 | if (unlikely((rw & WRITE) && retval < 0)) { | ||
| 1279 | loff_t isize = i_size_read(inode); | ||
| 1280 | loff_t end = offset + iov_length(iov, nr_segs); | ||
| 1281 | |||
| 1282 | if (end > isize) | ||
| 1283 | vmtruncate(inode, isize); | ||
| 1284 | } | ||
| 1285 | } | ||
| 1286 | |||
| 1287 | return retval; | ||
| 1288 | } | ||
| 1289 | EXPORT_SYMBOL(__blockdev_direct_IO); | 1255 | EXPORT_SYMBOL(__blockdev_direct_IO); |
diff --git a/fs/drop_caches.c b/fs/drop_caches.c index 83c4f600786a..2195c213ab2f 100644 --- a/fs/drop_caches.c +++ b/fs/drop_caches.c | |||
| @@ -18,7 +18,7 @@ static void drop_pagecache_sb(struct super_block *sb, void *unused) | |||
| 18 | 18 | ||
| 19 | spin_lock(&inode_lock); | 19 | spin_lock(&inode_lock); |
| 20 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { | 20 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { |
| 21 | if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE|I_NEW)) | 21 | if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) |
| 22 | continue; | 22 | continue; |
| 23 | if (inode->i_mapping->nrpages == 0) | 23 | if (inode->i_mapping->nrpages == 0) |
| 24 | continue; | 24 | continue; |
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index e8fcf4e2ed7d..622c95140802 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c | |||
| @@ -199,7 +199,7 @@ static int ecryptfs_open(struct inode *inode, struct file *file) | |||
| 199 | "the persistent file for the dentry with name " | 199 | "the persistent file for the dentry with name " |
| 200 | "[%s]; rc = [%d]\n", __func__, | 200 | "[%s]; rc = [%d]\n", __func__, |
| 201 | ecryptfs_dentry->d_name.name, rc); | 201 | ecryptfs_dentry->d_name.name, rc); |
| 202 | goto out; | 202 | goto out_free; |
| 203 | } | 203 | } |
| 204 | } | 204 | } |
| 205 | if ((ecryptfs_inode_to_private(inode)->lower_file->f_flags & O_RDONLY) | 205 | if ((ecryptfs_inode_to_private(inode)->lower_file->f_flags & O_RDONLY) |
| @@ -207,7 +207,7 @@ static int ecryptfs_open(struct inode *inode, struct file *file) | |||
| 207 | rc = -EPERM; | 207 | rc = -EPERM; |
| 208 | printk(KERN_WARNING "%s: Lower persistent file is RO; eCryptfs " | 208 | printk(KERN_WARNING "%s: Lower persistent file is RO; eCryptfs " |
| 209 | "file must hence be opened RO\n", __func__); | 209 | "file must hence be opened RO\n", __func__); |
| 210 | goto out; | 210 | goto out_free; |
| 211 | } | 211 | } |
| 212 | ecryptfs_set_file_lower( | 212 | ecryptfs_set_file_lower( |
| 213 | file, ecryptfs_inode_to_private(inode)->lower_file); | 213 | file, ecryptfs_inode_to_private(inode)->lower_file); |
| @@ -292,12 +292,40 @@ static int ecryptfs_fasync(int fd, struct file *file, int flag) | |||
| 292 | return rc; | 292 | return rc; |
| 293 | } | 293 | } |
| 294 | 294 | ||
| 295 | static int ecryptfs_ioctl(struct inode *inode, struct file *file, | 295 | static long |
| 296 | unsigned int cmd, unsigned long arg); | 296 | ecryptfs_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
| 297 | { | ||
| 298 | struct file *lower_file = NULL; | ||
| 299 | long rc = -ENOTTY; | ||
| 300 | |||
| 301 | if (ecryptfs_file_to_private(file)) | ||
| 302 | lower_file = ecryptfs_file_to_lower(file); | ||
| 303 | if (lower_file && lower_file->f_op && lower_file->f_op->unlocked_ioctl) | ||
| 304 | rc = lower_file->f_op->unlocked_ioctl(lower_file, cmd, arg); | ||
| 305 | return rc; | ||
| 306 | } | ||
| 307 | |||
| 308 | #ifdef CONFIG_COMPAT | ||
| 309 | static long | ||
| 310 | ecryptfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
| 311 | { | ||
| 312 | struct file *lower_file = NULL; | ||
| 313 | long rc = -ENOIOCTLCMD; | ||
| 314 | |||
| 315 | if (ecryptfs_file_to_private(file)) | ||
| 316 | lower_file = ecryptfs_file_to_lower(file); | ||
| 317 | if (lower_file && lower_file->f_op && lower_file->f_op->compat_ioctl) | ||
| 318 | rc = lower_file->f_op->compat_ioctl(lower_file, cmd, arg); | ||
| 319 | return rc; | ||
| 320 | } | ||
| 321 | #endif | ||
| 297 | 322 | ||
| 298 | const struct file_operations ecryptfs_dir_fops = { | 323 | const struct file_operations ecryptfs_dir_fops = { |
| 299 | .readdir = ecryptfs_readdir, | 324 | .readdir = ecryptfs_readdir, |
| 300 | .ioctl = ecryptfs_ioctl, | 325 | .unlocked_ioctl = ecryptfs_unlocked_ioctl, |
| 326 | #ifdef CONFIG_COMPAT | ||
| 327 | .compat_ioctl = ecryptfs_compat_ioctl, | ||
| 328 | #endif | ||
| 301 | .open = ecryptfs_open, | 329 | .open = ecryptfs_open, |
| 302 | .flush = ecryptfs_flush, | 330 | .flush = ecryptfs_flush, |
| 303 | .release = ecryptfs_release, | 331 | .release = ecryptfs_release, |
| @@ -313,7 +341,10 @@ const struct file_operations ecryptfs_main_fops = { | |||
| 313 | .write = do_sync_write, | 341 | .write = do_sync_write, |
| 314 | .aio_write = generic_file_aio_write, | 342 | .aio_write = generic_file_aio_write, |
| 315 | .readdir = ecryptfs_readdir, | 343 | .readdir = ecryptfs_readdir, |
| 316 | .ioctl = ecryptfs_ioctl, | 344 | .unlocked_ioctl = ecryptfs_unlocked_ioctl, |
| 345 | #ifdef CONFIG_COMPAT | ||
| 346 | .compat_ioctl = ecryptfs_compat_ioctl, | ||
| 347 | #endif | ||
| 317 | .mmap = generic_file_mmap, | 348 | .mmap = generic_file_mmap, |
| 318 | .open = ecryptfs_open, | 349 | .open = ecryptfs_open, |
| 319 | .flush = ecryptfs_flush, | 350 | .flush = ecryptfs_flush, |
| @@ -322,20 +353,3 @@ const struct file_operations ecryptfs_main_fops = { | |||
| 322 | .fasync = ecryptfs_fasync, | 353 | .fasync = ecryptfs_fasync, |
| 323 | .splice_read = generic_file_splice_read, | 354 | .splice_read = generic_file_splice_read, |
| 324 | }; | 355 | }; |
| 325 | |||
| 326 | static int | ||
| 327 | ecryptfs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | ||
| 328 | unsigned long arg) | ||
| 329 | { | ||
| 330 | int rc = 0; | ||
| 331 | struct file *lower_file = NULL; | ||
| 332 | |||
| 333 | if (ecryptfs_file_to_private(file)) | ||
| 334 | lower_file = ecryptfs_file_to_lower(file); | ||
| 335 | if (lower_file && lower_file->f_op && lower_file->f_op->ioctl) | ||
| 336 | rc = lower_file->f_op->ioctl(ecryptfs_inode_to_lower(inode), | ||
| 337 | lower_file, cmd, arg); | ||
| 338 | else | ||
| 339 | rc = -ENOTTY; | ||
| 340 | return rc; | ||
| 341 | } | ||
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 31ef5252f0fe..6c55113e7222 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c | |||
| @@ -264,7 +264,7 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, | |||
| 264 | printk(KERN_ERR "%s: Out of memory whilst attempting " | 264 | printk(KERN_ERR "%s: Out of memory whilst attempting " |
| 265 | "to allocate ecryptfs_dentry_info struct\n", | 265 | "to allocate ecryptfs_dentry_info struct\n", |
| 266 | __func__); | 266 | __func__); |
| 267 | goto out_dput; | 267 | goto out_put; |
| 268 | } | 268 | } |
| 269 | ecryptfs_set_dentry_lower(ecryptfs_dentry, lower_dentry); | 269 | ecryptfs_set_dentry_lower(ecryptfs_dentry, lower_dentry); |
| 270 | ecryptfs_set_dentry_lower_mnt(ecryptfs_dentry, lower_mnt); | 270 | ecryptfs_set_dentry_lower_mnt(ecryptfs_dentry, lower_mnt); |
| @@ -339,14 +339,85 @@ int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry, | |||
| 339 | out_free_kmem: | 339 | out_free_kmem: |
| 340 | kmem_cache_free(ecryptfs_header_cache_2, page_virt); | 340 | kmem_cache_free(ecryptfs_header_cache_2, page_virt); |
| 341 | goto out; | 341 | goto out; |
| 342 | out_dput: | 342 | out_put: |
| 343 | dput(lower_dentry); | 343 | dput(lower_dentry); |
| 344 | mntput(lower_mnt); | ||
| 344 | d_drop(ecryptfs_dentry); | 345 | d_drop(ecryptfs_dentry); |
| 345 | out: | 346 | out: |
| 346 | return rc; | 347 | return rc; |
| 347 | } | 348 | } |
| 348 | 349 | ||
| 349 | /** | 350 | /** |
| 351 | * ecryptfs_new_lower_dentry | ||
| 352 | * @ename: The name of the new dentry. | ||
| 353 | * @lower_dir_dentry: Parent directory of the new dentry. | ||
| 354 | * @nd: nameidata from last lookup. | ||
| 355 | * | ||
| 356 | * Create a new dentry or get it from lower parent dir. | ||
| 357 | */ | ||
| 358 | static struct dentry * | ||
| 359 | ecryptfs_new_lower_dentry(struct qstr *name, struct dentry *lower_dir_dentry, | ||
| 360 | struct nameidata *nd) | ||
| 361 | { | ||
| 362 | struct dentry *new_dentry; | ||
| 363 | struct dentry *tmp; | ||
| 364 | struct inode *lower_dir_inode; | ||
| 365 | |||
| 366 | lower_dir_inode = lower_dir_dentry->d_inode; | ||
| 367 | |||
| 368 | tmp = d_alloc(lower_dir_dentry, name); | ||
| 369 | if (!tmp) | ||
| 370 | return ERR_PTR(-ENOMEM); | ||
| 371 | |||
| 372 | mutex_lock(&lower_dir_inode->i_mutex); | ||
| 373 | new_dentry = lower_dir_inode->i_op->lookup(lower_dir_inode, tmp, nd); | ||
| 374 | mutex_unlock(&lower_dir_inode->i_mutex); | ||
| 375 | |||
| 376 | if (!new_dentry) | ||
| 377 | new_dentry = tmp; | ||
| 378 | else | ||
| 379 | dput(tmp); | ||
| 380 | |||
| 381 | return new_dentry; | ||
| 382 | } | ||
| 383 | |||
| 384 | |||
| 385 | /** | ||
| 386 | * ecryptfs_lookup_one_lower | ||
| 387 | * @ecryptfs_dentry: The eCryptfs dentry that we are looking up | ||
| 388 | * @lower_dir_dentry: lower parent directory | ||
| 389 | * | ||
| 390 | * Get the lower dentry from vfs. If lower dentry does not exist yet, | ||
| 391 | * create it. | ||
| 392 | */ | ||
| 393 | static struct dentry * | ||
| 394 | ecryptfs_lookup_one_lower(struct dentry *ecryptfs_dentry, | ||
| 395 | struct dentry *lower_dir_dentry) | ||
| 396 | { | ||
| 397 | struct nameidata nd; | ||
| 398 | struct vfsmount *lower_mnt; | ||
| 399 | struct qstr *name; | ||
| 400 | int err; | ||
| 401 | |||
| 402 | name = &ecryptfs_dentry->d_name; | ||
| 403 | lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt( | ||
| 404 | ecryptfs_dentry->d_parent)); | ||
| 405 | err = vfs_path_lookup(lower_dir_dentry, lower_mnt, name->name , 0, &nd); | ||
| 406 | mntput(lower_mnt); | ||
| 407 | |||
| 408 | if (!err) { | ||
| 409 | /* we dont need the mount */ | ||
| 410 | mntput(nd.path.mnt); | ||
| 411 | return nd.path.dentry; | ||
| 412 | } | ||
| 413 | if (err != -ENOENT) | ||
| 414 | return ERR_PTR(err); | ||
| 415 | |||
| 416 | /* create a new lower dentry */ | ||
| 417 | return ecryptfs_new_lower_dentry(name, lower_dir_dentry, &nd); | ||
| 418 | } | ||
| 419 | |||
| 420 | /** | ||
| 350 | * ecryptfs_lookup | 421 | * ecryptfs_lookup |
| 351 | * @ecryptfs_dir_inode: The eCryptfs directory inode | 422 | * @ecryptfs_dir_inode: The eCryptfs directory inode |
| 352 | * @ecryptfs_dentry: The eCryptfs dentry that we are looking up | 423 | * @ecryptfs_dentry: The eCryptfs dentry that we are looking up |
| @@ -373,14 +444,12 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, | |||
| 373 | goto out_d_drop; | 444 | goto out_d_drop; |
| 374 | } | 445 | } |
| 375 | lower_dir_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry->d_parent); | 446 | lower_dir_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry->d_parent); |
| 376 | mutex_lock(&lower_dir_dentry->d_inode->i_mutex); | 447 | |
| 377 | lower_dentry = lookup_one_len(ecryptfs_dentry->d_name.name, | 448 | lower_dentry = ecryptfs_lookup_one_lower(ecryptfs_dentry, |
| 378 | lower_dir_dentry, | 449 | lower_dir_dentry); |
| 379 | ecryptfs_dentry->d_name.len); | ||
| 380 | mutex_unlock(&lower_dir_dentry->d_inode->i_mutex); | ||
| 381 | if (IS_ERR(lower_dentry)) { | 450 | if (IS_ERR(lower_dentry)) { |
| 382 | rc = PTR_ERR(lower_dentry); | 451 | rc = PTR_ERR(lower_dentry); |
| 383 | ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned " | 452 | ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_lower() returned " |
| 384 | "[%d] on lower_dentry = [%s]\n", __func__, rc, | 453 | "[%d] on lower_dentry = [%s]\n", __func__, rc, |
| 385 | encrypted_and_encoded_name); | 454 | encrypted_and_encoded_name); |
| 386 | goto out_d_drop; | 455 | goto out_d_drop; |
| @@ -402,14 +471,11 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, | |||
| 402 | "filename; rc = [%d]\n", __func__, rc); | 471 | "filename; rc = [%d]\n", __func__, rc); |
| 403 | goto out_d_drop; | 472 | goto out_d_drop; |
| 404 | } | 473 | } |
| 405 | mutex_lock(&lower_dir_dentry->d_inode->i_mutex); | 474 | lower_dentry = ecryptfs_lookup_one_lower(ecryptfs_dentry, |
| 406 | lower_dentry = lookup_one_len(encrypted_and_encoded_name, | 475 | lower_dir_dentry); |
| 407 | lower_dir_dentry, | ||
| 408 | encrypted_and_encoded_name_size - 1); | ||
| 409 | mutex_unlock(&lower_dir_dentry->d_inode->i_mutex); | ||
| 410 | if (IS_ERR(lower_dentry)) { | 476 | if (IS_ERR(lower_dentry)) { |
| 411 | rc = PTR_ERR(lower_dentry); | 477 | rc = PTR_ERR(lower_dentry); |
| 412 | ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_len() returned " | 478 | ecryptfs_printk(KERN_DEBUG, "%s: lookup_one_lower() returned " |
| 413 | "[%d] on lower_dentry = [%s]\n", __func__, rc, | 479 | "[%d] on lower_dentry = [%s]\n", __func__, rc, |
| 414 | encrypted_and_encoded_name); | 480 | encrypted_and_encoded_name); |
| 415 | goto out_d_drop; | 481 | goto out_d_drop; |
| @@ -804,10 +870,20 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia, | |||
| 804 | size_t num_zeros = (PAGE_CACHE_SIZE | 870 | size_t num_zeros = (PAGE_CACHE_SIZE |
| 805 | - (ia->ia_size & ~PAGE_CACHE_MASK)); | 871 | - (ia->ia_size & ~PAGE_CACHE_MASK)); |
| 806 | 872 | ||
| 873 | |||
| 874 | /* | ||
| 875 | * XXX(truncate) this should really happen at the begginning | ||
| 876 | * of ->setattr. But the code is too messy to that as part | ||
| 877 | * of a larger patch. ecryptfs is also totally missing out | ||
| 878 | * on the inode_change_ok check at the beginning of | ||
| 879 | * ->setattr while would include this. | ||
| 880 | */ | ||
| 881 | rc = inode_newsize_ok(inode, ia->ia_size); | ||
| 882 | if (rc) | ||
| 883 | goto out; | ||
| 884 | |||
| 807 | if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { | 885 | if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { |
| 808 | rc = simple_setsize(inode, ia->ia_size); | 886 | truncate_setsize(inode, ia->ia_size); |
| 809 | if (rc) | ||
| 810 | goto out; | ||
| 811 | lower_ia->ia_size = ia->ia_size; | 887 | lower_ia->ia_size = ia->ia_size; |
| 812 | lower_ia->ia_valid |= ATTR_SIZE; | 888 | lower_ia->ia_valid |= ATTR_SIZE; |
| 813 | goto out; | 889 | goto out; |
| @@ -830,7 +906,7 @@ static int truncate_upper(struct dentry *dentry, struct iattr *ia, | |||
| 830 | goto out; | 906 | goto out; |
| 831 | } | 907 | } |
| 832 | } | 908 | } |
| 833 | simple_setsize(inode, ia->ia_size); | 909 | truncate_setsize(inode, ia->ia_size); |
| 834 | rc = ecryptfs_write_inode_size_to_metadata(inode); | 910 | rc = ecryptfs_write_inode_size_to_metadata(inode); |
| 835 | if (rc) { | 911 | if (rc) { |
| 836 | printk(KERN_ERR "Problem with " | 912 | printk(KERN_ERR "Problem with " |
diff --git a/fs/ecryptfs/messaging.c b/fs/ecryptfs/messaging.c index 46c4dd8dfcc3..bcb68c0cb1f0 100644 --- a/fs/ecryptfs/messaging.c +++ b/fs/ecryptfs/messaging.c | |||
| @@ -274,7 +274,7 @@ int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid, | |||
| 274 | struct user_namespace *user_ns, struct pid *pid, | 274 | struct user_namespace *user_ns, struct pid *pid, |
| 275 | u32 seq) | 275 | u32 seq) |
| 276 | { | 276 | { |
| 277 | struct ecryptfs_daemon *daemon; | 277 | struct ecryptfs_daemon *uninitialized_var(daemon); |
| 278 | struct ecryptfs_msg_ctx *msg_ctx; | 278 | struct ecryptfs_msg_ctx *msg_ctx; |
| 279 | size_t msg_size; | 279 | size_t msg_size; |
| 280 | struct nsproxy *nsproxy; | 280 | struct nsproxy *nsproxy; |
diff --git a/fs/ecryptfs/super.c b/fs/ecryptfs/super.c index 0435886e4a9f..f7fc286a3aa9 100644 --- a/fs/ecryptfs/super.c +++ b/fs/ecryptfs/super.c | |||
| @@ -118,11 +118,15 @@ void ecryptfs_init_inode(struct inode *inode, struct inode *lower_inode) | |||
| 118 | */ | 118 | */ |
| 119 | static int ecryptfs_statfs(struct dentry *dentry, struct kstatfs *buf) | 119 | static int ecryptfs_statfs(struct dentry *dentry, struct kstatfs *buf) |
| 120 | { | 120 | { |
| 121 | return vfs_statfs(ecryptfs_dentry_to_lower(dentry), buf); | 121 | struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); |
| 122 | |||
| 123 | if (!lower_dentry->d_sb->s_op->statfs) | ||
| 124 | return -ENOSYS; | ||
| 125 | return lower_dentry->d_sb->s_op->statfs(lower_dentry, buf); | ||
| 122 | } | 126 | } |
| 123 | 127 | ||
| 124 | /** | 128 | /** |
| 125 | * ecryptfs_clear_inode | 129 | * ecryptfs_evict_inode |
| 126 | * @inode - The ecryptfs inode | 130 | * @inode - The ecryptfs inode |
| 127 | * | 131 | * |
| 128 | * Called by iput() when the inode reference count reached zero | 132 | * Called by iput() when the inode reference count reached zero |
| @@ -131,8 +135,10 @@ static int ecryptfs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
| 131 | * on the inode free list. We use this to drop out reference to the | 135 | * on the inode free list. We use this to drop out reference to the |
| 132 | * lower inode. | 136 | * lower inode. |
| 133 | */ | 137 | */ |
| 134 | static void ecryptfs_clear_inode(struct inode *inode) | 138 | static void ecryptfs_evict_inode(struct inode *inode) |
| 135 | { | 139 | { |
| 140 | truncate_inode_pages(&inode->i_data, 0); | ||
| 141 | end_writeback(inode); | ||
| 136 | iput(ecryptfs_inode_to_lower(inode)); | 142 | iput(ecryptfs_inode_to_lower(inode)); |
| 137 | } | 143 | } |
| 138 | 144 | ||
| @@ -184,6 +190,6 @@ const struct super_operations ecryptfs_sops = { | |||
| 184 | .drop_inode = generic_delete_inode, | 190 | .drop_inode = generic_delete_inode, |
| 185 | .statfs = ecryptfs_statfs, | 191 | .statfs = ecryptfs_statfs, |
| 186 | .remount_fs = NULL, | 192 | .remount_fs = NULL, |
| 187 | .clear_inode = ecryptfs_clear_inode, | 193 | .evict_inode = ecryptfs_evict_inode, |
| 188 | .show_options = ecryptfs_show_options | 194 | .show_options = ecryptfs_show_options |
| 189 | }; | 195 | }; |
| @@ -128,7 +128,7 @@ SYSCALL_DEFINE1(uselib, const char __user *, library) | |||
| 128 | if (file->f_path.mnt->mnt_flags & MNT_NOEXEC) | 128 | if (file->f_path.mnt->mnt_flags & MNT_NOEXEC) |
| 129 | goto exit; | 129 | goto exit; |
| 130 | 130 | ||
| 131 | fsnotify_open(file->f_path.dentry); | 131 | fsnotify_open(file); |
| 132 | 132 | ||
| 133 | error = -ENOEXEC; | 133 | error = -ENOEXEC; |
| 134 | if(file->f_op) { | 134 | if(file->f_op) { |
| @@ -683,7 +683,7 @@ struct file *open_exec(const char *name) | |||
| 683 | if (file->f_path.mnt->mnt_flags & MNT_NOEXEC) | 683 | if (file->f_path.mnt->mnt_flags & MNT_NOEXEC) |
| 684 | goto exit; | 684 | goto exit; |
| 685 | 685 | ||
| 686 | fsnotify_open(file->f_path.dentry); | 686 | fsnotify_open(file); |
| 687 | 687 | ||
| 688 | err = deny_write_access(file); | 688 | err = deny_write_access(file); |
| 689 | if (err) | 689 | if (err) |
diff --git a/fs/exofs/exofs.h b/fs/exofs/exofs.h index 22721b2fd890..2dc925fa1010 100644 --- a/fs/exofs/exofs.h +++ b/fs/exofs/exofs.h | |||
| @@ -256,7 +256,6 @@ static inline int exofs_oi_read(struct exofs_i_info *oi, | |||
| 256 | } | 256 | } |
| 257 | 257 | ||
| 258 | /* inode.c */ | 258 | /* inode.c */ |
| 259 | void exofs_truncate(struct inode *inode); | ||
| 260 | int exofs_setattr(struct dentry *, struct iattr *); | 259 | int exofs_setattr(struct dentry *, struct iattr *); |
| 261 | int exofs_write_begin(struct file *file, struct address_space *mapping, | 260 | int exofs_write_begin(struct file *file, struct address_space *mapping, |
| 262 | loff_t pos, unsigned len, unsigned flags, | 261 | loff_t pos, unsigned len, unsigned flags, |
| @@ -264,7 +263,7 @@ int exofs_write_begin(struct file *file, struct address_space *mapping, | |||
| 264 | extern struct inode *exofs_iget(struct super_block *, unsigned long); | 263 | extern struct inode *exofs_iget(struct super_block *, unsigned long); |
| 265 | struct inode *exofs_new_inode(struct inode *, int); | 264 | struct inode *exofs_new_inode(struct inode *, int); |
| 266 | extern int exofs_write_inode(struct inode *, struct writeback_control *wbc); | 265 | extern int exofs_write_inode(struct inode *, struct writeback_control *wbc); |
| 267 | extern void exofs_delete_inode(struct inode *); | 266 | extern void exofs_evict_inode(struct inode *); |
| 268 | 267 | ||
| 269 | /* dir.c: */ | 268 | /* dir.c: */ |
| 270 | int exofs_add_link(struct dentry *, struct inode *); | 269 | int exofs_add_link(struct dentry *, struct inode *); |
diff --git a/fs/exofs/file.c b/fs/exofs/file.c index fef6899be397..68cb23e3bb98 100644 --- a/fs/exofs/file.c +++ b/fs/exofs/file.c | |||
| @@ -30,9 +30,6 @@ | |||
| 30 | * along with exofs; if not, write to the Free Software | 30 | * along with exofs; if not, write to the Free Software |
| 31 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 31 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| 32 | */ | 32 | */ |
| 33 | |||
| 34 | #include <linux/buffer_head.h> | ||
| 35 | |||
| 36 | #include "exofs.h" | 33 | #include "exofs.h" |
| 37 | 34 | ||
| 38 | static int exofs_release_file(struct inode *inode, struct file *filp) | 35 | static int exofs_release_file(struct inode *inode, struct file *filp) |
| @@ -40,19 +37,27 @@ static int exofs_release_file(struct inode *inode, struct file *filp) | |||
| 40 | return 0; | 37 | return 0; |
| 41 | } | 38 | } |
| 42 | 39 | ||
| 40 | /* exofs_file_fsync - flush the inode to disk | ||
| 41 | * | ||
| 42 | * Note, in exofs all metadata is written as part of inode, regardless. | ||
| 43 | * The writeout is synchronous | ||
| 44 | */ | ||
| 43 | static int exofs_file_fsync(struct file *filp, int datasync) | 45 | static int exofs_file_fsync(struct file *filp, int datasync) |
| 44 | { | 46 | { |
| 45 | int ret; | 47 | int ret; |
| 46 | struct address_space *mapping = filp->f_mapping; | 48 | struct inode *inode = filp->f_mapping->host; |
| 47 | struct inode *inode = mapping->host; | 49 | struct writeback_control wbc = { |
| 50 | .sync_mode = WB_SYNC_ALL, | ||
| 51 | .nr_to_write = 0, /* metadata-only; caller takes care of data */ | ||
| 52 | }; | ||
| 48 | struct super_block *sb; | 53 | struct super_block *sb; |
| 49 | 54 | ||
| 50 | ret = filemap_write_and_wait(mapping); | 55 | if (!(inode->i_state & I_DIRTY)) |
| 51 | if (ret) | 56 | return 0; |
| 52 | return ret; | 57 | if (datasync && !(inode->i_state & I_DIRTY_DATASYNC)) |
| 58 | return 0; | ||
| 53 | 59 | ||
| 54 | /* sync the inode attributes */ | 60 | ret = sync_inode(inode, &wbc); |
| 55 | ret = write_inode_now(inode, 1); | ||
| 56 | 61 | ||
| 57 | /* This is a good place to write the sb */ | 62 | /* This is a good place to write the sb */ |
| 58 | /* TODO: Sechedule an sb-sync on create */ | 63 | /* TODO: Sechedule an sb-sync on create */ |
| @@ -65,9 +70,9 @@ static int exofs_file_fsync(struct file *filp, int datasync) | |||
| 65 | 70 | ||
| 66 | static int exofs_flush(struct file *file, fl_owner_t id) | 71 | static int exofs_flush(struct file *file, fl_owner_t id) |
| 67 | { | 72 | { |
| 68 | exofs_file_fsync(file, 1); | 73 | int ret = vfs_fsync(file, 0); |
| 69 | /* TODO: Flush the OSD target */ | 74 | /* TODO: Flush the OSD target */ |
| 70 | return 0; | 75 | return ret; |
| 71 | } | 76 | } |
| 72 | 77 | ||
| 73 | const struct file_operations exofs_file_operations = { | 78 | const struct file_operations exofs_file_operations = { |
| @@ -86,6 +91,5 @@ const struct file_operations exofs_file_operations = { | |||
| 86 | }; | 91 | }; |
| 87 | 92 | ||
| 88 | const struct inode_operations exofs_file_inode_operations = { | 93 | const struct inode_operations exofs_file_inode_operations = { |
| 89 | .truncate = exofs_truncate, | ||
| 90 | .setattr = exofs_setattr, | 94 | .setattr = exofs_setattr, |
| 91 | }; | 95 | }; |
diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c index 4bb6ef822e46..eb7368ebd8cd 100644 --- a/fs/exofs/inode.c +++ b/fs/exofs/inode.c | |||
| @@ -32,9 +32,6 @@ | |||
| 32 | */ | 32 | */ |
| 33 | 33 | ||
| 34 | #include <linux/slab.h> | 34 | #include <linux/slab.h> |
| 35 | #include <linux/writeback.h> | ||
| 36 | #include <linux/buffer_head.h> | ||
| 37 | #include <scsi/scsi_device.h> | ||
| 38 | 35 | ||
| 39 | #include "exofs.h" | 36 | #include "exofs.h" |
| 40 | 37 | ||
| @@ -697,6 +694,13 @@ static int exofs_writepage(struct page *page, struct writeback_control *wbc) | |||
| 697 | return write_exec(&pcol); | 694 | return write_exec(&pcol); |
| 698 | } | 695 | } |
| 699 | 696 | ||
| 697 | /* i_mutex held using inode->i_size directly */ | ||
| 698 | static void _write_failed(struct inode *inode, loff_t to) | ||
| 699 | { | ||
| 700 | if (to > inode->i_size) | ||
| 701 | truncate_pagecache(inode, to, inode->i_size); | ||
| 702 | } | ||
| 703 | |||
| 700 | int exofs_write_begin(struct file *file, struct address_space *mapping, | 704 | int exofs_write_begin(struct file *file, struct address_space *mapping, |
| 701 | loff_t pos, unsigned len, unsigned flags, | 705 | loff_t pos, unsigned len, unsigned flags, |
| 702 | struct page **pagep, void **fsdata) | 706 | struct page **pagep, void **fsdata) |
| @@ -710,7 +714,7 @@ int exofs_write_begin(struct file *file, struct address_space *mapping, | |||
| 710 | fsdata); | 714 | fsdata); |
| 711 | if (ret) { | 715 | if (ret) { |
| 712 | EXOFS_DBGMSG("simple_write_begin faild\n"); | 716 | EXOFS_DBGMSG("simple_write_begin faild\n"); |
| 713 | return ret; | 717 | goto out; |
| 714 | } | 718 | } |
| 715 | 719 | ||
| 716 | page = *pagep; | 720 | page = *pagep; |
| @@ -725,6 +729,9 @@ int exofs_write_begin(struct file *file, struct address_space *mapping, | |||
| 725 | EXOFS_DBGMSG("__readpage_filler faild\n"); | 729 | EXOFS_DBGMSG("__readpage_filler faild\n"); |
| 726 | } | 730 | } |
| 727 | } | 731 | } |
| 732 | out: | ||
| 733 | if (unlikely(ret)) | ||
| 734 | _write_failed(mapping->host, pos + len); | ||
| 728 | 735 | ||
| 729 | return ret; | 736 | return ret; |
| 730 | } | 737 | } |
| @@ -750,6 +757,10 @@ static int exofs_write_end(struct file *file, struct address_space *mapping, | |||
| 750 | int ret; | 757 | int ret; |
| 751 | 758 | ||
| 752 | ret = simple_write_end(file, mapping,pos, len, copied, page, fsdata); | 759 | ret = simple_write_end(file, mapping,pos, len, copied, page, fsdata); |
| 760 | if (unlikely(ret)) | ||
| 761 | _write_failed(inode, pos + len); | ||
| 762 | |||
| 763 | /* TODO: once simple_write_end marks inode dirty remove */ | ||
| 753 | if (i_size != inode->i_size) | 764 | if (i_size != inode->i_size) |
| 754 | mark_inode_dirty(inode); | 765 | mark_inode_dirty(inode); |
| 755 | return ret; | 766 | return ret; |
| @@ -759,15 +770,13 @@ static int exofs_releasepage(struct page *page, gfp_t gfp) | |||
| 759 | { | 770 | { |
| 760 | EXOFS_DBGMSG("page 0x%lx\n", page->index); | 771 | EXOFS_DBGMSG("page 0x%lx\n", page->index); |
| 761 | WARN_ON(1); | 772 | WARN_ON(1); |
| 762 | return try_to_free_buffers(page); | 773 | return 0; |
| 763 | } | 774 | } |
| 764 | 775 | ||
| 765 | static void exofs_invalidatepage(struct page *page, unsigned long offset) | 776 | static void exofs_invalidatepage(struct page *page, unsigned long offset) |
| 766 | { | 777 | { |
| 767 | EXOFS_DBGMSG("page_has_buffers=>%d\n", page_has_buffers(page)); | 778 | EXOFS_DBGMSG("page 0x%lx offset 0x%lx\n", page->index, offset); |
| 768 | WARN_ON(1); | 779 | WARN_ON(1); |
| 769 | |||
| 770 | block_invalidatepage(page, offset); | ||
| 771 | } | 780 | } |
| 772 | 781 | ||
| 773 | const struct address_space_operations exofs_aops = { | 782 | const struct address_space_operations exofs_aops = { |
| @@ -808,87 +817,55 @@ static inline int exofs_inode_is_fast_symlink(struct inode *inode) | |||
| 808 | return S_ISLNK(inode->i_mode) && (oi->i_data[0] != 0); | 817 | return S_ISLNK(inode->i_mode) && (oi->i_data[0] != 0); |
| 809 | } | 818 | } |
| 810 | 819 | ||
| 811 | /* | ||
| 812 | * get_block_t - Fill in a buffer_head | ||
| 813 | * An OSD takes care of block allocation so we just fake an allocation by | ||
| 814 | * putting in the inode's sector_t in the buffer_head. | ||
| 815 | * TODO: What about the case of create==0 and @iblock does not exist in the | ||
| 816 | * object? | ||
| 817 | */ | ||
| 818 | static int exofs_get_block(struct inode *inode, sector_t iblock, | ||
| 819 | struct buffer_head *bh_result, int create) | ||
| 820 | { | ||
| 821 | map_bh(bh_result, inode->i_sb, iblock); | ||
| 822 | return 0; | ||
| 823 | } | ||
| 824 | |||
| 825 | const struct osd_attr g_attr_logical_length = ATTR_DEF( | 820 | const struct osd_attr g_attr_logical_length = ATTR_DEF( |
| 826 | OSD_APAGE_OBJECT_INFORMATION, OSD_ATTR_OI_LOGICAL_LENGTH, 8); | 821 | OSD_APAGE_OBJECT_INFORMATION, OSD_ATTR_OI_LOGICAL_LENGTH, 8); |
| 827 | 822 | ||
| 828 | static int _do_truncate(struct inode *inode) | 823 | static int _do_truncate(struct inode *inode, loff_t newsize) |
| 829 | { | 824 | { |
| 830 | struct exofs_i_info *oi = exofs_i(inode); | 825 | struct exofs_i_info *oi = exofs_i(inode); |
| 831 | loff_t isize = i_size_read(inode); | ||
| 832 | int ret; | 826 | int ret; |
| 833 | 827 | ||
| 834 | inode->i_mtime = inode->i_ctime = CURRENT_TIME; | 828 | inode->i_mtime = inode->i_ctime = CURRENT_TIME; |
| 835 | 829 | ||
| 836 | nobh_truncate_page(inode->i_mapping, isize, exofs_get_block); | 830 | ret = exofs_oi_truncate(oi, (u64)newsize); |
| 831 | if (likely(!ret)) | ||
| 832 | truncate_setsize(inode, newsize); | ||
| 837 | 833 | ||
| 838 | ret = exofs_oi_truncate(oi, (u64)isize); | 834 | EXOFS_DBGMSG("(0x%lx) size=0x%llx ret=>%d\n", |
| 839 | EXOFS_DBGMSG("(0x%lx) size=0x%llx\n", inode->i_ino, isize); | 835 | inode->i_ino, newsize, ret); |
| 840 | return ret; | 836 | return ret; |
| 841 | } | 837 | } |
| 842 | 838 | ||
| 843 | /* | 839 | /* |
| 844 | * Truncate a file to the specified size - all we have to do is set the size | 840 | * Set inode attributes - update size attribute on OSD if needed, |
| 845 | * attribute. We make sure the object exists first. | 841 | * otherwise just call generic functions. |
| 846 | */ | ||
| 847 | void exofs_truncate(struct inode *inode) | ||
| 848 | { | ||
| 849 | struct exofs_i_info *oi = exofs_i(inode); | ||
| 850 | int ret; | ||
| 851 | |||
| 852 | if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) | ||
| 853 | || S_ISLNK(inode->i_mode))) | ||
| 854 | return; | ||
| 855 | if (exofs_inode_is_fast_symlink(inode)) | ||
| 856 | return; | ||
| 857 | if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) | ||
| 858 | return; | ||
| 859 | |||
| 860 | /* if we are about to truncate an object, and it hasn't been | ||
| 861 | * created yet, wait | ||
| 862 | */ | ||
| 863 | if (unlikely(wait_obj_created(oi))) | ||
| 864 | goto fail; | ||
| 865 | |||
| 866 | ret = _do_truncate(inode); | ||
| 867 | if (ret) | ||
| 868 | goto fail; | ||
| 869 | |||
| 870 | out: | ||
| 871 | mark_inode_dirty(inode); | ||
| 872 | return; | ||
| 873 | fail: | ||
| 874 | make_bad_inode(inode); | ||
| 875 | goto out; | ||
| 876 | } | ||
| 877 | |||
| 878 | /* | ||
| 879 | * Set inode attributes - just call generic functions. | ||
| 880 | */ | 842 | */ |
| 881 | int exofs_setattr(struct dentry *dentry, struct iattr *iattr) | 843 | int exofs_setattr(struct dentry *dentry, struct iattr *iattr) |
| 882 | { | 844 | { |
| 883 | struct inode *inode = dentry->d_inode; | 845 | struct inode *inode = dentry->d_inode; |
| 884 | int error; | 846 | int error; |
| 885 | 847 | ||
| 848 | /* if we are about to modify an object, and it hasn't been | ||
| 849 | * created yet, wait | ||
| 850 | */ | ||
| 851 | error = wait_obj_created(exofs_i(inode)); | ||
| 852 | if (unlikely(error)) | ||
| 853 | return error; | ||
| 854 | |||
| 886 | error = inode_change_ok(inode, iattr); | 855 | error = inode_change_ok(inode, iattr); |
| 887 | if (error) | 856 | if (unlikely(error)) |
| 888 | return error; | 857 | return error; |
| 889 | 858 | ||
| 890 | error = inode_setattr(inode, iattr); | 859 | if ((iattr->ia_valid & ATTR_SIZE) && |
| 891 | return error; | 860 | iattr->ia_size != i_size_read(inode)) { |
| 861 | error = _do_truncate(inode, iattr->ia_size); | ||
| 862 | if (unlikely(error)) | ||
| 863 | return error; | ||
| 864 | } | ||
| 865 | |||
| 866 | setattr_copy(inode, iattr); | ||
| 867 | mark_inode_dirty(inode); | ||
| 868 | return 0; | ||
| 892 | } | 869 | } |
| 893 | 870 | ||
| 894 | static const struct osd_attr g_attr_inode_file_layout = ATTR_DEF( | 871 | static const struct osd_attr g_attr_inode_file_layout = ATTR_DEF( |
| @@ -1325,7 +1302,7 @@ static void delete_done(struct exofs_io_state *ios, void *p) | |||
| 1325 | * from the OSD here. We make sure the object was created before we try and | 1302 | * from the OSD here. We make sure the object was created before we try and |
| 1326 | * delete it. | 1303 | * delete it. |
| 1327 | */ | 1304 | */ |
| 1328 | void exofs_delete_inode(struct inode *inode) | 1305 | void exofs_evict_inode(struct inode *inode) |
| 1329 | { | 1306 | { |
| 1330 | struct exofs_i_info *oi = exofs_i(inode); | 1307 | struct exofs_i_info *oi = exofs_i(inode); |
| 1331 | struct super_block *sb = inode->i_sb; | 1308 | struct super_block *sb = inode->i_sb; |
| @@ -1335,30 +1312,27 @@ void exofs_delete_inode(struct inode *inode) | |||
| 1335 | 1312 | ||
| 1336 | truncate_inode_pages(&inode->i_data, 0); | 1313 | truncate_inode_pages(&inode->i_data, 0); |
| 1337 | 1314 | ||
| 1338 | if (is_bad_inode(inode)) | 1315 | /* TODO: should do better here */ |
| 1316 | if (inode->i_nlink || is_bad_inode(inode)) | ||
| 1339 | goto no_delete; | 1317 | goto no_delete; |
| 1340 | 1318 | ||
| 1341 | mark_inode_dirty(inode); | ||
| 1342 | exofs_update_inode(inode, inode_needs_sync(inode)); | ||
| 1343 | |||
| 1344 | inode->i_size = 0; | 1319 | inode->i_size = 0; |
| 1345 | if (inode->i_blocks) | 1320 | end_writeback(inode); |
| 1346 | exofs_truncate(inode); | ||
| 1347 | 1321 | ||
| 1348 | clear_inode(inode); | 1322 | /* if we are deleting an obj that hasn't been created yet, wait */ |
| 1323 | if (!obj_created(oi)) { | ||
| 1324 | BUG_ON(!obj_2bcreated(oi)); | ||
| 1325 | wait_event(oi->i_wq, obj_created(oi)); | ||
| 1326 | /* ignore the error attempt a remove anyway */ | ||
| 1327 | } | ||
| 1349 | 1328 | ||
| 1329 | /* Now Remove the OSD objects */ | ||
| 1350 | ret = exofs_get_io_state(&sbi->layout, &ios); | 1330 | ret = exofs_get_io_state(&sbi->layout, &ios); |
| 1351 | if (unlikely(ret)) { | 1331 | if (unlikely(ret)) { |
| 1352 | EXOFS_ERR("%s: exofs_get_io_state failed\n", __func__); | 1332 | EXOFS_ERR("%s: exofs_get_io_state failed\n", __func__); |
| 1353 | return; | 1333 | return; |
| 1354 | } | 1334 | } |
| 1355 | 1335 | ||
| 1356 | /* if we are deleting an obj that hasn't been created yet, wait */ | ||
| 1357 | if (!obj_created(oi)) { | ||
| 1358 | BUG_ON(!obj_2bcreated(oi)); | ||
| 1359 | wait_event(oi->i_wq, obj_created(oi)); | ||
| 1360 | } | ||
| 1361 | |||
| 1362 | ios->obj.id = exofs_oi_objno(oi); | 1336 | ios->obj.id = exofs_oi_objno(oi); |
| 1363 | ios->done = delete_done; | 1337 | ios->done = delete_done; |
| 1364 | ios->private = sbi; | 1338 | ios->private = sbi; |
| @@ -1374,5 +1348,5 @@ void exofs_delete_inode(struct inode *inode) | |||
| 1374 | return; | 1348 | return; |
| 1375 | 1349 | ||
| 1376 | no_delete: | 1350 | no_delete: |
| 1377 | clear_inode(inode); | 1351 | end_writeback(inode); |
| 1378 | } | 1352 | } |
diff --git a/fs/exofs/ios.c b/fs/exofs/ios.c index 4337cad7777b..6550bf70e41d 100644 --- a/fs/exofs/ios.c +++ b/fs/exofs/ios.c | |||
| @@ -305,8 +305,6 @@ int exofs_check_io(struct exofs_io_state *ios, u64 *resid) | |||
| 305 | struct _striping_info { | 305 | struct _striping_info { |
| 306 | u64 obj_offset; | 306 | u64 obj_offset; |
| 307 | u64 group_length; | 307 | u64 group_length; |
| 308 | u64 total_group_length; | ||
| 309 | u64 Major; | ||
| 310 | unsigned dev; | 308 | unsigned dev; |
| 311 | unsigned unit_off; | 309 | unsigned unit_off; |
| 312 | }; | 310 | }; |
| @@ -343,8 +341,6 @@ static void _calc_stripe_info(struct exofs_io_state *ios, u64 file_offset, | |||
| 343 | (M * group_depth * stripe_unit); | 341 | (M * group_depth * stripe_unit); |
| 344 | 342 | ||
| 345 | si->group_length = T - H; | 343 | si->group_length = T - H; |
| 346 | si->total_group_length = T; | ||
| 347 | si->Major = M; | ||
| 348 | } | 344 | } |
| 349 | 345 | ||
| 350 | static int _add_stripe_unit(struct exofs_io_state *ios, unsigned *cur_pg, | 346 | static int _add_stripe_unit(struct exofs_io_state *ios, unsigned *cur_pg, |
| @@ -392,20 +388,19 @@ static int _add_stripe_unit(struct exofs_io_state *ios, unsigned *cur_pg, | |||
| 392 | } | 388 | } |
| 393 | 389 | ||
| 394 | static int _prepare_one_group(struct exofs_io_state *ios, u64 length, | 390 | static int _prepare_one_group(struct exofs_io_state *ios, u64 length, |
| 395 | struct _striping_info *si, unsigned first_comp) | 391 | struct _striping_info *si) |
| 396 | { | 392 | { |
| 397 | unsigned stripe_unit = ios->layout->stripe_unit; | 393 | unsigned stripe_unit = ios->layout->stripe_unit; |
| 398 | unsigned mirrors_p1 = ios->layout->mirrors_p1; | 394 | unsigned mirrors_p1 = ios->layout->mirrors_p1; |
| 399 | unsigned devs_in_group = ios->layout->group_width * mirrors_p1; | 395 | unsigned devs_in_group = ios->layout->group_width * mirrors_p1; |
| 400 | unsigned dev = si->dev; | 396 | unsigned dev = si->dev; |
| 401 | unsigned first_dev = dev - (dev % devs_in_group); | 397 | unsigned first_dev = dev - (dev % devs_in_group); |
| 402 | unsigned comp = first_comp + (dev - first_dev); | ||
| 403 | unsigned max_comp = ios->numdevs ? ios->numdevs - mirrors_p1 : 0; | 398 | unsigned max_comp = ios->numdevs ? ios->numdevs - mirrors_p1 : 0; |
| 404 | unsigned cur_pg = ios->pages_consumed; | 399 | unsigned cur_pg = ios->pages_consumed; |
| 405 | int ret = 0; | 400 | int ret = 0; |
| 406 | 401 | ||
| 407 | while (length) { | 402 | while (length) { |
| 408 | struct exofs_per_dev_state *per_dev = &ios->per_dev[comp]; | 403 | struct exofs_per_dev_state *per_dev = &ios->per_dev[dev]; |
| 409 | unsigned cur_len, page_off = 0; | 404 | unsigned cur_len, page_off = 0; |
| 410 | 405 | ||
| 411 | if (!per_dev->length) { | 406 | if (!per_dev->length) { |
| @@ -424,11 +419,8 @@ static int _prepare_one_group(struct exofs_io_state *ios, u64 length, | |||
| 424 | cur_len = stripe_unit; | 419 | cur_len = stripe_unit; |
| 425 | } | 420 | } |
| 426 | 421 | ||
| 427 | if (max_comp < comp) | 422 | if (max_comp < dev) |
| 428 | max_comp = comp; | 423 | max_comp = dev; |
| 429 | |||
| 430 | dev += mirrors_p1; | ||
| 431 | dev = (dev % devs_in_group) + first_dev; | ||
| 432 | } else { | 424 | } else { |
| 433 | cur_len = stripe_unit; | 425 | cur_len = stripe_unit; |
| 434 | } | 426 | } |
| @@ -440,8 +432,8 @@ static int _prepare_one_group(struct exofs_io_state *ios, u64 length, | |||
| 440 | if (unlikely(ret)) | 432 | if (unlikely(ret)) |
| 441 | goto out; | 433 | goto out; |
| 442 | 434 | ||
| 443 | comp += mirrors_p1; | 435 | dev += mirrors_p1; |
| 444 | comp = (comp % devs_in_group) + first_comp; | 436 | dev = (dev % devs_in_group) + first_dev; |
| 445 | 437 | ||
| 446 | length -= cur_len; | 438 | length -= cur_len; |
| 447 | } | 439 | } |
| @@ -454,18 +446,15 @@ out: | |||
| 454 | static int _prepare_for_striping(struct exofs_io_state *ios) | 446 | static int _prepare_for_striping(struct exofs_io_state *ios) |
| 455 | { | 447 | { |
| 456 | u64 length = ios->length; | 448 | u64 length = ios->length; |
| 449 | u64 offset = ios->offset; | ||
| 457 | struct _striping_info si; | 450 | struct _striping_info si; |
| 458 | unsigned devs_in_group = ios->layout->group_width * | ||
| 459 | ios->layout->mirrors_p1; | ||
| 460 | unsigned first_comp = 0; | ||
| 461 | int ret = 0; | 451 | int ret = 0; |
| 462 | 452 | ||
| 463 | _calc_stripe_info(ios, ios->offset, &si); | ||
| 464 | |||
| 465 | if (!ios->pages) { | 453 | if (!ios->pages) { |
| 466 | if (ios->kern_buff) { | 454 | if (ios->kern_buff) { |
| 467 | struct exofs_per_dev_state *per_dev = &ios->per_dev[0]; | 455 | struct exofs_per_dev_state *per_dev = &ios->per_dev[0]; |
| 468 | 456 | ||
| 457 | _calc_stripe_info(ios, ios->offset, &si); | ||
| 469 | per_dev->offset = si.obj_offset; | 458 | per_dev->offset = si.obj_offset; |
| 470 | per_dev->dev = si.dev; | 459 | per_dev->dev = si.dev; |
| 471 | 460 | ||
| @@ -479,26 +468,17 @@ static int _prepare_for_striping(struct exofs_io_state *ios) | |||
| 479 | } | 468 | } |
| 480 | 469 | ||
| 481 | while (length) { | 470 | while (length) { |
| 471 | _calc_stripe_info(ios, offset, &si); | ||
| 472 | |||
| 482 | if (length < si.group_length) | 473 | if (length < si.group_length) |
| 483 | si.group_length = length; | 474 | si.group_length = length; |
| 484 | 475 | ||
| 485 | ret = _prepare_one_group(ios, si.group_length, &si, first_comp); | 476 | ret = _prepare_one_group(ios, si.group_length, &si); |
| 486 | if (unlikely(ret)) | 477 | if (unlikely(ret)) |
| 487 | goto out; | 478 | goto out; |
| 488 | 479 | ||
| 480 | offset += si.group_length; | ||
| 489 | length -= si.group_length; | 481 | length -= si.group_length; |
| 490 | |||
| 491 | si.group_length = si.total_group_length; | ||
| 492 | si.unit_off = 0; | ||
| 493 | ++si.Major; | ||
| 494 | si.obj_offset = si.Major * ios->layout->stripe_unit * | ||
| 495 | ios->layout->group_depth; | ||
| 496 | |||
| 497 | si.dev = (si.dev - (si.dev % devs_in_group)) + devs_in_group; | ||
| 498 | si.dev %= ios->layout->s_numdevs; | ||
| 499 | |||
| 500 | first_comp += devs_in_group; | ||
| 501 | first_comp %= ios->layout->s_numdevs; | ||
| 502 | } | 482 | } |
| 503 | 483 | ||
| 504 | out: | 484 | out: |
| @@ -599,7 +579,7 @@ static int _sbi_write_mirror(struct exofs_io_state *ios, int cur_comp) | |||
| 599 | } else { | 579 | } else { |
| 600 | bio = master_dev->bio; | 580 | bio = master_dev->bio; |
| 601 | /* FIXME: bio_set_dir() */ | 581 | /* FIXME: bio_set_dir() */ |
| 602 | bio->bi_rw |= (1 << BIO_RW); | 582 | bio->bi_rw |= REQ_WRITE; |
| 603 | } | 583 | } |
| 604 | 584 | ||
| 605 | osd_req_write(or, &ios->obj, per_dev->offset, bio, | 585 | osd_req_write(or, &ios->obj, per_dev->offset, bio, |
diff --git a/fs/exofs/super.c b/fs/exofs/super.c index 03149b9a5178..047e92fa3af8 100644 --- a/fs/exofs/super.c +++ b/fs/exofs/super.c | |||
| @@ -31,7 +31,6 @@ | |||
| 31 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 31 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| 32 | */ | 32 | */ |
| 33 | 33 | ||
| 34 | #include <linux/smp_lock.h> | ||
| 35 | #include <linux/string.h> | 34 | #include <linux/string.h> |
| 36 | #include <linux/parser.h> | 35 | #include <linux/parser.h> |
| 37 | #include <linux/vfs.h> | 36 | #include <linux/vfs.h> |
| @@ -743,7 +742,7 @@ static const struct super_operations exofs_sops = { | |||
| 743 | .alloc_inode = exofs_alloc_inode, | 742 | .alloc_inode = exofs_alloc_inode, |
| 744 | .destroy_inode = exofs_destroy_inode, | 743 | .destroy_inode = exofs_destroy_inode, |
| 745 | .write_inode = exofs_write_inode, | 744 | .write_inode = exofs_write_inode, |
| 746 | .delete_inode = exofs_delete_inode, | 745 | .evict_inode = exofs_evict_inode, |
| 747 | .put_super = exofs_put_super, | 746 | .put_super = exofs_put_super, |
| 748 | .write_super = exofs_write_super, | 747 | .write_super = exofs_write_super, |
| 749 | .sync_fs = exofs_sync_fs, | 748 | .sync_fs = exofs_sync_fs, |
diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c index e8766a396776..c6c684b44ea1 100644 --- a/fs/ext2/balloc.c +++ b/fs/ext2/balloc.c | |||
| @@ -571,7 +571,7 @@ do_more: | |||
| 571 | error_return: | 571 | error_return: |
| 572 | brelse(bitmap_bh); | 572 | brelse(bitmap_bh); |
| 573 | release_blocks(sb, freed); | 573 | release_blocks(sb, freed); |
| 574 | dquot_free_block(inode, freed); | 574 | dquot_free_block_nodirty(inode, freed); |
| 575 | } | 575 | } |
| 576 | 576 | ||
| 577 | /** | 577 | /** |
| @@ -1418,7 +1418,8 @@ allocated: | |||
| 1418 | 1418 | ||
| 1419 | *errp = 0; | 1419 | *errp = 0; |
| 1420 | brelse(bitmap_bh); | 1420 | brelse(bitmap_bh); |
| 1421 | dquot_free_block(inode, *count-num); | 1421 | dquot_free_block_nodirty(inode, *count-num); |
| 1422 | mark_inode_dirty(inode); | ||
| 1422 | *count = num; | 1423 | *count = num; |
| 1423 | return ret_block; | 1424 | return ret_block; |
| 1424 | 1425 | ||
| @@ -1428,8 +1429,10 @@ out: | |||
| 1428 | /* | 1429 | /* |
| 1429 | * Undo the block allocation | 1430 | * Undo the block allocation |
| 1430 | */ | 1431 | */ |
| 1431 | if (!performed_allocation) | 1432 | if (!performed_allocation) { |
| 1432 | dquot_free_block(inode, *count); | 1433 | dquot_free_block_nodirty(inode, *count); |
| 1434 | mark_inode_dirty(inode); | ||
| 1435 | } | ||
| 1433 | brelse(bitmap_bh); | 1436 | brelse(bitmap_bh); |
| 1434 | return 0; | 1437 | return 0; |
| 1435 | } | 1438 | } |
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index 7516957273ed..764109886ec0 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c | |||
| @@ -448,6 +448,11 @@ ino_t ext2_inode_by_name(struct inode *dir, struct qstr *child) | |||
| 448 | return res; | 448 | return res; |
| 449 | } | 449 | } |
| 450 | 450 | ||
| 451 | static int ext2_prepare_chunk(struct page *page, loff_t pos, unsigned len) | ||
| 452 | { | ||
| 453 | return __block_write_begin(page, pos, len, ext2_get_block); | ||
| 454 | } | ||
| 455 | |||
| 451 | /* Releases the page */ | 456 | /* Releases the page */ |
| 452 | void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de, | 457 | void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de, |
| 453 | struct page *page, struct inode *inode, int update_times) | 458 | struct page *page, struct inode *inode, int update_times) |
| @@ -458,8 +463,7 @@ void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de, | |||
| 458 | int err; | 463 | int err; |
| 459 | 464 | ||
| 460 | lock_page(page); | 465 | lock_page(page); |
| 461 | err = __ext2_write_begin(NULL, page->mapping, pos, len, | 466 | err = ext2_prepare_chunk(page, pos, len); |
| 462 | AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); | ||
| 463 | BUG_ON(err); | 467 | BUG_ON(err); |
| 464 | de->inode = cpu_to_le32(inode->i_ino); | 468 | de->inode = cpu_to_le32(inode->i_ino); |
| 465 | ext2_set_de_type(de, inode); | 469 | ext2_set_de_type(de, inode); |
| @@ -542,8 +546,7 @@ int ext2_add_link (struct dentry *dentry, struct inode *inode) | |||
| 542 | got_it: | 546 | got_it: |
| 543 | pos = page_offset(page) + | 547 | pos = page_offset(page) + |
| 544 | (char*)de - (char*)page_address(page); | 548 | (char*)de - (char*)page_address(page); |
| 545 | err = __ext2_write_begin(NULL, page->mapping, pos, rec_len, 0, | 549 | err = ext2_prepare_chunk(page, pos, rec_len); |
| 546 | &page, NULL); | ||
| 547 | if (err) | 550 | if (err) |
| 548 | goto out_unlock; | 551 | goto out_unlock; |
| 549 | if (de->inode) { | 552 | if (de->inode) { |
| @@ -576,8 +579,7 @@ out_unlock: | |||
| 576 | */ | 579 | */ |
| 577 | int ext2_delete_entry (struct ext2_dir_entry_2 * dir, struct page * page ) | 580 | int ext2_delete_entry (struct ext2_dir_entry_2 * dir, struct page * page ) |
| 578 | { | 581 | { |
| 579 | struct address_space *mapping = page->mapping; | 582 | struct inode *inode = page->mapping->host; |
| 580 | struct inode *inode = mapping->host; | ||
| 581 | char *kaddr = page_address(page); | 583 | char *kaddr = page_address(page); |
| 582 | unsigned from = ((char*)dir - kaddr) & ~(ext2_chunk_size(inode)-1); | 584 | unsigned from = ((char*)dir - kaddr) & ~(ext2_chunk_size(inode)-1); |
| 583 | unsigned to = ((char *)dir - kaddr) + | 585 | unsigned to = ((char *)dir - kaddr) + |
| @@ -601,8 +603,7 @@ int ext2_delete_entry (struct ext2_dir_entry_2 * dir, struct page * page ) | |||
| 601 | from = (char*)pde - (char*)page_address(page); | 603 | from = (char*)pde - (char*)page_address(page); |
| 602 | pos = page_offset(page) + from; | 604 | pos = page_offset(page) + from; |
| 603 | lock_page(page); | 605 | lock_page(page); |
| 604 | err = __ext2_write_begin(NULL, page->mapping, pos, to - from, 0, | 606 | err = ext2_prepare_chunk(page, pos, to - from); |
| 605 | &page, NULL); | ||
| 606 | BUG_ON(err); | 607 | BUG_ON(err); |
| 607 | if (pde) | 608 | if (pde) |
| 608 | pde->rec_len = ext2_rec_len_to_disk(to - from); | 609 | pde->rec_len = ext2_rec_len_to_disk(to - from); |
| @@ -621,8 +622,7 @@ out: | |||
| 621 | */ | 622 | */ |
| 622 | int ext2_make_empty(struct inode *inode, struct inode *parent) | 623 | int ext2_make_empty(struct inode *inode, struct inode *parent) |
| 623 | { | 624 | { |
| 624 | struct address_space *mapping = inode->i_mapping; | 625 | struct page *page = grab_cache_page(inode->i_mapping, 0); |
| 625 | struct page *page = grab_cache_page(mapping, 0); | ||
| 626 | unsigned chunk_size = ext2_chunk_size(inode); | 626 | unsigned chunk_size = ext2_chunk_size(inode); |
| 627 | struct ext2_dir_entry_2 * de; | 627 | struct ext2_dir_entry_2 * de; |
| 628 | int err; | 628 | int err; |
| @@ -631,8 +631,7 @@ int ext2_make_empty(struct inode *inode, struct inode *parent) | |||
| 631 | if (!page) | 631 | if (!page) |
| 632 | return -ENOMEM; | 632 | return -ENOMEM; |
| 633 | 633 | ||
| 634 | err = __ext2_write_begin(NULL, page->mapping, 0, chunk_size, 0, | 634 | err = ext2_prepare_chunk(page, 0, chunk_size); |
| 635 | &page, NULL); | ||
| 636 | if (err) { | 635 | if (err) { |
| 637 | unlock_page(page); | 636 | unlock_page(page); |
| 638 | goto fail; | 637 | goto fail; |
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index 52b34f1d2738..416daa62242c 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h | |||
| @@ -119,7 +119,7 @@ extern unsigned long ext2_count_free (struct buffer_head *, unsigned); | |||
| 119 | /* inode.c */ | 119 | /* inode.c */ |
| 120 | extern struct inode *ext2_iget (struct super_block *, unsigned long); | 120 | extern struct inode *ext2_iget (struct super_block *, unsigned long); |
| 121 | extern int ext2_write_inode (struct inode *, struct writeback_control *); | 121 | extern int ext2_write_inode (struct inode *, struct writeback_control *); |
| 122 | extern void ext2_delete_inode (struct inode *); | 122 | extern void ext2_evict_inode(struct inode *); |
| 123 | extern int ext2_sync_inode (struct inode *); | 123 | extern int ext2_sync_inode (struct inode *); |
| 124 | extern int ext2_get_block(struct inode *, sector_t, struct buffer_head *, int); | 124 | extern int ext2_get_block(struct inode *, sector_t, struct buffer_head *, int); |
| 125 | extern int ext2_setattr (struct dentry *, struct iattr *); | 125 | extern int ext2_setattr (struct dentry *, struct iattr *); |
| @@ -127,9 +127,6 @@ extern void ext2_set_inode_flags(struct inode *inode); | |||
| 127 | extern void ext2_get_inode_flags(struct ext2_inode_info *); | 127 | extern void ext2_get_inode_flags(struct ext2_inode_info *); |
| 128 | extern int ext2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, | 128 | extern int ext2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo, |
| 129 | u64 start, u64 len); | 129 | u64 start, u64 len); |
| 130 | int __ext2_write_begin(struct file *file, struct address_space *mapping, | ||
| 131 | loff_t pos, unsigned len, unsigned flags, | ||
| 132 | struct page **pagep, void **fsdata); | ||
| 133 | 130 | ||
| 134 | /* ioctl.c */ | 131 | /* ioctl.c */ |
| 135 | extern long ext2_ioctl(struct file *, unsigned int, unsigned long); | 132 | extern long ext2_ioctl(struct file *, unsigned int, unsigned long); |
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c index 938dbc739d00..ad70479aabff 100644 --- a/fs/ext2/ialloc.c +++ b/fs/ext2/ialloc.c | |||
| @@ -118,19 +118,14 @@ void ext2_free_inode (struct inode * inode) | |||
| 118 | * Note: we must free any quota before locking the superblock, | 118 | * Note: we must free any quota before locking the superblock, |
| 119 | * as writing the quota to disk may need the lock as well. | 119 | * as writing the quota to disk may need the lock as well. |
| 120 | */ | 120 | */ |
| 121 | if (!is_bad_inode(inode)) { | 121 | /* Quota is already initialized in iput() */ |
| 122 | /* Quota is already initialized in iput() */ | 122 | ext2_xattr_delete_inode(inode); |
| 123 | ext2_xattr_delete_inode(inode); | 123 | dquot_free_inode(inode); |
| 124 | dquot_free_inode(inode); | 124 | dquot_drop(inode); |
| 125 | dquot_drop(inode); | ||
| 126 | } | ||
| 127 | 125 | ||
| 128 | es = EXT2_SB(sb)->s_es; | 126 | es = EXT2_SB(sb)->s_es; |
| 129 | is_directory = S_ISDIR(inode->i_mode); | 127 | is_directory = S_ISDIR(inode->i_mode); |
| 130 | 128 | ||
| 131 | /* Do this BEFORE marking the inode not in use or returning an error */ | ||
| 132 | clear_inode (inode); | ||
| 133 | |||
| 134 | if (ino < EXT2_FIRST_INO(sb) || | 129 | if (ino < EXT2_FIRST_INO(sb) || |
| 135 | ino > le32_to_cpu(es->s_inodes_count)) { | 130 | ino > le32_to_cpu(es->s_inodes_count)) { |
| 136 | ext2_error (sb, "ext2_free_inode", | 131 | ext2_error (sb, "ext2_free_inode", |
diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index 3675088cb88c..940c96168868 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c | |||
| @@ -69,26 +69,42 @@ static void ext2_write_failed(struct address_space *mapping, loff_t to) | |||
| 69 | /* | 69 | /* |
| 70 | * Called at the last iput() if i_nlink is zero. | 70 | * Called at the last iput() if i_nlink is zero. |
| 71 | */ | 71 | */ |
| 72 | void ext2_delete_inode (struct inode * inode) | 72 | void ext2_evict_inode(struct inode * inode) |
| 73 | { | 73 | { |
| 74 | if (!is_bad_inode(inode)) | 74 | struct ext2_block_alloc_info *rsv; |
| 75 | int want_delete = 0; | ||
| 76 | |||
| 77 | if (!inode->i_nlink && !is_bad_inode(inode)) { | ||
| 78 | want_delete = 1; | ||
| 75 | dquot_initialize(inode); | 79 | dquot_initialize(inode); |
| 80 | } else { | ||
| 81 | dquot_drop(inode); | ||
| 82 | } | ||
| 83 | |||
| 76 | truncate_inode_pages(&inode->i_data, 0); | 84 | truncate_inode_pages(&inode->i_data, 0); |
| 77 | 85 | ||
| 78 | if (is_bad_inode(inode)) | 86 | if (want_delete) { |
| 79 | goto no_delete; | 87 | /* set dtime */ |
| 80 | EXT2_I(inode)->i_dtime = get_seconds(); | 88 | EXT2_I(inode)->i_dtime = get_seconds(); |
| 81 | mark_inode_dirty(inode); | 89 | mark_inode_dirty(inode); |
| 82 | __ext2_write_inode(inode, inode_needs_sync(inode)); | 90 | __ext2_write_inode(inode, inode_needs_sync(inode)); |
| 91 | /* truncate to 0 */ | ||
| 92 | inode->i_size = 0; | ||
| 93 | if (inode->i_blocks) | ||
| 94 | ext2_truncate_blocks(inode, 0); | ||
| 95 | } | ||
| 83 | 96 | ||
| 84 | inode->i_size = 0; | 97 | invalidate_inode_buffers(inode); |
| 85 | if (inode->i_blocks) | 98 | end_writeback(inode); |
| 86 | ext2_truncate_blocks(inode, 0); | ||
| 87 | ext2_free_inode (inode); | ||
| 88 | 99 | ||
| 89 | return; | 100 | ext2_discard_reservation(inode); |
| 90 | no_delete: | 101 | rsv = EXT2_I(inode)->i_block_alloc_info; |
| 91 | clear_inode(inode); /* We must guarantee clearing of inode... */ | 102 | EXT2_I(inode)->i_block_alloc_info = NULL; |
| 103 | if (unlikely(rsv)) | ||
| 104 | kfree(rsv); | ||
| 105 | |||
| 106 | if (want_delete) | ||
| 107 | ext2_free_inode(inode); | ||
| 92 | } | 108 | } |
| 93 | 109 | ||
| 94 | typedef struct { | 110 | typedef struct { |
| @@ -423,6 +439,8 @@ static int ext2_alloc_blocks(struct inode *inode, | |||
| 423 | failed_out: | 439 | failed_out: |
| 424 | for (i = 0; i <index; i++) | 440 | for (i = 0; i <index; i++) |
| 425 | ext2_free_blocks(inode, new_blocks[i], 1); | 441 | ext2_free_blocks(inode, new_blocks[i], 1); |
| 442 | if (index) | ||
| 443 | mark_inode_dirty(inode); | ||
| 426 | return ret; | 444 | return ret; |
| 427 | } | 445 | } |
| 428 | 446 | ||
| @@ -765,14 +783,6 @@ ext2_readpages(struct file *file, struct address_space *mapping, | |||
| 765 | return mpage_readpages(mapping, pages, nr_pages, ext2_get_block); | 783 | return mpage_readpages(mapping, pages, nr_pages, ext2_get_block); |
| 766 | } | 784 | } |
| 767 | 785 | ||
| 768 | int __ext2_write_begin(struct file *file, struct address_space *mapping, | ||
| 769 | loff_t pos, unsigned len, unsigned flags, | ||
| 770 | struct page **pagep, void **fsdata) | ||
| 771 | { | ||
| 772 | return block_write_begin_newtrunc(file, mapping, pos, len, flags, | ||
| 773 | pagep, fsdata, ext2_get_block); | ||
| 774 | } | ||
| 775 | |||
| 776 | static int | 786 | static int |
| 777 | ext2_write_begin(struct file *file, struct address_space *mapping, | 787 | ext2_write_begin(struct file *file, struct address_space *mapping, |
| 778 | loff_t pos, unsigned len, unsigned flags, | 788 | loff_t pos, unsigned len, unsigned flags, |
| @@ -780,8 +790,8 @@ ext2_write_begin(struct file *file, struct address_space *mapping, | |||
| 780 | { | 790 | { |
| 781 | int ret; | 791 | int ret; |
| 782 | 792 | ||
| 783 | *pagep = NULL; | 793 | ret = block_write_begin(mapping, pos, len, flags, pagep, |
| 784 | ret = __ext2_write_begin(file, mapping, pos, len, flags, pagep, fsdata); | 794 | ext2_get_block); |
| 785 | if (ret < 0) | 795 | if (ret < 0) |
| 786 | ext2_write_failed(mapping, pos + len); | 796 | ext2_write_failed(mapping, pos + len); |
| 787 | return ret; | 797 | return ret; |
| @@ -806,13 +816,8 @@ ext2_nobh_write_begin(struct file *file, struct address_space *mapping, | |||
| 806 | { | 816 | { |
| 807 | int ret; | 817 | int ret; |
| 808 | 818 | ||
| 809 | /* | 819 | ret = nobh_write_begin(mapping, pos, len, flags, pagep, fsdata, |
| 810 | * Dir-in-pagecache still uses ext2_write_begin. Would have to rework | 820 | ext2_get_block); |
| 811 | * directory handling code to pass around offsets rather than struct | ||
| 812 | * pages in order to make this work easily. | ||
| 813 | */ | ||
| 814 | ret = nobh_write_begin_newtrunc(file, mapping, pos, len, flags, pagep, | ||
| 815 | fsdata, ext2_get_block); | ||
| 816 | if (ret < 0) | 821 | if (ret < 0) |
| 817 | ext2_write_failed(mapping, pos + len); | 822 | ext2_write_failed(mapping, pos + len); |
| 818 | return ret; | 823 | return ret; |
| @@ -838,7 +843,7 @@ ext2_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, | |||
| 838 | struct inode *inode = mapping->host; | 843 | struct inode *inode = mapping->host; |
| 839 | ssize_t ret; | 844 | ssize_t ret; |
| 840 | 845 | ||
| 841 | ret = blockdev_direct_IO_newtrunc(rw, iocb, inode, inode->i_sb->s_bdev, | 846 | ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, |
| 842 | iov, offset, nr_segs, ext2_get_block, NULL); | 847 | iov, offset, nr_segs, ext2_get_block, NULL); |
| 843 | if (ret < 0 && (rw & WRITE)) | 848 | if (ret < 0 && (rw & WRITE)) |
| 844 | ext2_write_failed(mapping, offset + iov_length(iov, nr_segs)); | 849 | ext2_write_failed(mapping, offset + iov_length(iov, nr_segs)); |
| @@ -1006,8 +1011,8 @@ static inline void ext2_free_data(struct inode *inode, __le32 *p, __le32 *q) | |||
| 1006 | else if (block_to_free == nr - count) | 1011 | else if (block_to_free == nr - count) |
| 1007 | count++; | 1012 | count++; |
| 1008 | else { | 1013 | else { |
| 1009 | mark_inode_dirty(inode); | ||
| 1010 | ext2_free_blocks (inode, block_to_free, count); | 1014 | ext2_free_blocks (inode, block_to_free, count); |
| 1015 | mark_inode_dirty(inode); | ||
| 1011 | free_this: | 1016 | free_this: |
| 1012 | block_to_free = nr; | 1017 | block_to_free = nr; |
| 1013 | count = 1; | 1018 | count = 1; |
| @@ -1015,8 +1020,8 @@ static inline void ext2_free_data(struct inode *inode, __le32 *p, __le32 *q) | |||
| 1015 | } | 1020 | } |
| 1016 | } | 1021 | } |
| 1017 | if (count > 0) { | 1022 | if (count > 0) { |
| 1018 | mark_inode_dirty(inode); | ||
| 1019 | ext2_free_blocks (inode, block_to_free, count); | 1023 | ext2_free_blocks (inode, block_to_free, count); |
| 1024 | mark_inode_dirty(inode); | ||
| 1020 | } | 1025 | } |
| 1021 | } | 1026 | } |
| 1022 | 1027 | ||
| @@ -1169,15 +1174,10 @@ static void ext2_truncate_blocks(struct inode *inode, loff_t offset) | |||
| 1169 | __ext2_truncate_blocks(inode, offset); | 1174 | __ext2_truncate_blocks(inode, offset); |
| 1170 | } | 1175 | } |
| 1171 | 1176 | ||
| 1172 | int ext2_setsize(struct inode *inode, loff_t newsize) | 1177 | static int ext2_setsize(struct inode *inode, loff_t newsize) |
| 1173 | { | 1178 | { |
| 1174 | loff_t oldsize; | ||
| 1175 | int error; | 1179 | int error; |
| 1176 | 1180 | ||
| 1177 | error = inode_newsize_ok(inode, newsize); | ||
| 1178 | if (error) | ||
| 1179 | return error; | ||
| 1180 | |||
| 1181 | if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || | 1181 | if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || |
| 1182 | S_ISLNK(inode->i_mode))) | 1182 | S_ISLNK(inode->i_mode))) |
| 1183 | return -EINVAL; | 1183 | return -EINVAL; |
| @@ -1197,10 +1197,7 @@ int ext2_setsize(struct inode *inode, loff_t newsize) | |||
| 1197 | if (error) | 1197 | if (error) |
| 1198 | return error; | 1198 | return error; |
| 1199 | 1199 | ||
| 1200 | oldsize = inode->i_size; | 1200 | truncate_setsize(inode, newsize); |
| 1201 | i_size_write(inode, newsize); | ||
| 1202 | truncate_pagecache(inode, oldsize, newsize); | ||
| 1203 | |||
| 1204 | __ext2_truncate_blocks(inode, newsize); | 1201 | __ext2_truncate_blocks(inode, newsize); |
| 1205 | 1202 | ||
| 1206 | inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; | 1203 | inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC; |
| @@ -1557,7 +1554,7 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr) | |||
| 1557 | if (error) | 1554 | if (error) |
| 1558 | return error; | 1555 | return error; |
| 1559 | } | 1556 | } |
| 1560 | generic_setattr(inode, iattr); | 1557 | setattr_copy(inode, iattr); |
| 1561 | if (iattr->ia_valid & ATTR_MODE) | 1558 | if (iattr->ia_valid & ATTR_MODE) |
| 1562 | error = ext2_acl_chmod(inode); | 1559 | error = ext2_acl_chmod(inode); |
| 1563 | mark_inode_dirty(inode); | 1560 | mark_inode_dirty(inode); |
diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 7ff43f4a59cd..1ec602673ea8 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c | |||
| @@ -195,17 +195,6 @@ static void destroy_inodecache(void) | |||
| 195 | kmem_cache_destroy(ext2_inode_cachep); | 195 | kmem_cache_destroy(ext2_inode_cachep); |
| 196 | } | 196 | } |
| 197 | 197 | ||
| 198 | static void ext2_clear_inode(struct inode *inode) | ||
| 199 | { | ||
| 200 | struct ext2_block_alloc_info *rsv = EXT2_I(inode)->i_block_alloc_info; | ||
| 201 | |||
| 202 | dquot_drop(inode); | ||
| 203 | ext2_discard_reservation(inode); | ||
| 204 | EXT2_I(inode)->i_block_alloc_info = NULL; | ||
| 205 | if (unlikely(rsv)) | ||
| 206 | kfree(rsv); | ||
| 207 | } | ||
| 208 | |||
| 209 | static int ext2_show_options(struct seq_file *seq, struct vfsmount *vfs) | 198 | static int ext2_show_options(struct seq_file *seq, struct vfsmount *vfs) |
| 210 | { | 199 | { |
| 211 | struct super_block *sb = vfs->mnt_sb; | 200 | struct super_block *sb = vfs->mnt_sb; |
| @@ -299,13 +288,12 @@ static const struct super_operations ext2_sops = { | |||
| 299 | .alloc_inode = ext2_alloc_inode, | 288 | .alloc_inode = ext2_alloc_inode, |
| 300 | .destroy_inode = ext2_destroy_inode, | 289 | .destroy_inode = ext2_destroy_inode, |
| 301 | .write_inode = ext2_write_inode, | 290 | .write_inode = ext2_write_inode, |
| 302 | .delete_inode = ext2_delete_inode, | 291 | .evict_inode = ext2_evict_inode, |
| 303 | .put_super = ext2_put_super, | 292 | .put_super = ext2_put_super, |
| 304 | .write_super = ext2_write_super, | 293 | .write_super = ext2_write_super, |
| 305 | .sync_fs = ext2_sync_fs, | 294 | .sync_fs = ext2_sync_fs, |
| 306 | .statfs = ext2_statfs, | 295 | .statfs = ext2_statfs, |
| 307 | .remount_fs = ext2_remount, | 296 | .remount_fs = ext2_remount, |
| 308 | .clear_inode = ext2_clear_inode, | ||
| 309 | .show_options = ext2_show_options, | 297 | .show_options = ext2_show_options, |
| 310 | #ifdef CONFIG_QUOTA | 298 | #ifdef CONFIG_QUOTA |
| 311 | .quota_read = ext2_quota_read, | 299 | .quota_read = ext2_quota_read, |
diff --git a/fs/ext2/xattr.c b/fs/ext2/xattr.c index 7c3915780b19..8c29ae15129e 100644 --- a/fs/ext2/xattr.c +++ b/fs/ext2/xattr.c | |||
| @@ -674,6 +674,7 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh, | |||
| 674 | new_bh = sb_getblk(sb, block); | 674 | new_bh = sb_getblk(sb, block); |
| 675 | if (!new_bh) { | 675 | if (!new_bh) { |
| 676 | ext2_free_blocks(inode, block, 1); | 676 | ext2_free_blocks(inode, block, 1); |
| 677 | mark_inode_dirty(inode); | ||
| 677 | error = -EIO; | 678 | error = -EIO; |
| 678 | goto cleanup; | 679 | goto cleanup; |
| 679 | } | 680 | } |
| @@ -703,8 +704,10 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh, | |||
| 703 | * written (only some dirty data were not) so we just proceed | 704 | * written (only some dirty data were not) so we just proceed |
| 704 | * as if nothing happened and cleanup the unused block */ | 705 | * as if nothing happened and cleanup the unused block */ |
| 705 | if (error && error != -ENOSPC) { | 706 | if (error && error != -ENOSPC) { |
| 706 | if (new_bh && new_bh != old_bh) | 707 | if (new_bh && new_bh != old_bh) { |
| 707 | dquot_free_block(inode, 1); | 708 | dquot_free_block_nodirty(inode, 1); |
| 709 | mark_inode_dirty(inode); | ||
| 710 | } | ||
| 708 | goto cleanup; | 711 | goto cleanup; |
| 709 | } | 712 | } |
| 710 | } else | 713 | } else |
| @@ -727,6 +730,7 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh, | |||
| 727 | mb_cache_entry_free(ce); | 730 | mb_cache_entry_free(ce); |
| 728 | ea_bdebug(old_bh, "freeing"); | 731 | ea_bdebug(old_bh, "freeing"); |
| 729 | ext2_free_blocks(inode, old_bh->b_blocknr, 1); | 732 | ext2_free_blocks(inode, old_bh->b_blocknr, 1); |
| 733 | mark_inode_dirty(inode); | ||
| 730 | /* We let our caller release old_bh, so we | 734 | /* We let our caller release old_bh, so we |
| 731 | * need to duplicate the buffer before. */ | 735 | * need to duplicate the buffer before. */ |
| 732 | get_bh(old_bh); | 736 | get_bh(old_bh); |
| @@ -736,7 +740,8 @@ ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh, | |||
| 736 | le32_add_cpu(&HDR(old_bh)->h_refcount, -1); | 740 | le32_add_cpu(&HDR(old_bh)->h_refcount, -1); |
| 737 | if (ce) | 741 | if (ce) |
| 738 | mb_cache_entry_release(ce); | 742 | mb_cache_entry_release(ce); |
| 739 | dquot_free_block(inode, 1); | 743 | dquot_free_block_nodirty(inode, 1); |
| 744 | mark_inode_dirty(inode); | ||
| 740 | mark_buffer_dirty(old_bh); | 745 | mark_buffer_dirty(old_bh); |
| 741 | ea_bdebug(old_bh, "refcount now=%d", | 746 | ea_bdebug(old_bh, "refcount now=%d", |
| 742 | le32_to_cpu(HDR(old_bh)->h_refcount)); | 747 | le32_to_cpu(HDR(old_bh)->h_refcount)); |
| @@ -799,7 +804,7 @@ ext2_xattr_delete_inode(struct inode *inode) | |||
| 799 | mark_buffer_dirty(bh); | 804 | mark_buffer_dirty(bh); |
| 800 | if (IS_SYNC(inode)) | 805 | if (IS_SYNC(inode)) |
| 801 | sync_dirty_buffer(bh); | 806 | sync_dirty_buffer(bh); |
| 802 | dquot_free_block(inode, 1); | 807 | dquot_free_block_nodirty(inode, 1); |
| 803 | } | 808 | } |
| 804 | EXT2_I(inode)->i_file_acl = 0; | 809 | EXT2_I(inode)->i_file_acl = 0; |
| 805 | 810 | ||
| @@ -838,7 +843,7 @@ ext2_xattr_cache_insert(struct buffer_head *bh) | |||
| 838 | ce = mb_cache_entry_alloc(ext2_xattr_cache, GFP_NOFS); | 843 | ce = mb_cache_entry_alloc(ext2_xattr_cache, GFP_NOFS); |
| 839 | if (!ce) | 844 | if (!ce) |
| 840 | return -ENOMEM; | 845 | return -ENOMEM; |
| 841 | error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, &hash); | 846 | error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, hash); |
| 842 | if (error) { | 847 | if (error) { |
| 843 | mb_cache_entry_free(ce); | 848 | mb_cache_entry_free(ce); |
| 844 | if (error == -EBUSY) { | 849 | if (error == -EBUSY) { |
| @@ -912,8 +917,8 @@ ext2_xattr_cache_find(struct inode *inode, struct ext2_xattr_header *header) | |||
| 912 | return NULL; /* never share */ | 917 | return NULL; /* never share */ |
| 913 | ea_idebug(inode, "looking for cached blocks [%x]", (int)hash); | 918 | ea_idebug(inode, "looking for cached blocks [%x]", (int)hash); |
| 914 | again: | 919 | again: |
| 915 | ce = mb_cache_entry_find_first(ext2_xattr_cache, 0, | 920 | ce = mb_cache_entry_find_first(ext2_xattr_cache, inode->i_sb->s_bdev, |
| 916 | inode->i_sb->s_bdev, hash); | 921 | hash); |
| 917 | while (ce) { | 922 | while (ce) { |
| 918 | struct buffer_head *bh; | 923 | struct buffer_head *bh; |
| 919 | 924 | ||
| @@ -945,7 +950,7 @@ again: | |||
| 945 | unlock_buffer(bh); | 950 | unlock_buffer(bh); |
| 946 | brelse(bh); | 951 | brelse(bh); |
| 947 | } | 952 | } |
| 948 | ce = mb_cache_entry_find_next(ce, 0, inode->i_sb->s_bdev, hash); | 953 | ce = mb_cache_entry_find_next(ce, inode->i_sb->s_bdev, hash); |
| 949 | } | 954 | } |
| 950 | return NULL; | 955 | return NULL; |
| 951 | } | 956 | } |
| @@ -1021,9 +1026,7 @@ static void ext2_xattr_rehash(struct ext2_xattr_header *header, | |||
| 1021 | int __init | 1026 | int __init |
| 1022 | init_ext2_xattr(void) | 1027 | init_ext2_xattr(void) |
| 1023 | { | 1028 | { |
| 1024 | ext2_xattr_cache = mb_cache_create("ext2_xattr", NULL, | 1029 | ext2_xattr_cache = mb_cache_create("ext2_xattr", 6); |
| 1025 | sizeof(struct mb_cache_entry) + | ||
| 1026 | sizeof(((struct mb_cache_entry *) 0)->e_indexes[0]), 1, 6); | ||
| 1027 | if (!ext2_xattr_cache) | 1030 | if (!ext2_xattr_cache) |
| 1028 | return -ENOMEM; | 1031 | return -ENOMEM; |
| 1029 | return 0; | 1032 | return 0; |
diff --git a/fs/ext3/ialloc.c b/fs/ext3/ialloc.c index 498021eb88fb..4ab72db3559e 100644 --- a/fs/ext3/ialloc.c +++ b/fs/ext3/ialloc.c | |||
| @@ -119,20 +119,8 @@ void ext3_free_inode (handle_t *handle, struct inode * inode) | |||
| 119 | ino = inode->i_ino; | 119 | ino = inode->i_ino; |
| 120 | ext3_debug ("freeing inode %lu\n", ino); | 120 | ext3_debug ("freeing inode %lu\n", ino); |
| 121 | 121 | ||
| 122 | /* | ||
| 123 | * Note: we must free any quota before locking the superblock, | ||
| 124 | * as writing the quota to disk may need the lock as well. | ||
| 125 | */ | ||
| 126 | dquot_initialize(inode); | ||
| 127 | ext3_xattr_delete_inode(handle, inode); | ||
| 128 | dquot_free_inode(inode); | ||
| 129 | dquot_drop(inode); | ||
| 130 | |||
| 131 | is_directory = S_ISDIR(inode->i_mode); | 122 | is_directory = S_ISDIR(inode->i_mode); |
| 132 | 123 | ||
| 133 | /* Do this BEFORE marking the inode not in use or returning an error */ | ||
| 134 | clear_inode (inode); | ||
| 135 | |||
| 136 | es = EXT3_SB(sb)->s_es; | 124 | es = EXT3_SB(sb)->s_es; |
| 137 | if (ino < EXT3_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) { | 125 | if (ino < EXT3_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) { |
| 138 | ext3_error (sb, "ext3_free_inode", | 126 | ext3_error (sb, "ext3_free_inode", |
diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index 001eb0e2d48e..5e0faf4cda79 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c | |||
| @@ -190,18 +190,28 @@ static int truncate_restart_transaction(handle_t *handle, struct inode *inode) | |||
| 190 | } | 190 | } |
| 191 | 191 | ||
| 192 | /* | 192 | /* |
| 193 | * Called at the last iput() if i_nlink is zero. | 193 | * Called at inode eviction from icache |
| 194 | */ | 194 | */ |
| 195 | void ext3_delete_inode (struct inode * inode) | 195 | void ext3_evict_inode (struct inode *inode) |
| 196 | { | 196 | { |
| 197 | struct ext3_block_alloc_info *rsv; | ||
| 197 | handle_t *handle; | 198 | handle_t *handle; |
| 199 | int want_delete = 0; | ||
| 198 | 200 | ||
| 199 | if (!is_bad_inode(inode)) | 201 | if (!inode->i_nlink && !is_bad_inode(inode)) { |
| 200 | dquot_initialize(inode); | 202 | dquot_initialize(inode); |
| 203 | want_delete = 1; | ||
| 204 | } | ||
| 201 | 205 | ||
| 202 | truncate_inode_pages(&inode->i_data, 0); | 206 | truncate_inode_pages(&inode->i_data, 0); |
| 203 | 207 | ||
| 204 | if (is_bad_inode(inode)) | 208 | ext3_discard_reservation(inode); |
| 209 | rsv = EXT3_I(inode)->i_block_alloc_info; | ||
| 210 | EXT3_I(inode)->i_block_alloc_info = NULL; | ||
| 211 | if (unlikely(rsv)) | ||
| 212 | kfree(rsv); | ||
| 213 | |||
| 214 | if (!want_delete) | ||
| 205 | goto no_delete; | 215 | goto no_delete; |
| 206 | 216 | ||
| 207 | handle = start_transaction(inode); | 217 | handle = start_transaction(inode); |
| @@ -238,15 +248,22 @@ void ext3_delete_inode (struct inode * inode) | |||
| 238 | * having errors), but we can't free the inode if the mark_dirty | 248 | * having errors), but we can't free the inode if the mark_dirty |
| 239 | * fails. | 249 | * fails. |
| 240 | */ | 250 | */ |
| 241 | if (ext3_mark_inode_dirty(handle, inode)) | 251 | if (ext3_mark_inode_dirty(handle, inode)) { |
| 242 | /* If that failed, just do the required in-core inode clear. */ | 252 | /* If that failed, just dquot_drop() and be done with that */ |
| 243 | clear_inode(inode); | 253 | dquot_drop(inode); |
| 244 | else | 254 | end_writeback(inode); |
| 255 | } else { | ||
| 256 | ext3_xattr_delete_inode(handle, inode); | ||
| 257 | dquot_free_inode(inode); | ||
| 258 | dquot_drop(inode); | ||
| 259 | end_writeback(inode); | ||
| 245 | ext3_free_inode(handle, inode); | 260 | ext3_free_inode(handle, inode); |
| 261 | } | ||
| 246 | ext3_journal_stop(handle); | 262 | ext3_journal_stop(handle); |
| 247 | return; | 263 | return; |
| 248 | no_delete: | 264 | no_delete: |
| 249 | clear_inode(inode); /* We must guarantee clearing of inode... */ | 265 | end_writeback(inode); |
| 266 | dquot_drop(inode); | ||
| 250 | } | 267 | } |
| 251 | 268 | ||
| 252 | typedef struct { | 269 | typedef struct { |
| @@ -1212,8 +1229,7 @@ retry: | |||
| 1212 | ret = PTR_ERR(handle); | 1229 | ret = PTR_ERR(handle); |
| 1213 | goto out; | 1230 | goto out; |
| 1214 | } | 1231 | } |
| 1215 | ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata, | 1232 | ret = __block_write_begin(page, pos, len, ext3_get_block); |
| 1216 | ext3_get_block); | ||
| 1217 | if (ret) | 1233 | if (ret) |
| 1218 | goto write_begin_failed; | 1234 | goto write_begin_failed; |
| 1219 | 1235 | ||
| @@ -1798,6 +1814,17 @@ retry: | |||
| 1798 | ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, | 1814 | ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, |
| 1799 | offset, nr_segs, | 1815 | offset, nr_segs, |
| 1800 | ext3_get_block, NULL); | 1816 | ext3_get_block, NULL); |
| 1817 | /* | ||
| 1818 | * In case of error extending write may have instantiated a few | ||
| 1819 | * blocks outside i_size. Trim these off again. | ||
| 1820 | */ | ||
| 1821 | if (unlikely((rw & WRITE) && ret < 0)) { | ||
| 1822 | loff_t isize = i_size_read(inode); | ||
| 1823 | loff_t end = offset + iov_length(iov, nr_segs); | ||
| 1824 | |||
| 1825 | if (end > isize) | ||
| 1826 | vmtruncate(inode, isize); | ||
| 1827 | } | ||
| 1801 | if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries)) | 1828 | if (ret == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries)) |
| 1802 | goto retry; | 1829 | goto retry; |
| 1803 | 1830 | ||
| @@ -2560,7 +2587,7 @@ out_stop: | |||
| 2560 | * If this was a simple ftruncate(), and the file will remain alive | 2587 | * If this was a simple ftruncate(), and the file will remain alive |
| 2561 | * then we need to clear up the orphan record which we created above. | 2588 | * then we need to clear up the orphan record which we created above. |
| 2562 | * However, if this was a real unlink then we were called by | 2589 | * However, if this was a real unlink then we were called by |
| 2563 | * ext3_delete_inode(), and we allow that function to clean up the | 2590 | * ext3_evict_inode(), and we allow that function to clean up the |
| 2564 | * orphan info for us. | 2591 | * orphan info for us. |
| 2565 | */ | 2592 | */ |
| 2566 | if (inode->i_nlink) | 2593 | if (inode->i_nlink) |
| @@ -3204,9 +3231,17 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 3204 | ext3_journal_stop(handle); | 3231 | ext3_journal_stop(handle); |
| 3205 | } | 3232 | } |
| 3206 | 3233 | ||
| 3207 | rc = inode_setattr(inode, attr); | 3234 | if ((attr->ia_valid & ATTR_SIZE) && |
| 3235 | attr->ia_size != i_size_read(inode)) { | ||
| 3236 | rc = vmtruncate(inode, attr->ia_size); | ||
| 3237 | if (rc) | ||
| 3238 | goto err_out; | ||
| 3239 | } | ||
| 3240 | |||
| 3241 | setattr_copy(inode, attr); | ||
| 3242 | mark_inode_dirty(inode); | ||
| 3208 | 3243 | ||
| 3209 | if (!rc && (ia_valid & ATTR_MODE)) | 3244 | if (ia_valid & ATTR_MODE) |
| 3210 | rc = ext3_acl_chmod(inode); | 3245 | rc = ext3_acl_chmod(inode); |
| 3211 | 3246 | ||
| 3212 | err_out: | 3247 | err_out: |
diff --git a/fs/ext3/super.c b/fs/ext3/super.c index 9650a956fd0e..5dbf4dba03c4 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c | |||
| @@ -527,17 +527,6 @@ static void destroy_inodecache(void) | |||
| 527 | kmem_cache_destroy(ext3_inode_cachep); | 527 | kmem_cache_destroy(ext3_inode_cachep); |
| 528 | } | 528 | } |
| 529 | 529 | ||
| 530 | static void ext3_clear_inode(struct inode *inode) | ||
| 531 | { | ||
| 532 | struct ext3_block_alloc_info *rsv = EXT3_I(inode)->i_block_alloc_info; | ||
| 533 | |||
| 534 | dquot_drop(inode); | ||
| 535 | ext3_discard_reservation(inode); | ||
| 536 | EXT3_I(inode)->i_block_alloc_info = NULL; | ||
| 537 | if (unlikely(rsv)) | ||
| 538 | kfree(rsv); | ||
| 539 | } | ||
| 540 | |||
| 541 | static inline void ext3_show_quota_options(struct seq_file *seq, struct super_block *sb) | 530 | static inline void ext3_show_quota_options(struct seq_file *seq, struct super_block *sb) |
| 542 | { | 531 | { |
| 543 | #if defined(CONFIG_QUOTA) | 532 | #if defined(CONFIG_QUOTA) |
| @@ -780,14 +769,13 @@ static const struct super_operations ext3_sops = { | |||
| 780 | .destroy_inode = ext3_destroy_inode, | 769 | .destroy_inode = ext3_destroy_inode, |
| 781 | .write_inode = ext3_write_inode, | 770 | .write_inode = ext3_write_inode, |
| 782 | .dirty_inode = ext3_dirty_inode, | 771 | .dirty_inode = ext3_dirty_inode, |
| 783 | .delete_inode = ext3_delete_inode, | 772 | .evict_inode = ext3_evict_inode, |
| 784 | .put_super = ext3_put_super, | 773 | .put_super = ext3_put_super, |
| 785 | .sync_fs = ext3_sync_fs, | 774 | .sync_fs = ext3_sync_fs, |
| 786 | .freeze_fs = ext3_freeze, | 775 | .freeze_fs = ext3_freeze, |
| 787 | .unfreeze_fs = ext3_unfreeze, | 776 | .unfreeze_fs = ext3_unfreeze, |
| 788 | .statfs = ext3_statfs, | 777 | .statfs = ext3_statfs, |
| 789 | .remount_fs = ext3_remount, | 778 | .remount_fs = ext3_remount, |
| 790 | .clear_inode = ext3_clear_inode, | ||
| 791 | .show_options = ext3_show_options, | 779 | .show_options = ext3_show_options, |
| 792 | #ifdef CONFIG_QUOTA | 780 | #ifdef CONFIG_QUOTA |
| 793 | .quota_read = ext3_quota_read, | 781 | .quota_read = ext3_quota_read, |
diff --git a/fs/ext3/xattr.c b/fs/ext3/xattr.c index 71fb8d65e54c..e69dc6dfaa89 100644 --- a/fs/ext3/xattr.c +++ b/fs/ext3/xattr.c | |||
| @@ -1139,7 +1139,7 @@ ext3_xattr_cache_insert(struct buffer_head *bh) | |||
| 1139 | ea_bdebug(bh, "out of memory"); | 1139 | ea_bdebug(bh, "out of memory"); |
| 1140 | return; | 1140 | return; |
| 1141 | } | 1141 | } |
| 1142 | error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, &hash); | 1142 | error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, hash); |
| 1143 | if (error) { | 1143 | if (error) { |
| 1144 | mb_cache_entry_free(ce); | 1144 | mb_cache_entry_free(ce); |
| 1145 | if (error == -EBUSY) { | 1145 | if (error == -EBUSY) { |
| @@ -1211,8 +1211,8 @@ ext3_xattr_cache_find(struct inode *inode, struct ext3_xattr_header *header, | |||
| 1211 | return NULL; /* never share */ | 1211 | return NULL; /* never share */ |
| 1212 | ea_idebug(inode, "looking for cached blocks [%x]", (int)hash); | 1212 | ea_idebug(inode, "looking for cached blocks [%x]", (int)hash); |
| 1213 | again: | 1213 | again: |
| 1214 | ce = mb_cache_entry_find_first(ext3_xattr_cache, 0, | 1214 | ce = mb_cache_entry_find_first(ext3_xattr_cache, inode->i_sb->s_bdev, |
| 1215 | inode->i_sb->s_bdev, hash); | 1215 | hash); |
| 1216 | while (ce) { | 1216 | while (ce) { |
| 1217 | struct buffer_head *bh; | 1217 | struct buffer_head *bh; |
| 1218 | 1218 | ||
| @@ -1237,7 +1237,7 @@ again: | |||
| 1237 | return bh; | 1237 | return bh; |
| 1238 | } | 1238 | } |
| 1239 | brelse(bh); | 1239 | brelse(bh); |
| 1240 | ce = mb_cache_entry_find_next(ce, 0, inode->i_sb->s_bdev, hash); | 1240 | ce = mb_cache_entry_find_next(ce, inode->i_sb->s_bdev, hash); |
| 1241 | } | 1241 | } |
| 1242 | return NULL; | 1242 | return NULL; |
| 1243 | } | 1243 | } |
| @@ -1313,9 +1313,7 @@ static void ext3_xattr_rehash(struct ext3_xattr_header *header, | |||
| 1313 | int __init | 1313 | int __init |
| 1314 | init_ext3_xattr(void) | 1314 | init_ext3_xattr(void) |
| 1315 | { | 1315 | { |
| 1316 | ext3_xattr_cache = mb_cache_create("ext3_xattr", NULL, | 1316 | ext3_xattr_cache = mb_cache_create("ext3_xattr", 6); |
| 1317 | sizeof(struct mb_cache_entry) + | ||
| 1318 | sizeof(((struct mb_cache_entry *) 0)->e_indexes[0]), 1, 6); | ||
| 1319 | if (!ext3_xattr_cache) | 1317 | if (!ext3_xattr_cache) |
| 1320 | return -ENOMEM; | 1318 | return -ENOMEM; |
| 1321 | return 0; | 1319 | return 0; |
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index e03841d9f30b..889ec9d5e6ad 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h | |||
| @@ -1643,7 +1643,8 @@ extern int ext4_write_inode(struct inode *, struct writeback_control *); | |||
| 1643 | extern int ext4_setattr(struct dentry *, struct iattr *); | 1643 | extern int ext4_setattr(struct dentry *, struct iattr *); |
| 1644 | extern int ext4_getattr(struct vfsmount *mnt, struct dentry *dentry, | 1644 | extern int ext4_getattr(struct vfsmount *mnt, struct dentry *dentry, |
| 1645 | struct kstat *stat); | 1645 | struct kstat *stat); |
| 1646 | extern void ext4_delete_inode(struct inode *); | 1646 | extern void ext4_evict_inode(struct inode *); |
| 1647 | extern void ext4_clear_inode(struct inode *); | ||
| 1647 | extern int ext4_sync_inode(handle_t *, struct inode *); | 1648 | extern int ext4_sync_inode(handle_t *, struct inode *); |
| 1648 | extern void ext4_dirty_inode(struct inode *); | 1649 | extern void ext4_dirty_inode(struct inode *); |
| 1649 | extern int ext4_change_inode_journal_flag(struct inode *, int); | 1650 | extern int ext4_change_inode_journal_flag(struct inode *, int); |
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c index ac377505ed57..45853e0d1f21 100644 --- a/fs/ext4/ialloc.c +++ b/fs/ext4/ialloc.c | |||
| @@ -222,7 +222,7 @@ void ext4_free_inode(handle_t *handle, struct inode *inode) | |||
| 222 | is_directory = S_ISDIR(inode->i_mode); | 222 | is_directory = S_ISDIR(inode->i_mode); |
| 223 | 223 | ||
| 224 | /* Do this BEFORE marking the inode not in use or returning an error */ | 224 | /* Do this BEFORE marking the inode not in use or returning an error */ |
| 225 | clear_inode(inode); | 225 | ext4_clear_inode(inode); |
| 226 | 226 | ||
| 227 | es = EXT4_SB(sb)->s_es; | 227 | es = EXT4_SB(sb)->s_es; |
| 228 | if (ino < EXT4_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) { | 228 | if (ino < EXT4_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) { |
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index a0ab3754d0d6..4b8debeb3965 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c | |||
| @@ -167,11 +167,16 @@ int ext4_truncate_restart_trans(handle_t *handle, struct inode *inode, | |||
| 167 | /* | 167 | /* |
| 168 | * Called at the last iput() if i_nlink is zero. | 168 | * Called at the last iput() if i_nlink is zero. |
| 169 | */ | 169 | */ |
| 170 | void ext4_delete_inode(struct inode *inode) | 170 | void ext4_evict_inode(struct inode *inode) |
| 171 | { | 171 | { |
| 172 | handle_t *handle; | 172 | handle_t *handle; |
| 173 | int err; | 173 | int err; |
| 174 | 174 | ||
| 175 | if (inode->i_nlink) { | ||
| 176 | truncate_inode_pages(&inode->i_data, 0); | ||
| 177 | goto no_delete; | ||
| 178 | } | ||
| 179 | |||
| 175 | if (!is_bad_inode(inode)) | 180 | if (!is_bad_inode(inode)) |
| 176 | dquot_initialize(inode); | 181 | dquot_initialize(inode); |
| 177 | 182 | ||
| @@ -246,13 +251,13 @@ void ext4_delete_inode(struct inode *inode) | |||
| 246 | */ | 251 | */ |
| 247 | if (ext4_mark_inode_dirty(handle, inode)) | 252 | if (ext4_mark_inode_dirty(handle, inode)) |
| 248 | /* If that failed, just do the required in-core inode clear. */ | 253 | /* If that failed, just do the required in-core inode clear. */ |
| 249 | clear_inode(inode); | 254 | ext4_clear_inode(inode); |
| 250 | else | 255 | else |
| 251 | ext4_free_inode(handle, inode); | 256 | ext4_free_inode(handle, inode); |
| 252 | ext4_journal_stop(handle); | 257 | ext4_journal_stop(handle); |
| 253 | return; | 258 | return; |
| 254 | no_delete: | 259 | no_delete: |
| 255 | clear_inode(inode); /* We must guarantee clearing of inode... */ | 260 | ext4_clear_inode(inode); /* We must guarantee clearing of inode... */ |
| 256 | } | 261 | } |
| 257 | 262 | ||
| 258 | typedef struct { | 263 | typedef struct { |
| @@ -1602,11 +1607,9 @@ retry: | |||
| 1602 | *pagep = page; | 1607 | *pagep = page; |
| 1603 | 1608 | ||
| 1604 | if (ext4_should_dioread_nolock(inode)) | 1609 | if (ext4_should_dioread_nolock(inode)) |
| 1605 | ret = block_write_begin(file, mapping, pos, len, flags, pagep, | 1610 | ret = __block_write_begin(page, pos, len, ext4_get_block_write); |
| 1606 | fsdata, ext4_get_block_write); | ||
| 1607 | else | 1611 | else |
| 1608 | ret = block_write_begin(file, mapping, pos, len, flags, pagep, | 1612 | ret = __block_write_begin(page, pos, len, ext4_get_block); |
| 1609 | fsdata, ext4_get_block); | ||
| 1610 | 1613 | ||
| 1611 | if (!ret && ext4_should_journal_data(inode)) { | 1614 | if (!ret && ext4_should_journal_data(inode)) { |
| 1612 | ret = walk_page_buffers(handle, page_buffers(page), | 1615 | ret = walk_page_buffers(handle, page_buffers(page), |
| @@ -1617,7 +1620,7 @@ retry: | |||
| 1617 | unlock_page(page); | 1620 | unlock_page(page); |
| 1618 | page_cache_release(page); | 1621 | page_cache_release(page); |
| 1619 | /* | 1622 | /* |
| 1620 | * block_write_begin may have instantiated a few blocks | 1623 | * __block_write_begin may have instantiated a few blocks |
| 1621 | * outside i_size. Trim these off again. Don't need | 1624 | * outside i_size. Trim these off again. Don't need |
| 1622 | * i_size_read because we hold i_mutex. | 1625 | * i_size_read because we hold i_mutex. |
| 1623 | * | 1626 | * |
| @@ -3205,8 +3208,7 @@ retry: | |||
| 3205 | } | 3208 | } |
| 3206 | *pagep = page; | 3209 | *pagep = page; |
| 3207 | 3210 | ||
| 3208 | ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata, | 3211 | ret = __block_write_begin(page, pos, len, ext4_da_get_block_prep); |
| 3209 | ext4_da_get_block_prep); | ||
| 3210 | if (ret < 0) { | 3212 | if (ret < 0) { |
| 3211 | unlock_page(page); | 3213 | unlock_page(page); |
| 3212 | ext4_journal_stop(handle); | 3214 | ext4_journal_stop(handle); |
| @@ -3565,15 +3567,24 @@ static ssize_t ext4_ind_direct_IO(int rw, struct kiocb *iocb, | |||
| 3565 | 3567 | ||
| 3566 | retry: | 3568 | retry: |
| 3567 | if (rw == READ && ext4_should_dioread_nolock(inode)) | 3569 | if (rw == READ && ext4_should_dioread_nolock(inode)) |
| 3568 | ret = blockdev_direct_IO_no_locking(rw, iocb, inode, | 3570 | ret = __blockdev_direct_IO(rw, iocb, inode, |
| 3569 | inode->i_sb->s_bdev, iov, | 3571 | inode->i_sb->s_bdev, iov, |
| 3570 | offset, nr_segs, | 3572 | offset, nr_segs, |
| 3571 | ext4_get_block, NULL); | 3573 | ext4_get_block, NULL, NULL, 0); |
| 3572 | else | 3574 | else { |
| 3573 | ret = blockdev_direct_IO(rw, iocb, inode, | 3575 | ret = blockdev_direct_IO(rw, iocb, inode, |
| 3574 | inode->i_sb->s_bdev, iov, | 3576 | inode->i_sb->s_bdev, iov, |
| 3575 | offset, nr_segs, | 3577 | offset, nr_segs, |
| 3576 | ext4_get_block, NULL); | 3578 | ext4_get_block, NULL); |
| 3579 | |||
| 3580 | if (unlikely((rw & WRITE) && ret < 0)) { | ||
| 3581 | loff_t isize = i_size_read(inode); | ||
| 3582 | loff_t end = offset + iov_length(iov, nr_segs); | ||
| 3583 | |||
| 3584 | if (end > isize) | ||
| 3585 | vmtruncate(inode, isize); | ||
| 3586 | } | ||
| 3587 | } | ||
| 3577 | if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) | 3588 | if (ret == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries)) |
| 3578 | goto retry; | 3589 | goto retry; |
| 3579 | 3590 | ||
| @@ -5536,11 +5547,19 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 5536 | ext4_truncate(inode); | 5547 | ext4_truncate(inode); |
| 5537 | } | 5548 | } |
| 5538 | 5549 | ||
| 5539 | rc = inode_setattr(inode, attr); | 5550 | if ((attr->ia_valid & ATTR_SIZE) && |
| 5551 | attr->ia_size != i_size_read(inode)) | ||
| 5552 | rc = vmtruncate(inode, attr->ia_size); | ||
| 5540 | 5553 | ||
| 5541 | /* If inode_setattr's call to ext4_truncate failed to get a | 5554 | if (!rc) { |
| 5542 | * transaction handle at all, we need to clean up the in-core | 5555 | setattr_copy(inode, attr); |
| 5543 | * orphan list manually. */ | 5556 | mark_inode_dirty(inode); |
| 5557 | } | ||
| 5558 | |||
| 5559 | /* | ||
| 5560 | * If the call to ext4_truncate failed to get a transaction handle at | ||
| 5561 | * all, we need to clean up the in-core orphan list manually. | ||
| 5562 | */ | ||
| 5544 | if (inode->i_nlink) | 5563 | if (inode->i_nlink) |
| 5545 | ext4_orphan_del(NULL, inode); | 5564 | ext4_orphan_del(NULL, inode); |
| 5546 | 5565 | ||
diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 8d65575f8c8c..26147746c272 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c | |||
| @@ -868,8 +868,10 @@ static void destroy_inodecache(void) | |||
| 868 | kmem_cache_destroy(ext4_inode_cachep); | 868 | kmem_cache_destroy(ext4_inode_cachep); |
| 869 | } | 869 | } |
| 870 | 870 | ||
| 871 | static void ext4_clear_inode(struct inode *inode) | 871 | void ext4_clear_inode(struct inode *inode) |
| 872 | { | 872 | { |
| 873 | invalidate_inode_buffers(inode); | ||
| 874 | end_writeback(inode); | ||
| 873 | dquot_drop(inode); | 875 | dquot_drop(inode); |
| 874 | ext4_discard_preallocations(inode); | 876 | ext4_discard_preallocations(inode); |
| 875 | if (EXT4_JOURNAL(inode)) | 877 | if (EXT4_JOURNAL(inode)) |
| @@ -1158,14 +1160,13 @@ static const struct super_operations ext4_sops = { | |||
| 1158 | .destroy_inode = ext4_destroy_inode, | 1160 | .destroy_inode = ext4_destroy_inode, |
| 1159 | .write_inode = ext4_write_inode, | 1161 | .write_inode = ext4_write_inode, |
| 1160 | .dirty_inode = ext4_dirty_inode, | 1162 | .dirty_inode = ext4_dirty_inode, |
| 1161 | .delete_inode = ext4_delete_inode, | 1163 | .evict_inode = ext4_evict_inode, |
| 1162 | .put_super = ext4_put_super, | 1164 | .put_super = ext4_put_super, |
| 1163 | .sync_fs = ext4_sync_fs, | 1165 | .sync_fs = ext4_sync_fs, |
| 1164 | .freeze_fs = ext4_freeze, | 1166 | .freeze_fs = ext4_freeze, |
| 1165 | .unfreeze_fs = ext4_unfreeze, | 1167 | .unfreeze_fs = ext4_unfreeze, |
| 1166 | .statfs = ext4_statfs, | 1168 | .statfs = ext4_statfs, |
| 1167 | .remount_fs = ext4_remount, | 1169 | .remount_fs = ext4_remount, |
| 1168 | .clear_inode = ext4_clear_inode, | ||
| 1169 | .show_options = ext4_show_options, | 1170 | .show_options = ext4_show_options, |
| 1170 | #ifdef CONFIG_QUOTA | 1171 | #ifdef CONFIG_QUOTA |
| 1171 | .quota_read = ext4_quota_read, | 1172 | .quota_read = ext4_quota_read, |
| @@ -1179,12 +1180,11 @@ static const struct super_operations ext4_nojournal_sops = { | |||
| 1179 | .destroy_inode = ext4_destroy_inode, | 1180 | .destroy_inode = ext4_destroy_inode, |
| 1180 | .write_inode = ext4_write_inode, | 1181 | .write_inode = ext4_write_inode, |
| 1181 | .dirty_inode = ext4_dirty_inode, | 1182 | .dirty_inode = ext4_dirty_inode, |
| 1182 | .delete_inode = ext4_delete_inode, | 1183 | .evict_inode = ext4_evict_inode, |
| 1183 | .write_super = ext4_write_super, | 1184 | .write_super = ext4_write_super, |
| 1184 | .put_super = ext4_put_super, | 1185 | .put_super = ext4_put_super, |
| 1185 | .statfs = ext4_statfs, | 1186 | .statfs = ext4_statfs, |
| 1186 | .remount_fs = ext4_remount, | 1187 | .remount_fs = ext4_remount, |
| 1187 | .clear_inode = ext4_clear_inode, | ||
| 1188 | .show_options = ext4_show_options, | 1188 | .show_options = ext4_show_options, |
| 1189 | #ifdef CONFIG_QUOTA | 1189 | #ifdef CONFIG_QUOTA |
| 1190 | .quota_read = ext4_quota_read, | 1190 | .quota_read = ext4_quota_read, |
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c index a6f314249574..3a8cd8dff1ad 100644 --- a/fs/ext4/xattr.c +++ b/fs/ext4/xattr.c | |||
| @@ -1417,7 +1417,7 @@ ext4_xattr_cache_insert(struct buffer_head *bh) | |||
| 1417 | ea_bdebug(bh, "out of memory"); | 1417 | ea_bdebug(bh, "out of memory"); |
| 1418 | return; | 1418 | return; |
| 1419 | } | 1419 | } |
| 1420 | error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, &hash); | 1420 | error = mb_cache_entry_insert(ce, bh->b_bdev, bh->b_blocknr, hash); |
| 1421 | if (error) { | 1421 | if (error) { |
| 1422 | mb_cache_entry_free(ce); | 1422 | mb_cache_entry_free(ce); |
| 1423 | if (error == -EBUSY) { | 1423 | if (error == -EBUSY) { |
| @@ -1489,8 +1489,8 @@ ext4_xattr_cache_find(struct inode *inode, struct ext4_xattr_header *header, | |||
| 1489 | return NULL; /* never share */ | 1489 | return NULL; /* never share */ |
| 1490 | ea_idebug(inode, "looking for cached blocks [%x]", (int)hash); | 1490 | ea_idebug(inode, "looking for cached blocks [%x]", (int)hash); |
| 1491 | again: | 1491 | again: |
| 1492 | ce = mb_cache_entry_find_first(ext4_xattr_cache, 0, | 1492 | ce = mb_cache_entry_find_first(ext4_xattr_cache, inode->i_sb->s_bdev, |
| 1493 | inode->i_sb->s_bdev, hash); | 1493 | hash); |
| 1494 | while (ce) { | 1494 | while (ce) { |
| 1495 | struct buffer_head *bh; | 1495 | struct buffer_head *bh; |
| 1496 | 1496 | ||
| @@ -1514,7 +1514,7 @@ again: | |||
| 1514 | return bh; | 1514 | return bh; |
| 1515 | } | 1515 | } |
| 1516 | brelse(bh); | 1516 | brelse(bh); |
| 1517 | ce = mb_cache_entry_find_next(ce, 0, inode->i_sb->s_bdev, hash); | 1517 | ce = mb_cache_entry_find_next(ce, inode->i_sb->s_bdev, hash); |
| 1518 | } | 1518 | } |
| 1519 | return NULL; | 1519 | return NULL; |
| 1520 | } | 1520 | } |
| @@ -1590,9 +1590,7 @@ static void ext4_xattr_rehash(struct ext4_xattr_header *header, | |||
| 1590 | int __init | 1590 | int __init |
| 1591 | init_ext4_xattr(void) | 1591 | init_ext4_xattr(void) |
| 1592 | { | 1592 | { |
| 1593 | ext4_xattr_cache = mb_cache_create("ext4_xattr", NULL, | 1593 | ext4_xattr_cache = mb_cache_create("ext4_xattr", 6); |
| 1594 | sizeof(struct mb_cache_entry) + | ||
| 1595 | sizeof(((struct mb_cache_entry *) 0)->e_indexes[0]), 1, 6); | ||
| 1596 | if (!ext4_xattr_cache) | 1594 | if (!ext4_xattr_cache) |
| 1597 | return -ENOMEM; | 1595 | return -ENOMEM; |
| 1598 | return 0; | 1596 | return 0; |
diff --git a/fs/fat/fat.h b/fs/fat/fat.h index 27ac25725954..d75a77f85c28 100644 --- a/fs/fat/fat.h +++ b/fs/fat/fat.h | |||
| @@ -306,7 +306,6 @@ extern long fat_generic_ioctl(struct file *filp, unsigned int cmd, | |||
| 306 | extern const struct file_operations fat_file_operations; | 306 | extern const struct file_operations fat_file_operations; |
| 307 | extern const struct inode_operations fat_file_inode_operations; | 307 | extern const struct inode_operations fat_file_inode_operations; |
| 308 | extern int fat_setattr(struct dentry * dentry, struct iattr * attr); | 308 | extern int fat_setattr(struct dentry * dentry, struct iattr * attr); |
| 309 | extern int fat_setsize(struct inode *inode, loff_t offset); | ||
| 310 | extern void fat_truncate_blocks(struct inode *inode, loff_t offset); | 309 | extern void fat_truncate_blocks(struct inode *inode, loff_t offset); |
| 311 | extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, | 310 | extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, |
| 312 | struct kstat *stat); | 311 | struct kstat *stat); |
diff --git a/fs/fat/file.c b/fs/fat/file.c index 990dfae022e5..7257752b6d5d 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c | |||
| @@ -364,18 +364,6 @@ static int fat_allow_set_time(struct msdos_sb_info *sbi, struct inode *inode) | |||
| 364 | return 0; | 364 | return 0; |
| 365 | } | 365 | } |
| 366 | 366 | ||
| 367 | int fat_setsize(struct inode *inode, loff_t offset) | ||
| 368 | { | ||
| 369 | int error; | ||
| 370 | |||
| 371 | error = simple_setsize(inode, offset); | ||
| 372 | if (error) | ||
| 373 | return error; | ||
| 374 | fat_truncate_blocks(inode, offset); | ||
| 375 | |||
| 376 | return error; | ||
| 377 | } | ||
| 378 | |||
| 379 | #define TIMES_SET_FLAGS (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET) | 367 | #define TIMES_SET_FLAGS (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET) |
| 380 | /* valid file mode bits */ | 368 | /* valid file mode bits */ |
| 381 | #define FAT_VALID_MODE (S_IFREG | S_IFDIR | S_IRWXUGO) | 369 | #define FAT_VALID_MODE (S_IFREG | S_IFDIR | S_IRWXUGO) |
| @@ -387,21 +375,6 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 387 | unsigned int ia_valid; | 375 | unsigned int ia_valid; |
| 388 | int error; | 376 | int error; |
| 389 | 377 | ||
| 390 | /* | ||
| 391 | * Expand the file. Since inode_setattr() updates ->i_size | ||
| 392 | * before calling the ->truncate(), but FAT needs to fill the | ||
| 393 | * hole before it. XXX: this is no longer true with new truncate | ||
| 394 | * sequence. | ||
| 395 | */ | ||
| 396 | if (attr->ia_valid & ATTR_SIZE) { | ||
| 397 | if (attr->ia_size > inode->i_size) { | ||
| 398 | error = fat_cont_expand(inode, attr->ia_size); | ||
| 399 | if (error || attr->ia_valid == ATTR_SIZE) | ||
| 400 | goto out; | ||
| 401 | attr->ia_valid &= ~ATTR_SIZE; | ||
| 402 | } | ||
| 403 | } | ||
| 404 | |||
| 405 | /* Check for setting the inode time. */ | 378 | /* Check for setting the inode time. */ |
| 406 | ia_valid = attr->ia_valid; | 379 | ia_valid = attr->ia_valid; |
| 407 | if (ia_valid & TIMES_SET_FLAGS) { | 380 | if (ia_valid & TIMES_SET_FLAGS) { |
| @@ -417,6 +390,21 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 417 | goto out; | 390 | goto out; |
| 418 | } | 391 | } |
| 419 | 392 | ||
| 393 | /* | ||
| 394 | * Expand the file. Since inode_setattr() updates ->i_size | ||
| 395 | * before calling the ->truncate(), but FAT needs to fill the | ||
| 396 | * hole before it. XXX: this is no longer true with new truncate | ||
| 397 | * sequence. | ||
| 398 | */ | ||
| 399 | if (attr->ia_valid & ATTR_SIZE) { | ||
| 400 | if (attr->ia_size > inode->i_size) { | ||
| 401 | error = fat_cont_expand(inode, attr->ia_size); | ||
| 402 | if (error || attr->ia_valid == ATTR_SIZE) | ||
| 403 | goto out; | ||
| 404 | attr->ia_valid &= ~ATTR_SIZE; | ||
| 405 | } | ||
| 406 | } | ||
| 407 | |||
| 420 | if (((attr->ia_valid & ATTR_UID) && | 408 | if (((attr->ia_valid & ATTR_UID) && |
| 421 | (attr->ia_uid != sbi->options.fs_uid)) || | 409 | (attr->ia_uid != sbi->options.fs_uid)) || |
| 422 | ((attr->ia_valid & ATTR_GID) && | 410 | ((attr->ia_valid & ATTR_GID) && |
| @@ -441,12 +429,11 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 441 | } | 429 | } |
| 442 | 430 | ||
| 443 | if (attr->ia_valid & ATTR_SIZE) { | 431 | if (attr->ia_valid & ATTR_SIZE) { |
| 444 | error = fat_setsize(inode, attr->ia_size); | 432 | truncate_setsize(inode, attr->ia_size); |
| 445 | if (error) | 433 | fat_truncate_blocks(inode, attr->ia_size); |
| 446 | goto out; | ||
| 447 | } | 434 | } |
| 448 | 435 | ||
| 449 | generic_setattr(inode, attr); | 436 | setattr_copy(inode, attr); |
| 450 | mark_inode_dirty(inode); | 437 | mark_inode_dirty(inode); |
| 451 | out: | 438 | out: |
| 452 | return error; | 439 | return error; |
diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 7bf45aee56d7..830058057d33 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c | |||
| @@ -159,7 +159,7 @@ static int fat_write_begin(struct file *file, struct address_space *mapping, | |||
| 159 | int err; | 159 | int err; |
| 160 | 160 | ||
| 161 | *pagep = NULL; | 161 | *pagep = NULL; |
| 162 | err = cont_write_begin_newtrunc(file, mapping, pos, len, flags, | 162 | err = cont_write_begin(file, mapping, pos, len, flags, |
| 163 | pagep, fsdata, fat_get_block, | 163 | pagep, fsdata, fat_get_block, |
| 164 | &MSDOS_I(mapping->host)->mmu_private); | 164 | &MSDOS_I(mapping->host)->mmu_private); |
| 165 | if (err < 0) | 165 | if (err < 0) |
| @@ -212,8 +212,8 @@ static ssize_t fat_direct_IO(int rw, struct kiocb *iocb, | |||
| 212 | * FAT need to use the DIO_LOCKING for avoiding the race | 212 | * FAT need to use the DIO_LOCKING for avoiding the race |
| 213 | * condition of fat_get_block() and ->truncate(). | 213 | * condition of fat_get_block() and ->truncate(). |
| 214 | */ | 214 | */ |
| 215 | ret = blockdev_direct_IO_newtrunc(rw, iocb, inode, inode->i_sb->s_bdev, | 215 | ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, |
| 216 | iov, offset, nr_segs, fat_get_block, NULL); | 216 | iov, offset, nr_segs, fat_get_block, NULL); |
| 217 | if (ret < 0 && (rw & WRITE)) | 217 | if (ret < 0 && (rw & WRITE)) |
| 218 | fat_write_failed(mapping, offset + iov_length(iov, nr_segs)); | 218 | fat_write_failed(mapping, offset + iov_length(iov, nr_segs)); |
| 219 | 219 | ||
| @@ -263,7 +263,7 @@ static const struct address_space_operations fat_aops = { | |||
| 263 | * check if the location is still valid and retry if it | 263 | * check if the location is still valid and retry if it |
| 264 | * isn't. Otherwise we do changes. | 264 | * isn't. Otherwise we do changes. |
| 265 | * 5. Spinlock is used to protect hash/unhash/location check/lookup | 265 | * 5. Spinlock is used to protect hash/unhash/location check/lookup |
| 266 | * 6. fat_clear_inode() unhashes the F-d-c entry. | 266 | * 6. fat_evict_inode() unhashes the F-d-c entry. |
| 267 | * 7. lookup() and readdir() do igrab() if they find a F-d-c entry | 267 | * 7. lookup() and readdir() do igrab() if they find a F-d-c entry |
| 268 | * and consider negative result as cache miss. | 268 | * and consider negative result as cache miss. |
| 269 | */ | 269 | */ |
| @@ -448,16 +448,15 @@ out: | |||
| 448 | 448 | ||
| 449 | EXPORT_SYMBOL_GPL(fat_build_inode); | 449 | EXPORT_SYMBOL_GPL(fat_build_inode); |
| 450 | 450 | ||
| 451 | static void fat_delete_inode(struct inode *inode) | 451 | static void fat_evict_inode(struct inode *inode) |
| 452 | { | 452 | { |
| 453 | truncate_inode_pages(&inode->i_data, 0); | 453 | truncate_inode_pages(&inode->i_data, 0); |
| 454 | inode->i_size = 0; | 454 | if (!inode->i_nlink) { |
| 455 | fat_truncate_blocks(inode, 0); | 455 | inode->i_size = 0; |
| 456 | clear_inode(inode); | 456 | fat_truncate_blocks(inode, 0); |
| 457 | } | 457 | } |
| 458 | 458 | invalidate_inode_buffers(inode); | |
| 459 | static void fat_clear_inode(struct inode *inode) | 459 | end_writeback(inode); |
| 460 | { | ||
| 461 | fat_cache_inval_inode(inode); | 460 | fat_cache_inval_inode(inode); |
| 462 | fat_detach(inode); | 461 | fat_detach(inode); |
| 463 | } | 462 | } |
| @@ -674,12 +673,11 @@ static const struct super_operations fat_sops = { | |||
| 674 | .alloc_inode = fat_alloc_inode, | 673 | .alloc_inode = fat_alloc_inode, |
| 675 | .destroy_inode = fat_destroy_inode, | 674 | .destroy_inode = fat_destroy_inode, |
| 676 | .write_inode = fat_write_inode, | 675 | .write_inode = fat_write_inode, |
| 677 | .delete_inode = fat_delete_inode, | 676 | .evict_inode = fat_evict_inode, |
| 678 | .put_super = fat_put_super, | 677 | .put_super = fat_put_super, |
| 679 | .write_super = fat_write_super, | 678 | .write_super = fat_write_super, |
| 680 | .sync_fs = fat_sync_fs, | 679 | .sync_fs = fat_sync_fs, |
| 681 | .statfs = fat_statfs, | 680 | .statfs = fat_statfs, |
| 682 | .clear_inode = fat_clear_inode, | ||
| 683 | .remount_fs = fat_remount, | 681 | .remount_fs = fat_remount, |
| 684 | 682 | ||
| 685 | .show_options = fat_show_options, | 683 | .show_options = fat_show_options, |
diff --git a/fs/fcntl.c b/fs/fcntl.c index 9d175d623aab..6769fd0f35b8 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c | |||
| @@ -767,11 +767,22 @@ void kill_fasync(struct fasync_struct **fp, int sig, int band) | |||
| 767 | } | 767 | } |
| 768 | EXPORT_SYMBOL(kill_fasync); | 768 | EXPORT_SYMBOL(kill_fasync); |
| 769 | 769 | ||
| 770 | static int __init fasync_init(void) | 770 | static int __init fcntl_init(void) |
| 771 | { | 771 | { |
| 772 | /* please add new bits here to ensure allocation uniqueness */ | ||
| 773 | BUILD_BUG_ON(19 - 1 /* for O_RDONLY being 0 */ != HWEIGHT32( | ||
| 774 | O_RDONLY | O_WRONLY | O_RDWR | | ||
| 775 | O_CREAT | O_EXCL | O_NOCTTY | | ||
| 776 | O_TRUNC | O_APPEND | O_NONBLOCK | | ||
| 777 | __O_SYNC | O_DSYNC | FASYNC | | ||
| 778 | O_DIRECT | O_LARGEFILE | O_DIRECTORY | | ||
| 779 | O_NOFOLLOW | O_NOATIME | O_CLOEXEC | | ||
| 780 | FMODE_EXEC | ||
| 781 | )); | ||
| 782 | |||
| 772 | fasync_cache = kmem_cache_create("fasync_cache", | 783 | fasync_cache = kmem_cache_create("fasync_cache", |
| 773 | sizeof(struct fasync_struct), 0, SLAB_PANIC, NULL); | 784 | sizeof(struct fasync_struct), 0, SLAB_PANIC, NULL); |
| 774 | return 0; | 785 | return 0; |
| 775 | } | 786 | } |
| 776 | 787 | ||
| 777 | module_init(fasync_init) | 788 | module_init(fcntl_init) |
| @@ -39,28 +39,27 @@ int sysctl_nr_open_max = 1024 * 1024; /* raised later */ | |||
| 39 | */ | 39 | */ |
| 40 | static DEFINE_PER_CPU(struct fdtable_defer, fdtable_defer_list); | 40 | static DEFINE_PER_CPU(struct fdtable_defer, fdtable_defer_list); |
| 41 | 41 | ||
| 42 | static inline void * alloc_fdmem(unsigned int size) | 42 | static inline void *alloc_fdmem(unsigned int size) |
| 43 | { | 43 | { |
| 44 | if (size <= PAGE_SIZE) | 44 | void *data; |
| 45 | return kmalloc(size, GFP_KERNEL); | 45 | |
| 46 | else | 46 | data = kmalloc(size, GFP_KERNEL|__GFP_NOWARN); |
| 47 | return vmalloc(size); | 47 | if (data != NULL) |
| 48 | return data; | ||
| 49 | |||
| 50 | return vmalloc(size); | ||
| 48 | } | 51 | } |
| 49 | 52 | ||
| 50 | static inline void free_fdarr(struct fdtable *fdt) | 53 | static void free_fdmem(void *ptr) |
| 51 | { | 54 | { |
| 52 | if (fdt->max_fds <= (PAGE_SIZE / sizeof(struct file *))) | 55 | is_vmalloc_addr(ptr) ? vfree(ptr) : kfree(ptr); |
| 53 | kfree(fdt->fd); | ||
| 54 | else | ||
| 55 | vfree(fdt->fd); | ||
| 56 | } | 56 | } |
| 57 | 57 | ||
| 58 | static inline void free_fdset(struct fdtable *fdt) | 58 | static void __free_fdtable(struct fdtable *fdt) |
| 59 | { | 59 | { |
| 60 | if (fdt->max_fds <= (PAGE_SIZE * BITS_PER_BYTE / 2)) | 60 | free_fdmem(fdt->fd); |
| 61 | kfree(fdt->open_fds); | 61 | free_fdmem(fdt->open_fds); |
| 62 | else | 62 | kfree(fdt); |
| 63 | vfree(fdt->open_fds); | ||
| 64 | } | 63 | } |
| 65 | 64 | ||
| 66 | static void free_fdtable_work(struct work_struct *work) | 65 | static void free_fdtable_work(struct work_struct *work) |
| @@ -75,9 +74,8 @@ static void free_fdtable_work(struct work_struct *work) | |||
| 75 | spin_unlock_bh(&f->lock); | 74 | spin_unlock_bh(&f->lock); |
| 76 | while(fdt) { | 75 | while(fdt) { |
| 77 | struct fdtable *next = fdt->next; | 76 | struct fdtable *next = fdt->next; |
| 78 | vfree(fdt->fd); | 77 | |
| 79 | free_fdset(fdt); | 78 | __free_fdtable(fdt); |
| 80 | kfree(fdt); | ||
| 81 | fdt = next; | 79 | fdt = next; |
| 82 | } | 80 | } |
| 83 | } | 81 | } |
| @@ -98,7 +96,7 @@ void free_fdtable_rcu(struct rcu_head *rcu) | |||
| 98 | container_of(fdt, struct files_struct, fdtab)); | 96 | container_of(fdt, struct files_struct, fdtab)); |
| 99 | return; | 97 | return; |
| 100 | } | 98 | } |
| 101 | if (fdt->max_fds <= (PAGE_SIZE / sizeof(struct file *))) { | 99 | if (!is_vmalloc_addr(fdt->fd) && !is_vmalloc_addr(fdt->open_fds)) { |
| 102 | kfree(fdt->fd); | 100 | kfree(fdt->fd); |
| 103 | kfree(fdt->open_fds); | 101 | kfree(fdt->open_fds); |
| 104 | kfree(fdt); | 102 | kfree(fdt); |
| @@ -183,7 +181,7 @@ static struct fdtable * alloc_fdtable(unsigned int nr) | |||
| 183 | return fdt; | 181 | return fdt; |
| 184 | 182 | ||
| 185 | out_arr: | 183 | out_arr: |
| 186 | free_fdarr(fdt); | 184 | free_fdmem(fdt->fd); |
| 187 | out_fdt: | 185 | out_fdt: |
| 188 | kfree(fdt); | 186 | kfree(fdt); |
| 189 | out: | 187 | out: |
| @@ -213,9 +211,7 @@ static int expand_fdtable(struct files_struct *files, int nr) | |||
| 213 | * caller and alloc_fdtable(). Cheaper to catch it here... | 211 | * caller and alloc_fdtable(). Cheaper to catch it here... |
| 214 | */ | 212 | */ |
| 215 | if (unlikely(new_fdt->max_fds <= nr)) { | 213 | if (unlikely(new_fdt->max_fds <= nr)) { |
| 216 | free_fdarr(new_fdt); | 214 | __free_fdtable(new_fdt); |
| 217 | free_fdset(new_fdt); | ||
| 218 | kfree(new_fdt); | ||
| 219 | return -EMFILE; | 215 | return -EMFILE; |
| 220 | } | 216 | } |
| 221 | /* | 217 | /* |
| @@ -231,9 +227,7 @@ static int expand_fdtable(struct files_struct *files, int nr) | |||
| 231 | free_fdtable(cur_fdt); | 227 | free_fdtable(cur_fdt); |
| 232 | } else { | 228 | } else { |
| 233 | /* Somebody else expanded, so undo our attempt */ | 229 | /* Somebody else expanded, so undo our attempt */ |
| 234 | free_fdarr(new_fdt); | 230 | __free_fdtable(new_fdt); |
| 235 | free_fdset(new_fdt); | ||
| 236 | kfree(new_fdt); | ||
| 237 | } | 231 | } |
| 238 | return 1; | 232 | return 1; |
| 239 | } | 233 | } |
| @@ -323,11 +317,8 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp) | |||
| 323 | while (unlikely(open_files > new_fdt->max_fds)) { | 317 | while (unlikely(open_files > new_fdt->max_fds)) { |
| 324 | spin_unlock(&oldf->file_lock); | 318 | spin_unlock(&oldf->file_lock); |
| 325 | 319 | ||
| 326 | if (new_fdt != &newf->fdtab) { | 320 | if (new_fdt != &newf->fdtab) |
| 327 | free_fdarr(new_fdt); | 321 | __free_fdtable(new_fdt); |
| 328 | free_fdset(new_fdt); | ||
| 329 | kfree(new_fdt); | ||
| 330 | } | ||
| 331 | 322 | ||
| 332 | new_fdt = alloc_fdtable(open_files - 1); | 323 | new_fdt = alloc_fdtable(open_files - 1); |
| 333 | if (!new_fdt) { | 324 | if (!new_fdt) { |
| @@ -337,9 +328,7 @@ struct files_struct *dup_fd(struct files_struct *oldf, int *errorp) | |||
| 337 | 328 | ||
| 338 | /* beyond sysctl_nr_open; nothing to do */ | 329 | /* beyond sysctl_nr_open; nothing to do */ |
| 339 | if (unlikely(new_fdt->max_fds < open_files)) { | 330 | if (unlikely(new_fdt->max_fds < open_files)) { |
| 340 | free_fdarr(new_fdt); | 331 | __free_fdtable(new_fdt); |
| 341 | free_fdset(new_fdt); | ||
| 342 | kfree(new_fdt); | ||
| 343 | *errorp = -EMFILE; | 332 | *errorp = -EMFILE; |
| 344 | goto out_release; | 333 | goto out_release; |
| 345 | } | 334 | } |
diff --git a/fs/file_table.c b/fs/file_table.c index 5c7d10ead4ad..edecd36fed9b 100644 --- a/fs/file_table.c +++ b/fs/file_table.c | |||
| @@ -289,11 +289,20 @@ struct file *fget(unsigned int fd) | |||
| 289 | EXPORT_SYMBOL(fget); | 289 | EXPORT_SYMBOL(fget); |
| 290 | 290 | ||
| 291 | /* | 291 | /* |
| 292 | * Lightweight file lookup - no refcnt increment if fd table isn't shared. | 292 | * Lightweight file lookup - no refcnt increment if fd table isn't shared. |
| 293 | * You can use this only if it is guranteed that the current task already | 293 | * |
| 294 | * holds a refcnt to that file. That check has to be done at fget() only | 294 | * You can use this instead of fget if you satisfy all of the following |
| 295 | * and a flag is returned to be passed to the corresponding fput_light(). | 295 | * conditions: |
| 296 | * There must not be a cloning between an fget_light/fput_light pair. | 296 | * 1) You must call fput_light before exiting the syscall and returning control |
| 297 | * to userspace (i.e. you cannot remember the returned struct file * after | ||
| 298 | * returning to userspace). | ||
| 299 | * 2) You must not call filp_close on the returned struct file * in between | ||
| 300 | * calls to fget_light and fput_light. | ||
| 301 | * 3) You must not clone the current task in between the calls to fget_light | ||
| 302 | * and fput_light. | ||
| 303 | * | ||
| 304 | * The fput_needed flag returned by fget_light should be passed to the | ||
| 305 | * corresponding fput_light. | ||
| 297 | */ | 306 | */ |
| 298 | struct file *fget_light(unsigned int fd, int *fput_needed) | 307 | struct file *fget_light(unsigned int fd, int *fput_needed) |
| 299 | { | 308 | { |
diff --git a/fs/freevxfs/vxfs_extern.h b/fs/freevxfs/vxfs_extern.h index 50ab5eecb99b..881aa3d217f0 100644 --- a/fs/freevxfs/vxfs_extern.h +++ b/fs/freevxfs/vxfs_extern.h | |||
| @@ -63,7 +63,7 @@ extern void vxfs_put_fake_inode(struct inode *); | |||
| 63 | extern struct vxfs_inode_info * vxfs_blkiget(struct super_block *, u_long, ino_t); | 63 | extern struct vxfs_inode_info * vxfs_blkiget(struct super_block *, u_long, ino_t); |
| 64 | extern struct vxfs_inode_info * vxfs_stiget(struct super_block *, ino_t); | 64 | extern struct vxfs_inode_info * vxfs_stiget(struct super_block *, ino_t); |
| 65 | extern struct inode * vxfs_iget(struct super_block *, ino_t); | 65 | extern struct inode * vxfs_iget(struct super_block *, ino_t); |
| 66 | extern void vxfs_clear_inode(struct inode *); | 66 | extern void vxfs_evict_inode(struct inode *); |
| 67 | 67 | ||
| 68 | /* vxfs_lookup.c */ | 68 | /* vxfs_lookup.c */ |
| 69 | extern const struct inode_operations vxfs_dir_inode_ops; | 69 | extern const struct inode_operations vxfs_dir_inode_ops; |
diff --git a/fs/freevxfs/vxfs_inode.c b/fs/freevxfs/vxfs_inode.c index 03a6ea5e99f7..79d1b4ea13e7 100644 --- a/fs/freevxfs/vxfs_inode.c +++ b/fs/freevxfs/vxfs_inode.c | |||
| @@ -337,15 +337,17 @@ vxfs_iget(struct super_block *sbp, ino_t ino) | |||
| 337 | } | 337 | } |
| 338 | 338 | ||
| 339 | /** | 339 | /** |
| 340 | * vxfs_clear_inode - remove inode from main memory | 340 | * vxfs_evict_inode - remove inode from main memory |
| 341 | * @ip: inode to discard. | 341 | * @ip: inode to discard. |
| 342 | * | 342 | * |
| 343 | * Description: | 343 | * Description: |
| 344 | * vxfs_clear_inode() is called on the final iput and frees the private | 344 | * vxfs_evict_inode() is called on the final iput and frees the private |
| 345 | * inode area. | 345 | * inode area. |
| 346 | */ | 346 | */ |
| 347 | void | 347 | void |
| 348 | vxfs_clear_inode(struct inode *ip) | 348 | vxfs_evict_inode(struct inode *ip) |
| 349 | { | 349 | { |
| 350 | truncate_inode_pages(&ip->i_data, 0); | ||
| 351 | end_writeback(ip); | ||
| 350 | kmem_cache_free(vxfs_inode_cachep, ip->i_private); | 352 | kmem_cache_free(vxfs_inode_cachep, ip->i_private); |
| 351 | } | 353 | } |
diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c index 5132c99b1ca2..dc0c041e85cb 100644 --- a/fs/freevxfs/vxfs_super.c +++ b/fs/freevxfs/vxfs_super.c | |||
| @@ -61,7 +61,7 @@ static int vxfs_statfs(struct dentry *, struct kstatfs *); | |||
| 61 | static int vxfs_remount(struct super_block *, int *, char *); | 61 | static int vxfs_remount(struct super_block *, int *, char *); |
| 62 | 62 | ||
| 63 | static const struct super_operations vxfs_super_ops = { | 63 | static const struct super_operations vxfs_super_ops = { |
| 64 | .clear_inode = vxfs_clear_inode, | 64 | .evict_inode = vxfs_evict_inode, |
| 65 | .put_super = vxfs_put_super, | 65 | .put_super = vxfs_put_super, |
| 66 | .statfs = vxfs_statfs, | 66 | .statfs = vxfs_statfs, |
| 67 | .remount_fs = vxfs_remount, | 67 | .remount_fs = vxfs_remount, |
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c index 30ac305e8293..7d9d06ba184b 100644 --- a/fs/fs-writeback.c +++ b/fs/fs-writeback.c | |||
| @@ -26,15 +26,9 @@ | |||
| 26 | #include <linux/blkdev.h> | 26 | #include <linux/blkdev.h> |
| 27 | #include <linux/backing-dev.h> | 27 | #include <linux/backing-dev.h> |
| 28 | #include <linux/buffer_head.h> | 28 | #include <linux/buffer_head.h> |
| 29 | #include <linux/tracepoint.h> | ||
| 29 | #include "internal.h" | 30 | #include "internal.h" |
| 30 | 31 | ||
| 31 | #define inode_to_bdi(inode) ((inode)->i_mapping->backing_dev_info) | ||
| 32 | |||
| 33 | /* | ||
| 34 | * We don't actually have pdflush, but this one is exported though /proc... | ||
| 35 | */ | ||
| 36 | int nr_pdflush_threads; | ||
| 37 | |||
| 38 | /* | 32 | /* |
| 39 | * Passed into wb_writeback(), essentially a subset of writeback_control | 33 | * Passed into wb_writeback(), essentially a subset of writeback_control |
| 40 | */ | 34 | */ |
| @@ -50,6 +44,21 @@ struct wb_writeback_work { | |||
| 50 | struct completion *done; /* set if the caller waits */ | 44 | struct completion *done; /* set if the caller waits */ |
| 51 | }; | 45 | }; |
| 52 | 46 | ||
| 47 | /* | ||
| 48 | * Include the creation of the trace points after defining the | ||
| 49 | * wb_writeback_work structure so that the definition remains local to this | ||
| 50 | * file. | ||
| 51 | */ | ||
| 52 | #define CREATE_TRACE_POINTS | ||
| 53 | #include <trace/events/writeback.h> | ||
| 54 | |||
| 55 | #define inode_to_bdi(inode) ((inode)->i_mapping->backing_dev_info) | ||
| 56 | |||
| 57 | /* | ||
| 58 | * We don't actually have pdflush, but this one is exported though /proc... | ||
| 59 | */ | ||
| 60 | int nr_pdflush_threads; | ||
| 61 | |||
| 53 | /** | 62 | /** |
| 54 | * writeback_in_progress - determine whether there is writeback in progress | 63 | * writeback_in_progress - determine whether there is writeback in progress |
| 55 | * @bdi: the device's backing_dev_info structure. | 64 | * @bdi: the device's backing_dev_info structure. |
| @@ -59,28 +68,27 @@ struct wb_writeback_work { | |||
| 59 | */ | 68 | */ |
| 60 | int writeback_in_progress(struct backing_dev_info *bdi) | 69 | int writeback_in_progress(struct backing_dev_info *bdi) |
| 61 | { | 70 | { |
| 62 | return !list_empty(&bdi->work_list); | 71 | return test_bit(BDI_writeback_running, &bdi->state); |
| 63 | } | 72 | } |
| 64 | 73 | ||
| 65 | static void bdi_queue_work(struct backing_dev_info *bdi, | 74 | static void bdi_queue_work(struct backing_dev_info *bdi, |
| 66 | struct wb_writeback_work *work) | 75 | struct wb_writeback_work *work) |
| 67 | { | 76 | { |
| 68 | spin_lock(&bdi->wb_lock); | 77 | trace_writeback_queue(bdi, work); |
| 69 | list_add_tail(&work->list, &bdi->work_list); | ||
| 70 | spin_unlock(&bdi->wb_lock); | ||
| 71 | 78 | ||
| 72 | /* | 79 | spin_lock_bh(&bdi->wb_lock); |
| 73 | * If the default thread isn't there, make sure we add it. When | 80 | list_add_tail(&work->list, &bdi->work_list); |
| 74 | * it gets created and wakes up, we'll run this work. | 81 | if (bdi->wb.task) { |
| 75 | */ | 82 | wake_up_process(bdi->wb.task); |
| 76 | if (unlikely(list_empty_careful(&bdi->wb_list))) | 83 | } else { |
| 84 | /* | ||
| 85 | * The bdi thread isn't there, wake up the forker thread which | ||
| 86 | * will create and run it. | ||
| 87 | */ | ||
| 88 | trace_writeback_nothread(bdi, work); | ||
| 77 | wake_up_process(default_backing_dev_info.wb.task); | 89 | wake_up_process(default_backing_dev_info.wb.task); |
| 78 | else { | ||
| 79 | struct bdi_writeback *wb = &bdi->wb; | ||
| 80 | |||
| 81 | if (wb->task) | ||
| 82 | wake_up_process(wb->task); | ||
| 83 | } | 90 | } |
| 91 | spin_unlock_bh(&bdi->wb_lock); | ||
| 84 | } | 92 | } |
| 85 | 93 | ||
| 86 | static void | 94 | static void |
| @@ -95,8 +103,10 @@ __bdi_start_writeback(struct backing_dev_info *bdi, long nr_pages, | |||
| 95 | */ | 103 | */ |
| 96 | work = kzalloc(sizeof(*work), GFP_ATOMIC); | 104 | work = kzalloc(sizeof(*work), GFP_ATOMIC); |
| 97 | if (!work) { | 105 | if (!work) { |
| 98 | if (bdi->wb.task) | 106 | if (bdi->wb.task) { |
| 107 | trace_writeback_nowork(bdi); | ||
| 99 | wake_up_process(bdi->wb.task); | 108 | wake_up_process(bdi->wb.task); |
| 109 | } | ||
| 100 | return; | 110 | return; |
| 101 | } | 111 | } |
| 102 | 112 | ||
| @@ -239,10 +249,18 @@ static void move_expired_inodes(struct list_head *delaying_queue, | |||
| 239 | 249 | ||
| 240 | /* | 250 | /* |
| 241 | * Queue all expired dirty inodes for io, eldest first. | 251 | * Queue all expired dirty inodes for io, eldest first. |
| 252 | * Before | ||
| 253 | * newly dirtied b_dirty b_io b_more_io | ||
| 254 | * =============> gf edc BA | ||
| 255 | * After | ||
| 256 | * newly dirtied b_dirty b_io b_more_io | ||
| 257 | * =============> g fBAedc | ||
| 258 | * | | ||
| 259 | * +--> dequeue for IO | ||
| 242 | */ | 260 | */ |
| 243 | static void queue_io(struct bdi_writeback *wb, unsigned long *older_than_this) | 261 | static void queue_io(struct bdi_writeback *wb, unsigned long *older_than_this) |
| 244 | { | 262 | { |
| 245 | list_splice_init(&wb->b_more_io, wb->b_io.prev); | 263 | list_splice_init(&wb->b_more_io, &wb->b_io); |
| 246 | move_expired_inodes(&wb->b_dirty, &wb->b_io, older_than_this); | 264 | move_expired_inodes(&wb->b_dirty, &wb->b_io, older_than_this); |
| 247 | } | 265 | } |
| 248 | 266 | ||
| @@ -352,63 +370,36 @@ writeback_single_inode(struct inode *inode, struct writeback_control *wbc) | |||
| 352 | 370 | ||
| 353 | spin_lock(&inode_lock); | 371 | spin_lock(&inode_lock); |
| 354 | inode->i_state &= ~I_SYNC; | 372 | inode->i_state &= ~I_SYNC; |
| 355 | if (!(inode->i_state & (I_FREEING | I_CLEAR))) { | 373 | if (!(inode->i_state & I_FREEING)) { |
| 356 | if ((inode->i_state & I_DIRTY_PAGES) && wbc->for_kupdate) { | 374 | if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) { |
| 357 | /* | ||
| 358 | * More pages get dirtied by a fast dirtier. | ||
| 359 | */ | ||
| 360 | goto select_queue; | ||
| 361 | } else if (inode->i_state & I_DIRTY) { | ||
| 362 | /* | ||
| 363 | * At least XFS will redirty the inode during the | ||
| 364 | * writeback (delalloc) and on io completion (isize). | ||
| 365 | */ | ||
| 366 | redirty_tail(inode); | ||
| 367 | } else if (mapping_tagged(mapping, PAGECACHE_TAG_DIRTY)) { | ||
| 368 | /* | 375 | /* |
| 369 | * We didn't write back all the pages. nfs_writepages() | 376 | * We didn't write back all the pages. nfs_writepages() |
| 370 | * sometimes bales out without doing anything. Redirty | 377 | * sometimes bales out without doing anything. |
| 371 | * the inode; Move it from b_io onto b_more_io/b_dirty. | ||
| 372 | */ | ||
| 373 | /* | ||
| 374 | * akpm: if the caller was the kupdate function we put | ||
| 375 | * this inode at the head of b_dirty so it gets first | ||
| 376 | * consideration. Otherwise, move it to the tail, for | ||
| 377 | * the reasons described there. I'm not really sure | ||
| 378 | * how much sense this makes. Presumably I had a good | ||
| 379 | * reasons for doing it this way, and I'd rather not | ||
| 380 | * muck with it at present. | ||
| 381 | */ | 378 | */ |
| 382 | if (wbc->for_kupdate) { | 379 | inode->i_state |= I_DIRTY_PAGES; |
| 380 | if (wbc->nr_to_write <= 0) { | ||
| 383 | /* | 381 | /* |
| 384 | * For the kupdate function we move the inode | 382 | * slice used up: queue for next turn |
| 385 | * to b_more_io so it will get more writeout as | ||
| 386 | * soon as the queue becomes uncongested. | ||
| 387 | */ | 383 | */ |
| 388 | inode->i_state |= I_DIRTY_PAGES; | 384 | requeue_io(inode); |
| 389 | select_queue: | ||
| 390 | if (wbc->nr_to_write <= 0) { | ||
| 391 | /* | ||
| 392 | * slice used up: queue for next turn | ||
| 393 | */ | ||
| 394 | requeue_io(inode); | ||
| 395 | } else { | ||
| 396 | /* | ||
| 397 | * somehow blocked: retry later | ||
| 398 | */ | ||
| 399 | redirty_tail(inode); | ||
| 400 | } | ||
| 401 | } else { | 385 | } else { |
| 402 | /* | 386 | /* |
| 403 | * Otherwise fully redirty the inode so that | 387 | * Writeback blocked by something other than |
| 404 | * other inodes on this superblock will get some | 388 | * congestion. Delay the inode for some time to |
| 405 | * writeout. Otherwise heavy writing to one | 389 | * avoid spinning on the CPU (100% iowait) |
| 406 | * file would indefinitely suspend writeout of | 390 | * retrying writeback of the dirty page/inode |
| 407 | * all the other files. | 391 | * that cannot be performed immediately. |
| 408 | */ | 392 | */ |
| 409 | inode->i_state |= I_DIRTY_PAGES; | ||
| 410 | redirty_tail(inode); | 393 | redirty_tail(inode); |
| 411 | } | 394 | } |
| 395 | } else if (inode->i_state & I_DIRTY) { | ||
| 396 | /* | ||
| 397 | * Filesystems can dirty the inode during writeback | ||
| 398 | * operations, such as delayed allocation during | ||
| 399 | * submission or metadata updates after data IO | ||
| 400 | * completion. | ||
| 401 | */ | ||
| 402 | redirty_tail(inode); | ||
| 412 | } else if (atomic_read(&inode->i_count)) { | 403 | } else if (atomic_read(&inode->i_count)) { |
| 413 | /* | 404 | /* |
| 414 | * The inode is clean, inuse | 405 | * The inode is clean, inuse |
| @@ -499,7 +490,7 @@ static int writeback_sb_inodes(struct super_block *sb, struct bdi_writeback *wb, | |||
| 499 | if (inode_dirtied_after(inode, wbc->wb_start)) | 490 | if (inode_dirtied_after(inode, wbc->wb_start)) |
| 500 | return 1; | 491 | return 1; |
| 501 | 492 | ||
| 502 | BUG_ON(inode->i_state & (I_FREEING | I_CLEAR)); | 493 | BUG_ON(inode->i_state & I_FREEING); |
| 503 | __iget(inode); | 494 | __iget(inode); |
| 504 | pages_skipped = wbc->pages_skipped; | 495 | pages_skipped = wbc->pages_skipped; |
| 505 | writeback_single_inode(inode, wbc); | 496 | writeback_single_inode(inode, wbc); |
| @@ -580,7 +571,7 @@ static inline bool over_bground_thresh(void) | |||
| 580 | { | 571 | { |
| 581 | unsigned long background_thresh, dirty_thresh; | 572 | unsigned long background_thresh, dirty_thresh; |
| 582 | 573 | ||
| 583 | get_dirty_limits(&background_thresh, &dirty_thresh, NULL, NULL); | 574 | global_dirty_limits(&background_thresh, &dirty_thresh); |
| 584 | 575 | ||
| 585 | return (global_page_state(NR_FILE_DIRTY) + | 576 | return (global_page_state(NR_FILE_DIRTY) + |
| 586 | global_page_state(NR_UNSTABLE_NFS) >= background_thresh); | 577 | global_page_state(NR_UNSTABLE_NFS) >= background_thresh); |
| @@ -643,10 +634,14 @@ static long wb_writeback(struct bdi_writeback *wb, | |||
| 643 | wbc.more_io = 0; | 634 | wbc.more_io = 0; |
| 644 | wbc.nr_to_write = MAX_WRITEBACK_PAGES; | 635 | wbc.nr_to_write = MAX_WRITEBACK_PAGES; |
| 645 | wbc.pages_skipped = 0; | 636 | wbc.pages_skipped = 0; |
| 637 | |||
| 638 | trace_wbc_writeback_start(&wbc, wb->bdi); | ||
| 646 | if (work->sb) | 639 | if (work->sb) |
| 647 | __writeback_inodes_sb(work->sb, wb, &wbc); | 640 | __writeback_inodes_sb(work->sb, wb, &wbc); |
| 648 | else | 641 | else |
| 649 | writeback_inodes_wb(wb, &wbc); | 642 | writeback_inodes_wb(wb, &wbc); |
| 643 | trace_wbc_writeback_written(&wbc, wb->bdi); | ||
| 644 | |||
| 650 | work->nr_pages -= MAX_WRITEBACK_PAGES - wbc.nr_to_write; | 645 | work->nr_pages -= MAX_WRITEBACK_PAGES - wbc.nr_to_write; |
| 651 | wrote += MAX_WRITEBACK_PAGES - wbc.nr_to_write; | 646 | wrote += MAX_WRITEBACK_PAGES - wbc.nr_to_write; |
| 652 | 647 | ||
| @@ -674,6 +669,7 @@ static long wb_writeback(struct bdi_writeback *wb, | |||
| 674 | if (!list_empty(&wb->b_more_io)) { | 669 | if (!list_empty(&wb->b_more_io)) { |
| 675 | inode = list_entry(wb->b_more_io.prev, | 670 | inode = list_entry(wb->b_more_io.prev, |
| 676 | struct inode, i_list); | 671 | struct inode, i_list); |
| 672 | trace_wbc_writeback_wait(&wbc, wb->bdi); | ||
| 677 | inode_wait_for_writeback(inode); | 673 | inode_wait_for_writeback(inode); |
| 678 | } | 674 | } |
| 679 | spin_unlock(&inode_lock); | 675 | spin_unlock(&inode_lock); |
| @@ -686,17 +682,17 @@ static long wb_writeback(struct bdi_writeback *wb, | |||
| 686 | * Return the next wb_writeback_work struct that hasn't been processed yet. | 682 | * Return the next wb_writeback_work struct that hasn't been processed yet. |
| 687 | */ | 683 | */ |
| 688 | static struct wb_writeback_work * | 684 | static struct wb_writeback_work * |
| 689 | get_next_work_item(struct backing_dev_info *bdi, struct bdi_writeback *wb) | 685 | get_next_work_item(struct backing_dev_info *bdi) |
| 690 | { | 686 | { |
| 691 | struct wb_writeback_work *work = NULL; | 687 | struct wb_writeback_work *work = NULL; |
| 692 | 688 | ||
| 693 | spin_lock(&bdi->wb_lock); | 689 | spin_lock_bh(&bdi->wb_lock); |
| 694 | if (!list_empty(&bdi->work_list)) { | 690 | if (!list_empty(&bdi->work_list)) { |
| 695 | work = list_entry(bdi->work_list.next, | 691 | work = list_entry(bdi->work_list.next, |
| 696 | struct wb_writeback_work, list); | 692 | struct wb_writeback_work, list); |
| 697 | list_del_init(&work->list); | 693 | list_del_init(&work->list); |
| 698 | } | 694 | } |
| 699 | spin_unlock(&bdi->wb_lock); | 695 | spin_unlock_bh(&bdi->wb_lock); |
| 700 | return work; | 696 | return work; |
| 701 | } | 697 | } |
| 702 | 698 | ||
| @@ -744,7 +740,8 @@ long wb_do_writeback(struct bdi_writeback *wb, int force_wait) | |||
| 744 | struct wb_writeback_work *work; | 740 | struct wb_writeback_work *work; |
| 745 | long wrote = 0; | 741 | long wrote = 0; |
| 746 | 742 | ||
| 747 | while ((work = get_next_work_item(bdi, wb)) != NULL) { | 743 | set_bit(BDI_writeback_running, &wb->bdi->state); |
| 744 | while ((work = get_next_work_item(bdi)) != NULL) { | ||
| 748 | /* | 745 | /* |
| 749 | * Override sync mode, in case we must wait for completion | 746 | * Override sync mode, in case we must wait for completion |
| 750 | * because this thread is exiting now. | 747 | * because this thread is exiting now. |
| @@ -752,6 +749,8 @@ long wb_do_writeback(struct bdi_writeback *wb, int force_wait) | |||
| 752 | if (force_wait) | 749 | if (force_wait) |
| 753 | work->sync_mode = WB_SYNC_ALL; | 750 | work->sync_mode = WB_SYNC_ALL; |
| 754 | 751 | ||
| 752 | trace_writeback_exec(bdi, work); | ||
| 753 | |||
| 755 | wrote += wb_writeback(wb, work); | 754 | wrote += wb_writeback(wb, work); |
| 756 | 755 | ||
| 757 | /* | 756 | /* |
| @@ -768,6 +767,7 @@ long wb_do_writeback(struct bdi_writeback *wb, int force_wait) | |||
| 768 | * Check for periodic writeback, kupdated() style | 767 | * Check for periodic writeback, kupdated() style |
| 769 | */ | 768 | */ |
| 770 | wrote += wb_check_old_data_flush(wb); | 769 | wrote += wb_check_old_data_flush(wb); |
| 770 | clear_bit(BDI_writeback_running, &wb->bdi->state); | ||
| 771 | 771 | ||
| 772 | return wrote; | 772 | return wrote; |
| 773 | } | 773 | } |
| @@ -776,47 +776,66 @@ long wb_do_writeback(struct bdi_writeback *wb, int force_wait) | |||
| 776 | * Handle writeback of dirty data for the device backed by this bdi. Also | 776 | * Handle writeback of dirty data for the device backed by this bdi. Also |
| 777 | * wakes up periodically and does kupdated style flushing. | 777 | * wakes up periodically and does kupdated style flushing. |
| 778 | */ | 778 | */ |
| 779 | int bdi_writeback_task(struct bdi_writeback *wb) | 779 | int bdi_writeback_thread(void *data) |
| 780 | { | 780 | { |
| 781 | unsigned long last_active = jiffies; | 781 | struct bdi_writeback *wb = data; |
| 782 | unsigned long wait_jiffies = -1UL; | 782 | struct backing_dev_info *bdi = wb->bdi; |
| 783 | long pages_written; | 783 | long pages_written; |
| 784 | 784 | ||
| 785 | current->flags |= PF_FLUSHER | PF_SWAPWRITE; | ||
| 786 | set_freezable(); | ||
| 787 | wb->last_active = jiffies; | ||
| 788 | |||
| 789 | /* | ||
| 790 | * Our parent may run at a different priority, just set us to normal | ||
| 791 | */ | ||
| 792 | set_user_nice(current, 0); | ||
| 793 | |||
| 794 | trace_writeback_thread_start(bdi); | ||
| 795 | |||
| 785 | while (!kthread_should_stop()) { | 796 | while (!kthread_should_stop()) { |
| 797 | /* | ||
| 798 | * Remove own delayed wake-up timer, since we are already awake | ||
| 799 | * and we'll take care of the preriodic write-back. | ||
| 800 | */ | ||
| 801 | del_timer(&wb->wakeup_timer); | ||
| 802 | |||
| 786 | pages_written = wb_do_writeback(wb, 0); | 803 | pages_written = wb_do_writeback(wb, 0); |
| 787 | 804 | ||
| 805 | trace_writeback_pages_written(pages_written); | ||
| 806 | |||
| 788 | if (pages_written) | 807 | if (pages_written) |
| 789 | last_active = jiffies; | 808 | wb->last_active = jiffies; |
| 790 | else if (wait_jiffies != -1UL) { | ||
| 791 | unsigned long max_idle; | ||
| 792 | 809 | ||
| 793 | /* | 810 | set_current_state(TASK_INTERRUPTIBLE); |
| 794 | * Longest period of inactivity that we tolerate. If we | 811 | if (!list_empty(&bdi->work_list)) { |
| 795 | * see dirty data again later, the task will get | 812 | __set_current_state(TASK_RUNNING); |
| 796 | * recreated automatically. | 813 | continue; |
| 797 | */ | ||
| 798 | max_idle = max(5UL * 60 * HZ, wait_jiffies); | ||
| 799 | if (time_after(jiffies, max_idle + last_active)) | ||
| 800 | break; | ||
| 801 | } | 814 | } |
| 802 | 815 | ||
| 803 | if (dirty_writeback_interval) { | 816 | if (wb_has_dirty_io(wb) && dirty_writeback_interval) |
| 804 | wait_jiffies = msecs_to_jiffies(dirty_writeback_interval * 10); | 817 | schedule_timeout(msecs_to_jiffies(dirty_writeback_interval * 10)); |
| 805 | schedule_timeout_interruptible(wait_jiffies); | 818 | else { |
| 806 | } else { | 819 | /* |
| 807 | set_current_state(TASK_INTERRUPTIBLE); | 820 | * We have nothing to do, so can go sleep without any |
| 808 | if (list_empty_careful(&wb->bdi->work_list) && | 821 | * timeout and save power. When a work is queued or |
| 809 | !kthread_should_stop()) | 822 | * something is made dirty - we will be woken up. |
| 810 | schedule(); | 823 | */ |
| 811 | __set_current_state(TASK_RUNNING); | 824 | schedule(); |
| 812 | } | 825 | } |
| 813 | 826 | ||
| 814 | try_to_freeze(); | 827 | try_to_freeze(); |
| 815 | } | 828 | } |
| 816 | 829 | ||
| 830 | /* Flush any work that raced with us exiting */ | ||
| 831 | if (!list_empty(&bdi->work_list)) | ||
| 832 | wb_do_writeback(wb, 1); | ||
| 833 | |||
| 834 | trace_writeback_thread_stop(bdi); | ||
| 817 | return 0; | 835 | return 0; |
| 818 | } | 836 | } |
| 819 | 837 | ||
| 838 | |||
| 820 | /* | 839 | /* |
| 821 | * Start writeback of `nr_pages' pages. If `nr_pages' is zero, write back | 840 | * Start writeback of `nr_pages' pages. If `nr_pages' is zero, write back |
| 822 | * the whole world. | 841 | * the whole world. |
| @@ -891,6 +910,8 @@ static noinline void block_dump___mark_inode_dirty(struct inode *inode) | |||
| 891 | void __mark_inode_dirty(struct inode *inode, int flags) | 910 | void __mark_inode_dirty(struct inode *inode, int flags) |
| 892 | { | 911 | { |
| 893 | struct super_block *sb = inode->i_sb; | 912 | struct super_block *sb = inode->i_sb; |
| 913 | struct backing_dev_info *bdi = NULL; | ||
| 914 | bool wakeup_bdi = false; | ||
| 894 | 915 | ||
| 895 | /* | 916 | /* |
| 896 | * Don't do this for I_DIRTY_PAGES - that doesn't actually | 917 | * Don't do this for I_DIRTY_PAGES - that doesn't actually |
| @@ -936,7 +957,7 @@ void __mark_inode_dirty(struct inode *inode, int flags) | |||
| 936 | if (hlist_unhashed(&inode->i_hash)) | 957 | if (hlist_unhashed(&inode->i_hash)) |
| 937 | goto out; | 958 | goto out; |
| 938 | } | 959 | } |
| 939 | if (inode->i_state & (I_FREEING|I_CLEAR)) | 960 | if (inode->i_state & I_FREEING) |
| 940 | goto out; | 961 | goto out; |
| 941 | 962 | ||
| 942 | /* | 963 | /* |
| @@ -944,22 +965,31 @@ void __mark_inode_dirty(struct inode *inode, int flags) | |||
| 944 | * reposition it (that would break b_dirty time-ordering). | 965 | * reposition it (that would break b_dirty time-ordering). |
| 945 | */ | 966 | */ |
| 946 | if (!was_dirty) { | 967 | if (!was_dirty) { |
| 947 | struct bdi_writeback *wb = &inode_to_bdi(inode)->wb; | 968 | bdi = inode_to_bdi(inode); |
| 948 | struct backing_dev_info *bdi = wb->bdi; | 969 | |
| 949 | 970 | if (bdi_cap_writeback_dirty(bdi)) { | |
| 950 | if (bdi_cap_writeback_dirty(bdi) && | 971 | WARN(!test_bit(BDI_registered, &bdi->state), |
| 951 | !test_bit(BDI_registered, &bdi->state)) { | 972 | "bdi-%s not registered\n", bdi->name); |
| 952 | WARN_ON(1); | 973 | |
| 953 | printk(KERN_ERR "bdi-%s not registered\n", | 974 | /* |
| 954 | bdi->name); | 975 | * If this is the first dirty inode for this |
| 976 | * bdi, we have to wake-up the corresponding | ||
| 977 | * bdi thread to make sure background | ||
| 978 | * write-back happens later. | ||
| 979 | */ | ||
| 980 | if (!wb_has_dirty_io(&bdi->wb)) | ||
| 981 | wakeup_bdi = true; | ||
| 955 | } | 982 | } |
| 956 | 983 | ||
| 957 | inode->dirtied_when = jiffies; | 984 | inode->dirtied_when = jiffies; |
| 958 | list_move(&inode->i_list, &wb->b_dirty); | 985 | list_move(&inode->i_list, &bdi->wb.b_dirty); |
| 959 | } | 986 | } |
| 960 | } | 987 | } |
| 961 | out: | 988 | out: |
| 962 | spin_unlock(&inode_lock); | 989 | spin_unlock(&inode_lock); |
| 990 | |||
| 991 | if (wakeup_bdi) | ||
| 992 | bdi_wakeup_thread_delayed(bdi); | ||
| 963 | } | 993 | } |
| 964 | EXPORT_SYMBOL(__mark_inode_dirty); | 994 | EXPORT_SYMBOL(__mark_inode_dirty); |
| 965 | 995 | ||
| @@ -1002,7 +1032,7 @@ static void wait_sb_inodes(struct super_block *sb) | |||
| 1002 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { | 1032 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { |
| 1003 | struct address_space *mapping; | 1033 | struct address_space *mapping; |
| 1004 | 1034 | ||
| 1005 | if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE|I_NEW)) | 1035 | if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) |
| 1006 | continue; | 1036 | continue; |
| 1007 | mapping = inode->i_mapping; | 1037 | mapping = inode->i_mapping; |
| 1008 | if (mapping->nrpages == 0) | 1038 | if (mapping->nrpages == 0) |
diff --git a/fs/fs_struct.c b/fs/fs_struct.c index eee059052db5..1ee40eb9a2c0 100644 --- a/fs/fs_struct.c +++ b/fs/fs_struct.c | |||
| @@ -106,12 +106,7 @@ struct fs_struct *copy_fs_struct(struct fs_struct *old) | |||
| 106 | fs->in_exec = 0; | 106 | fs->in_exec = 0; |
| 107 | rwlock_init(&fs->lock); | 107 | rwlock_init(&fs->lock); |
| 108 | fs->umask = old->umask; | 108 | fs->umask = old->umask; |
| 109 | read_lock(&old->lock); | 109 | get_fs_root_and_pwd(old, &fs->root, &fs->pwd); |
| 110 | fs->root = old->root; | ||
| 111 | path_get(&old->root); | ||
| 112 | fs->pwd = old->pwd; | ||
| 113 | path_get(&old->pwd); | ||
| 114 | read_unlock(&old->lock); | ||
| 115 | } | 110 | } |
| 116 | return fs; | 111 | return fs; |
| 117 | } | 112 | } |
diff --git a/fs/fscache/internal.h b/fs/fscache/internal.h index 6a026441c5a6..f6aad48d38a8 100644 --- a/fs/fscache/internal.h +++ b/fs/fscache/internal.h | |||
| @@ -321,17 +321,11 @@ void fscache_put_context(struct fscache_cookie *cookie, void *context) | |||
| 321 | #define dbgprintk(FMT, ...) \ | 321 | #define dbgprintk(FMT, ...) \ |
| 322 | printk(KERN_DEBUG "[%-6.6s] "FMT"\n", current->comm, ##__VA_ARGS__) | 322 | printk(KERN_DEBUG "[%-6.6s] "FMT"\n", current->comm, ##__VA_ARGS__) |
| 323 | 323 | ||
| 324 | /* make sure we maintain the format strings, even when debugging is disabled */ | ||
| 325 | static inline __attribute__((format(printf, 1, 2))) | ||
| 326 | void _dbprintk(const char *fmt, ...) | ||
| 327 | { | ||
| 328 | } | ||
| 329 | |||
| 330 | #define kenter(FMT, ...) dbgprintk("==> %s("FMT")", __func__, ##__VA_ARGS__) | 324 | #define kenter(FMT, ...) dbgprintk("==> %s("FMT")", __func__, ##__VA_ARGS__) |
| 331 | #define kleave(FMT, ...) dbgprintk("<== %s()"FMT"", __func__, ##__VA_ARGS__) | 325 | #define kleave(FMT, ...) dbgprintk("<== %s()"FMT"", __func__, ##__VA_ARGS__) |
| 332 | #define kdebug(FMT, ...) dbgprintk(FMT, ##__VA_ARGS__) | 326 | #define kdebug(FMT, ...) dbgprintk(FMT, ##__VA_ARGS__) |
| 333 | 327 | ||
| 334 | #define kjournal(FMT, ...) _dbprintk(FMT, ##__VA_ARGS__) | 328 | #define kjournal(FMT, ...) no_printk(FMT, ##__VA_ARGS__) |
| 335 | 329 | ||
| 336 | #ifdef __KDEBUG | 330 | #ifdef __KDEBUG |
| 337 | #define _enter(FMT, ...) kenter(FMT, ##__VA_ARGS__) | 331 | #define _enter(FMT, ...) kenter(FMT, ##__VA_ARGS__) |
| @@ -358,9 +352,9 @@ do { \ | |||
| 358 | } while (0) | 352 | } while (0) |
| 359 | 353 | ||
| 360 | #else | 354 | #else |
| 361 | #define _enter(FMT, ...) _dbprintk("==> %s("FMT")", __func__, ##__VA_ARGS__) | 355 | #define _enter(FMT, ...) no_printk("==> %s("FMT")", __func__, ##__VA_ARGS__) |
| 362 | #define _leave(FMT, ...) _dbprintk("<== %s()"FMT"", __func__, ##__VA_ARGS__) | 356 | #define _leave(FMT, ...) no_printk("<== %s()"FMT"", __func__, ##__VA_ARGS__) |
| 363 | #define _debug(FMT, ...) _dbprintk(FMT, ##__VA_ARGS__) | 357 | #define _debug(FMT, ...) no_printk(FMT, ##__VA_ARGS__) |
| 364 | #endif | 358 | #endif |
| 365 | 359 | ||
| 366 | /* | 360 | /* |
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 431be0795b6b..c9627c95482d 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
| @@ -1270,21 +1270,18 @@ static int fuse_do_setattr(struct dentry *entry, struct iattr *attr, | |||
| 1270 | if (!fuse_allow_task(fc, current)) | 1270 | if (!fuse_allow_task(fc, current)) |
| 1271 | return -EACCES; | 1271 | return -EACCES; |
| 1272 | 1272 | ||
| 1273 | if (fc->flags & FUSE_DEFAULT_PERMISSIONS) { | 1273 | if (!(fc->flags & FUSE_DEFAULT_PERMISSIONS)) |
| 1274 | err = inode_change_ok(inode, attr); | 1274 | attr->ia_valid |= ATTR_FORCE; |
| 1275 | if (err) | 1275 | |
| 1276 | return err; | 1276 | err = inode_change_ok(inode, attr); |
| 1277 | } | 1277 | if (err) |
| 1278 | return err; | ||
| 1278 | 1279 | ||
| 1279 | if ((attr->ia_valid & ATTR_OPEN) && fc->atomic_o_trunc) | 1280 | if ((attr->ia_valid & ATTR_OPEN) && fc->atomic_o_trunc) |
| 1280 | return 0; | 1281 | return 0; |
| 1281 | 1282 | ||
| 1282 | if (attr->ia_valid & ATTR_SIZE) { | 1283 | if (attr->ia_valid & ATTR_SIZE) |
| 1283 | err = inode_newsize_ok(inode, attr->ia_size); | ||
| 1284 | if (err) | ||
| 1285 | return err; | ||
| 1286 | is_truncate = true; | 1284 | is_truncate = true; |
| 1287 | } | ||
| 1288 | 1285 | ||
| 1289 | req = fuse_get_req(fc); | 1286 | req = fuse_get_req(fc); |
| 1290 | if (IS_ERR(req)) | 1287 | if (IS_ERR(req)) |
diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index ec14d19ce501..da9e6e11374c 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c | |||
| @@ -122,8 +122,10 @@ void fuse_send_forget(struct fuse_conn *fc, struct fuse_req *req, | |||
| 122 | fuse_request_send_noreply(fc, req); | 122 | fuse_request_send_noreply(fc, req); |
| 123 | } | 123 | } |
| 124 | 124 | ||
| 125 | static void fuse_clear_inode(struct inode *inode) | 125 | static void fuse_evict_inode(struct inode *inode) |
| 126 | { | 126 | { |
| 127 | truncate_inode_pages(&inode->i_data, 0); | ||
| 128 | end_writeback(inode); | ||
| 127 | if (inode->i_sb->s_flags & MS_ACTIVE) { | 129 | if (inode->i_sb->s_flags & MS_ACTIVE) { |
| 128 | struct fuse_conn *fc = get_fuse_conn(inode); | 130 | struct fuse_conn *fc = get_fuse_conn(inode); |
| 129 | struct fuse_inode *fi = get_fuse_inode(inode); | 131 | struct fuse_inode *fi = get_fuse_inode(inode); |
| @@ -736,7 +738,7 @@ static const struct export_operations fuse_export_operations = { | |||
| 736 | static const struct super_operations fuse_super_operations = { | 738 | static const struct super_operations fuse_super_operations = { |
| 737 | .alloc_inode = fuse_alloc_inode, | 739 | .alloc_inode = fuse_alloc_inode, |
| 738 | .destroy_inode = fuse_destroy_inode, | 740 | .destroy_inode = fuse_destroy_inode, |
| 739 | .clear_inode = fuse_clear_inode, | 741 | .evict_inode = fuse_evict_inode, |
| 740 | .drop_inode = generic_delete_inode, | 742 | .drop_inode = generic_delete_inode, |
| 741 | .remount_fs = fuse_remount_fs, | 743 | .remount_fs = fuse_remount_fs, |
| 742 | .put_super = fuse_put_super, | 744 | .put_super = fuse_put_super, |
diff --git a/fs/gfs2/aops.c b/fs/gfs2/aops.c index 5e96cbd8a454..194fe16d8418 100644 --- a/fs/gfs2/aops.c +++ b/fs/gfs2/aops.c | |||
| @@ -697,12 +697,12 @@ out: | |||
| 697 | page_cache_release(page); | 697 | page_cache_release(page); |
| 698 | 698 | ||
| 699 | /* | 699 | /* |
| 700 | * XXX(hch): the call below should probably be replaced with | 700 | * XXX(truncate): the call below should probably be replaced with |
| 701 | * a call to the gfs2-specific truncate blocks helper to actually | 701 | * a call to the gfs2-specific truncate blocks helper to actually |
| 702 | * release disk blocks.. | 702 | * release disk blocks.. |
| 703 | */ | 703 | */ |
| 704 | if (pos + len > ip->i_inode.i_size) | 704 | if (pos + len > ip->i_inode.i_size) |
| 705 | simple_setsize(&ip->i_inode, ip->i_inode.i_size); | 705 | truncate_setsize(&ip->i_inode, ip->i_inode.i_size); |
| 706 | out_endtrans: | 706 | out_endtrans: |
| 707 | gfs2_trans_end(sdp); | 707 | gfs2_trans_end(sdp); |
| 708 | out_trans_fail: | 708 | out_trans_fail: |
| @@ -1042,9 +1042,9 @@ static ssize_t gfs2_direct_IO(int rw, struct kiocb *iocb, | |||
| 1042 | if (rv != 1) | 1042 | if (rv != 1) |
| 1043 | goto out; /* dio not valid, fall back to buffered i/o */ | 1043 | goto out; /* dio not valid, fall back to buffered i/o */ |
| 1044 | 1044 | ||
| 1045 | rv = blockdev_direct_IO_no_locking(rw, iocb, inode, inode->i_sb->s_bdev, | 1045 | rv = __blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, |
| 1046 | iov, offset, nr_segs, | 1046 | offset, nr_segs, gfs2_get_block_direct, |
| 1047 | gfs2_get_block_direct, NULL); | 1047 | NULL, NULL, 0); |
| 1048 | out: | 1048 | out: |
| 1049 | gfs2_glock_dq_m(1, &gh); | 1049 | gfs2_glock_dq_m(1, &gh); |
| 1050 | gfs2_holder_uninit(&gh); | 1050 | gfs2_holder_uninit(&gh); |
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c index f03afd9c44bc..08140f185a37 100644 --- a/fs/gfs2/inode.c +++ b/fs/gfs2/inode.c | |||
| @@ -84,7 +84,7 @@ static int iget_skip_test(struct inode *inode, void *opaque) | |||
| 84 | struct gfs2_skip_data *data = opaque; | 84 | struct gfs2_skip_data *data = opaque; |
| 85 | 85 | ||
| 86 | if (ip->i_no_addr == data->no_addr) { | 86 | if (ip->i_no_addr == data->no_addr) { |
| 87 | if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)){ | 87 | if (inode->i_state & (I_FREEING|I_WILL_FREE)){ |
| 88 | data->skipped = 1; | 88 | data->skipped = 1; |
| 89 | return 0; | 89 | return 0; |
| 90 | } | 90 | } |
| @@ -991,18 +991,29 @@ fail: | |||
| 991 | 991 | ||
| 992 | static int __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr) | 992 | static int __gfs2_setattr_simple(struct gfs2_inode *ip, struct iattr *attr) |
| 993 | { | 993 | { |
| 994 | struct inode *inode = &ip->i_inode; | ||
| 994 | struct buffer_head *dibh; | 995 | struct buffer_head *dibh; |
| 995 | int error; | 996 | int error; |
| 996 | 997 | ||
| 997 | error = gfs2_meta_inode_buffer(ip, &dibh); | 998 | error = gfs2_meta_inode_buffer(ip, &dibh); |
| 998 | if (!error) { | 999 | if (error) |
| 999 | error = inode_setattr(&ip->i_inode, attr); | 1000 | return error; |
| 1000 | gfs2_assert_warn(GFS2_SB(&ip->i_inode), !error); | 1001 | |
| 1001 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | 1002 | if ((attr->ia_valid & ATTR_SIZE) && |
| 1002 | gfs2_dinode_out(ip, dibh->b_data); | 1003 | attr->ia_size != i_size_read(inode)) { |
| 1003 | brelse(dibh); | 1004 | error = vmtruncate(inode, attr->ia_size); |
| 1005 | if (error) | ||
| 1006 | return error; | ||
| 1004 | } | 1007 | } |
| 1005 | return error; | 1008 | |
| 1009 | setattr_copy(inode, attr); | ||
| 1010 | mark_inode_dirty(inode); | ||
| 1011 | |||
| 1012 | gfs2_assert_warn(GFS2_SB(inode), !error); | ||
| 1013 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | ||
| 1014 | gfs2_dinode_out(ip, dibh->b_data); | ||
| 1015 | brelse(dibh); | ||
| 1016 | return 0; | ||
| 1006 | } | 1017 | } |
| 1007 | 1018 | ||
| 1008 | /** | 1019 | /** |
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c index 6a857e24f947..cde1248a6225 100644 --- a/fs/gfs2/log.c +++ b/fs/gfs2/log.c | |||
| @@ -595,7 +595,7 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull) | |||
| 595 | if (test_bit(SDF_NOBARRIERS, &sdp->sd_flags)) | 595 | if (test_bit(SDF_NOBARRIERS, &sdp->sd_flags)) |
| 596 | goto skip_barrier; | 596 | goto skip_barrier; |
| 597 | get_bh(bh); | 597 | get_bh(bh); |
| 598 | submit_bh(WRITE_SYNC | (1 << BIO_RW_BARRIER) | (1 << BIO_RW_META), bh); | 598 | submit_bh(WRITE_BARRIER | REQ_META, bh); |
| 599 | wait_on_buffer(bh); | 599 | wait_on_buffer(bh); |
| 600 | if (buffer_eopnotsupp(bh)) { | 600 | if (buffer_eopnotsupp(bh)) { |
| 601 | clear_buffer_eopnotsupp(bh); | 601 | clear_buffer_eopnotsupp(bh); |
| @@ -605,7 +605,7 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags, int pull) | |||
| 605 | lock_buffer(bh); | 605 | lock_buffer(bh); |
| 606 | skip_barrier: | 606 | skip_barrier: |
| 607 | get_bh(bh); | 607 | get_bh(bh); |
| 608 | submit_bh(WRITE_SYNC | (1 << BIO_RW_META), bh); | 608 | submit_bh(WRITE_SYNC | REQ_META, bh); |
| 609 | wait_on_buffer(bh); | 609 | wait_on_buffer(bh); |
| 610 | } | 610 | } |
| 611 | if (!buffer_uptodate(bh)) | 611 | if (!buffer_uptodate(bh)) |
diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 18176d0b75d7..f3b071f921aa 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c | |||
| @@ -36,8 +36,8 @@ static int gfs2_aspace_writepage(struct page *page, struct writeback_control *wb | |||
| 36 | { | 36 | { |
| 37 | struct buffer_head *bh, *head; | 37 | struct buffer_head *bh, *head; |
| 38 | int nr_underway = 0; | 38 | int nr_underway = 0; |
| 39 | int write_op = (1 << BIO_RW_META) | ((wbc->sync_mode == WB_SYNC_ALL ? | 39 | int write_op = REQ_META | |
| 40 | WRITE_SYNC_PLUG : WRITE)); | 40 | (wbc->sync_mode == WB_SYNC_ALL ? WRITE_SYNC_PLUG : WRITE); |
| 41 | 41 | ||
| 42 | BUG_ON(!PageLocked(page)); | 42 | BUG_ON(!PageLocked(page)); |
| 43 | BUG_ON(!page_has_buffers(page)); | 43 | BUG_ON(!page_has_buffers(page)); |
| @@ -225,7 +225,7 @@ int gfs2_meta_read(struct gfs2_glock *gl, u64 blkno, int flags, | |||
| 225 | } | 225 | } |
| 226 | bh->b_end_io = end_buffer_read_sync; | 226 | bh->b_end_io = end_buffer_read_sync; |
| 227 | get_bh(bh); | 227 | get_bh(bh); |
| 228 | submit_bh(READ_SYNC | (1 << BIO_RW_META), bh); | 228 | submit_bh(READ_SYNC | REQ_META, bh); |
| 229 | if (!(flags & DIO_WAIT)) | 229 | if (!(flags & DIO_WAIT)) |
| 230 | return 0; | 230 | return 0; |
| 231 | 231 | ||
| @@ -432,7 +432,7 @@ struct buffer_head *gfs2_meta_ra(struct gfs2_glock *gl, u64 dblock, u32 extlen) | |||
| 432 | if (buffer_uptodate(first_bh)) | 432 | if (buffer_uptodate(first_bh)) |
| 433 | goto out; | 433 | goto out; |
| 434 | if (!buffer_locked(first_bh)) | 434 | if (!buffer_locked(first_bh)) |
| 435 | ll_rw_block(READ_SYNC | (1 << BIO_RW_META), 1, &first_bh); | 435 | ll_rw_block(READ_SYNC | REQ_META, 1, &first_bh); |
| 436 | 436 | ||
| 437 | dblock++; | 437 | dblock++; |
| 438 | extlen--; | 438 | extlen--; |
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 4f44bdeb2f03..4d4b1e8ac64c 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c | |||
| @@ -274,7 +274,7 @@ static int gfs2_read_super(struct gfs2_sbd *sdp, sector_t sector) | |||
| 274 | 274 | ||
| 275 | bio->bi_end_io = end_bio_io_page; | 275 | bio->bi_end_io = end_bio_io_page; |
| 276 | bio->bi_private = page; | 276 | bio->bi_private = page; |
| 277 | submit_bio(READ_SYNC | (1 << BIO_RW_META), bio); | 277 | submit_bio(READ_SYNC | REQ_META, bio); |
| 278 | wait_on_page_locked(page); | 278 | wait_on_page_locked(page); |
| 279 | bio_put(bio); | 279 | bio_put(bio); |
| 280 | if (!PageUptodate(page)) { | 280 | if (!PageUptodate(page)) { |
diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 98cdd05f3316..1009be2c9737 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c | |||
| @@ -1072,7 +1072,7 @@ int gfs2_permission(struct inode *inode, int mask) | |||
| 1072 | } | 1072 | } |
| 1073 | 1073 | ||
| 1074 | /* | 1074 | /* |
| 1075 | * XXX: should be changed to have proper ordering by opencoding simple_setsize | 1075 | * XXX(truncate): the truncate_setsize calls should be moved to the end. |
| 1076 | */ | 1076 | */ |
| 1077 | static int setattr_size(struct inode *inode, struct iattr *attr) | 1077 | static int setattr_size(struct inode *inode, struct iattr *attr) |
| 1078 | { | 1078 | { |
| @@ -1084,10 +1084,8 @@ static int setattr_size(struct inode *inode, struct iattr *attr) | |||
| 1084 | error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks); | 1084 | error = gfs2_trans_begin(sdp, 0, sdp->sd_jdesc->jd_blocks); |
| 1085 | if (error) | 1085 | if (error) |
| 1086 | return error; | 1086 | return error; |
| 1087 | error = simple_setsize(inode, attr->ia_size); | 1087 | truncate_setsize(inode, attr->ia_size); |
| 1088 | gfs2_trans_end(sdp); | 1088 | gfs2_trans_end(sdp); |
| 1089 | if (error) | ||
| 1090 | return error; | ||
| 1091 | } | 1089 | } |
| 1092 | 1090 | ||
| 1093 | error = gfs2_truncatei(ip, attr->ia_size); | 1091 | error = gfs2_truncatei(ip, attr->ia_size); |
| @@ -1136,8 +1134,16 @@ static int setattr_chown(struct inode *inode, struct iattr *attr) | |||
| 1136 | if (error) | 1134 | if (error) |
| 1137 | goto out_end_trans; | 1135 | goto out_end_trans; |
| 1138 | 1136 | ||
| 1139 | error = inode_setattr(inode, attr); | 1137 | if ((attr->ia_valid & ATTR_SIZE) && |
| 1140 | gfs2_assert_warn(sdp, !error); | 1138 | attr->ia_size != i_size_read(inode)) { |
| 1139 | int error; | ||
| 1140 | |||
| 1141 | error = vmtruncate(inode, attr->ia_size); | ||
| 1142 | gfs2_assert_warn(sdp, !error); | ||
| 1143 | } | ||
| 1144 | |||
| 1145 | setattr_copy(inode, attr); | ||
| 1146 | mark_inode_dirty(inode); | ||
| 1141 | 1147 | ||
| 1142 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | 1148 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); |
| 1143 | gfs2_dinode_out(ip, dibh->b_data); | 1149 | gfs2_dinode_out(ip, dibh->b_data); |
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c index 4140811a921c..77cb9f830ee4 100644 --- a/fs/gfs2/super.c +++ b/fs/gfs2/super.c | |||
| @@ -1188,7 +1188,7 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data) | |||
| 1188 | * node for later deallocation. | 1188 | * node for later deallocation. |
| 1189 | */ | 1189 | */ |
| 1190 | 1190 | ||
| 1191 | static void gfs2_drop_inode(struct inode *inode) | 1191 | static int gfs2_drop_inode(struct inode *inode) |
| 1192 | { | 1192 | { |
| 1193 | struct gfs2_inode *ip = GFS2_I(inode); | 1193 | struct gfs2_inode *ip = GFS2_I(inode); |
| 1194 | 1194 | ||
| @@ -1197,26 +1197,7 @@ static void gfs2_drop_inode(struct inode *inode) | |||
| 1197 | if (gl && test_bit(GLF_DEMOTE, &gl->gl_flags)) | 1197 | if (gl && test_bit(GLF_DEMOTE, &gl->gl_flags)) |
| 1198 | clear_nlink(inode); | 1198 | clear_nlink(inode); |
| 1199 | } | 1199 | } |
| 1200 | generic_drop_inode(inode); | 1200 | return generic_drop_inode(inode); |
| 1201 | } | ||
| 1202 | |||
| 1203 | /** | ||
| 1204 | * gfs2_clear_inode - Deallocate an inode when VFS is done with it | ||
| 1205 | * @inode: The VFS inode | ||
| 1206 | * | ||
| 1207 | */ | ||
| 1208 | |||
| 1209 | static void gfs2_clear_inode(struct inode *inode) | ||
| 1210 | { | ||
| 1211 | struct gfs2_inode *ip = GFS2_I(inode); | ||
| 1212 | |||
| 1213 | ip->i_gl->gl_object = NULL; | ||
| 1214 | gfs2_glock_put(ip->i_gl); | ||
| 1215 | ip->i_gl = NULL; | ||
| 1216 | if (ip->i_iopen_gh.gh_gl) { | ||
| 1217 | ip->i_iopen_gh.gh_gl->gl_object = NULL; | ||
| 1218 | gfs2_glock_dq_uninit(&ip->i_iopen_gh); | ||
| 1219 | } | ||
| 1220 | } | 1201 | } |
| 1221 | 1202 | ||
| 1222 | static int is_ancestor(const struct dentry *d1, const struct dentry *d2) | 1203 | static int is_ancestor(const struct dentry *d1, const struct dentry *d2) |
| @@ -1344,13 +1325,16 @@ static int gfs2_show_options(struct seq_file *s, struct vfsmount *mnt) | |||
| 1344 | * is safe, just less efficient. | 1325 | * is safe, just less efficient. |
| 1345 | */ | 1326 | */ |
| 1346 | 1327 | ||
| 1347 | static void gfs2_delete_inode(struct inode *inode) | 1328 | static void gfs2_evict_inode(struct inode *inode) |
| 1348 | { | 1329 | { |
| 1349 | struct gfs2_sbd *sdp = inode->i_sb->s_fs_info; | 1330 | struct gfs2_sbd *sdp = inode->i_sb->s_fs_info; |
| 1350 | struct gfs2_inode *ip = GFS2_I(inode); | 1331 | struct gfs2_inode *ip = GFS2_I(inode); |
| 1351 | struct gfs2_holder gh; | 1332 | struct gfs2_holder gh; |
| 1352 | int error; | 1333 | int error; |
| 1353 | 1334 | ||
| 1335 | if (inode->i_nlink) | ||
| 1336 | goto out; | ||
| 1337 | |||
| 1354 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); | 1338 | error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh); |
| 1355 | if (unlikely(error)) { | 1339 | if (unlikely(error)) { |
| 1356 | gfs2_glock_dq_uninit(&ip->i_iopen_gh); | 1340 | gfs2_glock_dq_uninit(&ip->i_iopen_gh); |
| @@ -1404,10 +1388,18 @@ out_unlock: | |||
| 1404 | gfs2_holder_uninit(&ip->i_iopen_gh); | 1388 | gfs2_holder_uninit(&ip->i_iopen_gh); |
| 1405 | gfs2_glock_dq_uninit(&gh); | 1389 | gfs2_glock_dq_uninit(&gh); |
| 1406 | if (error && error != GLR_TRYFAILED && error != -EROFS) | 1390 | if (error && error != GLR_TRYFAILED && error != -EROFS) |
| 1407 | fs_warn(sdp, "gfs2_delete_inode: %d\n", error); | 1391 | fs_warn(sdp, "gfs2_evict_inode: %d\n", error); |
| 1408 | out: | 1392 | out: |
| 1409 | truncate_inode_pages(&inode->i_data, 0); | 1393 | truncate_inode_pages(&inode->i_data, 0); |
| 1410 | clear_inode(inode); | 1394 | end_writeback(inode); |
| 1395 | |||
| 1396 | ip->i_gl->gl_object = NULL; | ||
| 1397 | gfs2_glock_put(ip->i_gl); | ||
| 1398 | ip->i_gl = NULL; | ||
| 1399 | if (ip->i_iopen_gh.gh_gl) { | ||
| 1400 | ip->i_iopen_gh.gh_gl->gl_object = NULL; | ||
| 1401 | gfs2_glock_dq_uninit(&ip->i_iopen_gh); | ||
| 1402 | } | ||
| 1411 | } | 1403 | } |
| 1412 | 1404 | ||
| 1413 | static struct inode *gfs2_alloc_inode(struct super_block *sb) | 1405 | static struct inode *gfs2_alloc_inode(struct super_block *sb) |
| @@ -1431,14 +1423,13 @@ const struct super_operations gfs2_super_ops = { | |||
| 1431 | .alloc_inode = gfs2_alloc_inode, | 1423 | .alloc_inode = gfs2_alloc_inode, |
| 1432 | .destroy_inode = gfs2_destroy_inode, | 1424 | .destroy_inode = gfs2_destroy_inode, |
| 1433 | .write_inode = gfs2_write_inode, | 1425 | .write_inode = gfs2_write_inode, |
| 1434 | .delete_inode = gfs2_delete_inode, | 1426 | .evict_inode = gfs2_evict_inode, |
| 1435 | .put_super = gfs2_put_super, | 1427 | .put_super = gfs2_put_super, |
| 1436 | .sync_fs = gfs2_sync_fs, | 1428 | .sync_fs = gfs2_sync_fs, |
| 1437 | .freeze_fs = gfs2_freeze, | 1429 | .freeze_fs = gfs2_freeze, |
| 1438 | .unfreeze_fs = gfs2_unfreeze, | 1430 | .unfreeze_fs = gfs2_unfreeze, |
| 1439 | .statfs = gfs2_statfs, | 1431 | .statfs = gfs2_statfs, |
| 1440 | .remount_fs = gfs2_remount_fs, | 1432 | .remount_fs = gfs2_remount_fs, |
| 1441 | .clear_inode = gfs2_clear_inode, | ||
| 1442 | .drop_inode = gfs2_drop_inode, | 1433 | .drop_inode = gfs2_drop_inode, |
| 1443 | .show_options = gfs2_show_options, | 1434 | .show_options = gfs2_show_options, |
| 1444 | }; | 1435 | }; |
diff --git a/fs/gfs2/xattr.c b/fs/gfs2/xattr.c index 82f93da00d1b..776af6eb4bcb 100644 --- a/fs/gfs2/xattr.c +++ b/fs/gfs2/xattr.c | |||
| @@ -1296,6 +1296,7 @@ fail: | |||
| 1296 | 1296 | ||
| 1297 | int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data) | 1297 | int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data) |
| 1298 | { | 1298 | { |
| 1299 | struct inode *inode = &ip->i_inode; | ||
| 1299 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); | 1300 | struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
| 1300 | struct gfs2_ea_location el; | 1301 | struct gfs2_ea_location el; |
| 1301 | struct buffer_head *dibh; | 1302 | struct buffer_head *dibh; |
| @@ -1321,14 +1322,25 @@ int gfs2_xattr_acl_chmod(struct gfs2_inode *ip, struct iattr *attr, char *data) | |||
| 1321 | return error; | 1322 | return error; |
| 1322 | 1323 | ||
| 1323 | error = gfs2_meta_inode_buffer(ip, &dibh); | 1324 | error = gfs2_meta_inode_buffer(ip, &dibh); |
| 1324 | if (!error) { | 1325 | if (error) |
| 1325 | error = inode_setattr(&ip->i_inode, attr); | 1326 | goto out_trans_end; |
| 1326 | gfs2_assert_warn(GFS2_SB(&ip->i_inode), !error); | 1327 | |
| 1327 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | 1328 | if ((attr->ia_valid & ATTR_SIZE) && |
| 1328 | gfs2_dinode_out(ip, dibh->b_data); | 1329 | attr->ia_size != i_size_read(inode)) { |
| 1329 | brelse(dibh); | 1330 | int error; |
| 1331 | |||
| 1332 | error = vmtruncate(inode, attr->ia_size); | ||
| 1333 | gfs2_assert_warn(GFS2_SB(inode), !error); | ||
| 1330 | } | 1334 | } |
| 1331 | 1335 | ||
| 1336 | setattr_copy(inode, attr); | ||
| 1337 | mark_inode_dirty(inode); | ||
| 1338 | |||
| 1339 | gfs2_trans_add_bh(ip->i_gl, dibh, 1); | ||
| 1340 | gfs2_dinode_out(ip, dibh->b_data); | ||
| 1341 | brelse(dibh); | ||
| 1342 | |||
| 1343 | out_trans_end: | ||
| 1332 | gfs2_trans_end(sdp); | 1344 | gfs2_trans_end(sdp); |
| 1333 | return error; | 1345 | return error; |
| 1334 | } | 1346 | } |
diff --git a/fs/hfs/hfs_fs.h b/fs/hfs/hfs_fs.h index fe35e3b626c4..4f55651aaa51 100644 --- a/fs/hfs/hfs_fs.h +++ b/fs/hfs/hfs_fs.h | |||
| @@ -193,7 +193,7 @@ extern int hfs_inode_setattr(struct dentry *, struct iattr *); | |||
| 193 | extern void hfs_inode_read_fork(struct inode *inode, struct hfs_extent *ext, | 193 | extern void hfs_inode_read_fork(struct inode *inode, struct hfs_extent *ext, |
| 194 | __be32 log_size, __be32 phys_size, u32 clump_size); | 194 | __be32 log_size, __be32 phys_size, u32 clump_size); |
| 195 | extern struct inode *hfs_iget(struct super_block *, struct hfs_cat_key *, hfs_cat_rec *); | 195 | extern struct inode *hfs_iget(struct super_block *, struct hfs_cat_key *, hfs_cat_rec *); |
| 196 | extern void hfs_clear_inode(struct inode *); | 196 | extern void hfs_evict_inode(struct inode *); |
| 197 | extern void hfs_delete_inode(struct inode *); | 197 | extern void hfs_delete_inode(struct inode *); |
| 198 | 198 | ||
| 199 | /* attr.c */ | 199 | /* attr.c */ |
diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c index 14f5cb1b9fdc..397b7adc7ce6 100644 --- a/fs/hfs/inode.c +++ b/fs/hfs/inode.c | |||
| @@ -39,10 +39,19 @@ static int hfs_write_begin(struct file *file, struct address_space *mapping, | |||
| 39 | loff_t pos, unsigned len, unsigned flags, | 39 | loff_t pos, unsigned len, unsigned flags, |
| 40 | struct page **pagep, void **fsdata) | 40 | struct page **pagep, void **fsdata) |
| 41 | { | 41 | { |
| 42 | int ret; | ||
| 43 | |||
| 42 | *pagep = NULL; | 44 | *pagep = NULL; |
| 43 | return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, | 45 | ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, |
| 44 | hfs_get_block, | 46 | hfs_get_block, |
| 45 | &HFS_I(mapping->host)->phys_size); | 47 | &HFS_I(mapping->host)->phys_size); |
| 48 | if (unlikely(ret)) { | ||
| 49 | loff_t isize = mapping->host->i_size; | ||
| 50 | if (pos + len > isize) | ||
| 51 | vmtruncate(mapping->host, isize); | ||
| 52 | } | ||
| 53 | |||
| 54 | return ret; | ||
| 46 | } | 55 | } |
| 47 | 56 | ||
| 48 | static sector_t hfs_bmap(struct address_space *mapping, sector_t block) | 57 | static sector_t hfs_bmap(struct address_space *mapping, sector_t block) |
| @@ -112,9 +121,24 @@ static ssize_t hfs_direct_IO(int rw, struct kiocb *iocb, | |||
| 112 | { | 121 | { |
| 113 | struct file *file = iocb->ki_filp; | 122 | struct file *file = iocb->ki_filp; |
| 114 | struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host; | 123 | struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host; |
| 124 | ssize_t ret; | ||
| 115 | 125 | ||
| 116 | return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, | 126 | ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, |
| 117 | offset, nr_segs, hfs_get_block, NULL); | 127 | offset, nr_segs, hfs_get_block, NULL); |
| 128 | |||
| 129 | /* | ||
| 130 | * In case of error extending write may have instantiated a few | ||
| 131 | * blocks outside i_size. Trim these off again. | ||
| 132 | */ | ||
| 133 | if (unlikely((rw & WRITE) && ret < 0)) { | ||
| 134 | loff_t isize = i_size_read(inode); | ||
| 135 | loff_t end = offset + iov_length(iov, nr_segs); | ||
| 136 | |||
| 137 | if (end > isize) | ||
| 138 | vmtruncate(inode, isize); | ||
| 139 | } | ||
| 140 | |||
| 141 | return ret; | ||
| 118 | } | 142 | } |
| 119 | 143 | ||
| 120 | static int hfs_writepages(struct address_space *mapping, | 144 | static int hfs_writepages(struct address_space *mapping, |
| @@ -507,8 +531,10 @@ out: | |||
| 507 | return NULL; | 531 | return NULL; |
| 508 | } | 532 | } |
| 509 | 533 | ||
| 510 | void hfs_clear_inode(struct inode *inode) | 534 | void hfs_evict_inode(struct inode *inode) |
| 511 | { | 535 | { |
| 536 | truncate_inode_pages(&inode->i_data, 0); | ||
| 537 | end_writeback(inode); | ||
| 512 | if (HFS_IS_RSRC(inode) && HFS_I(inode)->rsrc_inode) { | 538 | if (HFS_IS_RSRC(inode) && HFS_I(inode)->rsrc_inode) { |
| 513 | HFS_I(HFS_I(inode)->rsrc_inode)->rsrc_inode = NULL; | 539 | HFS_I(HFS_I(inode)->rsrc_inode)->rsrc_inode = NULL; |
| 514 | iput(HFS_I(inode)->rsrc_inode); | 540 | iput(HFS_I(inode)->rsrc_inode); |
| @@ -588,13 +614,43 @@ int hfs_inode_setattr(struct dentry *dentry, struct iattr * attr) | |||
| 588 | attr->ia_mode = inode->i_mode & ~S_IWUGO; | 614 | attr->ia_mode = inode->i_mode & ~S_IWUGO; |
| 589 | attr->ia_mode &= S_ISDIR(inode->i_mode) ? ~hsb->s_dir_umask: ~hsb->s_file_umask; | 615 | attr->ia_mode &= S_ISDIR(inode->i_mode) ? ~hsb->s_dir_umask: ~hsb->s_file_umask; |
| 590 | } | 616 | } |
| 591 | error = inode_setattr(inode, attr); | ||
| 592 | if (error) | ||
| 593 | return error; | ||
| 594 | 617 | ||
| 618 | if ((attr->ia_valid & ATTR_SIZE) && | ||
| 619 | attr->ia_size != i_size_read(inode)) { | ||
| 620 | error = vmtruncate(inode, attr->ia_size); | ||
| 621 | if (error) | ||
| 622 | return error; | ||
| 623 | } | ||
| 624 | |||
| 625 | setattr_copy(inode, attr); | ||
| 626 | mark_inode_dirty(inode); | ||
| 595 | return 0; | 627 | return 0; |
| 596 | } | 628 | } |
| 597 | 629 | ||
| 630 | static int hfs_file_fsync(struct file *filp, int datasync) | ||
| 631 | { | ||
| 632 | struct inode *inode = filp->f_mapping->host; | ||
| 633 | struct super_block * sb; | ||
| 634 | int ret, err; | ||
| 635 | |||
| 636 | /* sync the inode to buffers */ | ||
| 637 | ret = write_inode_now(inode, 0); | ||
| 638 | |||
| 639 | /* sync the superblock to buffers */ | ||
| 640 | sb = inode->i_sb; | ||
| 641 | if (sb->s_dirt) { | ||
| 642 | lock_super(sb); | ||
| 643 | sb->s_dirt = 0; | ||
| 644 | if (!(sb->s_flags & MS_RDONLY)) | ||
| 645 | hfs_mdb_commit(sb); | ||
| 646 | unlock_super(sb); | ||
| 647 | } | ||
| 648 | /* .. finally sync the buffers to disk */ | ||
| 649 | err = sync_blockdev(sb->s_bdev); | ||
| 650 | if (!ret) | ||
| 651 | ret = err; | ||
| 652 | return ret; | ||
| 653 | } | ||
| 598 | 654 | ||
| 599 | static const struct file_operations hfs_file_operations = { | 655 | static const struct file_operations hfs_file_operations = { |
| 600 | .llseek = generic_file_llseek, | 656 | .llseek = generic_file_llseek, |
| @@ -604,7 +660,7 @@ static const struct file_operations hfs_file_operations = { | |||
| 604 | .aio_write = generic_file_aio_write, | 660 | .aio_write = generic_file_aio_write, |
| 605 | .mmap = generic_file_mmap, | 661 | .mmap = generic_file_mmap, |
| 606 | .splice_read = generic_file_splice_read, | 662 | .splice_read = generic_file_splice_read, |
| 607 | .fsync = file_fsync, | 663 | .fsync = hfs_file_fsync, |
| 608 | .open = hfs_file_open, | 664 | .open = hfs_file_open, |
| 609 | .release = hfs_file_release, | 665 | .release = hfs_file_release, |
| 610 | }; | 666 | }; |
diff --git a/fs/hfs/super.c b/fs/hfs/super.c index 0a81eb7111f3..34235d4bf08b 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c | |||
| @@ -181,7 +181,7 @@ static const struct super_operations hfs_super_operations = { | |||
| 181 | .alloc_inode = hfs_alloc_inode, | 181 | .alloc_inode = hfs_alloc_inode, |
| 182 | .destroy_inode = hfs_destroy_inode, | 182 | .destroy_inode = hfs_destroy_inode, |
| 183 | .write_inode = hfs_write_inode, | 183 | .write_inode = hfs_write_inode, |
| 184 | .clear_inode = hfs_clear_inode, | 184 | .evict_inode = hfs_evict_inode, |
| 185 | .put_super = hfs_put_super, | 185 | .put_super = hfs_put_super, |
| 186 | .write_super = hfs_write_super, | 186 | .write_super = hfs_write_super, |
| 187 | .sync_fs = hfs_sync_fs, | 187 | .sync_fs = hfs_sync_fs, |
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h index 6505c30ad965..dc856be3c2b0 100644 --- a/fs/hfsplus/hfsplus_fs.h +++ b/fs/hfsplus/hfsplus_fs.h | |||
| @@ -351,6 +351,7 @@ int hfsplus_show_options(struct seq_file *, struct vfsmount *); | |||
| 351 | 351 | ||
| 352 | /* super.c */ | 352 | /* super.c */ |
| 353 | struct inode *hfsplus_iget(struct super_block *, unsigned long); | 353 | struct inode *hfsplus_iget(struct super_block *, unsigned long); |
| 354 | int hfsplus_sync_fs(struct super_block *sb, int wait); | ||
| 354 | 355 | ||
| 355 | /* tables.c */ | 356 | /* tables.c */ |
| 356 | extern u16 hfsplus_case_fold_table[]; | 357 | extern u16 hfsplus_case_fold_table[]; |
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index 9bbb82924a22..c5a979d62c65 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c | |||
| @@ -31,10 +31,19 @@ static int hfsplus_write_begin(struct file *file, struct address_space *mapping, | |||
| 31 | loff_t pos, unsigned len, unsigned flags, | 31 | loff_t pos, unsigned len, unsigned flags, |
| 32 | struct page **pagep, void **fsdata) | 32 | struct page **pagep, void **fsdata) |
| 33 | { | 33 | { |
| 34 | int ret; | ||
| 35 | |||
| 34 | *pagep = NULL; | 36 | *pagep = NULL; |
| 35 | return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, | 37 | ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, |
| 36 | hfsplus_get_block, | 38 | hfsplus_get_block, |
| 37 | &HFSPLUS_I(mapping->host).phys_size); | 39 | &HFSPLUS_I(mapping->host).phys_size); |
| 40 | if (unlikely(ret)) { | ||
| 41 | loff_t isize = mapping->host->i_size; | ||
| 42 | if (pos + len > isize) | ||
| 43 | vmtruncate(mapping->host, isize); | ||
| 44 | } | ||
| 45 | |||
| 46 | return ret; | ||
| 38 | } | 47 | } |
| 39 | 48 | ||
| 40 | static sector_t hfsplus_bmap(struct address_space *mapping, sector_t block) | 49 | static sector_t hfsplus_bmap(struct address_space *mapping, sector_t block) |
| @@ -105,9 +114,24 @@ static ssize_t hfsplus_direct_IO(int rw, struct kiocb *iocb, | |||
| 105 | { | 114 | { |
| 106 | struct file *file = iocb->ki_filp; | 115 | struct file *file = iocb->ki_filp; |
| 107 | struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host; | 116 | struct inode *inode = file->f_path.dentry->d_inode->i_mapping->host; |
| 117 | ssize_t ret; | ||
| 108 | 118 | ||
| 109 | return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, | 119 | ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, |
| 110 | offset, nr_segs, hfsplus_get_block, NULL); | 120 | offset, nr_segs, hfsplus_get_block, NULL); |
| 121 | |||
| 122 | /* | ||
| 123 | * In case of error extending write may have instantiated a few | ||
| 124 | * blocks outside i_size. Trim these off again. | ||
| 125 | */ | ||
| 126 | if (unlikely((rw & WRITE) && ret < 0)) { | ||
| 127 | loff_t isize = i_size_read(inode); | ||
| 128 | loff_t end = offset + iov_length(iov, nr_segs); | ||
| 129 | |||
| 130 | if (end > isize) | ||
| 131 | vmtruncate(inode, isize); | ||
| 132 | } | ||
| 133 | |||
| 134 | return ret; | ||
| 111 | } | 135 | } |
| 112 | 136 | ||
| 113 | static int hfsplus_writepages(struct address_space *mapping, | 137 | static int hfsplus_writepages(struct address_space *mapping, |
| @@ -266,9 +290,56 @@ static int hfsplus_file_release(struct inode *inode, struct file *file) | |||
| 266 | return 0; | 290 | return 0; |
| 267 | } | 291 | } |
| 268 | 292 | ||
| 293 | static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr) | ||
| 294 | { | ||
| 295 | struct inode *inode = dentry->d_inode; | ||
| 296 | int error; | ||
| 297 | |||
| 298 | error = inode_change_ok(inode, attr); | ||
| 299 | if (error) | ||
| 300 | return error; | ||
| 301 | |||
| 302 | if ((attr->ia_valid & ATTR_SIZE) && | ||
| 303 | attr->ia_size != i_size_read(inode)) { | ||
| 304 | error = vmtruncate(inode, attr->ia_size); | ||
| 305 | if (error) | ||
| 306 | return error; | ||
| 307 | } | ||
| 308 | |||
| 309 | setattr_copy(inode, attr); | ||
| 310 | mark_inode_dirty(inode); | ||
| 311 | return 0; | ||
| 312 | } | ||
| 313 | |||
| 314 | static int hfsplus_file_fsync(struct file *filp, int datasync) | ||
| 315 | { | ||
| 316 | struct inode *inode = filp->f_mapping->host; | ||
| 317 | struct super_block * sb; | ||
| 318 | int ret, err; | ||
| 319 | |||
| 320 | /* sync the inode to buffers */ | ||
| 321 | ret = write_inode_now(inode, 0); | ||
| 322 | |||
| 323 | /* sync the superblock to buffers */ | ||
| 324 | sb = inode->i_sb; | ||
| 325 | if (sb->s_dirt) { | ||
| 326 | if (!(sb->s_flags & MS_RDONLY)) | ||
| 327 | hfsplus_sync_fs(sb, 1); | ||
| 328 | else | ||
| 329 | sb->s_dirt = 0; | ||
| 330 | } | ||
| 331 | |||
| 332 | /* .. finally sync the buffers to disk */ | ||
| 333 | err = sync_blockdev(sb->s_bdev); | ||
| 334 | if (!ret) | ||
| 335 | ret = err; | ||
| 336 | return ret; | ||
| 337 | } | ||
| 338 | |||
| 269 | static const struct inode_operations hfsplus_file_inode_operations = { | 339 | static const struct inode_operations hfsplus_file_inode_operations = { |
| 270 | .lookup = hfsplus_file_lookup, | 340 | .lookup = hfsplus_file_lookup, |
| 271 | .truncate = hfsplus_file_truncate, | 341 | .truncate = hfsplus_file_truncate, |
| 342 | .setattr = hfsplus_setattr, | ||
| 272 | .setxattr = hfsplus_setxattr, | 343 | .setxattr = hfsplus_setxattr, |
| 273 | .getxattr = hfsplus_getxattr, | 344 | .getxattr = hfsplus_getxattr, |
| 274 | .listxattr = hfsplus_listxattr, | 345 | .listxattr = hfsplus_listxattr, |
| @@ -282,7 +353,7 @@ static const struct file_operations hfsplus_file_operations = { | |||
| 282 | .aio_write = generic_file_aio_write, | 353 | .aio_write = generic_file_aio_write, |
| 283 | .mmap = generic_file_mmap, | 354 | .mmap = generic_file_mmap, |
| 284 | .splice_read = generic_file_splice_read, | 355 | .splice_read = generic_file_splice_read, |
| 285 | .fsync = file_fsync, | 356 | .fsync = hfsplus_file_fsync, |
| 286 | .open = hfsplus_file_open, | 357 | .open = hfsplus_file_open, |
| 287 | .release = hfsplus_file_release, | 358 | .release = hfsplus_file_release, |
| 288 | .unlocked_ioctl = hfsplus_ioctl, | 359 | .unlocked_ioctl = hfsplus_ioctl, |
diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index 74b473a8ef92..3b55c050c742 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c | |||
| @@ -145,16 +145,18 @@ static int hfsplus_write_inode(struct inode *inode, | |||
| 145 | return ret; | 145 | return ret; |
| 146 | } | 146 | } |
| 147 | 147 | ||
| 148 | static void hfsplus_clear_inode(struct inode *inode) | 148 | static void hfsplus_evict_inode(struct inode *inode) |
| 149 | { | 149 | { |
| 150 | dprint(DBG_INODE, "hfsplus_clear_inode: %lu\n", inode->i_ino); | 150 | dprint(DBG_INODE, "hfsplus_evict_inode: %lu\n", inode->i_ino); |
| 151 | truncate_inode_pages(&inode->i_data, 0); | ||
| 152 | end_writeback(inode); | ||
| 151 | if (HFSPLUS_IS_RSRC(inode)) { | 153 | if (HFSPLUS_IS_RSRC(inode)) { |
| 152 | HFSPLUS_I(HFSPLUS_I(inode).rsrc_inode).rsrc_inode = NULL; | 154 | HFSPLUS_I(HFSPLUS_I(inode).rsrc_inode).rsrc_inode = NULL; |
| 153 | iput(HFSPLUS_I(inode).rsrc_inode); | 155 | iput(HFSPLUS_I(inode).rsrc_inode); |
| 154 | } | 156 | } |
| 155 | } | 157 | } |
| 156 | 158 | ||
| 157 | static int hfsplus_sync_fs(struct super_block *sb, int wait) | 159 | int hfsplus_sync_fs(struct super_block *sb, int wait) |
| 158 | { | 160 | { |
| 159 | struct hfsplus_vh *vhdr = HFSPLUS_SB(sb).s_vhdr; | 161 | struct hfsplus_vh *vhdr = HFSPLUS_SB(sb).s_vhdr; |
| 160 | 162 | ||
| @@ -293,7 +295,7 @@ static const struct super_operations hfsplus_sops = { | |||
| 293 | .alloc_inode = hfsplus_alloc_inode, | 295 | .alloc_inode = hfsplus_alloc_inode, |
| 294 | .destroy_inode = hfsplus_destroy_inode, | 296 | .destroy_inode = hfsplus_destroy_inode, |
| 295 | .write_inode = hfsplus_write_inode, | 297 | .write_inode = hfsplus_write_inode, |
| 296 | .clear_inode = hfsplus_clear_inode, | 298 | .evict_inode = hfsplus_evict_inode, |
| 297 | .put_super = hfsplus_put_super, | 299 | .put_super = hfsplus_put_super, |
| 298 | .write_super = hfsplus_write_super, | 300 | .write_super = hfsplus_write_super, |
| 299 | .sync_fs = hfsplus_sync_fs, | 301 | .sync_fs = hfsplus_sync_fs, |
diff --git a/fs/hostfs/hostfs.h b/fs/hostfs/hostfs.h index 2f34f8f2134b..6bbd75c5589b 100644 --- a/fs/hostfs/hostfs.h +++ b/fs/hostfs/hostfs.h | |||
| @@ -53,18 +53,28 @@ struct hostfs_iattr { | |||
| 53 | struct timespec ia_ctime; | 53 | struct timespec ia_ctime; |
| 54 | }; | 54 | }; |
| 55 | 55 | ||
| 56 | extern int stat_file(const char *path, unsigned long long *inode_out, | 56 | struct hostfs_stat { |
| 57 | int *mode_out, int *nlink_out, int *uid_out, int *gid_out, | 57 | unsigned long long ino; |
| 58 | unsigned long long *size_out, struct timespec *atime_out, | 58 | unsigned int mode; |
| 59 | struct timespec *mtime_out, struct timespec *ctime_out, | 59 | unsigned int nlink; |
| 60 | int *blksize_out, unsigned long long *blocks_out, int fd); | 60 | unsigned int uid; |
| 61 | unsigned int gid; | ||
| 62 | unsigned long long size; | ||
| 63 | struct timespec atime, mtime, ctime; | ||
| 64 | unsigned int blksize; | ||
| 65 | unsigned long long blocks; | ||
| 66 | unsigned int maj; | ||
| 67 | unsigned int min; | ||
| 68 | }; | ||
| 69 | |||
| 70 | extern int stat_file(const char *path, struct hostfs_stat *p, int fd); | ||
| 61 | extern int access_file(char *path, int r, int w, int x); | 71 | extern int access_file(char *path, int r, int w, int x); |
| 62 | extern int open_file(char *path, int r, int w, int append); | 72 | extern int open_file(char *path, int r, int w, int append); |
| 63 | extern int file_type(const char *path, int *maj, int *min); | ||
| 64 | extern void *open_dir(char *path, int *err_out); | 73 | extern void *open_dir(char *path, int *err_out); |
| 65 | extern char *read_dir(void *stream, unsigned long long *pos, | 74 | extern char *read_dir(void *stream, unsigned long long *pos, |
| 66 | unsigned long long *ino_out, int *len_out); | 75 | unsigned long long *ino_out, int *len_out); |
| 67 | extern void close_file(void *stream); | 76 | extern void close_file(void *stream); |
| 77 | extern int replace_file(int oldfd, int fd); | ||
| 68 | extern void close_dir(void *stream); | 78 | extern void close_dir(void *stream); |
| 69 | extern int read_file(int fd, unsigned long long *offset, char *buf, int len); | 79 | extern int read_file(int fd, unsigned long long *offset, char *buf, int len); |
| 70 | extern int write_file(int fd, unsigned long long *offset, const char *buf, | 80 | extern int write_file(int fd, unsigned long long *offset, const char *buf, |
diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index 87ac1891a185..dd1e55535a4e 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c | |||
| @@ -14,12 +14,12 @@ | |||
| 14 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
| 15 | #include <linux/seq_file.h> | 15 | #include <linux/seq_file.h> |
| 16 | #include <linux/mount.h> | 16 | #include <linux/mount.h> |
| 17 | #include <linux/namei.h> | ||
| 17 | #include "hostfs.h" | 18 | #include "hostfs.h" |
| 18 | #include "init.h" | 19 | #include "init.h" |
| 19 | #include "kern.h" | 20 | #include "kern.h" |
| 20 | 21 | ||
| 21 | struct hostfs_inode_info { | 22 | struct hostfs_inode_info { |
| 22 | char *host_filename; | ||
| 23 | int fd; | 23 | int fd; |
| 24 | fmode_t mode; | 24 | fmode_t mode; |
| 25 | struct inode vfs_inode; | 25 | struct inode vfs_inode; |
| @@ -49,7 +49,7 @@ static int append = 0; | |||
| 49 | 49 | ||
| 50 | static const struct inode_operations hostfs_iops; | 50 | static const struct inode_operations hostfs_iops; |
| 51 | static const struct inode_operations hostfs_dir_iops; | 51 | static const struct inode_operations hostfs_dir_iops; |
| 52 | static const struct address_space_operations hostfs_link_aops; | 52 | static const struct inode_operations hostfs_link_iops; |
| 53 | 53 | ||
| 54 | #ifndef MODULE | 54 | #ifndef MODULE |
| 55 | static int __init hostfs_args(char *options, int *add) | 55 | static int __init hostfs_args(char *options, int *add) |
| @@ -90,71 +90,58 @@ __uml_setup("hostfs=", hostfs_args, | |||
| 90 | ); | 90 | ); |
| 91 | #endif | 91 | #endif |
| 92 | 92 | ||
| 93 | static char *dentry_name(struct dentry *dentry, int extra) | 93 | static char *__dentry_name(struct dentry *dentry, char *name) |
| 94 | { | 94 | { |
| 95 | struct dentry *parent; | 95 | char *p = __dentry_path(dentry, name, PATH_MAX); |
| 96 | char *root, *name; | 96 | char *root; |
| 97 | int len; | 97 | size_t len; |
| 98 | |||
| 99 | len = 0; | ||
| 100 | parent = dentry; | ||
| 101 | while (parent->d_parent != parent) { | ||
| 102 | len += parent->d_name.len + 1; | ||
| 103 | parent = parent->d_parent; | ||
| 104 | } | ||
| 105 | 98 | ||
| 106 | root = HOSTFS_I(parent->d_inode)->host_filename; | 99 | spin_unlock(&dcache_lock); |
| 107 | len += strlen(root); | ||
| 108 | name = kmalloc(len + extra + 1, GFP_KERNEL); | ||
| 109 | if (name == NULL) | ||
| 110 | return NULL; | ||
| 111 | 100 | ||
| 112 | name[len] = '\0'; | 101 | root = dentry->d_sb->s_fs_info; |
| 113 | parent = dentry; | 102 | len = strlen(root); |
| 114 | while (parent->d_parent != parent) { | 103 | if (IS_ERR(p)) { |
| 115 | len -= parent->d_name.len + 1; | 104 | __putname(name); |
| 116 | name[len] = '/'; | 105 | return NULL; |
| 117 | strncpy(&name[len + 1], parent->d_name.name, | 106 | } |
| 118 | parent->d_name.len); | 107 | strncpy(name, root, PATH_MAX); |
| 119 | parent = parent->d_parent; | 108 | if (len > p - name) { |
| 109 | __putname(name); | ||
| 110 | return NULL; | ||
| 111 | } | ||
| 112 | if (p > name + len) { | ||
| 113 | char *s = name + len; | ||
| 114 | while ((*s++ = *p++) != '\0') | ||
| 115 | ; | ||
| 120 | } | 116 | } |
| 121 | strncpy(name, root, strlen(root)); | ||
| 122 | return name; | 117 | return name; |
| 123 | } | 118 | } |
| 124 | 119 | ||
| 125 | static char *inode_name(struct inode *ino, int extra) | 120 | static char *dentry_name(struct dentry *dentry) |
| 126 | { | 121 | { |
| 127 | struct dentry *dentry; | 122 | char *name = __getname(); |
| 123 | if (!name) | ||
| 124 | return NULL; | ||
| 128 | 125 | ||
| 129 | dentry = list_entry(ino->i_dentry.next, struct dentry, d_alias); | 126 | spin_lock(&dcache_lock); |
| 130 | return dentry_name(dentry, extra); | 127 | return __dentry_name(dentry, name); /* will unlock */ |
| 131 | } | 128 | } |
| 132 | 129 | ||
| 133 | static int read_name(struct inode *ino, char *name) | 130 | static char *inode_name(struct inode *ino) |
| 134 | { | 131 | { |
| 135 | /* | 132 | struct dentry *dentry; |
| 136 | * The non-int inode fields are copied into ints by stat_file and | 133 | char *name = __getname(); |
| 137 | * then copied into the inode because passing the actual pointers | 134 | if (!name) |
| 138 | * in and having them treated as int * breaks on big-endian machines | 135 | return NULL; |
| 139 | */ | ||
| 140 | int err; | ||
| 141 | int i_mode, i_nlink, i_blksize; | ||
| 142 | unsigned long long i_size; | ||
| 143 | unsigned long long i_ino; | ||
| 144 | unsigned long long i_blocks; | ||
| 145 | |||
| 146 | err = stat_file(name, &i_ino, &i_mode, &i_nlink, &ino->i_uid, | ||
| 147 | &ino->i_gid, &i_size, &ino->i_atime, &ino->i_mtime, | ||
| 148 | &ino->i_ctime, &i_blksize, &i_blocks, -1); | ||
| 149 | if (err) | ||
| 150 | return err; | ||
| 151 | 136 | ||
| 152 | ino->i_ino = i_ino; | 137 | spin_lock(&dcache_lock); |
| 153 | ino->i_mode = i_mode; | 138 | if (list_empty(&ino->i_dentry)) { |
| 154 | ino->i_nlink = i_nlink; | 139 | spin_unlock(&dcache_lock); |
| 155 | ino->i_size = i_size; | 140 | __putname(name); |
| 156 | ino->i_blocks = i_blocks; | 141 | return NULL; |
| 157 | return 0; | 142 | } |
| 143 | dentry = list_first_entry(&ino->i_dentry, struct dentry, d_alias); | ||
| 144 | return __dentry_name(dentry, name); /* will unlock */ | ||
| 158 | } | 145 | } |
| 159 | 146 | ||
| 160 | static char *follow_link(char *link) | 147 | static char *follow_link(char *link) |
| @@ -205,53 +192,11 @@ static char *follow_link(char *link) | |||
| 205 | return ERR_PTR(n); | 192 | return ERR_PTR(n); |
| 206 | } | 193 | } |
| 207 | 194 | ||
| 208 | static int hostfs_read_inode(struct inode *ino) | ||
| 209 | { | ||
| 210 | char *name; | ||
| 211 | int err = 0; | ||
| 212 | |||
| 213 | /* | ||
| 214 | * Unfortunately, we are called from iget() when we don't have a dentry | ||
| 215 | * allocated yet. | ||
| 216 | */ | ||
| 217 | if (list_empty(&ino->i_dentry)) | ||
| 218 | goto out; | ||
| 219 | |||
| 220 | err = -ENOMEM; | ||
| 221 | name = inode_name(ino, 0); | ||
| 222 | if (name == NULL) | ||
| 223 | goto out; | ||
| 224 | |||
| 225 | if (file_type(name, NULL, NULL) == OS_TYPE_SYMLINK) { | ||
| 226 | name = follow_link(name); | ||
| 227 | if (IS_ERR(name)) { | ||
| 228 | err = PTR_ERR(name); | ||
| 229 | goto out; | ||
| 230 | } | ||
| 231 | } | ||
| 232 | |||
| 233 | err = read_name(ino, name); | ||
| 234 | kfree(name); | ||
| 235 | out: | ||
| 236 | return err; | ||
| 237 | } | ||
| 238 | |||
| 239 | static struct inode *hostfs_iget(struct super_block *sb) | 195 | static struct inode *hostfs_iget(struct super_block *sb) |
| 240 | { | 196 | { |
| 241 | struct inode *inode; | 197 | struct inode *inode = new_inode(sb); |
| 242 | long ret; | ||
| 243 | |||
| 244 | inode = iget_locked(sb, 0); | ||
| 245 | if (!inode) | 198 | if (!inode) |
| 246 | return ERR_PTR(-ENOMEM); | 199 | return ERR_PTR(-ENOMEM); |
| 247 | if (inode->i_state & I_NEW) { | ||
| 248 | ret = hostfs_read_inode(inode); | ||
| 249 | if (ret < 0) { | ||
| 250 | iget_failed(inode); | ||
| 251 | return ERR_PTR(ret); | ||
| 252 | } | ||
| 253 | unlock_new_inode(inode); | ||
| 254 | } | ||
| 255 | return inode; | 200 | return inode; |
| 256 | } | 201 | } |
| 257 | 202 | ||
| @@ -269,7 +214,7 @@ int hostfs_statfs(struct dentry *dentry, struct kstatfs *sf) | |||
| 269 | long long f_files; | 214 | long long f_files; |
| 270 | long long f_ffree; | 215 | long long f_ffree; |
| 271 | 216 | ||
| 272 | err = do_statfs(HOSTFS_I(dentry->d_sb->s_root->d_inode)->host_filename, | 217 | err = do_statfs(dentry->d_sb->s_fs_info, |
| 273 | &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files, | 218 | &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files, |
| 274 | &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid), | 219 | &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid), |
| 275 | &sf->f_namelen, sf->f_spare); | 220 | &sf->f_namelen, sf->f_spare); |
| @@ -288,47 +233,32 @@ static struct inode *hostfs_alloc_inode(struct super_block *sb) | |||
| 288 | { | 233 | { |
| 289 | struct hostfs_inode_info *hi; | 234 | struct hostfs_inode_info *hi; |
| 290 | 235 | ||
| 291 | hi = kmalloc(sizeof(*hi), GFP_KERNEL); | 236 | hi = kzalloc(sizeof(*hi), GFP_KERNEL); |
| 292 | if (hi == NULL) | 237 | if (hi == NULL) |
| 293 | return NULL; | 238 | return NULL; |
| 294 | 239 | hi->fd = -1; | |
| 295 | *hi = ((struct hostfs_inode_info) { .host_filename = NULL, | ||
| 296 | .fd = -1, | ||
| 297 | .mode = 0 }); | ||
| 298 | inode_init_once(&hi->vfs_inode); | 240 | inode_init_once(&hi->vfs_inode); |
| 299 | return &hi->vfs_inode; | 241 | return &hi->vfs_inode; |
| 300 | } | 242 | } |
| 301 | 243 | ||
| 302 | static void hostfs_delete_inode(struct inode *inode) | 244 | static void hostfs_evict_inode(struct inode *inode) |
| 303 | { | 245 | { |
| 304 | truncate_inode_pages(&inode->i_data, 0); | 246 | truncate_inode_pages(&inode->i_data, 0); |
| 247 | end_writeback(inode); | ||
| 305 | if (HOSTFS_I(inode)->fd != -1) { | 248 | if (HOSTFS_I(inode)->fd != -1) { |
| 306 | close_file(&HOSTFS_I(inode)->fd); | 249 | close_file(&HOSTFS_I(inode)->fd); |
| 307 | HOSTFS_I(inode)->fd = -1; | 250 | HOSTFS_I(inode)->fd = -1; |
| 308 | } | 251 | } |
| 309 | clear_inode(inode); | ||
| 310 | } | 252 | } |
| 311 | 253 | ||
| 312 | static void hostfs_destroy_inode(struct inode *inode) | 254 | static void hostfs_destroy_inode(struct inode *inode) |
| 313 | { | 255 | { |
| 314 | kfree(HOSTFS_I(inode)->host_filename); | ||
| 315 | |||
| 316 | /* | ||
| 317 | * XXX: This should not happen, probably. The check is here for | ||
| 318 | * additional safety. | ||
| 319 | */ | ||
| 320 | if (HOSTFS_I(inode)->fd != -1) { | ||
| 321 | close_file(&HOSTFS_I(inode)->fd); | ||
| 322 | printk(KERN_DEBUG "Closing host fd in .destroy_inode\n"); | ||
| 323 | } | ||
| 324 | |||
| 325 | kfree(HOSTFS_I(inode)); | 256 | kfree(HOSTFS_I(inode)); |
| 326 | } | 257 | } |
| 327 | 258 | ||
| 328 | static int hostfs_show_options(struct seq_file *seq, struct vfsmount *vfs) | 259 | static int hostfs_show_options(struct seq_file *seq, struct vfsmount *vfs) |
| 329 | { | 260 | { |
| 330 | struct inode *root = vfs->mnt_sb->s_root->d_inode; | 261 | const char *root_path = vfs->mnt_sb->s_fs_info; |
| 331 | const char *root_path = HOSTFS_I(root)->host_filename; | ||
| 332 | size_t offset = strlen(root_ino) + 1; | 262 | size_t offset = strlen(root_ino) + 1; |
| 333 | 263 | ||
| 334 | if (strlen(root_path) > offset) | 264 | if (strlen(root_path) > offset) |
| @@ -339,9 +269,8 @@ static int hostfs_show_options(struct seq_file *seq, struct vfsmount *vfs) | |||
| 339 | 269 | ||
| 340 | static const struct super_operations hostfs_sbops = { | 270 | static const struct super_operations hostfs_sbops = { |
| 341 | .alloc_inode = hostfs_alloc_inode, | 271 | .alloc_inode = hostfs_alloc_inode, |
| 342 | .drop_inode = generic_delete_inode, | ||
| 343 | .delete_inode = hostfs_delete_inode, | ||
| 344 | .destroy_inode = hostfs_destroy_inode, | 272 | .destroy_inode = hostfs_destroy_inode, |
| 273 | .evict_inode = hostfs_evict_inode, | ||
| 345 | .statfs = hostfs_statfs, | 274 | .statfs = hostfs_statfs, |
| 346 | .show_options = hostfs_show_options, | 275 | .show_options = hostfs_show_options, |
| 347 | }; | 276 | }; |
| @@ -353,11 +282,11 @@ int hostfs_readdir(struct file *file, void *ent, filldir_t filldir) | |||
| 353 | unsigned long long next, ino; | 282 | unsigned long long next, ino; |
| 354 | int error, len; | 283 | int error, len; |
| 355 | 284 | ||
| 356 | name = dentry_name(file->f_path.dentry, 0); | 285 | name = dentry_name(file->f_path.dentry); |
| 357 | if (name == NULL) | 286 | if (name == NULL) |
| 358 | return -ENOMEM; | 287 | return -ENOMEM; |
| 359 | dir = open_dir(name, &error); | 288 | dir = open_dir(name, &error); |
| 360 | kfree(name); | 289 | __putname(name); |
| 361 | if (dir == NULL) | 290 | if (dir == NULL) |
| 362 | return -error; | 291 | return -error; |
| 363 | next = file->f_pos; | 292 | next = file->f_pos; |
| @@ -373,40 +302,59 @@ int hostfs_readdir(struct file *file, void *ent, filldir_t filldir) | |||
| 373 | 302 | ||
| 374 | int hostfs_file_open(struct inode *ino, struct file *file) | 303 | int hostfs_file_open(struct inode *ino, struct file *file) |
| 375 | { | 304 | { |
| 305 | static DEFINE_MUTEX(open_mutex); | ||
| 376 | char *name; | 306 | char *name; |
| 377 | fmode_t mode = 0; | 307 | fmode_t mode = 0; |
| 308 | int err; | ||
| 378 | int r = 0, w = 0, fd; | 309 | int r = 0, w = 0, fd; |
| 379 | 310 | ||
| 380 | mode = file->f_mode & (FMODE_READ | FMODE_WRITE); | 311 | mode = file->f_mode & (FMODE_READ | FMODE_WRITE); |
| 381 | if ((mode & HOSTFS_I(ino)->mode) == mode) | 312 | if ((mode & HOSTFS_I(ino)->mode) == mode) |
| 382 | return 0; | 313 | return 0; |
| 383 | 314 | ||
| 384 | /* | 315 | mode |= HOSTFS_I(ino)->mode; |
| 385 | * The file may already have been opened, but with the wrong access, | ||
| 386 | * so this resets things and reopens the file with the new access. | ||
| 387 | */ | ||
| 388 | if (HOSTFS_I(ino)->fd != -1) { | ||
| 389 | close_file(&HOSTFS_I(ino)->fd); | ||
| 390 | HOSTFS_I(ino)->fd = -1; | ||
| 391 | } | ||
| 392 | 316 | ||
| 393 | HOSTFS_I(ino)->mode |= mode; | 317 | retry: |
| 394 | if (HOSTFS_I(ino)->mode & FMODE_READ) | 318 | if (mode & FMODE_READ) |
| 395 | r = 1; | 319 | r = 1; |
| 396 | if (HOSTFS_I(ino)->mode & FMODE_WRITE) | 320 | if (mode & FMODE_WRITE) |
| 397 | w = 1; | 321 | w = 1; |
| 398 | if (w) | 322 | if (w) |
| 399 | r = 1; | 323 | r = 1; |
| 400 | 324 | ||
| 401 | name = dentry_name(file->f_path.dentry, 0); | 325 | name = dentry_name(file->f_path.dentry); |
| 402 | if (name == NULL) | 326 | if (name == NULL) |
| 403 | return -ENOMEM; | 327 | return -ENOMEM; |
| 404 | 328 | ||
| 405 | fd = open_file(name, r, w, append); | 329 | fd = open_file(name, r, w, append); |
| 406 | kfree(name); | 330 | __putname(name); |
| 407 | if (fd < 0) | 331 | if (fd < 0) |
| 408 | return fd; | 332 | return fd; |
| 409 | FILE_HOSTFS_I(file)->fd = fd; | 333 | |
| 334 | mutex_lock(&open_mutex); | ||
| 335 | /* somebody else had handled it first? */ | ||
| 336 | if ((mode & HOSTFS_I(ino)->mode) == mode) { | ||
| 337 | mutex_unlock(&open_mutex); | ||
| 338 | return 0; | ||
| 339 | } | ||
| 340 | if ((mode | HOSTFS_I(ino)->mode) != mode) { | ||
| 341 | mode |= HOSTFS_I(ino)->mode; | ||
| 342 | mutex_unlock(&open_mutex); | ||
| 343 | close_file(&fd); | ||
| 344 | goto retry; | ||
| 345 | } | ||
| 346 | if (HOSTFS_I(ino)->fd == -1) { | ||
| 347 | HOSTFS_I(ino)->fd = fd; | ||
| 348 | } else { | ||
| 349 | err = replace_file(fd, HOSTFS_I(ino)->fd); | ||
| 350 | close_file(&fd); | ||
| 351 | if (err < 0) { | ||
| 352 | mutex_unlock(&open_mutex); | ||
| 353 | return err; | ||
| 354 | } | ||
| 355 | } | ||
| 356 | HOSTFS_I(ino)->mode = mode; | ||
| 357 | mutex_unlock(&open_mutex); | ||
| 410 | 358 | ||
| 411 | return 0; | 359 | return 0; |
| 412 | } | 360 | } |
| @@ -544,54 +492,50 @@ static const struct address_space_operations hostfs_aops = { | |||
| 544 | .write_end = hostfs_write_end, | 492 | .write_end = hostfs_write_end, |
| 545 | }; | 493 | }; |
| 546 | 494 | ||
| 547 | static int init_inode(struct inode *inode, struct dentry *dentry) | 495 | static int read_name(struct inode *ino, char *name) |
| 548 | { | 496 | { |
| 549 | char *name; | 497 | dev_t rdev; |
| 550 | int type, err = -ENOMEM; | 498 | struct hostfs_stat st; |
| 551 | int maj, min; | 499 | int err = stat_file(name, &st, -1); |
| 552 | dev_t rdev = 0; | 500 | if (err) |
| 501 | return err; | ||
| 553 | 502 | ||
| 554 | if (dentry) { | 503 | /* Reencode maj and min with the kernel encoding.*/ |
| 555 | name = dentry_name(dentry, 0); | 504 | rdev = MKDEV(st.maj, st.min); |
| 556 | if (name == NULL) | ||
| 557 | goto out; | ||
| 558 | type = file_type(name, &maj, &min); | ||
| 559 | /* Reencode maj and min with the kernel encoding.*/ | ||
| 560 | rdev = MKDEV(maj, min); | ||
| 561 | kfree(name); | ||
| 562 | } | ||
| 563 | else type = OS_TYPE_DIR; | ||
| 564 | 505 | ||
| 565 | err = 0; | 506 | switch (st.mode & S_IFMT) { |
| 566 | if (type == OS_TYPE_SYMLINK) | 507 | case S_IFLNK: |
| 567 | inode->i_op = &page_symlink_inode_operations; | 508 | ino->i_op = &hostfs_link_iops; |
| 568 | else if (type == OS_TYPE_DIR) | ||
| 569 | inode->i_op = &hostfs_dir_iops; | ||
| 570 | else inode->i_op = &hostfs_iops; | ||
| 571 | |||
| 572 | if (type == OS_TYPE_DIR) inode->i_fop = &hostfs_dir_fops; | ||
| 573 | else inode->i_fop = &hostfs_file_fops; | ||
| 574 | |||
| 575 | if (type == OS_TYPE_SYMLINK) | ||
| 576 | inode->i_mapping->a_ops = &hostfs_link_aops; | ||
| 577 | else inode->i_mapping->a_ops = &hostfs_aops; | ||
| 578 | |||
| 579 | switch (type) { | ||
| 580 | case OS_TYPE_CHARDEV: | ||
| 581 | init_special_inode(inode, S_IFCHR, rdev); | ||
| 582 | break; | 509 | break; |
| 583 | case OS_TYPE_BLOCKDEV: | 510 | case S_IFDIR: |
| 584 | init_special_inode(inode, S_IFBLK, rdev); | 511 | ino->i_op = &hostfs_dir_iops; |
| 512 | ino->i_fop = &hostfs_dir_fops; | ||
| 585 | break; | 513 | break; |
| 586 | case OS_TYPE_FIFO: | 514 | case S_IFCHR: |
| 587 | init_special_inode(inode, S_IFIFO, 0); | 515 | case S_IFBLK: |
| 516 | case S_IFIFO: | ||
| 517 | case S_IFSOCK: | ||
| 518 | init_special_inode(ino, st.mode & S_IFMT, rdev); | ||
| 519 | ino->i_op = &hostfs_iops; | ||
| 588 | break; | 520 | break; |
| 589 | case OS_TYPE_SOCK: | 521 | |
| 590 | init_special_inode(inode, S_IFSOCK, 0); | 522 | default: |
| 591 | break; | 523 | ino->i_op = &hostfs_iops; |
| 592 | } | 524 | ino->i_fop = &hostfs_file_fops; |
| 593 | out: | 525 | ino->i_mapping->a_ops = &hostfs_aops; |
| 594 | return err; | 526 | } |
| 527 | |||
| 528 | ino->i_ino = st.ino; | ||
| 529 | ino->i_mode = st.mode; | ||
| 530 | ino->i_nlink = st.nlink; | ||
| 531 | ino->i_uid = st.uid; | ||
| 532 | ino->i_gid = st.gid; | ||
| 533 | ino->i_atime = st.atime; | ||
| 534 | ino->i_mtime = st.mtime; | ||
| 535 | ino->i_ctime = st.ctime; | ||
| 536 | ino->i_size = st.size; | ||
| 537 | ino->i_blocks = st.blocks; | ||
| 538 | return 0; | ||
| 595 | } | 539 | } |
| 596 | 540 | ||
| 597 | int hostfs_create(struct inode *dir, struct dentry *dentry, int mode, | 541 | int hostfs_create(struct inode *dir, struct dentry *dentry, int mode, |
| @@ -607,12 +551,8 @@ int hostfs_create(struct inode *dir, struct dentry *dentry, int mode, | |||
| 607 | goto out; | 551 | goto out; |
| 608 | } | 552 | } |
| 609 | 553 | ||
| 610 | error = init_inode(inode, dentry); | ||
| 611 | if (error) | ||
| 612 | goto out_put; | ||
| 613 | |||
| 614 | error = -ENOMEM; | 554 | error = -ENOMEM; |
| 615 | name = dentry_name(dentry, 0); | 555 | name = dentry_name(dentry); |
| 616 | if (name == NULL) | 556 | if (name == NULL) |
| 617 | goto out_put; | 557 | goto out_put; |
| 618 | 558 | ||
| @@ -622,9 +562,10 @@ int hostfs_create(struct inode *dir, struct dentry *dentry, int mode, | |||
| 622 | mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH); | 562 | mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH); |
| 623 | if (fd < 0) | 563 | if (fd < 0) |
| 624 | error = fd; | 564 | error = fd; |
| 625 | else error = read_name(inode, name); | 565 | else |
| 566 | error = read_name(inode, name); | ||
| 626 | 567 | ||
| 627 | kfree(name); | 568 | __putname(name); |
| 628 | if (error) | 569 | if (error) |
| 629 | goto out_put; | 570 | goto out_put; |
| 630 | 571 | ||
| @@ -652,17 +593,14 @@ struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry, | |||
| 652 | goto out; | 593 | goto out; |
| 653 | } | 594 | } |
| 654 | 595 | ||
| 655 | err = init_inode(inode, dentry); | ||
| 656 | if (err) | ||
| 657 | goto out_put; | ||
| 658 | |||
| 659 | err = -ENOMEM; | 596 | err = -ENOMEM; |
| 660 | name = dentry_name(dentry, 0); | 597 | name = dentry_name(dentry); |
| 661 | if (name == NULL) | 598 | if (name == NULL) |
| 662 | goto out_put; | 599 | goto out_put; |
| 663 | 600 | ||
| 664 | err = read_name(inode, name); | 601 | err = read_name(inode, name); |
| 665 | kfree(name); | 602 | |
| 603 | __putname(name); | ||
| 666 | if (err == -ENOENT) { | 604 | if (err == -ENOENT) { |
| 667 | iput(inode); | 605 | iput(inode); |
| 668 | inode = NULL; | 606 | inode = NULL; |
| @@ -680,36 +618,21 @@ struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry, | |||
| 680 | return ERR_PTR(err); | 618 | return ERR_PTR(err); |
| 681 | } | 619 | } |
| 682 | 620 | ||
| 683 | static char *inode_dentry_name(struct inode *ino, struct dentry *dentry) | ||
| 684 | { | ||
| 685 | char *file; | ||
| 686 | int len; | ||
| 687 | |||
| 688 | file = inode_name(ino, dentry->d_name.len + 1); | ||
| 689 | if (file == NULL) | ||
| 690 | return NULL; | ||
| 691 | strcat(file, "/"); | ||
| 692 | len = strlen(file); | ||
| 693 | strncat(file, dentry->d_name.name, dentry->d_name.len); | ||
| 694 | file[len + dentry->d_name.len] = '\0'; | ||
| 695 | return file; | ||
| 696 | } | ||
| 697 | |||
| 698 | int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from) | 621 | int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from) |
| 699 | { | 622 | { |
| 700 | char *from_name, *to_name; | 623 | char *from_name, *to_name; |
| 701 | int err; | 624 | int err; |
| 702 | 625 | ||
| 703 | if ((from_name = inode_dentry_name(ino, from)) == NULL) | 626 | if ((from_name = dentry_name(from)) == NULL) |
| 704 | return -ENOMEM; | 627 | return -ENOMEM; |
| 705 | to_name = dentry_name(to, 0); | 628 | to_name = dentry_name(to); |
| 706 | if (to_name == NULL) { | 629 | if (to_name == NULL) { |
| 707 | kfree(from_name); | 630 | __putname(from_name); |
| 708 | return -ENOMEM; | 631 | return -ENOMEM; |
| 709 | } | 632 | } |
| 710 | err = link_file(to_name, from_name); | 633 | err = link_file(to_name, from_name); |
| 711 | kfree(from_name); | 634 | __putname(from_name); |
| 712 | kfree(to_name); | 635 | __putname(to_name); |
| 713 | return err; | 636 | return err; |
| 714 | } | 637 | } |
| 715 | 638 | ||
| @@ -718,13 +641,14 @@ int hostfs_unlink(struct inode *ino, struct dentry *dentry) | |||
| 718 | char *file; | 641 | char *file; |
| 719 | int err; | 642 | int err; |
| 720 | 643 | ||
| 721 | if ((file = inode_dentry_name(ino, dentry)) == NULL) | ||
| 722 | return -ENOMEM; | ||
| 723 | if (append) | 644 | if (append) |
| 724 | return -EPERM; | 645 | return -EPERM; |
| 725 | 646 | ||
| 647 | if ((file = dentry_name(dentry)) == NULL) | ||
| 648 | return -ENOMEM; | ||
| 649 | |||
| 726 | err = unlink_file(file); | 650 | err = unlink_file(file); |
| 727 | kfree(file); | 651 | __putname(file); |
| 728 | return err; | 652 | return err; |
| 729 | } | 653 | } |
| 730 | 654 | ||
| @@ -733,10 +657,10 @@ int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to) | |||
| 733 | char *file; | 657 | char *file; |
| 734 | int err; | 658 | int err; |
| 735 | 659 | ||
| 736 | if ((file = inode_dentry_name(ino, dentry)) == NULL) | 660 | if ((file = dentry_name(dentry)) == NULL) |
| 737 | return -ENOMEM; | 661 | return -ENOMEM; |
| 738 | err = make_symlink(file, to); | 662 | err = make_symlink(file, to); |
| 739 | kfree(file); | 663 | __putname(file); |
| 740 | return err; | 664 | return err; |
| 741 | } | 665 | } |
| 742 | 666 | ||
| @@ -745,10 +669,10 @@ int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode) | |||
| 745 | char *file; | 669 | char *file; |
| 746 | int err; | 670 | int err; |
| 747 | 671 | ||
| 748 | if ((file = inode_dentry_name(ino, dentry)) == NULL) | 672 | if ((file = dentry_name(dentry)) == NULL) |
| 749 | return -ENOMEM; | 673 | return -ENOMEM; |
| 750 | err = do_mkdir(file, mode); | 674 | err = do_mkdir(file, mode); |
| 751 | kfree(file); | 675 | __putname(file); |
| 752 | return err; | 676 | return err; |
| 753 | } | 677 | } |
| 754 | 678 | ||
| @@ -757,10 +681,10 @@ int hostfs_rmdir(struct inode *ino, struct dentry *dentry) | |||
| 757 | char *file; | 681 | char *file; |
| 758 | int err; | 682 | int err; |
| 759 | 683 | ||
| 760 | if ((file = inode_dentry_name(ino, dentry)) == NULL) | 684 | if ((file = dentry_name(dentry)) == NULL) |
| 761 | return -ENOMEM; | 685 | return -ENOMEM; |
| 762 | err = do_rmdir(file); | 686 | err = do_rmdir(file); |
| 763 | kfree(file); | 687 | __putname(file); |
| 764 | return err; | 688 | return err; |
| 765 | } | 689 | } |
| 766 | 690 | ||
| @@ -776,22 +700,20 @@ int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) | |||
| 776 | goto out; | 700 | goto out; |
| 777 | } | 701 | } |
| 778 | 702 | ||
| 779 | err = init_inode(inode, dentry); | ||
| 780 | if (err) | ||
| 781 | goto out_put; | ||
| 782 | |||
| 783 | err = -ENOMEM; | 703 | err = -ENOMEM; |
| 784 | name = dentry_name(dentry, 0); | 704 | name = dentry_name(dentry); |
| 785 | if (name == NULL) | 705 | if (name == NULL) |
| 786 | goto out_put; | 706 | goto out_put; |
| 787 | 707 | ||
| 788 | init_special_inode(inode, mode, dev); | 708 | init_special_inode(inode, mode, dev); |
| 789 | err = do_mknod(name, mode, MAJOR(dev), MINOR(dev)); | 709 | err = do_mknod(name, mode, MAJOR(dev), MINOR(dev)); |
| 790 | if (err) | 710 | if (!err) |
| 791 | goto out_free; | 711 | goto out_free; |
| 792 | 712 | ||
| 793 | err = read_name(inode, name); | 713 | err = read_name(inode, name); |
| 794 | kfree(name); | 714 | __putname(name); |
| 715 | if (err) | ||
| 716 | goto out_put; | ||
| 795 | if (err) | 717 | if (err) |
| 796 | goto out_put; | 718 | goto out_put; |
| 797 | 719 | ||
| @@ -799,7 +721,7 @@ int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) | |||
| 799 | return 0; | 721 | return 0; |
| 800 | 722 | ||
| 801 | out_free: | 723 | out_free: |
| 802 | kfree(name); | 724 | __putname(name); |
| 803 | out_put: | 725 | out_put: |
| 804 | iput(inode); | 726 | iput(inode); |
| 805 | out: | 727 | out: |
| @@ -812,15 +734,15 @@ int hostfs_rename(struct inode *from_ino, struct dentry *from, | |||
| 812 | char *from_name, *to_name; | 734 | char *from_name, *to_name; |
| 813 | int err; | 735 | int err; |
| 814 | 736 | ||
| 815 | if ((from_name = inode_dentry_name(from_ino, from)) == NULL) | 737 | if ((from_name = dentry_name(from)) == NULL) |
| 816 | return -ENOMEM; | 738 | return -ENOMEM; |
| 817 | if ((to_name = inode_dentry_name(to_ino, to)) == NULL) { | 739 | if ((to_name = dentry_name(to)) == NULL) { |
| 818 | kfree(from_name); | 740 | __putname(from_name); |
| 819 | return -ENOMEM; | 741 | return -ENOMEM; |
| 820 | } | 742 | } |
| 821 | err = rename_file(from_name, to_name); | 743 | err = rename_file(from_name, to_name); |
| 822 | kfree(from_name); | 744 | __putname(from_name); |
| 823 | kfree(to_name); | 745 | __putname(to_name); |
| 824 | return err; | 746 | return err; |
| 825 | } | 747 | } |
| 826 | 748 | ||
| @@ -832,7 +754,7 @@ int hostfs_permission(struct inode *ino, int desired) | |||
| 832 | if (desired & MAY_READ) r = 1; | 754 | if (desired & MAY_READ) r = 1; |
| 833 | if (desired & MAY_WRITE) w = 1; | 755 | if (desired & MAY_WRITE) w = 1; |
| 834 | if (desired & MAY_EXEC) x = 1; | 756 | if (desired & MAY_EXEC) x = 1; |
| 835 | name = inode_name(ino, 0); | 757 | name = inode_name(ino); |
| 836 | if (name == NULL) | 758 | if (name == NULL) |
| 837 | return -ENOMEM; | 759 | return -ENOMEM; |
| 838 | 760 | ||
| @@ -841,7 +763,7 @@ int hostfs_permission(struct inode *ino, int desired) | |||
| 841 | err = 0; | 763 | err = 0; |
| 842 | else | 764 | else |
| 843 | err = access_file(name, r, w, x); | 765 | err = access_file(name, r, w, x); |
| 844 | kfree(name); | 766 | __putname(name); |
| 845 | if (!err) | 767 | if (!err) |
| 846 | err = generic_permission(ino, desired, NULL); | 768 | err = generic_permission(ino, desired, NULL); |
| 847 | return err; | 769 | return err; |
| @@ -849,13 +771,14 @@ int hostfs_permission(struct inode *ino, int desired) | |||
| 849 | 771 | ||
| 850 | int hostfs_setattr(struct dentry *dentry, struct iattr *attr) | 772 | int hostfs_setattr(struct dentry *dentry, struct iattr *attr) |
| 851 | { | 773 | { |
| 774 | struct inode *inode = dentry->d_inode; | ||
| 852 | struct hostfs_iattr attrs; | 775 | struct hostfs_iattr attrs; |
| 853 | char *name; | 776 | char *name; |
| 854 | int err; | 777 | int err; |
| 855 | 778 | ||
| 856 | int fd = HOSTFS_I(dentry->d_inode)->fd; | 779 | int fd = HOSTFS_I(inode)->fd; |
| 857 | 780 | ||
| 858 | err = inode_change_ok(dentry->d_inode, attr); | 781 | err = inode_change_ok(inode, attr); |
| 859 | if (err) | 782 | if (err) |
| 860 | return err; | 783 | return err; |
| 861 | 784 | ||
| @@ -897,15 +820,26 @@ int hostfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 897 | if (attr->ia_valid & ATTR_MTIME_SET) { | 820 | if (attr->ia_valid & ATTR_MTIME_SET) { |
| 898 | attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET; | 821 | attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET; |
| 899 | } | 822 | } |
| 900 | name = dentry_name(dentry, 0); | 823 | name = dentry_name(dentry); |
| 901 | if (name == NULL) | 824 | if (name == NULL) |
| 902 | return -ENOMEM; | 825 | return -ENOMEM; |
| 903 | err = set_attr(name, &attrs, fd); | 826 | err = set_attr(name, &attrs, fd); |
| 904 | kfree(name); | 827 | __putname(name); |
| 905 | if (err) | 828 | if (err) |
| 906 | return err; | 829 | return err; |
| 907 | 830 | ||
| 908 | return inode_setattr(dentry->d_inode, attr); | 831 | if ((attr->ia_valid & ATTR_SIZE) && |
| 832 | attr->ia_size != i_size_read(inode)) { | ||
| 833 | int error; | ||
| 834 | |||
| 835 | error = vmtruncate(inode, attr->ia_size); | ||
| 836 | if (err) | ||
| 837 | return err; | ||
| 838 | } | ||
| 839 | |||
| 840 | setattr_copy(inode, attr); | ||
| 841 | mark_inode_dirty(inode); | ||
| 842 | return 0; | ||
| 909 | } | 843 | } |
| 910 | 844 | ||
| 911 | static const struct inode_operations hostfs_iops = { | 845 | static const struct inode_operations hostfs_iops = { |
| @@ -935,32 +869,41 @@ static const struct inode_operations hostfs_dir_iops = { | |||
| 935 | .setattr = hostfs_setattr, | 869 | .setattr = hostfs_setattr, |
| 936 | }; | 870 | }; |
| 937 | 871 | ||
| 938 | int hostfs_link_readpage(struct file *file, struct page *page) | 872 | static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd) |
| 939 | { | 873 | { |
| 940 | char *buffer, *name; | 874 | char *link = __getname(); |
| 941 | int err; | 875 | if (link) { |
| 942 | 876 | char *path = dentry_name(dentry); | |
| 943 | buffer = kmap(page); | 877 | int err = -ENOMEM; |
| 944 | name = inode_name(page->mapping->host, 0); | 878 | if (path) { |
| 945 | if (name == NULL) | 879 | int err = hostfs_do_readlink(path, link, PATH_MAX); |
| 946 | return -ENOMEM; | 880 | if (err == PATH_MAX) |
| 947 | err = hostfs_do_readlink(name, buffer, PAGE_CACHE_SIZE); | 881 | err = -E2BIG; |
| 948 | kfree(name); | 882 | __putname(path); |
| 949 | if (err == PAGE_CACHE_SIZE) | 883 | } |
| 950 | err = -E2BIG; | 884 | if (err < 0) { |
| 951 | else if (err > 0) { | 885 | __putname(link); |
| 952 | flush_dcache_page(page); | 886 | link = ERR_PTR(err); |
| 953 | SetPageUptodate(page); | 887 | } |
| 954 | if (PageError(page)) ClearPageError(page); | 888 | } else { |
| 955 | err = 0; | 889 | link = ERR_PTR(-ENOMEM); |
| 956 | } | 890 | } |
| 957 | kunmap(page); | 891 | |
| 958 | unlock_page(page); | 892 | nd_set_link(nd, link); |
| 959 | return err; | 893 | return NULL; |
| 960 | } | 894 | } |
| 961 | 895 | ||
| 962 | static const struct address_space_operations hostfs_link_aops = { | 896 | static void hostfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie) |
| 963 | .readpage = hostfs_link_readpage, | 897 | { |
| 898 | char *s = nd_get_link(nd); | ||
| 899 | if (!IS_ERR(s)) | ||
| 900 | __putname(s); | ||
| 901 | } | ||
| 902 | |||
| 903 | static const struct inode_operations hostfs_link_iops = { | ||
| 904 | .readlink = generic_readlink, | ||
| 905 | .follow_link = hostfs_follow_link, | ||
| 906 | .put_link = hostfs_put_link, | ||
| 964 | }; | 907 | }; |
| 965 | 908 | ||
| 966 | static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent) | 909 | static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent) |
| @@ -980,49 +923,41 @@ static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent) | |||
| 980 | req_root = ""; | 923 | req_root = ""; |
| 981 | 924 | ||
| 982 | err = -ENOMEM; | 925 | err = -ENOMEM; |
| 983 | host_root_path = kmalloc(strlen(root_ino) + 1 | 926 | sb->s_fs_info = host_root_path = |
| 984 | + strlen(req_root) + 1, GFP_KERNEL); | 927 | kmalloc(strlen(root_ino) + strlen(req_root) + 2, GFP_KERNEL); |
| 985 | if (host_root_path == NULL) | 928 | if (host_root_path == NULL) |
| 986 | goto out; | 929 | goto out; |
| 987 | 930 | ||
| 988 | sprintf(host_root_path, "%s/%s", root_ino, req_root); | 931 | sprintf(host_root_path, "%s/%s", root_ino, req_root); |
| 989 | 932 | ||
| 990 | root_inode = hostfs_iget(sb); | 933 | root_inode = new_inode(sb); |
| 991 | if (IS_ERR(root_inode)) { | 934 | if (!root_inode) |
| 992 | err = PTR_ERR(root_inode); | 935 | goto out; |
| 993 | goto out_free; | ||
| 994 | } | ||
| 995 | 936 | ||
| 996 | err = init_inode(root_inode, NULL); | 937 | err = read_name(root_inode, host_root_path); |
| 997 | if (err) | 938 | if (err) |
| 998 | goto out_put; | 939 | goto out_put; |
| 999 | 940 | ||
| 1000 | HOSTFS_I(root_inode)->host_filename = host_root_path; | 941 | if (S_ISLNK(root_inode->i_mode)) { |
| 1001 | /* | 942 | char *name = follow_link(host_root_path); |
| 1002 | * Avoid that in the error path, iput(root_inode) frees again | 943 | if (IS_ERR(name)) |
| 1003 | * host_root_path through hostfs_destroy_inode! | 944 | err = PTR_ERR(name); |
| 1004 | */ | 945 | else |
| 1005 | host_root_path = NULL; | 946 | err = read_name(root_inode, name); |
| 947 | kfree(name); | ||
| 948 | if (err) | ||
| 949 | goto out_put; | ||
| 950 | } | ||
| 1006 | 951 | ||
| 1007 | err = -ENOMEM; | 952 | err = -ENOMEM; |
| 1008 | sb->s_root = d_alloc_root(root_inode); | 953 | sb->s_root = d_alloc_root(root_inode); |
| 1009 | if (sb->s_root == NULL) | 954 | if (sb->s_root == NULL) |
| 1010 | goto out_put; | 955 | goto out_put; |
| 1011 | 956 | ||
| 1012 | err = hostfs_read_inode(root_inode); | ||
| 1013 | if (err) { | ||
| 1014 | /* No iput in this case because the dput does that for us */ | ||
| 1015 | dput(sb->s_root); | ||
| 1016 | sb->s_root = NULL; | ||
| 1017 | goto out; | ||
| 1018 | } | ||
| 1019 | |||
| 1020 | return 0; | 957 | return 0; |
| 1021 | 958 | ||
| 1022 | out_put: | 959 | out_put: |
| 1023 | iput(root_inode); | 960 | iput(root_inode); |
| 1024 | out_free: | ||
| 1025 | kfree(host_root_path); | ||
| 1026 | out: | 961 | out: |
| 1027 | return err; | 962 | return err; |
| 1028 | } | 963 | } |
| @@ -1034,11 +969,17 @@ static int hostfs_read_sb(struct file_system_type *type, | |||
| 1034 | return get_sb_nodev(type, flags, data, hostfs_fill_sb_common, mnt); | 969 | return get_sb_nodev(type, flags, data, hostfs_fill_sb_common, mnt); |
| 1035 | } | 970 | } |
| 1036 | 971 | ||
| 972 | static void hostfs_kill_sb(struct super_block *s) | ||
| 973 | { | ||
| 974 | kill_anon_super(s); | ||
| 975 | kfree(s->s_fs_info); | ||
| 976 | } | ||
| 977 | |||
| 1037 | static struct file_system_type hostfs_type = { | 978 | static struct file_system_type hostfs_type = { |
| 1038 | .owner = THIS_MODULE, | 979 | .owner = THIS_MODULE, |
| 1039 | .name = "hostfs", | 980 | .name = "hostfs", |
| 1040 | .get_sb = hostfs_read_sb, | 981 | .get_sb = hostfs_read_sb, |
| 1041 | .kill_sb = kill_anon_super, | 982 | .kill_sb = hostfs_kill_sb, |
| 1042 | .fs_flags = 0, | 983 | .fs_flags = 0, |
| 1043 | }; | 984 | }; |
| 1044 | 985 | ||
diff --git a/fs/hostfs/hostfs_user.c b/fs/hostfs/hostfs_user.c index b79424f93282..6777aa06ce2c 100644 --- a/fs/hostfs/hostfs_user.c +++ b/fs/hostfs/hostfs_user.c | |||
| @@ -19,11 +19,27 @@ | |||
| 19 | #include "user.h" | 19 | #include "user.h" |
| 20 | #include <utime.h> | 20 | #include <utime.h> |
| 21 | 21 | ||
| 22 | int stat_file(const char *path, unsigned long long *inode_out, int *mode_out, | 22 | static void stat64_to_hostfs(const struct stat64 *buf, struct hostfs_stat *p) |
| 23 | int *nlink_out, int *uid_out, int *gid_out, | 23 | { |
| 24 | unsigned long long *size_out, struct timespec *atime_out, | 24 | p->ino = buf->st_ino; |
| 25 | struct timespec *mtime_out, struct timespec *ctime_out, | 25 | p->mode = buf->st_mode; |
| 26 | int *blksize_out, unsigned long long *blocks_out, int fd) | 26 | p->nlink = buf->st_nlink; |
| 27 | p->uid = buf->st_uid; | ||
| 28 | p->gid = buf->st_gid; | ||
| 29 | p->size = buf->st_size; | ||
| 30 | p->atime.tv_sec = buf->st_atime; | ||
| 31 | p->atime.tv_nsec = 0; | ||
| 32 | p->ctime.tv_sec = buf->st_ctime; | ||
| 33 | p->ctime.tv_nsec = 0; | ||
| 34 | p->mtime.tv_sec = buf->st_mtime; | ||
| 35 | p->mtime.tv_nsec = 0; | ||
| 36 | p->blksize = buf->st_blksize; | ||
| 37 | p->blocks = buf->st_blocks; | ||
| 38 | p->maj = os_major(buf->st_rdev); | ||
| 39 | p->min = os_minor(buf->st_rdev); | ||
| 40 | } | ||
| 41 | |||
| 42 | int stat_file(const char *path, struct hostfs_stat *p, int fd) | ||
| 27 | { | 43 | { |
| 28 | struct stat64 buf; | 44 | struct stat64 buf; |
| 29 | 45 | ||
| @@ -33,68 +49,10 @@ int stat_file(const char *path, unsigned long long *inode_out, int *mode_out, | |||
| 33 | } else if (lstat64(path, &buf) < 0) { | 49 | } else if (lstat64(path, &buf) < 0) { |
| 34 | return -errno; | 50 | return -errno; |
| 35 | } | 51 | } |
| 36 | 52 | stat64_to_hostfs(&buf, p); | |
| 37 | if (inode_out != NULL) | ||
| 38 | *inode_out = buf.st_ino; | ||
| 39 | if (mode_out != NULL) | ||
| 40 | *mode_out = buf.st_mode; | ||
| 41 | if (nlink_out != NULL) | ||
| 42 | *nlink_out = buf.st_nlink; | ||
| 43 | if (uid_out != NULL) | ||
| 44 | *uid_out = buf.st_uid; | ||
| 45 | if (gid_out != NULL) | ||
| 46 | *gid_out = buf.st_gid; | ||
| 47 | if (size_out != NULL) | ||
| 48 | *size_out = buf.st_size; | ||
| 49 | if (atime_out != NULL) { | ||
| 50 | atime_out->tv_sec = buf.st_atime; | ||
| 51 | atime_out->tv_nsec = 0; | ||
| 52 | } | ||
| 53 | if (mtime_out != NULL) { | ||
| 54 | mtime_out->tv_sec = buf.st_mtime; | ||
| 55 | mtime_out->tv_nsec = 0; | ||
| 56 | } | ||
| 57 | if (ctime_out != NULL) { | ||
| 58 | ctime_out->tv_sec = buf.st_ctime; | ||
| 59 | ctime_out->tv_nsec = 0; | ||
| 60 | } | ||
| 61 | if (blksize_out != NULL) | ||
| 62 | *blksize_out = buf.st_blksize; | ||
| 63 | if (blocks_out != NULL) | ||
| 64 | *blocks_out = buf.st_blocks; | ||
| 65 | return 0; | 53 | return 0; |
| 66 | } | 54 | } |
| 67 | 55 | ||
| 68 | int file_type(const char *path, int *maj, int *min) | ||
| 69 | { | ||
| 70 | struct stat64 buf; | ||
| 71 | |||
| 72 | if (lstat64(path, &buf) < 0) | ||
| 73 | return -errno; | ||
| 74 | /* | ||
| 75 | * We cannot pass rdev as is because glibc and the kernel disagree | ||
| 76 | * about its definition. | ||
| 77 | */ | ||
| 78 | if (maj != NULL) | ||
| 79 | *maj = major(buf.st_rdev); | ||
| 80 | if (min != NULL) | ||
| 81 | *min = minor(buf.st_rdev); | ||
| 82 | |||
| 83 | if (S_ISDIR(buf.st_mode)) | ||
| 84 | return OS_TYPE_DIR; | ||
| 85 | else if (S_ISLNK(buf.st_mode)) | ||
| 86 | return OS_TYPE_SYMLINK; | ||
| 87 | else if (S_ISCHR(buf.st_mode)) | ||
| 88 | return OS_TYPE_CHARDEV; | ||
| 89 | else if (S_ISBLK(buf.st_mode)) | ||
| 90 | return OS_TYPE_BLOCKDEV; | ||
| 91 | else if (S_ISFIFO(buf.st_mode)) | ||
| 92 | return OS_TYPE_FIFO; | ||
| 93 | else if (S_ISSOCK(buf.st_mode)) | ||
| 94 | return OS_TYPE_SOCK; | ||
| 95 | else return OS_TYPE_FILE; | ||
| 96 | } | ||
| 97 | |||
| 98 | int access_file(char *path, int r, int w, int x) | 56 | int access_file(char *path, int r, int w, int x) |
| 99 | { | 57 | { |
| 100 | int mode = 0; | 58 | int mode = 0; |
| @@ -202,6 +160,11 @@ int fsync_file(int fd, int datasync) | |||
| 202 | return 0; | 160 | return 0; |
| 203 | } | 161 | } |
| 204 | 162 | ||
| 163 | int replace_file(int oldfd, int fd) | ||
| 164 | { | ||
| 165 | return dup2(oldfd, fd); | ||
| 166 | } | ||
| 167 | |||
| 205 | void close_file(void *stream) | 168 | void close_file(void *stream) |
| 206 | { | 169 | { |
| 207 | close(*((int *) stream)); | 170 | close(*((int *) stream)); |
| @@ -235,8 +198,8 @@ int file_create(char *name, int ur, int uw, int ux, int gr, | |||
| 235 | 198 | ||
| 236 | int set_attr(const char *file, struct hostfs_iattr *attrs, int fd) | 199 | int set_attr(const char *file, struct hostfs_iattr *attrs, int fd) |
| 237 | { | 200 | { |
| 201 | struct hostfs_stat st; | ||
| 238 | struct timeval times[2]; | 202 | struct timeval times[2]; |
| 239 | struct timespec atime_ts, mtime_ts; | ||
| 240 | int err, ma; | 203 | int err, ma; |
| 241 | 204 | ||
| 242 | if (attrs->ia_valid & HOSTFS_ATTR_MODE) { | 205 | if (attrs->ia_valid & HOSTFS_ATTR_MODE) { |
| @@ -279,15 +242,14 @@ int set_attr(const char *file, struct hostfs_iattr *attrs, int fd) | |||
| 279 | */ | 242 | */ |
| 280 | ma = (HOSTFS_ATTR_ATIME_SET | HOSTFS_ATTR_MTIME_SET); | 243 | ma = (HOSTFS_ATTR_ATIME_SET | HOSTFS_ATTR_MTIME_SET); |
| 281 | if (attrs->ia_valid & ma) { | 244 | if (attrs->ia_valid & ma) { |
| 282 | err = stat_file(file, NULL, NULL, NULL, NULL, NULL, NULL, | 245 | err = stat_file(file, &st, fd); |
| 283 | &atime_ts, &mtime_ts, NULL, NULL, NULL, fd); | ||
| 284 | if (err != 0) | 246 | if (err != 0) |
| 285 | return err; | 247 | return err; |
| 286 | 248 | ||
| 287 | times[0].tv_sec = atime_ts.tv_sec; | 249 | times[0].tv_sec = st.atime.tv_sec; |
| 288 | times[0].tv_usec = atime_ts.tv_nsec / 1000; | 250 | times[0].tv_usec = st.atime.tv_nsec / 1000; |
| 289 | times[1].tv_sec = mtime_ts.tv_sec; | 251 | times[1].tv_sec = st.mtime.tv_sec; |
| 290 | times[1].tv_usec = mtime_ts.tv_nsec / 1000; | 252 | times[1].tv_usec = st.mtime.tv_nsec / 1000; |
| 291 | 253 | ||
| 292 | if (attrs->ia_valid & HOSTFS_ATTR_ATIME_SET) { | 254 | if (attrs->ia_valid & HOSTFS_ATTR_ATIME_SET) { |
| 293 | times[0].tv_sec = attrs->ia_atime.tv_sec; | 255 | times[0].tv_sec = attrs->ia_atime.tv_sec; |
| @@ -308,9 +270,9 @@ int set_attr(const char *file, struct hostfs_iattr *attrs, int fd) | |||
| 308 | 270 | ||
| 309 | /* Note: ctime is not handled */ | 271 | /* Note: ctime is not handled */ |
| 310 | if (attrs->ia_valid & (HOSTFS_ATTR_ATIME | HOSTFS_ATTR_MTIME)) { | 272 | if (attrs->ia_valid & (HOSTFS_ATTR_ATIME | HOSTFS_ATTR_MTIME)) { |
| 311 | err = stat_file(file, NULL, NULL, NULL, NULL, NULL, NULL, | 273 | err = stat_file(file, &st, fd); |
| 312 | &attrs->ia_atime, &attrs->ia_mtime, NULL, | 274 | attrs->ia_atime = st.atime; |
| 313 | NULL, NULL, fd); | 275 | attrs->ia_mtime = st.mtime; |
| 314 | if (err != 0) | 276 | if (err != 0) |
| 315 | return err; | 277 | return err; |
| 316 | } | 278 | } |
| @@ -361,7 +323,7 @@ int do_mknod(const char *file, int mode, unsigned int major, unsigned int minor) | |||
| 361 | { | 323 | { |
| 362 | int err; | 324 | int err; |
| 363 | 325 | ||
| 364 | err = mknod(file, mode, makedev(major, minor)); | 326 | err = mknod(file, mode, os_makedev(major, minor)); |
| 365 | if (err) | 327 | if (err) |
| 366 | return -errno; | 328 | return -errno; |
| 367 | return 0; | 329 | return 0; |
diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c index a9ae9bfa752f..c0340887c7ea 100644 --- a/fs/hpfs/file.c +++ b/fs/hpfs/file.c | |||
| @@ -97,10 +97,19 @@ static int hpfs_write_begin(struct file *file, struct address_space *mapping, | |||
| 97 | loff_t pos, unsigned len, unsigned flags, | 97 | loff_t pos, unsigned len, unsigned flags, |
| 98 | struct page **pagep, void **fsdata) | 98 | struct page **pagep, void **fsdata) |
| 99 | { | 99 | { |
| 100 | int ret; | ||
| 101 | |||
| 100 | *pagep = NULL; | 102 | *pagep = NULL; |
| 101 | return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, | 103 | ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, |
| 102 | hpfs_get_block, | 104 | hpfs_get_block, |
| 103 | &hpfs_i(mapping->host)->mmu_private); | 105 | &hpfs_i(mapping->host)->mmu_private); |
| 106 | if (unlikely(ret)) { | ||
| 107 | loff_t isize = mapping->host->i_size; | ||
| 108 | if (pos + len > isize) | ||
| 109 | vmtruncate(mapping->host, isize); | ||
| 110 | } | ||
| 111 | |||
| 112 | return ret; | ||
| 104 | } | 113 | } |
| 105 | 114 | ||
| 106 | static sector_t _hpfs_bmap(struct address_space *mapping, sector_t block) | 115 | static sector_t _hpfs_bmap(struct address_space *mapping, sector_t block) |
diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h index 75f9d4324851..b59eac0232a0 100644 --- a/fs/hpfs/hpfs_fn.h +++ b/fs/hpfs/hpfs_fn.h | |||
| @@ -281,7 +281,7 @@ void hpfs_write_inode(struct inode *); | |||
| 281 | void hpfs_write_inode_nolock(struct inode *); | 281 | void hpfs_write_inode_nolock(struct inode *); |
| 282 | int hpfs_setattr(struct dentry *, struct iattr *); | 282 | int hpfs_setattr(struct dentry *, struct iattr *); |
| 283 | void hpfs_write_if_changed(struct inode *); | 283 | void hpfs_write_if_changed(struct inode *); |
| 284 | void hpfs_delete_inode(struct inode *); | 284 | void hpfs_evict_inode(struct inode *); |
| 285 | 285 | ||
| 286 | /* map.c */ | 286 | /* map.c */ |
| 287 | 287 | ||
diff --git a/fs/hpfs/inode.c b/fs/hpfs/inode.c index 1042a9bc97f3..56f0da1cfd10 100644 --- a/fs/hpfs/inode.c +++ b/fs/hpfs/inode.c | |||
| @@ -277,9 +277,15 @@ int hpfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 277 | if (error) | 277 | if (error) |
| 278 | goto out_unlock; | 278 | goto out_unlock; |
| 279 | 279 | ||
| 280 | error = inode_setattr(inode, attr); | 280 | if ((attr->ia_valid & ATTR_SIZE) && |
| 281 | if (error) | 281 | attr->ia_size != i_size_read(inode)) { |
| 282 | goto out_unlock; | 282 | error = vmtruncate(inode, attr->ia_size); |
| 283 | if (error) | ||
| 284 | return error; | ||
| 285 | } | ||
| 286 | |||
| 287 | setattr_copy(inode, attr); | ||
| 288 | mark_inode_dirty(inode); | ||
| 283 | 289 | ||
| 284 | hpfs_write_inode(inode); | 290 | hpfs_write_inode(inode); |
| 285 | 291 | ||
| @@ -296,11 +302,13 @@ void hpfs_write_if_changed(struct inode *inode) | |||
| 296 | hpfs_write_inode(inode); | 302 | hpfs_write_inode(inode); |
| 297 | } | 303 | } |
| 298 | 304 | ||
| 299 | void hpfs_delete_inode(struct inode *inode) | 305 | void hpfs_evict_inode(struct inode *inode) |
| 300 | { | 306 | { |
| 301 | truncate_inode_pages(&inode->i_data, 0); | 307 | truncate_inode_pages(&inode->i_data, 0); |
| 302 | lock_kernel(); | 308 | end_writeback(inode); |
| 303 | hpfs_remove_fnode(inode->i_sb, inode->i_ino); | 309 | if (!inode->i_nlink) { |
| 304 | unlock_kernel(); | 310 | lock_kernel(); |
| 305 | clear_inode(inode); | 311 | hpfs_remove_fnode(inode->i_sb, inode->i_ino); |
| 312 | unlock_kernel(); | ||
| 313 | } | ||
| 306 | } | 314 | } |
diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index aa53842c599c..2607010be2fe 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c | |||
| @@ -450,7 +450,7 @@ static const struct super_operations hpfs_sops = | |||
| 450 | { | 450 | { |
| 451 | .alloc_inode = hpfs_alloc_inode, | 451 | .alloc_inode = hpfs_alloc_inode, |
| 452 | .destroy_inode = hpfs_destroy_inode, | 452 | .destroy_inode = hpfs_destroy_inode, |
| 453 | .delete_inode = hpfs_delete_inode, | 453 | .evict_inode = hpfs_evict_inode, |
| 454 | .put_super = hpfs_put_super, | 454 | .put_super = hpfs_put_super, |
| 455 | .statfs = hpfs_statfs, | 455 | .statfs = hpfs_statfs, |
| 456 | .remount_fs = hpfs_remount_fs, | 456 | .remount_fs = hpfs_remount_fs, |
diff --git a/fs/hppfs/hppfs.c b/fs/hppfs/hppfs.c index 826c3f9d29ac..7b027720d820 100644 --- a/fs/hppfs/hppfs.c +++ b/fs/hppfs/hppfs.c | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
| 16 | #include <linux/statfs.h> | 16 | #include <linux/statfs.h> |
| 17 | #include <linux/types.h> | 17 | #include <linux/types.h> |
| 18 | #include <linux/pid_namespace.h> | ||
| 18 | #include <asm/uaccess.h> | 19 | #include <asm/uaccess.h> |
| 19 | #include "os.h" | 20 | #include "os.h" |
| 20 | 21 | ||
| @@ -623,12 +624,11 @@ static struct inode *hppfs_alloc_inode(struct super_block *sb) | |||
| 623 | return &hi->vfs_inode; | 624 | return &hi->vfs_inode; |
| 624 | } | 625 | } |
| 625 | 626 | ||
| 626 | void hppfs_delete_inode(struct inode *ino) | 627 | void hppfs_evict_inode(struct inode *ino) |
| 627 | { | 628 | { |
| 629 | end_writeback(ino); | ||
| 628 | dput(HPPFS_I(ino)->proc_dentry); | 630 | dput(HPPFS_I(ino)->proc_dentry); |
| 629 | mntput(ino->i_sb->s_fs_info); | 631 | mntput(ino->i_sb->s_fs_info); |
| 630 | |||
| 631 | clear_inode(ino); | ||
| 632 | } | 632 | } |
| 633 | 633 | ||
| 634 | static void hppfs_destroy_inode(struct inode *inode) | 634 | static void hppfs_destroy_inode(struct inode *inode) |
| @@ -639,7 +639,7 @@ static void hppfs_destroy_inode(struct inode *inode) | |||
| 639 | static const struct super_operations hppfs_sbops = { | 639 | static const struct super_operations hppfs_sbops = { |
| 640 | .alloc_inode = hppfs_alloc_inode, | 640 | .alloc_inode = hppfs_alloc_inode, |
| 641 | .destroy_inode = hppfs_destroy_inode, | 641 | .destroy_inode = hppfs_destroy_inode, |
| 642 | .delete_inode = hppfs_delete_inode, | 642 | .evict_inode = hppfs_evict_inode, |
| 643 | .statfs = hppfs_statfs, | 643 | .statfs = hppfs_statfs, |
| 644 | }; | 644 | }; |
| 645 | 645 | ||
diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index a4e9a7ec3691..6e5bd42f3860 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c | |||
| @@ -371,27 +371,10 @@ static void truncate_hugepages(struct inode *inode, loff_t lstart) | |||
| 371 | hugetlb_unreserve_pages(inode, start, freed); | 371 | hugetlb_unreserve_pages(inode, start, freed); |
| 372 | } | 372 | } |
| 373 | 373 | ||
| 374 | static void hugetlbfs_delete_inode(struct inode *inode) | 374 | static void hugetlbfs_evict_inode(struct inode *inode) |
| 375 | { | 375 | { |
| 376 | truncate_hugepages(inode, 0); | 376 | truncate_hugepages(inode, 0); |
| 377 | clear_inode(inode); | 377 | end_writeback(inode); |
| 378 | } | ||
| 379 | |||
| 380 | static void hugetlbfs_forget_inode(struct inode *inode) __releases(inode_lock) | ||
| 381 | { | ||
| 382 | if (generic_detach_inode(inode)) { | ||
| 383 | truncate_hugepages(inode, 0); | ||
| 384 | clear_inode(inode); | ||
| 385 | destroy_inode(inode); | ||
| 386 | } | ||
| 387 | } | ||
| 388 | |||
| 389 | static void hugetlbfs_drop_inode(struct inode *inode) | ||
| 390 | { | ||
| 391 | if (!inode->i_nlink) | ||
| 392 | generic_delete_inode(inode); | ||
| 393 | else | ||
| 394 | hugetlbfs_forget_inode(inode); | ||
| 395 | } | 378 | } |
| 396 | 379 | ||
| 397 | static inline void | 380 | static inline void |
| @@ -448,19 +431,20 @@ static int hugetlbfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 448 | 431 | ||
| 449 | error = inode_change_ok(inode, attr); | 432 | error = inode_change_ok(inode, attr); |
| 450 | if (error) | 433 | if (error) |
| 451 | goto out; | 434 | return error; |
| 452 | 435 | ||
| 453 | if (ia_valid & ATTR_SIZE) { | 436 | if (ia_valid & ATTR_SIZE) { |
| 454 | error = -EINVAL; | 437 | error = -EINVAL; |
| 455 | if (!(attr->ia_size & ~huge_page_mask(h))) | 438 | if (attr->ia_size & ~huge_page_mask(h)) |
| 456 | error = hugetlb_vmtruncate(inode, attr->ia_size); | 439 | return -EINVAL; |
| 440 | error = hugetlb_vmtruncate(inode, attr->ia_size); | ||
| 457 | if (error) | 441 | if (error) |
| 458 | goto out; | 442 | return error; |
| 459 | attr->ia_valid &= ~ATTR_SIZE; | ||
| 460 | } | 443 | } |
| 461 | error = inode_setattr(inode, attr); | 444 | |
| 462 | out: | 445 | setattr_copy(inode, attr); |
| 463 | return error; | 446 | mark_inode_dirty(inode); |
| 447 | return 0; | ||
| 464 | } | 448 | } |
| 465 | 449 | ||
| 466 | static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid, | 450 | static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid, |
| @@ -712,9 +696,8 @@ static const struct inode_operations hugetlbfs_inode_operations = { | |||
| 712 | static const struct super_operations hugetlbfs_ops = { | 696 | static const struct super_operations hugetlbfs_ops = { |
| 713 | .alloc_inode = hugetlbfs_alloc_inode, | 697 | .alloc_inode = hugetlbfs_alloc_inode, |
| 714 | .destroy_inode = hugetlbfs_destroy_inode, | 698 | .destroy_inode = hugetlbfs_destroy_inode, |
| 699 | .evict_inode = hugetlbfs_evict_inode, | ||
| 715 | .statfs = hugetlbfs_statfs, | 700 | .statfs = hugetlbfs_statfs, |
| 716 | .delete_inode = hugetlbfs_delete_inode, | ||
| 717 | .drop_inode = hugetlbfs_drop_inode, | ||
| 718 | .put_super = hugetlbfs_put_super, | 701 | .put_super = hugetlbfs_put_super, |
| 719 | .show_options = generic_show_options, | 702 | .show_options = generic_show_options, |
| 720 | }; | 703 | }; |
diff --git a/fs/inode.c b/fs/inode.c index 722860b323a9..86464332e590 100644 --- a/fs/inode.c +++ b/fs/inode.c | |||
| @@ -20,7 +20,6 @@ | |||
| 20 | #include <linux/pagemap.h> | 20 | #include <linux/pagemap.h> |
| 21 | #include <linux/cdev.h> | 21 | #include <linux/cdev.h> |
| 22 | #include <linux/bootmem.h> | 22 | #include <linux/bootmem.h> |
| 23 | #include <linux/inotify.h> | ||
| 24 | #include <linux/fsnotify.h> | 23 | #include <linux/fsnotify.h> |
| 25 | #include <linux/mount.h> | 24 | #include <linux/mount.h> |
| 26 | #include <linux/async.h> | 25 | #include <linux/async.h> |
| @@ -264,12 +263,8 @@ void inode_init_once(struct inode *inode) | |||
| 264 | INIT_RAW_PRIO_TREE_ROOT(&inode->i_data.i_mmap); | 263 | INIT_RAW_PRIO_TREE_ROOT(&inode->i_data.i_mmap); |
| 265 | INIT_LIST_HEAD(&inode->i_data.i_mmap_nonlinear); | 264 | INIT_LIST_HEAD(&inode->i_data.i_mmap_nonlinear); |
| 266 | i_size_ordered_init(inode); | 265 | i_size_ordered_init(inode); |
| 267 | #ifdef CONFIG_INOTIFY | ||
| 268 | INIT_LIST_HEAD(&inode->inotify_watches); | ||
| 269 | mutex_init(&inode->inotify_mutex); | ||
| 270 | #endif | ||
| 271 | #ifdef CONFIG_FSNOTIFY | 266 | #ifdef CONFIG_FSNOTIFY |
| 272 | INIT_HLIST_HEAD(&inode->i_fsnotify_mark_entries); | 267 | INIT_HLIST_HEAD(&inode->i_fsnotify_marks); |
| 273 | #endif | 268 | #endif |
| 274 | } | 269 | } |
| 275 | EXPORT_SYMBOL(inode_init_once); | 270 | EXPORT_SYMBOL(inode_init_once); |
| @@ -294,32 +289,34 @@ void __iget(struct inode *inode) | |||
| 294 | inodes_stat.nr_unused--; | 289 | inodes_stat.nr_unused--; |
| 295 | } | 290 | } |
| 296 | 291 | ||
| 297 | /** | 292 | void end_writeback(struct inode *inode) |
| 298 | * clear_inode - clear an inode | ||
| 299 | * @inode: inode to clear | ||
| 300 | * | ||
| 301 | * This is called by the filesystem to tell us | ||
| 302 | * that the inode is no longer useful. We just | ||
| 303 | * terminate it with extreme prejudice. | ||
| 304 | */ | ||
| 305 | void clear_inode(struct inode *inode) | ||
| 306 | { | 293 | { |
| 307 | might_sleep(); | 294 | might_sleep(); |
| 308 | invalidate_inode_buffers(inode); | ||
| 309 | |||
| 310 | BUG_ON(inode->i_data.nrpages); | 295 | BUG_ON(inode->i_data.nrpages); |
| 296 | BUG_ON(!list_empty(&inode->i_data.private_list)); | ||
| 311 | BUG_ON(!(inode->i_state & I_FREEING)); | 297 | BUG_ON(!(inode->i_state & I_FREEING)); |
| 312 | BUG_ON(inode->i_state & I_CLEAR); | 298 | BUG_ON(inode->i_state & I_CLEAR); |
| 313 | inode_sync_wait(inode); | 299 | inode_sync_wait(inode); |
| 314 | if (inode->i_sb->s_op->clear_inode) | 300 | inode->i_state = I_FREEING | I_CLEAR; |
| 315 | inode->i_sb->s_op->clear_inode(inode); | 301 | } |
| 302 | EXPORT_SYMBOL(end_writeback); | ||
| 303 | |||
| 304 | static void evict(struct inode *inode) | ||
| 305 | { | ||
| 306 | const struct super_operations *op = inode->i_sb->s_op; | ||
| 307 | |||
| 308 | if (op->evict_inode) { | ||
| 309 | op->evict_inode(inode); | ||
| 310 | } else { | ||
| 311 | if (inode->i_data.nrpages) | ||
| 312 | truncate_inode_pages(&inode->i_data, 0); | ||
| 313 | end_writeback(inode); | ||
| 314 | } | ||
| 316 | if (S_ISBLK(inode->i_mode) && inode->i_bdev) | 315 | if (S_ISBLK(inode->i_mode) && inode->i_bdev) |
| 317 | bd_forget(inode); | 316 | bd_forget(inode); |
| 318 | if (S_ISCHR(inode->i_mode) && inode->i_cdev) | 317 | if (S_ISCHR(inode->i_mode) && inode->i_cdev) |
| 319 | cd_forget(inode); | 318 | cd_forget(inode); |
| 320 | inode->i_state = I_CLEAR; | ||
| 321 | } | 319 | } |
| 322 | EXPORT_SYMBOL(clear_inode); | ||
| 323 | 320 | ||
| 324 | /* | 321 | /* |
| 325 | * dispose_list - dispose of the contents of a local list | 322 | * dispose_list - dispose of the contents of a local list |
| @@ -338,9 +335,7 @@ static void dispose_list(struct list_head *head) | |||
| 338 | inode = list_first_entry(head, struct inode, i_list); | 335 | inode = list_first_entry(head, struct inode, i_list); |
| 339 | list_del(&inode->i_list); | 336 | list_del(&inode->i_list); |
| 340 | 337 | ||
| 341 | if (inode->i_data.nrpages) | 338 | evict(inode); |
| 342 | truncate_inode_pages(&inode->i_data, 0); | ||
| 343 | clear_inode(inode); | ||
| 344 | 339 | ||
| 345 | spin_lock(&inode_lock); | 340 | spin_lock(&inode_lock); |
| 346 | hlist_del_init(&inode->i_hash); | 341 | hlist_del_init(&inode->i_hash); |
| @@ -413,7 +408,6 @@ int invalidate_inodes(struct super_block *sb) | |||
| 413 | 408 | ||
| 414 | down_write(&iprune_sem); | 409 | down_write(&iprune_sem); |
| 415 | spin_lock(&inode_lock); | 410 | spin_lock(&inode_lock); |
| 416 | inotify_unmount_inodes(&sb->s_inodes); | ||
| 417 | fsnotify_unmount_inodes(&sb->s_inodes); | 411 | fsnotify_unmount_inodes(&sb->s_inodes); |
| 418 | busy = invalidate_list(&sb->s_inodes, &throw_away); | 412 | busy = invalidate_list(&sb->s_inodes, &throw_away); |
| 419 | spin_unlock(&inode_lock); | 413 | spin_unlock(&inode_lock); |
| @@ -553,7 +547,7 @@ repeat: | |||
| 553 | continue; | 547 | continue; |
| 554 | if (!test(inode, data)) | 548 | if (!test(inode, data)) |
| 555 | continue; | 549 | continue; |
| 556 | if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)) { | 550 | if (inode->i_state & (I_FREEING|I_WILL_FREE)) { |
| 557 | __wait_on_freeing_inode(inode); | 551 | __wait_on_freeing_inode(inode); |
| 558 | goto repeat; | 552 | goto repeat; |
| 559 | } | 553 | } |
| @@ -578,7 +572,7 @@ repeat: | |||
| 578 | continue; | 572 | continue; |
| 579 | if (inode->i_sb != sb) | 573 | if (inode->i_sb != sb) |
| 580 | continue; | 574 | continue; |
| 581 | if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)) { | 575 | if (inode->i_state & (I_FREEING|I_WILL_FREE)) { |
| 582 | __wait_on_freeing_inode(inode); | 576 | __wait_on_freeing_inode(inode); |
| 583 | goto repeat; | 577 | goto repeat; |
| 584 | } | 578 | } |
| @@ -840,7 +834,7 @@ EXPORT_SYMBOL(iunique); | |||
| 840 | struct inode *igrab(struct inode *inode) | 834 | struct inode *igrab(struct inode *inode) |
| 841 | { | 835 | { |
| 842 | spin_lock(&inode_lock); | 836 | spin_lock(&inode_lock); |
| 843 | if (!(inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE))) | 837 | if (!(inode->i_state & (I_FREEING|I_WILL_FREE))) |
| 844 | __iget(inode); | 838 | __iget(inode); |
| 845 | else | 839 | else |
| 846 | /* | 840 | /* |
| @@ -1089,7 +1083,7 @@ int insert_inode_locked(struct inode *inode) | |||
| 1089 | continue; | 1083 | continue; |
| 1090 | if (old->i_sb != sb) | 1084 | if (old->i_sb != sb) |
| 1091 | continue; | 1085 | continue; |
| 1092 | if (old->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)) | 1086 | if (old->i_state & (I_FREEING|I_WILL_FREE)) |
| 1093 | continue; | 1087 | continue; |
| 1094 | break; | 1088 | break; |
| 1095 | } | 1089 | } |
| @@ -1128,7 +1122,7 @@ int insert_inode_locked4(struct inode *inode, unsigned long hashval, | |||
| 1128 | continue; | 1122 | continue; |
| 1129 | if (!test(old, data)) | 1123 | if (!test(old, data)) |
| 1130 | continue; | 1124 | continue; |
| 1131 | if (old->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE)) | 1125 | if (old->i_state & (I_FREEING|I_WILL_FREE)) |
| 1132 | continue; | 1126 | continue; |
| 1133 | break; | 1127 | break; |
| 1134 | } | 1128 | } |
| @@ -1180,69 +1174,51 @@ void remove_inode_hash(struct inode *inode) | |||
| 1180 | } | 1174 | } |
| 1181 | EXPORT_SYMBOL(remove_inode_hash); | 1175 | EXPORT_SYMBOL(remove_inode_hash); |
| 1182 | 1176 | ||
| 1177 | int generic_delete_inode(struct inode *inode) | ||
| 1178 | { | ||
| 1179 | return 1; | ||
| 1180 | } | ||
| 1181 | EXPORT_SYMBOL(generic_delete_inode); | ||
| 1182 | |||
| 1183 | /* | 1183 | /* |
| 1184 | * Tell the filesystem that this inode is no longer of any interest and should | 1184 | * Normal UNIX filesystem behaviour: delete the |
| 1185 | * be completely destroyed. | 1185 | * inode when the usage count drops to zero, and |
| 1186 | * | 1186 | * i_nlink is zero. |
| 1187 | * We leave the inode in the inode hash table until *after* the filesystem's | ||
| 1188 | * ->delete_inode completes. This ensures that an iget (such as nfsd might | ||
| 1189 | * instigate) will always find up-to-date information either in the hash or on | ||
| 1190 | * disk. | ||
| 1191 | * | ||
| 1192 | * I_FREEING is set so that no-one will take a new reference to the inode while | ||
| 1193 | * it is being deleted. | ||
| 1194 | */ | 1187 | */ |
| 1195 | void generic_delete_inode(struct inode *inode) | 1188 | int generic_drop_inode(struct inode *inode) |
| 1196 | { | 1189 | { |
| 1197 | const struct super_operations *op = inode->i_sb->s_op; | 1190 | return !inode->i_nlink || hlist_unhashed(&inode->i_hash); |
| 1198 | |||
| 1199 | list_del_init(&inode->i_list); | ||
| 1200 | list_del_init(&inode->i_sb_list); | ||
| 1201 | WARN_ON(inode->i_state & I_NEW); | ||
| 1202 | inode->i_state |= I_FREEING; | ||
| 1203 | inodes_stat.nr_inodes--; | ||
| 1204 | spin_unlock(&inode_lock); | ||
| 1205 | |||
| 1206 | if (op->delete_inode) { | ||
| 1207 | void (*delete)(struct inode *) = op->delete_inode; | ||
| 1208 | /* Filesystems implementing their own | ||
| 1209 | * s_op->delete_inode are required to call | ||
| 1210 | * truncate_inode_pages and clear_inode() | ||
| 1211 | * internally */ | ||
| 1212 | delete(inode); | ||
| 1213 | } else { | ||
| 1214 | truncate_inode_pages(&inode->i_data, 0); | ||
| 1215 | clear_inode(inode); | ||
| 1216 | } | ||
| 1217 | spin_lock(&inode_lock); | ||
| 1218 | hlist_del_init(&inode->i_hash); | ||
| 1219 | spin_unlock(&inode_lock); | ||
| 1220 | wake_up_inode(inode); | ||
| 1221 | BUG_ON(inode->i_state != I_CLEAR); | ||
| 1222 | destroy_inode(inode); | ||
| 1223 | } | 1191 | } |
| 1224 | EXPORT_SYMBOL(generic_delete_inode); | 1192 | EXPORT_SYMBOL_GPL(generic_drop_inode); |
| 1225 | 1193 | ||
| 1226 | /** | 1194 | /* |
| 1227 | * generic_detach_inode - remove inode from inode lists | 1195 | * Called when we're dropping the last reference |
| 1228 | * @inode: inode to remove | 1196 | * to an inode. |
| 1229 | * | ||
| 1230 | * Remove inode from inode lists, write it if it's dirty. This is just an | ||
| 1231 | * internal VFS helper exported for hugetlbfs. Do not use! | ||
| 1232 | * | 1197 | * |
| 1233 | * Returns 1 if inode should be completely destroyed. | 1198 | * Call the FS "drop_inode()" function, defaulting to |
| 1199 | * the legacy UNIX filesystem behaviour. If it tells | ||
| 1200 | * us to evict inode, do so. Otherwise, retain inode | ||
| 1201 | * in cache if fs is alive, sync and evict if fs is | ||
| 1202 | * shutting down. | ||
| 1234 | */ | 1203 | */ |
| 1235 | int generic_detach_inode(struct inode *inode) | 1204 | static void iput_final(struct inode *inode) |
| 1236 | { | 1205 | { |
| 1237 | struct super_block *sb = inode->i_sb; | 1206 | struct super_block *sb = inode->i_sb; |
| 1207 | const struct super_operations *op = inode->i_sb->s_op; | ||
| 1208 | int drop; | ||
| 1238 | 1209 | ||
| 1239 | if (!hlist_unhashed(&inode->i_hash)) { | 1210 | if (op && op->drop_inode) |
| 1211 | drop = op->drop_inode(inode); | ||
| 1212 | else | ||
| 1213 | drop = generic_drop_inode(inode); | ||
| 1214 | |||
| 1215 | if (!drop) { | ||
| 1240 | if (!(inode->i_state & (I_DIRTY|I_SYNC))) | 1216 | if (!(inode->i_state & (I_DIRTY|I_SYNC))) |
| 1241 | list_move(&inode->i_list, &inode_unused); | 1217 | list_move(&inode->i_list, &inode_unused); |
| 1242 | inodes_stat.nr_unused++; | 1218 | inodes_stat.nr_unused++; |
| 1243 | if (sb->s_flags & MS_ACTIVE) { | 1219 | if (sb->s_flags & MS_ACTIVE) { |
| 1244 | spin_unlock(&inode_lock); | 1220 | spin_unlock(&inode_lock); |
| 1245 | return 0; | 1221 | return; |
| 1246 | } | 1222 | } |
| 1247 | WARN_ON(inode->i_state & I_NEW); | 1223 | WARN_ON(inode->i_state & I_NEW); |
| 1248 | inode->i_state |= I_WILL_FREE; | 1224 | inode->i_state |= I_WILL_FREE; |
| @@ -1260,56 +1236,15 @@ int generic_detach_inode(struct inode *inode) | |||
| 1260 | inode->i_state |= I_FREEING; | 1236 | inode->i_state |= I_FREEING; |
| 1261 | inodes_stat.nr_inodes--; | 1237 | inodes_stat.nr_inodes--; |
| 1262 | spin_unlock(&inode_lock); | 1238 | spin_unlock(&inode_lock); |
| 1263 | return 1; | 1239 | evict(inode); |
| 1264 | } | 1240 | spin_lock(&inode_lock); |
| 1265 | EXPORT_SYMBOL_GPL(generic_detach_inode); | 1241 | hlist_del_init(&inode->i_hash); |
| 1266 | 1242 | spin_unlock(&inode_lock); | |
| 1267 | static void generic_forget_inode(struct inode *inode) | ||
| 1268 | { | ||
| 1269 | if (!generic_detach_inode(inode)) | ||
| 1270 | return; | ||
| 1271 | if (inode->i_data.nrpages) | ||
| 1272 | truncate_inode_pages(&inode->i_data, 0); | ||
| 1273 | clear_inode(inode); | ||
| 1274 | wake_up_inode(inode); | 1243 | wake_up_inode(inode); |
| 1244 | BUG_ON(inode->i_state != (I_FREEING | I_CLEAR)); | ||
| 1275 | destroy_inode(inode); | 1245 | destroy_inode(inode); |
| 1276 | } | 1246 | } |
| 1277 | 1247 | ||
| 1278 | /* | ||
| 1279 | * Normal UNIX filesystem behaviour: delete the | ||
| 1280 | * inode when the usage count drops to zero, and | ||
| 1281 | * i_nlink is zero. | ||
| 1282 | */ | ||
| 1283 | void generic_drop_inode(struct inode *inode) | ||
| 1284 | { | ||
| 1285 | if (!inode->i_nlink) | ||
| 1286 | generic_delete_inode(inode); | ||
| 1287 | else | ||
| 1288 | generic_forget_inode(inode); | ||
| 1289 | } | ||
| 1290 | EXPORT_SYMBOL_GPL(generic_drop_inode); | ||
| 1291 | |||
| 1292 | /* | ||
| 1293 | * Called when we're dropping the last reference | ||
| 1294 | * to an inode. | ||
| 1295 | * | ||
| 1296 | * Call the FS "drop()" function, defaulting to | ||
| 1297 | * the legacy UNIX filesystem behaviour.. | ||
| 1298 | * | ||
| 1299 | * NOTE! NOTE! NOTE! We're called with the inode lock | ||
| 1300 | * held, and the drop function is supposed to release | ||
| 1301 | * the lock! | ||
| 1302 | */ | ||
| 1303 | static inline void iput_final(struct inode *inode) | ||
| 1304 | { | ||
| 1305 | const struct super_operations *op = inode->i_sb->s_op; | ||
| 1306 | void (*drop)(struct inode *) = generic_drop_inode; | ||
| 1307 | |||
| 1308 | if (op && op->drop_inode) | ||
| 1309 | drop = op->drop_inode; | ||
| 1310 | drop(inode); | ||
| 1311 | } | ||
| 1312 | |||
| 1313 | /** | 1248 | /** |
| 1314 | * iput - put an inode | 1249 | * iput - put an inode |
| 1315 | * @inode: inode to put | 1250 | * @inode: inode to put |
| @@ -1322,7 +1257,7 @@ static inline void iput_final(struct inode *inode) | |||
| 1322 | void iput(struct inode *inode) | 1257 | void iput(struct inode *inode) |
| 1323 | { | 1258 | { |
| 1324 | if (inode) { | 1259 | if (inode) { |
| 1325 | BUG_ON(inode->i_state == I_CLEAR); | 1260 | BUG_ON(inode->i_state & I_CLEAR); |
| 1326 | 1261 | ||
| 1327 | if (atomic_dec_and_lock(&inode->i_count, &inode_lock)) | 1262 | if (atomic_dec_and_lock(&inode->i_count, &inode_lock)) |
| 1328 | iput_final(inode); | 1263 | iput_final(inode); |
diff --git a/fs/ioctl.c b/fs/ioctl.c index 2d140a713861..f855ea4fc888 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c | |||
| @@ -29,7 +29,6 @@ | |||
| 29 | * @arg: command-specific argument for ioctl | 29 | * @arg: command-specific argument for ioctl |
| 30 | * | 30 | * |
| 31 | * Invokes filesystem specific ->unlocked_ioctl, if one exists; otherwise | 31 | * Invokes filesystem specific ->unlocked_ioctl, if one exists; otherwise |
| 32 | * invokes filesystem specific ->ioctl method. If neither method exists, | ||
| 33 | * returns -ENOTTY. | 32 | * returns -ENOTTY. |
| 34 | * | 33 | * |
| 35 | * Returns 0 on success, -errno on error. | 34 | * Returns 0 on success, -errno on error. |
| @@ -39,21 +38,12 @@ static long vfs_ioctl(struct file *filp, unsigned int cmd, | |||
| 39 | { | 38 | { |
| 40 | int error = -ENOTTY; | 39 | int error = -ENOTTY; |
| 41 | 40 | ||
| 42 | if (!filp->f_op) | 41 | if (!filp->f_op || !filp->f_op->unlocked_ioctl) |
| 43 | goto out; | 42 | goto out; |
| 44 | 43 | ||
| 45 | if (filp->f_op->unlocked_ioctl) { | 44 | error = filp->f_op->unlocked_ioctl(filp, cmd, arg); |
| 46 | error = filp->f_op->unlocked_ioctl(filp, cmd, arg); | 45 | if (error == -ENOIOCTLCMD) |
| 47 | if (error == -ENOIOCTLCMD) | 46 | error = -EINVAL; |
| 48 | error = -EINVAL; | ||
| 49 | goto out; | ||
| 50 | } else if (filp->f_op->ioctl) { | ||
| 51 | lock_kernel(); | ||
| 52 | error = filp->f_op->ioctl(filp->f_path.dentry->d_inode, | ||
| 53 | filp, cmd, arg); | ||
| 54 | unlock_kernel(); | ||
| 55 | } | ||
| 56 | |||
| 57 | out: | 47 | out: |
| 58 | return error; | 48 | return error; |
| 59 | } | 49 | } |
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 6b4dcd4f2943..5a44811b5027 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c | |||
| @@ -722,7 +722,12 @@ root_found: | |||
| 722 | } | 722 | } |
| 723 | 723 | ||
| 724 | s->s_magic = ISOFS_SUPER_MAGIC; | 724 | s->s_magic = ISOFS_SUPER_MAGIC; |
| 725 | s->s_maxbytes = 0xffffffff; /* We can handle files up to 4 GB */ | 725 | |
| 726 | /* | ||
| 727 | * With multi-extent files, file size is only limited by the maximum | ||
| 728 | * size of a file system, which is 8 TB. | ||
| 729 | */ | ||
| 730 | s->s_maxbytes = 0x80000000000LL; | ||
| 726 | 731 | ||
| 727 | /* | 732 | /* |
| 728 | * The CDROM is read-only, has no nodes (devices) on it, and since | 733 | * The CDROM is read-only, has no nodes (devices) on it, and since |
diff --git a/fs/jbd2/transaction.c b/fs/jbd2/transaction.c index d95cc9d0401d..f3479d6e0a83 100644 --- a/fs/jbd2/transaction.c +++ b/fs/jbd2/transaction.c | |||
| @@ -82,6 +82,32 @@ jbd2_get_transaction(journal_t *journal, transaction_t *transaction) | |||
| 82 | */ | 82 | */ |
| 83 | 83 | ||
| 84 | /* | 84 | /* |
| 85 | * Update transiaction's maximum wait time, if debugging is enabled. | ||
| 86 | * | ||
| 87 | * In order for t_max_wait to be reliable, it must be protected by a | ||
| 88 | * lock. But doing so will mean that start_this_handle() can not be | ||
| 89 | * run in parallel on SMP systems, which limits our scalability. So | ||
| 90 | * unless debugging is enabled, we no longer update t_max_wait, which | ||
| 91 | * means that maximum wait time reported by the jbd2_run_stats | ||
| 92 | * tracepoint will always be zero. | ||
| 93 | */ | ||
| 94 | static inline void update_t_max_wait(transaction_t *transaction) | ||
| 95 | { | ||
| 96 | #ifdef CONFIG_JBD2_DEBUG | ||
| 97 | unsigned long ts = jiffies; | ||
| 98 | |||
| 99 | if (jbd2_journal_enable_debug && | ||
| 100 | time_after(transaction->t_start, ts)) { | ||
| 101 | ts = jbd2_time_diff(ts, transaction->t_start); | ||
| 102 | spin_lock(&transaction->t_handle_lock); | ||
| 103 | if (ts > transaction->t_max_wait) | ||
| 104 | transaction->t_max_wait = ts; | ||
| 105 | spin_unlock(&transaction->t_handle_lock); | ||
| 106 | } | ||
| 107 | #endif | ||
| 108 | } | ||
| 109 | |||
| 110 | /* | ||
| 85 | * start_this_handle: Given a handle, deal with any locking or stalling | 111 | * start_this_handle: Given a handle, deal with any locking or stalling |
| 86 | * needed to make sure that there is enough journal space for the handle | 112 | * needed to make sure that there is enough journal space for the handle |
| 87 | * to begin. Attach the handle to a transaction and set up the | 113 | * to begin. Attach the handle to a transaction and set up the |
| @@ -95,7 +121,6 @@ static int start_this_handle(journal_t *journal, handle_t *handle, | |||
| 95 | int needed; | 121 | int needed; |
| 96 | int nblocks = handle->h_buffer_credits; | 122 | int nblocks = handle->h_buffer_credits; |
| 97 | transaction_t *new_transaction = NULL; | 123 | transaction_t *new_transaction = NULL; |
| 98 | unsigned long ts = jiffies; | ||
| 99 | 124 | ||
| 100 | if (nblocks > journal->j_max_transaction_buffers) { | 125 | if (nblocks > journal->j_max_transaction_buffers) { |
| 101 | printk(KERN_ERR "JBD: %s wants too many credits (%d > %d)\n", | 126 | printk(KERN_ERR "JBD: %s wants too many credits (%d > %d)\n", |
| @@ -241,25 +266,8 @@ repeat: | |||
| 241 | 266 | ||
| 242 | /* OK, account for the buffers that this operation expects to | 267 | /* OK, account for the buffers that this operation expects to |
| 243 | * use and add the handle to the running transaction. | 268 | * use and add the handle to the running transaction. |
| 244 | * | ||
| 245 | * In order for t_max_wait to be reliable, it must be | ||
| 246 | * protected by a lock. But doing so will mean that | ||
| 247 | * start_this_handle() can not be run in parallel on SMP | ||
| 248 | * systems, which limits our scalability. So we only enable | ||
| 249 | * it when debugging is enabled. We may want to use a | ||
| 250 | * separate flag, eventually, so we can enable this | ||
| 251 | * independently of debugging. | ||
| 252 | */ | 269 | */ |
| 253 | #ifdef CONFIG_JBD2_DEBUG | 270 | update_t_max_wait(transaction); |
| 254 | if (jbd2_journal_enable_debug && | ||
| 255 | time_after(transaction->t_start, ts)) { | ||
| 256 | ts = jbd2_time_diff(ts, transaction->t_start); | ||
| 257 | spin_lock(&transaction->t_handle_lock); | ||
| 258 | if (ts > transaction->t_max_wait) | ||
| 259 | transaction->t_max_wait = ts; | ||
| 260 | spin_unlock(&transaction->t_handle_lock); | ||
| 261 | } | ||
| 262 | #endif | ||
| 263 | handle->h_transaction = transaction; | 271 | handle->h_transaction = transaction; |
| 264 | atomic_inc(&transaction->t_updates); | 272 | atomic_inc(&transaction->t_updates); |
| 265 | atomic_inc(&transaction->t_handle_count); | 273 | atomic_inc(&transaction->t_handle_count); |
diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c index 55f1dde2fa8b..404111b016c9 100644 --- a/fs/jffs2/background.c +++ b/fs/jffs2/background.c | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright © 2001-2007 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> | ||
| 5 | * | 6 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 7 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 8 | * |
diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c index c5e1450d79f9..a906f538d11c 100644 --- a/fs/jffs2/build.c +++ b/fs/jffs2/build.c | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright © 2001-2007 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> | ||
| 5 | * | 6 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 7 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 8 | * |
diff --git a/fs/jffs2/compr.c b/fs/jffs2/compr.c index f0294410868d..617a1e5694c1 100644 --- a/fs/jffs2/compr.c +++ b/fs/jffs2/compr.c | |||
| @@ -2,11 +2,12 @@ | |||
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright © 2001-2007 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * Created by Arjan van de Ven <arjanv@redhat.com> | 5 | * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> |
| 6 | * | ||
| 7 | * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, | 6 | * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, |
| 8 | * University of Szeged, Hungary | 7 | * University of Szeged, Hungary |
| 9 | * | 8 | * |
| 9 | * Created by Arjan van de Ven <arjan@infradead.org> | ||
| 10 | * | ||
| 10 | * For licensing information, see the file 'LICENCE' in this directory. | 11 | * For licensing information, see the file 'LICENCE' in this directory. |
| 11 | * | 12 | * |
| 12 | */ | 13 | */ |
diff --git a/fs/jffs2/compr.h b/fs/jffs2/compr.h index 7d1d72faa774..e471a9106fd9 100644 --- a/fs/jffs2/compr.h +++ b/fs/jffs2/compr.h | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | * | 3 | * |
| 4 | * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, | 4 | * Copyright © 2004 Ferenc Havasi <havasi@inf.u-szeged.hu>, |
| 5 | * University of Szeged, Hungary | 5 | * University of Szeged, Hungary |
| 6 | * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> | ||
| 6 | * | 7 | * |
| 7 | * For licensing information, see the file 'LICENCE' in this directory. | 8 | * For licensing information, see the file 'LICENCE' in this directory. |
| 8 | * | 9 | * |
diff --git a/fs/jffs2/compr_lzo.c b/fs/jffs2/compr_lzo.c index cd02acafde8a..ed25ae7c98eb 100644 --- a/fs/jffs2/compr_lzo.c +++ b/fs/jffs2/compr_lzo.c | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright © 2007 Nokia Corporation. All rights reserved. | 4 | * Copyright © 2007 Nokia Corporation. All rights reserved. |
| 5 | * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> | ||
| 5 | * | 6 | * |
| 6 | * Created by Richard Purdie <rpurdie@openedhand.com> | 7 | * Created by Richard Purdie <rpurdie@openedhand.com> |
| 7 | * | 8 | * |
diff --git a/fs/jffs2/compr_rtime.c b/fs/jffs2/compr_rtime.c index 546d1538d076..9696ad9ef5f7 100644 --- a/fs/jffs2/compr_rtime.c +++ b/fs/jffs2/compr_rtime.c | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright © 2001-2007 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> | ||
| 5 | * | 6 | * |
| 6 | * Created by Arjan van de Ven <arjanv@redhat.com> | 7 | * Created by Arjan van de Ven <arjanv@redhat.com> |
| 7 | * | 8 | * |
diff --git a/fs/jffs2/compr_rubin.c b/fs/jffs2/compr_rubin.c index 170d289ac785..a12b4f763373 100644 --- a/fs/jffs2/compr_rubin.c +++ b/fs/jffs2/compr_rubin.c | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright © 2001-2007 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> | ||
| 5 | * | 6 | * |
| 6 | * Created by Arjan van de Ven <arjanv@redhat.com> | 7 | * Created by Arjan van de Ven <arjanv@redhat.com> |
| 7 | * | 8 | * |
diff --git a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c index b46661a42758..97fc45de6f81 100644 --- a/fs/jffs2/compr_zlib.c +++ b/fs/jffs2/compr_zlib.c | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright © 2001-2007 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> | ||
| 5 | * | 6 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 7 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 8 | * |
diff --git a/fs/jffs2/debug.c b/fs/jffs2/debug.c index ec3538413926..e0b76c87a91a 100644 --- a/fs/jffs2/debug.c +++ b/fs/jffs2/debug.c | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright © 2001-2007 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> | ||
| 5 | * | 6 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 7 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 8 | * |
diff --git a/fs/jffs2/debug.h b/fs/jffs2/debug.h index a113ecc3bafe..c4f8eef5ca68 100644 --- a/fs/jffs2/debug.h +++ b/fs/jffs2/debug.h | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright © 2001-2007 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> | ||
| 5 | * | 6 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 7 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 8 | * |
diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index 166062a68230..ed78a3cf3cb0 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright © 2001-2007 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> | ||
| 5 | * | 6 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 7 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 8 | * |
| @@ -232,9 +233,7 @@ static int jffs2_create(struct inode *dir_i, struct dentry *dentry, int mode, | |||
| 232 | return 0; | 233 | return 0; |
| 233 | 234 | ||
| 234 | fail: | 235 | fail: |
| 235 | make_bad_inode(inode); | 236 | iget_failed(inode); |
| 236 | unlock_new_inode(inode); | ||
| 237 | iput(inode); | ||
| 238 | jffs2_free_raw_inode(ri); | 237 | jffs2_free_raw_inode(ri); |
| 239 | return ret; | 238 | return ret; |
| 240 | } | 239 | } |
| @@ -454,9 +453,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char | |||
| 454 | return 0; | 453 | return 0; |
| 455 | 454 | ||
| 456 | fail: | 455 | fail: |
| 457 | make_bad_inode(inode); | 456 | iget_failed(inode); |
| 458 | unlock_new_inode(inode); | ||
| 459 | iput(inode); | ||
| 460 | return ret; | 457 | return ret; |
| 461 | } | 458 | } |
| 462 | 459 | ||
| @@ -601,9 +598,7 @@ static int jffs2_mkdir (struct inode *dir_i, struct dentry *dentry, int mode) | |||
| 601 | return 0; | 598 | return 0; |
| 602 | 599 | ||
| 603 | fail: | 600 | fail: |
| 604 | make_bad_inode(inode); | 601 | iget_failed(inode); |
| 605 | unlock_new_inode(inode); | ||
| 606 | iput(inode); | ||
| 607 | return ret; | 602 | return ret; |
| 608 | } | 603 | } |
| 609 | 604 | ||
| @@ -778,9 +773,7 @@ static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, de | |||
| 778 | return 0; | 773 | return 0; |
| 779 | 774 | ||
| 780 | fail: | 775 | fail: |
| 781 | make_bad_inode(inode); | 776 | iget_failed(inode); |
| 782 | unlock_new_inode(inode); | ||
| 783 | iput(inode); | ||
| 784 | return ret; | 777 | return ret; |
| 785 | } | 778 | } |
| 786 | 779 | ||
diff --git a/fs/jffs2/erase.c b/fs/jffs2/erase.c index 6286ad9b00f7..abac961f617b 100644 --- a/fs/jffs2/erase.c +++ b/fs/jffs2/erase.c | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright © 2001-2007 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> | ||
| 5 | * | 6 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 7 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 8 | * |
diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index 813497024437..1c0a08d711aa 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright © 2001-2007 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> | ||
| 5 | * | 6 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 7 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 8 | * |
diff --git a/fs/jffs2/fs.c b/fs/jffs2/fs.c index 459d39d1ea0b..6b2964a19850 100644 --- a/fs/jffs2/fs.c +++ b/fs/jffs2/fs.c | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright © 2001-2007 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> | ||
| 5 | * | 6 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 7 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 8 | * |
| @@ -169,13 +170,13 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) | |||
| 169 | mutex_unlock(&f->sem); | 170 | mutex_unlock(&f->sem); |
| 170 | jffs2_complete_reservation(c); | 171 | jffs2_complete_reservation(c); |
| 171 | 172 | ||
| 172 | /* We have to do the simple_setsize() without f->sem held, since | 173 | /* We have to do the truncate_setsize() without f->sem held, since |
| 173 | some pages may be locked and waiting for it in readpage(). | 174 | some pages may be locked and waiting for it in readpage(). |
| 174 | We are protected from a simultaneous write() extending i_size | 175 | We are protected from a simultaneous write() extending i_size |
| 175 | back past iattr->ia_size, because do_truncate() holds the | 176 | back past iattr->ia_size, because do_truncate() holds the |
| 176 | generic inode semaphore. */ | 177 | generic inode semaphore. */ |
| 177 | if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) { | 178 | if (ivalid & ATTR_SIZE && inode->i_size > iattr->ia_size) { |
| 178 | simple_setsize(inode, iattr->ia_size); | 179 | truncate_setsize(inode, iattr->ia_size); |
| 179 | inode->i_blocks = (inode->i_size + 511) >> 9; | 180 | inode->i_blocks = (inode->i_size + 511) >> 9; |
| 180 | } | 181 | } |
| 181 | 182 | ||
| @@ -225,7 +226,7 @@ int jffs2_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
| 225 | } | 226 | } |
| 226 | 227 | ||
| 227 | 228 | ||
| 228 | void jffs2_clear_inode (struct inode *inode) | 229 | void jffs2_evict_inode (struct inode *inode) |
| 229 | { | 230 | { |
| 230 | /* We can forget about this inode for now - drop all | 231 | /* We can forget about this inode for now - drop all |
| 231 | * the nodelists associated with it, etc. | 232 | * the nodelists associated with it, etc. |
| @@ -233,7 +234,9 @@ void jffs2_clear_inode (struct inode *inode) | |||
| 233 | struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); | 234 | struct jffs2_sb_info *c = JFFS2_SB_INFO(inode->i_sb); |
| 234 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); | 235 | struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode); |
| 235 | 236 | ||
| 236 | D1(printk(KERN_DEBUG "jffs2_clear_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode)); | 237 | D1(printk(KERN_DEBUG "jffs2_evict_inode(): ino #%lu mode %o\n", inode->i_ino, inode->i_mode)); |
| 238 | truncate_inode_pages(&inode->i_data, 0); | ||
| 239 | end_writeback(inode); | ||
| 237 | jffs2_do_clear_inode(c, f); | 240 | jffs2_do_clear_inode(c, f); |
| 238 | } | 241 | } |
| 239 | 242 | ||
diff --git a/fs/jffs2/gc.c b/fs/jffs2/gc.c index f5e96bd656e8..846a79452497 100644 --- a/fs/jffs2/gc.c +++ b/fs/jffs2/gc.c | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright © 2001-2007 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> | ||
| 5 | * | 6 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 7 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 8 | * |
diff --git a/fs/jffs2/ioctl.c b/fs/jffs2/ioctl.c index 9d41f43e47bb..859a598af020 100644 --- a/fs/jffs2/ioctl.c +++ b/fs/jffs2/ioctl.c | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright © 2001-2007 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> | ||
| 5 | * | 6 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 7 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 8 | * |
diff --git a/fs/jffs2/jffs2_fs_i.h b/fs/jffs2/jffs2_fs_i.h index c6923da98263..2e4a86763c07 100644 --- a/fs/jffs2/jffs2_fs_i.h +++ b/fs/jffs2/jffs2_fs_i.h | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright © 2001-2007 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> | ||
| 5 | * | 6 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 7 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 8 | * |
diff --git a/fs/jffs2/jffs2_fs_sb.h b/fs/jffs2/jffs2_fs_sb.h index 85ef6dbb1be7..6784bc89add1 100644 --- a/fs/jffs2/jffs2_fs_sb.h +++ b/fs/jffs2/jffs2_fs_sb.h | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | * JFFS2 -- Journalling Flash File System, Version 2. | 2 | * JFFS2 -- Journalling Flash File System, Version 2. |
| 3 | * | 3 | * |
| 4 | * Copyright © 2001-2007 Red Hat, Inc. | 4 | * Copyright © 2001-2007 Red Hat, Inc. |
| 5 | * Copyright © 2004-2010 David Woodhouse <dwmw2@infradead.org> | ||
| 5 | * | 6 | * |
| 6 | * Created by David Woodhouse <dwmw2@infradead.org> | 7 | * Created by David Woodhouse <dwmw2@infradead.org> |
| 7 | * | 8 | * |
diff --git a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h index a881a42f19e3..523a91691052 100644 --- a/fs/jffs2/nodelist.h +++ b/fs/jffs2/nodelist.h | |||
| @@ -24,7 +24,6 @@ | |||
| 24 | #ifdef __ECOS | 24 | #ifdef __ECOS |
| 25 | #include "os-ecos.h" | 25 | #include "os-ecos.h" |
| 26 | #else | 26 | #else |
| 27 | #include <linux/mtd/compatmac.h> /* For compatibility with older kernels */ | ||
| 28 | #include "os-linux.h" | 27 | #include "os-linux.h" |
| 29 | #endif | 28 | #endif |
| 30 | 29 | ||
diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index 4791aacf3084..00bae7cc2e48 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h | |||
| @@ -171,7 +171,7 @@ extern const struct inode_operations jffs2_symlink_inode_operations; | |||
| 171 | int jffs2_setattr (struct dentry *, struct iattr *); | 171 | int jffs2_setattr (struct dentry *, struct iattr *); |
| 172 | int jffs2_do_setattr (struct inode *, struct iattr *); | 172 | int jffs2_do_setattr (struct inode *, struct iattr *); |
| 173 | struct inode *jffs2_iget(struct super_block *, unsigned long); | 173 | struct inode *jffs2_iget(struct super_block *, unsigned long); |
| 174 | void jffs2_clear_inode (struct inode *); | 174 | void jffs2_evict_inode (struct inode *); |
| 175 | void jffs2_dirty_inode(struct inode *inode); | 175 | void jffs2_dirty_inode(struct inode *inode); |
| 176 | struct inode *jffs2_new_inode (struct inode *dir_i, int mode, | 176 | struct inode *jffs2_new_inode (struct inode *dir_i, int mode, |
| 177 | struct jffs2_raw_inode *ri); | 177 | struct jffs2_raw_inode *ri); |
diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index 511e2d609d12..662bba099501 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c | |||
| @@ -135,7 +135,7 @@ static const struct super_operations jffs2_super_operations = | |||
| 135 | .write_super = jffs2_write_super, | 135 | .write_super = jffs2_write_super, |
| 136 | .statfs = jffs2_statfs, | 136 | .statfs = jffs2_statfs, |
| 137 | .remount_fs = jffs2_remount_fs, | 137 | .remount_fs = jffs2_remount_fs, |
| 138 | .clear_inode = jffs2_clear_inode, | 138 | .evict_inode = jffs2_evict_inode, |
| 139 | .dirty_inode = jffs2_dirty_inode, | 139 | .dirty_inode = jffs2_dirty_inode, |
| 140 | .sync_fs = jffs2_sync_fs, | 140 | .sync_fs = jffs2_sync_fs, |
| 141 | }; | 141 | }; |
diff --git a/fs/jffs2/xattr.c b/fs/jffs2/xattr.c index d258e261bdc7..9b572ca40a49 100644 --- a/fs/jffs2/xattr.c +++ b/fs/jffs2/xattr.c | |||
| @@ -588,7 +588,7 @@ static void delete_xattr_ref(struct jffs2_sb_info *c, struct jffs2_xattr_ref *re | |||
| 588 | 588 | ||
| 589 | void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) | 589 | void jffs2_xattr_delete_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) |
| 590 | { | 590 | { |
| 591 | /* It's called from jffs2_clear_inode() on inode removing. | 591 | /* It's called from jffs2_evict_inode() on inode removing. |
| 592 | When an inode with XATTR is removed, those XATTRs must be removed. */ | 592 | When an inode with XATTR is removed, those XATTRs must be removed. */ |
| 593 | struct jffs2_xattr_ref *ref, *_ref; | 593 | struct jffs2_xattr_ref *ref, *_ref; |
| 594 | 594 | ||
diff --git a/fs/jfs/file.c b/fs/jfs/file.c index 127263cc8657..c5ce6c1d1ff4 100644 --- a/fs/jfs/file.c +++ b/fs/jfs/file.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 18 | */ | 18 | */ |
| 19 | 19 | ||
| 20 | #include <linux/mm.h> | ||
| 20 | #include <linux/fs.h> | 21 | #include <linux/fs.h> |
| 21 | #include <linux/quotaops.h> | 22 | #include <linux/quotaops.h> |
| 22 | #include "jfs_incore.h" | 23 | #include "jfs_incore.h" |
| @@ -107,11 +108,18 @@ int jfs_setattr(struct dentry *dentry, struct iattr *iattr) | |||
| 107 | return rc; | 108 | return rc; |
| 108 | } | 109 | } |
| 109 | 110 | ||
| 110 | rc = inode_setattr(inode, iattr); | 111 | if ((iattr->ia_valid & ATTR_SIZE) && |
| 112 | iattr->ia_size != i_size_read(inode)) { | ||
| 113 | rc = vmtruncate(inode, iattr->ia_size); | ||
| 114 | if (rc) | ||
| 115 | return rc; | ||
| 116 | } | ||
| 111 | 117 | ||
| 112 | if (!rc && (iattr->ia_valid & ATTR_MODE)) | 118 | setattr_copy(inode, iattr); |
| 113 | rc = jfs_acl_chmod(inode); | 119 | mark_inode_dirty(inode); |
| 114 | 120 | ||
| 121 | if (iattr->ia_valid & ATTR_MODE) | ||
| 122 | rc = jfs_acl_chmod(inode); | ||
| 115 | return rc; | 123 | return rc; |
| 116 | } | 124 | } |
| 117 | 125 | ||
diff --git a/fs/jfs/inode.c b/fs/jfs/inode.c index ed9ba6fe04f5..9978803ceedc 100644 --- a/fs/jfs/inode.c +++ b/fs/jfs/inode.c | |||
| @@ -145,31 +145,32 @@ int jfs_write_inode(struct inode *inode, struct writeback_control *wbc) | |||
| 145 | return 0; | 145 | return 0; |
| 146 | } | 146 | } |
| 147 | 147 | ||
| 148 | void jfs_delete_inode(struct inode *inode) | 148 | void jfs_evict_inode(struct inode *inode) |
| 149 | { | 149 | { |
| 150 | jfs_info("In jfs_delete_inode, inode = 0x%p", inode); | 150 | jfs_info("In jfs_evict_inode, inode = 0x%p", inode); |
| 151 | 151 | ||
| 152 | if (!is_bad_inode(inode)) | 152 | if (!inode->i_nlink && !is_bad_inode(inode)) { |
| 153 | dquot_initialize(inode); | 153 | dquot_initialize(inode); |
| 154 | 154 | ||
| 155 | if (!is_bad_inode(inode) && | 155 | if (JFS_IP(inode)->fileset == FILESYSTEM_I) { |
| 156 | (JFS_IP(inode)->fileset == FILESYSTEM_I)) { | 156 | truncate_inode_pages(&inode->i_data, 0); |
| 157 | truncate_inode_pages(&inode->i_data, 0); | ||
| 158 | 157 | ||
| 159 | if (test_cflag(COMMIT_Freewmap, inode)) | 158 | if (test_cflag(COMMIT_Freewmap, inode)) |
| 160 | jfs_free_zero_link(inode); | 159 | jfs_free_zero_link(inode); |
| 161 | 160 | ||
| 162 | diFree(inode); | 161 | diFree(inode); |
| 163 | 162 | ||
| 164 | /* | 163 | /* |
| 165 | * Free the inode from the quota allocation. | 164 | * Free the inode from the quota allocation. |
| 166 | */ | 165 | */ |
| 167 | dquot_initialize(inode); | 166 | dquot_initialize(inode); |
| 168 | dquot_free_inode(inode); | 167 | dquot_free_inode(inode); |
| 169 | dquot_drop(inode); | 168 | } |
| 169 | } else { | ||
| 170 | truncate_inode_pages(&inode->i_data, 0); | ||
| 170 | } | 171 | } |
| 171 | 172 | end_writeback(inode); | |
| 172 | clear_inode(inode); | 173 | dquot_drop(inode); |
| 173 | } | 174 | } |
| 174 | 175 | ||
| 175 | void jfs_dirty_inode(struct inode *inode) | 176 | void jfs_dirty_inode(struct inode *inode) |
| @@ -303,8 +304,17 @@ static int jfs_write_begin(struct file *file, struct address_space *mapping, | |||
| 303 | loff_t pos, unsigned len, unsigned flags, | 304 | loff_t pos, unsigned len, unsigned flags, |
| 304 | struct page **pagep, void **fsdata) | 305 | struct page **pagep, void **fsdata) |
| 305 | { | 306 | { |
| 306 | return nobh_write_begin(file, mapping, pos, len, flags, pagep, fsdata, | 307 | int ret; |
| 308 | |||
| 309 | ret = nobh_write_begin(mapping, pos, len, flags, pagep, fsdata, | ||
| 307 | jfs_get_block); | 310 | jfs_get_block); |
| 311 | if (unlikely(ret)) { | ||
| 312 | loff_t isize = mapping->host->i_size; | ||
| 313 | if (pos + len > isize) | ||
| 314 | vmtruncate(mapping->host, isize); | ||
| 315 | } | ||
| 316 | |||
| 317 | return ret; | ||
| 308 | } | 318 | } |
| 309 | 319 | ||
| 310 | static sector_t jfs_bmap(struct address_space *mapping, sector_t block) | 320 | static sector_t jfs_bmap(struct address_space *mapping, sector_t block) |
| @@ -317,9 +327,24 @@ static ssize_t jfs_direct_IO(int rw, struct kiocb *iocb, | |||
| 317 | { | 327 | { |
| 318 | struct file *file = iocb->ki_filp; | 328 | struct file *file = iocb->ki_filp; |
| 319 | struct inode *inode = file->f_mapping->host; | 329 | struct inode *inode = file->f_mapping->host; |
| 330 | ssize_t ret; | ||
| 320 | 331 | ||
| 321 | return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, | 332 | ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, |
| 322 | offset, nr_segs, jfs_get_block, NULL); | 333 | offset, nr_segs, jfs_get_block, NULL); |
| 334 | |||
| 335 | /* | ||
| 336 | * In case of error extending write may have instantiated a few | ||
| 337 | * blocks outside i_size. Trim these off again. | ||
| 338 | */ | ||
| 339 | if (unlikely((rw & WRITE) && ret < 0)) { | ||
| 340 | loff_t isize = i_size_read(inode); | ||
| 341 | loff_t end = offset + iov_length(iov, nr_segs); | ||
| 342 | |||
| 343 | if (end > isize) | ||
| 344 | vmtruncate(inode, isize); | ||
| 345 | } | ||
| 346 | |||
| 347 | return ret; | ||
| 323 | } | 348 | } |
| 324 | 349 | ||
| 325 | const struct address_space_operations jfs_aops = { | 350 | const struct address_space_operations jfs_aops = { |
diff --git a/fs/jfs/jfs_inode.h b/fs/jfs/jfs_inode.h index 11042b1f44b5..155e91eff07d 100644 --- a/fs/jfs/jfs_inode.h +++ b/fs/jfs/jfs_inode.h | |||
| @@ -27,7 +27,7 @@ extern long jfs_compat_ioctl(struct file *, unsigned int, unsigned long); | |||
| 27 | extern struct inode *jfs_iget(struct super_block *, unsigned long); | 27 | extern struct inode *jfs_iget(struct super_block *, unsigned long); |
| 28 | extern int jfs_commit_inode(struct inode *, int); | 28 | extern int jfs_commit_inode(struct inode *, int); |
| 29 | extern int jfs_write_inode(struct inode *, struct writeback_control *); | 29 | extern int jfs_write_inode(struct inode *, struct writeback_control *); |
| 30 | extern void jfs_delete_inode(struct inode *); | 30 | extern void jfs_evict_inode(struct inode *); |
| 31 | extern void jfs_dirty_inode(struct inode *); | 31 | extern void jfs_dirty_inode(struct inode *); |
| 32 | extern void jfs_truncate(struct inode *); | 32 | extern void jfs_truncate(struct inode *); |
| 33 | extern void jfs_truncate_nolock(struct inode *, loff_t); | 33 | extern void jfs_truncate_nolock(struct inode *, loff_t); |
diff --git a/fs/jfs/super.c b/fs/jfs/super.c index b38f96bef829..ec8c3e4baca3 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c | |||
| @@ -132,11 +132,6 @@ static void jfs_destroy_inode(struct inode *inode) | |||
| 132 | kmem_cache_free(jfs_inode_cachep, ji); | 132 | kmem_cache_free(jfs_inode_cachep, ji); |
| 133 | } | 133 | } |
| 134 | 134 | ||
| 135 | static void jfs_clear_inode(struct inode *inode) | ||
| 136 | { | ||
| 137 | dquot_drop(inode); | ||
| 138 | } | ||
| 139 | |||
| 140 | static int jfs_statfs(struct dentry *dentry, struct kstatfs *buf) | 135 | static int jfs_statfs(struct dentry *dentry, struct kstatfs *buf) |
| 141 | { | 136 | { |
| 142 | struct jfs_sb_info *sbi = JFS_SBI(dentry->d_sb); | 137 | struct jfs_sb_info *sbi = JFS_SBI(dentry->d_sb); |
| @@ -765,8 +760,7 @@ static const struct super_operations jfs_super_operations = { | |||
| 765 | .destroy_inode = jfs_destroy_inode, | 760 | .destroy_inode = jfs_destroy_inode, |
| 766 | .dirty_inode = jfs_dirty_inode, | 761 | .dirty_inode = jfs_dirty_inode, |
| 767 | .write_inode = jfs_write_inode, | 762 | .write_inode = jfs_write_inode, |
| 768 | .delete_inode = jfs_delete_inode, | 763 | .evict_inode = jfs_evict_inode, |
| 769 | .clear_inode = jfs_clear_inode, | ||
| 770 | .put_super = jfs_put_super, | 764 | .put_super = jfs_put_super, |
| 771 | .sync_fs = jfs_sync_fs, | 765 | .sync_fs = jfs_sync_fs, |
| 772 | .freeze_fs = jfs_freeze, | 766 | .freeze_fs = jfs_freeze, |
diff --git a/fs/jfs/xattr.c b/fs/jfs/xattr.c index fa96bbb26343..2d7f165d0f1d 100644 --- a/fs/jfs/xattr.c +++ b/fs/jfs/xattr.c | |||
| @@ -86,46 +86,25 @@ struct ea_buffer { | |||
| 86 | #define EA_MALLOC 0x0008 | 86 | #define EA_MALLOC 0x0008 |
| 87 | 87 | ||
| 88 | 88 | ||
| 89 | static int is_known_namespace(const char *name) | ||
| 90 | { | ||
| 91 | if (strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN) && | ||
| 92 | strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) && | ||
| 93 | strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) && | ||
| 94 | strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN)) | ||
| 95 | return false; | ||
| 96 | |||
| 97 | return true; | ||
| 98 | } | ||
| 99 | |||
| 89 | /* | 100 | /* |
| 90 | * These three routines are used to recognize on-disk extended attributes | 101 | * These three routines are used to recognize on-disk extended attributes |
| 91 | * that are in a recognized namespace. If the attribute is not recognized, | 102 | * that are in a recognized namespace. If the attribute is not recognized, |
| 92 | * "os2." is prepended to the name | 103 | * "os2." is prepended to the name |
| 93 | */ | 104 | */ |
| 94 | static inline int is_os2_xattr(struct jfs_ea *ea) | 105 | static int is_os2_xattr(struct jfs_ea *ea) |
| 95 | { | 106 | { |
| 96 | /* | 107 | return !is_known_namespace(ea->name); |
| 97 | * Check for "system." | ||
| 98 | */ | ||
| 99 | if ((ea->namelen >= XATTR_SYSTEM_PREFIX_LEN) && | ||
| 100 | !strncmp(ea->name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) | ||
| 101 | return false; | ||
| 102 | /* | ||
| 103 | * Check for "user." | ||
| 104 | */ | ||
| 105 | if ((ea->namelen >= XATTR_USER_PREFIX_LEN) && | ||
| 106 | !strncmp(ea->name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) | ||
| 107 | return false; | ||
| 108 | /* | ||
| 109 | * Check for "security." | ||
| 110 | */ | ||
| 111 | if ((ea->namelen >= XATTR_SECURITY_PREFIX_LEN) && | ||
| 112 | !strncmp(ea->name, XATTR_SECURITY_PREFIX, | ||
| 113 | XATTR_SECURITY_PREFIX_LEN)) | ||
| 114 | return false; | ||
| 115 | /* | ||
| 116 | * Check for "trusted." | ||
| 117 | */ | ||
| 118 | if ((ea->namelen >= XATTR_TRUSTED_PREFIX_LEN) && | ||
| 119 | !strncmp(ea->name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN)) | ||
| 120 | return false; | ||
| 121 | /* | ||
| 122 | * Add any other valid namespace prefixes here | ||
| 123 | */ | ||
| 124 | |||
| 125 | /* | ||
| 126 | * We assume it's OS/2's flat namespace | ||
| 127 | */ | ||
| 128 | return true; | ||
| 129 | } | 108 | } |
| 130 | 109 | ||
| 131 | static inline int name_size(struct jfs_ea *ea) | 110 | static inline int name_size(struct jfs_ea *ea) |
| @@ -764,13 +743,23 @@ static int can_set_xattr(struct inode *inode, const char *name, | |||
| 764 | if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) | 743 | if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN)) |
| 765 | return can_set_system_xattr(inode, name, value, value_len); | 744 | return can_set_system_xattr(inode, name, value, value_len); |
| 766 | 745 | ||
| 746 | if (!strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN)) { | ||
| 747 | /* | ||
| 748 | * This makes sure that we aren't trying to set an | ||
| 749 | * attribute in a different namespace by prefixing it | ||
| 750 | * with "os2." | ||
| 751 | */ | ||
| 752 | if (is_known_namespace(name + XATTR_OS2_PREFIX_LEN)) | ||
| 753 | return -EOPNOTSUPP; | ||
| 754 | return 0; | ||
| 755 | } | ||
| 756 | |||
| 767 | /* | 757 | /* |
| 768 | * Don't allow setting an attribute in an unknown namespace. | 758 | * Don't allow setting an attribute in an unknown namespace. |
| 769 | */ | 759 | */ |
| 770 | if (strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) && | 760 | if (strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) && |
| 771 | strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) && | 761 | strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) && |
| 772 | strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) && | 762 | strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) |
| 773 | strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN)) | ||
| 774 | return -EOPNOTSUPP; | 763 | return -EOPNOTSUPP; |
| 775 | 764 | ||
| 776 | return 0; | 765 | return 0; |
| @@ -952,19 +941,8 @@ ssize_t __jfs_getxattr(struct inode *inode, const char *name, void *data, | |||
| 952 | int xattr_size; | 941 | int xattr_size; |
| 953 | ssize_t size; | 942 | ssize_t size; |
| 954 | int namelen = strlen(name); | 943 | int namelen = strlen(name); |
| 955 | char *os2name = NULL; | ||
| 956 | char *value; | 944 | char *value; |
| 957 | 945 | ||
| 958 | if (strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) { | ||
| 959 | os2name = kmalloc(namelen - XATTR_OS2_PREFIX_LEN + 1, | ||
| 960 | GFP_KERNEL); | ||
| 961 | if (!os2name) | ||
| 962 | return -ENOMEM; | ||
| 963 | strcpy(os2name, name + XATTR_OS2_PREFIX_LEN); | ||
| 964 | name = os2name; | ||
| 965 | namelen -= XATTR_OS2_PREFIX_LEN; | ||
| 966 | } | ||
| 967 | |||
| 968 | down_read(&JFS_IP(inode)->xattr_sem); | 946 | down_read(&JFS_IP(inode)->xattr_sem); |
| 969 | 947 | ||
| 970 | xattr_size = ea_get(inode, &ea_buf, 0); | 948 | xattr_size = ea_get(inode, &ea_buf, 0); |
| @@ -1002,8 +980,6 @@ ssize_t __jfs_getxattr(struct inode *inode, const char *name, void *data, | |||
| 1002 | out: | 980 | out: |
| 1003 | up_read(&JFS_IP(inode)->xattr_sem); | 981 | up_read(&JFS_IP(inode)->xattr_sem); |
| 1004 | 982 | ||
| 1005 | kfree(os2name); | ||
| 1006 | |||
| 1007 | return size; | 983 | return size; |
| 1008 | } | 984 | } |
| 1009 | 985 | ||
| @@ -1012,6 +988,19 @@ ssize_t jfs_getxattr(struct dentry *dentry, const char *name, void *data, | |||
| 1012 | { | 988 | { |
| 1013 | int err; | 989 | int err; |
| 1014 | 990 | ||
| 991 | if (strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) { | ||
| 992 | /* | ||
| 993 | * skip past "os2." prefix | ||
| 994 | */ | ||
| 995 | name += XATTR_OS2_PREFIX_LEN; | ||
| 996 | /* | ||
| 997 | * Don't allow retrieving properly prefixed attributes | ||
| 998 | * by prepending them with "os2." | ||
| 999 | */ | ||
| 1000 | if (is_known_namespace(name)) | ||
| 1001 | return -EOPNOTSUPP; | ||
| 1002 | } | ||
| 1003 | |||
| 1015 | err = __jfs_getxattr(dentry->d_inode, name, data, buf_size); | 1004 | err = __jfs_getxattr(dentry->d_inode, name, data, buf_size); |
| 1016 | 1005 | ||
| 1017 | return err; | 1006 | return err; |
diff --git a/fs/libfs.c b/fs/libfs.c index dcaf972cbf1b..0a9da95317f7 100644 --- a/fs/libfs.c +++ b/fs/libfs.c | |||
| @@ -327,77 +327,35 @@ int simple_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
| 327 | } | 327 | } |
| 328 | 328 | ||
| 329 | /** | 329 | /** |
| 330 | * simple_setsize - handle core mm and vfs requirements for file size change | 330 | * simple_setattr - setattr for simple filesystem |
| 331 | * @inode: inode | ||
| 332 | * @newsize: new file size | ||
| 333 | * | ||
| 334 | * Returns 0 on success, -error on failure. | ||
| 335 | * | ||
| 336 | * simple_setsize must be called with inode_mutex held. | ||
| 337 | * | ||
| 338 | * simple_setsize will check that the requested new size is OK (see | ||
| 339 | * inode_newsize_ok), and then will perform the necessary i_size update | ||
| 340 | * and pagecache truncation (if necessary). It will be typically be called | ||
| 341 | * from the filesystem's setattr function when ATTR_SIZE is passed in. | ||
| 342 | * | ||
| 343 | * The inode itself must have correct permissions and attributes to allow | ||
| 344 | * i_size to be changed, this function then just checks that the new size | ||
| 345 | * requested is valid. | ||
| 346 | * | ||
| 347 | * In the case of simple in-memory filesystems with inodes stored solely | ||
| 348 | * in the inode cache, and file data in the pagecache, nothing more needs | ||
| 349 | * to be done to satisfy a truncate request. Filesystems with on-disk | ||
| 350 | * blocks for example will need to free them in the case of truncate, in | ||
| 351 | * that case it may be easier not to use simple_setsize (but each of its | ||
| 352 | * components will likely be required at some point to update pagecache | ||
| 353 | * and inode etc). | ||
| 354 | */ | ||
| 355 | int simple_setsize(struct inode *inode, loff_t newsize) | ||
| 356 | { | ||
| 357 | loff_t oldsize; | ||
| 358 | int error; | ||
| 359 | |||
| 360 | error = inode_newsize_ok(inode, newsize); | ||
| 361 | if (error) | ||
| 362 | return error; | ||
| 363 | |||
| 364 | oldsize = inode->i_size; | ||
| 365 | i_size_write(inode, newsize); | ||
| 366 | truncate_pagecache(inode, oldsize, newsize); | ||
| 367 | |||
| 368 | return error; | ||
| 369 | } | ||
| 370 | EXPORT_SYMBOL(simple_setsize); | ||
| 371 | |||
| 372 | /** | ||
| 373 | * simple_setattr - setattr for simple in-memory filesystem | ||
| 374 | * @dentry: dentry | 331 | * @dentry: dentry |
| 375 | * @iattr: iattr structure | 332 | * @iattr: iattr structure |
| 376 | * | 333 | * |
| 377 | * Returns 0 on success, -error on failure. | 334 | * Returns 0 on success, -error on failure. |
| 378 | * | 335 | * |
| 379 | * simple_setattr implements setattr for an in-memory filesystem which | 336 | * simple_setattr is a simple ->setattr implementation without a proper |
| 380 | * does not store its own file data or metadata (eg. uses the page cache | 337 | * implementation of size changes. |
| 381 | * and inode cache as its data store). | 338 | * |
| 339 | * It can either be used for in-memory filesystems or special files | ||
| 340 | * on simple regular filesystems. Anything that needs to change on-disk | ||
| 341 | * or wire state on size changes needs its own setattr method. | ||
| 382 | */ | 342 | */ |
| 383 | int simple_setattr(struct dentry *dentry, struct iattr *iattr) | 343 | int simple_setattr(struct dentry *dentry, struct iattr *iattr) |
| 384 | { | 344 | { |
| 385 | struct inode *inode = dentry->d_inode; | 345 | struct inode *inode = dentry->d_inode; |
| 386 | int error; | 346 | int error; |
| 387 | 347 | ||
| 348 | WARN_ON_ONCE(inode->i_op->truncate); | ||
| 349 | |||
| 388 | error = inode_change_ok(inode, iattr); | 350 | error = inode_change_ok(inode, iattr); |
| 389 | if (error) | 351 | if (error) |
| 390 | return error; | 352 | return error; |
| 391 | 353 | ||
| 392 | if (iattr->ia_valid & ATTR_SIZE) { | 354 | if (iattr->ia_valid & ATTR_SIZE) |
| 393 | error = simple_setsize(inode, iattr->ia_size); | 355 | truncate_setsize(inode, iattr->ia_size); |
| 394 | if (error) | 356 | setattr_copy(inode, iattr); |
| 395 | return error; | 357 | mark_inode_dirty(inode); |
| 396 | } | 358 | return 0; |
| 397 | |||
| 398 | generic_setattr(inode, iattr); | ||
| 399 | |||
| 400 | return error; | ||
| 401 | } | 359 | } |
| 402 | EXPORT_SYMBOL(simple_setattr); | 360 | EXPORT_SYMBOL(simple_setattr); |
| 403 | 361 | ||
diff --git a/fs/logfs/dir.c b/fs/logfs/dir.c index 72d1893ddd36..9777eb5b5522 100644 --- a/fs/logfs/dir.c +++ b/fs/logfs/dir.c | |||
| @@ -434,8 +434,11 @@ static int __logfs_create(struct inode *dir, struct dentry *dentry, | |||
| 434 | int ret; | 434 | int ret; |
| 435 | 435 | ||
| 436 | ta = kzalloc(sizeof(*ta), GFP_KERNEL); | 436 | ta = kzalloc(sizeof(*ta), GFP_KERNEL); |
| 437 | if (!ta) | 437 | if (!ta) { |
| 438 | inode->i_nlink--; | ||
| 439 | iput(inode); | ||
| 438 | return -ENOMEM; | 440 | return -ENOMEM; |
| 441 | } | ||
| 439 | 442 | ||
| 440 | ta->state = CREATE_1; | 443 | ta->state = CREATE_1; |
| 441 | ta->ino = inode->i_ino; | 444 | ta->ino = inode->i_ino; |
| @@ -821,7 +824,7 @@ const struct inode_operations logfs_dir_iops = { | |||
| 821 | }; | 824 | }; |
| 822 | const struct file_operations logfs_dir_fops = { | 825 | const struct file_operations logfs_dir_fops = { |
| 823 | .fsync = logfs_fsync, | 826 | .fsync = logfs_fsync, |
| 824 | .ioctl = logfs_ioctl, | 827 | .unlocked_ioctl = logfs_ioctl, |
| 825 | .readdir = logfs_readdir, | 828 | .readdir = logfs_readdir, |
| 826 | .read = generic_read_dir, | 829 | .read = generic_read_dir, |
| 827 | }; | 830 | }; |
diff --git a/fs/logfs/file.c b/fs/logfs/file.c index abe1cafbd4c2..e86376b87af1 100644 --- a/fs/logfs/file.c +++ b/fs/logfs/file.c | |||
| @@ -181,9 +181,9 @@ static int logfs_releasepage(struct page *page, gfp_t only_xfs_uses_this) | |||
| 181 | } | 181 | } |
| 182 | 182 | ||
| 183 | 183 | ||
| 184 | int logfs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | 184 | long logfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
| 185 | unsigned long arg) | ||
| 186 | { | 185 | { |
| 186 | struct inode *inode = file->f_path.dentry->d_inode; | ||
| 187 | struct logfs_inode *li = logfs_inode(inode); | 187 | struct logfs_inode *li = logfs_inode(inode); |
| 188 | unsigned int oldflags, flags; | 188 | unsigned int oldflags, flags; |
| 189 | int err; | 189 | int err; |
| @@ -232,15 +232,19 @@ static int logfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 232 | struct inode *inode = dentry->d_inode; | 232 | struct inode *inode = dentry->d_inode; |
| 233 | int err = 0; | 233 | int err = 0; |
| 234 | 234 | ||
| 235 | if (attr->ia_valid & ATTR_SIZE) | 235 | err = inode_change_ok(inode, attr); |
| 236 | if (err) | ||
| 237 | return err; | ||
| 238 | |||
| 239 | if (attr->ia_valid & ATTR_SIZE) { | ||
| 236 | err = logfs_truncate(inode, attr->ia_size); | 240 | err = logfs_truncate(inode, attr->ia_size); |
| 237 | attr->ia_valid &= ~ATTR_SIZE; | 241 | if (err) |
| 242 | return err; | ||
| 243 | } | ||
| 238 | 244 | ||
| 239 | if (!err) | 245 | setattr_copy(inode, attr); |
| 240 | err = inode_change_ok(inode, attr); | 246 | mark_inode_dirty(inode); |
| 241 | if (!err) | 247 | return 0; |
| 242 | err = inode_setattr(inode, attr); | ||
| 243 | return err; | ||
| 244 | } | 248 | } |
| 245 | 249 | ||
| 246 | const struct inode_operations logfs_reg_iops = { | 250 | const struct inode_operations logfs_reg_iops = { |
| @@ -251,7 +255,7 @@ const struct file_operations logfs_reg_fops = { | |||
| 251 | .aio_read = generic_file_aio_read, | 255 | .aio_read = generic_file_aio_read, |
| 252 | .aio_write = generic_file_aio_write, | 256 | .aio_write = generic_file_aio_write, |
| 253 | .fsync = logfs_fsync, | 257 | .fsync = logfs_fsync, |
| 254 | .ioctl = logfs_ioctl, | 258 | .unlocked_ioctl = logfs_ioctl, |
| 255 | .llseek = generic_file_llseek, | 259 | .llseek = generic_file_llseek, |
| 256 | .mmap = generic_file_readonly_mmap, | 260 | .mmap = generic_file_readonly_mmap, |
| 257 | .open = generic_file_open, | 261 | .open = generic_file_open, |
diff --git a/fs/logfs/inode.c b/fs/logfs/inode.c index f602e230e162..d8c71ece098f 100644 --- a/fs/logfs/inode.c +++ b/fs/logfs/inode.c | |||
| @@ -235,33 +235,21 @@ static struct inode *logfs_alloc_inode(struct super_block *sb) | |||
| 235 | * purpose is to create a new inode that will not trigger the warning if such | 235 | * purpose is to create a new inode that will not trigger the warning if such |
| 236 | * an inode is still in use. An ugly hack, no doubt. Suggections for | 236 | * an inode is still in use. An ugly hack, no doubt. Suggections for |
| 237 | * improvement are welcome. | 237 | * improvement are welcome. |
| 238 | * | ||
| 239 | * AV: that's what ->put_super() is for... | ||
| 238 | */ | 240 | */ |
| 239 | struct inode *logfs_new_meta_inode(struct super_block *sb, u64 ino) | 241 | struct inode *logfs_new_meta_inode(struct super_block *sb, u64 ino) |
| 240 | { | 242 | { |
| 241 | struct inode *inode; | 243 | struct inode *inode; |
| 242 | 244 | ||
| 243 | inode = logfs_alloc_inode(sb); | 245 | inode = new_inode(sb); |
| 244 | if (!inode) | 246 | if (!inode) |
| 245 | return ERR_PTR(-ENOMEM); | 247 | return ERR_PTR(-ENOMEM); |
| 246 | 248 | ||
| 247 | inode->i_mode = S_IFREG; | 249 | inode->i_mode = S_IFREG; |
| 248 | inode->i_ino = ino; | 250 | inode->i_ino = ino; |
| 249 | inode->i_sb = sb; | 251 | inode->i_data.a_ops = &logfs_reg_aops; |
| 250 | 252 | mapping_set_gfp_mask(&inode->i_data, GFP_NOFS); | |
| 251 | /* This is a blatant copy of alloc_inode code. We'd need alloc_inode | ||
| 252 | * to be nonstatic, alas. */ | ||
| 253 | { | ||
| 254 | struct address_space * const mapping = &inode->i_data; | ||
| 255 | |||
| 256 | mapping->a_ops = &logfs_reg_aops; | ||
| 257 | mapping->host = inode; | ||
| 258 | mapping->flags = 0; | ||
| 259 | mapping_set_gfp_mask(mapping, GFP_NOFS); | ||
| 260 | mapping->assoc_mapping = NULL; | ||
| 261 | mapping->backing_dev_info = &default_backing_dev_info; | ||
| 262 | inode->i_mapping = mapping; | ||
| 263 | inode->i_nlink = 1; | ||
| 264 | } | ||
| 265 | 253 | ||
| 266 | return inode; | 254 | return inode; |
| 267 | } | 255 | } |
| @@ -277,7 +265,7 @@ struct inode *logfs_read_meta_inode(struct super_block *sb, u64 ino) | |||
| 277 | 265 | ||
| 278 | err = logfs_read_inode(inode); | 266 | err = logfs_read_inode(inode); |
| 279 | if (err) { | 267 | if (err) { |
| 280 | destroy_meta_inode(inode); | 268 | iput(inode); |
| 281 | return ERR_PTR(err); | 269 | return ERR_PTR(err); |
| 282 | } | 270 | } |
| 283 | logfs_inode_setops(inode); | 271 | logfs_inode_setops(inode); |
| @@ -298,18 +286,8 @@ static int logfs_write_inode(struct inode *inode, struct writeback_control *wbc) | |||
| 298 | return ret; | 286 | return ret; |
| 299 | } | 287 | } |
| 300 | 288 | ||
| 301 | void destroy_meta_inode(struct inode *inode) | ||
| 302 | { | ||
| 303 | if (inode) { | ||
| 304 | if (inode->i_data.nrpages) | ||
| 305 | truncate_inode_pages(&inode->i_data, 0); | ||
| 306 | logfs_clear_inode(inode); | ||
| 307 | kmem_cache_free(logfs_inode_cache, logfs_inode(inode)); | ||
| 308 | } | ||
| 309 | } | ||
| 310 | |||
| 311 | /* called with inode_lock held */ | 289 | /* called with inode_lock held */ |
| 312 | static void logfs_drop_inode(struct inode *inode) | 290 | static int logfs_drop_inode(struct inode *inode) |
| 313 | { | 291 | { |
| 314 | struct logfs_super *super = logfs_super(inode->i_sb); | 292 | struct logfs_super *super = logfs_super(inode->i_sb); |
| 315 | struct logfs_inode *li = logfs_inode(inode); | 293 | struct logfs_inode *li = logfs_inode(inode); |
| @@ -317,7 +295,7 @@ static void logfs_drop_inode(struct inode *inode) | |||
| 317 | spin_lock(&logfs_inode_lock); | 295 | spin_lock(&logfs_inode_lock); |
| 318 | list_move(&li->li_freeing_list, &super->s_freeing_list); | 296 | list_move(&li->li_freeing_list, &super->s_freeing_list); |
| 319 | spin_unlock(&logfs_inode_lock); | 297 | spin_unlock(&logfs_inode_lock); |
| 320 | generic_drop_inode(inode); | 298 | return generic_drop_inode(inode); |
| 321 | } | 299 | } |
| 322 | 300 | ||
| 323 | static void logfs_set_ino_generation(struct super_block *sb, | 301 | static void logfs_set_ino_generation(struct super_block *sb, |
| @@ -384,12 +362,21 @@ static int logfs_sync_fs(struct super_block *sb, int wait) | |||
| 384 | return 0; | 362 | return 0; |
| 385 | } | 363 | } |
| 386 | 364 | ||
| 365 | static void logfs_put_super(struct super_block *sb) | ||
| 366 | { | ||
| 367 | struct logfs_super *super = logfs_super(sb); | ||
| 368 | /* kill the meta-inodes */ | ||
| 369 | iput(super->s_master_inode); | ||
| 370 | iput(super->s_segfile_inode); | ||
| 371 | iput(super->s_mapping_inode); | ||
| 372 | } | ||
| 373 | |||
| 387 | const struct super_operations logfs_super_operations = { | 374 | const struct super_operations logfs_super_operations = { |
| 388 | .alloc_inode = logfs_alloc_inode, | 375 | .alloc_inode = logfs_alloc_inode, |
| 389 | .clear_inode = logfs_clear_inode, | ||
| 390 | .delete_inode = logfs_delete_inode, | ||
| 391 | .destroy_inode = logfs_destroy_inode, | 376 | .destroy_inode = logfs_destroy_inode, |
| 377 | .evict_inode = logfs_evict_inode, | ||
| 392 | .drop_inode = logfs_drop_inode, | 378 | .drop_inode = logfs_drop_inode, |
| 379 | .put_super = logfs_put_super, | ||
| 393 | .write_inode = logfs_write_inode, | 380 | .write_inode = logfs_write_inode, |
| 394 | .statfs = logfs_statfs, | 381 | .statfs = logfs_statfs, |
| 395 | .sync_fs = logfs_sync_fs, | 382 | .sync_fs = logfs_sync_fs, |
diff --git a/fs/logfs/journal.c b/fs/logfs/journal.c index 4b0e0616b357..f46ee8b0e135 100644 --- a/fs/logfs/journal.c +++ b/fs/logfs/journal.c | |||
| @@ -889,8 +889,6 @@ void logfs_cleanup_journal(struct super_block *sb) | |||
| 889 | struct logfs_super *super = logfs_super(sb); | 889 | struct logfs_super *super = logfs_super(sb); |
| 890 | 890 | ||
| 891 | btree_grim_visitor32(&super->s_reserved_segments, 0, NULL); | 891 | btree_grim_visitor32(&super->s_reserved_segments, 0, NULL); |
| 892 | destroy_meta_inode(super->s_master_inode); | ||
| 893 | super->s_master_inode = NULL; | ||
| 894 | 892 | ||
| 895 | kfree(super->s_compressed_je); | 893 | kfree(super->s_compressed_je); |
| 896 | kfree(super->s_je); | 894 | kfree(super->s_je); |
diff --git a/fs/logfs/logfs.h b/fs/logfs/logfs.h index c838c4d72111..b8786264d243 100644 --- a/fs/logfs/logfs.h +++ b/fs/logfs/logfs.h | |||
| @@ -504,8 +504,7 @@ extern const struct inode_operations logfs_reg_iops; | |||
| 504 | extern const struct file_operations logfs_reg_fops; | 504 | extern const struct file_operations logfs_reg_fops; |
| 505 | extern const struct address_space_operations logfs_reg_aops; | 505 | extern const struct address_space_operations logfs_reg_aops; |
| 506 | int logfs_readpage(struct file *file, struct page *page); | 506 | int logfs_readpage(struct file *file, struct page *page); |
| 507 | int logfs_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | 507 | long logfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg); |
| 508 | unsigned long arg); | ||
| 509 | int logfs_fsync(struct file *file, int datasync); | 508 | int logfs_fsync(struct file *file, int datasync); |
| 510 | 509 | ||
| 511 | /* gc.c */ | 510 | /* gc.c */ |
| @@ -525,13 +524,11 @@ struct inode *logfs_new_meta_inode(struct super_block *sb, u64 ino); | |||
| 525 | struct inode *logfs_read_meta_inode(struct super_block *sb, u64 ino); | 524 | struct inode *logfs_read_meta_inode(struct super_block *sb, u64 ino); |
| 526 | int logfs_init_inode_cache(void); | 525 | int logfs_init_inode_cache(void); |
| 527 | void logfs_destroy_inode_cache(void); | 526 | void logfs_destroy_inode_cache(void); |
| 528 | void destroy_meta_inode(struct inode *inode); | ||
| 529 | void logfs_set_blocks(struct inode *inode, u64 no); | 527 | void logfs_set_blocks(struct inode *inode, u64 no); |
| 530 | /* these logically belong into inode.c but actually reside in readwrite.c */ | 528 | /* these logically belong into inode.c but actually reside in readwrite.c */ |
| 531 | int logfs_read_inode(struct inode *inode); | 529 | int logfs_read_inode(struct inode *inode); |
| 532 | int __logfs_write_inode(struct inode *inode, long flags); | 530 | int __logfs_write_inode(struct inode *inode, long flags); |
| 533 | void logfs_delete_inode(struct inode *inode); | 531 | void logfs_evict_inode(struct inode *inode); |
| 534 | void logfs_clear_inode(struct inode *inode); | ||
| 535 | 532 | ||
| 536 | /* journal.c */ | 533 | /* journal.c */ |
| 537 | void logfs_write_anchor(struct super_block *sb); | 534 | void logfs_write_anchor(struct super_block *sb); |
diff --git a/fs/logfs/readwrite.c b/fs/logfs/readwrite.c index 0718d112a1a5..6127baf0e188 100644 --- a/fs/logfs/readwrite.c +++ b/fs/logfs/readwrite.c | |||
| @@ -1972,31 +1972,6 @@ static struct page *inode_to_page(struct inode *inode) | |||
| 1972 | return page; | 1972 | return page; |
| 1973 | } | 1973 | } |
| 1974 | 1974 | ||
| 1975 | /* Cheaper version of write_inode. All changes are concealed in | ||
| 1976 | * aliases, which are moved back. No write to the medium happens. | ||
| 1977 | */ | ||
| 1978 | void logfs_clear_inode(struct inode *inode) | ||
| 1979 | { | ||
| 1980 | struct super_block *sb = inode->i_sb; | ||
| 1981 | struct logfs_inode *li = logfs_inode(inode); | ||
| 1982 | struct logfs_block *block = li->li_block; | ||
| 1983 | struct page *page; | ||
| 1984 | |||
| 1985 | /* Only deleted files may be dirty at this point */ | ||
| 1986 | BUG_ON(inode->i_state & I_DIRTY && inode->i_nlink); | ||
| 1987 | if (!block) | ||
| 1988 | return; | ||
| 1989 | if ((logfs_super(sb)->s_flags & LOGFS_SB_FLAG_SHUTDOWN)) { | ||
| 1990 | block->ops->free_block(inode->i_sb, block); | ||
| 1991 | return; | ||
| 1992 | } | ||
| 1993 | |||
| 1994 | BUG_ON(inode->i_ino < LOGFS_RESERVED_INOS); | ||
| 1995 | page = inode_to_page(inode); | ||
| 1996 | BUG_ON(!page); /* FIXME: Use emergency page */ | ||
| 1997 | logfs_put_write_page(page); | ||
| 1998 | } | ||
| 1999 | |||
| 2000 | static int do_write_inode(struct inode *inode) | 1975 | static int do_write_inode(struct inode *inode) |
| 2001 | { | 1976 | { |
| 2002 | struct super_block *sb = inode->i_sb; | 1977 | struct super_block *sb = inode->i_sb; |
| @@ -2164,18 +2139,40 @@ static int do_delete_inode(struct inode *inode) | |||
| 2164 | * ZOMBIE inodes have already been deleted before and should remain dead, | 2139 | * ZOMBIE inodes have already been deleted before and should remain dead, |
| 2165 | * if it weren't for valid checking. No need to kill them again here. | 2140 | * if it weren't for valid checking. No need to kill them again here. |
| 2166 | */ | 2141 | */ |
| 2167 | void logfs_delete_inode(struct inode *inode) | 2142 | void logfs_evict_inode(struct inode *inode) |
| 2168 | { | 2143 | { |
| 2144 | struct super_block *sb = inode->i_sb; | ||
| 2169 | struct logfs_inode *li = logfs_inode(inode); | 2145 | struct logfs_inode *li = logfs_inode(inode); |
| 2146 | struct logfs_block *block = li->li_block; | ||
| 2147 | struct page *page; | ||
| 2170 | 2148 | ||
| 2171 | if (!(li->li_flags & LOGFS_IF_ZOMBIE)) { | 2149 | if (!inode->i_nlink) { |
| 2172 | li->li_flags |= LOGFS_IF_ZOMBIE; | 2150 | if (!(li->li_flags & LOGFS_IF_ZOMBIE)) { |
| 2173 | if (i_size_read(inode) > 0) | 2151 | li->li_flags |= LOGFS_IF_ZOMBIE; |
| 2174 | logfs_truncate(inode, 0); | 2152 | if (i_size_read(inode) > 0) |
| 2175 | do_delete_inode(inode); | 2153 | logfs_truncate(inode, 0); |
| 2154 | do_delete_inode(inode); | ||
| 2155 | } | ||
| 2176 | } | 2156 | } |
| 2177 | truncate_inode_pages(&inode->i_data, 0); | 2157 | truncate_inode_pages(&inode->i_data, 0); |
| 2178 | clear_inode(inode); | 2158 | end_writeback(inode); |
| 2159 | |||
| 2160 | /* Cheaper version of write_inode. All changes are concealed in | ||
| 2161 | * aliases, which are moved back. No write to the medium happens. | ||
| 2162 | */ | ||
| 2163 | /* Only deleted files may be dirty at this point */ | ||
| 2164 | BUG_ON(inode->i_state & I_DIRTY && inode->i_nlink); | ||
| 2165 | if (!block) | ||
| 2166 | return; | ||
| 2167 | if ((logfs_super(sb)->s_flags & LOGFS_SB_FLAG_SHUTDOWN)) { | ||
| 2168 | block->ops->free_block(inode->i_sb, block); | ||
| 2169 | return; | ||
| 2170 | } | ||
| 2171 | |||
| 2172 | BUG_ON(inode->i_ino < LOGFS_RESERVED_INOS); | ||
| 2173 | page = inode_to_page(inode); | ||
| 2174 | BUG_ON(!page); /* FIXME: Use emergency page */ | ||
| 2175 | logfs_put_write_page(page); | ||
| 2179 | } | 2176 | } |
| 2180 | 2177 | ||
| 2181 | void btree_write_block(struct logfs_block *block) | 2178 | void btree_write_block(struct logfs_block *block) |
| @@ -2272,7 +2269,6 @@ void logfs_cleanup_rw(struct super_block *sb) | |||
| 2272 | { | 2269 | { |
| 2273 | struct logfs_super *super = logfs_super(sb); | 2270 | struct logfs_super *super = logfs_super(sb); |
| 2274 | 2271 | ||
| 2275 | destroy_meta_inode(super->s_segfile_inode); | ||
| 2276 | logfs_mempool_destroy(super->s_block_pool); | 2272 | logfs_mempool_destroy(super->s_block_pool); |
| 2277 | logfs_mempool_destroy(super->s_shadow_pool); | 2273 | logfs_mempool_destroy(super->s_shadow_pool); |
| 2278 | } | 2274 | } |
diff --git a/fs/logfs/segment.c b/fs/logfs/segment.c index a9657afb70ad..9d5187353255 100644 --- a/fs/logfs/segment.c +++ b/fs/logfs/segment.c | |||
| @@ -929,5 +929,4 @@ void logfs_cleanup_areas(struct super_block *sb) | |||
| 929 | for_each_area(i) | 929 | for_each_area(i) |
| 930 | free_area(super->s_area[i]); | 930 | free_area(super->s_area[i]); |
| 931 | free_area(super->s_journal_area); | 931 | free_area(super->s_journal_area); |
| 932 | destroy_meta_inode(super->s_mapping_inode); | ||
| 933 | } | 932 | } |
diff --git a/fs/logfs/super.c b/fs/logfs/super.c index d651e10a1e9c..5336155c5d81 100644 --- a/fs/logfs/super.c +++ b/fs/logfs/super.c | |||
| @@ -342,24 +342,27 @@ static int logfs_get_sb_final(struct super_block *sb, struct vfsmount *mnt) | |||
| 342 | goto fail; | 342 | goto fail; |
| 343 | } | 343 | } |
| 344 | 344 | ||
| 345 | /* at that point we know that ->put_super() will be called */ | ||
| 345 | super->s_erase_page = alloc_pages(GFP_KERNEL, 0); | 346 | super->s_erase_page = alloc_pages(GFP_KERNEL, 0); |
| 346 | if (!super->s_erase_page) | 347 | if (!super->s_erase_page) |
| 347 | goto fail; | 348 | return -ENOMEM; |
| 348 | memset(page_address(super->s_erase_page), 0xFF, PAGE_SIZE); | 349 | memset(page_address(super->s_erase_page), 0xFF, PAGE_SIZE); |
| 349 | 350 | ||
| 350 | /* FIXME: check for read-only mounts */ | 351 | /* FIXME: check for read-only mounts */ |
| 351 | err = logfs_make_writeable(sb); | 352 | err = logfs_make_writeable(sb); |
| 352 | if (err) | 353 | if (err) { |
| 353 | goto fail1; | 354 | __free_page(super->s_erase_page); |
| 355 | return err; | ||
| 356 | } | ||
| 354 | 357 | ||
| 355 | log_super("LogFS: Finished mounting\n"); | 358 | log_super("LogFS: Finished mounting\n"); |
| 356 | simple_set_mnt(mnt, sb); | 359 | simple_set_mnt(mnt, sb); |
| 357 | return 0; | 360 | return 0; |
| 358 | 361 | ||
| 359 | fail1: | ||
| 360 | __free_page(super->s_erase_page); | ||
| 361 | fail: | 362 | fail: |
| 362 | iput(logfs_super(sb)->s_master_inode); | 363 | iput(super->s_master_inode); |
| 364 | iput(super->s_segfile_inode); | ||
| 365 | iput(super->s_mapping_inode); | ||
| 363 | return -EIO; | 366 | return -EIO; |
| 364 | } | 367 | } |
| 365 | 368 | ||
| @@ -580,10 +583,14 @@ int logfs_get_sb_device(struct file_system_type *type, int flags, | |||
| 580 | sb->s_flags |= MS_ACTIVE; | 583 | sb->s_flags |= MS_ACTIVE; |
| 581 | err = logfs_get_sb_final(sb, mnt); | 584 | err = logfs_get_sb_final(sb, mnt); |
| 582 | if (err) | 585 | if (err) |
| 583 | goto err1; | 586 | deactivate_locked_super(sb); |
| 584 | return 0; | 587 | return err; |
| 585 | 588 | ||
| 586 | err1: | 589 | err1: |
| 590 | /* no ->s_root, no ->put_super() */ | ||
| 591 | iput(super->s_master_inode); | ||
| 592 | iput(super->s_segfile_inode); | ||
| 593 | iput(super->s_mapping_inode); | ||
| 587 | deactivate_locked_super(sb); | 594 | deactivate_locked_super(sb); |
| 588 | return err; | 595 | return err; |
| 589 | err0: | 596 | err0: |
diff --git a/fs/mbcache.c b/fs/mbcache.c index e28f21b95344..cf4e6cdfd15b 100644 --- a/fs/mbcache.c +++ b/fs/mbcache.c | |||
| @@ -79,15 +79,11 @@ EXPORT_SYMBOL(mb_cache_entry_find_next); | |||
| 79 | struct mb_cache { | 79 | struct mb_cache { |
| 80 | struct list_head c_cache_list; | 80 | struct list_head c_cache_list; |
| 81 | const char *c_name; | 81 | const char *c_name; |
| 82 | struct mb_cache_op c_op; | ||
| 83 | atomic_t c_entry_count; | 82 | atomic_t c_entry_count; |
| 84 | int c_bucket_bits; | 83 | int c_bucket_bits; |
| 85 | #ifndef MB_CACHE_INDEXES_COUNT | 84 | struct kmem_cache *c_entry_cache; |
| 86 | int c_indexes_count; | ||
| 87 | #endif | ||
| 88 | struct kmem_cache *c_entry_cache; | ||
| 89 | struct list_head *c_block_hash; | 85 | struct list_head *c_block_hash; |
| 90 | struct list_head *c_indexes_hash[0]; | 86 | struct list_head *c_index_hash; |
| 91 | }; | 87 | }; |
| 92 | 88 | ||
| 93 | 89 | ||
| @@ -101,16 +97,6 @@ static LIST_HEAD(mb_cache_list); | |||
| 101 | static LIST_HEAD(mb_cache_lru_list); | 97 | static LIST_HEAD(mb_cache_lru_list); |
| 102 | static DEFINE_SPINLOCK(mb_cache_spinlock); | 98 | static DEFINE_SPINLOCK(mb_cache_spinlock); |
| 103 | 99 | ||
| 104 | static inline int | ||
| 105 | mb_cache_indexes(struct mb_cache *cache) | ||
| 106 | { | ||
| 107 | #ifdef MB_CACHE_INDEXES_COUNT | ||
| 108 | return MB_CACHE_INDEXES_COUNT; | ||
| 109 | #else | ||
| 110 | return cache->c_indexes_count; | ||
| 111 | #endif | ||
| 112 | } | ||
| 113 | |||
| 114 | /* | 100 | /* |
| 115 | * What the mbcache registers as to get shrunk dynamically. | 101 | * What the mbcache registers as to get shrunk dynamically. |
| 116 | */ | 102 | */ |
| @@ -132,12 +118,9 @@ __mb_cache_entry_is_hashed(struct mb_cache_entry *ce) | |||
| 132 | static void | 118 | static void |
| 133 | __mb_cache_entry_unhash(struct mb_cache_entry *ce) | 119 | __mb_cache_entry_unhash(struct mb_cache_entry *ce) |
| 134 | { | 120 | { |
| 135 | int n; | ||
| 136 | |||
| 137 | if (__mb_cache_entry_is_hashed(ce)) { | 121 | if (__mb_cache_entry_is_hashed(ce)) { |
| 138 | list_del_init(&ce->e_block_list); | 122 | list_del_init(&ce->e_block_list); |
| 139 | for (n=0; n<mb_cache_indexes(ce->e_cache); n++) | 123 | list_del(&ce->e_index.o_list); |
| 140 | list_del(&ce->e_indexes[n].o_list); | ||
| 141 | } | 124 | } |
| 142 | } | 125 | } |
| 143 | 126 | ||
| @@ -148,16 +131,8 @@ __mb_cache_entry_forget(struct mb_cache_entry *ce, gfp_t gfp_mask) | |||
| 148 | struct mb_cache *cache = ce->e_cache; | 131 | struct mb_cache *cache = ce->e_cache; |
| 149 | 132 | ||
| 150 | mb_assert(!(ce->e_used || ce->e_queued)); | 133 | mb_assert(!(ce->e_used || ce->e_queued)); |
| 151 | if (cache->c_op.free && cache->c_op.free(ce, gfp_mask)) { | 134 | kmem_cache_free(cache->c_entry_cache, ce); |
| 152 | /* free failed -- put back on the lru list | 135 | atomic_dec(&cache->c_entry_count); |
| 153 | for freeing later. */ | ||
| 154 | spin_lock(&mb_cache_spinlock); | ||
| 155 | list_add(&ce->e_lru_list, &mb_cache_lru_list); | ||
| 156 | spin_unlock(&mb_cache_spinlock); | ||
| 157 | } else { | ||
| 158 | kmem_cache_free(cache->c_entry_cache, ce); | ||
| 159 | atomic_dec(&cache->c_entry_count); | ||
| 160 | } | ||
| 161 | } | 136 | } |
| 162 | 137 | ||
| 163 | 138 | ||
| @@ -201,22 +176,12 @@ static int | |||
| 201 | mb_cache_shrink_fn(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask) | 176 | mb_cache_shrink_fn(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask) |
| 202 | { | 177 | { |
| 203 | LIST_HEAD(free_list); | 178 | LIST_HEAD(free_list); |
| 204 | struct list_head *l, *ltmp; | 179 | struct mb_cache *cache; |
| 180 | struct mb_cache_entry *entry, *tmp; | ||
| 205 | int count = 0; | 181 | int count = 0; |
| 206 | 182 | ||
| 207 | spin_lock(&mb_cache_spinlock); | ||
| 208 | list_for_each(l, &mb_cache_list) { | ||
| 209 | struct mb_cache *cache = | ||
| 210 | list_entry(l, struct mb_cache, c_cache_list); | ||
| 211 | mb_debug("cache %s (%d)", cache->c_name, | ||
| 212 | atomic_read(&cache->c_entry_count)); | ||
| 213 | count += atomic_read(&cache->c_entry_count); | ||
| 214 | } | ||
| 215 | mb_debug("trying to free %d entries", nr_to_scan); | 183 | mb_debug("trying to free %d entries", nr_to_scan); |
| 216 | if (nr_to_scan == 0) { | 184 | spin_lock(&mb_cache_spinlock); |
| 217 | spin_unlock(&mb_cache_spinlock); | ||
| 218 | goto out; | ||
| 219 | } | ||
| 220 | while (nr_to_scan-- && !list_empty(&mb_cache_lru_list)) { | 185 | while (nr_to_scan-- && !list_empty(&mb_cache_lru_list)) { |
| 221 | struct mb_cache_entry *ce = | 186 | struct mb_cache_entry *ce = |
| 222 | list_entry(mb_cache_lru_list.next, | 187 | list_entry(mb_cache_lru_list.next, |
| @@ -224,12 +189,15 @@ mb_cache_shrink_fn(struct shrinker *shrink, int nr_to_scan, gfp_t gfp_mask) | |||
| 224 | list_move_tail(&ce->e_lru_list, &free_list); | 189 | list_move_tail(&ce->e_lru_list, &free_list); |
| 225 | __mb_cache_entry_unhash(ce); | 190 | __mb_cache_entry_unhash(ce); |
| 226 | } | 191 | } |
| 192 | list_for_each_entry(cache, &mb_cache_list, c_cache_list) { | ||
| 193 | mb_debug("cache %s (%d)", cache->c_name, | ||
| 194 | atomic_read(&cache->c_entry_count)); | ||
| 195 | count += atomic_read(&cache->c_entry_count); | ||
| 196 | } | ||
| 227 | spin_unlock(&mb_cache_spinlock); | 197 | spin_unlock(&mb_cache_spinlock); |
| 228 | list_for_each_safe(l, ltmp, &free_list) { | 198 | list_for_each_entry_safe(entry, tmp, &free_list, e_lru_list) { |
| 229 | __mb_cache_entry_forget(list_entry(l, struct mb_cache_entry, | 199 | __mb_cache_entry_forget(entry, gfp_mask); |
| 230 | e_lru_list), gfp_mask); | ||
| 231 | } | 200 | } |
| 232 | out: | ||
| 233 | return (count / 100) * sysctl_vfs_cache_pressure; | 201 | return (count / 100) * sysctl_vfs_cache_pressure; |
| 234 | } | 202 | } |
| 235 | 203 | ||
| @@ -243,72 +211,49 @@ out: | |||
| 243 | * memory was available. | 211 | * memory was available. |
| 244 | * | 212 | * |
| 245 | * @name: name of the cache (informal) | 213 | * @name: name of the cache (informal) |
| 246 | * @cache_op: contains the callback called when freeing a cache entry | ||
| 247 | * @entry_size: The size of a cache entry, including | ||
| 248 | * struct mb_cache_entry | ||
| 249 | * @indexes_count: number of additional indexes in the cache. Must equal | ||
| 250 | * MB_CACHE_INDEXES_COUNT if the number of indexes is | ||
| 251 | * hardwired. | ||
| 252 | * @bucket_bits: log2(number of hash buckets) | 214 | * @bucket_bits: log2(number of hash buckets) |
| 253 | */ | 215 | */ |
| 254 | struct mb_cache * | 216 | struct mb_cache * |
| 255 | mb_cache_create(const char *name, struct mb_cache_op *cache_op, | 217 | mb_cache_create(const char *name, int bucket_bits) |
| 256 | size_t entry_size, int indexes_count, int bucket_bits) | ||
| 257 | { | 218 | { |
| 258 | int m=0, n, bucket_count = 1 << bucket_bits; | 219 | int n, bucket_count = 1 << bucket_bits; |
| 259 | struct mb_cache *cache = NULL; | 220 | struct mb_cache *cache = NULL; |
| 260 | 221 | ||
| 261 | if(entry_size < sizeof(struct mb_cache_entry) + | 222 | cache = kmalloc(sizeof(struct mb_cache), GFP_KERNEL); |
| 262 | indexes_count * sizeof(((struct mb_cache_entry *) 0)->e_indexes[0])) | ||
| 263 | return NULL; | ||
| 264 | |||
| 265 | cache = kmalloc(sizeof(struct mb_cache) + | ||
| 266 | indexes_count * sizeof(struct list_head), GFP_KERNEL); | ||
| 267 | if (!cache) | 223 | if (!cache) |
| 268 | goto fail; | 224 | return NULL; |
| 269 | cache->c_name = name; | 225 | cache->c_name = name; |
| 270 | cache->c_op.free = NULL; | ||
| 271 | if (cache_op) | ||
| 272 | cache->c_op.free = cache_op->free; | ||
| 273 | atomic_set(&cache->c_entry_count, 0); | 226 | atomic_set(&cache->c_entry_count, 0); |
| 274 | cache->c_bucket_bits = bucket_bits; | 227 | cache->c_bucket_bits = bucket_bits; |
| 275 | #ifdef MB_CACHE_INDEXES_COUNT | ||
| 276 | mb_assert(indexes_count == MB_CACHE_INDEXES_COUNT); | ||
| 277 | #else | ||
| 278 | cache->c_indexes_count = indexes_count; | ||
| 279 | #endif | ||
| 280 | cache->c_block_hash = kmalloc(bucket_count * sizeof(struct list_head), | 228 | cache->c_block_hash = kmalloc(bucket_count * sizeof(struct list_head), |
| 281 | GFP_KERNEL); | 229 | GFP_KERNEL); |
| 282 | if (!cache->c_block_hash) | 230 | if (!cache->c_block_hash) |
| 283 | goto fail; | 231 | goto fail; |
| 284 | for (n=0; n<bucket_count; n++) | 232 | for (n=0; n<bucket_count; n++) |
| 285 | INIT_LIST_HEAD(&cache->c_block_hash[n]); | 233 | INIT_LIST_HEAD(&cache->c_block_hash[n]); |
| 286 | for (m=0; m<indexes_count; m++) { | 234 | cache->c_index_hash = kmalloc(bucket_count * sizeof(struct list_head), |
| 287 | cache->c_indexes_hash[m] = kmalloc(bucket_count * | 235 | GFP_KERNEL); |
| 288 | sizeof(struct list_head), | 236 | if (!cache->c_index_hash) |
| 289 | GFP_KERNEL); | 237 | goto fail; |
| 290 | if (!cache->c_indexes_hash[m]) | 238 | for (n=0; n<bucket_count; n++) |
| 291 | goto fail; | 239 | INIT_LIST_HEAD(&cache->c_index_hash[n]); |
| 292 | for (n=0; n<bucket_count; n++) | 240 | cache->c_entry_cache = kmem_cache_create(name, |
| 293 | INIT_LIST_HEAD(&cache->c_indexes_hash[m][n]); | 241 | sizeof(struct mb_cache_entry), 0, |
| 294 | } | ||
| 295 | cache->c_entry_cache = kmem_cache_create(name, entry_size, 0, | ||
| 296 | SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL); | 242 | SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL); |
| 297 | if (!cache->c_entry_cache) | 243 | if (!cache->c_entry_cache) |
| 298 | goto fail; | 244 | goto fail2; |
| 299 | 245 | ||
| 300 | spin_lock(&mb_cache_spinlock); | 246 | spin_lock(&mb_cache_spinlock); |
| 301 | list_add(&cache->c_cache_list, &mb_cache_list); | 247 | list_add(&cache->c_cache_list, &mb_cache_list); |
| 302 | spin_unlock(&mb_cache_spinlock); | 248 | spin_unlock(&mb_cache_spinlock); |
| 303 | return cache; | 249 | return cache; |
| 304 | 250 | ||
| 251 | fail2: | ||
| 252 | kfree(cache->c_index_hash); | ||
| 253 | |||
| 305 | fail: | 254 | fail: |
| 306 | if (cache) { | 255 | kfree(cache->c_block_hash); |
| 307 | while (--m >= 0) | 256 | kfree(cache); |
| 308 | kfree(cache->c_indexes_hash[m]); | ||
| 309 | kfree(cache->c_block_hash); | ||
| 310 | kfree(cache); | ||
| 311 | } | ||
| 312 | return NULL; | 257 | return NULL; |
| 313 | } | 258 | } |
| 314 | 259 | ||
| @@ -357,7 +302,6 @@ mb_cache_destroy(struct mb_cache *cache) | |||
| 357 | { | 302 | { |
| 358 | LIST_HEAD(free_list); | 303 | LIST_HEAD(free_list); |
| 359 | struct list_head *l, *ltmp; | 304 | struct list_head *l, *ltmp; |
| 360 | int n; | ||
| 361 | 305 | ||
| 362 | spin_lock(&mb_cache_spinlock); | 306 | spin_lock(&mb_cache_spinlock); |
| 363 | list_for_each_safe(l, ltmp, &mb_cache_lru_list) { | 307 | list_for_each_safe(l, ltmp, &mb_cache_lru_list) { |
| @@ -384,8 +328,7 @@ mb_cache_destroy(struct mb_cache *cache) | |||
| 384 | 328 | ||
| 385 | kmem_cache_destroy(cache->c_entry_cache); | 329 | kmem_cache_destroy(cache->c_entry_cache); |
| 386 | 330 | ||
| 387 | for (n=0; n < mb_cache_indexes(cache); n++) | 331 | kfree(cache->c_index_hash); |
| 388 | kfree(cache->c_indexes_hash[n]); | ||
| 389 | kfree(cache->c_block_hash); | 332 | kfree(cache->c_block_hash); |
| 390 | kfree(cache); | 333 | kfree(cache); |
| 391 | } | 334 | } |
| @@ -429,17 +372,16 @@ mb_cache_entry_alloc(struct mb_cache *cache, gfp_t gfp_flags) | |||
| 429 | * | 372 | * |
| 430 | * @bdev: device the cache entry belongs to | 373 | * @bdev: device the cache entry belongs to |
| 431 | * @block: block number | 374 | * @block: block number |
| 432 | * @keys: array of additional keys. There must be indexes_count entries | 375 | * @key: lookup key |
| 433 | * in the array (as specified when creating the cache). | ||
| 434 | */ | 376 | */ |
| 435 | int | 377 | int |
| 436 | mb_cache_entry_insert(struct mb_cache_entry *ce, struct block_device *bdev, | 378 | mb_cache_entry_insert(struct mb_cache_entry *ce, struct block_device *bdev, |
| 437 | sector_t block, unsigned int keys[]) | 379 | sector_t block, unsigned int key) |
| 438 | { | 380 | { |
| 439 | struct mb_cache *cache = ce->e_cache; | 381 | struct mb_cache *cache = ce->e_cache; |
| 440 | unsigned int bucket; | 382 | unsigned int bucket; |
| 441 | struct list_head *l; | 383 | struct list_head *l; |
| 442 | int error = -EBUSY, n; | 384 | int error = -EBUSY; |
| 443 | 385 | ||
| 444 | bucket = hash_long((unsigned long)bdev + (block & 0xffffffff), | 386 | bucket = hash_long((unsigned long)bdev + (block & 0xffffffff), |
| 445 | cache->c_bucket_bits); | 387 | cache->c_bucket_bits); |
| @@ -454,12 +396,9 @@ mb_cache_entry_insert(struct mb_cache_entry *ce, struct block_device *bdev, | |||
| 454 | ce->e_bdev = bdev; | 396 | ce->e_bdev = bdev; |
| 455 | ce->e_block = block; | 397 | ce->e_block = block; |
| 456 | list_add(&ce->e_block_list, &cache->c_block_hash[bucket]); | 398 | list_add(&ce->e_block_list, &cache->c_block_hash[bucket]); |
| 457 | for (n=0; n<mb_cache_indexes(cache); n++) { | 399 | ce->e_index.o_key = key; |
| 458 | ce->e_indexes[n].o_key = keys[n]; | 400 | bucket = hash_long(key, cache->c_bucket_bits); |
| 459 | bucket = hash_long(keys[n], cache->c_bucket_bits); | 401 | list_add(&ce->e_index.o_list, &cache->c_index_hash[bucket]); |
| 460 | list_add(&ce->e_indexes[n].o_list, | ||
| 461 | &cache->c_indexes_hash[n][bucket]); | ||
| 462 | } | ||
| 463 | error = 0; | 402 | error = 0; |
| 464 | out: | 403 | out: |
| 465 | spin_unlock(&mb_cache_spinlock); | 404 | spin_unlock(&mb_cache_spinlock); |
| @@ -555,13 +494,12 @@ cleanup: | |||
| 555 | 494 | ||
| 556 | static struct mb_cache_entry * | 495 | static struct mb_cache_entry * |
| 557 | __mb_cache_entry_find(struct list_head *l, struct list_head *head, | 496 | __mb_cache_entry_find(struct list_head *l, struct list_head *head, |
| 558 | int index, struct block_device *bdev, unsigned int key) | 497 | struct block_device *bdev, unsigned int key) |
| 559 | { | 498 | { |
| 560 | while (l != head) { | 499 | while (l != head) { |
| 561 | struct mb_cache_entry *ce = | 500 | struct mb_cache_entry *ce = |
| 562 | list_entry(l, struct mb_cache_entry, | 501 | list_entry(l, struct mb_cache_entry, e_index.o_list); |
| 563 | e_indexes[index].o_list); | 502 | if (ce->e_bdev == bdev && ce->e_index.o_key == key) { |
| 564 | if (ce->e_bdev == bdev && ce->e_indexes[index].o_key == key) { | ||
| 565 | DEFINE_WAIT(wait); | 503 | DEFINE_WAIT(wait); |
| 566 | 504 | ||
| 567 | if (!list_empty(&ce->e_lru_list)) | 505 | if (!list_empty(&ce->e_lru_list)) |
| @@ -603,23 +541,20 @@ __mb_cache_entry_find(struct list_head *l, struct list_head *head, | |||
| 603 | * returned cache entry is locked for shared access ("multiple readers"). | 541 | * returned cache entry is locked for shared access ("multiple readers"). |
| 604 | * | 542 | * |
| 605 | * @cache: the cache to search | 543 | * @cache: the cache to search |
| 606 | * @index: the number of the additonal index to search (0<=index<indexes_count) | ||
| 607 | * @bdev: the device the cache entry should belong to | 544 | * @bdev: the device the cache entry should belong to |
| 608 | * @key: the key in the index | 545 | * @key: the key in the index |
| 609 | */ | 546 | */ |
| 610 | struct mb_cache_entry * | 547 | struct mb_cache_entry * |
| 611 | mb_cache_entry_find_first(struct mb_cache *cache, int index, | 548 | mb_cache_entry_find_first(struct mb_cache *cache, struct block_device *bdev, |
| 612 | struct block_device *bdev, unsigned int key) | 549 | unsigned int key) |
| 613 | { | 550 | { |
| 614 | unsigned int bucket = hash_long(key, cache->c_bucket_bits); | 551 | unsigned int bucket = hash_long(key, cache->c_bucket_bits); |
| 615 | struct list_head *l; | 552 | struct list_head *l; |
| 616 | struct mb_cache_entry *ce; | 553 | struct mb_cache_entry *ce; |
| 617 | 554 | ||
| 618 | mb_assert(index < mb_cache_indexes(cache)); | ||
| 619 | spin_lock(&mb_cache_spinlock); | 555 | spin_lock(&mb_cache_spinlock); |
| 620 | l = cache->c_indexes_hash[index][bucket].next; | 556 | l = cache->c_index_hash[bucket].next; |
| 621 | ce = __mb_cache_entry_find(l, &cache->c_indexes_hash[index][bucket], | 557 | ce = __mb_cache_entry_find(l, &cache->c_index_hash[bucket], bdev, key); |
| 622 | index, bdev, key); | ||
| 623 | spin_unlock(&mb_cache_spinlock); | 558 | spin_unlock(&mb_cache_spinlock); |
| 624 | return ce; | 559 | return ce; |
| 625 | } | 560 | } |
| @@ -640,12 +575,11 @@ mb_cache_entry_find_first(struct mb_cache *cache, int index, | |||
| 640 | * } | 575 | * } |
| 641 | * | 576 | * |
| 642 | * @prev: The previous match | 577 | * @prev: The previous match |
| 643 | * @index: the number of the additonal index to search (0<=index<indexes_count) | ||
| 644 | * @bdev: the device the cache entry should belong to | 578 | * @bdev: the device the cache entry should belong to |
| 645 | * @key: the key in the index | 579 | * @key: the key in the index |
| 646 | */ | 580 | */ |
| 647 | struct mb_cache_entry * | 581 | struct mb_cache_entry * |
| 648 | mb_cache_entry_find_next(struct mb_cache_entry *prev, int index, | 582 | mb_cache_entry_find_next(struct mb_cache_entry *prev, |
| 649 | struct block_device *bdev, unsigned int key) | 583 | struct block_device *bdev, unsigned int key) |
| 650 | { | 584 | { |
| 651 | struct mb_cache *cache = prev->e_cache; | 585 | struct mb_cache *cache = prev->e_cache; |
| @@ -653,11 +587,9 @@ mb_cache_entry_find_next(struct mb_cache_entry *prev, int index, | |||
| 653 | struct list_head *l; | 587 | struct list_head *l; |
| 654 | struct mb_cache_entry *ce; | 588 | struct mb_cache_entry *ce; |
| 655 | 589 | ||
| 656 | mb_assert(index < mb_cache_indexes(cache)); | ||
| 657 | spin_lock(&mb_cache_spinlock); | 590 | spin_lock(&mb_cache_spinlock); |
| 658 | l = prev->e_indexes[index].o_list.next; | 591 | l = prev->e_index.o_list.next; |
| 659 | ce = __mb_cache_entry_find(l, &cache->c_indexes_hash[index][bucket], | 592 | ce = __mb_cache_entry_find(l, &cache->c_index_hash[bucket], bdev, key); |
| 660 | index, bdev, key); | ||
| 661 | __mb_cache_entry_release_unlock(prev); | 593 | __mb_cache_entry_release_unlock(prev); |
| 662 | return ce; | 594 | return ce; |
| 663 | } | 595 | } |
diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c index 482779fe4e7c..3f32bcb0d9bd 100644 --- a/fs/minix/bitmap.c +++ b/fs/minix/bitmap.c | |||
| @@ -200,13 +200,13 @@ void minix_free_inode(struct inode * inode) | |||
| 200 | ino = inode->i_ino; | 200 | ino = inode->i_ino; |
| 201 | if (ino < 1 || ino > sbi->s_ninodes) { | 201 | if (ino < 1 || ino > sbi->s_ninodes) { |
| 202 | printk("minix_free_inode: inode 0 or nonexistent inode\n"); | 202 | printk("minix_free_inode: inode 0 or nonexistent inode\n"); |
| 203 | goto out; | 203 | return; |
| 204 | } | 204 | } |
| 205 | bit = ino & ((1<<k) - 1); | 205 | bit = ino & ((1<<k) - 1); |
| 206 | ino >>= k; | 206 | ino >>= k; |
| 207 | if (ino >= sbi->s_imap_blocks) { | 207 | if (ino >= sbi->s_imap_blocks) { |
| 208 | printk("minix_free_inode: nonexistent imap in superblock\n"); | 208 | printk("minix_free_inode: nonexistent imap in superblock\n"); |
| 209 | goto out; | 209 | return; |
| 210 | } | 210 | } |
| 211 | 211 | ||
| 212 | minix_clear_inode(inode); /* clear on-disk copy */ | 212 | minix_clear_inode(inode); /* clear on-disk copy */ |
| @@ -217,8 +217,6 @@ void minix_free_inode(struct inode * inode) | |||
| 217 | printk("minix_free_inode: bit %lu already cleared\n", bit); | 217 | printk("minix_free_inode: bit %lu already cleared\n", bit); |
| 218 | spin_unlock(&bitmap_lock); | 218 | spin_unlock(&bitmap_lock); |
| 219 | mark_buffer_dirty(bh); | 219 | mark_buffer_dirty(bh); |
| 220 | out: | ||
| 221 | clear_inode(inode); /* clear in-memory copy */ | ||
| 222 | } | 220 | } |
| 223 | 221 | ||
| 224 | struct inode *minix_new_inode(const struct inode *dir, int mode, int *error) | 222 | struct inode *minix_new_inode(const struct inode *dir, int mode, int *error) |
diff --git a/fs/minix/dir.c b/fs/minix/dir.c index 1dbf921ca44b..085a9262c692 100644 --- a/fs/minix/dir.c +++ b/fs/minix/dir.c | |||
| @@ -271,8 +271,7 @@ int minix_add_link(struct dentry *dentry, struct inode *inode) | |||
| 271 | 271 | ||
| 272 | got_it: | 272 | got_it: |
| 273 | pos = page_offset(page) + p - (char *)page_address(page); | 273 | pos = page_offset(page) + p - (char *)page_address(page); |
| 274 | err = __minix_write_begin(NULL, page->mapping, pos, sbi->s_dirsize, | 274 | err = minix_prepare_chunk(page, pos, sbi->s_dirsize); |
| 275 | AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); | ||
| 276 | if (err) | 275 | if (err) |
| 277 | goto out_unlock; | 276 | goto out_unlock; |
| 278 | memcpy (namx, name, namelen); | 277 | memcpy (namx, name, namelen); |
| @@ -297,8 +296,7 @@ out_unlock: | |||
| 297 | 296 | ||
| 298 | int minix_delete_entry(struct minix_dir_entry *de, struct page *page) | 297 | int minix_delete_entry(struct minix_dir_entry *de, struct page *page) |
| 299 | { | 298 | { |
| 300 | struct address_space *mapping = page->mapping; | 299 | struct inode *inode = page->mapping->host; |
| 301 | struct inode *inode = (struct inode*)mapping->host; | ||
| 302 | char *kaddr = page_address(page); | 300 | char *kaddr = page_address(page); |
| 303 | loff_t pos = page_offset(page) + (char*)de - kaddr; | 301 | loff_t pos = page_offset(page) + (char*)de - kaddr; |
| 304 | struct minix_sb_info *sbi = minix_sb(inode->i_sb); | 302 | struct minix_sb_info *sbi = minix_sb(inode->i_sb); |
| @@ -306,8 +304,7 @@ int minix_delete_entry(struct minix_dir_entry *de, struct page *page) | |||
| 306 | int err; | 304 | int err; |
| 307 | 305 | ||
| 308 | lock_page(page); | 306 | lock_page(page); |
| 309 | err = __minix_write_begin(NULL, mapping, pos, len, | 307 | err = minix_prepare_chunk(page, pos, len); |
| 310 | AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); | ||
| 311 | if (err == 0) { | 308 | if (err == 0) { |
| 312 | if (sbi->s_version == MINIX_V3) | 309 | if (sbi->s_version == MINIX_V3) |
| 313 | ((minix3_dirent *) de)->inode = 0; | 310 | ((minix3_dirent *) de)->inode = 0; |
| @@ -325,16 +322,14 @@ int minix_delete_entry(struct minix_dir_entry *de, struct page *page) | |||
| 325 | 322 | ||
| 326 | int minix_make_empty(struct inode *inode, struct inode *dir) | 323 | int minix_make_empty(struct inode *inode, struct inode *dir) |
| 327 | { | 324 | { |
| 328 | struct address_space *mapping = inode->i_mapping; | 325 | struct page *page = grab_cache_page(inode->i_mapping, 0); |
| 329 | struct page *page = grab_cache_page(mapping, 0); | ||
| 330 | struct minix_sb_info *sbi = minix_sb(inode->i_sb); | 326 | struct minix_sb_info *sbi = minix_sb(inode->i_sb); |
| 331 | char *kaddr; | 327 | char *kaddr; |
| 332 | int err; | 328 | int err; |
| 333 | 329 | ||
| 334 | if (!page) | 330 | if (!page) |
| 335 | return -ENOMEM; | 331 | return -ENOMEM; |
| 336 | err = __minix_write_begin(NULL, mapping, 0, 2 * sbi->s_dirsize, | 332 | err = minix_prepare_chunk(page, 0, 2 * sbi->s_dirsize); |
| 337 | AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); | ||
| 338 | if (err) { | 333 | if (err) { |
| 339 | unlock_page(page); | 334 | unlock_page(page); |
| 340 | goto fail; | 335 | goto fail; |
| @@ -425,8 +420,7 @@ not_empty: | |||
| 425 | void minix_set_link(struct minix_dir_entry *de, struct page *page, | 420 | void minix_set_link(struct minix_dir_entry *de, struct page *page, |
| 426 | struct inode *inode) | 421 | struct inode *inode) |
| 427 | { | 422 | { |
| 428 | struct address_space *mapping = page->mapping; | 423 | struct inode *dir = page->mapping->host; |
| 429 | struct inode *dir = mapping->host; | ||
| 430 | struct minix_sb_info *sbi = minix_sb(dir->i_sb); | 424 | struct minix_sb_info *sbi = minix_sb(dir->i_sb); |
| 431 | loff_t pos = page_offset(page) + | 425 | loff_t pos = page_offset(page) + |
| 432 | (char *)de-(char*)page_address(page); | 426 | (char *)de-(char*)page_address(page); |
| @@ -434,8 +428,7 @@ void minix_set_link(struct minix_dir_entry *de, struct page *page, | |||
| 434 | 428 | ||
| 435 | lock_page(page); | 429 | lock_page(page); |
| 436 | 430 | ||
| 437 | err = __minix_write_begin(NULL, mapping, pos, sbi->s_dirsize, | 431 | err = minix_prepare_chunk(page, pos, sbi->s_dirsize); |
| 438 | AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); | ||
| 439 | if (err == 0) { | 432 | if (err == 0) { |
| 440 | if (sbi->s_version == MINIX_V3) | 433 | if (sbi->s_version == MINIX_V3) |
| 441 | ((minix3_dirent *) de)->inode = inode->i_ino; | 434 | ((minix3_dirent *) de)->inode = inode->i_ino; |
diff --git a/fs/minix/file.c b/fs/minix/file.c index d5320ff23faf..4493ce695ab8 100644 --- a/fs/minix/file.c +++ b/fs/minix/file.c | |||
| @@ -23,7 +23,29 @@ const struct file_operations minix_file_operations = { | |||
| 23 | .splice_read = generic_file_splice_read, | 23 | .splice_read = generic_file_splice_read, |
| 24 | }; | 24 | }; |
| 25 | 25 | ||
| 26 | static int minix_setattr(struct dentry *dentry, struct iattr *attr) | ||
| 27 | { | ||
| 28 | struct inode *inode = dentry->d_inode; | ||
| 29 | int error; | ||
| 30 | |||
| 31 | error = inode_change_ok(inode, attr); | ||
| 32 | if (error) | ||
| 33 | return error; | ||
| 34 | |||
| 35 | if ((attr->ia_valid & ATTR_SIZE) && | ||
| 36 | attr->ia_size != i_size_read(inode)) { | ||
| 37 | error = vmtruncate(inode, attr->ia_size); | ||
| 38 | if (error) | ||
| 39 | return error; | ||
| 40 | } | ||
| 41 | |||
| 42 | setattr_copy(inode, attr); | ||
| 43 | mark_inode_dirty(inode); | ||
| 44 | return 0; | ||
| 45 | } | ||
| 46 | |||
| 26 | const struct inode_operations minix_file_inode_operations = { | 47 | const struct inode_operations minix_file_inode_operations = { |
| 27 | .truncate = minix_truncate, | 48 | .truncate = minix_truncate, |
| 49 | .setattr = minix_setattr, | ||
| 28 | .getattr = minix_getattr, | 50 | .getattr = minix_getattr, |
| 29 | }; | 51 | }; |
diff --git a/fs/minix/inode.c b/fs/minix/inode.c index 756f8c93780c..e39d6bf2e8fb 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c | |||
| @@ -24,12 +24,17 @@ static int minix_write_inode(struct inode *inode, | |||
| 24 | static int minix_statfs(struct dentry *dentry, struct kstatfs *buf); | 24 | static int minix_statfs(struct dentry *dentry, struct kstatfs *buf); |
| 25 | static int minix_remount (struct super_block * sb, int * flags, char * data); | 25 | static int minix_remount (struct super_block * sb, int * flags, char * data); |
| 26 | 26 | ||
| 27 | static void minix_delete_inode(struct inode *inode) | 27 | static void minix_evict_inode(struct inode *inode) |
| 28 | { | 28 | { |
| 29 | truncate_inode_pages(&inode->i_data, 0); | 29 | truncate_inode_pages(&inode->i_data, 0); |
| 30 | inode->i_size = 0; | 30 | if (!inode->i_nlink) { |
| 31 | minix_truncate(inode); | 31 | inode->i_size = 0; |
| 32 | minix_free_inode(inode); | 32 | minix_truncate(inode); |
| 33 | } | ||
| 34 | invalidate_inode_buffers(inode); | ||
| 35 | end_writeback(inode); | ||
| 36 | if (!inode->i_nlink) | ||
| 37 | minix_free_inode(inode); | ||
| 33 | } | 38 | } |
| 34 | 39 | ||
| 35 | static void minix_put_super(struct super_block *sb) | 40 | static void minix_put_super(struct super_block *sb) |
| @@ -96,7 +101,7 @@ static const struct super_operations minix_sops = { | |||
| 96 | .alloc_inode = minix_alloc_inode, | 101 | .alloc_inode = minix_alloc_inode, |
| 97 | .destroy_inode = minix_destroy_inode, | 102 | .destroy_inode = minix_destroy_inode, |
| 98 | .write_inode = minix_write_inode, | 103 | .write_inode = minix_write_inode, |
| 99 | .delete_inode = minix_delete_inode, | 104 | .evict_inode = minix_evict_inode, |
| 100 | .put_super = minix_put_super, | 105 | .put_super = minix_put_super, |
| 101 | .statfs = minix_statfs, | 106 | .statfs = minix_statfs, |
| 102 | .remount_fs = minix_remount, | 107 | .remount_fs = minix_remount, |
| @@ -357,20 +362,26 @@ static int minix_readpage(struct file *file, struct page *page) | |||
| 357 | return block_read_full_page(page,minix_get_block); | 362 | return block_read_full_page(page,minix_get_block); |
| 358 | } | 363 | } |
| 359 | 364 | ||
| 360 | int __minix_write_begin(struct file *file, struct address_space *mapping, | 365 | int minix_prepare_chunk(struct page *page, loff_t pos, unsigned len) |
| 361 | loff_t pos, unsigned len, unsigned flags, | ||
| 362 | struct page **pagep, void **fsdata) | ||
| 363 | { | 366 | { |
| 364 | return block_write_begin(file, mapping, pos, len, flags, pagep, fsdata, | 367 | return __block_write_begin(page, pos, len, minix_get_block); |
| 365 | minix_get_block); | ||
| 366 | } | 368 | } |
| 367 | 369 | ||
| 368 | static int minix_write_begin(struct file *file, struct address_space *mapping, | 370 | static int minix_write_begin(struct file *file, struct address_space *mapping, |
| 369 | loff_t pos, unsigned len, unsigned flags, | 371 | loff_t pos, unsigned len, unsigned flags, |
| 370 | struct page **pagep, void **fsdata) | 372 | struct page **pagep, void **fsdata) |
| 371 | { | 373 | { |
| 372 | *pagep = NULL; | 374 | int ret; |
| 373 | return __minix_write_begin(file, mapping, pos, len, flags, pagep, fsdata); | 375 | |
| 376 | ret = block_write_begin(mapping, pos, len, flags, pagep, | ||
| 377 | minix_get_block); | ||
| 378 | if (unlikely(ret)) { | ||
| 379 | loff_t isize = mapping->host->i_size; | ||
| 380 | if (pos + len > isize) | ||
| 381 | vmtruncate(mapping->host, isize); | ||
| 382 | } | ||
| 383 | |||
| 384 | return ret; | ||
| 374 | } | 385 | } |
| 375 | 386 | ||
| 376 | static sector_t minix_bmap(struct address_space *mapping, sector_t block) | 387 | static sector_t minix_bmap(struct address_space *mapping, sector_t block) |
diff --git a/fs/minix/minix.h b/fs/minix/minix.h index 111f34ee9e3b..407b1c84911e 100644 --- a/fs/minix/minix.h +++ b/fs/minix/minix.h | |||
| @@ -53,9 +53,7 @@ extern int minix_new_block(struct inode * inode); | |||
| 53 | extern void minix_free_block(struct inode *inode, unsigned long block); | 53 | extern void minix_free_block(struct inode *inode, unsigned long block); |
| 54 | extern unsigned long minix_count_free_blocks(struct minix_sb_info *sbi); | 54 | extern unsigned long minix_count_free_blocks(struct minix_sb_info *sbi); |
| 55 | extern int minix_getattr(struct vfsmount *, struct dentry *, struct kstat *); | 55 | extern int minix_getattr(struct vfsmount *, struct dentry *, struct kstat *); |
| 56 | extern int __minix_write_begin(struct file *file, struct address_space *mapping, | 56 | extern int minix_prepare_chunk(struct page *page, loff_t pos, unsigned len); |
| 57 | loff_t pos, unsigned len, unsigned flags, | ||
| 58 | struct page **pagep, void **fsdata); | ||
| 59 | 57 | ||
| 60 | extern void V1_minix_truncate(struct inode *); | 58 | extern void V1_minix_truncate(struct inode *); |
| 61 | extern void V2_minix_truncate(struct inode *); | 59 | extern void V2_minix_truncate(struct inode *); |
diff --git a/fs/namei.c b/fs/namei.c index 42d2d28fb827..17ea76bf2fbe 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -483,13 +483,8 @@ ok: | |||
| 483 | 483 | ||
| 484 | static __always_inline void set_root(struct nameidata *nd) | 484 | static __always_inline void set_root(struct nameidata *nd) |
| 485 | { | 485 | { |
| 486 | if (!nd->root.mnt) { | 486 | if (!nd->root.mnt) |
| 487 | struct fs_struct *fs = current->fs; | 487 | get_fs_root(current->fs, &nd->root); |
| 488 | read_lock(&fs->lock); | ||
| 489 | nd->root = fs->root; | ||
| 490 | path_get(&nd->root); | ||
| 491 | read_unlock(&fs->lock); | ||
| 492 | } | ||
| 493 | } | 488 | } |
| 494 | 489 | ||
| 495 | static int link_path_walk(const char *, struct nameidata *); | 490 | static int link_path_walk(const char *, struct nameidata *); |
| @@ -1015,11 +1010,7 @@ static int path_init(int dfd, const char *name, unsigned int flags, struct namei | |||
| 1015 | nd->path = nd->root; | 1010 | nd->path = nd->root; |
| 1016 | path_get(&nd->root); | 1011 | path_get(&nd->root); |
| 1017 | } else if (dfd == AT_FDCWD) { | 1012 | } else if (dfd == AT_FDCWD) { |
| 1018 | struct fs_struct *fs = current->fs; | 1013 | get_fs_pwd(current->fs, &nd->path); |
| 1019 | read_lock(&fs->lock); | ||
| 1020 | nd->path = fs->pwd; | ||
| 1021 | path_get(&fs->pwd); | ||
| 1022 | read_unlock(&fs->lock); | ||
| 1023 | } else { | 1014 | } else { |
| 1024 | struct dentry *dentry; | 1015 | struct dentry *dentry; |
| 1025 | 1016 | ||
| @@ -2633,7 +2624,7 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | |||
| 2633 | { | 2624 | { |
| 2634 | int error; | 2625 | int error; |
| 2635 | int is_dir = S_ISDIR(old_dentry->d_inode->i_mode); | 2626 | int is_dir = S_ISDIR(old_dentry->d_inode->i_mode); |
| 2636 | const char *old_name; | 2627 | const unsigned char *old_name; |
| 2637 | 2628 | ||
| 2638 | if (old_dentry->d_inode == new_dentry->d_inode) | 2629 | if (old_dentry->d_inode == new_dentry->d_inode) |
| 2639 | return 0; | 2630 | return 0; |
diff --git a/fs/namespace.c b/fs/namespace.c index 88058de59c7c..2e10cb19c5b0 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include <linux/log2.h> | 29 | #include <linux/log2.h> |
| 30 | #include <linux/idr.h> | 30 | #include <linux/idr.h> |
| 31 | #include <linux/fs_struct.h> | 31 | #include <linux/fs_struct.h> |
| 32 | #include <linux/fsnotify.h> | ||
| 32 | #include <asm/uaccess.h> | 33 | #include <asm/uaccess.h> |
| 33 | #include <asm/unistd.h> | 34 | #include <asm/unistd.h> |
| 34 | #include "pnode.h" | 35 | #include "pnode.h" |
| @@ -150,6 +151,9 @@ struct vfsmount *alloc_vfsmnt(const char *name) | |||
| 150 | INIT_LIST_HEAD(&mnt->mnt_share); | 151 | INIT_LIST_HEAD(&mnt->mnt_share); |
| 151 | INIT_LIST_HEAD(&mnt->mnt_slave_list); | 152 | INIT_LIST_HEAD(&mnt->mnt_slave_list); |
| 152 | INIT_LIST_HEAD(&mnt->mnt_slave); | 153 | INIT_LIST_HEAD(&mnt->mnt_slave); |
| 154 | #ifdef CONFIG_FSNOTIFY | ||
| 155 | INIT_HLIST_HEAD(&mnt->mnt_fsnotify_marks); | ||
| 156 | #endif | ||
| 153 | #ifdef CONFIG_SMP | 157 | #ifdef CONFIG_SMP |
| 154 | mnt->mnt_writers = alloc_percpu(int); | 158 | mnt->mnt_writers = alloc_percpu(int); |
| 155 | if (!mnt->mnt_writers) | 159 | if (!mnt->mnt_writers) |
| @@ -610,6 +614,7 @@ static inline void __mntput(struct vfsmount *mnt) | |||
| 610 | * provides barriers, so count_mnt_writers() below is safe. AV | 614 | * provides barriers, so count_mnt_writers() below is safe. AV |
| 611 | */ | 615 | */ |
| 612 | WARN_ON(count_mnt_writers(mnt)); | 616 | WARN_ON(count_mnt_writers(mnt)); |
| 617 | fsnotify_vfsmount_delete(mnt); | ||
| 613 | dput(mnt->mnt_root); | 618 | dput(mnt->mnt_root); |
| 614 | free_vfsmnt(mnt); | 619 | free_vfsmnt(mnt); |
| 615 | deactivate_super(sb); | 620 | deactivate_super(sb); |
| @@ -783,7 +788,6 @@ static void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt) | |||
| 783 | { MNT_NOATIME, ",noatime" }, | 788 | { MNT_NOATIME, ",noatime" }, |
| 784 | { MNT_NODIRATIME, ",nodiratime" }, | 789 | { MNT_NODIRATIME, ",nodiratime" }, |
| 785 | { MNT_RELATIME, ",relatime" }, | 790 | { MNT_RELATIME, ",relatime" }, |
| 786 | { MNT_STRICTATIME, ",strictatime" }, | ||
| 787 | { 0, NULL } | 791 | { 0, NULL } |
| 788 | }; | 792 | }; |
| 789 | const struct proc_fs_info *fs_infop; | 793 | const struct proc_fs_info *fs_infop; |
| @@ -1984,7 +1988,7 @@ long do_mount(char *dev_name, char *dir_name, char *type_page, | |||
| 1984 | if (flags & MS_RDONLY) | 1988 | if (flags & MS_RDONLY) |
| 1985 | mnt_flags |= MNT_READONLY; | 1989 | mnt_flags |= MNT_READONLY; |
| 1986 | 1990 | ||
| 1987 | flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | | 1991 | flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | MS_BORN | |
| 1988 | MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT | | 1992 | MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT | |
| 1989 | MS_STRICTATIME); | 1993 | MS_STRICTATIME); |
| 1990 | 1994 | ||
| @@ -2208,10 +2212,7 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root, | |||
| 2208 | goto out1; | 2212 | goto out1; |
| 2209 | } | 2213 | } |
| 2210 | 2214 | ||
| 2211 | read_lock(¤t->fs->lock); | 2215 | get_fs_root(current->fs, &root); |
| 2212 | root = current->fs->root; | ||
| 2213 | path_get(¤t->fs->root); | ||
| 2214 | read_unlock(¤t->fs->lock); | ||
| 2215 | down_write(&namespace_sem); | 2216 | down_write(&namespace_sem); |
| 2216 | mutex_lock(&old.dentry->d_inode->i_mutex); | 2217 | mutex_lock(&old.dentry->d_inode->i_mutex); |
| 2217 | error = -EINVAL; | 2218 | error = -EINVAL; |
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 1e634deff941..b4de38cf49f5 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c | |||
| @@ -43,7 +43,7 @@ | |||
| 43 | #define NCP_DEFAULT_TIME_OUT 10 | 43 | #define NCP_DEFAULT_TIME_OUT 10 |
| 44 | #define NCP_DEFAULT_RETRY_COUNT 20 | 44 | #define NCP_DEFAULT_RETRY_COUNT 20 |
| 45 | 45 | ||
| 46 | static void ncp_delete_inode(struct inode *); | 46 | static void ncp_evict_inode(struct inode *); |
| 47 | static void ncp_put_super(struct super_block *); | 47 | static void ncp_put_super(struct super_block *); |
| 48 | static int ncp_statfs(struct dentry *, struct kstatfs *); | 48 | static int ncp_statfs(struct dentry *, struct kstatfs *); |
| 49 | static int ncp_show_options(struct seq_file *, struct vfsmount *); | 49 | static int ncp_show_options(struct seq_file *, struct vfsmount *); |
| @@ -100,7 +100,7 @@ static const struct super_operations ncp_sops = | |||
| 100 | .alloc_inode = ncp_alloc_inode, | 100 | .alloc_inode = ncp_alloc_inode, |
| 101 | .destroy_inode = ncp_destroy_inode, | 101 | .destroy_inode = ncp_destroy_inode, |
| 102 | .drop_inode = generic_delete_inode, | 102 | .drop_inode = generic_delete_inode, |
| 103 | .delete_inode = ncp_delete_inode, | 103 | .evict_inode = ncp_evict_inode, |
| 104 | .put_super = ncp_put_super, | 104 | .put_super = ncp_put_super, |
| 105 | .statfs = ncp_statfs, | 105 | .statfs = ncp_statfs, |
| 106 | .remount_fs = ncp_remount, | 106 | .remount_fs = ncp_remount, |
| @@ -282,19 +282,19 @@ ncp_iget(struct super_block *sb, struct ncp_entry_info *info) | |||
| 282 | } | 282 | } |
| 283 | 283 | ||
| 284 | static void | 284 | static void |
| 285 | ncp_delete_inode(struct inode *inode) | 285 | ncp_evict_inode(struct inode *inode) |
| 286 | { | 286 | { |
| 287 | truncate_inode_pages(&inode->i_data, 0); | 287 | truncate_inode_pages(&inode->i_data, 0); |
| 288 | end_writeback(inode); | ||
| 288 | 289 | ||
| 289 | if (S_ISDIR(inode->i_mode)) { | 290 | if (S_ISDIR(inode->i_mode)) { |
| 290 | DDPRINTK("ncp_delete_inode: put directory %ld\n", inode->i_ino); | 291 | DDPRINTK("ncp_evict_inode: put directory %ld\n", inode->i_ino); |
| 291 | } | 292 | } |
| 292 | 293 | ||
| 293 | if (ncp_make_closed(inode) != 0) { | 294 | if (ncp_make_closed(inode) != 0) { |
| 294 | /* We can't do anything but complain. */ | 295 | /* We can't do anything but complain. */ |
| 295 | printk(KERN_ERR "ncp_delete_inode: could not close\n"); | 296 | printk(KERN_ERR "ncp_evict_inode: could not close\n"); |
| 296 | } | 297 | } |
| 297 | clear_inode(inode); | ||
| 298 | } | 298 | } |
| 299 | 299 | ||
| 300 | static void ncp_stop_tasks(struct ncp_server *server) { | 300 | static void ncp_stop_tasks(struct ncp_server *server) { |
| @@ -924,9 +924,8 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr) | |||
| 924 | tmpattr.ia_valid = ATTR_MODE; | 924 | tmpattr.ia_valid = ATTR_MODE; |
| 925 | tmpattr.ia_mode = attr->ia_mode; | 925 | tmpattr.ia_mode = attr->ia_mode; |
| 926 | 926 | ||
| 927 | result = inode_setattr(inode, &tmpattr); | 927 | setattr_copy(inode, &tmpattr); |
| 928 | if (result) | 928 | mark_inode_dirty(inode); |
| 929 | goto out; | ||
| 930 | } | 929 | } |
| 931 | } | 930 | } |
| 932 | #endif | 931 | #endif |
| @@ -954,15 +953,12 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr) | |||
| 954 | result = ncp_make_closed(inode); | 953 | result = ncp_make_closed(inode); |
| 955 | if (result) | 954 | if (result) |
| 956 | goto out; | 955 | goto out; |
| 957 | { | 956 | |
| 958 | struct iattr tmpattr; | 957 | if (attr->ia_size != i_size_read(inode)) { |
| 959 | 958 | result = vmtruncate(inode, attr->ia_size); | |
| 960 | tmpattr.ia_valid = ATTR_SIZE; | ||
| 961 | tmpattr.ia_size = attr->ia_size; | ||
| 962 | |||
| 963 | result = inode_setattr(inode, &tmpattr); | ||
| 964 | if (result) | 959 | if (result) |
| 965 | goto out; | 960 | goto out; |
| 961 | mark_inode_dirty(inode); | ||
| 966 | } | 962 | } |
| 967 | } | 963 | } |
| 968 | if ((attr->ia_valid & ATTR_CTIME) != 0) { | 964 | if ((attr->ia_valid & ATTR_CTIME) != 0) { |
| @@ -1002,8 +998,12 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr) | |||
| 1002 | NCP_FINFO(inode)->nwattr = info.attributes; | 998 | NCP_FINFO(inode)->nwattr = info.attributes; |
| 1003 | #endif | 999 | #endif |
| 1004 | } | 1000 | } |
| 1005 | if (!result) | 1001 | if (result) |
| 1006 | result = inode_setattr(inode, attr); | 1002 | goto out; |
| 1003 | |||
| 1004 | setattr_copy(inode, attr); | ||
| 1005 | mark_inode_dirty(inode); | ||
| 1006 | |||
| 1007 | out: | 1007 | out: |
| 1008 | unlock_kernel(); | 1008 | unlock_kernel(); |
| 1009 | return result; | 1009 | return result; |
diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c index 023c03d02070..84a8cfc4e38e 100644 --- a/fs/ncpfs/ioctl.c +++ b/fs/ncpfs/ioctl.c | |||
| @@ -20,7 +20,6 @@ | |||
| 20 | #include <linux/smp_lock.h> | 20 | #include <linux/smp_lock.h> |
| 21 | #include <linux/vmalloc.h> | 21 | #include <linux/vmalloc.h> |
| 22 | #include <linux/sched.h> | 22 | #include <linux/sched.h> |
| 23 | #include <linux/smp_lock.h> | ||
| 24 | 23 | ||
| 25 | #include <linux/ncp_fs.h> | 24 | #include <linux/ncp_fs.h> |
| 26 | 25 | ||
diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig index cc1bb33b59b8..26a510a7be09 100644 --- a/fs/nfs/Kconfig +++ b/fs/nfs/Kconfig | |||
| @@ -100,3 +100,20 @@ config NFS_FSCACHE | |||
| 100 | help | 100 | help |
| 101 | Say Y here if you want NFS data to be cached locally on disc through | 101 | Say Y here if you want NFS data to be cached locally on disc through |
| 102 | the general filesystem cache manager | 102 | the general filesystem cache manager |
| 103 | |||
| 104 | config NFS_USE_LEGACY_DNS | ||
| 105 | bool "Use the legacy NFS DNS resolver" | ||
| 106 | depends on NFS_V4 | ||
| 107 | help | ||
| 108 | The kernel now provides a method for translating a host name into an | ||
| 109 | IP address. Select Y here if you would rather use your own DNS | ||
| 110 | resolver script. | ||
| 111 | |||
| 112 | If unsure, say N | ||
| 113 | |||
| 114 | config NFS_USE_KERNEL_DNS | ||
| 115 | bool | ||
| 116 | depends on NFS_V4 && !NFS_USE_LEGACY_DNS | ||
| 117 | select DNS_RESOLVER | ||
| 118 | select KEYS | ||
| 119 | default y | ||
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 36dfdae95123..e17b49e2eabd 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
| @@ -45,7 +45,7 @@ unsigned short nfs_callback_tcpport; | |||
| 45 | unsigned short nfs_callback_tcpport6; | 45 | unsigned short nfs_callback_tcpport6; |
| 46 | #define NFS_CALLBACK_MAXPORTNR (65535U) | 46 | #define NFS_CALLBACK_MAXPORTNR (65535U) |
| 47 | 47 | ||
| 48 | static int param_set_portnr(const char *val, struct kernel_param *kp) | 48 | static int param_set_portnr(const char *val, const struct kernel_param *kp) |
| 49 | { | 49 | { |
| 50 | unsigned long num; | 50 | unsigned long num; |
| 51 | int ret; | 51 | int ret; |
| @@ -58,11 +58,10 @@ static int param_set_portnr(const char *val, struct kernel_param *kp) | |||
| 58 | *((unsigned int *)kp->arg) = num; | 58 | *((unsigned int *)kp->arg) = num; |
| 59 | return 0; | 59 | return 0; |
| 60 | } | 60 | } |
| 61 | 61 | static struct kernel_param_ops param_ops_portnr = { | |
| 62 | static int param_get_portnr(char *buffer, struct kernel_param *kp) | 62 | .set = param_set_portnr, |
| 63 | { | 63 | .get = param_get_uint, |
| 64 | return param_get_uint(buffer, kp); | 64 | }; |
| 65 | } | ||
| 66 | #define param_check_portnr(name, p) __param_check(name, p, unsigned int); | 65 | #define param_check_portnr(name, p) __param_check(name, p, unsigned int); |
| 67 | 66 | ||
| 68 | module_param_named(callback_tcpport, nfs_callback_set_tcpport, portnr, 0644); | 67 | module_param_named(callback_tcpport, nfs_callback_set_tcpport, portnr, 0644); |
diff --git a/fs/nfs/dns_resolve.c b/fs/nfs/dns_resolve.c index 76fd235d0024..dba50a5625db 100644 --- a/fs/nfs/dns_resolve.c +++ b/fs/nfs/dns_resolve.c | |||
| @@ -6,6 +6,29 @@ | |||
| 6 | * Resolves DNS hostnames into valid ip addresses | 6 | * Resolves DNS hostnames into valid ip addresses |
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | #ifdef CONFIG_NFS_USE_KERNEL_DNS | ||
| 10 | |||
| 11 | #include <linux/sunrpc/clnt.h> | ||
| 12 | #include <linux/dns_resolver.h> | ||
| 13 | |||
| 14 | ssize_t nfs_dns_resolve_name(char *name, size_t namelen, | ||
| 15 | struct sockaddr *sa, size_t salen) | ||
| 16 | { | ||
| 17 | ssize_t ret; | ||
| 18 | char *ip_addr = NULL; | ||
| 19 | int ip_len; | ||
| 20 | |||
| 21 | ip_len = dns_query(NULL, name, namelen, NULL, &ip_addr, NULL); | ||
| 22 | if (ip_len > 0) | ||
| 23 | ret = rpc_pton(ip_addr, ip_len, sa, salen); | ||
| 24 | else | ||
| 25 | ret = -ESRCH; | ||
| 26 | kfree(ip_addr); | ||
| 27 | return ret; | ||
| 28 | } | ||
| 29 | |||
| 30 | #else | ||
| 31 | |||
| 9 | #include <linux/hash.h> | 32 | #include <linux/hash.h> |
| 10 | #include <linux/string.h> | 33 | #include <linux/string.h> |
| 11 | #include <linux/kmod.h> | 34 | #include <linux/kmod.h> |
| @@ -346,3 +369,4 @@ void nfs_dns_resolver_destroy(void) | |||
| 346 | nfs_cache_unregister(&nfs_dns_resolve); | 369 | nfs_cache_unregister(&nfs_dns_resolve); |
| 347 | } | 370 | } |
| 348 | 371 | ||
| 372 | #endif | ||
diff --git a/fs/nfs/dns_resolve.h b/fs/nfs/dns_resolve.h index a3f0938babf7..199bb5543a91 100644 --- a/fs/nfs/dns_resolve.h +++ b/fs/nfs/dns_resolve.h | |||
| @@ -6,8 +6,20 @@ | |||
| 6 | 6 | ||
| 7 | #define NFS_DNS_HOSTNAME_MAXLEN (128) | 7 | #define NFS_DNS_HOSTNAME_MAXLEN (128) |
| 8 | 8 | ||
| 9 | |||
| 10 | #ifdef CONFIG_NFS_USE_KERNEL_DNS | ||
| 11 | static inline int nfs_dns_resolver_init(void) | ||
| 12 | { | ||
| 13 | return 0; | ||
| 14 | } | ||
| 15 | |||
| 16 | static inline void nfs_dns_resolver_destroy(void) | ||
| 17 | {} | ||
| 18 | #else | ||
| 9 | extern int nfs_dns_resolver_init(void); | 19 | extern int nfs_dns_resolver_init(void); |
| 10 | extern void nfs_dns_resolver_destroy(void); | 20 | extern void nfs_dns_resolver_destroy(void); |
| 21 | #endif | ||
| 22 | |||
| 11 | extern ssize_t nfs_dns_resolve_name(char *name, size_t namelen, | 23 | extern ssize_t nfs_dns_resolve_name(char *name, size_t namelen, |
| 12 | struct sockaddr *sa, size_t salen); | 24 | struct sockaddr *sa, size_t salen); |
| 13 | 25 | ||
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 581d8f081e68..7d2d6c72aa78 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
| @@ -98,7 +98,7 @@ u64 nfs_compat_user_ino64(u64 fileid) | |||
| 98 | return ino; | 98 | return ino; |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | void nfs_clear_inode(struct inode *inode) | 101 | static void nfs_clear_inode(struct inode *inode) |
| 102 | { | 102 | { |
| 103 | /* | 103 | /* |
| 104 | * The following should never happen... | 104 | * The following should never happen... |
| @@ -110,6 +110,13 @@ void nfs_clear_inode(struct inode *inode) | |||
| 110 | nfs_fscache_release_inode_cookie(inode); | 110 | nfs_fscache_release_inode_cookie(inode); |
| 111 | } | 111 | } |
| 112 | 112 | ||
| 113 | void nfs_evict_inode(struct inode *inode) | ||
| 114 | { | ||
| 115 | truncate_inode_pages(&inode->i_data, 0); | ||
| 116 | end_writeback(inode); | ||
| 117 | nfs_clear_inode(inode); | ||
| 118 | } | ||
| 119 | |||
| 113 | /** | 120 | /** |
| 114 | * nfs_sync_mapping - helper to flush all mmapped dirty data to disk | 121 | * nfs_sync_mapping - helper to flush all mmapped dirty data to disk |
| 115 | */ | 122 | */ |
| @@ -1398,8 +1405,10 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr) | |||
| 1398 | * to open() calls that passed nfs_atomic_lookup, but failed to call | 1405 | * to open() calls that passed nfs_atomic_lookup, but failed to call |
| 1399 | * nfs_open(). | 1406 | * nfs_open(). |
| 1400 | */ | 1407 | */ |
| 1401 | void nfs4_clear_inode(struct inode *inode) | 1408 | void nfs4_evict_inode(struct inode *inode) |
| 1402 | { | 1409 | { |
| 1410 | truncate_inode_pages(&inode->i_data, 0); | ||
| 1411 | end_writeback(inode); | ||
| 1403 | /* If we are holding a delegation, return it! */ | 1412 | /* If we are holding a delegation, return it! */ |
| 1404 | nfs_inode_return_delegation_noreclaim(inode); | 1413 | nfs_inode_return_delegation_noreclaim(inode); |
| 1405 | /* First call standard NFS clear_inode() code */ | 1414 | /* First call standard NFS clear_inode() code */ |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index 4c2150d86714..c961bc92c107 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
| @@ -213,9 +213,9 @@ extern struct workqueue_struct *nfsiod_workqueue; | |||
| 213 | extern struct inode *nfs_alloc_inode(struct super_block *sb); | 213 | extern struct inode *nfs_alloc_inode(struct super_block *sb); |
| 214 | extern void nfs_destroy_inode(struct inode *); | 214 | extern void nfs_destroy_inode(struct inode *); |
| 215 | extern int nfs_write_inode(struct inode *, struct writeback_control *); | 215 | extern int nfs_write_inode(struct inode *, struct writeback_control *); |
| 216 | extern void nfs_clear_inode(struct inode *); | 216 | extern void nfs_evict_inode(struct inode *); |
| 217 | #ifdef CONFIG_NFS_V4 | 217 | #ifdef CONFIG_NFS_V4 |
| 218 | extern void nfs4_clear_inode(struct inode *); | 218 | extern void nfs4_evict_inode(struct inode *); |
| 219 | #endif | 219 | #endif |
| 220 | void nfs_zap_acl_cache(struct inode *inode); | 220 | void nfs_zap_acl_cache(struct inode *inode); |
| 221 | extern int nfs_wait_bit_killable(void *word); | 221 | extern int nfs_wait_bit_killable(void *word); |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index f1ae39f6cb02..ee26316ad1f4 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
| @@ -270,7 +270,7 @@ static const struct super_operations nfs_sops = { | |||
| 270 | .write_inode = nfs_write_inode, | 270 | .write_inode = nfs_write_inode, |
| 271 | .put_super = nfs_put_super, | 271 | .put_super = nfs_put_super, |
| 272 | .statfs = nfs_statfs, | 272 | .statfs = nfs_statfs, |
| 273 | .clear_inode = nfs_clear_inode, | 273 | .evict_inode = nfs_evict_inode, |
| 274 | .umount_begin = nfs_umount_begin, | 274 | .umount_begin = nfs_umount_begin, |
| 275 | .show_options = nfs_show_options, | 275 | .show_options = nfs_show_options, |
| 276 | .show_stats = nfs_show_stats, | 276 | .show_stats = nfs_show_stats, |
| @@ -340,7 +340,7 @@ static const struct super_operations nfs4_sops = { | |||
| 340 | .write_inode = nfs_write_inode, | 340 | .write_inode = nfs_write_inode, |
| 341 | .put_super = nfs_put_super, | 341 | .put_super = nfs_put_super, |
| 342 | .statfs = nfs_statfs, | 342 | .statfs = nfs_statfs, |
| 343 | .clear_inode = nfs4_clear_inode, | 343 | .evict_inode = nfs4_evict_inode, |
| 344 | .umount_begin = nfs_umount_begin, | 344 | .umount_begin = nfs_umount_begin, |
| 345 | .show_options = nfs_show_options, | 345 | .show_options = nfs_show_options, |
| 346 | .show_stats = nfs_show_stats, | 346 | .show_stats = nfs_show_stats, |
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index f8931acb05f3..1a468bbd330f 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
| @@ -1756,6 +1756,10 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
| 1756 | struct nfs4_acl *acl = NULL; | 1756 | struct nfs4_acl *acl = NULL; |
| 1757 | struct nfsd4_compoundres *resp = rqstp->rq_resp; | 1757 | struct nfsd4_compoundres *resp = rqstp->rq_resp; |
| 1758 | u32 minorversion = resp->cstate.minorversion; | 1758 | u32 minorversion = resp->cstate.minorversion; |
| 1759 | struct path path = { | ||
| 1760 | .mnt = exp->ex_path.mnt, | ||
| 1761 | .dentry = dentry, | ||
| 1762 | }; | ||
| 1759 | 1763 | ||
| 1760 | BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1); | 1764 | BUG_ON(bmval1 & NFSD_WRITEONLY_ATTRS_WORD1); |
| 1761 | BUG_ON(bmval0 & ~nfsd_suppattrs0(minorversion)); | 1765 | BUG_ON(bmval0 & ~nfsd_suppattrs0(minorversion)); |
| @@ -1776,7 +1780,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp, | |||
| 1776 | FATTR4_WORD0_MAXNAME)) || | 1780 | FATTR4_WORD0_MAXNAME)) || |
| 1777 | (bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | | 1781 | (bmval1 & (FATTR4_WORD1_SPACE_AVAIL | FATTR4_WORD1_SPACE_FREE | |
| 1778 | FATTR4_WORD1_SPACE_TOTAL))) { | 1782 | FATTR4_WORD1_SPACE_TOTAL))) { |
| 1779 | err = vfs_statfs(dentry, &statfs); | 1783 | err = vfs_statfs(&path, &statfs); |
| 1780 | if (err) | 1784 | if (err) |
| 1781 | goto out_nfserr; | 1785 | goto out_nfserr; |
| 1782 | } | 1786 | } |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 9df85a13af28..96360a83cb91 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
| @@ -934,7 +934,7 @@ nfsd_vfs_read(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
| 934 | nfsdstats.io_read += host_err; | 934 | nfsdstats.io_read += host_err; |
| 935 | *count = host_err; | 935 | *count = host_err; |
| 936 | err = 0; | 936 | err = 0; |
| 937 | fsnotify_access(file->f_path.dentry); | 937 | fsnotify_access(file); |
| 938 | } else | 938 | } else |
| 939 | err = nfserrno(host_err); | 939 | err = nfserrno(host_err); |
| 940 | out: | 940 | out: |
| @@ -1045,7 +1045,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
| 1045 | goto out_nfserr; | 1045 | goto out_nfserr; |
| 1046 | *cnt = host_err; | 1046 | *cnt = host_err; |
| 1047 | nfsdstats.io_write += host_err; | 1047 | nfsdstats.io_write += host_err; |
| 1048 | fsnotify_modify(file->f_path.dentry); | 1048 | fsnotify_modify(file); |
| 1049 | 1049 | ||
| 1050 | /* clear setuid/setgid flag after write */ | 1050 | /* clear setuid/setgid flag after write */ |
| 1051 | if (inode->i_mode & (S_ISUID | S_ISGID)) | 1051 | if (inode->i_mode & (S_ISUID | S_ISGID)) |
| @@ -2033,8 +2033,14 @@ out: | |||
| 2033 | __be32 | 2033 | __be32 |
| 2034 | nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat, int access) | 2034 | nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct kstatfs *stat, int access) |
| 2035 | { | 2035 | { |
| 2036 | __be32 err = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP | access); | 2036 | struct path path = { |
| 2037 | if (!err && vfs_statfs(fhp->fh_dentry,stat)) | 2037 | .mnt = fhp->fh_export->ex_path.mnt, |
| 2038 | .dentry = fhp->fh_dentry, | ||
| 2039 | }; | ||
| 2040 | __be32 err; | ||
| 2041 | |||
| 2042 | err = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP | access); | ||
| 2043 | if (!err && vfs_statfs(&path, stat)) | ||
| 2038 | err = nfserr_io; | 2044 | err = nfserr_io; |
| 2039 | return err; | 2045 | return err; |
| 2040 | } | 2046 | } |
diff --git a/fs/nilfs2/dir.c b/fs/nilfs2/dir.c index b60277b44468..cb003c8ee1f6 100644 --- a/fs/nilfs2/dir.c +++ b/fs/nilfs2/dir.c | |||
| @@ -80,23 +80,10 @@ static unsigned nilfs_last_byte(struct inode *inode, unsigned long page_nr) | |||
| 80 | return last_byte; | 80 | return last_byte; |
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | static int nilfs_prepare_chunk_uninterruptible(struct page *page, | 83 | static int nilfs_prepare_chunk(struct page *page, unsigned from, unsigned to) |
| 84 | struct address_space *mapping, | ||
| 85 | unsigned from, unsigned to) | ||
| 86 | { | 84 | { |
| 87 | loff_t pos = page_offset(page) + from; | 85 | loff_t pos = page_offset(page) + from; |
| 88 | return block_write_begin(NULL, mapping, pos, to - from, | 86 | return __block_write_begin(page, pos, to - from, nilfs_get_block); |
| 89 | AOP_FLAG_UNINTERRUPTIBLE, &page, | ||
| 90 | NULL, nilfs_get_block); | ||
| 91 | } | ||
| 92 | |||
| 93 | static int nilfs_prepare_chunk(struct page *page, | ||
| 94 | struct address_space *mapping, | ||
| 95 | unsigned from, unsigned to) | ||
| 96 | { | ||
| 97 | loff_t pos = page_offset(page) + from; | ||
| 98 | return block_write_begin(NULL, mapping, pos, to - from, 0, &page, | ||
| 99 | NULL, nilfs_get_block); | ||
| 100 | } | 87 | } |
| 101 | 88 | ||
| 102 | static void nilfs_commit_chunk(struct page *page, | 89 | static void nilfs_commit_chunk(struct page *page, |
| @@ -447,7 +434,7 @@ void nilfs_set_link(struct inode *dir, struct nilfs_dir_entry *de, | |||
| 447 | int err; | 434 | int err; |
| 448 | 435 | ||
| 449 | lock_page(page); | 436 | lock_page(page); |
| 450 | err = nilfs_prepare_chunk_uninterruptible(page, mapping, from, to); | 437 | err = nilfs_prepare_chunk(page, from, to); |
| 451 | BUG_ON(err); | 438 | BUG_ON(err); |
| 452 | de->inode = cpu_to_le64(inode->i_ino); | 439 | de->inode = cpu_to_le64(inode->i_ino); |
| 453 | nilfs_set_de_type(de, inode); | 440 | nilfs_set_de_type(de, inode); |
| @@ -528,7 +515,7 @@ int nilfs_add_link(struct dentry *dentry, struct inode *inode) | |||
| 528 | got_it: | 515 | got_it: |
| 529 | from = (char *)de - (char *)page_address(page); | 516 | from = (char *)de - (char *)page_address(page); |
| 530 | to = from + rec_len; | 517 | to = from + rec_len; |
| 531 | err = nilfs_prepare_chunk(page, page->mapping, from, to); | 518 | err = nilfs_prepare_chunk(page, from, to); |
| 532 | if (err) | 519 | if (err) |
| 533 | goto out_unlock; | 520 | goto out_unlock; |
| 534 | if (de->inode) { | 521 | if (de->inode) { |
| @@ -586,7 +573,7 @@ int nilfs_delete_entry(struct nilfs_dir_entry *dir, struct page *page) | |||
| 586 | if (pde) | 573 | if (pde) |
| 587 | from = (char *)pde - (char *)page_address(page); | 574 | from = (char *)pde - (char *)page_address(page); |
| 588 | lock_page(page); | 575 | lock_page(page); |
| 589 | err = nilfs_prepare_chunk(page, mapping, from, to); | 576 | err = nilfs_prepare_chunk(page, from, to); |
| 590 | BUG_ON(err); | 577 | BUG_ON(err); |
| 591 | if (pde) | 578 | if (pde) |
| 592 | pde->rec_len = nilfs_rec_len_to_disk(to - from); | 579 | pde->rec_len = nilfs_rec_len_to_disk(to - from); |
| @@ -614,7 +601,7 @@ int nilfs_make_empty(struct inode *inode, struct inode *parent) | |||
| 614 | if (!page) | 601 | if (!page) |
| 615 | return -ENOMEM; | 602 | return -ENOMEM; |
| 616 | 603 | ||
| 617 | err = nilfs_prepare_chunk(page, mapping, 0, chunk_size); | 604 | err = nilfs_prepare_chunk(page, 0, chunk_size); |
| 618 | if (unlikely(err)) { | 605 | if (unlikely(err)) { |
| 619 | unlock_page(page); | 606 | unlock_page(page); |
| 620 | goto fail; | 607 | goto fail; |
diff --git a/fs/nilfs2/gcdat.c b/fs/nilfs2/gcdat.c index dd5f7e0a95f6..84a45d1d5464 100644 --- a/fs/nilfs2/gcdat.c +++ b/fs/nilfs2/gcdat.c | |||
| @@ -78,7 +78,7 @@ void nilfs_clear_gcdat_inode(struct the_nilfs *nilfs) | |||
| 78 | struct inode *gcdat = nilfs->ns_gc_dat; | 78 | struct inode *gcdat = nilfs->ns_gc_dat; |
| 79 | struct nilfs_inode_info *gii = NILFS_I(gcdat); | 79 | struct nilfs_inode_info *gii = NILFS_I(gcdat); |
| 80 | 80 | ||
| 81 | gcdat->i_state = I_CLEAR; | 81 | gcdat->i_state = I_FREEING | I_CLEAR; |
| 82 | gii->i_flags = 0; | 82 | gii->i_flags = 0; |
| 83 | 83 | ||
| 84 | nilfs_palloc_clear_cache(gcdat); | 84 | nilfs_palloc_clear_cache(gcdat); |
diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c index 39e038ac8fcb..eccb2f2e2315 100644 --- a/fs/nilfs2/inode.c +++ b/fs/nilfs2/inode.c | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | #include <linux/writeback.h> | 27 | #include <linux/writeback.h> |
| 28 | #include <linux/uio.h> | 28 | #include <linux/uio.h> |
| 29 | #include "nilfs.h" | 29 | #include "nilfs.h" |
| 30 | #include "btnode.h" | ||
| 30 | #include "segment.h" | 31 | #include "segment.h" |
| 31 | #include "page.h" | 32 | #include "page.h" |
| 32 | #include "mdt.h" | 33 | #include "mdt.h" |
| @@ -197,11 +198,15 @@ static int nilfs_write_begin(struct file *file, struct address_space *mapping, | |||
| 197 | if (unlikely(err)) | 198 | if (unlikely(err)) |
| 198 | return err; | 199 | return err; |
| 199 | 200 | ||
| 200 | *pagep = NULL; | 201 | err = block_write_begin(mapping, pos, len, flags, pagep, |
| 201 | err = block_write_begin(file, mapping, pos, len, flags, pagep, | 202 | nilfs_get_block); |
| 202 | fsdata, nilfs_get_block); | 203 | if (unlikely(err)) { |
| 203 | if (unlikely(err)) | 204 | loff_t isize = mapping->host->i_size; |
| 205 | if (pos + len > isize) | ||
| 206 | vmtruncate(mapping->host, isize); | ||
| 207 | |||
| 204 | nilfs_transaction_abort(inode->i_sb); | 208 | nilfs_transaction_abort(inode->i_sb); |
| 209 | } | ||
| 205 | return err; | 210 | return err; |
| 206 | } | 211 | } |
| 207 | 212 | ||
| @@ -237,6 +242,19 @@ nilfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, | |||
| 237 | /* Needs synchronization with the cleaner */ | 242 | /* Needs synchronization with the cleaner */ |
| 238 | size = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, | 243 | size = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, |
| 239 | offset, nr_segs, nilfs_get_block, NULL); | 244 | offset, nr_segs, nilfs_get_block, NULL); |
| 245 | |||
| 246 | /* | ||
| 247 | * In case of error extending write may have instantiated a few | ||
| 248 | * blocks outside i_size. Trim these off again. | ||
| 249 | */ | ||
| 250 | if (unlikely((rw & WRITE) && size < 0)) { | ||
| 251 | loff_t isize = i_size_read(inode); | ||
| 252 | loff_t end = offset + iov_length(iov, nr_segs); | ||
| 253 | |||
| 254 | if (end > isize) | ||
| 255 | vmtruncate(inode, isize); | ||
| 256 | } | ||
| 257 | |||
| 240 | return size; | 258 | return size; |
| 241 | } | 259 | } |
| 242 | 260 | ||
| @@ -337,7 +355,6 @@ void nilfs_free_inode(struct inode *inode) | |||
| 337 | struct super_block *sb = inode->i_sb; | 355 | struct super_block *sb = inode->i_sb; |
| 338 | struct nilfs_sb_info *sbi = NILFS_SB(sb); | 356 | struct nilfs_sb_info *sbi = NILFS_SB(sb); |
| 339 | 357 | ||
| 340 | clear_inode(inode); | ||
| 341 | /* XXX: check error code? Is there any thing I can do? */ | 358 | /* XXX: check error code? Is there any thing I can do? */ |
| 342 | (void) nilfs_ifile_delete_inode(sbi->s_ifile, inode->i_ino); | 359 | (void) nilfs_ifile_delete_inode(sbi->s_ifile, inode->i_ino); |
| 343 | atomic_dec(&sbi->s_inodes_count); | 360 | atomic_dec(&sbi->s_inodes_count); |
| @@ -597,16 +614,34 @@ void nilfs_truncate(struct inode *inode) | |||
| 597 | But truncate has no return value. */ | 614 | But truncate has no return value. */ |
| 598 | } | 615 | } |
| 599 | 616 | ||
| 600 | void nilfs_delete_inode(struct inode *inode) | 617 | static void nilfs_clear_inode(struct inode *inode) |
| 618 | { | ||
| 619 | struct nilfs_inode_info *ii = NILFS_I(inode); | ||
| 620 | |||
| 621 | /* | ||
| 622 | * Free resources allocated in nilfs_read_inode(), here. | ||
| 623 | */ | ||
| 624 | BUG_ON(!list_empty(&ii->i_dirty)); | ||
| 625 | brelse(ii->i_bh); | ||
| 626 | ii->i_bh = NULL; | ||
| 627 | |||
| 628 | if (test_bit(NILFS_I_BMAP, &ii->i_state)) | ||
| 629 | nilfs_bmap_clear(ii->i_bmap); | ||
| 630 | |||
| 631 | nilfs_btnode_cache_clear(&ii->i_btnode_cache); | ||
| 632 | } | ||
| 633 | |||
| 634 | void nilfs_evict_inode(struct inode *inode) | ||
| 601 | { | 635 | { |
| 602 | struct nilfs_transaction_info ti; | 636 | struct nilfs_transaction_info ti; |
| 603 | struct super_block *sb = inode->i_sb; | 637 | struct super_block *sb = inode->i_sb; |
| 604 | struct nilfs_inode_info *ii = NILFS_I(inode); | 638 | struct nilfs_inode_info *ii = NILFS_I(inode); |
| 605 | 639 | ||
| 606 | if (unlikely(is_bad_inode(inode))) { | 640 | if (inode->i_nlink || unlikely(is_bad_inode(inode))) { |
| 607 | if (inode->i_data.nrpages) | 641 | if (inode->i_data.nrpages) |
| 608 | truncate_inode_pages(&inode->i_data, 0); | 642 | truncate_inode_pages(&inode->i_data, 0); |
| 609 | clear_inode(inode); | 643 | end_writeback(inode); |
| 644 | nilfs_clear_inode(inode); | ||
| 610 | return; | 645 | return; |
| 611 | } | 646 | } |
| 612 | nilfs_transaction_begin(sb, &ti, 0); /* never fails */ | 647 | nilfs_transaction_begin(sb, &ti, 0); /* never fails */ |
| @@ -616,6 +651,8 @@ void nilfs_delete_inode(struct inode *inode) | |||
| 616 | 651 | ||
| 617 | nilfs_truncate_bmap(ii, 0); | 652 | nilfs_truncate_bmap(ii, 0); |
| 618 | nilfs_mark_inode_dirty(inode); | 653 | nilfs_mark_inode_dirty(inode); |
| 654 | end_writeback(inode); | ||
| 655 | nilfs_clear_inode(inode); | ||
| 619 | nilfs_free_inode(inode); | 656 | nilfs_free_inode(inode); |
| 620 | /* nilfs_free_inode() marks inode buffer dirty */ | 657 | /* nilfs_free_inode() marks inode buffer dirty */ |
| 621 | if (IS_SYNC(inode)) | 658 | if (IS_SYNC(inode)) |
| @@ -639,14 +676,27 @@ int nilfs_setattr(struct dentry *dentry, struct iattr *iattr) | |||
| 639 | err = nilfs_transaction_begin(sb, &ti, 0); | 676 | err = nilfs_transaction_begin(sb, &ti, 0); |
| 640 | if (unlikely(err)) | 677 | if (unlikely(err)) |
| 641 | return err; | 678 | return err; |
| 642 | err = inode_setattr(inode, iattr); | 679 | |
| 643 | if (!err && (iattr->ia_valid & ATTR_MODE)) | 680 | if ((iattr->ia_valid & ATTR_SIZE) && |
| 681 | iattr->ia_size != i_size_read(inode)) { | ||
| 682 | err = vmtruncate(inode, iattr->ia_size); | ||
| 683 | if (unlikely(err)) | ||
| 684 | goto out_err; | ||
| 685 | } | ||
| 686 | |||
| 687 | setattr_copy(inode, iattr); | ||
| 688 | mark_inode_dirty(inode); | ||
| 689 | |||
| 690 | if (iattr->ia_valid & ATTR_MODE) { | ||
| 644 | err = nilfs_acl_chmod(inode); | 691 | err = nilfs_acl_chmod(inode); |
| 645 | if (likely(!err)) | 692 | if (unlikely(err)) |
| 646 | err = nilfs_transaction_commit(sb); | 693 | goto out_err; |
| 647 | else | 694 | } |
| 648 | nilfs_transaction_abort(sb); | 695 | |
| 696 | return nilfs_transaction_commit(sb); | ||
| 649 | 697 | ||
| 698 | out_err: | ||
| 699 | nilfs_transaction_abort(sb); | ||
| 650 | return err; | 700 | return err; |
| 651 | } | 701 | } |
| 652 | 702 | ||
diff --git a/fs/nilfs2/nilfs.h b/fs/nilfs2/nilfs.h index 0842d775b3e0..d3d54046e5f8 100644 --- a/fs/nilfs2/nilfs.h +++ b/fs/nilfs2/nilfs.h | |||
| @@ -250,7 +250,7 @@ extern void nilfs_write_inode_common(struct inode *, struct nilfs_inode *, int); | |||
| 250 | extern struct inode *nilfs_iget(struct super_block *, unsigned long); | 250 | extern struct inode *nilfs_iget(struct super_block *, unsigned long); |
| 251 | extern void nilfs_update_inode(struct inode *, struct buffer_head *); | 251 | extern void nilfs_update_inode(struct inode *, struct buffer_head *); |
| 252 | extern void nilfs_truncate(struct inode *); | 252 | extern void nilfs_truncate(struct inode *); |
| 253 | extern void nilfs_delete_inode(struct inode *); | 253 | extern void nilfs_evict_inode(struct inode *); |
| 254 | extern int nilfs_setattr(struct dentry *, struct iattr *); | 254 | extern int nilfs_setattr(struct dentry *, struct iattr *); |
| 255 | extern int nilfs_load_inode_block(struct nilfs_sb_info *, struct inode *, | 255 | extern int nilfs_load_inode_block(struct nilfs_sb_info *, struct inode *, |
| 256 | struct buffer_head **); | 256 | struct buffer_head **); |
diff --git a/fs/nilfs2/recovery.c b/fs/nilfs2/recovery.c index 83e3d8c61a01..d0c35ef39f6a 100644 --- a/fs/nilfs2/recovery.c +++ b/fs/nilfs2/recovery.c | |||
| @@ -523,11 +523,14 @@ static int nilfs_recover_dsync_blocks(struct the_nilfs *nilfs, | |||
| 523 | } | 523 | } |
| 524 | 524 | ||
| 525 | pos = rb->blkoff << inode->i_blkbits; | 525 | pos = rb->blkoff << inode->i_blkbits; |
| 526 | page = NULL; | 526 | err = block_write_begin(inode->i_mapping, pos, blocksize, |
| 527 | err = block_write_begin(NULL, inode->i_mapping, pos, blocksize, | 527 | 0, &page, nilfs_get_block); |
| 528 | 0, &page, NULL, nilfs_get_block); | 528 | if (unlikely(err)) { |
| 529 | if (unlikely(err)) | 529 | loff_t isize = inode->i_size; |
| 530 | if (pos + blocksize > isize) | ||
| 531 | vmtruncate(inode, isize); | ||
| 530 | goto failed_inode; | 532 | goto failed_inode; |
| 533 | } | ||
| 531 | 534 | ||
| 532 | err = nilfs_recovery_copy_block(nilfs, rb, page); | 535 | err = nilfs_recovery_copy_block(nilfs, rb, page); |
| 533 | if (unlikely(err)) | 536 | if (unlikely(err)) |
diff --git a/fs/nilfs2/segbuf.c b/fs/nilfs2/segbuf.c index 2e6a2723b8fa..4588fb9e93df 100644 --- a/fs/nilfs2/segbuf.c +++ b/fs/nilfs2/segbuf.c | |||
| @@ -508,7 +508,7 @@ static int nilfs_segbuf_write(struct nilfs_segment_buffer *segbuf, | |||
| 508 | * Last BIO is always sent through the following | 508 | * Last BIO is always sent through the following |
| 509 | * submission. | 509 | * submission. |
| 510 | */ | 510 | */ |
| 511 | rw |= (1 << BIO_RW_SYNCIO) | (1 << BIO_RW_UNPLUG); | 511 | rw |= REQ_SYNC | REQ_UNPLUG; |
| 512 | res = nilfs_segbuf_submit_bio(segbuf, &wi, rw); | 512 | res = nilfs_segbuf_submit_bio(segbuf, &wi, rw); |
| 513 | } | 513 | } |
| 514 | 514 | ||
diff --git a/fs/nilfs2/super.c b/fs/nilfs2/super.c index 26078b3407c9..1fa86b9df73b 100644 --- a/fs/nilfs2/super.c +++ b/fs/nilfs2/super.c | |||
| @@ -171,23 +171,6 @@ void nilfs_destroy_inode(struct inode *inode) | |||
| 171 | kmem_cache_free(nilfs_inode_cachep, NILFS_I(inode)); | 171 | kmem_cache_free(nilfs_inode_cachep, NILFS_I(inode)); |
| 172 | } | 172 | } |
| 173 | 173 | ||
| 174 | static void nilfs_clear_inode(struct inode *inode) | ||
| 175 | { | ||
| 176 | struct nilfs_inode_info *ii = NILFS_I(inode); | ||
| 177 | |||
| 178 | /* | ||
| 179 | * Free resources allocated in nilfs_read_inode(), here. | ||
| 180 | */ | ||
| 181 | BUG_ON(!list_empty(&ii->i_dirty)); | ||
| 182 | brelse(ii->i_bh); | ||
| 183 | ii->i_bh = NULL; | ||
| 184 | |||
| 185 | if (test_bit(NILFS_I_BMAP, &ii->i_state)) | ||
| 186 | nilfs_bmap_clear(ii->i_bmap); | ||
| 187 | |||
| 188 | nilfs_btnode_cache_clear(&ii->i_btnode_cache); | ||
| 189 | } | ||
| 190 | |||
| 191 | static int nilfs_sync_super(struct nilfs_sb_info *sbi, int flag) | 174 | static int nilfs_sync_super(struct nilfs_sb_info *sbi, int flag) |
| 192 | { | 175 | { |
| 193 | struct the_nilfs *nilfs = sbi->s_nilfs; | 176 | struct the_nilfs *nilfs = sbi->s_nilfs; |
| @@ -548,7 +531,7 @@ static const struct super_operations nilfs_sops = { | |||
| 548 | /* .write_inode = nilfs_write_inode, */ | 531 | /* .write_inode = nilfs_write_inode, */ |
| 549 | /* .put_inode = nilfs_put_inode, */ | 532 | /* .put_inode = nilfs_put_inode, */ |
| 550 | /* .drop_inode = nilfs_drop_inode, */ | 533 | /* .drop_inode = nilfs_drop_inode, */ |
| 551 | .delete_inode = nilfs_delete_inode, | 534 | .evict_inode = nilfs_evict_inode, |
| 552 | .put_super = nilfs_put_super, | 535 | .put_super = nilfs_put_super, |
| 553 | /* .write_super = nilfs_write_super, */ | 536 | /* .write_super = nilfs_write_super, */ |
| 554 | .sync_fs = nilfs_sync_fs, | 537 | .sync_fs = nilfs_sync_fs, |
| @@ -556,7 +539,6 @@ static const struct super_operations nilfs_sops = { | |||
| 556 | /* .unlockfs */ | 539 | /* .unlockfs */ |
| 557 | .statfs = nilfs_statfs, | 540 | .statfs = nilfs_statfs, |
| 558 | .remount_fs = nilfs_remount, | 541 | .remount_fs = nilfs_remount, |
| 559 | .clear_inode = nilfs_clear_inode, | ||
| 560 | /* .umount_begin */ | 542 | /* .umount_begin */ |
| 561 | .show_options = nilfs_show_options | 543 | .show_options = nilfs_show_options |
| 562 | }; | 544 | }; |
diff --git a/fs/notify/Kconfig b/fs/notify/Kconfig index dffbb0911d02..22c629eedd82 100644 --- a/fs/notify/Kconfig +++ b/fs/notify/Kconfig | |||
| @@ -3,3 +3,4 @@ config FSNOTIFY | |||
| 3 | 3 | ||
| 4 | source "fs/notify/dnotify/Kconfig" | 4 | source "fs/notify/dnotify/Kconfig" |
| 5 | source "fs/notify/inotify/Kconfig" | 5 | source "fs/notify/inotify/Kconfig" |
| 6 | source "fs/notify/fanotify/Kconfig" | ||
diff --git a/fs/notify/Makefile b/fs/notify/Makefile index 0922cc826c46..ae5f33a6d868 100644 --- a/fs/notify/Makefile +++ b/fs/notify/Makefile | |||
| @@ -1,4 +1,6 @@ | |||
| 1 | obj-$(CONFIG_FSNOTIFY) += fsnotify.o notification.o group.o inode_mark.o | 1 | obj-$(CONFIG_FSNOTIFY) += fsnotify.o notification.o group.o inode_mark.o \ |
| 2 | mark.o vfsmount_mark.o | ||
| 2 | 3 | ||
| 3 | obj-y += dnotify/ | 4 | obj-y += dnotify/ |
| 4 | obj-y += inotify/ | 5 | obj-y += inotify/ |
| 6 | obj-y += fanotify/ | ||
diff --git a/fs/notify/dnotify/dnotify.c b/fs/notify/dnotify/dnotify.c index 7e54e52964dd..3344bdd5506e 100644 --- a/fs/notify/dnotify/dnotify.c +++ b/fs/notify/dnotify/dnotify.c | |||
| @@ -29,17 +29,17 @@ | |||
| 29 | int dir_notify_enable __read_mostly = 1; | 29 | int dir_notify_enable __read_mostly = 1; |
| 30 | 30 | ||
| 31 | static struct kmem_cache *dnotify_struct_cache __read_mostly; | 31 | static struct kmem_cache *dnotify_struct_cache __read_mostly; |
| 32 | static struct kmem_cache *dnotify_mark_entry_cache __read_mostly; | 32 | static struct kmem_cache *dnotify_mark_cache __read_mostly; |
| 33 | static struct fsnotify_group *dnotify_group __read_mostly; | 33 | static struct fsnotify_group *dnotify_group __read_mostly; |
| 34 | static DEFINE_MUTEX(dnotify_mark_mutex); | 34 | static DEFINE_MUTEX(dnotify_mark_mutex); |
| 35 | 35 | ||
| 36 | /* | 36 | /* |
| 37 | * dnotify will attach one of these to each inode (i_fsnotify_mark_entries) which | 37 | * dnotify will attach one of these to each inode (i_fsnotify_marks) which |
| 38 | * is being watched by dnotify. If multiple userspace applications are watching | 38 | * is being watched by dnotify. If multiple userspace applications are watching |
| 39 | * the same directory with dnotify their information is chained in dn | 39 | * the same directory with dnotify their information is chained in dn |
| 40 | */ | 40 | */ |
| 41 | struct dnotify_mark_entry { | 41 | struct dnotify_mark { |
| 42 | struct fsnotify_mark_entry fsn_entry; | 42 | struct fsnotify_mark fsn_mark; |
| 43 | struct dnotify_struct *dn; | 43 | struct dnotify_struct *dn; |
| 44 | }; | 44 | }; |
| 45 | 45 | ||
| @@ -51,27 +51,27 @@ struct dnotify_mark_entry { | |||
| 51 | * it calls the fsnotify function so it can update the set of all events relevant | 51 | * it calls the fsnotify function so it can update the set of all events relevant |
| 52 | * to this inode. | 52 | * to this inode. |
| 53 | */ | 53 | */ |
| 54 | static void dnotify_recalc_inode_mask(struct fsnotify_mark_entry *entry) | 54 | static void dnotify_recalc_inode_mask(struct fsnotify_mark *fsn_mark) |
| 55 | { | 55 | { |
| 56 | __u32 new_mask, old_mask; | 56 | __u32 new_mask, old_mask; |
| 57 | struct dnotify_struct *dn; | 57 | struct dnotify_struct *dn; |
| 58 | struct dnotify_mark_entry *dnentry = container_of(entry, | 58 | struct dnotify_mark *dn_mark = container_of(fsn_mark, |
| 59 | struct dnotify_mark_entry, | 59 | struct dnotify_mark, |
| 60 | fsn_entry); | 60 | fsn_mark); |
| 61 | 61 | ||
| 62 | assert_spin_locked(&entry->lock); | 62 | assert_spin_locked(&fsn_mark->lock); |
| 63 | 63 | ||
| 64 | old_mask = entry->mask; | 64 | old_mask = fsn_mark->mask; |
| 65 | new_mask = 0; | 65 | new_mask = 0; |
| 66 | for (dn = dnentry->dn; dn != NULL; dn = dn->dn_next) | 66 | for (dn = dn_mark->dn; dn != NULL; dn = dn->dn_next) |
| 67 | new_mask |= (dn->dn_mask & ~FS_DN_MULTISHOT); | 67 | new_mask |= (dn->dn_mask & ~FS_DN_MULTISHOT); |
| 68 | entry->mask = new_mask; | 68 | fsnotify_set_mark_mask_locked(fsn_mark, new_mask); |
| 69 | 69 | ||
| 70 | if (old_mask == new_mask) | 70 | if (old_mask == new_mask) |
| 71 | return; | 71 | return; |
| 72 | 72 | ||
| 73 | if (entry->inode) | 73 | if (fsn_mark->i.inode) |
| 74 | fsnotify_recalc_inode_mask(entry->inode); | 74 | fsnotify_recalc_inode_mask(fsn_mark->i.inode); |
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | /* | 77 | /* |
| @@ -83,29 +83,25 @@ static void dnotify_recalc_inode_mask(struct fsnotify_mark_entry *entry) | |||
| 83 | * events. | 83 | * events. |
| 84 | */ | 84 | */ |
| 85 | static int dnotify_handle_event(struct fsnotify_group *group, | 85 | static int dnotify_handle_event(struct fsnotify_group *group, |
| 86 | struct fsnotify_mark *inode_mark, | ||
| 87 | struct fsnotify_mark *vfsmount_mark, | ||
| 86 | struct fsnotify_event *event) | 88 | struct fsnotify_event *event) |
| 87 | { | 89 | { |
| 88 | struct fsnotify_mark_entry *entry = NULL; | 90 | struct dnotify_mark *dn_mark; |
| 89 | struct dnotify_mark_entry *dnentry; | ||
| 90 | struct inode *to_tell; | 91 | struct inode *to_tell; |
| 91 | struct dnotify_struct *dn; | 92 | struct dnotify_struct *dn; |
| 92 | struct dnotify_struct **prev; | 93 | struct dnotify_struct **prev; |
| 93 | struct fown_struct *fown; | 94 | struct fown_struct *fown; |
| 94 | __u32 test_mask = event->mask & ~FS_EVENT_ON_CHILD; | 95 | __u32 test_mask = event->mask & ~FS_EVENT_ON_CHILD; |
| 95 | 96 | ||
| 96 | to_tell = event->to_tell; | 97 | BUG_ON(vfsmount_mark); |
| 97 | 98 | ||
| 98 | spin_lock(&to_tell->i_lock); | 99 | to_tell = event->to_tell; |
| 99 | entry = fsnotify_find_mark_entry(group, to_tell); | ||
| 100 | spin_unlock(&to_tell->i_lock); | ||
| 101 | 100 | ||
| 102 | /* unlikely since we alreay passed dnotify_should_send_event() */ | 101 | dn_mark = container_of(inode_mark, struct dnotify_mark, fsn_mark); |
| 103 | if (unlikely(!entry)) | ||
| 104 | return 0; | ||
| 105 | dnentry = container_of(entry, struct dnotify_mark_entry, fsn_entry); | ||
| 106 | 102 | ||
| 107 | spin_lock(&entry->lock); | 103 | spin_lock(&inode_mark->lock); |
| 108 | prev = &dnentry->dn; | 104 | prev = &dn_mark->dn; |
| 109 | while ((dn = *prev) != NULL) { | 105 | while ((dn = *prev) != NULL) { |
| 110 | if ((dn->dn_mask & test_mask) == 0) { | 106 | if ((dn->dn_mask & test_mask) == 0) { |
| 111 | prev = &dn->dn_next; | 107 | prev = &dn->dn_next; |
| @@ -118,12 +114,11 @@ static int dnotify_handle_event(struct fsnotify_group *group, | |||
| 118 | else { | 114 | else { |
| 119 | *prev = dn->dn_next; | 115 | *prev = dn->dn_next; |
| 120 | kmem_cache_free(dnotify_struct_cache, dn); | 116 | kmem_cache_free(dnotify_struct_cache, dn); |
| 121 | dnotify_recalc_inode_mask(entry); | 117 | dnotify_recalc_inode_mask(inode_mark); |
| 122 | } | 118 | } |
| 123 | } | 119 | } |
| 124 | 120 | ||
| 125 | spin_unlock(&entry->lock); | 121 | spin_unlock(&inode_mark->lock); |
| 126 | fsnotify_put_mark(entry); | ||
| 127 | 122 | ||
| 128 | return 0; | 123 | return 0; |
| 129 | } | 124 | } |
| @@ -133,44 +128,27 @@ static int dnotify_handle_event(struct fsnotify_group *group, | |||
| 133 | * userspace notification for that pair. | 128 | * userspace notification for that pair. |
| 134 | */ | 129 | */ |
| 135 | static bool dnotify_should_send_event(struct fsnotify_group *group, | 130 | static bool dnotify_should_send_event(struct fsnotify_group *group, |
| 136 | struct inode *inode, __u32 mask) | 131 | struct inode *inode, |
| 132 | struct fsnotify_mark *inode_mark, | ||
| 133 | struct fsnotify_mark *vfsmount_mark, | ||
| 134 | __u32 mask, void *data, int data_type) | ||
| 137 | { | 135 | { |
| 138 | struct fsnotify_mark_entry *entry; | ||
| 139 | bool send; | ||
| 140 | |||
| 141 | /* !dir_notify_enable should never get here, don't waste time checking | ||
| 142 | if (!dir_notify_enable) | ||
| 143 | return 0; */ | ||
| 144 | |||
| 145 | /* not a dir, dnotify doesn't care */ | 136 | /* not a dir, dnotify doesn't care */ |
| 146 | if (!S_ISDIR(inode->i_mode)) | 137 | if (!S_ISDIR(inode->i_mode)) |
| 147 | return false; | 138 | return false; |
| 148 | 139 | ||
| 149 | spin_lock(&inode->i_lock); | 140 | return true; |
| 150 | entry = fsnotify_find_mark_entry(group, inode); | ||
| 151 | spin_unlock(&inode->i_lock); | ||
| 152 | |||
| 153 | /* no mark means no dnotify watch */ | ||
| 154 | if (!entry) | ||
| 155 | return false; | ||
| 156 | |||
| 157 | mask = (mask & ~FS_EVENT_ON_CHILD); | ||
| 158 | send = (mask & entry->mask); | ||
| 159 | |||
| 160 | fsnotify_put_mark(entry); /* matches fsnotify_find_mark_entry */ | ||
| 161 | |||
| 162 | return send; | ||
| 163 | } | 141 | } |
| 164 | 142 | ||
| 165 | static void dnotify_free_mark(struct fsnotify_mark_entry *entry) | 143 | static void dnotify_free_mark(struct fsnotify_mark *fsn_mark) |
| 166 | { | 144 | { |
| 167 | struct dnotify_mark_entry *dnentry = container_of(entry, | 145 | struct dnotify_mark *dn_mark = container_of(fsn_mark, |
| 168 | struct dnotify_mark_entry, | 146 | struct dnotify_mark, |
| 169 | fsn_entry); | 147 | fsn_mark); |
| 170 | 148 | ||
| 171 | BUG_ON(dnentry->dn); | 149 | BUG_ON(dn_mark->dn); |
| 172 | 150 | ||
| 173 | kmem_cache_free(dnotify_mark_entry_cache, dnentry); | 151 | kmem_cache_free(dnotify_mark_cache, dn_mark); |
| 174 | } | 152 | } |
| 175 | 153 | ||
| 176 | static struct fsnotify_ops dnotify_fsnotify_ops = { | 154 | static struct fsnotify_ops dnotify_fsnotify_ops = { |
| @@ -183,15 +161,15 @@ static struct fsnotify_ops dnotify_fsnotify_ops = { | |||
| 183 | 161 | ||
| 184 | /* | 162 | /* |
| 185 | * Called every time a file is closed. Looks first for a dnotify mark on the | 163 | * Called every time a file is closed. Looks first for a dnotify mark on the |
| 186 | * inode. If one is found run all of the ->dn entries attached to that | 164 | * inode. If one is found run all of the ->dn structures attached to that |
| 187 | * mark for one relevant to this process closing the file and remove that | 165 | * mark for one relevant to this process closing the file and remove that |
| 188 | * dnotify_struct. If that was the last dnotify_struct also remove the | 166 | * dnotify_struct. If that was the last dnotify_struct also remove the |
| 189 | * fsnotify_mark_entry. | 167 | * fsnotify_mark. |
| 190 | */ | 168 | */ |
| 191 | void dnotify_flush(struct file *filp, fl_owner_t id) | 169 | void dnotify_flush(struct file *filp, fl_owner_t id) |
| 192 | { | 170 | { |
| 193 | struct fsnotify_mark_entry *entry; | 171 | struct fsnotify_mark *fsn_mark; |
| 194 | struct dnotify_mark_entry *dnentry; | 172 | struct dnotify_mark *dn_mark; |
| 195 | struct dnotify_struct *dn; | 173 | struct dnotify_struct *dn; |
| 196 | struct dnotify_struct **prev; | 174 | struct dnotify_struct **prev; |
| 197 | struct inode *inode; | 175 | struct inode *inode; |
| @@ -200,38 +178,34 @@ void dnotify_flush(struct file *filp, fl_owner_t id) | |||
| 200 | if (!S_ISDIR(inode->i_mode)) | 178 | if (!S_ISDIR(inode->i_mode)) |
| 201 | return; | 179 | return; |
| 202 | 180 | ||
| 203 | spin_lock(&inode->i_lock); | 181 | fsn_mark = fsnotify_find_inode_mark(dnotify_group, inode); |
| 204 | entry = fsnotify_find_mark_entry(dnotify_group, inode); | 182 | if (!fsn_mark) |
| 205 | spin_unlock(&inode->i_lock); | ||
| 206 | if (!entry) | ||
| 207 | return; | 183 | return; |
| 208 | dnentry = container_of(entry, struct dnotify_mark_entry, fsn_entry); | 184 | dn_mark = container_of(fsn_mark, struct dnotify_mark, fsn_mark); |
| 209 | 185 | ||
| 210 | mutex_lock(&dnotify_mark_mutex); | 186 | mutex_lock(&dnotify_mark_mutex); |
| 211 | 187 | ||
| 212 | spin_lock(&entry->lock); | 188 | spin_lock(&fsn_mark->lock); |
| 213 | prev = &dnentry->dn; | 189 | prev = &dn_mark->dn; |
| 214 | while ((dn = *prev) != NULL) { | 190 | while ((dn = *prev) != NULL) { |
| 215 | if ((dn->dn_owner == id) && (dn->dn_filp == filp)) { | 191 | if ((dn->dn_owner == id) && (dn->dn_filp == filp)) { |
| 216 | *prev = dn->dn_next; | 192 | *prev = dn->dn_next; |
| 217 | kmem_cache_free(dnotify_struct_cache, dn); | 193 | kmem_cache_free(dnotify_struct_cache, dn); |
| 218 | dnotify_recalc_inode_mask(entry); | 194 | dnotify_recalc_inode_mask(fsn_mark); |
| 219 | break; | 195 | break; |
| 220 | } | 196 | } |
| 221 | prev = &dn->dn_next; | 197 | prev = &dn->dn_next; |
| 222 | } | 198 | } |
| 223 | 199 | ||
| 224 | spin_unlock(&entry->lock); | 200 | spin_unlock(&fsn_mark->lock); |
| 225 | 201 | ||
| 226 | /* nothing else could have found us thanks to the dnotify_mark_mutex */ | 202 | /* nothing else could have found us thanks to the dnotify_mark_mutex */ |
| 227 | if (dnentry->dn == NULL) | 203 | if (dn_mark->dn == NULL) |
| 228 | fsnotify_destroy_mark_by_entry(entry); | 204 | fsnotify_destroy_mark(fsn_mark); |
| 229 | |||
| 230 | fsnotify_recalc_group_mask(dnotify_group); | ||
| 231 | 205 | ||
| 232 | mutex_unlock(&dnotify_mark_mutex); | 206 | mutex_unlock(&dnotify_mark_mutex); |
| 233 | 207 | ||
| 234 | fsnotify_put_mark(entry); | 208 | fsnotify_put_mark(fsn_mark); |
| 235 | } | 209 | } |
| 236 | 210 | ||
| 237 | /* this conversion is done only at watch creation */ | 211 | /* this conversion is done only at watch creation */ |
| @@ -259,16 +233,16 @@ static __u32 convert_arg(unsigned long arg) | |||
| 259 | 233 | ||
| 260 | /* | 234 | /* |
| 261 | * If multiple processes watch the same inode with dnotify there is only one | 235 | * If multiple processes watch the same inode with dnotify there is only one |
| 262 | * dnotify mark in inode->i_fsnotify_mark_entries but we chain a dnotify_struct | 236 | * dnotify mark in inode->i_fsnotify_marks but we chain a dnotify_struct |
| 263 | * onto that mark. This function either attaches the new dnotify_struct onto | 237 | * onto that mark. This function either attaches the new dnotify_struct onto |
| 264 | * that list, or it |= the mask onto an existing dnofiy_struct. | 238 | * that list, or it |= the mask onto an existing dnofiy_struct. |
| 265 | */ | 239 | */ |
| 266 | static int attach_dn(struct dnotify_struct *dn, struct dnotify_mark_entry *dnentry, | 240 | static int attach_dn(struct dnotify_struct *dn, struct dnotify_mark *dn_mark, |
| 267 | fl_owner_t id, int fd, struct file *filp, __u32 mask) | 241 | fl_owner_t id, int fd, struct file *filp, __u32 mask) |
| 268 | { | 242 | { |
| 269 | struct dnotify_struct *odn; | 243 | struct dnotify_struct *odn; |
| 270 | 244 | ||
| 271 | odn = dnentry->dn; | 245 | odn = dn_mark->dn; |
| 272 | while (odn != NULL) { | 246 | while (odn != NULL) { |
| 273 | /* adding more events to existing dnofiy_struct? */ | 247 | /* adding more events to existing dnofiy_struct? */ |
| 274 | if ((odn->dn_owner == id) && (odn->dn_filp == filp)) { | 248 | if ((odn->dn_owner == id) && (odn->dn_filp == filp)) { |
| @@ -283,8 +257,8 @@ static int attach_dn(struct dnotify_struct *dn, struct dnotify_mark_entry *dnent | |||
| 283 | dn->dn_fd = fd; | 257 | dn->dn_fd = fd; |
| 284 | dn->dn_filp = filp; | 258 | dn->dn_filp = filp; |
| 285 | dn->dn_owner = id; | 259 | dn->dn_owner = id; |
| 286 | dn->dn_next = dnentry->dn; | 260 | dn->dn_next = dn_mark->dn; |
| 287 | dnentry->dn = dn; | 261 | dn_mark->dn = dn; |
| 288 | 262 | ||
| 289 | return 0; | 263 | return 0; |
| 290 | } | 264 | } |
| @@ -296,8 +270,8 @@ static int attach_dn(struct dnotify_struct *dn, struct dnotify_mark_entry *dnent | |||
| 296 | */ | 270 | */ |
| 297 | int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg) | 271 | int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg) |
| 298 | { | 272 | { |
| 299 | struct dnotify_mark_entry *new_dnentry, *dnentry; | 273 | struct dnotify_mark *new_dn_mark, *dn_mark; |
| 300 | struct fsnotify_mark_entry *new_entry, *entry; | 274 | struct fsnotify_mark *new_fsn_mark, *fsn_mark; |
| 301 | struct dnotify_struct *dn; | 275 | struct dnotify_struct *dn; |
| 302 | struct inode *inode; | 276 | struct inode *inode; |
| 303 | fl_owner_t id = current->files; | 277 | fl_owner_t id = current->files; |
| @@ -306,7 +280,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg) | |||
| 306 | __u32 mask; | 280 | __u32 mask; |
| 307 | 281 | ||
| 308 | /* we use these to tell if we need to kfree */ | 282 | /* we use these to tell if we need to kfree */ |
| 309 | new_entry = NULL; | 283 | new_fsn_mark = NULL; |
| 310 | dn = NULL; | 284 | dn = NULL; |
| 311 | 285 | ||
| 312 | if (!dir_notify_enable) { | 286 | if (!dir_notify_enable) { |
| @@ -336,8 +310,8 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg) | |||
| 336 | } | 310 | } |
| 337 | 311 | ||
| 338 | /* new fsnotify mark, we expect most fcntl calls to add a new mark */ | 312 | /* new fsnotify mark, we expect most fcntl calls to add a new mark */ |
| 339 | new_dnentry = kmem_cache_alloc(dnotify_mark_entry_cache, GFP_KERNEL); | 313 | new_dn_mark = kmem_cache_alloc(dnotify_mark_cache, GFP_KERNEL); |
| 340 | if (!new_dnentry) { | 314 | if (!new_dn_mark) { |
| 341 | error = -ENOMEM; | 315 | error = -ENOMEM; |
| 342 | goto out_err; | 316 | goto out_err; |
| 343 | } | 317 | } |
| @@ -345,29 +319,27 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg) | |||
| 345 | /* convert the userspace DN_* "arg" to the internal FS_* defines in fsnotify */ | 319 | /* convert the userspace DN_* "arg" to the internal FS_* defines in fsnotify */ |
| 346 | mask = convert_arg(arg); | 320 | mask = convert_arg(arg); |
| 347 | 321 | ||
| 348 | /* set up the new_entry and new_dnentry */ | 322 | /* set up the new_fsn_mark and new_dn_mark */ |
| 349 | new_entry = &new_dnentry->fsn_entry; | 323 | new_fsn_mark = &new_dn_mark->fsn_mark; |
| 350 | fsnotify_init_mark(new_entry, dnotify_free_mark); | 324 | fsnotify_init_mark(new_fsn_mark, dnotify_free_mark); |
| 351 | new_entry->mask = mask; | 325 | new_fsn_mark->mask = mask; |
| 352 | new_dnentry->dn = NULL; | 326 | new_dn_mark->dn = NULL; |
| 353 | 327 | ||
| 354 | /* this is needed to prevent the fcntl/close race described below */ | 328 | /* this is needed to prevent the fcntl/close race described below */ |
| 355 | mutex_lock(&dnotify_mark_mutex); | 329 | mutex_lock(&dnotify_mark_mutex); |
| 356 | 330 | ||
| 357 | /* add the new_entry or find an old one. */ | 331 | /* add the new_fsn_mark or find an old one. */ |
| 358 | spin_lock(&inode->i_lock); | 332 | fsn_mark = fsnotify_find_inode_mark(dnotify_group, inode); |
| 359 | entry = fsnotify_find_mark_entry(dnotify_group, inode); | 333 | if (fsn_mark) { |
| 360 | spin_unlock(&inode->i_lock); | 334 | dn_mark = container_of(fsn_mark, struct dnotify_mark, fsn_mark); |
| 361 | if (entry) { | 335 | spin_lock(&fsn_mark->lock); |
| 362 | dnentry = container_of(entry, struct dnotify_mark_entry, fsn_entry); | ||
| 363 | spin_lock(&entry->lock); | ||
| 364 | } else { | 336 | } else { |
| 365 | fsnotify_add_mark(new_entry, dnotify_group, inode); | 337 | fsnotify_add_mark(new_fsn_mark, dnotify_group, inode, NULL, 0); |
| 366 | spin_lock(&new_entry->lock); | 338 | spin_lock(&new_fsn_mark->lock); |
| 367 | entry = new_entry; | 339 | fsn_mark = new_fsn_mark; |
| 368 | dnentry = new_dnentry; | 340 | dn_mark = new_dn_mark; |
| 369 | /* we used new_entry, so don't free it */ | 341 | /* we used new_fsn_mark, so don't free it */ |
| 370 | new_entry = NULL; | 342 | new_fsn_mark = NULL; |
| 371 | } | 343 | } |
| 372 | 344 | ||
| 373 | rcu_read_lock(); | 345 | rcu_read_lock(); |
| @@ -376,17 +348,17 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg) | |||
| 376 | 348 | ||
| 377 | /* if (f != filp) means that we lost a race and another task/thread | 349 | /* if (f != filp) means that we lost a race and another task/thread |
| 378 | * actually closed the fd we are still playing with before we grabbed | 350 | * actually closed the fd we are still playing with before we grabbed |
| 379 | * the dnotify_mark_mutex and entry->lock. Since closing the fd is the | 351 | * the dnotify_mark_mutex and fsn_mark->lock. Since closing the fd is the |
| 380 | * only time we clean up the mark entries we need to get our mark off | 352 | * only time we clean up the marks we need to get our mark off |
| 381 | * the list. */ | 353 | * the list. */ |
| 382 | if (f != filp) { | 354 | if (f != filp) { |
| 383 | /* if we added ourselves, shoot ourselves, it's possible that | 355 | /* if we added ourselves, shoot ourselves, it's possible that |
| 384 | * the flush actually did shoot this entry. That's fine too | 356 | * the flush actually did shoot this fsn_mark. That's fine too |
| 385 | * since multiple calls to destroy_mark is perfectly safe, if | 357 | * since multiple calls to destroy_mark is perfectly safe, if |
| 386 | * we found a dnentry already attached to the inode, just sod | 358 | * we found a dn_mark already attached to the inode, just sod |
| 387 | * off silently as the flush at close time dealt with it. | 359 | * off silently as the flush at close time dealt with it. |
| 388 | */ | 360 | */ |
| 389 | if (dnentry == new_dnentry) | 361 | if (dn_mark == new_dn_mark) |
| 390 | destroy = 1; | 362 | destroy = 1; |
| 391 | goto out; | 363 | goto out; |
| 392 | } | 364 | } |
| @@ -394,13 +366,13 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg) | |||
| 394 | error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0); | 366 | error = __f_setown(filp, task_pid(current), PIDTYPE_PID, 0); |
| 395 | if (error) { | 367 | if (error) { |
| 396 | /* if we added, we must shoot */ | 368 | /* if we added, we must shoot */ |
| 397 | if (dnentry == new_dnentry) | 369 | if (dn_mark == new_dn_mark) |
| 398 | destroy = 1; | 370 | destroy = 1; |
| 399 | goto out; | 371 | goto out; |
| 400 | } | 372 | } |
| 401 | 373 | ||
| 402 | error = attach_dn(dn, dnentry, id, fd, filp, mask); | 374 | error = attach_dn(dn, dn_mark, id, fd, filp, mask); |
| 403 | /* !error means that we attached the dn to the dnentry, so don't free it */ | 375 | /* !error means that we attached the dn to the dn_mark, so don't free it */ |
| 404 | if (!error) | 376 | if (!error) |
| 405 | dn = NULL; | 377 | dn = NULL; |
| 406 | /* -EEXIST means that we didn't add this new dn and used an old one. | 378 | /* -EEXIST means that we didn't add this new dn and used an old one. |
| @@ -408,20 +380,18 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg) | |||
| 408 | else if (error == -EEXIST) | 380 | else if (error == -EEXIST) |
| 409 | error = 0; | 381 | error = 0; |
| 410 | 382 | ||
| 411 | dnotify_recalc_inode_mask(entry); | 383 | dnotify_recalc_inode_mask(fsn_mark); |
| 412 | out: | 384 | out: |
| 413 | spin_unlock(&entry->lock); | 385 | spin_unlock(&fsn_mark->lock); |
| 414 | 386 | ||
| 415 | if (destroy) | 387 | if (destroy) |
| 416 | fsnotify_destroy_mark_by_entry(entry); | 388 | fsnotify_destroy_mark(fsn_mark); |
| 417 | |||
| 418 | fsnotify_recalc_group_mask(dnotify_group); | ||
| 419 | 389 | ||
| 420 | mutex_unlock(&dnotify_mark_mutex); | 390 | mutex_unlock(&dnotify_mark_mutex); |
| 421 | fsnotify_put_mark(entry); | 391 | fsnotify_put_mark(fsn_mark); |
| 422 | out_err: | 392 | out_err: |
| 423 | if (new_entry) | 393 | if (new_fsn_mark) |
| 424 | fsnotify_put_mark(new_entry); | 394 | fsnotify_put_mark(new_fsn_mark); |
| 425 | if (dn) | 395 | if (dn) |
| 426 | kmem_cache_free(dnotify_struct_cache, dn); | 396 | kmem_cache_free(dnotify_struct_cache, dn); |
| 427 | return error; | 397 | return error; |
| @@ -430,10 +400,9 @@ out_err: | |||
| 430 | static int __init dnotify_init(void) | 400 | static int __init dnotify_init(void) |
| 431 | { | 401 | { |
| 432 | dnotify_struct_cache = KMEM_CACHE(dnotify_struct, SLAB_PANIC); | 402 | dnotify_struct_cache = KMEM_CACHE(dnotify_struct, SLAB_PANIC); |
| 433 | dnotify_mark_entry_cache = KMEM_CACHE(dnotify_mark_entry, SLAB_PANIC); | 403 | dnotify_mark_cache = KMEM_CACHE(dnotify_mark, SLAB_PANIC); |
| 434 | 404 | ||
| 435 | dnotify_group = fsnotify_obtain_group(DNOTIFY_GROUP_NUM, | 405 | dnotify_group = fsnotify_alloc_group(&dnotify_fsnotify_ops); |
| 436 | 0, &dnotify_fsnotify_ops); | ||
| 437 | if (IS_ERR(dnotify_group)) | 406 | if (IS_ERR(dnotify_group)) |
| 438 | panic("unable to allocate fsnotify group for dnotify\n"); | 407 | panic("unable to allocate fsnotify group for dnotify\n"); |
| 439 | return 0; | 408 | return 0; |
diff --git a/fs/notify/fanotify/Kconfig b/fs/notify/fanotify/Kconfig new file mode 100644 index 000000000000..3ac36b7bf6b9 --- /dev/null +++ b/fs/notify/fanotify/Kconfig | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | config FANOTIFY | ||
| 2 | bool "Filesystem wide access notification" | ||
| 3 | select FSNOTIFY | ||
| 4 | select ANON_INODES | ||
| 5 | default n | ||
| 6 | ---help--- | ||
| 7 | Say Y here to enable fanotify suport. fanotify is a file access | ||
| 8 | notification system which differs from inotify in that it sends | ||
| 9 | and open file descriptor to the userspace listener along with | ||
| 10 | the event. | ||
| 11 | |||
| 12 | If unsure, say Y. | ||
| 13 | |||
| 14 | config FANOTIFY_ACCESS_PERMISSIONS | ||
| 15 | bool "fanotify permissions checking" | ||
| 16 | depends on FANOTIFY | ||
| 17 | depends on SECURITY | ||
| 18 | default n | ||
| 19 | ---help--- | ||
| 20 | Say Y here is you want fanotify listeners to be able to make permissions | ||
| 21 | decisions concerning filesystem events. This is used by some fanotify | ||
| 22 | listeners which need to scan files before allowing the system access to | ||
| 23 | use those files. This is used by some anti-malware vendors and by some | ||
| 24 | hierarchical storage managent systems. | ||
| 25 | |||
| 26 | If unsure, say N. | ||
diff --git a/fs/notify/fanotify/Makefile b/fs/notify/fanotify/Makefile new file mode 100644 index 000000000000..0999213e7e6e --- /dev/null +++ b/fs/notify/fanotify/Makefile | |||
| @@ -0,0 +1 @@ | |||
| obj-$(CONFIG_FANOTIFY) += fanotify.o fanotify_user.o | |||
diff --git a/fs/notify/fanotify/fanotify.c b/fs/notify/fanotify/fanotify.c new file mode 100644 index 000000000000..756566fe8449 --- /dev/null +++ b/fs/notify/fanotify/fanotify.c | |||
| @@ -0,0 +1,212 @@ | |||
| 1 | #include <linux/fanotify.h> | ||
| 2 | #include <linux/fdtable.h> | ||
| 3 | #include <linux/fsnotify_backend.h> | ||
| 4 | #include <linux/init.h> | ||
| 5 | #include <linux/jiffies.h> | ||
| 6 | #include <linux/kernel.h> /* UINT_MAX */ | ||
| 7 | #include <linux/mount.h> | ||
| 8 | #include <linux/sched.h> | ||
| 9 | #include <linux/types.h> | ||
| 10 | #include <linux/wait.h> | ||
| 11 | |||
| 12 | static bool should_merge(struct fsnotify_event *old, struct fsnotify_event *new) | ||
| 13 | { | ||
| 14 | pr_debug("%s: old=%p new=%p\n", __func__, old, new); | ||
| 15 | |||
| 16 | if (old->to_tell == new->to_tell && | ||
| 17 | old->data_type == new->data_type && | ||
| 18 | old->tgid == new->tgid) { | ||
| 19 | switch (old->data_type) { | ||
| 20 | case (FSNOTIFY_EVENT_PATH): | ||
| 21 | if ((old->path.mnt == new->path.mnt) && | ||
| 22 | (old->path.dentry == new->path.dentry)) | ||
| 23 | return true; | ||
| 24 | case (FSNOTIFY_EVENT_NONE): | ||
| 25 | return true; | ||
| 26 | default: | ||
| 27 | BUG(); | ||
| 28 | }; | ||
| 29 | } | ||
| 30 | return false; | ||
| 31 | } | ||
| 32 | |||
| 33 | /* and the list better be locked by something too! */ | ||
| 34 | static struct fsnotify_event *fanotify_merge(struct list_head *list, | ||
| 35 | struct fsnotify_event *event) | ||
| 36 | { | ||
| 37 | struct fsnotify_event_holder *test_holder; | ||
| 38 | struct fsnotify_event *test_event = NULL; | ||
| 39 | struct fsnotify_event *new_event; | ||
| 40 | |||
| 41 | pr_debug("%s: list=%p event=%p\n", __func__, list, event); | ||
| 42 | |||
| 43 | |||
| 44 | list_for_each_entry_reverse(test_holder, list, event_list) { | ||
| 45 | if (should_merge(test_holder->event, event)) { | ||
| 46 | test_event = test_holder->event; | ||
| 47 | break; | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | if (!test_event) | ||
| 52 | return NULL; | ||
| 53 | |||
| 54 | fsnotify_get_event(test_event); | ||
| 55 | |||
| 56 | /* if they are exactly the same we are done */ | ||
| 57 | if (test_event->mask == event->mask) | ||
| 58 | return test_event; | ||
| 59 | |||
| 60 | /* | ||
| 61 | * if the refcnt == 2 this is the only queue | ||
| 62 | * for this event and so we can update the mask | ||
| 63 | * in place. | ||
| 64 | */ | ||
| 65 | if (atomic_read(&test_event->refcnt) == 2) { | ||
| 66 | test_event->mask |= event->mask; | ||
| 67 | return test_event; | ||
| 68 | } | ||
| 69 | |||
| 70 | new_event = fsnotify_clone_event(test_event); | ||
| 71 | |||
| 72 | /* done with test_event */ | ||
| 73 | fsnotify_put_event(test_event); | ||
| 74 | |||
| 75 | /* couldn't allocate memory, merge was not possible */ | ||
| 76 | if (unlikely(!new_event)) | ||
| 77 | return ERR_PTR(-ENOMEM); | ||
| 78 | |||
| 79 | /* build new event and replace it on the list */ | ||
| 80 | new_event->mask = (test_event->mask | event->mask); | ||
| 81 | fsnotify_replace_event(test_holder, new_event); | ||
| 82 | |||
| 83 | /* we hold a reference on new_event from clone_event */ | ||
| 84 | return new_event; | ||
| 85 | } | ||
| 86 | |||
| 87 | #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS | ||
| 88 | static int fanotify_get_response_from_access(struct fsnotify_group *group, | ||
| 89 | struct fsnotify_event *event) | ||
| 90 | { | ||
| 91 | int ret; | ||
| 92 | |||
| 93 | pr_debug("%s: group=%p event=%p\n", __func__, group, event); | ||
| 94 | |||
| 95 | wait_event(group->fanotify_data.access_waitq, event->response); | ||
| 96 | |||
| 97 | /* userspace responded, convert to something usable */ | ||
| 98 | spin_lock(&event->lock); | ||
| 99 | switch (event->response) { | ||
| 100 | case FAN_ALLOW: | ||
| 101 | ret = 0; | ||
| 102 | break; | ||
| 103 | case FAN_DENY: | ||
| 104 | default: | ||
| 105 | ret = -EPERM; | ||
| 106 | } | ||
| 107 | event->response = 0; | ||
| 108 | spin_unlock(&event->lock); | ||
| 109 | |||
| 110 | pr_debug("%s: group=%p event=%p about to return ret=%d\n", __func__, | ||
| 111 | group, event, ret); | ||
| 112 | |||
| 113 | return ret; | ||
| 114 | } | ||
| 115 | #endif | ||
| 116 | |||
| 117 | static int fanotify_handle_event(struct fsnotify_group *group, | ||
| 118 | struct fsnotify_mark *inode_mark, | ||
| 119 | struct fsnotify_mark *fanotify_mark, | ||
| 120 | struct fsnotify_event *event) | ||
| 121 | { | ||
| 122 | int ret = 0; | ||
| 123 | struct fsnotify_event *notify_event = NULL; | ||
| 124 | |||
| 125 | BUILD_BUG_ON(FAN_ACCESS != FS_ACCESS); | ||
| 126 | BUILD_BUG_ON(FAN_MODIFY != FS_MODIFY); | ||
| 127 | BUILD_BUG_ON(FAN_CLOSE_NOWRITE != FS_CLOSE_NOWRITE); | ||
| 128 | BUILD_BUG_ON(FAN_CLOSE_WRITE != FS_CLOSE_WRITE); | ||
| 129 | BUILD_BUG_ON(FAN_OPEN != FS_OPEN); | ||
| 130 | BUILD_BUG_ON(FAN_EVENT_ON_CHILD != FS_EVENT_ON_CHILD); | ||
| 131 | BUILD_BUG_ON(FAN_Q_OVERFLOW != FS_Q_OVERFLOW); | ||
| 132 | BUILD_BUG_ON(FAN_OPEN_PERM != FS_OPEN_PERM); | ||
| 133 | BUILD_BUG_ON(FAN_ACCESS_PERM != FS_ACCESS_PERM); | ||
| 134 | |||
| 135 | pr_debug("%s: group=%p event=%p\n", __func__, group, event); | ||
| 136 | |||
| 137 | notify_event = fsnotify_add_notify_event(group, event, NULL, fanotify_merge); | ||
| 138 | if (IS_ERR(notify_event)) | ||
| 139 | return PTR_ERR(notify_event); | ||
| 140 | |||
| 141 | #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS | ||
| 142 | if (event->mask & FAN_ALL_PERM_EVENTS) { | ||
| 143 | /* if we merged we need to wait on the new event */ | ||
| 144 | if (notify_event) | ||
| 145 | event = notify_event; | ||
| 146 | ret = fanotify_get_response_from_access(group, event); | ||
| 147 | } | ||
| 148 | #endif | ||
| 149 | |||
| 150 | if (notify_event) | ||
| 151 | fsnotify_put_event(notify_event); | ||
| 152 | |||
| 153 | return ret; | ||
| 154 | } | ||
| 155 | |||
| 156 | static bool fanotify_should_send_event(struct fsnotify_group *group, | ||
| 157 | struct inode *to_tell, | ||
| 158 | struct fsnotify_mark *inode_mark, | ||
| 159 | struct fsnotify_mark *vfsmnt_mark, | ||
| 160 | __u32 event_mask, void *data, int data_type) | ||
| 161 | { | ||
| 162 | __u32 marks_mask, marks_ignored_mask; | ||
| 163 | |||
| 164 | pr_debug("%s: group=%p to_tell=%p inode_mark=%p vfsmnt_mark=%p " | ||
| 165 | "mask=%x data=%p data_type=%d\n", __func__, group, to_tell, | ||
| 166 | inode_mark, vfsmnt_mark, event_mask, data, data_type); | ||
| 167 | |||
| 168 | pr_debug("%s: group=%p vfsmount_mark=%p inode_mark=%p mask=%x\n", | ||
| 169 | __func__, group, vfsmnt_mark, inode_mark, event_mask); | ||
| 170 | |||
| 171 | /* sorry, fanotify only gives a damn about files and dirs */ | ||
| 172 | if (!S_ISREG(to_tell->i_mode) && | ||
| 173 | !S_ISDIR(to_tell->i_mode)) | ||
| 174 | return false; | ||
| 175 | |||
| 176 | /* if we don't have enough info to send an event to userspace say no */ | ||
| 177 | if (data_type != FSNOTIFY_EVENT_PATH) | ||
| 178 | return false; | ||
| 179 | |||
| 180 | if (inode_mark && vfsmnt_mark) { | ||
| 181 | marks_mask = (vfsmnt_mark->mask | inode_mark->mask); | ||
| 182 | marks_ignored_mask = (vfsmnt_mark->ignored_mask | inode_mark->ignored_mask); | ||
| 183 | } else if (inode_mark) { | ||
| 184 | /* | ||
| 185 | * if the event is for a child and this inode doesn't care about | ||
| 186 | * events on the child, don't send it! | ||
| 187 | */ | ||
| 188 | if ((event_mask & FS_EVENT_ON_CHILD) && | ||
| 189 | !(inode_mark->mask & FS_EVENT_ON_CHILD)) | ||
| 190 | return false; | ||
| 191 | marks_mask = inode_mark->mask; | ||
| 192 | marks_ignored_mask = inode_mark->ignored_mask; | ||
| 193 | } else if (vfsmnt_mark) { | ||
| 194 | marks_mask = vfsmnt_mark->mask; | ||
| 195 | marks_ignored_mask = vfsmnt_mark->ignored_mask; | ||
| 196 | } else { | ||
| 197 | BUG(); | ||
| 198 | } | ||
| 199 | |||
| 200 | if (event_mask & marks_mask & ~marks_ignored_mask) | ||
| 201 | return true; | ||
| 202 | |||
| 203 | return false; | ||
| 204 | } | ||
| 205 | |||
| 206 | const struct fsnotify_ops fanotify_fsnotify_ops = { | ||
| 207 | .handle_event = fanotify_handle_event, | ||
| 208 | .should_send_event = fanotify_should_send_event, | ||
| 209 | .free_group_priv = NULL, | ||
| 210 | .free_event_priv = NULL, | ||
| 211 | .freeing_mark = NULL, | ||
| 212 | }; | ||
diff --git a/fs/notify/fanotify/fanotify_user.c b/fs/notify/fanotify/fanotify_user.c new file mode 100644 index 000000000000..032b837fcd11 --- /dev/null +++ b/fs/notify/fanotify/fanotify_user.c | |||
| @@ -0,0 +1,760 @@ | |||
| 1 | #include <linux/fanotify.h> | ||
| 2 | #include <linux/fcntl.h> | ||
| 3 | #include <linux/file.h> | ||
| 4 | #include <linux/fs.h> | ||
| 5 | #include <linux/anon_inodes.h> | ||
| 6 | #include <linux/fsnotify_backend.h> | ||
| 7 | #include <linux/init.h> | ||
| 8 | #include <linux/mount.h> | ||
| 9 | #include <linux/namei.h> | ||
| 10 | #include <linux/poll.h> | ||
| 11 | #include <linux/security.h> | ||
| 12 | #include <linux/syscalls.h> | ||
| 13 | #include <linux/slab.h> | ||
| 14 | #include <linux/types.h> | ||
| 15 | #include <linux/uaccess.h> | ||
| 16 | |||
| 17 | #include <asm/ioctls.h> | ||
| 18 | |||
| 19 | extern const struct fsnotify_ops fanotify_fsnotify_ops; | ||
| 20 | |||
| 21 | static struct kmem_cache *fanotify_mark_cache __read_mostly; | ||
| 22 | static struct kmem_cache *fanotify_response_event_cache __read_mostly; | ||
| 23 | |||
| 24 | struct fanotify_response_event { | ||
| 25 | struct list_head list; | ||
| 26 | __s32 fd; | ||
| 27 | struct fsnotify_event *event; | ||
| 28 | }; | ||
| 29 | |||
| 30 | /* | ||
| 31 | * Get an fsnotify notification event if one exists and is small | ||
| 32 | * enough to fit in "count". Return an error pointer if the count | ||
| 33 | * is not large enough. | ||
| 34 | * | ||
| 35 | * Called with the group->notification_mutex held. | ||
| 36 | */ | ||
| 37 | static struct fsnotify_event *get_one_event(struct fsnotify_group *group, | ||
| 38 | size_t count) | ||
| 39 | { | ||
| 40 | BUG_ON(!mutex_is_locked(&group->notification_mutex)); | ||
| 41 | |||
| 42 | pr_debug("%s: group=%p count=%zd\n", __func__, group, count); | ||
| 43 | |||
| 44 | if (fsnotify_notify_queue_is_empty(group)) | ||
| 45 | return NULL; | ||
| 46 | |||
| 47 | if (FAN_EVENT_METADATA_LEN > count) | ||
| 48 | return ERR_PTR(-EINVAL); | ||
| 49 | |||
| 50 | /* held the notification_mutex the whole time, so this is the | ||
| 51 | * same event we peeked above */ | ||
| 52 | return fsnotify_remove_notify_event(group); | ||
| 53 | } | ||
| 54 | |||
| 55 | static int create_fd(struct fsnotify_group *group, struct fsnotify_event *event) | ||
| 56 | { | ||
| 57 | int client_fd; | ||
| 58 | struct dentry *dentry; | ||
| 59 | struct vfsmount *mnt; | ||
| 60 | struct file *new_file; | ||
| 61 | |||
| 62 | pr_debug("%s: group=%p event=%p\n", __func__, group, event); | ||
| 63 | |||
| 64 | client_fd = get_unused_fd(); | ||
| 65 | if (client_fd < 0) | ||
| 66 | return client_fd; | ||
| 67 | |||
| 68 | if (event->data_type != FSNOTIFY_EVENT_PATH) { | ||
| 69 | WARN_ON(1); | ||
| 70 | put_unused_fd(client_fd); | ||
| 71 | return -EINVAL; | ||
| 72 | } | ||
| 73 | |||
| 74 | /* | ||
| 75 | * we need a new file handle for the userspace program so it can read even if it was | ||
| 76 | * originally opened O_WRONLY. | ||
| 77 | */ | ||
| 78 | dentry = dget(event->path.dentry); | ||
| 79 | mnt = mntget(event->path.mnt); | ||
| 80 | /* it's possible this event was an overflow event. in that case dentry and mnt | ||
| 81 | * are NULL; That's fine, just don't call dentry open */ | ||
| 82 | if (dentry && mnt) | ||
| 83 | new_file = dentry_open(dentry, mnt, | ||
| 84 | group->fanotify_data.f_flags | FMODE_NONOTIFY, | ||
| 85 | current_cred()); | ||
| 86 | else | ||
| 87 | new_file = ERR_PTR(-EOVERFLOW); | ||
| 88 | if (IS_ERR(new_file)) { | ||
| 89 | /* | ||
| 90 | * we still send an event even if we can't open the file. this | ||
| 91 | * can happen when say tasks are gone and we try to open their | ||
| 92 | * /proc files or we try to open a WRONLY file like in sysfs | ||
| 93 | * we just send the errno to userspace since there isn't much | ||
| 94 | * else we can do. | ||
| 95 | */ | ||
| 96 | put_unused_fd(client_fd); | ||
| 97 | client_fd = PTR_ERR(new_file); | ||
| 98 | } else { | ||
| 99 | fd_install(client_fd, new_file); | ||
| 100 | } | ||
| 101 | |||
| 102 | return client_fd; | ||
| 103 | } | ||
| 104 | |||
| 105 | static ssize_t fill_event_metadata(struct fsnotify_group *group, | ||
| 106 | struct fanotify_event_metadata *metadata, | ||
| 107 | struct fsnotify_event *event) | ||
| 108 | { | ||
| 109 | pr_debug("%s: group=%p metadata=%p event=%p\n", __func__, | ||
| 110 | group, metadata, event); | ||
| 111 | |||
| 112 | metadata->event_len = FAN_EVENT_METADATA_LEN; | ||
| 113 | metadata->vers = FANOTIFY_METADATA_VERSION; | ||
| 114 | metadata->mask = event->mask & FAN_ALL_OUTGOING_EVENTS; | ||
| 115 | metadata->pid = pid_vnr(event->tgid); | ||
| 116 | metadata->fd = create_fd(group, event); | ||
| 117 | |||
| 118 | return metadata->fd; | ||
| 119 | } | ||
| 120 | |||
| 121 | #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS | ||
| 122 | static struct fanotify_response_event *dequeue_re(struct fsnotify_group *group, | ||
| 123 | __s32 fd) | ||
| 124 | { | ||
| 125 | struct fanotify_response_event *re, *return_re = NULL; | ||
| 126 | |||
| 127 | mutex_lock(&group->fanotify_data.access_mutex); | ||
| 128 | list_for_each_entry(re, &group->fanotify_data.access_list, list) { | ||
| 129 | if (re->fd != fd) | ||
| 130 | continue; | ||
| 131 | |||
| 132 | list_del_init(&re->list); | ||
| 133 | return_re = re; | ||
| 134 | break; | ||
| 135 | } | ||
| 136 | mutex_unlock(&group->fanotify_data.access_mutex); | ||
| 137 | |||
| 138 | pr_debug("%s: found return_re=%p\n", __func__, return_re); | ||
| 139 | |||
| 140 | return return_re; | ||
| 141 | } | ||
| 142 | |||
| 143 | static int process_access_response(struct fsnotify_group *group, | ||
| 144 | struct fanotify_response *response_struct) | ||
| 145 | { | ||
| 146 | struct fanotify_response_event *re; | ||
| 147 | __s32 fd = response_struct->fd; | ||
| 148 | __u32 response = response_struct->response; | ||
| 149 | |||
| 150 | pr_debug("%s: group=%p fd=%d response=%d\n", __func__, group, | ||
| 151 | fd, response); | ||
| 152 | /* | ||
| 153 | * make sure the response is valid, if invalid we do nothing and either | ||
| 154 | * userspace can send a valid responce or we will clean it up after the | ||
| 155 | * timeout | ||
| 156 | */ | ||
| 157 | switch (response) { | ||
| 158 | case FAN_ALLOW: | ||
| 159 | case FAN_DENY: | ||
| 160 | break; | ||
| 161 | default: | ||
| 162 | return -EINVAL; | ||
| 163 | } | ||
| 164 | |||
| 165 | if (fd < 0) | ||
| 166 | return -EINVAL; | ||
| 167 | |||
| 168 | re = dequeue_re(group, fd); | ||
| 169 | if (!re) | ||
| 170 | return -ENOENT; | ||
| 171 | |||
| 172 | re->event->response = response; | ||
| 173 | |||
| 174 | wake_up(&group->fanotify_data.access_waitq); | ||
| 175 | |||
| 176 | kmem_cache_free(fanotify_response_event_cache, re); | ||
| 177 | |||
| 178 | return 0; | ||
| 179 | } | ||
| 180 | |||
| 181 | static int prepare_for_access_response(struct fsnotify_group *group, | ||
| 182 | struct fsnotify_event *event, | ||
| 183 | __s32 fd) | ||
| 184 | { | ||
| 185 | struct fanotify_response_event *re; | ||
| 186 | |||
| 187 | if (!(event->mask & FAN_ALL_PERM_EVENTS)) | ||
| 188 | return 0; | ||
| 189 | |||
| 190 | re = kmem_cache_alloc(fanotify_response_event_cache, GFP_KERNEL); | ||
| 191 | if (!re) | ||
| 192 | return -ENOMEM; | ||
| 193 | |||
| 194 | re->event = event; | ||
| 195 | re->fd = fd; | ||
| 196 | |||
| 197 | mutex_lock(&group->fanotify_data.access_mutex); | ||
| 198 | list_add_tail(&re->list, &group->fanotify_data.access_list); | ||
| 199 | mutex_unlock(&group->fanotify_data.access_mutex); | ||
| 200 | |||
| 201 | return 0; | ||
| 202 | } | ||
| 203 | |||
| 204 | static void remove_access_response(struct fsnotify_group *group, | ||
| 205 | struct fsnotify_event *event, | ||
| 206 | __s32 fd) | ||
| 207 | { | ||
| 208 | struct fanotify_response_event *re; | ||
| 209 | |||
| 210 | if (!(event->mask & FAN_ALL_PERM_EVENTS)) | ||
| 211 | return; | ||
| 212 | |||
| 213 | re = dequeue_re(group, fd); | ||
| 214 | if (!re) | ||
| 215 | return; | ||
| 216 | |||
| 217 | BUG_ON(re->event != event); | ||
| 218 | |||
| 219 | kmem_cache_free(fanotify_response_event_cache, re); | ||
| 220 | |||
| 221 | return; | ||
| 222 | } | ||
| 223 | #else | ||
| 224 | static int prepare_for_access_response(struct fsnotify_group *group, | ||
| 225 | struct fsnotify_event *event, | ||
| 226 | __s32 fd) | ||
| 227 | { | ||
| 228 | return 0; | ||
| 229 | } | ||
| 230 | |||
| 231 | static void remove_access_response(struct fsnotify_group *group, | ||
| 232 | struct fsnotify_event *event, | ||
| 233 | __s32 fd) | ||
| 234 | { | ||
| 235 | return; | ||
| 236 | } | ||
| 237 | #endif | ||
| 238 | |||
| 239 | static ssize_t copy_event_to_user(struct fsnotify_group *group, | ||
| 240 | struct fsnotify_event *event, | ||
| 241 | char __user *buf) | ||
| 242 | { | ||
| 243 | struct fanotify_event_metadata fanotify_event_metadata; | ||
| 244 | int fd, ret; | ||
| 245 | |||
| 246 | pr_debug("%s: group=%p event=%p\n", __func__, group, event); | ||
| 247 | |||
| 248 | fd = fill_event_metadata(group, &fanotify_event_metadata, event); | ||
| 249 | if (fd < 0) | ||
| 250 | return fd; | ||
| 251 | |||
| 252 | ret = prepare_for_access_response(group, event, fd); | ||
| 253 | if (ret) | ||
| 254 | goto out_close_fd; | ||
| 255 | |||
| 256 | ret = -EFAULT; | ||
| 257 | if (copy_to_user(buf, &fanotify_event_metadata, FAN_EVENT_METADATA_LEN)) | ||
| 258 | goto out_kill_access_response; | ||
| 259 | |||
| 260 | return FAN_EVENT_METADATA_LEN; | ||
| 261 | |||
| 262 | out_kill_access_response: | ||
| 263 | remove_access_response(group, event, fd); | ||
| 264 | out_close_fd: | ||
| 265 | sys_close(fd); | ||
| 266 | return ret; | ||
| 267 | } | ||
| 268 | |||
| 269 | /* intofiy userspace file descriptor functions */ | ||
| 270 | static unsigned int fanotify_poll(struct file *file, poll_table *wait) | ||
| 271 | { | ||
| 272 | struct fsnotify_group *group = file->private_data; | ||
| 273 | int ret = 0; | ||
| 274 | |||
| 275 | poll_wait(file, &group->notification_waitq, wait); | ||
| 276 | mutex_lock(&group->notification_mutex); | ||
| 277 | if (!fsnotify_notify_queue_is_empty(group)) | ||
| 278 | ret = POLLIN | POLLRDNORM; | ||
| 279 | mutex_unlock(&group->notification_mutex); | ||
| 280 | |||
| 281 | return ret; | ||
| 282 | } | ||
| 283 | |||
| 284 | static ssize_t fanotify_read(struct file *file, char __user *buf, | ||
| 285 | size_t count, loff_t *pos) | ||
| 286 | { | ||
| 287 | struct fsnotify_group *group; | ||
| 288 | struct fsnotify_event *kevent; | ||
| 289 | char __user *start; | ||
| 290 | int ret; | ||
| 291 | DEFINE_WAIT(wait); | ||
| 292 | |||
| 293 | start = buf; | ||
| 294 | group = file->private_data; | ||
| 295 | |||
| 296 | pr_debug("%s: group=%p\n", __func__, group); | ||
| 297 | |||
| 298 | while (1) { | ||
| 299 | prepare_to_wait(&group->notification_waitq, &wait, TASK_INTERRUPTIBLE); | ||
| 300 | |||
| 301 | mutex_lock(&group->notification_mutex); | ||
| 302 | kevent = get_one_event(group, count); | ||
| 303 | mutex_unlock(&group->notification_mutex); | ||
| 304 | |||
| 305 | if (kevent) { | ||
| 306 | ret = PTR_ERR(kevent); | ||
| 307 | if (IS_ERR(kevent)) | ||
| 308 | break; | ||
| 309 | ret = copy_event_to_user(group, kevent, buf); | ||
| 310 | fsnotify_put_event(kevent); | ||
| 311 | if (ret < 0) | ||
| 312 | break; | ||
| 313 | buf += ret; | ||
| 314 | count -= ret; | ||
| 315 | continue; | ||
| 316 | } | ||
| 317 | |||
| 318 | ret = -EAGAIN; | ||
| 319 | if (file->f_flags & O_NONBLOCK) | ||
| 320 | break; | ||
| 321 | ret = -EINTR; | ||
| 322 | if (signal_pending(current)) | ||
| 323 | break; | ||
| 324 | |||
| 325 | if (start != buf) | ||
| 326 | break; | ||
| 327 | |||
| 328 | schedule(); | ||
| 329 | } | ||
| 330 | |||
| 331 | finish_wait(&group->notification_waitq, &wait); | ||
| 332 | if (start != buf && ret != -EFAULT) | ||
| 333 | ret = buf - start; | ||
| 334 | return ret; | ||
| 335 | } | ||
| 336 | |||
| 337 | static ssize_t fanotify_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) | ||
| 338 | { | ||
| 339 | #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS | ||
| 340 | struct fanotify_response response = { .fd = -1, .response = -1 }; | ||
| 341 | struct fsnotify_group *group; | ||
| 342 | int ret; | ||
| 343 | |||
| 344 | group = file->private_data; | ||
| 345 | |||
| 346 | if (count > sizeof(response)) | ||
| 347 | count = sizeof(response); | ||
| 348 | |||
| 349 | pr_debug("%s: group=%p count=%zu\n", __func__, group, count); | ||
| 350 | |||
| 351 | if (copy_from_user(&response, buf, count)) | ||
| 352 | return -EFAULT; | ||
| 353 | |||
| 354 | ret = process_access_response(group, &response); | ||
| 355 | if (ret < 0) | ||
| 356 | count = ret; | ||
| 357 | |||
| 358 | return count; | ||
| 359 | #else | ||
| 360 | return -EINVAL; | ||
| 361 | #endif | ||
| 362 | } | ||
| 363 | |||
| 364 | static int fanotify_release(struct inode *ignored, struct file *file) | ||
| 365 | { | ||
| 366 | struct fsnotify_group *group = file->private_data; | ||
| 367 | |||
| 368 | pr_debug("%s: file=%p group=%p\n", __func__, file, group); | ||
| 369 | |||
| 370 | /* matches the fanotify_init->fsnotify_alloc_group */ | ||
| 371 | fsnotify_put_group(group); | ||
| 372 | |||
| 373 | return 0; | ||
| 374 | } | ||
| 375 | |||
| 376 | static long fanotify_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
| 377 | { | ||
| 378 | struct fsnotify_group *group; | ||
| 379 | struct fsnotify_event_holder *holder; | ||
| 380 | void __user *p; | ||
| 381 | int ret = -ENOTTY; | ||
| 382 | size_t send_len = 0; | ||
| 383 | |||
| 384 | group = file->private_data; | ||
| 385 | |||
| 386 | p = (void __user *) arg; | ||
| 387 | |||
| 388 | switch (cmd) { | ||
| 389 | case FIONREAD: | ||
| 390 | mutex_lock(&group->notification_mutex); | ||
| 391 | list_for_each_entry(holder, &group->notification_list, event_list) | ||
| 392 | send_len += FAN_EVENT_METADATA_LEN; | ||
| 393 | mutex_unlock(&group->notification_mutex); | ||
| 394 | ret = put_user(send_len, (int __user *) p); | ||
| 395 | break; | ||
| 396 | } | ||
| 397 | |||
| 398 | return ret; | ||
| 399 | } | ||
| 400 | |||
| 401 | static const struct file_operations fanotify_fops = { | ||
| 402 | .poll = fanotify_poll, | ||
| 403 | .read = fanotify_read, | ||
| 404 | .write = fanotify_write, | ||
| 405 | .fasync = NULL, | ||
| 406 | .release = fanotify_release, | ||
| 407 | .unlocked_ioctl = fanotify_ioctl, | ||
| 408 | .compat_ioctl = fanotify_ioctl, | ||
| 409 | }; | ||
| 410 | |||
| 411 | static void fanotify_free_mark(struct fsnotify_mark *fsn_mark) | ||
| 412 | { | ||
| 413 | kmem_cache_free(fanotify_mark_cache, fsn_mark); | ||
| 414 | } | ||
| 415 | |||
| 416 | static int fanotify_find_path(int dfd, const char __user *filename, | ||
| 417 | struct path *path, unsigned int flags) | ||
| 418 | { | ||
| 419 | int ret; | ||
| 420 | |||
| 421 | pr_debug("%s: dfd=%d filename=%p flags=%x\n", __func__, | ||
| 422 | dfd, filename, flags); | ||
| 423 | |||
| 424 | if (filename == NULL) { | ||
| 425 | struct file *file; | ||
| 426 | int fput_needed; | ||
| 427 | |||
| 428 | ret = -EBADF; | ||
| 429 | file = fget_light(dfd, &fput_needed); | ||
| 430 | if (!file) | ||
| 431 | goto out; | ||
| 432 | |||
| 433 | ret = -ENOTDIR; | ||
| 434 | if ((flags & FAN_MARK_ONLYDIR) && | ||
| 435 | !(S_ISDIR(file->f_path.dentry->d_inode->i_mode))) { | ||
| 436 | fput_light(file, fput_needed); | ||
| 437 | goto out; | ||
| 438 | } | ||
| 439 | |||
| 440 | *path = file->f_path; | ||
| 441 | path_get(path); | ||
| 442 | fput_light(file, fput_needed); | ||
| 443 | } else { | ||
| 444 | unsigned int lookup_flags = 0; | ||
| 445 | |||
| 446 | if (!(flags & FAN_MARK_DONT_FOLLOW)) | ||
| 447 | lookup_flags |= LOOKUP_FOLLOW; | ||
| 448 | if (flags & FAN_MARK_ONLYDIR) | ||
| 449 | lookup_flags |= LOOKUP_DIRECTORY; | ||
| 450 | |||
| 451 | ret = user_path_at(dfd, filename, lookup_flags, path); | ||
| 452 | if (ret) | ||
| 453 | goto out; | ||
| 454 | } | ||
| 455 | |||
| 456 | /* you can only watch an inode if you have read permissions on it */ | ||
| 457 | ret = inode_permission(path->dentry->d_inode, MAY_READ); | ||
| 458 | if (ret) | ||
| 459 | path_put(path); | ||
| 460 | out: | ||
| 461 | return ret; | ||
| 462 | } | ||
| 463 | |||
| 464 | static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark, | ||
| 465 | __u32 mask, | ||
| 466 | unsigned int flags) | ||
| 467 | { | ||
| 468 | __u32 oldmask; | ||
| 469 | |||
| 470 | spin_lock(&fsn_mark->lock); | ||
| 471 | if (!(flags & FAN_MARK_IGNORED_MASK)) { | ||
| 472 | oldmask = fsn_mark->mask; | ||
| 473 | fsnotify_set_mark_mask_locked(fsn_mark, (oldmask & ~mask)); | ||
| 474 | } else { | ||
| 475 | oldmask = fsn_mark->ignored_mask; | ||
| 476 | fsnotify_set_mark_ignored_mask_locked(fsn_mark, (oldmask & ~mask)); | ||
| 477 | } | ||
| 478 | spin_unlock(&fsn_mark->lock); | ||
| 479 | |||
| 480 | if (!(oldmask & ~mask)) | ||
| 481 | fsnotify_destroy_mark(fsn_mark); | ||
| 482 | |||
| 483 | return mask & oldmask; | ||
| 484 | } | ||
| 485 | |||
| 486 | static int fanotify_remove_vfsmount_mark(struct fsnotify_group *group, | ||
| 487 | struct vfsmount *mnt, __u32 mask, | ||
| 488 | unsigned int flags) | ||
| 489 | { | ||
| 490 | struct fsnotify_mark *fsn_mark = NULL; | ||
| 491 | __u32 removed; | ||
| 492 | |||
| 493 | fsn_mark = fsnotify_find_vfsmount_mark(group, mnt); | ||
| 494 | if (!fsn_mark) | ||
| 495 | return -ENOENT; | ||
| 496 | |||
| 497 | removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags); | ||
| 498 | fsnotify_put_mark(fsn_mark); | ||
| 499 | if (removed & mnt->mnt_fsnotify_mask) | ||
| 500 | fsnotify_recalc_vfsmount_mask(mnt); | ||
| 501 | |||
| 502 | return 0; | ||
| 503 | } | ||
| 504 | |||
| 505 | static int fanotify_remove_inode_mark(struct fsnotify_group *group, | ||
| 506 | struct inode *inode, __u32 mask, | ||
| 507 | unsigned int flags) | ||
| 508 | { | ||
| 509 | struct fsnotify_mark *fsn_mark = NULL; | ||
| 510 | __u32 removed; | ||
| 511 | |||
| 512 | fsn_mark = fsnotify_find_inode_mark(group, inode); | ||
| 513 | if (!fsn_mark) | ||
| 514 | return -ENOENT; | ||
| 515 | |||
| 516 | removed = fanotify_mark_remove_from_mask(fsn_mark, mask, flags); | ||
| 517 | /* matches the fsnotify_find_inode_mark() */ | ||
| 518 | fsnotify_put_mark(fsn_mark); | ||
| 519 | if (removed & inode->i_fsnotify_mask) | ||
| 520 | fsnotify_recalc_inode_mask(inode); | ||
| 521 | |||
| 522 | return 0; | ||
| 523 | } | ||
| 524 | |||
| 525 | static __u32 fanotify_mark_add_to_mask(struct fsnotify_mark *fsn_mark, | ||
| 526 | __u32 mask, | ||
| 527 | unsigned int flags) | ||
| 528 | { | ||
| 529 | __u32 oldmask; | ||
| 530 | |||
| 531 | spin_lock(&fsn_mark->lock); | ||
| 532 | if (!(flags & FAN_MARK_IGNORED_MASK)) { | ||
| 533 | oldmask = fsn_mark->mask; | ||
| 534 | fsnotify_set_mark_mask_locked(fsn_mark, (oldmask | mask)); | ||
| 535 | } else { | ||
| 536 | oldmask = fsn_mark->ignored_mask; | ||
| 537 | fsnotify_set_mark_ignored_mask_locked(fsn_mark, (oldmask | mask)); | ||
| 538 | if (flags & FAN_MARK_IGNORED_SURV_MODIFY) | ||
| 539 | fsn_mark->flags |= FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY; | ||
| 540 | } | ||
| 541 | spin_unlock(&fsn_mark->lock); | ||
| 542 | |||
| 543 | return mask & ~oldmask; | ||
| 544 | } | ||
| 545 | |||
| 546 | static int fanotify_add_vfsmount_mark(struct fsnotify_group *group, | ||
| 547 | struct vfsmount *mnt, __u32 mask, | ||
| 548 | unsigned int flags) | ||
| 549 | { | ||
| 550 | struct fsnotify_mark *fsn_mark; | ||
| 551 | __u32 added; | ||
| 552 | |||
| 553 | fsn_mark = fsnotify_find_vfsmount_mark(group, mnt); | ||
| 554 | if (!fsn_mark) { | ||
| 555 | int ret; | ||
| 556 | |||
| 557 | fsn_mark = kmem_cache_alloc(fanotify_mark_cache, GFP_KERNEL); | ||
| 558 | if (!fsn_mark) | ||
| 559 | return -ENOMEM; | ||
| 560 | |||
| 561 | fsnotify_init_mark(fsn_mark, fanotify_free_mark); | ||
| 562 | ret = fsnotify_add_mark(fsn_mark, group, NULL, mnt, 0); | ||
| 563 | if (ret) { | ||
| 564 | fanotify_free_mark(fsn_mark); | ||
| 565 | return ret; | ||
| 566 | } | ||
| 567 | } | ||
| 568 | added = fanotify_mark_add_to_mask(fsn_mark, mask, flags); | ||
| 569 | fsnotify_put_mark(fsn_mark); | ||
| 570 | if (added & ~mnt->mnt_fsnotify_mask) | ||
| 571 | fsnotify_recalc_vfsmount_mask(mnt); | ||
| 572 | |||
| 573 | return 0; | ||
| 574 | } | ||
| 575 | |||
| 576 | static int fanotify_add_inode_mark(struct fsnotify_group *group, | ||
| 577 | struct inode *inode, __u32 mask, | ||
| 578 | unsigned int flags) | ||
| 579 | { | ||
| 580 | struct fsnotify_mark *fsn_mark; | ||
| 581 | __u32 added; | ||
| 582 | |||
| 583 | pr_debug("%s: group=%p inode=%p\n", __func__, group, inode); | ||
| 584 | |||
| 585 | fsn_mark = fsnotify_find_inode_mark(group, inode); | ||
| 586 | if (!fsn_mark) { | ||
| 587 | int ret; | ||
| 588 | |||
| 589 | fsn_mark = kmem_cache_alloc(fanotify_mark_cache, GFP_KERNEL); | ||
| 590 | if (!fsn_mark) | ||
| 591 | return -ENOMEM; | ||
| 592 | |||
| 593 | fsnotify_init_mark(fsn_mark, fanotify_free_mark); | ||
| 594 | ret = fsnotify_add_mark(fsn_mark, group, inode, NULL, 0); | ||
| 595 | if (ret) { | ||
| 596 | fanotify_free_mark(fsn_mark); | ||
| 597 | return ret; | ||
| 598 | } | ||
| 599 | } | ||
| 600 | added = fanotify_mark_add_to_mask(fsn_mark, mask, flags); | ||
| 601 | fsnotify_put_mark(fsn_mark); | ||
| 602 | if (added & ~inode->i_fsnotify_mask) | ||
| 603 | fsnotify_recalc_inode_mask(inode); | ||
| 604 | return 0; | ||
| 605 | } | ||
| 606 | |||
| 607 | /* fanotify syscalls */ | ||
| 608 | SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) | ||
| 609 | { | ||
| 610 | struct fsnotify_group *group; | ||
| 611 | int f_flags, fd; | ||
| 612 | |||
| 613 | pr_debug("%s: flags=%d event_f_flags=%d\n", | ||
| 614 | __func__, flags, event_f_flags); | ||
| 615 | |||
| 616 | if (!capable(CAP_SYS_ADMIN)) | ||
| 617 | return -EACCES; | ||
| 618 | |||
| 619 | if (flags & ~FAN_ALL_INIT_FLAGS) | ||
| 620 | return -EINVAL; | ||
| 621 | |||
| 622 | f_flags = O_RDWR | FMODE_NONOTIFY; | ||
| 623 | if (flags & FAN_CLOEXEC) | ||
| 624 | f_flags |= O_CLOEXEC; | ||
| 625 | if (flags & FAN_NONBLOCK) | ||
| 626 | f_flags |= O_NONBLOCK; | ||
| 627 | |||
| 628 | /* fsnotify_alloc_group takes a ref. Dropped in fanotify_release */ | ||
| 629 | group = fsnotify_alloc_group(&fanotify_fsnotify_ops); | ||
| 630 | if (IS_ERR(group)) | ||
| 631 | return PTR_ERR(group); | ||
| 632 | |||
| 633 | group->fanotify_data.f_flags = event_f_flags; | ||
| 634 | #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS | ||
| 635 | mutex_init(&group->fanotify_data.access_mutex); | ||
| 636 | init_waitqueue_head(&group->fanotify_data.access_waitq); | ||
| 637 | INIT_LIST_HEAD(&group->fanotify_data.access_list); | ||
| 638 | #endif | ||
| 639 | |||
| 640 | fd = anon_inode_getfd("[fanotify]", &fanotify_fops, group, f_flags); | ||
| 641 | if (fd < 0) | ||
| 642 | goto out_put_group; | ||
| 643 | |||
| 644 | return fd; | ||
| 645 | |||
| 646 | out_put_group: | ||
| 647 | fsnotify_put_group(group); | ||
| 648 | return fd; | ||
| 649 | } | ||
| 650 | |||
| 651 | SYSCALL_DEFINE(fanotify_mark)(int fanotify_fd, unsigned int flags, | ||
| 652 | __u64 mask, int dfd, | ||
| 653 | const char __user * pathname) | ||
| 654 | { | ||
| 655 | struct inode *inode = NULL; | ||
| 656 | struct vfsmount *mnt = NULL; | ||
| 657 | struct fsnotify_group *group; | ||
| 658 | struct file *filp; | ||
| 659 | struct path path; | ||
| 660 | int ret, fput_needed; | ||
| 661 | |||
| 662 | pr_debug("%s: fanotify_fd=%d flags=%x dfd=%d pathname=%p mask=%llx\n", | ||
| 663 | __func__, fanotify_fd, flags, dfd, pathname, mask); | ||
| 664 | |||
| 665 | /* we only use the lower 32 bits as of right now. */ | ||
| 666 | if (mask & ((__u64)0xffffffff << 32)) | ||
| 667 | return -EINVAL; | ||
| 668 | |||
| 669 | if (flags & ~FAN_ALL_MARK_FLAGS) | ||
| 670 | return -EINVAL; | ||
| 671 | switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE | FAN_MARK_FLUSH)) { | ||
| 672 | case FAN_MARK_ADD: | ||
| 673 | case FAN_MARK_REMOVE: | ||
| 674 | case FAN_MARK_FLUSH: | ||
| 675 | break; | ||
| 676 | default: | ||
| 677 | return -EINVAL; | ||
| 678 | } | ||
| 679 | #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS | ||
| 680 | if (mask & ~(FAN_ALL_EVENTS | FAN_ALL_PERM_EVENTS | FAN_EVENT_ON_CHILD)) | ||
| 681 | #else | ||
| 682 | if (mask & ~(FAN_ALL_EVENTS | FAN_EVENT_ON_CHILD)) | ||
| 683 | #endif | ||
| 684 | return -EINVAL; | ||
| 685 | |||
| 686 | filp = fget_light(fanotify_fd, &fput_needed); | ||
| 687 | if (unlikely(!filp)) | ||
| 688 | return -EBADF; | ||
| 689 | |||
| 690 | /* verify that this is indeed an fanotify instance */ | ||
| 691 | ret = -EINVAL; | ||
| 692 | if (unlikely(filp->f_op != &fanotify_fops)) | ||
| 693 | goto fput_and_out; | ||
| 694 | |||
| 695 | ret = fanotify_find_path(dfd, pathname, &path, flags); | ||
| 696 | if (ret) | ||
| 697 | goto fput_and_out; | ||
| 698 | |||
| 699 | /* inode held in place by reference to path; group by fget on fd */ | ||
| 700 | if (!(flags & FAN_MARK_MOUNT)) | ||
| 701 | inode = path.dentry->d_inode; | ||
| 702 | else | ||
| 703 | mnt = path.mnt; | ||
| 704 | group = filp->private_data; | ||
| 705 | |||
| 706 | /* create/update an inode mark */ | ||
| 707 | switch (flags & (FAN_MARK_ADD | FAN_MARK_REMOVE | FAN_MARK_FLUSH)) { | ||
| 708 | case FAN_MARK_ADD: | ||
| 709 | if (flags & FAN_MARK_MOUNT) | ||
| 710 | ret = fanotify_add_vfsmount_mark(group, mnt, mask, flags); | ||
| 711 | else | ||
| 712 | ret = fanotify_add_inode_mark(group, inode, mask, flags); | ||
| 713 | break; | ||
| 714 | case FAN_MARK_REMOVE: | ||
| 715 | if (flags & FAN_MARK_MOUNT) | ||
| 716 | ret = fanotify_remove_vfsmount_mark(group, mnt, mask, flags); | ||
| 717 | else | ||
| 718 | ret = fanotify_remove_inode_mark(group, inode, mask, flags); | ||
| 719 | break; | ||
| 720 | case FAN_MARK_FLUSH: | ||
| 721 | if (flags & FAN_MARK_MOUNT) | ||
| 722 | fsnotify_clear_vfsmount_marks_by_group(group); | ||
| 723 | else | ||
| 724 | fsnotify_clear_inode_marks_by_group(group); | ||
| 725 | break; | ||
| 726 | default: | ||
| 727 | ret = -EINVAL; | ||
| 728 | } | ||
| 729 | |||
| 730 | path_put(&path); | ||
| 731 | fput_and_out: | ||
| 732 | fput_light(filp, fput_needed); | ||
| 733 | return ret; | ||
| 734 | } | ||
| 735 | |||
| 736 | #ifdef CONFIG_HAVE_SYSCALL_WRAPPERS | ||
| 737 | asmlinkage long SyS_fanotify_mark(long fanotify_fd, long flags, __u64 mask, | ||
| 738 | long dfd, long pathname) | ||
| 739 | { | ||
| 740 | return SYSC_fanotify_mark((int) fanotify_fd, (unsigned int) flags, | ||
| 741 | mask, (int) dfd, | ||
| 742 | (const char __user *) pathname); | ||
| 743 | } | ||
| 744 | SYSCALL_ALIAS(sys_fanotify_mark, SyS_fanotify_mark); | ||
| 745 | #endif | ||
| 746 | |||
| 747 | /* | ||
| 748 | * fanotify_user_setup - Our initialization function. Note that we cannnot return | ||
| 749 | * error because we have compiled-in VFS hooks. So an (unlikely) failure here | ||
| 750 | * must result in panic(). | ||
| 751 | */ | ||
| 752 | static int __init fanotify_user_setup(void) | ||
| 753 | { | ||
| 754 | fanotify_mark_cache = KMEM_CACHE(fsnotify_mark, SLAB_PANIC); | ||
| 755 | fanotify_response_event_cache = KMEM_CACHE(fanotify_response_event, | ||
| 756 | SLAB_PANIC); | ||
| 757 | |||
| 758 | return 0; | ||
| 759 | } | ||
| 760 | device_initcall(fanotify_user_setup); | ||
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c index fcc2f064af83..3970392b2722 100644 --- a/fs/notify/fsnotify.c +++ b/fs/notify/fsnotify.c | |||
| @@ -21,6 +21,7 @@ | |||
| 21 | #include <linux/gfp.h> | 21 | #include <linux/gfp.h> |
| 22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
| 23 | #include <linux/module.h> | 23 | #include <linux/module.h> |
| 24 | #include <linux/mount.h> | ||
| 24 | #include <linux/srcu.h> | 25 | #include <linux/srcu.h> |
| 25 | 26 | ||
| 26 | #include <linux/fsnotify_backend.h> | 27 | #include <linux/fsnotify_backend.h> |
| @@ -35,6 +36,11 @@ void __fsnotify_inode_delete(struct inode *inode) | |||
| 35 | } | 36 | } |
| 36 | EXPORT_SYMBOL_GPL(__fsnotify_inode_delete); | 37 | EXPORT_SYMBOL_GPL(__fsnotify_inode_delete); |
| 37 | 38 | ||
| 39 | void __fsnotify_vfsmount_delete(struct vfsmount *mnt) | ||
| 40 | { | ||
| 41 | fsnotify_clear_marks_by_mount(mnt); | ||
| 42 | } | ||
| 43 | |||
| 38 | /* | 44 | /* |
| 39 | * Given an inode, first check if we care what happens to our children. Inotify | 45 | * Given an inode, first check if we care what happens to our children. Inotify |
| 40 | * and dnotify both tell their parents about events. If we care about any event | 46 | * and dnotify both tell their parents about events. If we care about any event |
| @@ -78,13 +84,16 @@ void __fsnotify_update_child_dentry_flags(struct inode *inode) | |||
| 78 | } | 84 | } |
| 79 | 85 | ||
| 80 | /* Notify this dentry's parent about a child's events. */ | 86 | /* Notify this dentry's parent about a child's events. */ |
| 81 | void __fsnotify_parent(struct dentry *dentry, __u32 mask) | 87 | void __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask) |
| 82 | { | 88 | { |
| 83 | struct dentry *parent; | 89 | struct dentry *parent; |
| 84 | struct inode *p_inode; | 90 | struct inode *p_inode; |
| 85 | bool send = false; | 91 | bool send = false; |
| 86 | bool should_update_children = false; | 92 | bool should_update_children = false; |
| 87 | 93 | ||
| 94 | if (!dentry) | ||
| 95 | dentry = path->dentry; | ||
| 96 | |||
| 88 | if (!(dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED)) | 97 | if (!(dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED)) |
| 89 | return; | 98 | return; |
| 90 | 99 | ||
| @@ -115,8 +124,12 @@ void __fsnotify_parent(struct dentry *dentry, __u32 mask) | |||
| 115 | * specifies these are events which came from a child. */ | 124 | * specifies these are events which came from a child. */ |
| 116 | mask |= FS_EVENT_ON_CHILD; | 125 | mask |= FS_EVENT_ON_CHILD; |
| 117 | 126 | ||
| 118 | fsnotify(p_inode, mask, dentry->d_inode, FSNOTIFY_EVENT_INODE, | 127 | if (path) |
| 119 | dentry->d_name.name, 0); | 128 | fsnotify(p_inode, mask, path, FSNOTIFY_EVENT_PATH, |
| 129 | dentry->d_name.name, 0); | ||
| 130 | else | ||
| 131 | fsnotify(p_inode, mask, dentry->d_inode, FSNOTIFY_EVENT_INODE, | ||
| 132 | dentry->d_name.name, 0); | ||
| 120 | dput(parent); | 133 | dput(parent); |
| 121 | } | 134 | } |
| 122 | 135 | ||
| @@ -127,63 +140,181 @@ void __fsnotify_parent(struct dentry *dentry, __u32 mask) | |||
| 127 | } | 140 | } |
| 128 | EXPORT_SYMBOL_GPL(__fsnotify_parent); | 141 | EXPORT_SYMBOL_GPL(__fsnotify_parent); |
| 129 | 142 | ||
| 143 | static int send_to_group(struct inode *to_tell, struct vfsmount *mnt, | ||
| 144 | struct fsnotify_mark *inode_mark, | ||
| 145 | struct fsnotify_mark *vfsmount_mark, | ||
| 146 | __u32 mask, void *data, | ||
| 147 | int data_is, u32 cookie, | ||
| 148 | const unsigned char *file_name, | ||
| 149 | struct fsnotify_event **event) | ||
| 150 | { | ||
| 151 | struct fsnotify_group *group = inode_mark->group; | ||
| 152 | __u32 inode_test_mask = (mask & ~FS_EVENT_ON_CHILD); | ||
| 153 | __u32 vfsmount_test_mask = (mask & ~FS_EVENT_ON_CHILD); | ||
| 154 | |||
| 155 | pr_debug("%s: group=%p to_tell=%p mnt=%p mark=%p mask=%x data=%p" | ||
| 156 | " data_is=%d cookie=%d event=%p\n", __func__, group, to_tell, | ||
| 157 | mnt, inode_mark, mask, data, data_is, cookie, *event); | ||
| 158 | |||
| 159 | /* clear ignored on inode modification */ | ||
| 160 | if (mask & FS_MODIFY) { | ||
| 161 | if (inode_mark && | ||
| 162 | !(inode_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) | ||
| 163 | inode_mark->ignored_mask = 0; | ||
| 164 | if (vfsmount_mark && | ||
| 165 | !(vfsmount_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) | ||
| 166 | vfsmount_mark->ignored_mask = 0; | ||
| 167 | } | ||
| 168 | |||
| 169 | /* does the inode mark tell us to do something? */ | ||
| 170 | if (inode_mark) { | ||
| 171 | inode_test_mask &= inode_mark->mask; | ||
| 172 | inode_test_mask &= ~inode_mark->ignored_mask; | ||
| 173 | } | ||
| 174 | |||
| 175 | /* does the vfsmount_mark tell us to do something? */ | ||
| 176 | if (vfsmount_mark) { | ||
| 177 | vfsmount_test_mask &= vfsmount_mark->mask; | ||
| 178 | vfsmount_test_mask &= ~vfsmount_mark->ignored_mask; | ||
| 179 | if (inode_mark) | ||
| 180 | vfsmount_test_mask &= ~inode_mark->ignored_mask; | ||
| 181 | } | ||
| 182 | |||
| 183 | if (!inode_test_mask && !vfsmount_test_mask) | ||
| 184 | return 0; | ||
| 185 | |||
| 186 | if (group->ops->should_send_event(group, to_tell, inode_mark, | ||
| 187 | vfsmount_mark, mask, data, | ||
| 188 | data_is) == false) | ||
| 189 | return 0; | ||
| 190 | |||
| 191 | if (!*event) { | ||
| 192 | *event = fsnotify_create_event(to_tell, mask, data, | ||
| 193 | data_is, file_name, | ||
| 194 | cookie, GFP_KERNEL); | ||
| 195 | if (!*event) | ||
| 196 | return -ENOMEM; | ||
| 197 | } | ||
| 198 | return group->ops->handle_event(group, inode_mark, vfsmount_mark, *event); | ||
| 199 | } | ||
| 200 | |||
| 130 | /* | 201 | /* |
| 131 | * This is the main call to fsnotify. The VFS calls into hook specific functions | 202 | * This is the main call to fsnotify. The VFS calls into hook specific functions |
| 132 | * in linux/fsnotify.h. Those functions then in turn call here. Here will call | 203 | * in linux/fsnotify.h. Those functions then in turn call here. Here will call |
| 133 | * out to all of the registered fsnotify_group. Those groups can then use the | 204 | * out to all of the registered fsnotify_group. Those groups can then use the |
| 134 | * notification event in whatever means they feel necessary. | 205 | * notification event in whatever means they feel necessary. |
| 135 | */ | 206 | */ |
| 136 | void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, const char *file_name, u32 cookie) | 207 | int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, |
| 208 | const unsigned char *file_name, u32 cookie) | ||
| 137 | { | 209 | { |
| 138 | struct fsnotify_group *group; | 210 | struct hlist_node *inode_node, *vfsmount_node; |
| 211 | struct fsnotify_mark *inode_mark = NULL, *vfsmount_mark = NULL; | ||
| 212 | struct fsnotify_group *inode_group, *vfsmount_group; | ||
| 139 | struct fsnotify_event *event = NULL; | 213 | struct fsnotify_event *event = NULL; |
| 140 | int idx; | 214 | struct vfsmount *mnt; |
| 215 | int idx, ret = 0; | ||
| 216 | bool used_inode = false, used_vfsmount = false; | ||
| 141 | /* global tests shouldn't care about events on child only the specific event */ | 217 | /* global tests shouldn't care about events on child only the specific event */ |
| 142 | __u32 test_mask = (mask & ~FS_EVENT_ON_CHILD); | 218 | __u32 test_mask = (mask & ~FS_EVENT_ON_CHILD); |
| 143 | 219 | ||
| 144 | if (list_empty(&fsnotify_groups)) | 220 | if (data_is == FSNOTIFY_EVENT_PATH) |
| 145 | return; | 221 | mnt = ((struct path *)data)->mnt; |
| 222 | else | ||
| 223 | mnt = NULL; | ||
| 146 | 224 | ||
| 147 | if (!(test_mask & fsnotify_mask)) | ||
| 148 | return; | ||
| 149 | |||
| 150 | if (!(test_mask & to_tell->i_fsnotify_mask)) | ||
| 151 | return; | ||
| 152 | /* | 225 | /* |
| 153 | * SRCU!! the groups list is very very much read only and the path is | 226 | * if this is a modify event we may need to clear the ignored masks |
| 154 | * very hot. The VAST majority of events are not going to need to do | 227 | * otherwise return if neither the inode nor the vfsmount care about |
| 155 | * anything other than walk the list so it's crazy to pre-allocate. | 228 | * this type of event. |
| 156 | */ | 229 | */ |
| 157 | idx = srcu_read_lock(&fsnotify_grp_srcu); | 230 | if (!(mask & FS_MODIFY) && |
| 158 | list_for_each_entry_rcu(group, &fsnotify_groups, group_list) { | 231 | !(test_mask & to_tell->i_fsnotify_mask) && |
| 159 | if (test_mask & group->mask) { | 232 | !(mnt && test_mask & mnt->mnt_fsnotify_mask)) |
| 160 | if (!group->ops->should_send_event(group, to_tell, mask)) | 233 | return 0; |
| 161 | continue; | 234 | |
| 162 | if (!event) { | 235 | idx = srcu_read_lock(&fsnotify_mark_srcu); |
| 163 | event = fsnotify_create_event(to_tell, mask, data, | 236 | |
| 164 | data_is, file_name, cookie, | 237 | if ((mask & FS_MODIFY) || |
| 165 | GFP_KERNEL); | 238 | (test_mask & to_tell->i_fsnotify_mask)) |
| 166 | /* shit, we OOM'd and now we can't tell, maybe | 239 | inode_node = srcu_dereference(to_tell->i_fsnotify_marks.first, |
| 167 | * someday someone else will want to do something | 240 | &fsnotify_mark_srcu); |
| 168 | * here */ | 241 | else |
| 169 | if (!event) | 242 | inode_node = NULL; |
| 170 | break; | 243 | |
| 171 | } | 244 | if (mnt) { |
| 172 | group->ops->handle_event(group, event); | 245 | if ((mask & FS_MODIFY) || |
| 246 | (test_mask & mnt->mnt_fsnotify_mask)) | ||
| 247 | vfsmount_node = srcu_dereference(mnt->mnt_fsnotify_marks.first, | ||
| 248 | &fsnotify_mark_srcu); | ||
| 249 | else | ||
| 250 | vfsmount_node = NULL; | ||
| 251 | } else { | ||
| 252 | mnt = NULL; | ||
| 253 | vfsmount_node = NULL; | ||
| 254 | } | ||
| 255 | |||
| 256 | while (inode_node || vfsmount_node) { | ||
| 257 | if (inode_node) { | ||
| 258 | inode_mark = hlist_entry(srcu_dereference(inode_node, &fsnotify_mark_srcu), | ||
| 259 | struct fsnotify_mark, i.i_list); | ||
| 260 | inode_group = inode_mark->group; | ||
| 261 | } else | ||
| 262 | inode_group = (void *)-1; | ||
| 263 | |||
| 264 | if (vfsmount_node) { | ||
| 265 | vfsmount_mark = hlist_entry(srcu_dereference(vfsmount_node, &fsnotify_mark_srcu), | ||
| 266 | struct fsnotify_mark, m.m_list); | ||
| 267 | vfsmount_group = vfsmount_mark->group; | ||
| 268 | } else | ||
| 269 | vfsmount_group = (void *)-1; | ||
| 270 | |||
| 271 | if (inode_group < vfsmount_group) { | ||
| 272 | /* handle inode */ | ||
| 273 | send_to_group(to_tell, NULL, inode_mark, NULL, mask, data, | ||
| 274 | data_is, cookie, file_name, &event); | ||
| 275 | used_inode = true; | ||
| 276 | } else if (vfsmount_group < inode_group) { | ||
| 277 | send_to_group(to_tell, mnt, NULL, vfsmount_mark, mask, data, | ||
| 278 | data_is, cookie, file_name, &event); | ||
| 279 | used_vfsmount = true; | ||
| 280 | } else { | ||
| 281 | send_to_group(to_tell, mnt, inode_mark, vfsmount_mark, | ||
| 282 | mask, data, data_is, cookie, file_name, | ||
| 283 | &event); | ||
| 284 | used_vfsmount = true; | ||
| 285 | used_inode = true; | ||
| 173 | } | 286 | } |
| 287 | |||
| 288 | if (used_inode) | ||
| 289 | inode_node = srcu_dereference(inode_node->next, | ||
| 290 | &fsnotify_mark_srcu); | ||
| 291 | if (used_vfsmount) | ||
| 292 | vfsmount_node = srcu_dereference(vfsmount_node->next, | ||
| 293 | &fsnotify_mark_srcu); | ||
| 174 | } | 294 | } |
| 175 | srcu_read_unlock(&fsnotify_grp_srcu, idx); | 295 | |
| 296 | srcu_read_unlock(&fsnotify_mark_srcu, idx); | ||
| 176 | /* | 297 | /* |
| 177 | * fsnotify_create_event() took a reference so the event can't be cleaned | 298 | * fsnotify_create_event() took a reference so the event can't be cleaned |
| 178 | * up while we are still trying to add it to lists, drop that one. | 299 | * up while we are still trying to add it to lists, drop that one. |
| 179 | */ | 300 | */ |
| 180 | if (event) | 301 | if (event) |
| 181 | fsnotify_put_event(event); | 302 | fsnotify_put_event(event); |
| 303 | |||
| 304 | return ret; | ||
| 182 | } | 305 | } |
| 183 | EXPORT_SYMBOL_GPL(fsnotify); | 306 | EXPORT_SYMBOL_GPL(fsnotify); |
| 184 | 307 | ||
| 185 | static __init int fsnotify_init(void) | 308 | static __init int fsnotify_init(void) |
| 186 | { | 309 | { |
| 187 | return init_srcu_struct(&fsnotify_grp_srcu); | 310 | int ret; |
| 311 | |||
| 312 | BUG_ON(hweight32(ALL_FSNOTIFY_EVENTS) != 23); | ||
| 313 | |||
| 314 | ret = init_srcu_struct(&fsnotify_mark_srcu); | ||
| 315 | if (ret) | ||
| 316 | panic("initializing fsnotify_mark_srcu"); | ||
| 317 | |||
| 318 | return 0; | ||
| 188 | } | 319 | } |
| 189 | subsys_initcall(fsnotify_init); | 320 | core_initcall(fsnotify_init); |
diff --git a/fs/notify/fsnotify.h b/fs/notify/fsnotify.h index 4dc240824b2d..85e7d2b431d9 100644 --- a/fs/notify/fsnotify.h +++ b/fs/notify/fsnotify.h | |||
| @@ -6,21 +6,34 @@ | |||
| 6 | #include <linux/srcu.h> | 6 | #include <linux/srcu.h> |
| 7 | #include <linux/types.h> | 7 | #include <linux/types.h> |
| 8 | 8 | ||
| 9 | /* protects reads of fsnotify_groups */ | ||
| 10 | extern struct srcu_struct fsnotify_grp_srcu; | ||
| 11 | /* all groups which receive fsnotify events */ | ||
| 12 | extern struct list_head fsnotify_groups; | ||
| 13 | /* all bitwise OR of all event types (FS_*) for all fsnotify_groups */ | ||
| 14 | extern __u32 fsnotify_mask; | ||
| 15 | |||
| 16 | /* destroy all events sitting in this groups notification queue */ | 9 | /* destroy all events sitting in this groups notification queue */ |
| 17 | extern void fsnotify_flush_notify(struct fsnotify_group *group); | 10 | extern void fsnotify_flush_notify(struct fsnotify_group *group); |
| 18 | 11 | ||
| 12 | /* protects reads of inode and vfsmount marks list */ | ||
| 13 | extern struct srcu_struct fsnotify_mark_srcu; | ||
| 14 | |||
| 15 | extern void fsnotify_set_inode_mark_mask_locked(struct fsnotify_mark *fsn_mark, | ||
| 16 | __u32 mask); | ||
| 17 | /* add a mark to an inode */ | ||
| 18 | extern int fsnotify_add_inode_mark(struct fsnotify_mark *mark, | ||
| 19 | struct fsnotify_group *group, struct inode *inode, | ||
| 20 | int allow_dups); | ||
| 21 | /* add a mark to a vfsmount */ | ||
| 22 | extern int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark, | ||
| 23 | struct fsnotify_group *group, struct vfsmount *mnt, | ||
| 24 | int allow_dups); | ||
| 25 | |||
| 19 | /* final kfree of a group */ | 26 | /* final kfree of a group */ |
| 20 | extern void fsnotify_final_destroy_group(struct fsnotify_group *group); | 27 | extern void fsnotify_final_destroy_group(struct fsnotify_group *group); |
| 21 | 28 | ||
| 29 | /* vfsmount specific destruction of a mark */ | ||
| 30 | extern void fsnotify_destroy_vfsmount_mark(struct fsnotify_mark *mark); | ||
| 31 | /* inode specific destruction of a mark */ | ||
| 32 | extern void fsnotify_destroy_inode_mark(struct fsnotify_mark *mark); | ||
| 22 | /* run the list of all marks associated with inode and flag them to be freed */ | 33 | /* run the list of all marks associated with inode and flag them to be freed */ |
| 23 | extern void fsnotify_clear_marks_by_inode(struct inode *inode); | 34 | extern void fsnotify_clear_marks_by_inode(struct inode *inode); |
| 35 | /* run the list of all marks associated with vfsmount and flag them to be freed */ | ||
| 36 | extern void fsnotify_clear_marks_by_mount(struct vfsmount *mnt); | ||
| 24 | /* | 37 | /* |
| 25 | * update the dentry->d_flags of all of inode's children to indicate if inode cares | 38 | * update the dentry->d_flags of all of inode's children to indicate if inode cares |
| 26 | * about events that happen to its children. | 39 | * about events that happen to its children. |
diff --git a/fs/notify/group.c b/fs/notify/group.c index 0e1677144bc5..d309f38449cb 100644 --- a/fs/notify/group.c +++ b/fs/notify/group.c | |||
| @@ -28,64 +28,6 @@ | |||
| 28 | 28 | ||
| 29 | #include <asm/atomic.h> | 29 | #include <asm/atomic.h> |
| 30 | 30 | ||
| 31 | /* protects writes to fsnotify_groups and fsnotify_mask */ | ||
| 32 | static DEFINE_MUTEX(fsnotify_grp_mutex); | ||
| 33 | /* protects reads while running the fsnotify_groups list */ | ||
| 34 | struct srcu_struct fsnotify_grp_srcu; | ||
| 35 | /* all groups registered to receive filesystem notifications */ | ||
| 36 | LIST_HEAD(fsnotify_groups); | ||
| 37 | /* bitwise OR of all events (FS_*) interesting to some group on this system */ | ||
| 38 | __u32 fsnotify_mask; | ||
| 39 | |||
| 40 | /* | ||
| 41 | * When a new group registers or changes it's set of interesting events | ||
| 42 | * this function updates the fsnotify_mask to contain all interesting events | ||
| 43 | */ | ||
| 44 | void fsnotify_recalc_global_mask(void) | ||
| 45 | { | ||
| 46 | struct fsnotify_group *group; | ||
| 47 | __u32 mask = 0; | ||
| 48 | int idx; | ||
| 49 | |||
| 50 | idx = srcu_read_lock(&fsnotify_grp_srcu); | ||
| 51 | list_for_each_entry_rcu(group, &fsnotify_groups, group_list) | ||
| 52 | mask |= group->mask; | ||
| 53 | srcu_read_unlock(&fsnotify_grp_srcu, idx); | ||
| 54 | fsnotify_mask = mask; | ||
| 55 | } | ||
| 56 | |||
| 57 | /* | ||
| 58 | * Update the group->mask by running all of the marks associated with this | ||
| 59 | * group and finding the bitwise | of all of the mark->mask. If we change | ||
| 60 | * the group->mask we need to update the global mask of events interesting | ||
| 61 | * to the system. | ||
| 62 | */ | ||
| 63 | void fsnotify_recalc_group_mask(struct fsnotify_group *group) | ||
| 64 | { | ||
| 65 | __u32 mask = 0; | ||
| 66 | __u32 old_mask = group->mask; | ||
| 67 | struct fsnotify_mark_entry *entry; | ||
| 68 | |||
| 69 | spin_lock(&group->mark_lock); | ||
| 70 | list_for_each_entry(entry, &group->mark_entries, g_list) | ||
| 71 | mask |= entry->mask; | ||
| 72 | spin_unlock(&group->mark_lock); | ||
| 73 | |||
| 74 | group->mask = mask; | ||
| 75 | |||
| 76 | if (old_mask != mask) | ||
| 77 | fsnotify_recalc_global_mask(); | ||
| 78 | } | ||
| 79 | |||
| 80 | /* | ||
| 81 | * Take a reference to a group so things found under the fsnotify_grp_mutex | ||
| 82 | * can't get freed under us | ||
| 83 | */ | ||
| 84 | static void fsnotify_get_group(struct fsnotify_group *group) | ||
| 85 | { | ||
| 86 | atomic_inc(&group->refcnt); | ||
| 87 | } | ||
| 88 | |||
| 89 | /* | 31 | /* |
| 90 | * Final freeing of a group | 32 | * Final freeing of a group |
| 91 | */ | 33 | */ |
| @@ -110,145 +52,53 @@ void fsnotify_final_destroy_group(struct fsnotify_group *group) | |||
| 110 | */ | 52 | */ |
| 111 | static void fsnotify_destroy_group(struct fsnotify_group *group) | 53 | static void fsnotify_destroy_group(struct fsnotify_group *group) |
| 112 | { | 54 | { |
| 113 | /* clear all inode mark entries for this group */ | 55 | /* clear all inode marks for this group */ |
| 114 | fsnotify_clear_marks_by_group(group); | 56 | fsnotify_clear_marks_by_group(group); |
| 115 | 57 | ||
| 58 | synchronize_srcu(&fsnotify_mark_srcu); | ||
| 59 | |||
| 116 | /* past the point of no return, matches the initial value of 1 */ | 60 | /* past the point of no return, matches the initial value of 1 */ |
| 117 | if (atomic_dec_and_test(&group->num_marks)) | 61 | if (atomic_dec_and_test(&group->num_marks)) |
| 118 | fsnotify_final_destroy_group(group); | 62 | fsnotify_final_destroy_group(group); |
| 119 | } | 63 | } |
| 120 | 64 | ||
| 121 | /* | 65 | /* |
| 122 | * Remove this group from the global list of groups that will get events | ||
| 123 | * this can be done even if there are still references and things still using | ||
| 124 | * this group. This just stops the group from getting new events. | ||
| 125 | */ | ||
| 126 | static void __fsnotify_evict_group(struct fsnotify_group *group) | ||
| 127 | { | ||
| 128 | BUG_ON(!mutex_is_locked(&fsnotify_grp_mutex)); | ||
| 129 | |||
| 130 | if (group->on_group_list) | ||
| 131 | list_del_rcu(&group->group_list); | ||
| 132 | group->on_group_list = 0; | ||
| 133 | } | ||
| 134 | |||
| 135 | /* | ||
| 136 | * Called when a group is no longer interested in getting events. This can be | ||
| 137 | * used if a group is misbehaving or if for some reason a group should no longer | ||
| 138 | * get any filesystem events. | ||
| 139 | */ | ||
| 140 | void fsnotify_evict_group(struct fsnotify_group *group) | ||
| 141 | { | ||
| 142 | mutex_lock(&fsnotify_grp_mutex); | ||
| 143 | __fsnotify_evict_group(group); | ||
| 144 | mutex_unlock(&fsnotify_grp_mutex); | ||
| 145 | } | ||
| 146 | |||
| 147 | /* | ||
| 148 | * Drop a reference to a group. Free it if it's through. | 66 | * Drop a reference to a group. Free it if it's through. |
| 149 | */ | 67 | */ |
| 150 | void fsnotify_put_group(struct fsnotify_group *group) | 68 | void fsnotify_put_group(struct fsnotify_group *group) |
| 151 | { | 69 | { |
| 152 | if (!atomic_dec_and_mutex_lock(&group->refcnt, &fsnotify_grp_mutex)) | 70 | if (atomic_dec_and_test(&group->refcnt)) |
| 153 | return; | 71 | fsnotify_destroy_group(group); |
| 154 | |||
| 155 | /* | ||
| 156 | * OK, now we know that there's no other users *and* we hold mutex, | ||
| 157 | * so no new references will appear | ||
| 158 | */ | ||
| 159 | __fsnotify_evict_group(group); | ||
| 160 | |||
| 161 | /* | ||
| 162 | * now it's off the list, so the only thing we might care about is | ||
| 163 | * srcu access.... | ||
| 164 | */ | ||
| 165 | mutex_unlock(&fsnotify_grp_mutex); | ||
| 166 | synchronize_srcu(&fsnotify_grp_srcu); | ||
| 167 | |||
| 168 | /* and now it is really dead. _Nothing_ could be seeing it */ | ||
| 169 | fsnotify_recalc_global_mask(); | ||
| 170 | fsnotify_destroy_group(group); | ||
| 171 | } | ||
| 172 | |||
| 173 | /* | ||
| 174 | * Simply run the fsnotify_groups list and find a group which matches | ||
| 175 | * the given parameters. If a group is found we take a reference to that | ||
| 176 | * group. | ||
| 177 | */ | ||
| 178 | static struct fsnotify_group *fsnotify_find_group(unsigned int group_num, __u32 mask, | ||
| 179 | const struct fsnotify_ops *ops) | ||
| 180 | { | ||
| 181 | struct fsnotify_group *group_iter; | ||
| 182 | struct fsnotify_group *group = NULL; | ||
| 183 | |||
| 184 | BUG_ON(!mutex_is_locked(&fsnotify_grp_mutex)); | ||
| 185 | |||
| 186 | list_for_each_entry_rcu(group_iter, &fsnotify_groups, group_list) { | ||
| 187 | if (group_iter->group_num == group_num) { | ||
| 188 | if ((group_iter->mask == mask) && | ||
| 189 | (group_iter->ops == ops)) { | ||
| 190 | fsnotify_get_group(group_iter); | ||
| 191 | group = group_iter; | ||
| 192 | } else | ||
| 193 | group = ERR_PTR(-EEXIST); | ||
| 194 | } | ||
| 195 | } | ||
| 196 | return group; | ||
| 197 | } | 72 | } |
| 198 | 73 | ||
| 199 | /* | 74 | /* |
| 200 | * Either finds an existing group which matches the group_num, mask, and ops or | 75 | * Create a new fsnotify_group and hold a reference for the group returned. |
| 201 | * creates a new group and adds it to the global group list. In either case we | ||
| 202 | * take a reference for the group returned. | ||
| 203 | */ | 76 | */ |
| 204 | struct fsnotify_group *fsnotify_obtain_group(unsigned int group_num, __u32 mask, | 77 | struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops) |
| 205 | const struct fsnotify_ops *ops) | ||
| 206 | { | 78 | { |
| 207 | struct fsnotify_group *group, *tgroup; | 79 | struct fsnotify_group *group; |
| 208 | 80 | ||
| 209 | /* very low use, simpler locking if we just always alloc */ | 81 | group = kzalloc(sizeof(struct fsnotify_group), GFP_KERNEL); |
| 210 | group = kmalloc(sizeof(struct fsnotify_group), GFP_KERNEL); | ||
| 211 | if (!group) | 82 | if (!group) |
| 212 | return ERR_PTR(-ENOMEM); | 83 | return ERR_PTR(-ENOMEM); |
| 213 | 84 | ||
| 85 | /* set to 0 when there a no external references to this group */ | ||
| 214 | atomic_set(&group->refcnt, 1); | 86 | atomic_set(&group->refcnt, 1); |
| 215 | 87 | /* | |
| 216 | group->on_group_list = 0; | 88 | * hits 0 when there are no external references AND no marks for |
| 217 | group->group_num = group_num; | 89 | * this group |
| 218 | group->mask = mask; | 90 | */ |
| 91 | atomic_set(&group->num_marks, 1); | ||
| 219 | 92 | ||
| 220 | mutex_init(&group->notification_mutex); | 93 | mutex_init(&group->notification_mutex); |
| 221 | INIT_LIST_HEAD(&group->notification_list); | 94 | INIT_LIST_HEAD(&group->notification_list); |
| 222 | init_waitqueue_head(&group->notification_waitq); | 95 | init_waitqueue_head(&group->notification_waitq); |
| 223 | group->q_len = 0; | ||
| 224 | group->max_events = UINT_MAX; | 96 | group->max_events = UINT_MAX; |
| 225 | 97 | ||
| 226 | spin_lock_init(&group->mark_lock); | 98 | spin_lock_init(&group->mark_lock); |
| 227 | atomic_set(&group->num_marks, 0); | 99 | INIT_LIST_HEAD(&group->marks_list); |
| 228 | INIT_LIST_HEAD(&group->mark_entries); | ||
| 229 | 100 | ||
| 230 | group->ops = ops; | 101 | group->ops = ops; |
| 231 | 102 | ||
| 232 | mutex_lock(&fsnotify_grp_mutex); | ||
| 233 | tgroup = fsnotify_find_group(group_num, mask, ops); | ||
| 234 | if (tgroup) { | ||
| 235 | /* group already exists */ | ||
| 236 | mutex_unlock(&fsnotify_grp_mutex); | ||
| 237 | /* destroy the new one we made */ | ||
| 238 | fsnotify_put_group(group); | ||
| 239 | return tgroup; | ||
| 240 | } | ||
| 241 | |||
| 242 | /* group not found, add a new one */ | ||
| 243 | list_add_rcu(&group->group_list, &fsnotify_groups); | ||
| 244 | group->on_group_list = 1; | ||
| 245 | /* being on the fsnotify_groups list holds one num_marks */ | ||
| 246 | atomic_inc(&group->num_marks); | ||
| 247 | |||
| 248 | mutex_unlock(&fsnotify_grp_mutex); | ||
| 249 | |||
| 250 | if (mask) | ||
| 251 | fsnotify_recalc_global_mask(); | ||
| 252 | |||
| 253 | return group; | 103 | return group; |
| 254 | } | 104 | } |
diff --git a/fs/notify/inode_mark.c b/fs/notify/inode_mark.c index 0399bcbe09c8..33297c005060 100644 --- a/fs/notify/inode_mark.c +++ b/fs/notify/inode_mark.c | |||
| @@ -16,72 +16,6 @@ | |||
| 16 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | 16 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. |
| 17 | */ | 17 | */ |
| 18 | 18 | ||
| 19 | /* | ||
| 20 | * fsnotify inode mark locking/lifetime/and refcnting | ||
| 21 | * | ||
| 22 | * REFCNT: | ||
| 23 | * The mark->refcnt tells how many "things" in the kernel currently are | ||
| 24 | * referencing this object. The object typically will live inside the kernel | ||
| 25 | * with a refcnt of 2, one for each list it is on (i_list, g_list). Any task | ||
| 26 | * which can find this object holding the appropriete locks, can take a reference | ||
| 27 | * and the object itself is guarenteed to survive until the reference is dropped. | ||
| 28 | * | ||
| 29 | * LOCKING: | ||
| 30 | * There are 3 spinlocks involved with fsnotify inode marks and they MUST | ||
| 31 | * be taken in order as follows: | ||
| 32 | * | ||
| 33 | * entry->lock | ||
| 34 | * group->mark_lock | ||
| 35 | * inode->i_lock | ||
| 36 | * | ||
| 37 | * entry->lock protects 2 things, entry->group and entry->inode. You must hold | ||
| 38 | * that lock to dereference either of these things (they could be NULL even with | ||
| 39 | * the lock) | ||
| 40 | * | ||
| 41 | * group->mark_lock protects the mark_entries list anchored inside a given group | ||
| 42 | * and each entry is hooked via the g_list. It also sorta protects the | ||
| 43 | * free_g_list, which when used is anchored by a private list on the stack of the | ||
| 44 | * task which held the group->mark_lock. | ||
| 45 | * | ||
| 46 | * inode->i_lock protects the i_fsnotify_mark_entries list anchored inside a | ||
| 47 | * given inode and each entry is hooked via the i_list. (and sorta the | ||
| 48 | * free_i_list) | ||
| 49 | * | ||
| 50 | * | ||
| 51 | * LIFETIME: | ||
| 52 | * Inode marks survive between when they are added to an inode and when their | ||
| 53 | * refcnt==0. | ||
| 54 | * | ||
| 55 | * The inode mark can be cleared for a number of different reasons including: | ||
| 56 | * - The inode is unlinked for the last time. (fsnotify_inode_remove) | ||
| 57 | * - The inode is being evicted from cache. (fsnotify_inode_delete) | ||
| 58 | * - The fs the inode is on is unmounted. (fsnotify_inode_delete/fsnotify_unmount_inodes) | ||
| 59 | * - Something explicitly requests that it be removed. (fsnotify_destroy_mark_by_entry) | ||
| 60 | * - The fsnotify_group associated with the mark is going away and all such marks | ||
| 61 | * need to be cleaned up. (fsnotify_clear_marks_by_group) | ||
| 62 | * | ||
| 63 | * Worst case we are given an inode and need to clean up all the marks on that | ||
| 64 | * inode. We take i_lock and walk the i_fsnotify_mark_entries safely. For each | ||
| 65 | * mark on the list we take a reference (so the mark can't disappear under us). | ||
| 66 | * We remove that mark form the inode's list of marks and we add this mark to a | ||
| 67 | * private list anchored on the stack using i_free_list; At this point we no | ||
| 68 | * longer fear anything finding the mark using the inode's list of marks. | ||
| 69 | * | ||
| 70 | * We can safely and locklessly run the private list on the stack of everything | ||
| 71 | * we just unattached from the original inode. For each mark on the private list | ||
| 72 | * we grab the mark-> and can thus dereference mark->group and mark->inode. If | ||
| 73 | * we see the group and inode are not NULL we take those locks. Now holding all | ||
| 74 | * 3 locks we can completely remove the mark from other tasks finding it in the | ||
| 75 | * future. Remember, 10 things might already be referencing this mark, but they | ||
| 76 | * better be holding a ref. We drop our reference we took before we unhooked it | ||
| 77 | * from the inode. When the ref hits 0 we can free the mark. | ||
| 78 | * | ||
| 79 | * Very similarly for freeing by group, except we use free_g_list. | ||
| 80 | * | ||
| 81 | * This has the very interesting property of being able to run concurrently with | ||
| 82 | * any (or all) other directions. | ||
| 83 | */ | ||
| 84 | |||
| 85 | #include <linux/fs.h> | 19 | #include <linux/fs.h> |
| 86 | #include <linux/init.h> | 20 | #include <linux/init.h> |
| 87 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
| @@ -95,30 +29,19 @@ | |||
| 95 | #include <linux/fsnotify_backend.h> | 29 | #include <linux/fsnotify_backend.h> |
| 96 | #include "fsnotify.h" | 30 | #include "fsnotify.h" |
| 97 | 31 | ||
| 98 | void fsnotify_get_mark(struct fsnotify_mark_entry *entry) | ||
| 99 | { | ||
| 100 | atomic_inc(&entry->refcnt); | ||
| 101 | } | ||
| 102 | |||
| 103 | void fsnotify_put_mark(struct fsnotify_mark_entry *entry) | ||
| 104 | { | ||
| 105 | if (atomic_dec_and_test(&entry->refcnt)) | ||
| 106 | entry->free_mark(entry); | ||
| 107 | } | ||
| 108 | |||
| 109 | /* | 32 | /* |
| 110 | * Recalculate the mask of events relevant to a given inode locked. | 33 | * Recalculate the mask of events relevant to a given inode locked. |
| 111 | */ | 34 | */ |
| 112 | static void fsnotify_recalc_inode_mask_locked(struct inode *inode) | 35 | static void fsnotify_recalc_inode_mask_locked(struct inode *inode) |
| 113 | { | 36 | { |
| 114 | struct fsnotify_mark_entry *entry; | 37 | struct fsnotify_mark *mark; |
| 115 | struct hlist_node *pos; | 38 | struct hlist_node *pos; |
| 116 | __u32 new_mask = 0; | 39 | __u32 new_mask = 0; |
| 117 | 40 | ||
| 118 | assert_spin_locked(&inode->i_lock); | 41 | assert_spin_locked(&inode->i_lock); |
| 119 | 42 | ||
| 120 | hlist_for_each_entry(entry, pos, &inode->i_fsnotify_mark_entries, i_list) | 43 | hlist_for_each_entry(mark, pos, &inode->i_fsnotify_marks, i.i_list) |
| 121 | new_mask |= entry->mask; | 44 | new_mask |= mark->mask; |
| 122 | inode->i_fsnotify_mask = new_mask; | 45 | inode->i_fsnotify_mask = new_mask; |
| 123 | } | 46 | } |
| 124 | 47 | ||
| @@ -135,107 +58,26 @@ void fsnotify_recalc_inode_mask(struct inode *inode) | |||
| 135 | __fsnotify_update_child_dentry_flags(inode); | 58 | __fsnotify_update_child_dentry_flags(inode); |
| 136 | } | 59 | } |
| 137 | 60 | ||
| 138 | /* | 61 | void fsnotify_destroy_inode_mark(struct fsnotify_mark *mark) |
| 139 | * Any time a mark is getting freed we end up here. | ||
| 140 | * The caller had better be holding a reference to this mark so we don't actually | ||
| 141 | * do the final put under the entry->lock | ||
| 142 | */ | ||
| 143 | void fsnotify_destroy_mark_by_entry(struct fsnotify_mark_entry *entry) | ||
| 144 | { | 62 | { |
| 145 | struct fsnotify_group *group; | 63 | struct inode *inode = mark->i.inode; |
| 146 | struct inode *inode; | ||
| 147 | 64 | ||
| 148 | spin_lock(&entry->lock); | 65 | assert_spin_locked(&mark->lock); |
| 66 | assert_spin_locked(&mark->group->mark_lock); | ||
| 149 | 67 | ||
| 150 | group = entry->group; | ||
| 151 | inode = entry->inode; | ||
| 152 | |||
| 153 | BUG_ON(group && !inode); | ||
| 154 | BUG_ON(!group && inode); | ||
| 155 | |||
| 156 | /* if !group something else already marked this to die */ | ||
| 157 | if (!group) { | ||
| 158 | spin_unlock(&entry->lock); | ||
| 159 | return; | ||
| 160 | } | ||
| 161 | |||
| 162 | /* 1 from caller and 1 for being on i_list/g_list */ | ||
| 163 | BUG_ON(atomic_read(&entry->refcnt) < 2); | ||
| 164 | |||
| 165 | spin_lock(&group->mark_lock); | ||
| 166 | spin_lock(&inode->i_lock); | 68 | spin_lock(&inode->i_lock); |
| 167 | 69 | ||
| 168 | hlist_del_init(&entry->i_list); | 70 | hlist_del_init_rcu(&mark->i.i_list); |
| 169 | entry->inode = NULL; | 71 | mark->i.inode = NULL; |
| 170 | |||
| 171 | list_del_init(&entry->g_list); | ||
| 172 | entry->group = NULL; | ||
| 173 | |||
| 174 | fsnotify_put_mark(entry); /* for i_list and g_list */ | ||
| 175 | 72 | ||
| 176 | /* | 73 | /* |
| 177 | * this mark is now off the inode->i_fsnotify_mark_entries list and we | 74 | * this mark is now off the inode->i_fsnotify_marks list and we |
| 178 | * hold the inode->i_lock, so this is the perfect time to update the | 75 | * hold the inode->i_lock, so this is the perfect time to update the |
| 179 | * inode->i_fsnotify_mask | 76 | * inode->i_fsnotify_mask |
| 180 | */ | 77 | */ |
| 181 | fsnotify_recalc_inode_mask_locked(inode); | 78 | fsnotify_recalc_inode_mask_locked(inode); |
| 182 | 79 | ||
| 183 | spin_unlock(&inode->i_lock); | 80 | spin_unlock(&inode->i_lock); |
| 184 | spin_unlock(&group->mark_lock); | ||
| 185 | spin_unlock(&entry->lock); | ||
| 186 | |||
| 187 | /* | ||
| 188 | * Some groups like to know that marks are being freed. This is a | ||
| 189 | * callback to the group function to let it know that this entry | ||
| 190 | * is being freed. | ||
| 191 | */ | ||
| 192 | if (group->ops->freeing_mark) | ||
| 193 | group->ops->freeing_mark(entry, group); | ||
| 194 | |||
| 195 | /* | ||
| 196 | * __fsnotify_update_child_dentry_flags(inode); | ||
| 197 | * | ||
| 198 | * I really want to call that, but we can't, we have no idea if the inode | ||
| 199 | * still exists the second we drop the entry->lock. | ||
| 200 | * | ||
| 201 | * The next time an event arrive to this inode from one of it's children | ||
| 202 | * __fsnotify_parent will see that the inode doesn't care about it's | ||
| 203 | * children and will update all of these flags then. So really this | ||
| 204 | * is just a lazy update (and could be a perf win...) | ||
| 205 | */ | ||
| 206 | |||
| 207 | |||
| 208 | iput(inode); | ||
| 209 | |||
| 210 | /* | ||
| 211 | * it's possible that this group tried to destroy itself, but this | ||
| 212 | * this mark was simultaneously being freed by inode. If that's the | ||
| 213 | * case, we finish freeing the group here. | ||
| 214 | */ | ||
| 215 | if (unlikely(atomic_dec_and_test(&group->num_marks))) | ||
| 216 | fsnotify_final_destroy_group(group); | ||
| 217 | } | ||
| 218 | |||
| 219 | /* | ||
| 220 | * Given a group, destroy all of the marks associated with that group. | ||
| 221 | */ | ||
| 222 | void fsnotify_clear_marks_by_group(struct fsnotify_group *group) | ||
| 223 | { | ||
| 224 | struct fsnotify_mark_entry *lentry, *entry; | ||
| 225 | LIST_HEAD(free_list); | ||
| 226 | |||
| 227 | spin_lock(&group->mark_lock); | ||
| 228 | list_for_each_entry_safe(entry, lentry, &group->mark_entries, g_list) { | ||
| 229 | list_add(&entry->free_g_list, &free_list); | ||
| 230 | list_del_init(&entry->g_list); | ||
| 231 | fsnotify_get_mark(entry); | ||
| 232 | } | ||
| 233 | spin_unlock(&group->mark_lock); | ||
| 234 | |||
| 235 | list_for_each_entry_safe(entry, lentry, &free_list, free_g_list) { | ||
| 236 | fsnotify_destroy_mark_by_entry(entry); | ||
| 237 | fsnotify_put_mark(entry); | ||
| 238 | } | ||
| 239 | } | 81 | } |
| 240 | 82 | ||
| 241 | /* | 83 | /* |
| @@ -243,112 +85,145 @@ void fsnotify_clear_marks_by_group(struct fsnotify_group *group) | |||
| 243 | */ | 85 | */ |
| 244 | void fsnotify_clear_marks_by_inode(struct inode *inode) | 86 | void fsnotify_clear_marks_by_inode(struct inode *inode) |
| 245 | { | 87 | { |
| 246 | struct fsnotify_mark_entry *entry, *lentry; | 88 | struct fsnotify_mark *mark, *lmark; |
| 247 | struct hlist_node *pos, *n; | 89 | struct hlist_node *pos, *n; |
| 248 | LIST_HEAD(free_list); | 90 | LIST_HEAD(free_list); |
| 249 | 91 | ||
| 250 | spin_lock(&inode->i_lock); | 92 | spin_lock(&inode->i_lock); |
| 251 | hlist_for_each_entry_safe(entry, pos, n, &inode->i_fsnotify_mark_entries, i_list) { | 93 | hlist_for_each_entry_safe(mark, pos, n, &inode->i_fsnotify_marks, i.i_list) { |
| 252 | list_add(&entry->free_i_list, &free_list); | 94 | list_add(&mark->i.free_i_list, &free_list); |
| 253 | hlist_del_init(&entry->i_list); | 95 | hlist_del_init_rcu(&mark->i.i_list); |
| 254 | fsnotify_get_mark(entry); | 96 | fsnotify_get_mark(mark); |
| 255 | } | 97 | } |
| 256 | spin_unlock(&inode->i_lock); | 98 | spin_unlock(&inode->i_lock); |
| 257 | 99 | ||
| 258 | list_for_each_entry_safe(entry, lentry, &free_list, free_i_list) { | 100 | list_for_each_entry_safe(mark, lmark, &free_list, i.free_i_list) { |
| 259 | fsnotify_destroy_mark_by_entry(entry); | 101 | fsnotify_destroy_mark(mark); |
| 260 | fsnotify_put_mark(entry); | 102 | fsnotify_put_mark(mark); |
| 261 | } | 103 | } |
| 262 | } | 104 | } |
| 263 | 105 | ||
| 264 | /* | 106 | /* |
| 107 | * Given a group clear all of the inode marks associated with that group. | ||
| 108 | */ | ||
| 109 | void fsnotify_clear_inode_marks_by_group(struct fsnotify_group *group) | ||
| 110 | { | ||
| 111 | fsnotify_clear_marks_by_group_flags(group, FSNOTIFY_MARK_FLAG_INODE); | ||
| 112 | } | ||
| 113 | |||
| 114 | /* | ||
| 265 | * given a group and inode, find the mark associated with that combination. | 115 | * given a group and inode, find the mark associated with that combination. |
| 266 | * if found take a reference to that mark and return it, else return NULL | 116 | * if found take a reference to that mark and return it, else return NULL |
| 267 | */ | 117 | */ |
| 268 | struct fsnotify_mark_entry *fsnotify_find_mark_entry(struct fsnotify_group *group, | 118 | struct fsnotify_mark *fsnotify_find_inode_mark_locked(struct fsnotify_group *group, |
| 269 | struct inode *inode) | 119 | struct inode *inode) |
| 270 | { | 120 | { |
| 271 | struct fsnotify_mark_entry *entry; | 121 | struct fsnotify_mark *mark; |
| 272 | struct hlist_node *pos; | 122 | struct hlist_node *pos; |
| 273 | 123 | ||
| 274 | assert_spin_locked(&inode->i_lock); | 124 | assert_spin_locked(&inode->i_lock); |
| 275 | 125 | ||
| 276 | hlist_for_each_entry(entry, pos, &inode->i_fsnotify_mark_entries, i_list) { | 126 | hlist_for_each_entry(mark, pos, &inode->i_fsnotify_marks, i.i_list) { |
| 277 | if (entry->group == group) { | 127 | if (mark->group == group) { |
| 278 | fsnotify_get_mark(entry); | 128 | fsnotify_get_mark(mark); |
| 279 | return entry; | 129 | return mark; |
| 280 | } | 130 | } |
| 281 | } | 131 | } |
| 282 | return NULL; | 132 | return NULL; |
| 283 | } | 133 | } |
| 284 | 134 | ||
| 285 | /* | 135 | /* |
| 286 | * Nothing fancy, just initialize lists and locks and counters. | 136 | * given a group and inode, find the mark associated with that combination. |
| 137 | * if found take a reference to that mark and return it, else return NULL | ||
| 287 | */ | 138 | */ |
| 288 | void fsnotify_init_mark(struct fsnotify_mark_entry *entry, | 139 | struct fsnotify_mark *fsnotify_find_inode_mark(struct fsnotify_group *group, |
| 289 | void (*free_mark)(struct fsnotify_mark_entry *entry)) | 140 | struct inode *inode) |
| 141 | { | ||
| 142 | struct fsnotify_mark *mark; | ||
| 143 | |||
| 144 | spin_lock(&inode->i_lock); | ||
| 145 | mark = fsnotify_find_inode_mark_locked(group, inode); | ||
| 146 | spin_unlock(&inode->i_lock); | ||
| 290 | 147 | ||
| 148 | return mark; | ||
| 149 | } | ||
| 150 | |||
| 151 | /* | ||
| 152 | * If we are setting a mark mask on an inode mark we should pin the inode | ||
| 153 | * in memory. | ||
| 154 | */ | ||
| 155 | void fsnotify_set_inode_mark_mask_locked(struct fsnotify_mark *mark, | ||
| 156 | __u32 mask) | ||
| 291 | { | 157 | { |
| 292 | spin_lock_init(&entry->lock); | 158 | struct inode *inode; |
| 293 | atomic_set(&entry->refcnt, 1); | 159 | |
| 294 | INIT_HLIST_NODE(&entry->i_list); | 160 | assert_spin_locked(&mark->lock); |
| 295 | entry->group = NULL; | 161 | |
| 296 | entry->mask = 0; | 162 | if (mask && |
| 297 | entry->inode = NULL; | 163 | mark->i.inode && |
| 298 | entry->free_mark = free_mark; | 164 | !(mark->flags & FSNOTIFY_MARK_FLAG_OBJECT_PINNED)) { |
| 165 | mark->flags |= FSNOTIFY_MARK_FLAG_OBJECT_PINNED; | ||
| 166 | inode = igrab(mark->i.inode); | ||
| 167 | /* | ||
| 168 | * we shouldn't be able to get here if the inode wasn't | ||
| 169 | * already safely held in memory. But bug in case it | ||
| 170 | * ever is wrong. | ||
| 171 | */ | ||
| 172 | BUG_ON(!inode); | ||
| 173 | } | ||
| 299 | } | 174 | } |
| 300 | 175 | ||
| 301 | /* | 176 | /* |
| 302 | * Attach an initialized mark entry to a given group and inode. | 177 | * Attach an initialized mark to a given inode. |
| 303 | * These marks may be used for the fsnotify backend to determine which | 178 | * These marks may be used for the fsnotify backend to determine which |
| 304 | * event types should be delivered to which group and for which inodes. | 179 | * event types should be delivered to which group and for which inodes. These |
| 180 | * marks are ordered according to the group's location in memory. | ||
| 305 | */ | 181 | */ |
| 306 | int fsnotify_add_mark(struct fsnotify_mark_entry *entry, | 182 | int fsnotify_add_inode_mark(struct fsnotify_mark *mark, |
| 307 | struct fsnotify_group *group, struct inode *inode) | 183 | struct fsnotify_group *group, struct inode *inode, |
| 184 | int allow_dups) | ||
| 308 | { | 185 | { |
| 309 | struct fsnotify_mark_entry *lentry; | 186 | struct fsnotify_mark *lmark; |
| 187 | struct hlist_node *node, *last = NULL; | ||
| 310 | int ret = 0; | 188 | int ret = 0; |
| 311 | 189 | ||
| 312 | inode = igrab(inode); | 190 | mark->flags |= FSNOTIFY_MARK_FLAG_INODE; |
| 313 | if (unlikely(!inode)) | 191 | |
| 314 | return -EINVAL; | 192 | assert_spin_locked(&mark->lock); |
| 193 | assert_spin_locked(&group->mark_lock); | ||
| 315 | 194 | ||
| 316 | /* | ||
| 317 | * LOCKING ORDER!!!! | ||
| 318 | * entry->lock | ||
| 319 | * group->mark_lock | ||
| 320 | * inode->i_lock | ||
| 321 | */ | ||
| 322 | spin_lock(&entry->lock); | ||
| 323 | spin_lock(&group->mark_lock); | ||
| 324 | spin_lock(&inode->i_lock); | 195 | spin_lock(&inode->i_lock); |
| 325 | 196 | ||
| 326 | lentry = fsnotify_find_mark_entry(group, inode); | 197 | mark->i.inode = inode; |
| 327 | if (!lentry) { | ||
| 328 | entry->group = group; | ||
| 329 | entry->inode = inode; | ||
| 330 | 198 | ||
| 331 | hlist_add_head(&entry->i_list, &inode->i_fsnotify_mark_entries); | 199 | /* is mark the first mark? */ |
| 332 | list_add(&entry->g_list, &group->mark_entries); | 200 | if (hlist_empty(&inode->i_fsnotify_marks)) { |
| 201 | hlist_add_head_rcu(&mark->i.i_list, &inode->i_fsnotify_marks); | ||
| 202 | goto out; | ||
| 203 | } | ||
| 333 | 204 | ||
| 334 | fsnotify_get_mark(entry); /* for i_list and g_list */ | 205 | /* should mark be in the middle of the current list? */ |
| 206 | hlist_for_each_entry(lmark, node, &inode->i_fsnotify_marks, i.i_list) { | ||
| 207 | last = node; | ||
| 208 | |||
| 209 | if ((lmark->group == group) && !allow_dups) { | ||
| 210 | ret = -EEXIST; | ||
| 211 | goto out; | ||
| 212 | } | ||
| 335 | 213 | ||
| 336 | atomic_inc(&group->num_marks); | 214 | if (mark->group < lmark->group) |
| 215 | continue; | ||
| 337 | 216 | ||
| 338 | fsnotify_recalc_inode_mask_locked(inode); | 217 | hlist_add_before_rcu(&mark->i.i_list, &lmark->i.i_list); |
| 218 | goto out; | ||
| 339 | } | 219 | } |
| 340 | 220 | ||
| 221 | BUG_ON(last == NULL); | ||
| 222 | /* mark should be the last entry. last is the current last entry */ | ||
| 223 | hlist_add_after_rcu(last, &mark->i.i_list); | ||
| 224 | out: | ||
| 225 | fsnotify_recalc_inode_mask_locked(inode); | ||
| 341 | spin_unlock(&inode->i_lock); | 226 | spin_unlock(&inode->i_lock); |
| 342 | spin_unlock(&group->mark_lock); | ||
| 343 | spin_unlock(&entry->lock); | ||
| 344 | |||
| 345 | if (lentry) { | ||
| 346 | ret = -EEXIST; | ||
| 347 | iput(inode); | ||
| 348 | fsnotify_put_mark(lentry); | ||
| 349 | } else { | ||
| 350 | __fsnotify_update_child_dentry_flags(inode); | ||
| 351 | } | ||
| 352 | 227 | ||
| 353 | return ret; | 228 | return ret; |
| 354 | } | 229 | } |
| @@ -369,11 +244,11 @@ void fsnotify_unmount_inodes(struct list_head *list) | |||
| 369 | struct inode *need_iput_tmp; | 244 | struct inode *need_iput_tmp; |
| 370 | 245 | ||
| 371 | /* | 246 | /* |
| 372 | * We cannot __iget() an inode in state I_CLEAR, I_FREEING, | 247 | * We cannot __iget() an inode in state I_FREEING, |
| 373 | * I_WILL_FREE, or I_NEW which is fine because by that point | 248 | * I_WILL_FREE, or I_NEW which is fine because by that point |
| 374 | * the inode cannot have any associated watches. | 249 | * the inode cannot have any associated watches. |
| 375 | */ | 250 | */ |
| 376 | if (inode->i_state & (I_CLEAR|I_FREEING|I_WILL_FREE|I_NEW)) | 251 | if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) |
| 377 | continue; | 252 | continue; |
| 378 | 253 | ||
| 379 | /* | 254 | /* |
| @@ -397,7 +272,7 @@ void fsnotify_unmount_inodes(struct list_head *list) | |||
| 397 | /* In case the dropping of a reference would nuke next_i. */ | 272 | /* In case the dropping of a reference would nuke next_i. */ |
| 398 | if ((&next_i->i_sb_list != list) && | 273 | if ((&next_i->i_sb_list != list) && |
| 399 | atomic_read(&next_i->i_count) && | 274 | atomic_read(&next_i->i_count) && |
| 400 | !(next_i->i_state & (I_CLEAR | I_FREEING | I_WILL_FREE))) { | 275 | !(next_i->i_state & (I_FREEING | I_WILL_FREE))) { |
| 401 | __iget(next_i); | 276 | __iget(next_i); |
| 402 | need_iput = next_i; | 277 | need_iput = next_i; |
| 403 | } | 278 | } |
diff --git a/fs/notify/inotify/Kconfig b/fs/notify/inotify/Kconfig index b3a159b21cfd..b981fc0c8379 100644 --- a/fs/notify/inotify/Kconfig +++ b/fs/notify/inotify/Kconfig | |||
| @@ -1,18 +1,3 @@ | |||
| 1 | config INOTIFY | ||
| 2 | bool "Inotify file change notification support" | ||
| 3 | default n | ||
| 4 | ---help--- | ||
| 5 | Say Y here to enable legacy in kernel inotify support. Inotify is a | ||
| 6 | file change notification system. It is a replacement for dnotify. | ||
| 7 | This option only provides the legacy inotify in kernel API. There | ||
| 8 | are no in tree kernel users of this interface since it is deprecated. | ||
| 9 | You only need this if you are loading an out of tree kernel module | ||
| 10 | that uses inotify. | ||
| 11 | |||
| 12 | For more information, see <file:Documentation/filesystems/inotify.txt> | ||
| 13 | |||
| 14 | If unsure, say N. | ||
| 15 | |||
| 16 | config INOTIFY_USER | 1 | config INOTIFY_USER |
| 17 | bool "Inotify support for userspace" | 2 | bool "Inotify support for userspace" |
| 18 | select ANON_INODES | 3 | select ANON_INODES |
diff --git a/fs/notify/inotify/Makefile b/fs/notify/inotify/Makefile index 943828171362..a380dabe09de 100644 --- a/fs/notify/inotify/Makefile +++ b/fs/notify/inotify/Makefile | |||
| @@ -1,2 +1 @@ | |||
| 1 | obj-$(CONFIG_INOTIFY) += inotify.o | ||
| 2 | obj-$(CONFIG_INOTIFY_USER) += inotify_fsnotify.o inotify_user.o | obj-$(CONFIG_INOTIFY_USER) += inotify_fsnotify.o inotify_user.o | |
diff --git a/fs/notify/inotify/inotify.c b/fs/notify/inotify/inotify.c deleted file mode 100644 index 27b75ebc7460..000000000000 --- a/fs/notify/inotify/inotify.c +++ /dev/null | |||
| @@ -1,873 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * fs/inotify.c - inode-based file event notifications | ||
| 3 | * | ||
| 4 | * Authors: | ||
| 5 | * John McCutchan <ttb@tentacle.dhs.org> | ||
| 6 | * Robert Love <rml@novell.com> | ||
| 7 | * | ||
| 8 | * Kernel API added by: Amy Griffis <amy.griffis@hp.com> | ||
| 9 | * | ||
| 10 | * Copyright (C) 2005 John McCutchan | ||
| 11 | * Copyright 2006 Hewlett-Packard Development Company, L.P. | ||
| 12 | * | ||
| 13 | * This program is free software; you can redistribute it and/or modify it | ||
| 14 | * under the terms of the GNU General Public License as published by the | ||
| 15 | * Free Software Foundation; either version 2, or (at your option) any | ||
| 16 | * later version. | ||
| 17 | * | ||
| 18 | * This program is distributed in the hope that it will be useful, but | ||
| 19 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 21 | * General Public License for more details. | ||
| 22 | */ | ||
| 23 | |||
| 24 | #include <linux/module.h> | ||
| 25 | #include <linux/kernel.h> | ||
| 26 | #include <linux/spinlock.h> | ||
| 27 | #include <linux/idr.h> | ||
| 28 | #include <linux/slab.h> | ||
| 29 | #include <linux/fs.h> | ||
| 30 | #include <linux/sched.h> | ||
| 31 | #include <linux/init.h> | ||
| 32 | #include <linux/list.h> | ||
| 33 | #include <linux/writeback.h> | ||
| 34 | #include <linux/inotify.h> | ||
| 35 | #include <linux/fsnotify_backend.h> | ||
| 36 | |||
| 37 | static atomic_t inotify_cookie; | ||
| 38 | |||
| 39 | /* | ||
| 40 | * Lock ordering: | ||
| 41 | * | ||
| 42 | * dentry->d_lock (used to keep d_move() away from dentry->d_parent) | ||
| 43 | * iprune_mutex (synchronize shrink_icache_memory()) | ||
| 44 | * inode_lock (protects the super_block->s_inodes list) | ||
| 45 | * inode->inotify_mutex (protects inode->inotify_watches and watches->i_list) | ||
| 46 | * inotify_handle->mutex (protects inotify_handle and watches->h_list) | ||
| 47 | * | ||
| 48 | * The inode->inotify_mutex and inotify_handle->mutex and held during execution | ||
| 49 | * of a caller's event handler. Thus, the caller must not hold any locks | ||
| 50 | * taken in their event handler while calling any of the published inotify | ||
| 51 | * interfaces. | ||
| 52 | */ | ||
| 53 | |||
| 54 | /* | ||
| 55 | * Lifetimes of the three main data structures--inotify_handle, inode, and | ||
| 56 | * inotify_watch--are managed by reference count. | ||
| 57 | * | ||
| 58 | * inotify_handle: Lifetime is from inotify_init() to inotify_destroy(). | ||
| 59 | * Additional references can bump the count via get_inotify_handle() and drop | ||
| 60 | * the count via put_inotify_handle(). | ||
| 61 | * | ||
| 62 | * inotify_watch: for inotify's purposes, lifetime is from inotify_add_watch() | ||
| 63 | * to remove_watch_no_event(). Additional references can bump the count via | ||
| 64 | * get_inotify_watch() and drop the count via put_inotify_watch(). The caller | ||
| 65 | * is reponsible for the final put after receiving IN_IGNORED, or when using | ||
| 66 | * IN_ONESHOT after receiving the first event. Inotify does the final put if | ||
| 67 | * inotify_destroy() is called. | ||
| 68 | * | ||
| 69 | * inode: Pinned so long as the inode is associated with a watch, from | ||
| 70 | * inotify_add_watch() to the final put_inotify_watch(). | ||
| 71 | */ | ||
| 72 | |||
| 73 | /* | ||
| 74 | * struct inotify_handle - represents an inotify instance | ||
| 75 | * | ||
| 76 | * This structure is protected by the mutex 'mutex'. | ||
| 77 | */ | ||
| 78 | struct inotify_handle { | ||
| 79 | struct idr idr; /* idr mapping wd -> watch */ | ||
| 80 | struct mutex mutex; /* protects this bad boy */ | ||
| 81 | struct list_head watches; /* list of watches */ | ||
| 82 | atomic_t count; /* reference count */ | ||
| 83 | u32 last_wd; /* the last wd allocated */ | ||
| 84 | const struct inotify_operations *in_ops; /* inotify caller operations */ | ||
| 85 | }; | ||
| 86 | |||
| 87 | static inline void get_inotify_handle(struct inotify_handle *ih) | ||
| 88 | { | ||
| 89 | atomic_inc(&ih->count); | ||
| 90 | } | ||
| 91 | |||
| 92 | static inline void put_inotify_handle(struct inotify_handle *ih) | ||
| 93 | { | ||
| 94 | if (atomic_dec_and_test(&ih->count)) { | ||
| 95 | idr_destroy(&ih->idr); | ||
| 96 | kfree(ih); | ||
| 97 | } | ||
| 98 | } | ||
| 99 | |||
| 100 | /** | ||
| 101 | * get_inotify_watch - grab a reference to an inotify_watch | ||
| 102 | * @watch: watch to grab | ||
| 103 | */ | ||
| 104 | void get_inotify_watch(struct inotify_watch *watch) | ||
| 105 | { | ||
| 106 | atomic_inc(&watch->count); | ||
| 107 | } | ||
| 108 | EXPORT_SYMBOL_GPL(get_inotify_watch); | ||
| 109 | |||
| 110 | int pin_inotify_watch(struct inotify_watch *watch) | ||
| 111 | { | ||
| 112 | struct super_block *sb = watch->inode->i_sb; | ||
| 113 | if (atomic_inc_not_zero(&sb->s_active)) { | ||
| 114 | atomic_inc(&watch->count); | ||
| 115 | return 1; | ||
| 116 | } | ||
| 117 | return 0; | ||
| 118 | } | ||
| 119 | |||
| 120 | /** | ||
| 121 | * put_inotify_watch - decrements the ref count on a given watch. cleans up | ||
| 122 | * watch references if the count reaches zero. inotify_watch is freed by | ||
| 123 | * inotify callers via the destroy_watch() op. | ||
| 124 | * @watch: watch to release | ||
| 125 | */ | ||
| 126 | void put_inotify_watch(struct inotify_watch *watch) | ||
| 127 | { | ||
| 128 | if (atomic_dec_and_test(&watch->count)) { | ||
| 129 | struct inotify_handle *ih = watch->ih; | ||
| 130 | |||
| 131 | iput(watch->inode); | ||
| 132 | ih->in_ops->destroy_watch(watch); | ||
| 133 | put_inotify_handle(ih); | ||
| 134 | } | ||
| 135 | } | ||
| 136 | EXPORT_SYMBOL_GPL(put_inotify_watch); | ||
| 137 | |||
| 138 | void unpin_inotify_watch(struct inotify_watch *watch) | ||
| 139 | { | ||
| 140 | struct super_block *sb = watch->inode->i_sb; | ||
| 141 | put_inotify_watch(watch); | ||
| 142 | deactivate_super(sb); | ||
| 143 | } | ||
| 144 | |||
| 145 | /* | ||
| 146 | * inotify_handle_get_wd - returns the next WD for use by the given handle | ||
| 147 | * | ||
| 148 | * Callers must hold ih->mutex. This function can sleep. | ||
| 149 | */ | ||
| 150 | static int inotify_handle_get_wd(struct inotify_handle *ih, | ||
| 151 | struct inotify_watch *watch) | ||
| 152 | { | ||
| 153 | int ret; | ||
| 154 | |||
| 155 | do { | ||
| 156 | if (unlikely(!idr_pre_get(&ih->idr, GFP_NOFS))) | ||
| 157 | return -ENOSPC; | ||
| 158 | ret = idr_get_new_above(&ih->idr, watch, ih->last_wd+1, &watch->wd); | ||
| 159 | } while (ret == -EAGAIN); | ||
| 160 | |||
| 161 | if (likely(!ret)) | ||
| 162 | ih->last_wd = watch->wd; | ||
| 163 | |||
| 164 | return ret; | ||
| 165 | } | ||
| 166 | |||
| 167 | /* | ||
| 168 | * inotify_inode_watched - returns nonzero if there are watches on this inode | ||
| 169 | * and zero otherwise. We call this lockless, we do not care if we race. | ||
| 170 | */ | ||
| 171 | static inline int inotify_inode_watched(struct inode *inode) | ||
| 172 | { | ||
| 173 | return !list_empty(&inode->inotify_watches); | ||
| 174 | } | ||
| 175 | |||
| 176 | /* | ||
| 177 | * Get child dentry flag into synch with parent inode. | ||
| 178 | * Flag should always be clear for negative dentrys. | ||
| 179 | */ | ||
| 180 | static void set_dentry_child_flags(struct inode *inode, int watched) | ||
| 181 | { | ||
| 182 | struct dentry *alias; | ||
| 183 | |||
| 184 | spin_lock(&dcache_lock); | ||
| 185 | list_for_each_entry(alias, &inode->i_dentry, d_alias) { | ||
| 186 | struct dentry *child; | ||
| 187 | |||
| 188 | list_for_each_entry(child, &alias->d_subdirs, d_u.d_child) { | ||
| 189 | if (!child->d_inode) | ||
| 190 | continue; | ||
| 191 | |||
| 192 | spin_lock(&child->d_lock); | ||
| 193 | if (watched) | ||
| 194 | child->d_flags |= DCACHE_INOTIFY_PARENT_WATCHED; | ||
| 195 | else | ||
| 196 | child->d_flags &=~DCACHE_INOTIFY_PARENT_WATCHED; | ||
| 197 | spin_unlock(&child->d_lock); | ||
| 198 | } | ||
| 199 | } | ||
| 200 | spin_unlock(&dcache_lock); | ||
| 201 | } | ||
| 202 | |||
| 203 | /* | ||
| 204 | * inotify_find_handle - find the watch associated with the given inode and | ||
| 205 | * handle | ||
| 206 | * | ||
| 207 | * Callers must hold inode->inotify_mutex. | ||
| 208 | */ | ||
| 209 | static struct inotify_watch *inode_find_handle(struct inode *inode, | ||
| 210 | struct inotify_handle *ih) | ||
| 211 | { | ||
| 212 | struct inotify_watch *watch; | ||
| 213 | |||
| 214 | list_for_each_entry(watch, &inode->inotify_watches, i_list) { | ||
| 215 | if (watch->ih == ih) | ||
| 216 | return watch; | ||
| 217 | } | ||
| 218 | |||
| 219 | return NULL; | ||
| 220 | } | ||
| 221 | |||
| 222 | /* | ||
| 223 | * remove_watch_no_event - remove watch without the IN_IGNORED event. | ||
| 224 | * | ||
| 225 | * Callers must hold both inode->inotify_mutex and ih->mutex. | ||
| 226 | */ | ||
| 227 | static void remove_watch_no_event(struct inotify_watch *watch, | ||
| 228 | struct inotify_handle *ih) | ||
| 229 | { | ||
| 230 | list_del(&watch->i_list); | ||
| 231 | list_del(&watch->h_list); | ||
| 232 | |||
| 233 | if (!inotify_inode_watched(watch->inode)) | ||
| 234 | set_dentry_child_flags(watch->inode, 0); | ||
| 235 | |||
| 236 | idr_remove(&ih->idr, watch->wd); | ||
| 237 | } | ||
| 238 | |||
| 239 | /** | ||
| 240 | * inotify_remove_watch_locked - Remove a watch from both the handle and the | ||
| 241 | * inode. Sends the IN_IGNORED event signifying that the inode is no longer | ||
| 242 | * watched. May be invoked from a caller's event handler. | ||
| 243 | * @ih: inotify handle associated with watch | ||
| 244 | * @watch: watch to remove | ||
| 245 | * | ||
| 246 | * Callers must hold both inode->inotify_mutex and ih->mutex. | ||
| 247 | */ | ||
| 248 | void inotify_remove_watch_locked(struct inotify_handle *ih, | ||
| 249 | struct inotify_watch *watch) | ||
| 250 | { | ||
| 251 | remove_watch_no_event(watch, ih); | ||
| 252 | ih->in_ops->handle_event(watch, watch->wd, IN_IGNORED, 0, NULL, NULL); | ||
| 253 | } | ||
| 254 | EXPORT_SYMBOL_GPL(inotify_remove_watch_locked); | ||
| 255 | |||
| 256 | /* Kernel API for producing events */ | ||
| 257 | |||
| 258 | /* | ||
| 259 | * inotify_d_instantiate - instantiate dcache entry for inode | ||
| 260 | */ | ||
| 261 | void inotify_d_instantiate(struct dentry *entry, struct inode *inode) | ||
| 262 | { | ||
| 263 | struct dentry *parent; | ||
| 264 | |||
| 265 | if (!inode) | ||
| 266 | return; | ||
| 267 | |||
| 268 | spin_lock(&entry->d_lock); | ||
| 269 | parent = entry->d_parent; | ||
| 270 | if (parent->d_inode && inotify_inode_watched(parent->d_inode)) | ||
| 271 | entry->d_flags |= DCACHE_INOTIFY_PARENT_WATCHED; | ||
| 272 | spin_unlock(&entry->d_lock); | ||
| 273 | } | ||
| 274 | |||
| 275 | /* | ||
| 276 | * inotify_d_move - dcache entry has been moved | ||
| 277 | */ | ||
| 278 | void inotify_d_move(struct dentry *entry) | ||
| 279 | { | ||
| 280 | struct dentry *parent; | ||
| 281 | |||
| 282 | parent = entry->d_parent; | ||
| 283 | if (inotify_inode_watched(parent->d_inode)) | ||
| 284 | entry->d_flags |= DCACHE_INOTIFY_PARENT_WATCHED; | ||
| 285 | else | ||
| 286 | entry->d_flags &= ~DCACHE_INOTIFY_PARENT_WATCHED; | ||
| 287 | } | ||
| 288 | |||
| 289 | /** | ||
| 290 | * inotify_inode_queue_event - queue an event to all watches on this inode | ||
| 291 | * @inode: inode event is originating from | ||
| 292 | * @mask: event mask describing this event | ||
| 293 | * @cookie: cookie for synchronization, or zero | ||
| 294 | * @name: filename, if any | ||
| 295 | * @n_inode: inode associated with name | ||
| 296 | */ | ||
| 297 | void inotify_inode_queue_event(struct inode *inode, u32 mask, u32 cookie, | ||
| 298 | const char *name, struct inode *n_inode) | ||
| 299 | { | ||
| 300 | struct inotify_watch *watch, *next; | ||
| 301 | |||
| 302 | if (!inotify_inode_watched(inode)) | ||
| 303 | return; | ||
| 304 | |||
| 305 | mutex_lock(&inode->inotify_mutex); | ||
| 306 | list_for_each_entry_safe(watch, next, &inode->inotify_watches, i_list) { | ||
| 307 | u32 watch_mask = watch->mask; | ||
| 308 | if (watch_mask & mask) { | ||
| 309 | struct inotify_handle *ih= watch->ih; | ||
| 310 | mutex_lock(&ih->mutex); | ||
| 311 | if (watch_mask & IN_ONESHOT) | ||
| 312 | remove_watch_no_event(watch, ih); | ||
| 313 | ih->in_ops->handle_event(watch, watch->wd, mask, cookie, | ||
| 314 | name, n_inode); | ||
| 315 | mutex_unlock(&ih->mutex); | ||
| 316 | } | ||
| 317 | } | ||
| 318 | mutex_unlock(&inode->inotify_mutex); | ||
| 319 | } | ||
| 320 | EXPORT_SYMBOL_GPL(inotify_inode_queue_event); | ||
| 321 | |||
| 322 | /** | ||
| 323 | * inotify_dentry_parent_queue_event - queue an event to a dentry's parent | ||
| 324 | * @dentry: the dentry in question, we queue against this dentry's parent | ||
| 325 | * @mask: event mask describing this event | ||
| 326 | * @cookie: cookie for synchronization, or zero | ||
| 327 | * @name: filename, if any | ||
| 328 | */ | ||
| 329 | void inotify_dentry_parent_queue_event(struct dentry *dentry, u32 mask, | ||
| 330 | u32 cookie, const char *name) | ||
| 331 | { | ||
| 332 | struct dentry *parent; | ||
| 333 | struct inode *inode; | ||
| 334 | |||
| 335 | if (!(dentry->d_flags & DCACHE_INOTIFY_PARENT_WATCHED)) | ||
| 336 | return; | ||
| 337 | |||
| 338 | spin_lock(&dentry->d_lock); | ||
| 339 | parent = dentry->d_parent; | ||
| 340 | inode = parent->d_inode; | ||
| 341 | |||
| 342 | if (inotify_inode_watched(inode)) { | ||
| 343 | dget(parent); | ||
| 344 | spin_unlock(&dentry->d_lock); | ||
| 345 | inotify_inode_queue_event(inode, mask, cookie, name, | ||
| 346 | dentry->d_inode); | ||
| 347 | dput(parent); | ||
| 348 | } else | ||
| 349 | spin_unlock(&dentry->d_lock); | ||
| 350 | } | ||
| 351 | EXPORT_SYMBOL_GPL(inotify_dentry_parent_queue_event); | ||
| 352 | |||
| 353 | /** | ||
| 354 | * inotify_get_cookie - return a unique cookie for use in synchronizing events. | ||
| 355 | */ | ||
| 356 | u32 inotify_get_cookie(void) | ||
| 357 | { | ||
| 358 | return atomic_inc_return(&inotify_cookie); | ||
| 359 | } | ||
| 360 | EXPORT_SYMBOL_GPL(inotify_get_cookie); | ||
| 361 | |||
| 362 | /** | ||
| 363 | * inotify_unmount_inodes - an sb is unmounting. handle any watched inodes. | ||
| 364 | * @list: list of inodes being unmounted (sb->s_inodes) | ||
| 365 | * | ||
| 366 | * Called with inode_lock held, protecting the unmounting super block's list | ||
| 367 | * of inodes, and with iprune_mutex held, keeping shrink_icache_memory() at bay. | ||
| 368 | * We temporarily drop inode_lock, however, and CAN block. | ||
| 369 | */ | ||
| 370 | void inotify_unmount_inodes(struct list_head *list) | ||
| 371 | { | ||
| 372 | struct inode *inode, *next_i, *need_iput = NULL; | ||
| 373 | |||
| 374 | list_for_each_entry_safe(inode, next_i, list, i_sb_list) { | ||
| 375 | struct inotify_watch *watch, *next_w; | ||
| 376 | struct inode *need_iput_tmp; | ||
| 377 | struct list_head *watches; | ||
| 378 | |||
| 379 | /* | ||
| 380 | * We cannot __iget() an inode in state I_CLEAR, I_FREEING, | ||
| 381 | * I_WILL_FREE, or I_NEW which is fine because by that point | ||
| 382 | * the inode cannot have any associated watches. | ||
| 383 | */ | ||
| 384 | if (inode->i_state & (I_CLEAR|I_FREEING|I_WILL_FREE|I_NEW)) | ||
| 385 | continue; | ||
| 386 | |||
| 387 | /* | ||
| 388 | * If i_count is zero, the inode cannot have any watches and | ||
| 389 | * doing an __iget/iput with MS_ACTIVE clear would actually | ||
| 390 | * evict all inodes with zero i_count from icache which is | ||
| 391 | * unnecessarily violent and may in fact be illegal to do. | ||
| 392 | */ | ||
| 393 | if (!atomic_read(&inode->i_count)) | ||
| 394 | continue; | ||
| 395 | |||
| 396 | need_iput_tmp = need_iput; | ||
| 397 | need_iput = NULL; | ||
| 398 | /* In case inotify_remove_watch_locked() drops a reference. */ | ||
| 399 | if (inode != need_iput_tmp) | ||
| 400 | __iget(inode); | ||
| 401 | else | ||
| 402 | need_iput_tmp = NULL; | ||
| 403 | /* In case the dropping of a reference would nuke next_i. */ | ||
| 404 | if ((&next_i->i_sb_list != list) && | ||
| 405 | atomic_read(&next_i->i_count) && | ||
| 406 | !(next_i->i_state & (I_CLEAR | I_FREEING | | ||
| 407 | I_WILL_FREE))) { | ||
| 408 | __iget(next_i); | ||
| 409 | need_iput = next_i; | ||
| 410 | } | ||
| 411 | |||
| 412 | /* | ||
| 413 | * We can safely drop inode_lock here because we hold | ||
| 414 | * references on both inode and next_i. Also no new inodes | ||
| 415 | * will be added since the umount has begun. Finally, | ||
| 416 | * iprune_mutex keeps shrink_icache_memory() away. | ||
| 417 | */ | ||
| 418 | spin_unlock(&inode_lock); | ||
| 419 | |||
| 420 | if (need_iput_tmp) | ||
| 421 | iput(need_iput_tmp); | ||
| 422 | |||
| 423 | /* for each watch, send IN_UNMOUNT and then remove it */ | ||
| 424 | mutex_lock(&inode->inotify_mutex); | ||
| 425 | watches = &inode->inotify_watches; | ||
| 426 | list_for_each_entry_safe(watch, next_w, watches, i_list) { | ||
| 427 | struct inotify_handle *ih= watch->ih; | ||
| 428 | get_inotify_watch(watch); | ||
| 429 | mutex_lock(&ih->mutex); | ||
| 430 | ih->in_ops->handle_event(watch, watch->wd, IN_UNMOUNT, 0, | ||
| 431 | NULL, NULL); | ||
| 432 | inotify_remove_watch_locked(ih, watch); | ||
| 433 | mutex_unlock(&ih->mutex); | ||
| 434 | put_inotify_watch(watch); | ||
| 435 | } | ||
| 436 | mutex_unlock(&inode->inotify_mutex); | ||
| 437 | iput(inode); | ||
| 438 | |||
| 439 | spin_lock(&inode_lock); | ||
| 440 | } | ||
| 441 | } | ||
| 442 | EXPORT_SYMBOL_GPL(inotify_unmount_inodes); | ||
| 443 | |||
| 444 | /** | ||
| 445 | * inotify_inode_is_dead - an inode has been deleted, cleanup any watches | ||
| 446 | * @inode: inode that is about to be removed | ||
| 447 | */ | ||
| 448 | void inotify_inode_is_dead(struct inode *inode) | ||
| 449 | { | ||
| 450 | struct inotify_watch *watch, *next; | ||
| 451 | |||
| 452 | mutex_lock(&inode->inotify_mutex); | ||
| 453 | list_for_each_entry_safe(watch, next, &inode->inotify_watches, i_list) { | ||
| 454 | struct inotify_handle *ih = watch->ih; | ||
| 455 | mutex_lock(&ih->mutex); | ||
| 456 | inotify_remove_watch_locked(ih, watch); | ||
| 457 | mutex_unlock(&ih->mutex); | ||
| 458 | } | ||
| 459 | mutex_unlock(&inode->inotify_mutex); | ||
| 460 | } | ||
| 461 | EXPORT_SYMBOL_GPL(inotify_inode_is_dead); | ||
| 462 | |||
| 463 | /* Kernel Consumer API */ | ||
| 464 | |||
| 465 | /** | ||
| 466 | * inotify_init - allocate and initialize an inotify instance | ||
| 467 | * @ops: caller's inotify operations | ||
| 468 | */ | ||
| 469 | struct inotify_handle *inotify_init(const struct inotify_operations *ops) | ||
| 470 | { | ||
| 471 | struct inotify_handle *ih; | ||
| 472 | |||
| 473 | ih = kmalloc(sizeof(struct inotify_handle), GFP_KERNEL); | ||
| 474 | if (unlikely(!ih)) | ||
| 475 | return ERR_PTR(-ENOMEM); | ||
| 476 | |||
| 477 | idr_init(&ih->idr); | ||
| 478 | INIT_LIST_HEAD(&ih->watches); | ||
| 479 | mutex_init(&ih->mutex); | ||
| 480 | ih->last_wd = 0; | ||
| 481 | ih->in_ops = ops; | ||
| 482 | atomic_set(&ih->count, 0); | ||
| 483 | get_inotify_handle(ih); | ||
| 484 | |||
| 485 | return ih; | ||
| 486 | } | ||
| 487 | EXPORT_SYMBOL_GPL(inotify_init); | ||
| 488 | |||
| 489 | /** | ||
| 490 | * inotify_init_watch - initialize an inotify watch | ||
| 491 | * @watch: watch to initialize | ||
| 492 | */ | ||
| 493 | void inotify_init_watch(struct inotify_watch *watch) | ||
| 494 | { | ||
| 495 | INIT_LIST_HEAD(&watch->h_list); | ||
| 496 | INIT_LIST_HEAD(&watch->i_list); | ||
| 497 | atomic_set(&watch->count, 0); | ||
| 498 | get_inotify_watch(watch); /* initial get */ | ||
| 499 | } | ||
| 500 | EXPORT_SYMBOL_GPL(inotify_init_watch); | ||
| 501 | |||
| 502 | /* | ||
| 503 | * Watch removals suck violently. To kick the watch out we need (in this | ||
| 504 | * order) inode->inotify_mutex and ih->mutex. That's fine if we have | ||
| 505 | * a hold on inode; however, for all other cases we need to make damn sure | ||
| 506 | * we don't race with umount. We can *NOT* just grab a reference to a | ||
| 507 | * watch - inotify_unmount_inodes() will happily sail past it and we'll end | ||
| 508 | * with reference to inode potentially outliving its superblock. Ideally | ||
| 509 | * we just want to grab an active reference to superblock if we can; that | ||
| 510 | * will make sure we won't go into inotify_umount_inodes() until we are | ||
| 511 | * done. Cleanup is just deactivate_super(). However, that leaves a messy | ||
| 512 | * case - what if we *are* racing with umount() and active references to | ||
| 513 | * superblock can't be acquired anymore? We can bump ->s_count, grab | ||
| 514 | * ->s_umount, which will wait until the superblock is shut down and the | ||
| 515 | * watch in question is pining for fjords. | ||
| 516 | * | ||
| 517 | * And yes, this is far beyond mere "not very pretty"; so's the entire | ||
| 518 | * concept of inotify to start with. | ||
| 519 | */ | ||
| 520 | |||
| 521 | /** | ||
| 522 | * pin_to_kill - pin the watch down for removal | ||
| 523 | * @ih: inotify handle | ||
| 524 | * @watch: watch to kill | ||
| 525 | * | ||
| 526 | * Called with ih->mutex held, drops it. Possible return values: | ||
| 527 | * 0 - nothing to do, it has died | ||
| 528 | * 1 - remove it, drop the reference and deactivate_super() | ||
| 529 | */ | ||
| 530 | static int pin_to_kill(struct inotify_handle *ih, struct inotify_watch *watch) | ||
| 531 | { | ||
| 532 | struct super_block *sb = watch->inode->i_sb; | ||
| 533 | |||
| 534 | if (atomic_inc_not_zero(&sb->s_active)) { | ||
| 535 | get_inotify_watch(watch); | ||
| 536 | mutex_unlock(&ih->mutex); | ||
| 537 | return 1; /* the best outcome */ | ||
| 538 | } | ||
| 539 | spin_lock(&sb_lock); | ||
| 540 | sb->s_count++; | ||
| 541 | spin_unlock(&sb_lock); | ||
| 542 | mutex_unlock(&ih->mutex); /* can't grab ->s_umount under it */ | ||
| 543 | down_read(&sb->s_umount); | ||
| 544 | /* fs is already shut down; the watch is dead */ | ||
| 545 | drop_super(sb); | ||
| 546 | return 0; | ||
| 547 | } | ||
| 548 | |||
| 549 | static void unpin_and_kill(struct inotify_watch *watch) | ||
| 550 | { | ||
| 551 | struct super_block *sb = watch->inode->i_sb; | ||
| 552 | put_inotify_watch(watch); | ||
| 553 | deactivate_super(sb); | ||
| 554 | } | ||
| 555 | |||
| 556 | /** | ||
| 557 | * inotify_destroy - clean up and destroy an inotify instance | ||
| 558 | * @ih: inotify handle | ||
| 559 | */ | ||
| 560 | void inotify_destroy(struct inotify_handle *ih) | ||
| 561 | { | ||
| 562 | /* | ||
| 563 | * Destroy all of the watches for this handle. Unfortunately, not very | ||
| 564 | * pretty. We cannot do a simple iteration over the list, because we | ||
| 565 | * do not know the inode until we iterate to the watch. But we need to | ||
| 566 | * hold inode->inotify_mutex before ih->mutex. The following works. | ||
| 567 | * | ||
| 568 | * AV: it had to become even uglier to start working ;-/ | ||
| 569 | */ | ||
| 570 | while (1) { | ||
| 571 | struct inotify_watch *watch; | ||
| 572 | struct list_head *watches; | ||
| 573 | struct super_block *sb; | ||
| 574 | struct inode *inode; | ||
| 575 | |||
| 576 | mutex_lock(&ih->mutex); | ||
| 577 | watches = &ih->watches; | ||
| 578 | if (list_empty(watches)) { | ||
| 579 | mutex_unlock(&ih->mutex); | ||
| 580 | break; | ||
| 581 | } | ||
| 582 | watch = list_first_entry(watches, struct inotify_watch, h_list); | ||
| 583 | sb = watch->inode->i_sb; | ||
| 584 | if (!pin_to_kill(ih, watch)) | ||
| 585 | continue; | ||
| 586 | |||
| 587 | inode = watch->inode; | ||
| 588 | mutex_lock(&inode->inotify_mutex); | ||
| 589 | mutex_lock(&ih->mutex); | ||
| 590 | |||
| 591 | /* make sure we didn't race with another list removal */ | ||
| 592 | if (likely(idr_find(&ih->idr, watch->wd))) { | ||
| 593 | remove_watch_no_event(watch, ih); | ||
| 594 | put_inotify_watch(watch); | ||
| 595 | } | ||
| 596 | |||
| 597 | mutex_unlock(&ih->mutex); | ||
| 598 | mutex_unlock(&inode->inotify_mutex); | ||
| 599 | unpin_and_kill(watch); | ||
| 600 | } | ||
| 601 | |||
| 602 | /* free this handle: the put matching the get in inotify_init() */ | ||
| 603 | put_inotify_handle(ih); | ||
| 604 | } | ||
| 605 | EXPORT_SYMBOL_GPL(inotify_destroy); | ||
| 606 | |||
| 607 | /** | ||
| 608 | * inotify_find_watch - find an existing watch for an (ih,inode) pair | ||
| 609 | * @ih: inotify handle | ||
| 610 | * @inode: inode to watch | ||
| 611 | * @watchp: pointer to existing inotify_watch | ||
| 612 | * | ||
| 613 | * Caller must pin given inode (via nameidata). | ||
| 614 | */ | ||
| 615 | s32 inotify_find_watch(struct inotify_handle *ih, struct inode *inode, | ||
| 616 | struct inotify_watch **watchp) | ||
| 617 | { | ||
| 618 | struct inotify_watch *old; | ||
| 619 | int ret = -ENOENT; | ||
| 620 | |||
| 621 | mutex_lock(&inode->inotify_mutex); | ||
| 622 | mutex_lock(&ih->mutex); | ||
| 623 | |||
| 624 | old = inode_find_handle(inode, ih); | ||
| 625 | if (unlikely(old)) { | ||
| 626 | get_inotify_watch(old); /* caller must put watch */ | ||
| 627 | *watchp = old; | ||
| 628 | ret = old->wd; | ||
| 629 | } | ||
| 630 | |||
| 631 | mutex_unlock(&ih->mutex); | ||
| 632 | mutex_unlock(&inode->inotify_mutex); | ||
| 633 | |||
| 634 | return ret; | ||
| 635 | } | ||
| 636 | EXPORT_SYMBOL_GPL(inotify_find_watch); | ||
| 637 | |||
| 638 | /** | ||
| 639 | * inotify_find_update_watch - find and update the mask of an existing watch | ||
| 640 | * @ih: inotify handle | ||
| 641 | * @inode: inode's watch to update | ||
| 642 | * @mask: mask of events to watch | ||
| 643 | * | ||
| 644 | * Caller must pin given inode (via nameidata). | ||
| 645 | */ | ||
| 646 | s32 inotify_find_update_watch(struct inotify_handle *ih, struct inode *inode, | ||
| 647 | u32 mask) | ||
| 648 | { | ||
| 649 | struct inotify_watch *old; | ||
| 650 | int mask_add = 0; | ||
| 651 | int ret; | ||
| 652 | |||
| 653 | if (mask & IN_MASK_ADD) | ||
| 654 | mask_add = 1; | ||
| 655 | |||
| 656 | /* don't allow invalid bits: we don't want flags set */ | ||
| 657 | mask &= IN_ALL_EVENTS | IN_ONESHOT; | ||
| 658 | if (unlikely(!mask)) | ||
| 659 | return -EINVAL; | ||
| 660 | |||
| 661 | mutex_lock(&inode->inotify_mutex); | ||
| 662 | mutex_lock(&ih->mutex); | ||
| 663 | |||
| 664 | /* | ||
| 665 | * Handle the case of re-adding a watch on an (inode,ih) pair that we | ||
| 666 | * are already watching. We just update the mask and return its wd. | ||
| 667 | */ | ||
| 668 | old = inode_find_handle(inode, ih); | ||
| 669 | if (unlikely(!old)) { | ||
| 670 | ret = -ENOENT; | ||
| 671 | goto out; | ||
| 672 | } | ||
| 673 | |||
| 674 | if (mask_add) | ||
| 675 | old->mask |= mask; | ||
| 676 | else | ||
| 677 | old->mask = mask; | ||
| 678 | ret = old->wd; | ||
| 679 | out: | ||
| 680 | mutex_unlock(&ih->mutex); | ||
| 681 | mutex_unlock(&inode->inotify_mutex); | ||
| 682 | return ret; | ||
| 683 | } | ||
| 684 | EXPORT_SYMBOL_GPL(inotify_find_update_watch); | ||
| 685 | |||
| 686 | /** | ||
| 687 | * inotify_add_watch - add a watch to an inotify instance | ||
| 688 | * @ih: inotify handle | ||
| 689 | * @watch: caller allocated watch structure | ||
| 690 | * @inode: inode to watch | ||
| 691 | * @mask: mask of events to watch | ||
| 692 | * | ||
| 693 | * Caller must pin given inode (via nameidata). | ||
| 694 | * Caller must ensure it only calls inotify_add_watch() once per watch. | ||
| 695 | * Calls inotify_handle_get_wd() so may sleep. | ||
| 696 | */ | ||
| 697 | s32 inotify_add_watch(struct inotify_handle *ih, struct inotify_watch *watch, | ||
| 698 | struct inode *inode, u32 mask) | ||
| 699 | { | ||
| 700 | int ret = 0; | ||
| 701 | int newly_watched; | ||
| 702 | |||
| 703 | /* don't allow invalid bits: we don't want flags set */ | ||
| 704 | mask &= IN_ALL_EVENTS | IN_ONESHOT; | ||
| 705 | if (unlikely(!mask)) | ||
| 706 | return -EINVAL; | ||
| 707 | watch->mask = mask; | ||
| 708 | |||
| 709 | mutex_lock(&inode->inotify_mutex); | ||
| 710 | mutex_lock(&ih->mutex); | ||
| 711 | |||
| 712 | /* Initialize a new watch */ | ||
| 713 | ret = inotify_handle_get_wd(ih, watch); | ||
| 714 | if (unlikely(ret)) | ||
| 715 | goto out; | ||
| 716 | ret = watch->wd; | ||
| 717 | |||
| 718 | /* save a reference to handle and bump the count to make it official */ | ||
| 719 | get_inotify_handle(ih); | ||
| 720 | watch->ih = ih; | ||
| 721 | |||
| 722 | /* | ||
| 723 | * Save a reference to the inode and bump the ref count to make it | ||
| 724 | * official. We hold a reference to nameidata, which makes this safe. | ||
| 725 | */ | ||
| 726 | watch->inode = igrab(inode); | ||
| 727 | |||
| 728 | /* Add the watch to the handle's and the inode's list */ | ||
| 729 | newly_watched = !inotify_inode_watched(inode); | ||
| 730 | list_add(&watch->h_list, &ih->watches); | ||
| 731 | list_add(&watch->i_list, &inode->inotify_watches); | ||
| 732 | /* | ||
| 733 | * Set child flags _after_ adding the watch, so there is no race | ||
| 734 | * windows where newly instantiated children could miss their parent's | ||
| 735 | * watched flag. | ||
| 736 | */ | ||
| 737 | if (newly_watched) | ||
| 738 | set_dentry_child_flags(inode, 1); | ||
| 739 | |||
| 740 | out: | ||
| 741 | mutex_unlock(&ih->mutex); | ||
| 742 | mutex_unlock(&inode->inotify_mutex); | ||
| 743 | return ret; | ||
| 744 | } | ||
| 745 | EXPORT_SYMBOL_GPL(inotify_add_watch); | ||
| 746 | |||
| 747 | /** | ||
| 748 | * inotify_clone_watch - put the watch next to existing one | ||
| 749 | * @old: already installed watch | ||
| 750 | * @new: new watch | ||
| 751 | * | ||
| 752 | * Caller must hold the inotify_mutex of inode we are dealing with; | ||
| 753 | * it is expected to remove the old watch before unlocking the inode. | ||
| 754 | */ | ||
| 755 | s32 inotify_clone_watch(struct inotify_watch *old, struct inotify_watch *new) | ||
| 756 | { | ||
| 757 | struct inotify_handle *ih = old->ih; | ||
| 758 | int ret = 0; | ||
| 759 | |||
| 760 | new->mask = old->mask; | ||
| 761 | new->ih = ih; | ||
| 762 | |||
| 763 | mutex_lock(&ih->mutex); | ||
| 764 | |||
| 765 | /* Initialize a new watch */ | ||
| 766 | ret = inotify_handle_get_wd(ih, new); | ||
| 767 | if (unlikely(ret)) | ||
| 768 | goto out; | ||
| 769 | ret = new->wd; | ||
| 770 | |||
| 771 | get_inotify_handle(ih); | ||
| 772 | |||
| 773 | new->inode = igrab(old->inode); | ||
| 774 | |||
| 775 | list_add(&new->h_list, &ih->watches); | ||
| 776 | list_add(&new->i_list, &old->inode->inotify_watches); | ||
| 777 | out: | ||
| 778 | mutex_unlock(&ih->mutex); | ||
| 779 | return ret; | ||
| 780 | } | ||
| 781 | |||
| 782 | void inotify_evict_watch(struct inotify_watch *watch) | ||
| 783 | { | ||
| 784 | get_inotify_watch(watch); | ||
| 785 | mutex_lock(&watch->ih->mutex); | ||
| 786 | inotify_remove_watch_locked(watch->ih, watch); | ||
| 787 | mutex_unlock(&watch->ih->mutex); | ||
| 788 | } | ||
| 789 | |||
| 790 | /** | ||
| 791 | * inotify_rm_wd - remove a watch from an inotify instance | ||
| 792 | * @ih: inotify handle | ||
| 793 | * @wd: watch descriptor to remove | ||
| 794 | * | ||
| 795 | * Can sleep. | ||
| 796 | */ | ||
| 797 | int inotify_rm_wd(struct inotify_handle *ih, u32 wd) | ||
| 798 | { | ||
| 799 | struct inotify_watch *watch; | ||
| 800 | struct super_block *sb; | ||
| 801 | struct inode *inode; | ||
| 802 | |||
| 803 | mutex_lock(&ih->mutex); | ||
| 804 | watch = idr_find(&ih->idr, wd); | ||
| 805 | if (unlikely(!watch)) { | ||
| 806 | mutex_unlock(&ih->mutex); | ||
| 807 | return -EINVAL; | ||
| 808 | } | ||
| 809 | sb = watch->inode->i_sb; | ||
| 810 | if (!pin_to_kill(ih, watch)) | ||
| 811 | return 0; | ||
| 812 | |||
| 813 | inode = watch->inode; | ||
| 814 | |||
| 815 | mutex_lock(&inode->inotify_mutex); | ||
| 816 | mutex_lock(&ih->mutex); | ||
| 817 | |||
| 818 | /* make sure that we did not race */ | ||
| 819 | if (likely(idr_find(&ih->idr, wd) == watch)) | ||
| 820 | inotify_remove_watch_locked(ih, watch); | ||
| 821 | |||
| 822 | mutex_unlock(&ih->mutex); | ||
| 823 | mutex_unlock(&inode->inotify_mutex); | ||
| 824 | unpin_and_kill(watch); | ||
| 825 | |||
| 826 | return 0; | ||
| 827 | } | ||
| 828 | EXPORT_SYMBOL_GPL(inotify_rm_wd); | ||
| 829 | |||
| 830 | /** | ||
| 831 | * inotify_rm_watch - remove a watch from an inotify instance | ||
| 832 | * @ih: inotify handle | ||
| 833 | * @watch: watch to remove | ||
| 834 | * | ||
| 835 | * Can sleep. | ||
| 836 | */ | ||
| 837 | int inotify_rm_watch(struct inotify_handle *ih, | ||
| 838 | struct inotify_watch *watch) | ||
| 839 | { | ||
| 840 | return inotify_rm_wd(ih, watch->wd); | ||
| 841 | } | ||
| 842 | EXPORT_SYMBOL_GPL(inotify_rm_watch); | ||
| 843 | |||
| 844 | /* | ||
| 845 | * inotify_setup - core initialization function | ||
| 846 | */ | ||
| 847 | static int __init inotify_setup(void) | ||
| 848 | { | ||
| 849 | BUILD_BUG_ON(IN_ACCESS != FS_ACCESS); | ||
| 850 | BUILD_BUG_ON(IN_MODIFY != FS_MODIFY); | ||
| 851 | BUILD_BUG_ON(IN_ATTRIB != FS_ATTRIB); | ||
| 852 | BUILD_BUG_ON(IN_CLOSE_WRITE != FS_CLOSE_WRITE); | ||
| 853 | BUILD_BUG_ON(IN_CLOSE_NOWRITE != FS_CLOSE_NOWRITE); | ||
| 854 | BUILD_BUG_ON(IN_OPEN != FS_OPEN); | ||
| 855 | BUILD_BUG_ON(IN_MOVED_FROM != FS_MOVED_FROM); | ||
| 856 | BUILD_BUG_ON(IN_MOVED_TO != FS_MOVED_TO); | ||
| 857 | BUILD_BUG_ON(IN_CREATE != FS_CREATE); | ||
| 858 | BUILD_BUG_ON(IN_DELETE != FS_DELETE); | ||
| 859 | BUILD_BUG_ON(IN_DELETE_SELF != FS_DELETE_SELF); | ||
| 860 | BUILD_BUG_ON(IN_MOVE_SELF != FS_MOVE_SELF); | ||
| 861 | BUILD_BUG_ON(IN_Q_OVERFLOW != FS_Q_OVERFLOW); | ||
| 862 | |||
| 863 | BUILD_BUG_ON(IN_UNMOUNT != FS_UNMOUNT); | ||
| 864 | BUILD_BUG_ON(IN_ISDIR != FS_IN_ISDIR); | ||
| 865 | BUILD_BUG_ON(IN_IGNORED != FS_IN_IGNORED); | ||
| 866 | BUILD_BUG_ON(IN_ONESHOT != FS_IN_ONESHOT); | ||
| 867 | |||
| 868 | atomic_set(&inotify_cookie, 0); | ||
| 869 | |||
| 870 | return 0; | ||
| 871 | } | ||
| 872 | |||
| 873 | module_init(inotify_setup); | ||
diff --git a/fs/notify/inotify/inotify.h b/fs/notify/inotify/inotify.h index f234f3a4c8ca..b6642e4de4bf 100644 --- a/fs/notify/inotify/inotify.h +++ b/fs/notify/inotify/inotify.h | |||
| @@ -9,13 +9,12 @@ struct inotify_event_private_data { | |||
| 9 | int wd; | 9 | int wd; |
| 10 | }; | 10 | }; |
| 11 | 11 | ||
| 12 | struct inotify_inode_mark_entry { | 12 | struct inotify_inode_mark { |
| 13 | /* fsnotify_mark_entry MUST be the first thing */ | 13 | struct fsnotify_mark fsn_mark; |
| 14 | struct fsnotify_mark_entry fsn_entry; | ||
| 15 | int wd; | 14 | int wd; |
| 16 | }; | 15 | }; |
| 17 | 16 | ||
| 18 | extern void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry, | 17 | extern void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark, |
| 19 | struct fsnotify_group *group); | 18 | struct fsnotify_group *group); |
| 20 | extern void inotify_free_event_priv(struct fsnotify_event_private_data *event_priv); | 19 | extern void inotify_free_event_priv(struct fsnotify_event_private_data *event_priv); |
| 21 | 20 | ||
diff --git a/fs/notify/inotify/inotify_fsnotify.c b/fs/notify/inotify/inotify_fsnotify.c index e27960cd76ab..a91b69a6a291 100644 --- a/fs/notify/inotify/inotify_fsnotify.c +++ b/fs/notify/inotify/inotify_fsnotify.c | |||
| @@ -22,6 +22,7 @@ | |||
| 22 | * General Public License for more details. | 22 | * General Public License for more details. |
| 23 | */ | 23 | */ |
| 24 | 24 | ||
| 25 | #include <linux/dcache.h> /* d_unlinked */ | ||
| 25 | #include <linux/fs.h> /* struct inode */ | 26 | #include <linux/fs.h> /* struct inode */ |
| 26 | #include <linux/fsnotify_backend.h> | 27 | #include <linux/fsnotify_backend.h> |
| 27 | #include <linux/inotify.h> | 28 | #include <linux/inotify.h> |
| @@ -32,26 +33,84 @@ | |||
| 32 | 33 | ||
| 33 | #include "inotify.h" | 34 | #include "inotify.h" |
| 34 | 35 | ||
| 35 | static int inotify_handle_event(struct fsnotify_group *group, struct fsnotify_event *event) | 36 | /* |
| 37 | * Check if 2 events contain the same information. We do not compare private data | ||
| 38 | * but at this moment that isn't a problem for any know fsnotify listeners. | ||
| 39 | */ | ||
| 40 | static bool event_compare(struct fsnotify_event *old, struct fsnotify_event *new) | ||
| 41 | { | ||
| 42 | if ((old->mask == new->mask) && | ||
| 43 | (old->to_tell == new->to_tell) && | ||
| 44 | (old->data_type == new->data_type) && | ||
| 45 | (old->name_len == new->name_len)) { | ||
| 46 | switch (old->data_type) { | ||
| 47 | case (FSNOTIFY_EVENT_INODE): | ||
| 48 | /* remember, after old was put on the wait_q we aren't | ||
| 49 | * allowed to look at the inode any more, only thing | ||
| 50 | * left to check was if the file_name is the same */ | ||
| 51 | if (!old->name_len || | ||
| 52 | !strcmp(old->file_name, new->file_name)) | ||
| 53 | return true; | ||
| 54 | break; | ||
| 55 | case (FSNOTIFY_EVENT_PATH): | ||
| 56 | if ((old->path.mnt == new->path.mnt) && | ||
| 57 | (old->path.dentry == new->path.dentry)) | ||
| 58 | return true; | ||
| 59 | break; | ||
| 60 | case (FSNOTIFY_EVENT_NONE): | ||
| 61 | if (old->mask & FS_Q_OVERFLOW) | ||
| 62 | return true; | ||
| 63 | else if (old->mask & FS_IN_IGNORED) | ||
| 64 | return false; | ||
| 65 | return true; | ||
| 66 | }; | ||
| 67 | } | ||
| 68 | return false; | ||
| 69 | } | ||
| 70 | |||
| 71 | static struct fsnotify_event *inotify_merge(struct list_head *list, | ||
| 72 | struct fsnotify_event *event) | ||
| 36 | { | 73 | { |
| 37 | struct fsnotify_mark_entry *entry; | 74 | struct fsnotify_event_holder *last_holder; |
| 38 | struct inotify_inode_mark_entry *ientry; | 75 | struct fsnotify_event *last_event; |
| 76 | |||
| 77 | /* and the list better be locked by something too */ | ||
| 78 | spin_lock(&event->lock); | ||
| 79 | |||
| 80 | last_holder = list_entry(list->prev, struct fsnotify_event_holder, event_list); | ||
| 81 | last_event = last_holder->event; | ||
| 82 | if (event_compare(last_event, event)) | ||
| 83 | fsnotify_get_event(last_event); | ||
| 84 | else | ||
| 85 | last_event = NULL; | ||
| 86 | |||
| 87 | spin_unlock(&event->lock); | ||
| 88 | |||
| 89 | return last_event; | ||
| 90 | } | ||
| 91 | |||
| 92 | static int inotify_handle_event(struct fsnotify_group *group, | ||
| 93 | struct fsnotify_mark *inode_mark, | ||
| 94 | struct fsnotify_mark *vfsmount_mark, | ||
| 95 | struct fsnotify_event *event) | ||
| 96 | { | ||
| 97 | struct inotify_inode_mark *i_mark; | ||
| 39 | struct inode *to_tell; | 98 | struct inode *to_tell; |
| 40 | struct inotify_event_private_data *event_priv; | 99 | struct inotify_event_private_data *event_priv; |
| 41 | struct fsnotify_event_private_data *fsn_event_priv; | 100 | struct fsnotify_event_private_data *fsn_event_priv; |
| 42 | int wd, ret; | 101 | struct fsnotify_event *added_event; |
| 102 | int wd, ret = 0; | ||
| 103 | |||
| 104 | BUG_ON(vfsmount_mark); | ||
| 105 | |||
| 106 | pr_debug("%s: group=%p event=%p to_tell=%p mask=%x\n", __func__, group, | ||
| 107 | event, event->to_tell, event->mask); | ||
| 43 | 108 | ||
| 44 | to_tell = event->to_tell; | 109 | to_tell = event->to_tell; |
| 45 | 110 | ||
| 46 | spin_lock(&to_tell->i_lock); | 111 | i_mark = container_of(inode_mark, struct inotify_inode_mark, |
| 47 | entry = fsnotify_find_mark_entry(group, to_tell); | 112 | fsn_mark); |
| 48 | spin_unlock(&to_tell->i_lock); | 113 | wd = i_mark->wd; |
| 49 | /* race with watch removal? We already passes should_send */ | ||
| 50 | if (unlikely(!entry)) | ||
| 51 | return 0; | ||
| 52 | ientry = container_of(entry, struct inotify_inode_mark_entry, | ||
| 53 | fsn_entry); | ||
| 54 | wd = ientry->wd; | ||
| 55 | 114 | ||
| 56 | event_priv = kmem_cache_alloc(event_priv_cachep, GFP_KERNEL); | 115 | event_priv = kmem_cache_alloc(event_priv_cachep, GFP_KERNEL); |
| 57 | if (unlikely(!event_priv)) | 116 | if (unlikely(!event_priv)) |
| @@ -62,48 +121,40 @@ static int inotify_handle_event(struct fsnotify_group *group, struct fsnotify_ev | |||
| 62 | fsn_event_priv->group = group; | 121 | fsn_event_priv->group = group; |
| 63 | event_priv->wd = wd; | 122 | event_priv->wd = wd; |
| 64 | 123 | ||
| 65 | ret = fsnotify_add_notify_event(group, event, fsn_event_priv); | 124 | added_event = fsnotify_add_notify_event(group, event, fsn_event_priv, inotify_merge); |
| 66 | if (ret) { | 125 | if (added_event) { |
| 67 | inotify_free_event_priv(fsn_event_priv); | 126 | inotify_free_event_priv(fsn_event_priv); |
| 68 | /* EEXIST says we tail matched, EOVERFLOW isn't something | 127 | if (!IS_ERR(added_event)) |
| 69 | * to report up the stack. */ | 128 | fsnotify_put_event(added_event); |
| 70 | if ((ret == -EEXIST) || | 129 | else |
| 71 | (ret == -EOVERFLOW)) | 130 | ret = PTR_ERR(added_event); |
| 72 | ret = 0; | ||
| 73 | } | 131 | } |
| 74 | 132 | ||
| 75 | /* | 133 | if (inode_mark->mask & IN_ONESHOT) |
| 76 | * If we hold the entry until after the event is on the queue | 134 | fsnotify_destroy_mark(inode_mark); |
| 77 | * IN_IGNORED won't be able to pass this event in the queue | ||
| 78 | */ | ||
| 79 | fsnotify_put_mark(entry); | ||
| 80 | 135 | ||
| 81 | return ret; | 136 | return ret; |
| 82 | } | 137 | } |
| 83 | 138 | ||
| 84 | static void inotify_freeing_mark(struct fsnotify_mark_entry *entry, struct fsnotify_group *group) | 139 | static void inotify_freeing_mark(struct fsnotify_mark *fsn_mark, struct fsnotify_group *group) |
| 85 | { | 140 | { |
| 86 | inotify_ignored_and_remove_idr(entry, group); | 141 | inotify_ignored_and_remove_idr(fsn_mark, group); |
| 87 | } | 142 | } |
| 88 | 143 | ||
| 89 | static bool inotify_should_send_event(struct fsnotify_group *group, struct inode *inode, __u32 mask) | 144 | static bool inotify_should_send_event(struct fsnotify_group *group, struct inode *inode, |
| 145 | struct fsnotify_mark *inode_mark, | ||
| 146 | struct fsnotify_mark *vfsmount_mark, | ||
| 147 | __u32 mask, void *data, int data_type) | ||
| 90 | { | 148 | { |
| 91 | struct fsnotify_mark_entry *entry; | 149 | if ((inode_mark->mask & FS_EXCL_UNLINK) && |
| 92 | bool send; | 150 | (data_type == FSNOTIFY_EVENT_PATH)) { |
| 93 | 151 | struct path *path = data; | |
| 94 | spin_lock(&inode->i_lock); | ||
| 95 | entry = fsnotify_find_mark_entry(group, inode); | ||
| 96 | spin_unlock(&inode->i_lock); | ||
| 97 | if (!entry) | ||
| 98 | return false; | ||
| 99 | 152 | ||
| 100 | mask = (mask & ~FS_EVENT_ON_CHILD); | 153 | if (d_unlinked(path->dentry)) |
| 101 | send = (entry->mask & mask); | 154 | return false; |
| 102 | 155 | } | |
| 103 | /* find took a reference */ | ||
| 104 | fsnotify_put_mark(entry); | ||
| 105 | 156 | ||
| 106 | return send; | 157 | return true; |
| 107 | } | 158 | } |
| 108 | 159 | ||
| 109 | /* | 160 | /* |
| @@ -115,18 +166,18 @@ static bool inotify_should_send_event(struct fsnotify_group *group, struct inode | |||
| 115 | */ | 166 | */ |
| 116 | static int idr_callback(int id, void *p, void *data) | 167 | static int idr_callback(int id, void *p, void *data) |
| 117 | { | 168 | { |
| 118 | struct fsnotify_mark_entry *entry; | 169 | struct fsnotify_mark *fsn_mark; |
| 119 | struct inotify_inode_mark_entry *ientry; | 170 | struct inotify_inode_mark *i_mark; |
| 120 | static bool warned = false; | 171 | static bool warned = false; |
| 121 | 172 | ||
| 122 | if (warned) | 173 | if (warned) |
| 123 | return 0; | 174 | return 0; |
| 124 | 175 | ||
| 125 | warned = true; | 176 | warned = true; |
| 126 | entry = p; | 177 | fsn_mark = p; |
| 127 | ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry); | 178 | i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark); |
| 128 | 179 | ||
| 129 | WARN(1, "inotify closing but id=%d for entry=%p in group=%p still in " | 180 | WARN(1, "inotify closing but id=%d for fsn_mark=%p in group=%p still in " |
| 130 | "idr. Probably leaking memory\n", id, p, data); | 181 | "idr. Probably leaking memory\n", id, p, data); |
| 131 | 182 | ||
| 132 | /* | 183 | /* |
| @@ -135,9 +186,9 @@ static int idr_callback(int id, void *p, void *data) | |||
| 135 | * out why we got here and the panic is no worse than the original | 186 | * out why we got here and the panic is no worse than the original |
| 136 | * BUG() that was here. | 187 | * BUG() that was here. |
| 137 | */ | 188 | */ |
| 138 | if (entry) | 189 | if (fsn_mark) |
| 139 | printk(KERN_WARNING "entry->group=%p inode=%p wd=%d\n", | 190 | printk(KERN_WARNING "fsn_mark->group=%p inode=%p wd=%d\n", |
| 140 | entry->group, entry->inode, ientry->wd); | 191 | fsn_mark->group, fsn_mark->i.inode, i_mark->wd); |
| 141 | return 0; | 192 | return 0; |
| 142 | } | 193 | } |
| 143 | 194 | ||
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c index e46ca685b9be..bf7f6d776c31 100644 --- a/fs/notify/inotify/inotify_user.c +++ b/fs/notify/inotify/inotify_user.c | |||
| @@ -46,17 +46,11 @@ | |||
| 46 | /* these are configurable via /proc/sys/fs/inotify/ */ | 46 | /* these are configurable via /proc/sys/fs/inotify/ */ |
| 47 | static int inotify_max_user_instances __read_mostly; | 47 | static int inotify_max_user_instances __read_mostly; |
| 48 | static int inotify_max_queued_events __read_mostly; | 48 | static int inotify_max_queued_events __read_mostly; |
| 49 | int inotify_max_user_watches __read_mostly; | 49 | static int inotify_max_user_watches __read_mostly; |
| 50 | 50 | ||
| 51 | static struct kmem_cache *inotify_inode_mark_cachep __read_mostly; | 51 | static struct kmem_cache *inotify_inode_mark_cachep __read_mostly; |
| 52 | struct kmem_cache *event_priv_cachep __read_mostly; | 52 | struct kmem_cache *event_priv_cachep __read_mostly; |
| 53 | 53 | ||
| 54 | /* | ||
| 55 | * When inotify registers a new group it increments this and uses that | ||
| 56 | * value as an offset to set the fsnotify group "name" and priority. | ||
| 57 | */ | ||
| 58 | static atomic_t inotify_grp_num; | ||
| 59 | |||
| 60 | #ifdef CONFIG_SYSCTL | 54 | #ifdef CONFIG_SYSCTL |
| 61 | 55 | ||
| 62 | #include <linux/sysctl.h> | 56 | #include <linux/sysctl.h> |
| @@ -96,11 +90,14 @@ static inline __u32 inotify_arg_to_mask(u32 arg) | |||
| 96 | { | 90 | { |
| 97 | __u32 mask; | 91 | __u32 mask; |
| 98 | 92 | ||
| 99 | /* everything should accept their own ignored and cares about children */ | 93 | /* |
| 100 | mask = (FS_IN_IGNORED | FS_EVENT_ON_CHILD); | 94 | * everything should accept their own ignored, cares about children, |
| 95 | * and should receive events when the inode is unmounted | ||
| 96 | */ | ||
| 97 | mask = (FS_IN_IGNORED | FS_EVENT_ON_CHILD | FS_UNMOUNT); | ||
| 101 | 98 | ||
| 102 | /* mask off the flags used to open the fd */ | 99 | /* mask off the flags used to open the fd */ |
| 103 | mask |= (arg & (IN_ALL_EVENTS | IN_ONESHOT)); | 100 | mask |= (arg & (IN_ALL_EVENTS | IN_ONESHOT | IN_EXCL_UNLINK)); |
| 104 | 101 | ||
| 105 | return mask; | 102 | return mask; |
| 106 | } | 103 | } |
| @@ -144,6 +141,8 @@ static struct fsnotify_event *get_one_event(struct fsnotify_group *group, | |||
| 144 | 141 | ||
| 145 | event = fsnotify_peek_notify_event(group); | 142 | event = fsnotify_peek_notify_event(group); |
| 146 | 143 | ||
| 144 | pr_debug("%s: group=%p event=%p\n", __func__, group, event); | ||
| 145 | |||
| 147 | if (event->name_len) | 146 | if (event->name_len) |
| 148 | event_size += roundup(event->name_len + 1, event_size); | 147 | event_size += roundup(event->name_len + 1, event_size); |
| 149 | 148 | ||
| @@ -173,6 +172,8 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group, | |||
| 173 | size_t event_size = sizeof(struct inotify_event); | 172 | size_t event_size = sizeof(struct inotify_event); |
| 174 | size_t name_len = 0; | 173 | size_t name_len = 0; |
| 175 | 174 | ||
| 175 | pr_debug("%s: group=%p event=%p\n", __func__, group, event); | ||
| 176 | |||
| 176 | /* we get the inotify watch descriptor from the event private data */ | 177 | /* we get the inotify watch descriptor from the event private data */ |
| 177 | spin_lock(&event->lock); | 178 | spin_lock(&event->lock); |
| 178 | fsn_priv = fsnotify_remove_priv_from_event(group, event); | 179 | fsn_priv = fsnotify_remove_priv_from_event(group, event); |
| @@ -245,6 +246,8 @@ static ssize_t inotify_read(struct file *file, char __user *buf, | |||
| 245 | kevent = get_one_event(group, count); | 246 | kevent = get_one_event(group, count); |
| 246 | mutex_unlock(&group->notification_mutex); | 247 | mutex_unlock(&group->notification_mutex); |
| 247 | 248 | ||
| 249 | pr_debug("%s: group=%p kevent=%p\n", __func__, group, kevent); | ||
| 250 | |||
| 248 | if (kevent) { | 251 | if (kevent) { |
| 249 | ret = PTR_ERR(kevent); | 252 | ret = PTR_ERR(kevent); |
| 250 | if (IS_ERR(kevent)) | 253 | if (IS_ERR(kevent)) |
| @@ -289,6 +292,8 @@ static int inotify_release(struct inode *ignored, struct file *file) | |||
| 289 | struct fsnotify_group *group = file->private_data; | 292 | struct fsnotify_group *group = file->private_data; |
| 290 | struct user_struct *user = group->inotify_data.user; | 293 | struct user_struct *user = group->inotify_data.user; |
| 291 | 294 | ||
| 295 | pr_debug("%s: group=%p\n", __func__, group); | ||
| 296 | |||
| 292 | fsnotify_clear_marks_by_group(group); | 297 | fsnotify_clear_marks_by_group(group); |
| 293 | 298 | ||
| 294 | /* free this group, matching get was inotify_init->fsnotify_obtain_group */ | 299 | /* free this group, matching get was inotify_init->fsnotify_obtain_group */ |
| @@ -312,6 +317,8 @@ static long inotify_ioctl(struct file *file, unsigned int cmd, | |||
| 312 | group = file->private_data; | 317 | group = file->private_data; |
| 313 | p = (void __user *) arg; | 318 | p = (void __user *) arg; |
| 314 | 319 | ||
| 320 | pr_debug("%s: group=%p cmd=%u\n", __func__, group, cmd); | ||
| 321 | |||
| 315 | switch (cmd) { | 322 | switch (cmd) { |
| 316 | case FIONREAD: | 323 | case FIONREAD: |
| 317 | mutex_lock(&group->notification_mutex); | 324 | mutex_lock(&group->notification_mutex); |
| @@ -357,59 +364,159 @@ static int inotify_find_inode(const char __user *dirname, struct path *path, uns | |||
| 357 | return error; | 364 | return error; |
| 358 | } | 365 | } |
| 359 | 366 | ||
| 367 | static int inotify_add_to_idr(struct idr *idr, spinlock_t *idr_lock, | ||
| 368 | int *last_wd, | ||
| 369 | struct inotify_inode_mark *i_mark) | ||
| 370 | { | ||
| 371 | int ret; | ||
| 372 | |||
| 373 | do { | ||
| 374 | if (unlikely(!idr_pre_get(idr, GFP_KERNEL))) | ||
| 375 | return -ENOMEM; | ||
| 376 | |||
| 377 | spin_lock(idr_lock); | ||
| 378 | ret = idr_get_new_above(idr, i_mark, *last_wd + 1, | ||
| 379 | &i_mark->wd); | ||
| 380 | /* we added the mark to the idr, take a reference */ | ||
| 381 | if (!ret) { | ||
| 382 | *last_wd = i_mark->wd; | ||
| 383 | fsnotify_get_mark(&i_mark->fsn_mark); | ||
| 384 | } | ||
| 385 | spin_unlock(idr_lock); | ||
| 386 | } while (ret == -EAGAIN); | ||
| 387 | |||
| 388 | return ret; | ||
| 389 | } | ||
| 390 | |||
| 391 | static struct inotify_inode_mark *inotify_idr_find_locked(struct fsnotify_group *group, | ||
| 392 | int wd) | ||
| 393 | { | ||
| 394 | struct idr *idr = &group->inotify_data.idr; | ||
| 395 | spinlock_t *idr_lock = &group->inotify_data.idr_lock; | ||
| 396 | struct inotify_inode_mark *i_mark; | ||
| 397 | |||
| 398 | assert_spin_locked(idr_lock); | ||
| 399 | |||
| 400 | i_mark = idr_find(idr, wd); | ||
| 401 | if (i_mark) { | ||
| 402 | struct fsnotify_mark *fsn_mark = &i_mark->fsn_mark; | ||
| 403 | |||
| 404 | fsnotify_get_mark(fsn_mark); | ||
| 405 | /* One ref for being in the idr, one ref we just took */ | ||
| 406 | BUG_ON(atomic_read(&fsn_mark->refcnt) < 2); | ||
| 407 | } | ||
| 408 | |||
| 409 | return i_mark; | ||
| 410 | } | ||
| 411 | |||
| 412 | static struct inotify_inode_mark *inotify_idr_find(struct fsnotify_group *group, | ||
| 413 | int wd) | ||
| 414 | { | ||
| 415 | struct inotify_inode_mark *i_mark; | ||
| 416 | spinlock_t *idr_lock = &group->inotify_data.idr_lock; | ||
| 417 | |||
| 418 | spin_lock(idr_lock); | ||
| 419 | i_mark = inotify_idr_find_locked(group, wd); | ||
| 420 | spin_unlock(idr_lock); | ||
| 421 | |||
| 422 | return i_mark; | ||
| 423 | } | ||
| 424 | |||
| 425 | static void do_inotify_remove_from_idr(struct fsnotify_group *group, | ||
| 426 | struct inotify_inode_mark *i_mark) | ||
| 427 | { | ||
| 428 | struct idr *idr = &group->inotify_data.idr; | ||
| 429 | spinlock_t *idr_lock = &group->inotify_data.idr_lock; | ||
| 430 | int wd = i_mark->wd; | ||
| 431 | |||
| 432 | assert_spin_locked(idr_lock); | ||
| 433 | |||
| 434 | idr_remove(idr, wd); | ||
| 435 | |||
| 436 | /* removed from the idr, drop that ref */ | ||
| 437 | fsnotify_put_mark(&i_mark->fsn_mark); | ||
| 438 | } | ||
| 439 | |||
| 360 | /* | 440 | /* |
| 361 | * Remove the mark from the idr (if present) and drop the reference | 441 | * Remove the mark from the idr (if present) and drop the reference |
| 362 | * on the mark because it was in the idr. | 442 | * on the mark because it was in the idr. |
| 363 | */ | 443 | */ |
| 364 | static void inotify_remove_from_idr(struct fsnotify_group *group, | 444 | static void inotify_remove_from_idr(struct fsnotify_group *group, |
| 365 | struct inotify_inode_mark_entry *ientry) | 445 | struct inotify_inode_mark *i_mark) |
| 366 | { | 446 | { |
| 367 | struct idr *idr; | 447 | spinlock_t *idr_lock = &group->inotify_data.idr_lock; |
| 368 | struct fsnotify_mark_entry *entry; | 448 | struct inotify_inode_mark *found_i_mark = NULL; |
| 369 | struct inotify_inode_mark_entry *found_ientry; | ||
| 370 | int wd; | 449 | int wd; |
| 371 | 450 | ||
| 372 | spin_lock(&group->inotify_data.idr_lock); | 451 | spin_lock(idr_lock); |
| 373 | idr = &group->inotify_data.idr; | 452 | wd = i_mark->wd; |
| 374 | wd = ientry->wd; | ||
| 375 | 453 | ||
| 376 | if (wd == -1) | 454 | /* |
| 455 | * does this i_mark think it is in the idr? we shouldn't get called | ||
| 456 | * if it wasn't.... | ||
| 457 | */ | ||
| 458 | if (wd == -1) { | ||
| 459 | WARN_ONCE(1, "%s: i_mark=%p i_mark->wd=%d i_mark->group=%p" | ||
| 460 | " i_mark->inode=%p\n", __func__, i_mark, i_mark->wd, | ||
| 461 | i_mark->fsn_mark.group, i_mark->fsn_mark.i.inode); | ||
| 377 | goto out; | 462 | goto out; |
| 463 | } | ||
| 378 | 464 | ||
| 379 | entry = idr_find(&group->inotify_data.idr, wd); | 465 | /* Lets look in the idr to see if we find it */ |
| 380 | if (unlikely(!entry)) | 466 | found_i_mark = inotify_idr_find_locked(group, wd); |
| 467 | if (unlikely(!found_i_mark)) { | ||
| 468 | WARN_ONCE(1, "%s: i_mark=%p i_mark->wd=%d i_mark->group=%p" | ||
| 469 | " i_mark->inode=%p\n", __func__, i_mark, i_mark->wd, | ||
| 470 | i_mark->fsn_mark.group, i_mark->fsn_mark.i.inode); | ||
| 381 | goto out; | 471 | goto out; |
| 472 | } | ||
| 382 | 473 | ||
| 383 | found_ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry); | 474 | /* |
| 384 | if (unlikely(found_ientry != ientry)) { | 475 | * We found an mark in the idr at the right wd, but it's |
| 385 | /* We found an entry in the idr with the right wd, but it's | 476 | * not the mark we were told to remove. eparis seriously |
| 386 | * not the entry we were told to remove. eparis seriously | 477 | * fucked up somewhere. |
| 387 | * fucked up somewhere. */ | 478 | */ |
| 388 | WARN_ON(1); | 479 | if (unlikely(found_i_mark != i_mark)) { |
| 389 | ientry->wd = -1; | 480 | WARN_ONCE(1, "%s: i_mark=%p i_mark->wd=%d i_mark->group=%p " |
| 481 | "mark->inode=%p found_i_mark=%p found_i_mark->wd=%d " | ||
| 482 | "found_i_mark->group=%p found_i_mark->inode=%p\n", | ||
| 483 | __func__, i_mark, i_mark->wd, i_mark->fsn_mark.group, | ||
| 484 | i_mark->fsn_mark.i.inode, found_i_mark, found_i_mark->wd, | ||
| 485 | found_i_mark->fsn_mark.group, | ||
| 486 | found_i_mark->fsn_mark.i.inode); | ||
| 390 | goto out; | 487 | goto out; |
| 391 | } | 488 | } |
| 392 | 489 | ||
| 393 | /* One ref for being in the idr, one ref held by the caller */ | 490 | /* |
| 394 | BUG_ON(atomic_read(&entry->refcnt) < 2); | 491 | * One ref for being in the idr |
| 395 | 492 | * one ref held by the caller trying to kill us | |
| 396 | idr_remove(idr, wd); | 493 | * one ref grabbed by inotify_idr_find |
| 397 | ientry->wd = -1; | 494 | */ |
| 495 | if (unlikely(atomic_read(&i_mark->fsn_mark.refcnt) < 3)) { | ||
| 496 | printk(KERN_ERR "%s: i_mark=%p i_mark->wd=%d i_mark->group=%p" | ||
| 497 | " i_mark->inode=%p\n", __func__, i_mark, i_mark->wd, | ||
| 498 | i_mark->fsn_mark.group, i_mark->fsn_mark.i.inode); | ||
| 499 | /* we can't really recover with bad ref cnting.. */ | ||
| 500 | BUG(); | ||
| 501 | } | ||
| 398 | 502 | ||
| 399 | /* removed from the idr, drop that ref */ | 503 | do_inotify_remove_from_idr(group, i_mark); |
| 400 | fsnotify_put_mark(entry); | ||
| 401 | out: | 504 | out: |
| 402 | spin_unlock(&group->inotify_data.idr_lock); | 505 | /* match the ref taken by inotify_idr_find_locked() */ |
| 506 | if (found_i_mark) | ||
| 507 | fsnotify_put_mark(&found_i_mark->fsn_mark); | ||
| 508 | i_mark->wd = -1; | ||
| 509 | spin_unlock(idr_lock); | ||
| 403 | } | 510 | } |
| 404 | 511 | ||
| 405 | /* | 512 | /* |
| 406 | * Send IN_IGNORED for this wd, remove this wd from the idr. | 513 | * Send IN_IGNORED for this wd, remove this wd from the idr. |
| 407 | */ | 514 | */ |
| 408 | void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry, | 515 | void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark, |
| 409 | struct fsnotify_group *group) | 516 | struct fsnotify_group *group) |
| 410 | { | 517 | { |
| 411 | struct inotify_inode_mark_entry *ientry; | 518 | struct inotify_inode_mark *i_mark; |
| 412 | struct fsnotify_event *ignored_event; | 519 | struct fsnotify_event *ignored_event, *notify_event; |
| 413 | struct inotify_event_private_data *event_priv; | 520 | struct inotify_event_private_data *event_priv; |
| 414 | struct fsnotify_event_private_data *fsn_event_priv; | 521 | struct fsnotify_event_private_data *fsn_event_priv; |
| 415 | int ret; | 522 | int ret; |
| @@ -420,7 +527,7 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry, | |||
| 420 | if (!ignored_event) | 527 | if (!ignored_event) |
| 421 | return; | 528 | return; |
| 422 | 529 | ||
| 423 | ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry); | 530 | i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark); |
| 424 | 531 | ||
| 425 | event_priv = kmem_cache_alloc(event_priv_cachep, GFP_NOFS); | 532 | event_priv = kmem_cache_alloc(event_priv_cachep, GFP_NOFS); |
| 426 | if (unlikely(!event_priv)) | 533 | if (unlikely(!event_priv)) |
| @@ -429,37 +536,44 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry, | |||
| 429 | fsn_event_priv = &event_priv->fsnotify_event_priv_data; | 536 | fsn_event_priv = &event_priv->fsnotify_event_priv_data; |
| 430 | 537 | ||
| 431 | fsn_event_priv->group = group; | 538 | fsn_event_priv->group = group; |
| 432 | event_priv->wd = ientry->wd; | 539 | event_priv->wd = i_mark->wd; |
| 433 | 540 | ||
| 434 | ret = fsnotify_add_notify_event(group, ignored_event, fsn_event_priv); | 541 | notify_event = fsnotify_add_notify_event(group, ignored_event, fsn_event_priv, NULL); |
| 435 | if (ret) | 542 | if (notify_event) { |
| 543 | if (IS_ERR(notify_event)) | ||
| 544 | ret = PTR_ERR(notify_event); | ||
| 545 | else | ||
| 546 | fsnotify_put_event(notify_event); | ||
| 436 | inotify_free_event_priv(fsn_event_priv); | 547 | inotify_free_event_priv(fsn_event_priv); |
| 548 | } | ||
| 437 | 549 | ||
| 438 | skip_send_ignore: | 550 | skip_send_ignore: |
| 439 | 551 | ||
| 440 | /* matches the reference taken when the event was created */ | 552 | /* matches the reference taken when the event was created */ |
| 441 | fsnotify_put_event(ignored_event); | 553 | fsnotify_put_event(ignored_event); |
| 442 | 554 | ||
| 443 | /* remove this entry from the idr */ | 555 | /* remove this mark from the idr */ |
| 444 | inotify_remove_from_idr(group, ientry); | 556 | inotify_remove_from_idr(group, i_mark); |
| 445 | 557 | ||
| 446 | atomic_dec(&group->inotify_data.user->inotify_watches); | 558 | atomic_dec(&group->inotify_data.user->inotify_watches); |
| 447 | } | 559 | } |
| 448 | 560 | ||
| 449 | /* ding dong the mark is dead */ | 561 | /* ding dong the mark is dead */ |
| 450 | static void inotify_free_mark(struct fsnotify_mark_entry *entry) | 562 | static void inotify_free_mark(struct fsnotify_mark *fsn_mark) |
| 451 | { | 563 | { |
| 452 | struct inotify_inode_mark_entry *ientry = (struct inotify_inode_mark_entry *)entry; | 564 | struct inotify_inode_mark *i_mark; |
| 565 | |||
| 566 | i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark); | ||
| 453 | 567 | ||
| 454 | kmem_cache_free(inotify_inode_mark_cachep, ientry); | 568 | kmem_cache_free(inotify_inode_mark_cachep, i_mark); |
| 455 | } | 569 | } |
| 456 | 570 | ||
| 457 | static int inotify_update_existing_watch(struct fsnotify_group *group, | 571 | static int inotify_update_existing_watch(struct fsnotify_group *group, |
| 458 | struct inode *inode, | 572 | struct inode *inode, |
| 459 | u32 arg) | 573 | u32 arg) |
| 460 | { | 574 | { |
| 461 | struct fsnotify_mark_entry *entry; | 575 | struct fsnotify_mark *fsn_mark; |
| 462 | struct inotify_inode_mark_entry *ientry; | 576 | struct inotify_inode_mark *i_mark; |
| 463 | __u32 old_mask, new_mask; | 577 | __u32 old_mask, new_mask; |
| 464 | __u32 mask; | 578 | __u32 mask; |
| 465 | int add = (arg & IN_MASK_ADD); | 579 | int add = (arg & IN_MASK_ADD); |
| @@ -467,52 +581,43 @@ static int inotify_update_existing_watch(struct fsnotify_group *group, | |||
| 467 | 581 | ||
| 468 | /* don't allow invalid bits: we don't want flags set */ | 582 | /* don't allow invalid bits: we don't want flags set */ |
| 469 | mask = inotify_arg_to_mask(arg); | 583 | mask = inotify_arg_to_mask(arg); |
| 470 | if (unlikely(!mask)) | 584 | if (unlikely(!(mask & IN_ALL_EVENTS))) |
| 471 | return -EINVAL; | 585 | return -EINVAL; |
| 472 | 586 | ||
| 473 | spin_lock(&inode->i_lock); | 587 | fsn_mark = fsnotify_find_inode_mark(group, inode); |
| 474 | entry = fsnotify_find_mark_entry(group, inode); | 588 | if (!fsn_mark) |
| 475 | spin_unlock(&inode->i_lock); | ||
| 476 | if (!entry) | ||
| 477 | return -ENOENT; | 589 | return -ENOENT; |
| 478 | 590 | ||
| 479 | ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry); | 591 | i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark); |
| 480 | 592 | ||
| 481 | spin_lock(&entry->lock); | 593 | spin_lock(&fsn_mark->lock); |
| 482 | 594 | ||
| 483 | old_mask = entry->mask; | 595 | old_mask = fsn_mark->mask; |
| 484 | if (add) { | 596 | if (add) |
| 485 | entry->mask |= mask; | 597 | fsnotify_set_mark_mask_locked(fsn_mark, (fsn_mark->mask | mask)); |
| 486 | new_mask = entry->mask; | 598 | else |
| 487 | } else { | 599 | fsnotify_set_mark_mask_locked(fsn_mark, mask); |
| 488 | entry->mask = mask; | 600 | new_mask = fsn_mark->mask; |
| 489 | new_mask = entry->mask; | ||
| 490 | } | ||
| 491 | 601 | ||
| 492 | spin_unlock(&entry->lock); | 602 | spin_unlock(&fsn_mark->lock); |
| 493 | 603 | ||
| 494 | if (old_mask != new_mask) { | 604 | if (old_mask != new_mask) { |
| 495 | /* more bits in old than in new? */ | 605 | /* more bits in old than in new? */ |
| 496 | int dropped = (old_mask & ~new_mask); | 606 | int dropped = (old_mask & ~new_mask); |
| 497 | /* more bits in this entry than the inode's mask? */ | 607 | /* more bits in this fsn_mark than the inode's mask? */ |
| 498 | int do_inode = (new_mask & ~inode->i_fsnotify_mask); | 608 | int do_inode = (new_mask & ~inode->i_fsnotify_mask); |
| 499 | /* more bits in this entry than the group? */ | ||
| 500 | int do_group = (new_mask & ~group->mask); | ||
| 501 | 609 | ||
| 502 | /* update the inode with this new entry */ | 610 | /* update the inode with this new fsn_mark */ |
| 503 | if (dropped || do_inode) | 611 | if (dropped || do_inode) |
| 504 | fsnotify_recalc_inode_mask(inode); | 612 | fsnotify_recalc_inode_mask(inode); |
| 505 | 613 | ||
| 506 | /* update the group mask with the new mask */ | ||
| 507 | if (dropped || do_group) | ||
| 508 | fsnotify_recalc_group_mask(group); | ||
| 509 | } | 614 | } |
| 510 | 615 | ||
| 511 | /* return the wd */ | 616 | /* return the wd */ |
| 512 | ret = ientry->wd; | 617 | ret = i_mark->wd; |
| 513 | 618 | ||
| 514 | /* match the get from fsnotify_find_mark_entry() */ | 619 | /* match the get from fsnotify_find_mark() */ |
| 515 | fsnotify_put_mark(entry); | 620 | fsnotify_put_mark(fsn_mark); |
| 516 | 621 | ||
| 517 | return ret; | 622 | return ret; |
| 518 | } | 623 | } |
| @@ -521,73 +626,51 @@ static int inotify_new_watch(struct fsnotify_group *group, | |||
| 521 | struct inode *inode, | 626 | struct inode *inode, |
| 522 | u32 arg) | 627 | u32 arg) |
| 523 | { | 628 | { |
| 524 | struct inotify_inode_mark_entry *tmp_ientry; | 629 | struct inotify_inode_mark *tmp_i_mark; |
| 525 | __u32 mask; | 630 | __u32 mask; |
| 526 | int ret; | 631 | int ret; |
| 632 | struct idr *idr = &group->inotify_data.idr; | ||
| 633 | spinlock_t *idr_lock = &group->inotify_data.idr_lock; | ||
| 527 | 634 | ||
| 528 | /* don't allow invalid bits: we don't want flags set */ | 635 | /* don't allow invalid bits: we don't want flags set */ |
| 529 | mask = inotify_arg_to_mask(arg); | 636 | mask = inotify_arg_to_mask(arg); |
| 530 | if (unlikely(!mask)) | 637 | if (unlikely(!(mask & IN_ALL_EVENTS))) |
| 531 | return -EINVAL; | 638 | return -EINVAL; |
| 532 | 639 | ||
| 533 | tmp_ientry = kmem_cache_alloc(inotify_inode_mark_cachep, GFP_KERNEL); | 640 | tmp_i_mark = kmem_cache_alloc(inotify_inode_mark_cachep, GFP_KERNEL); |
| 534 | if (unlikely(!tmp_ientry)) | 641 | if (unlikely(!tmp_i_mark)) |
| 535 | return -ENOMEM; | 642 | return -ENOMEM; |
| 536 | 643 | ||
| 537 | fsnotify_init_mark(&tmp_ientry->fsn_entry, inotify_free_mark); | 644 | fsnotify_init_mark(&tmp_i_mark->fsn_mark, inotify_free_mark); |
| 538 | tmp_ientry->fsn_entry.mask = mask; | 645 | tmp_i_mark->fsn_mark.mask = mask; |
| 539 | tmp_ientry->wd = -1; | 646 | tmp_i_mark->wd = -1; |
| 540 | 647 | ||
| 541 | ret = -ENOSPC; | 648 | ret = -ENOSPC; |
| 542 | if (atomic_read(&group->inotify_data.user->inotify_watches) >= inotify_max_user_watches) | 649 | if (atomic_read(&group->inotify_data.user->inotify_watches) >= inotify_max_user_watches) |
| 543 | goto out_err; | 650 | goto out_err; |
| 544 | retry: | ||
| 545 | ret = -ENOMEM; | ||
| 546 | if (unlikely(!idr_pre_get(&group->inotify_data.idr, GFP_KERNEL))) | ||
| 547 | goto out_err; | ||
| 548 | 651 | ||
| 549 | /* we are putting the mark on the idr, take a reference */ | 652 | ret = inotify_add_to_idr(idr, idr_lock, &group->inotify_data.last_wd, |
| 550 | fsnotify_get_mark(&tmp_ientry->fsn_entry); | 653 | tmp_i_mark); |
| 551 | 654 | if (ret) | |
| 552 | spin_lock(&group->inotify_data.idr_lock); | ||
| 553 | ret = idr_get_new_above(&group->inotify_data.idr, &tmp_ientry->fsn_entry, | ||
| 554 | group->inotify_data.last_wd+1, | ||
| 555 | &tmp_ientry->wd); | ||
| 556 | spin_unlock(&group->inotify_data.idr_lock); | ||
| 557 | if (ret) { | ||
| 558 | /* we didn't get on the idr, drop the idr reference */ | ||
| 559 | fsnotify_put_mark(&tmp_ientry->fsn_entry); | ||
| 560 | |||
| 561 | /* idr was out of memory allocate and try again */ | ||
| 562 | if (ret == -EAGAIN) | ||
| 563 | goto retry; | ||
| 564 | goto out_err; | 655 | goto out_err; |
| 565 | } | ||
| 566 | 656 | ||
| 567 | /* we are on the idr, now get on the inode */ | 657 | /* we are on the idr, now get on the inode */ |
| 568 | ret = fsnotify_add_mark(&tmp_ientry->fsn_entry, group, inode); | 658 | ret = fsnotify_add_mark(&tmp_i_mark->fsn_mark, group, inode, NULL, 0); |
| 569 | if (ret) { | 659 | if (ret) { |
| 570 | /* we failed to get on the inode, get off the idr */ | 660 | /* we failed to get on the inode, get off the idr */ |
| 571 | inotify_remove_from_idr(group, tmp_ientry); | 661 | inotify_remove_from_idr(group, tmp_i_mark); |
| 572 | goto out_err; | 662 | goto out_err; |
| 573 | } | 663 | } |
| 574 | 664 | ||
| 575 | /* update the idr hint, who cares about races, it's just a hint */ | ||
| 576 | group->inotify_data.last_wd = tmp_ientry->wd; | ||
| 577 | |||
| 578 | /* increment the number of watches the user has */ | 665 | /* increment the number of watches the user has */ |
| 579 | atomic_inc(&group->inotify_data.user->inotify_watches); | 666 | atomic_inc(&group->inotify_data.user->inotify_watches); |
| 580 | 667 | ||
| 581 | /* return the watch descriptor for this new entry */ | 668 | /* return the watch descriptor for this new mark */ |
| 582 | ret = tmp_ientry->wd; | 669 | ret = tmp_i_mark->wd; |
| 583 | |||
| 584 | /* if this mark added a new event update the group mask */ | ||
| 585 | if (mask & ~group->mask) | ||
| 586 | fsnotify_recalc_group_mask(group); | ||
| 587 | 670 | ||
| 588 | out_err: | 671 | out_err: |
| 589 | /* match the ref from fsnotify_init_markentry() */ | 672 | /* match the ref from fsnotify_init_mark() */ |
| 590 | fsnotify_put_mark(&tmp_ientry->fsn_entry); | 673 | fsnotify_put_mark(&tmp_i_mark->fsn_mark); |
| 591 | 674 | ||
| 592 | return ret; | 675 | return ret; |
| 593 | } | 676 | } |
| @@ -616,11 +699,8 @@ retry: | |||
| 616 | static struct fsnotify_group *inotify_new_group(struct user_struct *user, unsigned int max_events) | 699 | static struct fsnotify_group *inotify_new_group(struct user_struct *user, unsigned int max_events) |
| 617 | { | 700 | { |
| 618 | struct fsnotify_group *group; | 701 | struct fsnotify_group *group; |
| 619 | unsigned int grp_num; | ||
| 620 | 702 | ||
| 621 | /* fsnotify_obtain_group took a reference to group, we put this when we kill the file in the end */ | 703 | group = fsnotify_alloc_group(&inotify_fsnotify_ops); |
| 622 | grp_num = (INOTIFY_GROUP_NUM - atomic_inc_return(&inotify_grp_num)); | ||
| 623 | group = fsnotify_obtain_group(grp_num, 0, &inotify_fsnotify_ops); | ||
| 624 | if (IS_ERR(group)) | 704 | if (IS_ERR(group)) |
| 625 | return group; | 705 | return group; |
| 626 | 706 | ||
| @@ -726,7 +806,7 @@ fput_and_out: | |||
| 726 | SYSCALL_DEFINE2(inotify_rm_watch, int, fd, __s32, wd) | 806 | SYSCALL_DEFINE2(inotify_rm_watch, int, fd, __s32, wd) |
| 727 | { | 807 | { |
| 728 | struct fsnotify_group *group; | 808 | struct fsnotify_group *group; |
| 729 | struct fsnotify_mark_entry *entry; | 809 | struct inotify_inode_mark *i_mark; |
| 730 | struct file *filp; | 810 | struct file *filp; |
| 731 | int ret = 0, fput_needed; | 811 | int ret = 0, fput_needed; |
| 732 | 812 | ||
| @@ -735,25 +815,23 @@ SYSCALL_DEFINE2(inotify_rm_watch, int, fd, __s32, wd) | |||
| 735 | return -EBADF; | 815 | return -EBADF; |
| 736 | 816 | ||
| 737 | /* verify that this is indeed an inotify instance */ | 817 | /* verify that this is indeed an inotify instance */ |
| 738 | if (unlikely(filp->f_op != &inotify_fops)) { | 818 | ret = -EINVAL; |
| 739 | ret = -EINVAL; | 819 | if (unlikely(filp->f_op != &inotify_fops)) |
| 740 | goto out; | 820 | goto out; |
| 741 | } | ||
| 742 | 821 | ||
| 743 | group = filp->private_data; | 822 | group = filp->private_data; |
| 744 | 823 | ||
| 745 | spin_lock(&group->inotify_data.idr_lock); | 824 | ret = -EINVAL; |
| 746 | entry = idr_find(&group->inotify_data.idr, wd); | 825 | i_mark = inotify_idr_find(group, wd); |
| 747 | if (unlikely(!entry)) { | 826 | if (unlikely(!i_mark)) |
| 748 | spin_unlock(&group->inotify_data.idr_lock); | ||
| 749 | ret = -EINVAL; | ||
| 750 | goto out; | 827 | goto out; |
| 751 | } | ||
| 752 | fsnotify_get_mark(entry); | ||
| 753 | spin_unlock(&group->inotify_data.idr_lock); | ||
| 754 | 828 | ||
| 755 | fsnotify_destroy_mark_by_entry(entry); | 829 | ret = 0; |
| 756 | fsnotify_put_mark(entry); | 830 | |
| 831 | fsnotify_destroy_mark(&i_mark->fsn_mark); | ||
| 832 | |||
| 833 | /* match ref taken by inotify_idr_find */ | ||
| 834 | fsnotify_put_mark(&i_mark->fsn_mark); | ||
| 757 | 835 | ||
| 758 | out: | 836 | out: |
| 759 | fput_light(filp, fput_needed); | 837 | fput_light(filp, fput_needed); |
| @@ -767,7 +845,28 @@ out: | |||
| 767 | */ | 845 | */ |
| 768 | static int __init inotify_user_setup(void) | 846 | static int __init inotify_user_setup(void) |
| 769 | { | 847 | { |
| 770 | inotify_inode_mark_cachep = KMEM_CACHE(inotify_inode_mark_entry, SLAB_PANIC); | 848 | BUILD_BUG_ON(IN_ACCESS != FS_ACCESS); |
| 849 | BUILD_BUG_ON(IN_MODIFY != FS_MODIFY); | ||
| 850 | BUILD_BUG_ON(IN_ATTRIB != FS_ATTRIB); | ||
| 851 | BUILD_BUG_ON(IN_CLOSE_WRITE != FS_CLOSE_WRITE); | ||
| 852 | BUILD_BUG_ON(IN_CLOSE_NOWRITE != FS_CLOSE_NOWRITE); | ||
| 853 | BUILD_BUG_ON(IN_OPEN != FS_OPEN); | ||
| 854 | BUILD_BUG_ON(IN_MOVED_FROM != FS_MOVED_FROM); | ||
| 855 | BUILD_BUG_ON(IN_MOVED_TO != FS_MOVED_TO); | ||
| 856 | BUILD_BUG_ON(IN_CREATE != FS_CREATE); | ||
| 857 | BUILD_BUG_ON(IN_DELETE != FS_DELETE); | ||
| 858 | BUILD_BUG_ON(IN_DELETE_SELF != FS_DELETE_SELF); | ||
| 859 | BUILD_BUG_ON(IN_MOVE_SELF != FS_MOVE_SELF); | ||
| 860 | BUILD_BUG_ON(IN_UNMOUNT != FS_UNMOUNT); | ||
| 861 | BUILD_BUG_ON(IN_Q_OVERFLOW != FS_Q_OVERFLOW); | ||
| 862 | BUILD_BUG_ON(IN_IGNORED != FS_IN_IGNORED); | ||
| 863 | BUILD_BUG_ON(IN_EXCL_UNLINK != FS_EXCL_UNLINK); | ||
| 864 | BUILD_BUG_ON(IN_ISDIR != FS_IN_ISDIR); | ||
| 865 | BUILD_BUG_ON(IN_ONESHOT != FS_IN_ONESHOT); | ||
| 866 | |||
| 867 | BUG_ON(hweight32(ALL_INOTIFY_BITS) != 21); | ||
| 868 | |||
| 869 | inotify_inode_mark_cachep = KMEM_CACHE(inotify_inode_mark, SLAB_PANIC); | ||
| 771 | event_priv_cachep = KMEM_CACHE(inotify_event_private_data, SLAB_PANIC); | 870 | event_priv_cachep = KMEM_CACHE(inotify_event_private_data, SLAB_PANIC); |
| 772 | 871 | ||
| 773 | inotify_max_queued_events = 16384; | 872 | inotify_max_queued_events = 16384; |
diff --git a/fs/notify/mark.c b/fs/notify/mark.c new file mode 100644 index 000000000000..325185e514bb --- /dev/null +++ b/fs/notify/mark.c | |||
| @@ -0,0 +1,371 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2008 Red Hat, Inc., Eric Paris <eparis@redhat.com> | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 7 | * any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; see the file COPYING. If not, write to | ||
| 16 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 17 | */ | ||
| 18 | |||
| 19 | /* | ||
| 20 | * fsnotify inode mark locking/lifetime/and refcnting | ||
| 21 | * | ||
| 22 | * REFCNT: | ||
| 23 | * The mark->refcnt tells how many "things" in the kernel currently are | ||
| 24 | * referencing this object. The object typically will live inside the kernel | ||
| 25 | * with a refcnt of 2, one for each list it is on (i_list, g_list). Any task | ||
| 26 | * which can find this object holding the appropriete locks, can take a reference | ||
| 27 | * and the object itself is guarenteed to survive until the reference is dropped. | ||
| 28 | * | ||
| 29 | * LOCKING: | ||
| 30 | * There are 3 spinlocks involved with fsnotify inode marks and they MUST | ||
| 31 | * be taken in order as follows: | ||
| 32 | * | ||
| 33 | * mark->lock | ||
| 34 | * group->mark_lock | ||
| 35 | * inode->i_lock | ||
| 36 | * | ||
| 37 | * mark->lock protects 2 things, mark->group and mark->inode. You must hold | ||
| 38 | * that lock to dereference either of these things (they could be NULL even with | ||
| 39 | * the lock) | ||
| 40 | * | ||
| 41 | * group->mark_lock protects the marks_list anchored inside a given group | ||
| 42 | * and each mark is hooked via the g_list. It also sorta protects the | ||
| 43 | * free_g_list, which when used is anchored by a private list on the stack of the | ||
| 44 | * task which held the group->mark_lock. | ||
| 45 | * | ||
| 46 | * inode->i_lock protects the i_fsnotify_marks list anchored inside a | ||
| 47 | * given inode and each mark is hooked via the i_list. (and sorta the | ||
| 48 | * free_i_list) | ||
| 49 | * | ||
| 50 | * | ||
| 51 | * LIFETIME: | ||
| 52 | * Inode marks survive between when they are added to an inode and when their | ||
| 53 | * refcnt==0. | ||
| 54 | * | ||
| 55 | * The inode mark can be cleared for a number of different reasons including: | ||
| 56 | * - The inode is unlinked for the last time. (fsnotify_inode_remove) | ||
| 57 | * - The inode is being evicted from cache. (fsnotify_inode_delete) | ||
| 58 | * - The fs the inode is on is unmounted. (fsnotify_inode_delete/fsnotify_unmount_inodes) | ||
| 59 | * - Something explicitly requests that it be removed. (fsnotify_destroy_mark) | ||
| 60 | * - The fsnotify_group associated with the mark is going away and all such marks | ||
| 61 | * need to be cleaned up. (fsnotify_clear_marks_by_group) | ||
| 62 | * | ||
| 63 | * Worst case we are given an inode and need to clean up all the marks on that | ||
| 64 | * inode. We take i_lock and walk the i_fsnotify_marks safely. For each | ||
| 65 | * mark on the list we take a reference (so the mark can't disappear under us). | ||
| 66 | * We remove that mark form the inode's list of marks and we add this mark to a | ||
| 67 | * private list anchored on the stack using i_free_list; At this point we no | ||
| 68 | * longer fear anything finding the mark using the inode's list of marks. | ||
| 69 | * | ||
| 70 | * We can safely and locklessly run the private list on the stack of everything | ||
| 71 | * we just unattached from the original inode. For each mark on the private list | ||
| 72 | * we grab the mark-> and can thus dereference mark->group and mark->inode. If | ||
| 73 | * we see the group and inode are not NULL we take those locks. Now holding all | ||
| 74 | * 3 locks we can completely remove the mark from other tasks finding it in the | ||
| 75 | * future. Remember, 10 things might already be referencing this mark, but they | ||
| 76 | * better be holding a ref. We drop our reference we took before we unhooked it | ||
| 77 | * from the inode. When the ref hits 0 we can free the mark. | ||
| 78 | * | ||
| 79 | * Very similarly for freeing by group, except we use free_g_list. | ||
| 80 | * | ||
| 81 | * This has the very interesting property of being able to run concurrently with | ||
| 82 | * any (or all) other directions. | ||
| 83 | */ | ||
| 84 | |||
| 85 | #include <linux/fs.h> | ||
| 86 | #include <linux/init.h> | ||
| 87 | #include <linux/kernel.h> | ||
| 88 | #include <linux/kthread.h> | ||
| 89 | #include <linux/module.h> | ||
| 90 | #include <linux/mutex.h> | ||
| 91 | #include <linux/slab.h> | ||
| 92 | #include <linux/spinlock.h> | ||
| 93 | #include <linux/srcu.h> | ||
| 94 | #include <linux/writeback.h> /* for inode_lock */ | ||
| 95 | |||
| 96 | #include <asm/atomic.h> | ||
| 97 | |||
| 98 | #include <linux/fsnotify_backend.h> | ||
| 99 | #include "fsnotify.h" | ||
| 100 | |||
| 101 | struct srcu_struct fsnotify_mark_srcu; | ||
| 102 | static DEFINE_SPINLOCK(destroy_lock); | ||
| 103 | static LIST_HEAD(destroy_list); | ||
| 104 | static DECLARE_WAIT_QUEUE_HEAD(destroy_waitq); | ||
| 105 | |||
| 106 | void fsnotify_get_mark(struct fsnotify_mark *mark) | ||
| 107 | { | ||
| 108 | atomic_inc(&mark->refcnt); | ||
| 109 | } | ||
| 110 | |||
| 111 | void fsnotify_put_mark(struct fsnotify_mark *mark) | ||
| 112 | { | ||
| 113 | if (atomic_dec_and_test(&mark->refcnt)) | ||
| 114 | mark->free_mark(mark); | ||
| 115 | } | ||
| 116 | |||
| 117 | /* | ||
| 118 | * Any time a mark is getting freed we end up here. | ||
| 119 | * The caller had better be holding a reference to this mark so we don't actually | ||
| 120 | * do the final put under the mark->lock | ||
| 121 | */ | ||
| 122 | void fsnotify_destroy_mark(struct fsnotify_mark *mark) | ||
| 123 | { | ||
| 124 | struct fsnotify_group *group; | ||
| 125 | struct inode *inode = NULL; | ||
| 126 | |||
| 127 | spin_lock(&mark->lock); | ||
| 128 | |||
| 129 | group = mark->group; | ||
| 130 | |||
| 131 | /* something else already called this function on this mark */ | ||
| 132 | if (!(mark->flags & FSNOTIFY_MARK_FLAG_ALIVE)) { | ||
| 133 | spin_unlock(&mark->lock); | ||
| 134 | return; | ||
| 135 | } | ||
| 136 | |||
| 137 | mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE; | ||
| 138 | |||
| 139 | /* 1 from caller and 1 for being on i_list/g_list */ | ||
| 140 | BUG_ON(atomic_read(&mark->refcnt) < 2); | ||
| 141 | |||
| 142 | spin_lock(&group->mark_lock); | ||
| 143 | |||
| 144 | if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) { | ||
| 145 | inode = mark->i.inode; | ||
| 146 | fsnotify_destroy_inode_mark(mark); | ||
| 147 | } else if (mark->flags & FSNOTIFY_MARK_FLAG_VFSMOUNT) | ||
| 148 | fsnotify_destroy_vfsmount_mark(mark); | ||
| 149 | else | ||
| 150 | BUG(); | ||
| 151 | |||
| 152 | list_del_init(&mark->g_list); | ||
| 153 | |||
| 154 | spin_unlock(&group->mark_lock); | ||
| 155 | spin_unlock(&mark->lock); | ||
| 156 | |||
| 157 | spin_lock(&destroy_lock); | ||
| 158 | list_add(&mark->destroy_list, &destroy_list); | ||
| 159 | spin_unlock(&destroy_lock); | ||
| 160 | wake_up(&destroy_waitq); | ||
| 161 | |||
| 162 | /* | ||
| 163 | * Some groups like to know that marks are being freed. This is a | ||
| 164 | * callback to the group function to let it know that this mark | ||
| 165 | * is being freed. | ||
| 166 | */ | ||
| 167 | if (group->ops->freeing_mark) | ||
| 168 | group->ops->freeing_mark(mark, group); | ||
| 169 | |||
| 170 | /* | ||
| 171 | * __fsnotify_update_child_dentry_flags(inode); | ||
| 172 | * | ||
| 173 | * I really want to call that, but we can't, we have no idea if the inode | ||
| 174 | * still exists the second we drop the mark->lock. | ||
| 175 | * | ||
| 176 | * The next time an event arrive to this inode from one of it's children | ||
| 177 | * __fsnotify_parent will see that the inode doesn't care about it's | ||
| 178 | * children and will update all of these flags then. So really this | ||
| 179 | * is just a lazy update (and could be a perf win...) | ||
| 180 | */ | ||
| 181 | |||
| 182 | if (inode && (mark->flags & FSNOTIFY_MARK_FLAG_OBJECT_PINNED)) | ||
| 183 | iput(inode); | ||
| 184 | |||
| 185 | /* | ||
| 186 | * it's possible that this group tried to destroy itself, but this | ||
| 187 | * this mark was simultaneously being freed by inode. If that's the | ||
| 188 | * case, we finish freeing the group here. | ||
| 189 | */ | ||
| 190 | if (unlikely(atomic_dec_and_test(&group->num_marks))) | ||
| 191 | fsnotify_final_destroy_group(group); | ||
| 192 | } | ||
| 193 | |||
| 194 | void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask) | ||
| 195 | { | ||
| 196 | assert_spin_locked(&mark->lock); | ||
| 197 | |||
| 198 | mark->mask = mask; | ||
| 199 | |||
| 200 | if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) | ||
| 201 | fsnotify_set_inode_mark_mask_locked(mark, mask); | ||
| 202 | } | ||
| 203 | |||
| 204 | void fsnotify_set_mark_ignored_mask_locked(struct fsnotify_mark *mark, __u32 mask) | ||
| 205 | { | ||
| 206 | assert_spin_locked(&mark->lock); | ||
| 207 | |||
| 208 | mark->ignored_mask = mask; | ||
| 209 | } | ||
| 210 | |||
| 211 | /* | ||
| 212 | * Attach an initialized mark to a given group and fs object. | ||
| 213 | * These marks may be used for the fsnotify backend to determine which | ||
| 214 | * event types should be delivered to which group. | ||
| 215 | */ | ||
| 216 | int fsnotify_add_mark(struct fsnotify_mark *mark, | ||
| 217 | struct fsnotify_group *group, struct inode *inode, | ||
| 218 | struct vfsmount *mnt, int allow_dups) | ||
| 219 | { | ||
| 220 | int ret = 0; | ||
| 221 | |||
| 222 | BUG_ON(inode && mnt); | ||
| 223 | BUG_ON(!inode && !mnt); | ||
| 224 | |||
| 225 | /* | ||
| 226 | * LOCKING ORDER!!!! | ||
| 227 | * mark->lock | ||
| 228 | * group->mark_lock | ||
| 229 | * inode->i_lock | ||
| 230 | */ | ||
| 231 | spin_lock(&mark->lock); | ||
| 232 | spin_lock(&group->mark_lock); | ||
| 233 | |||
| 234 | mark->flags |= FSNOTIFY_MARK_FLAG_ALIVE; | ||
| 235 | |||
| 236 | mark->group = group; | ||
| 237 | list_add(&mark->g_list, &group->marks_list); | ||
| 238 | atomic_inc(&group->num_marks); | ||
| 239 | fsnotify_get_mark(mark); /* for i_list and g_list */ | ||
| 240 | |||
| 241 | if (inode) { | ||
| 242 | ret = fsnotify_add_inode_mark(mark, group, inode, allow_dups); | ||
| 243 | if (ret) | ||
| 244 | goto err; | ||
| 245 | } else if (mnt) { | ||
| 246 | ret = fsnotify_add_vfsmount_mark(mark, group, mnt, allow_dups); | ||
| 247 | if (ret) | ||
| 248 | goto err; | ||
| 249 | } else { | ||
| 250 | BUG(); | ||
| 251 | } | ||
| 252 | |||
| 253 | spin_unlock(&group->mark_lock); | ||
| 254 | |||
| 255 | /* this will pin the object if appropriate */ | ||
| 256 | fsnotify_set_mark_mask_locked(mark, mark->mask); | ||
| 257 | |||
| 258 | spin_unlock(&mark->lock); | ||
| 259 | |||
| 260 | if (inode) | ||
| 261 | __fsnotify_update_child_dentry_flags(inode); | ||
| 262 | |||
| 263 | return ret; | ||
| 264 | err: | ||
| 265 | mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE; | ||
| 266 | list_del_init(&mark->g_list); | ||
| 267 | mark->group = NULL; | ||
| 268 | atomic_dec(&group->num_marks); | ||
| 269 | |||
| 270 | spin_unlock(&group->mark_lock); | ||
| 271 | spin_unlock(&mark->lock); | ||
| 272 | |||
| 273 | spin_lock(&destroy_lock); | ||
| 274 | list_add(&mark->destroy_list, &destroy_list); | ||
| 275 | spin_unlock(&destroy_lock); | ||
| 276 | wake_up(&destroy_waitq); | ||
| 277 | |||
| 278 | return ret; | ||
| 279 | } | ||
| 280 | |||
| 281 | /* | ||
| 282 | * clear any marks in a group in which mark->flags & flags is true | ||
| 283 | */ | ||
| 284 | void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group, | ||
| 285 | unsigned int flags) | ||
| 286 | { | ||
| 287 | struct fsnotify_mark *lmark, *mark; | ||
| 288 | LIST_HEAD(free_list); | ||
| 289 | |||
| 290 | spin_lock(&group->mark_lock); | ||
| 291 | list_for_each_entry_safe(mark, lmark, &group->marks_list, g_list) { | ||
| 292 | if (mark->flags & flags) { | ||
| 293 | list_add(&mark->free_g_list, &free_list); | ||
| 294 | list_del_init(&mark->g_list); | ||
| 295 | fsnotify_get_mark(mark); | ||
| 296 | } | ||
| 297 | } | ||
| 298 | spin_unlock(&group->mark_lock); | ||
| 299 | |||
| 300 | list_for_each_entry_safe(mark, lmark, &free_list, free_g_list) { | ||
| 301 | fsnotify_destroy_mark(mark); | ||
| 302 | fsnotify_put_mark(mark); | ||
| 303 | } | ||
| 304 | } | ||
| 305 | |||
| 306 | /* | ||
| 307 | * Given a group, destroy all of the marks associated with that group. | ||
| 308 | */ | ||
| 309 | void fsnotify_clear_marks_by_group(struct fsnotify_group *group) | ||
| 310 | { | ||
| 311 | fsnotify_clear_marks_by_group_flags(group, (unsigned int)-1); | ||
| 312 | } | ||
| 313 | |||
| 314 | void fsnotify_duplicate_mark(struct fsnotify_mark *new, struct fsnotify_mark *old) | ||
| 315 | { | ||
| 316 | assert_spin_locked(&old->lock); | ||
| 317 | new->i.inode = old->i.inode; | ||
| 318 | new->m.mnt = old->m.mnt; | ||
| 319 | new->group = old->group; | ||
| 320 | new->mask = old->mask; | ||
| 321 | new->free_mark = old->free_mark; | ||
| 322 | } | ||
| 323 | |||
| 324 | /* | ||
| 325 | * Nothing fancy, just initialize lists and locks and counters. | ||
| 326 | */ | ||
| 327 | void fsnotify_init_mark(struct fsnotify_mark *mark, | ||
| 328 | void (*free_mark)(struct fsnotify_mark *mark)) | ||
| 329 | { | ||
| 330 | memset(mark, 0, sizeof(*mark)); | ||
| 331 | spin_lock_init(&mark->lock); | ||
| 332 | atomic_set(&mark->refcnt, 1); | ||
| 333 | mark->free_mark = free_mark; | ||
| 334 | } | ||
| 335 | |||
| 336 | static int fsnotify_mark_destroy(void *ignored) | ||
| 337 | { | ||
| 338 | struct fsnotify_mark *mark, *next; | ||
| 339 | LIST_HEAD(private_destroy_list); | ||
| 340 | |||
| 341 | for (;;) { | ||
| 342 | spin_lock(&destroy_lock); | ||
| 343 | /* exchange the list head */ | ||
| 344 | list_replace_init(&destroy_list, &private_destroy_list); | ||
| 345 | spin_unlock(&destroy_lock); | ||
| 346 | |||
| 347 | synchronize_srcu(&fsnotify_mark_srcu); | ||
| 348 | |||
| 349 | list_for_each_entry_safe(mark, next, &private_destroy_list, destroy_list) { | ||
| 350 | list_del_init(&mark->destroy_list); | ||
| 351 | fsnotify_put_mark(mark); | ||
| 352 | } | ||
| 353 | |||
| 354 | wait_event_interruptible(destroy_waitq, !list_empty(&destroy_list)); | ||
| 355 | } | ||
| 356 | |||
| 357 | return 0; | ||
| 358 | } | ||
| 359 | |||
| 360 | static int __init fsnotify_mark_init(void) | ||
| 361 | { | ||
| 362 | struct task_struct *thread; | ||
| 363 | |||
| 364 | thread = kthread_run(fsnotify_mark_destroy, NULL, | ||
| 365 | "fsnotify_mark"); | ||
| 366 | if (IS_ERR(thread)) | ||
| 367 | panic("unable to start fsnotify mark destruction thread."); | ||
| 368 | |||
| 369 | return 0; | ||
| 370 | } | ||
| 371 | device_initcall(fsnotify_mark_init); | ||
diff --git a/fs/notify/notification.c b/fs/notify/notification.c index b8bf53b4c108..f39260f8f865 100644 --- a/fs/notify/notification.c +++ b/fs/notify/notification.c | |||
| @@ -56,7 +56,7 @@ static struct kmem_cache *fsnotify_event_holder_cachep; | |||
| 56 | * it is needed. It's refcnt is set 1 at kernel init time and will never | 56 | * it is needed. It's refcnt is set 1 at kernel init time and will never |
| 57 | * get set to 0 so it will never get 'freed' | 57 | * get set to 0 so it will never get 'freed' |
| 58 | */ | 58 | */ |
| 59 | static struct fsnotify_event q_overflow_event; | 59 | static struct fsnotify_event *q_overflow_event; |
| 60 | static atomic_t fsnotify_sync_cookie = ATOMIC_INIT(0); | 60 | static atomic_t fsnotify_sync_cookie = ATOMIC_INIT(0); |
| 61 | 61 | ||
| 62 | /** | 62 | /** |
| @@ -87,12 +87,15 @@ void fsnotify_put_event(struct fsnotify_event *event) | |||
| 87 | return; | 87 | return; |
| 88 | 88 | ||
| 89 | if (atomic_dec_and_test(&event->refcnt)) { | 89 | if (atomic_dec_and_test(&event->refcnt)) { |
| 90 | pr_debug("%s: event=%p\n", __func__, event); | ||
| 91 | |||
| 90 | if (event->data_type == FSNOTIFY_EVENT_PATH) | 92 | if (event->data_type == FSNOTIFY_EVENT_PATH) |
| 91 | path_put(&event->path); | 93 | path_put(&event->path); |
| 92 | 94 | ||
| 93 | BUG_ON(!list_empty(&event->private_data_list)); | 95 | BUG_ON(!list_empty(&event->private_data_list)); |
| 94 | 96 | ||
| 95 | kfree(event->file_name); | 97 | kfree(event->file_name); |
| 98 | put_pid(event->tgid); | ||
| 96 | kmem_cache_free(fsnotify_event_cachep, event); | 99 | kmem_cache_free(fsnotify_event_cachep, event); |
| 97 | } | 100 | } |
| 98 | } | 101 | } |
| @@ -104,7 +107,8 @@ struct fsnotify_event_holder *fsnotify_alloc_event_holder(void) | |||
| 104 | 107 | ||
| 105 | void fsnotify_destroy_event_holder(struct fsnotify_event_holder *holder) | 108 | void fsnotify_destroy_event_holder(struct fsnotify_event_holder *holder) |
| 106 | { | 109 | { |
| 107 | kmem_cache_free(fsnotify_event_holder_cachep, holder); | 110 | if (holder) |
| 111 | kmem_cache_free(fsnotify_event_holder_cachep, holder); | ||
| 108 | } | 112 | } |
| 109 | 113 | ||
| 110 | /* | 114 | /* |
| @@ -129,53 +133,20 @@ struct fsnotify_event_private_data *fsnotify_remove_priv_from_event(struct fsnot | |||
| 129 | } | 133 | } |
| 130 | 134 | ||
| 131 | /* | 135 | /* |
| 132 | * Check if 2 events contain the same information. We do not compare private data | ||
| 133 | * but at this moment that isn't a problem for any know fsnotify listeners. | ||
| 134 | */ | ||
| 135 | static bool event_compare(struct fsnotify_event *old, struct fsnotify_event *new) | ||
| 136 | { | ||
| 137 | if ((old->mask == new->mask) && | ||
| 138 | (old->to_tell == new->to_tell) && | ||
| 139 | (old->data_type == new->data_type) && | ||
| 140 | (old->name_len == new->name_len)) { | ||
| 141 | switch (old->data_type) { | ||
| 142 | case (FSNOTIFY_EVENT_INODE): | ||
| 143 | /* remember, after old was put on the wait_q we aren't | ||
| 144 | * allowed to look at the inode any more, only thing | ||
| 145 | * left to check was if the file_name is the same */ | ||
| 146 | if (!old->name_len || | ||
| 147 | !strcmp(old->file_name, new->file_name)) | ||
| 148 | return true; | ||
| 149 | break; | ||
| 150 | case (FSNOTIFY_EVENT_PATH): | ||
| 151 | if ((old->path.mnt == new->path.mnt) && | ||
| 152 | (old->path.dentry == new->path.dentry)) | ||
| 153 | return true; | ||
| 154 | break; | ||
| 155 | case (FSNOTIFY_EVENT_NONE): | ||
| 156 | if (old->mask & FS_Q_OVERFLOW) | ||
| 157 | return true; | ||
| 158 | else if (old->mask & FS_IN_IGNORED) | ||
| 159 | return false; | ||
| 160 | return false; | ||
| 161 | }; | ||
| 162 | } | ||
| 163 | return false; | ||
| 164 | } | ||
| 165 | |||
| 166 | /* | ||
| 167 | * Add an event to the group notification queue. The group can later pull this | 136 | * Add an event to the group notification queue. The group can later pull this |
| 168 | * event off the queue to deal with. If the event is successfully added to the | 137 | * event off the queue to deal with. If the event is successfully added to the |
| 169 | * group's notification queue, a reference is taken on event. | 138 | * group's notification queue, a reference is taken on event. |
| 170 | */ | 139 | */ |
| 171 | int fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_event *event, | 140 | struct fsnotify_event *fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_event *event, |
| 172 | struct fsnotify_event_private_data *priv) | 141 | struct fsnotify_event_private_data *priv, |
| 142 | struct fsnotify_event *(*merge)(struct list_head *, | ||
| 143 | struct fsnotify_event *)) | ||
| 173 | { | 144 | { |
| 145 | struct fsnotify_event *return_event = NULL; | ||
| 174 | struct fsnotify_event_holder *holder = NULL; | 146 | struct fsnotify_event_holder *holder = NULL; |
| 175 | struct list_head *list = &group->notification_list; | 147 | struct list_head *list = &group->notification_list; |
| 176 | struct fsnotify_event_holder *last_holder; | 148 | |
| 177 | struct fsnotify_event *last_event; | 149 | pr_debug("%s: group=%p event=%p priv=%p\n", __func__, group, event, priv); |
| 178 | int ret = 0; | ||
| 179 | 150 | ||
| 180 | /* | 151 | /* |
| 181 | * There is one fsnotify_event_holder embedded inside each fsnotify_event. | 152 | * There is one fsnotify_event_holder embedded inside each fsnotify_event. |
| @@ -189,18 +160,40 @@ int fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_even | |||
| 189 | alloc_holder: | 160 | alloc_holder: |
| 190 | holder = fsnotify_alloc_event_holder(); | 161 | holder = fsnotify_alloc_event_holder(); |
| 191 | if (!holder) | 162 | if (!holder) |
| 192 | return -ENOMEM; | 163 | return ERR_PTR(-ENOMEM); |
| 193 | } | 164 | } |
| 194 | 165 | ||
| 195 | mutex_lock(&group->notification_mutex); | 166 | mutex_lock(&group->notification_mutex); |
| 196 | 167 | ||
| 197 | if (group->q_len >= group->max_events) { | 168 | if (group->q_len >= group->max_events) { |
| 198 | event = &q_overflow_event; | 169 | event = q_overflow_event; |
| 199 | ret = -EOVERFLOW; | 170 | |
| 171 | /* | ||
| 172 | * we need to return the overflow event | ||
| 173 | * which means we need a ref | ||
| 174 | */ | ||
| 175 | fsnotify_get_event(event); | ||
| 176 | return_event = event; | ||
| 177 | |||
| 200 | /* sorry, no private data on the overflow event */ | 178 | /* sorry, no private data on the overflow event */ |
| 201 | priv = NULL; | 179 | priv = NULL; |
| 202 | } | 180 | } |
| 203 | 181 | ||
| 182 | if (!list_empty(list) && merge) { | ||
| 183 | struct fsnotify_event *tmp; | ||
| 184 | |||
| 185 | tmp = merge(list, event); | ||
| 186 | if (tmp) { | ||
| 187 | mutex_unlock(&group->notification_mutex); | ||
| 188 | |||
| 189 | if (return_event) | ||
| 190 | fsnotify_put_event(return_event); | ||
| 191 | if (holder != &event->holder) | ||
| 192 | fsnotify_destroy_event_holder(holder); | ||
| 193 | return tmp; | ||
| 194 | } | ||
| 195 | } | ||
| 196 | |||
| 204 | spin_lock(&event->lock); | 197 | spin_lock(&event->lock); |
| 205 | 198 | ||
| 206 | if (list_empty(&event->holder.event_list)) { | 199 | if (list_empty(&event->holder.event_list)) { |
| @@ -212,19 +205,13 @@ alloc_holder: | |||
| 212 | * event holder was used, go back and get a new one */ | 205 | * event holder was used, go back and get a new one */ |
| 213 | spin_unlock(&event->lock); | 206 | spin_unlock(&event->lock); |
| 214 | mutex_unlock(&group->notification_mutex); | 207 | mutex_unlock(&group->notification_mutex); |
| 215 | goto alloc_holder; | ||
| 216 | } | ||
| 217 | 208 | ||
| 218 | if (!list_empty(list)) { | 209 | if (return_event) { |
| 219 | last_holder = list_entry(list->prev, struct fsnotify_event_holder, event_list); | 210 | fsnotify_put_event(return_event); |
| 220 | last_event = last_holder->event; | 211 | return_event = NULL; |
| 221 | if (event_compare(last_event, event)) { | ||
| 222 | spin_unlock(&event->lock); | ||
| 223 | mutex_unlock(&group->notification_mutex); | ||
| 224 | if (holder != &event->holder) | ||
| 225 | fsnotify_destroy_event_holder(holder); | ||
| 226 | return -EEXIST; | ||
| 227 | } | 212 | } |
| 213 | |||
| 214 | goto alloc_holder; | ||
| 228 | } | 215 | } |
| 229 | 216 | ||
| 230 | group->q_len++; | 217 | group->q_len++; |
| @@ -238,7 +225,7 @@ alloc_holder: | |||
| 238 | mutex_unlock(&group->notification_mutex); | 225 | mutex_unlock(&group->notification_mutex); |
| 239 | 226 | ||
| 240 | wake_up(&group->notification_waitq); | 227 | wake_up(&group->notification_waitq); |
| 241 | return ret; | 228 | return return_event; |
| 242 | } | 229 | } |
| 243 | 230 | ||
| 244 | /* | 231 | /* |
| @@ -253,6 +240,8 @@ struct fsnotify_event *fsnotify_remove_notify_event(struct fsnotify_group *group | |||
| 253 | 240 | ||
| 254 | BUG_ON(!mutex_is_locked(&group->notification_mutex)); | 241 | BUG_ON(!mutex_is_locked(&group->notification_mutex)); |
| 255 | 242 | ||
| 243 | pr_debug("%s: group=%p\n", __func__, group); | ||
| 244 | |||
| 256 | holder = list_first_entry(&group->notification_list, struct fsnotify_event_holder, event_list); | 245 | holder = list_first_entry(&group->notification_list, struct fsnotify_event_holder, event_list); |
| 257 | 246 | ||
| 258 | event = holder->event; | 247 | event = holder->event; |
| @@ -314,25 +303,82 @@ void fsnotify_flush_notify(struct fsnotify_group *group) | |||
| 314 | 303 | ||
| 315 | static void initialize_event(struct fsnotify_event *event) | 304 | static void initialize_event(struct fsnotify_event *event) |
| 316 | { | 305 | { |
| 317 | event->holder.event = NULL; | ||
| 318 | INIT_LIST_HEAD(&event->holder.event_list); | 306 | INIT_LIST_HEAD(&event->holder.event_list); |
| 319 | atomic_set(&event->refcnt, 1); | 307 | atomic_set(&event->refcnt, 1); |
| 320 | 308 | ||
| 321 | spin_lock_init(&event->lock); | 309 | spin_lock_init(&event->lock); |
| 322 | 310 | ||
| 323 | event->path.dentry = NULL; | ||
| 324 | event->path.mnt = NULL; | ||
| 325 | event->inode = NULL; | ||
| 326 | event->data_type = FSNOTIFY_EVENT_NONE; | ||
| 327 | |||
| 328 | INIT_LIST_HEAD(&event->private_data_list); | 311 | INIT_LIST_HEAD(&event->private_data_list); |
| 312 | } | ||
| 313 | |||
| 314 | /* | ||
| 315 | * Caller damn well better be holding whatever mutex is protecting the | ||
| 316 | * old_holder->event_list and the new_event must be a clean event which | ||
| 317 | * cannot be found anywhere else in the kernel. | ||
| 318 | */ | ||
| 319 | int fsnotify_replace_event(struct fsnotify_event_holder *old_holder, | ||
| 320 | struct fsnotify_event *new_event) | ||
| 321 | { | ||
| 322 | struct fsnotify_event *old_event = old_holder->event; | ||
| 323 | struct fsnotify_event_holder *new_holder = &new_event->holder; | ||
| 329 | 324 | ||
| 330 | event->to_tell = NULL; | 325 | enum event_spinlock_class { |
| 326 | SPINLOCK_OLD, | ||
| 327 | SPINLOCK_NEW, | ||
| 328 | }; | ||
| 331 | 329 | ||
| 332 | event->file_name = NULL; | 330 | pr_debug("%s: old_event=%p new_event=%p\n", __func__, old_event, new_event); |
| 333 | event->name_len = 0; | ||
| 334 | 331 | ||
| 335 | event->sync_cookie = 0; | 332 | /* |
| 333 | * if the new_event's embedded holder is in use someone | ||
| 334 | * screwed up and didn't give us a clean new event. | ||
| 335 | */ | ||
| 336 | BUG_ON(!list_empty(&new_holder->event_list)); | ||
| 337 | |||
| 338 | spin_lock_nested(&old_event->lock, SPINLOCK_OLD); | ||
| 339 | spin_lock_nested(&new_event->lock, SPINLOCK_NEW); | ||
| 340 | |||
| 341 | new_holder->event = new_event; | ||
| 342 | list_replace_init(&old_holder->event_list, &new_holder->event_list); | ||
| 343 | |||
| 344 | spin_unlock(&new_event->lock); | ||
| 345 | spin_unlock(&old_event->lock); | ||
| 346 | |||
| 347 | /* event == holder means we are referenced through the in event holder */ | ||
| 348 | if (old_holder != &old_event->holder) | ||
| 349 | fsnotify_destroy_event_holder(old_holder); | ||
| 350 | |||
| 351 | fsnotify_get_event(new_event); /* on the list take reference */ | ||
| 352 | fsnotify_put_event(old_event); /* off the list, drop reference */ | ||
| 353 | |||
| 354 | return 0; | ||
| 355 | } | ||
| 356 | |||
| 357 | struct fsnotify_event *fsnotify_clone_event(struct fsnotify_event *old_event) | ||
| 358 | { | ||
| 359 | struct fsnotify_event *event; | ||
| 360 | |||
| 361 | event = kmem_cache_alloc(fsnotify_event_cachep, GFP_KERNEL); | ||
| 362 | if (!event) | ||
| 363 | return NULL; | ||
| 364 | |||
| 365 | pr_debug("%s: old_event=%p new_event=%p\n", __func__, old_event, event); | ||
| 366 | |||
| 367 | memcpy(event, old_event, sizeof(*event)); | ||
| 368 | initialize_event(event); | ||
| 369 | |||
| 370 | if (event->name_len) { | ||
| 371 | event->file_name = kstrdup(old_event->file_name, GFP_KERNEL); | ||
| 372 | if (!event->file_name) { | ||
| 373 | kmem_cache_free(fsnotify_event_cachep, event); | ||
| 374 | return NULL; | ||
| 375 | } | ||
| 376 | } | ||
| 377 | event->tgid = get_pid(old_event->tgid); | ||
| 378 | if (event->data_type == FSNOTIFY_EVENT_PATH) | ||
| 379 | path_get(&event->path); | ||
| 380 | |||
| 381 | return event; | ||
| 336 | } | 382 | } |
| 337 | 383 | ||
| 338 | /* | 384 | /* |
| @@ -348,15 +394,18 @@ static void initialize_event(struct fsnotify_event *event) | |||
| 348 | * @name the filename, if available | 394 | * @name the filename, if available |
| 349 | */ | 395 | */ |
| 350 | struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask, void *data, | 396 | struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask, void *data, |
| 351 | int data_type, const char *name, u32 cookie, | 397 | int data_type, const unsigned char *name, |
| 352 | gfp_t gfp) | 398 | u32 cookie, gfp_t gfp) |
| 353 | { | 399 | { |
| 354 | struct fsnotify_event *event; | 400 | struct fsnotify_event *event; |
| 355 | 401 | ||
| 356 | event = kmem_cache_alloc(fsnotify_event_cachep, gfp); | 402 | event = kmem_cache_zalloc(fsnotify_event_cachep, gfp); |
| 357 | if (!event) | 403 | if (!event) |
| 358 | return NULL; | 404 | return NULL; |
| 359 | 405 | ||
| 406 | pr_debug("%s: event=%p to_tell=%p mask=%x data=%p data_type=%d\n", | ||
| 407 | __func__, event, to_tell, mask, data, data_type); | ||
| 408 | |||
| 360 | initialize_event(event); | 409 | initialize_event(event); |
| 361 | 410 | ||
| 362 | if (name) { | 411 | if (name) { |
| @@ -368,30 +417,21 @@ struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask, | |||
| 368 | event->name_len = strlen(event->file_name); | 417 | event->name_len = strlen(event->file_name); |
| 369 | } | 418 | } |
| 370 | 419 | ||
| 420 | event->tgid = get_pid(task_tgid(current)); | ||
| 371 | event->sync_cookie = cookie; | 421 | event->sync_cookie = cookie; |
| 372 | event->to_tell = to_tell; | 422 | event->to_tell = to_tell; |
| 423 | event->data_type = data_type; | ||
| 373 | 424 | ||
| 374 | switch (data_type) { | 425 | switch (data_type) { |
| 375 | case FSNOTIFY_EVENT_FILE: { | ||
| 376 | struct file *file = data; | ||
| 377 | struct path *path = &file->f_path; | ||
| 378 | event->path.dentry = path->dentry; | ||
| 379 | event->path.mnt = path->mnt; | ||
| 380 | path_get(&event->path); | ||
| 381 | event->data_type = FSNOTIFY_EVENT_PATH; | ||
| 382 | break; | ||
| 383 | } | ||
| 384 | case FSNOTIFY_EVENT_PATH: { | 426 | case FSNOTIFY_EVENT_PATH: { |
| 385 | struct path *path = data; | 427 | struct path *path = data; |
| 386 | event->path.dentry = path->dentry; | 428 | event->path.dentry = path->dentry; |
| 387 | event->path.mnt = path->mnt; | 429 | event->path.mnt = path->mnt; |
| 388 | path_get(&event->path); | 430 | path_get(&event->path); |
| 389 | event->data_type = FSNOTIFY_EVENT_PATH; | ||
| 390 | break; | 431 | break; |
| 391 | } | 432 | } |
| 392 | case FSNOTIFY_EVENT_INODE: | 433 | case FSNOTIFY_EVENT_INODE: |
| 393 | event->inode = data; | 434 | event->inode = data; |
| 394 | event->data_type = FSNOTIFY_EVENT_INODE; | ||
| 395 | break; | 435 | break; |
| 396 | case FSNOTIFY_EVENT_NONE: | 436 | case FSNOTIFY_EVENT_NONE: |
| 397 | event->inode = NULL; | 437 | event->inode = NULL; |
| @@ -412,8 +452,11 @@ __init int fsnotify_notification_init(void) | |||
| 412 | fsnotify_event_cachep = KMEM_CACHE(fsnotify_event, SLAB_PANIC); | 452 | fsnotify_event_cachep = KMEM_CACHE(fsnotify_event, SLAB_PANIC); |
| 413 | fsnotify_event_holder_cachep = KMEM_CACHE(fsnotify_event_holder, SLAB_PANIC); | 453 | fsnotify_event_holder_cachep = KMEM_CACHE(fsnotify_event_holder, SLAB_PANIC); |
| 414 | 454 | ||
| 415 | initialize_event(&q_overflow_event); | 455 | q_overflow_event = fsnotify_create_event(NULL, FS_Q_OVERFLOW, NULL, |
| 416 | q_overflow_event.mask = FS_Q_OVERFLOW; | 456 | FSNOTIFY_EVENT_NONE, NULL, 0, |
| 457 | GFP_KERNEL); | ||
| 458 | if (!q_overflow_event) | ||
| 459 | panic("unable to allocate fsnotify q_overflow_event\n"); | ||
| 417 | 460 | ||
| 418 | return 0; | 461 | return 0; |
| 419 | } | 462 | } |
diff --git a/fs/notify/vfsmount_mark.c b/fs/notify/vfsmount_mark.c new file mode 100644 index 000000000000..56772b578fbd --- /dev/null +++ b/fs/notify/vfsmount_mark.c | |||
| @@ -0,0 +1,187 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2008 Red Hat, Inc., Eric Paris <eparis@redhat.com> | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation; either version 2, or (at your option) | ||
| 7 | * any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; see the file COPYING. If not, write to | ||
| 16 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #include <linux/fs.h> | ||
| 20 | #include <linux/init.h> | ||
| 21 | #include <linux/kernel.h> | ||
| 22 | #include <linux/module.h> | ||
| 23 | #include <linux/mount.h> | ||
| 24 | #include <linux/mutex.h> | ||
| 25 | #include <linux/spinlock.h> | ||
| 26 | #include <linux/writeback.h> /* for inode_lock */ | ||
| 27 | |||
| 28 | #include <asm/atomic.h> | ||
| 29 | |||
| 30 | #include <linux/fsnotify_backend.h> | ||
| 31 | #include "fsnotify.h" | ||
| 32 | |||
| 33 | void fsnotify_clear_marks_by_mount(struct vfsmount *mnt) | ||
| 34 | { | ||
| 35 | struct fsnotify_mark *mark, *lmark; | ||
| 36 | struct hlist_node *pos, *n; | ||
| 37 | LIST_HEAD(free_list); | ||
| 38 | |||
| 39 | spin_lock(&mnt->mnt_root->d_lock); | ||
| 40 | hlist_for_each_entry_safe(mark, pos, n, &mnt->mnt_fsnotify_marks, m.m_list) { | ||
| 41 | list_add(&mark->m.free_m_list, &free_list); | ||
| 42 | hlist_del_init_rcu(&mark->m.m_list); | ||
| 43 | fsnotify_get_mark(mark); | ||
| 44 | } | ||
| 45 | spin_unlock(&mnt->mnt_root->d_lock); | ||
| 46 | |||
| 47 | list_for_each_entry_safe(mark, lmark, &free_list, m.free_m_list) { | ||
| 48 | fsnotify_destroy_mark(mark); | ||
| 49 | fsnotify_put_mark(mark); | ||
| 50 | } | ||
| 51 | } | ||
| 52 | |||
| 53 | void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group) | ||
| 54 | { | ||
| 55 | fsnotify_clear_marks_by_group_flags(group, FSNOTIFY_MARK_FLAG_VFSMOUNT); | ||
| 56 | } | ||
| 57 | |||
| 58 | /* | ||
| 59 | * Recalculate the mask of events relevant to a given vfsmount locked. | ||
| 60 | */ | ||
| 61 | static void fsnotify_recalc_vfsmount_mask_locked(struct vfsmount *mnt) | ||
| 62 | { | ||
| 63 | struct fsnotify_mark *mark; | ||
| 64 | struct hlist_node *pos; | ||
| 65 | __u32 new_mask = 0; | ||
| 66 | |||
| 67 | assert_spin_locked(&mnt->mnt_root->d_lock); | ||
| 68 | |||
| 69 | hlist_for_each_entry(mark, pos, &mnt->mnt_fsnotify_marks, m.m_list) | ||
| 70 | new_mask |= mark->mask; | ||
| 71 | mnt->mnt_fsnotify_mask = new_mask; | ||
| 72 | } | ||
| 73 | |||
| 74 | /* | ||
| 75 | * Recalculate the mnt->mnt_fsnotify_mask, or the mask of all FS_* event types | ||
| 76 | * any notifier is interested in hearing for this mount point | ||
| 77 | */ | ||
| 78 | void fsnotify_recalc_vfsmount_mask(struct vfsmount *mnt) | ||
| 79 | { | ||
| 80 | spin_lock(&mnt->mnt_root->d_lock); | ||
| 81 | fsnotify_recalc_vfsmount_mask_locked(mnt); | ||
| 82 | spin_unlock(&mnt->mnt_root->d_lock); | ||
| 83 | } | ||
| 84 | |||
| 85 | void fsnotify_destroy_vfsmount_mark(struct fsnotify_mark *mark) | ||
| 86 | { | ||
| 87 | struct vfsmount *mnt = mark->m.mnt; | ||
| 88 | |||
| 89 | assert_spin_locked(&mark->lock); | ||
| 90 | assert_spin_locked(&mark->group->mark_lock); | ||
| 91 | |||
| 92 | spin_lock(&mnt->mnt_root->d_lock); | ||
| 93 | |||
| 94 | hlist_del_init_rcu(&mark->m.m_list); | ||
| 95 | mark->m.mnt = NULL; | ||
| 96 | |||
| 97 | fsnotify_recalc_vfsmount_mask_locked(mnt); | ||
| 98 | |||
| 99 | spin_unlock(&mnt->mnt_root->d_lock); | ||
| 100 | } | ||
| 101 | |||
| 102 | static struct fsnotify_mark *fsnotify_find_vfsmount_mark_locked(struct fsnotify_group *group, | ||
| 103 | struct vfsmount *mnt) | ||
| 104 | { | ||
| 105 | struct fsnotify_mark *mark; | ||
| 106 | struct hlist_node *pos; | ||
| 107 | |||
| 108 | assert_spin_locked(&mnt->mnt_root->d_lock); | ||
| 109 | |||
| 110 | hlist_for_each_entry(mark, pos, &mnt->mnt_fsnotify_marks, m.m_list) { | ||
| 111 | if (mark->group == group) { | ||
| 112 | fsnotify_get_mark(mark); | ||
| 113 | return mark; | ||
| 114 | } | ||
| 115 | } | ||
| 116 | return NULL; | ||
| 117 | } | ||
| 118 | |||
| 119 | /* | ||
| 120 | * given a group and vfsmount, find the mark associated with that combination. | ||
| 121 | * if found take a reference to that mark and return it, else return NULL | ||
| 122 | */ | ||
| 123 | struct fsnotify_mark *fsnotify_find_vfsmount_mark(struct fsnotify_group *group, | ||
| 124 | struct vfsmount *mnt) | ||
| 125 | { | ||
| 126 | struct fsnotify_mark *mark; | ||
| 127 | |||
| 128 | spin_lock(&mnt->mnt_root->d_lock); | ||
| 129 | mark = fsnotify_find_vfsmount_mark_locked(group, mnt); | ||
| 130 | spin_unlock(&mnt->mnt_root->d_lock); | ||
| 131 | |||
| 132 | return mark; | ||
| 133 | } | ||
| 134 | |||
| 135 | /* | ||
| 136 | * Attach an initialized mark to a given group and vfsmount. | ||
| 137 | * These marks may be used for the fsnotify backend to determine which | ||
| 138 | * event types should be delivered to which groups. | ||
| 139 | */ | ||
| 140 | int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark, | ||
| 141 | struct fsnotify_group *group, struct vfsmount *mnt, | ||
| 142 | int allow_dups) | ||
| 143 | { | ||
| 144 | struct fsnotify_mark *lmark; | ||
| 145 | struct hlist_node *node, *last = NULL; | ||
| 146 | int ret = 0; | ||
| 147 | |||
| 148 | mark->flags |= FSNOTIFY_MARK_FLAG_VFSMOUNT; | ||
| 149 | |||
| 150 | assert_spin_locked(&mark->lock); | ||
| 151 | assert_spin_locked(&group->mark_lock); | ||
| 152 | |||
| 153 | spin_lock(&mnt->mnt_root->d_lock); | ||
| 154 | |||
| 155 | mark->m.mnt = mnt; | ||
| 156 | |||
| 157 | /* is mark the first mark? */ | ||
| 158 | if (hlist_empty(&mnt->mnt_fsnotify_marks)) { | ||
| 159 | hlist_add_head_rcu(&mark->m.m_list, &mnt->mnt_fsnotify_marks); | ||
| 160 | goto out; | ||
| 161 | } | ||
| 162 | |||
| 163 | /* should mark be in the middle of the current list? */ | ||
| 164 | hlist_for_each_entry(lmark, node, &mnt->mnt_fsnotify_marks, m.m_list) { | ||
| 165 | last = node; | ||
| 166 | |||
| 167 | if ((lmark->group == group) && !allow_dups) { | ||
| 168 | ret = -EEXIST; | ||
| 169 | goto out; | ||
| 170 | } | ||
| 171 | |||
| 172 | if (mark->group < lmark->group) | ||
| 173 | continue; | ||
| 174 | |||
| 175 | hlist_add_before_rcu(&mark->m.m_list, &lmark->m.m_list); | ||
| 176 | goto out; | ||
| 177 | } | ||
| 178 | |||
| 179 | BUG_ON(last == NULL); | ||
| 180 | /* mark should be the last entry. last is the current last entry */ | ||
| 181 | hlist_add_after_rcu(last, &mark->m.m_list); | ||
| 182 | out: | ||
| 183 | fsnotify_recalc_vfsmount_mask_locked(mnt); | ||
| 184 | spin_unlock(&mnt->mnt_root->d_lock); | ||
| 185 | |||
| 186 | return ret; | ||
| 187 | } | ||
diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index 4b57fb1eac2a..93622b175fc7 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c | |||
| @@ -2238,7 +2238,7 @@ void ntfs_clear_extent_inode(ntfs_inode *ni) | |||
| 2238 | } | 2238 | } |
| 2239 | 2239 | ||
| 2240 | /** | 2240 | /** |
| 2241 | * ntfs_clear_big_inode - clean up the ntfs specific part of an inode | 2241 | * ntfs_evict_big_inode - clean up the ntfs specific part of an inode |
| 2242 | * @vi: vfs inode pending annihilation | 2242 | * @vi: vfs inode pending annihilation |
| 2243 | * | 2243 | * |
| 2244 | * When the VFS is going to remove an inode from memory, ntfs_clear_big_inode() | 2244 | * When the VFS is going to remove an inode from memory, ntfs_clear_big_inode() |
| @@ -2247,10 +2247,13 @@ void ntfs_clear_extent_inode(ntfs_inode *ni) | |||
| 2247 | * | 2247 | * |
| 2248 | * If the MFT record is dirty, we commit it before doing anything else. | 2248 | * If the MFT record is dirty, we commit it before doing anything else. |
| 2249 | */ | 2249 | */ |
| 2250 | void ntfs_clear_big_inode(struct inode *vi) | 2250 | void ntfs_evict_big_inode(struct inode *vi) |
| 2251 | { | 2251 | { |
| 2252 | ntfs_inode *ni = NTFS_I(vi); | 2252 | ntfs_inode *ni = NTFS_I(vi); |
| 2253 | 2253 | ||
| 2254 | truncate_inode_pages(&vi->i_data, 0); | ||
| 2255 | end_writeback(vi); | ||
| 2256 | |||
| 2254 | #ifdef NTFS_RW | 2257 | #ifdef NTFS_RW |
| 2255 | if (NInoDirty(ni)) { | 2258 | if (NInoDirty(ni)) { |
| 2256 | bool was_bad = (is_bad_inode(vi)); | 2259 | bool was_bad = (is_bad_inode(vi)); |
| @@ -2879,9 +2882,6 @@ void ntfs_truncate_vfs(struct inode *vi) { | |||
| 2879 | * | 2882 | * |
| 2880 | * Called with ->i_mutex held. For the ATTR_SIZE (i.e. ->truncate) case, also | 2883 | * Called with ->i_mutex held. For the ATTR_SIZE (i.e. ->truncate) case, also |
| 2881 | * called with ->i_alloc_sem held for writing. | 2884 | * called with ->i_alloc_sem held for writing. |
| 2882 | * | ||
| 2883 | * Basically this is a copy of generic notify_change() and inode_setattr() | ||
| 2884 | * functionality, except we intercept and abort changes in i_size. | ||
| 2885 | */ | 2885 | */ |
| 2886 | int ntfs_setattr(struct dentry *dentry, struct iattr *attr) | 2886 | int ntfs_setattr(struct dentry *dentry, struct iattr *attr) |
| 2887 | { | 2887 | { |
diff --git a/fs/ntfs/inode.h b/fs/ntfs/inode.h index 9a113544605d..2dabf813456c 100644 --- a/fs/ntfs/inode.h +++ b/fs/ntfs/inode.h | |||
| @@ -279,7 +279,7 @@ extern struct inode *ntfs_index_iget(struct inode *base_vi, ntfschar *name, | |||
| 279 | 279 | ||
| 280 | extern struct inode *ntfs_alloc_big_inode(struct super_block *sb); | 280 | extern struct inode *ntfs_alloc_big_inode(struct super_block *sb); |
| 281 | extern void ntfs_destroy_big_inode(struct inode *inode); | 281 | extern void ntfs_destroy_big_inode(struct inode *inode); |
| 282 | extern void ntfs_clear_big_inode(struct inode *vi); | 282 | extern void ntfs_evict_big_inode(struct inode *vi); |
| 283 | 283 | ||
| 284 | extern void __ntfs_init_inode(struct super_block *sb, ntfs_inode *ni); | 284 | extern void __ntfs_init_inode(struct super_block *sb, ntfs_inode *ni); |
| 285 | 285 | ||
diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index 0de1db6cddbf..512806171bfa 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c | |||
| @@ -2700,7 +2700,7 @@ static const struct super_operations ntfs_sops = { | |||
| 2700 | .put_super = ntfs_put_super, /* Syscall: umount. */ | 2700 | .put_super = ntfs_put_super, /* Syscall: umount. */ |
| 2701 | .statfs = ntfs_statfs, /* Syscall: statfs */ | 2701 | .statfs = ntfs_statfs, /* Syscall: statfs */ |
| 2702 | .remount_fs = ntfs_remount, /* Syscall: mount -o remount. */ | 2702 | .remount_fs = ntfs_remount, /* Syscall: mount -o remount. */ |
| 2703 | .clear_inode = ntfs_clear_big_inode, /* VFS: Called when an inode is | 2703 | .evict_inode = ntfs_evict_big_inode, /* VFS: Called when an inode is |
| 2704 | removed from memory. */ | 2704 | removed from memory. */ |
| 2705 | //.umount_begin = NULL, /* Forced umount. */ | 2705 | //.umount_begin = NULL, /* Forced umount. */ |
| 2706 | .show_options = ntfs_show_options, /* Show mount options in | 2706 | .show_options = ntfs_show_options, /* Show mount options in |
diff --git a/fs/ocfs2/acl.c b/fs/ocfs2/acl.c index da702294d7e7..a76e0aa5cd3f 100644 --- a/fs/ocfs2/acl.c +++ b/fs/ocfs2/acl.c | |||
| @@ -290,12 +290,30 @@ static int ocfs2_set_acl(handle_t *handle, | |||
| 290 | 290 | ||
| 291 | int ocfs2_check_acl(struct inode *inode, int mask) | 291 | int ocfs2_check_acl(struct inode *inode, int mask) |
| 292 | { | 292 | { |
| 293 | struct posix_acl *acl = ocfs2_get_acl(inode, ACL_TYPE_ACCESS); | 293 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); |
| 294 | struct buffer_head *di_bh = NULL; | ||
| 295 | struct posix_acl *acl; | ||
| 296 | int ret = -EAGAIN; | ||
| 294 | 297 | ||
| 295 | if (IS_ERR(acl)) | 298 | if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL)) |
| 299 | return ret; | ||
| 300 | |||
| 301 | ret = ocfs2_read_inode_block(inode, &di_bh); | ||
| 302 | if (ret < 0) { | ||
| 303 | mlog_errno(ret); | ||
| 304 | return ret; | ||
| 305 | } | ||
| 306 | |||
| 307 | acl = ocfs2_get_acl_nolock(inode, ACL_TYPE_ACCESS, di_bh); | ||
| 308 | |||
| 309 | brelse(di_bh); | ||
| 310 | |||
| 311 | if (IS_ERR(acl)) { | ||
| 312 | mlog_errno(PTR_ERR(acl)); | ||
| 296 | return PTR_ERR(acl); | 313 | return PTR_ERR(acl); |
| 314 | } | ||
| 297 | if (acl) { | 315 | if (acl) { |
| 298 | int ret = posix_acl_permission(inode, acl, mask); | 316 | ret = posix_acl_permission(inode, acl, mask); |
| 299 | posix_acl_release(acl); | 317 | posix_acl_release(acl); |
| 300 | return ret; | 318 | return ret; |
| 301 | } | 319 | } |
| @@ -344,7 +362,7 @@ int ocfs2_init_acl(handle_t *handle, | |||
| 344 | { | 362 | { |
| 345 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); | 363 | struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); |
| 346 | struct posix_acl *acl = NULL; | 364 | struct posix_acl *acl = NULL; |
| 347 | int ret = 0; | 365 | int ret = 0, ret2; |
| 348 | mode_t mode; | 366 | mode_t mode; |
| 349 | 367 | ||
| 350 | if (!S_ISLNK(inode->i_mode)) { | 368 | if (!S_ISLNK(inode->i_mode)) { |
| @@ -381,7 +399,12 @@ int ocfs2_init_acl(handle_t *handle, | |||
| 381 | mode = inode->i_mode; | 399 | mode = inode->i_mode; |
| 382 | ret = posix_acl_create_masq(clone, &mode); | 400 | ret = posix_acl_create_masq(clone, &mode); |
| 383 | if (ret >= 0) { | 401 | if (ret >= 0) { |
| 384 | ret = ocfs2_acl_set_mode(inode, di_bh, handle, mode); | 402 | ret2 = ocfs2_acl_set_mode(inode, di_bh, handle, mode); |
| 403 | if (ret2) { | ||
| 404 | mlog_errno(ret2); | ||
| 405 | ret = ret2; | ||
| 406 | goto cleanup; | ||
| 407 | } | ||
| 385 | if (ret > 0) { | 408 | if (ret > 0) { |
| 386 | ret = ocfs2_set_acl(handle, inode, | 409 | ret = ocfs2_set_acl(handle, inode, |
| 387 | di_bh, ACL_TYPE_ACCESS, | 410 | di_bh, ACL_TYPE_ACCESS, |
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index 96337a4fbbdf..0de69c9a08be 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c | |||
| @@ -643,11 +643,10 @@ static ssize_t ocfs2_direct_IO(int rw, | |||
| 643 | if (i_size_read(inode) <= offset) | 643 | if (i_size_read(inode) <= offset) |
| 644 | return 0; | 644 | return 0; |
| 645 | 645 | ||
| 646 | ret = blockdev_direct_IO_no_locking(rw, iocb, inode, | 646 | ret = __blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, |
| 647 | inode->i_sb->s_bdev, iov, offset, | 647 | iov, offset, nr_segs, |
| 648 | nr_segs, | 648 | ocfs2_direct_IO_get_blocks, |
| 649 | ocfs2_direct_IO_get_blocks, | 649 | ocfs2_dio_end_io, NULL, 0); |
| 650 | ocfs2_dio_end_io); | ||
| 651 | 650 | ||
| 652 | mlog_exit(ret); | 651 | mlog_exit(ret); |
| 653 | return ret; | 652 | return ret; |
diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c index aa75ca3f78da..1361997cf205 100644 --- a/fs/ocfs2/cluster/tcp.c +++ b/fs/ocfs2/cluster/tcp.c | |||
| @@ -1759,6 +1759,7 @@ static int o2net_accept_one(struct socket *sock) | |||
| 1759 | struct sockaddr_in sin; | 1759 | struct sockaddr_in sin; |
| 1760 | struct socket *new_sock = NULL; | 1760 | struct socket *new_sock = NULL; |
| 1761 | struct o2nm_node *node = NULL; | 1761 | struct o2nm_node *node = NULL; |
| 1762 | struct o2nm_node *local_node = NULL; | ||
| 1762 | struct o2net_sock_container *sc = NULL; | 1763 | struct o2net_sock_container *sc = NULL; |
| 1763 | struct o2net_node *nn; | 1764 | struct o2net_node *nn; |
| 1764 | 1765 | ||
| @@ -1796,11 +1797,15 @@ static int o2net_accept_one(struct socket *sock) | |||
| 1796 | goto out; | 1797 | goto out; |
| 1797 | } | 1798 | } |
| 1798 | 1799 | ||
| 1799 | if (o2nm_this_node() > node->nd_num) { | 1800 | if (o2nm_this_node() >= node->nd_num) { |
| 1800 | mlog(ML_NOTICE, "unexpected connect attempted from a lower " | 1801 | local_node = o2nm_get_node_by_num(o2nm_this_node()); |
| 1801 | "numbered node '%s' at " "%pI4:%d with num %u\n", | 1802 | mlog(ML_NOTICE, "unexpected connect attempt seen at node '%s' (" |
| 1802 | node->nd_name, &sin.sin_addr.s_addr, | 1803 | "%u, %pI4:%d) from node '%s' (%u, %pI4:%d)\n", |
| 1803 | ntohs(sin.sin_port), node->nd_num); | 1804 | local_node->nd_name, local_node->nd_num, |
| 1805 | &(local_node->nd_ipv4_address), | ||
| 1806 | ntohs(local_node->nd_ipv4_port), | ||
| 1807 | node->nd_name, node->nd_num, &sin.sin_addr.s_addr, | ||
| 1808 | ntohs(sin.sin_port)); | ||
| 1804 | ret = -EINVAL; | 1809 | ret = -EINVAL; |
| 1805 | goto out; | 1810 | goto out; |
| 1806 | } | 1811 | } |
| @@ -1857,6 +1862,8 @@ out: | |||
| 1857 | sock_release(new_sock); | 1862 | sock_release(new_sock); |
| 1858 | if (node) | 1863 | if (node) |
| 1859 | o2nm_node_put(node); | 1864 | o2nm_node_put(node); |
| 1865 | if (local_node) | ||
| 1866 | o2nm_node_put(local_node); | ||
| 1860 | if (sc) | 1867 | if (sc) |
| 1861 | sc_put(sc); | 1868 | sc_put(sc); |
| 1862 | return ret; | 1869 | return ret; |
diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c index 94b97fc6a88e..ffb4c68dafa4 100644 --- a/fs/ocfs2/dlm/dlmmaster.c +++ b/fs/ocfs2/dlm/dlmmaster.c | |||
| @@ -511,8 +511,6 @@ static void dlm_lockres_release(struct kref *kref) | |||
| 511 | 511 | ||
| 512 | atomic_dec(&dlm->res_cur_count); | 512 | atomic_dec(&dlm->res_cur_count); |
| 513 | 513 | ||
| 514 | dlm_put(dlm); | ||
| 515 | |||
| 516 | if (!hlist_unhashed(&res->hash_node) || | 514 | if (!hlist_unhashed(&res->hash_node) || |
| 517 | !list_empty(&res->granted) || | 515 | !list_empty(&res->granted) || |
| 518 | !list_empty(&res->converting) || | 516 | !list_empty(&res->converting) || |
| @@ -585,8 +583,6 @@ static void dlm_init_lockres(struct dlm_ctxt *dlm, | |||
| 585 | res->migration_pending = 0; | 583 | res->migration_pending = 0; |
| 586 | res->inflight_locks = 0; | 584 | res->inflight_locks = 0; |
| 587 | 585 | ||
| 588 | /* put in dlm_lockres_release */ | ||
| 589 | dlm_grab(dlm); | ||
| 590 | res->dlm = dlm; | 586 | res->dlm = dlm; |
| 591 | 587 | ||
| 592 | kref_init(&res->refs); | 588 | kref_init(&res->refs); |
| @@ -3050,8 +3046,6 @@ int dlm_migrate_request_handler(struct o2net_msg *msg, u32 len, void *data, | |||
| 3050 | /* check for pre-existing lock */ | 3046 | /* check for pre-existing lock */ |
| 3051 | spin_lock(&dlm->spinlock); | 3047 | spin_lock(&dlm->spinlock); |
| 3052 | res = __dlm_lookup_lockres(dlm, name, namelen, hash); | 3048 | res = __dlm_lookup_lockres(dlm, name, namelen, hash); |
| 3053 | spin_lock(&dlm->master_lock); | ||
| 3054 | |||
| 3055 | if (res) { | 3049 | if (res) { |
| 3056 | spin_lock(&res->spinlock); | 3050 | spin_lock(&res->spinlock); |
| 3057 | if (res->state & DLM_LOCK_RES_RECOVERING) { | 3051 | if (res->state & DLM_LOCK_RES_RECOVERING) { |
| @@ -3069,14 +3063,15 @@ int dlm_migrate_request_handler(struct o2net_msg *msg, u32 len, void *data, | |||
| 3069 | spin_unlock(&res->spinlock); | 3063 | spin_unlock(&res->spinlock); |
| 3070 | } | 3064 | } |
| 3071 | 3065 | ||
| 3066 | spin_lock(&dlm->master_lock); | ||
| 3072 | /* ignore status. only nonzero status would BUG. */ | 3067 | /* ignore status. only nonzero status would BUG. */ |
| 3073 | ret = dlm_add_migration_mle(dlm, res, mle, &oldmle, | 3068 | ret = dlm_add_migration_mle(dlm, res, mle, &oldmle, |
| 3074 | name, namelen, | 3069 | name, namelen, |
| 3075 | migrate->new_master, | 3070 | migrate->new_master, |
| 3076 | migrate->master); | 3071 | migrate->master); |
| 3077 | 3072 | ||
| 3078 | unlock: | ||
| 3079 | spin_unlock(&dlm->master_lock); | 3073 | spin_unlock(&dlm->master_lock); |
| 3074 | unlock: | ||
| 3080 | spin_unlock(&dlm->spinlock); | 3075 | spin_unlock(&dlm->spinlock); |
| 3081 | 3076 | ||
| 3082 | if (oldmle) { | 3077 | if (oldmle) { |
diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c index 9dfaac73b36d..aaaffbcbe916 100644 --- a/fs/ocfs2/dlm/dlmrecovery.c +++ b/fs/ocfs2/dlm/dlmrecovery.c | |||
| @@ -1997,6 +1997,8 @@ void dlm_move_lockres_to_recovery_list(struct dlm_ctxt *dlm, | |||
| 1997 | struct list_head *queue; | 1997 | struct list_head *queue; |
| 1998 | struct dlm_lock *lock, *next; | 1998 | struct dlm_lock *lock, *next; |
| 1999 | 1999 | ||
| 2000 | assert_spin_locked(&dlm->spinlock); | ||
| 2001 | assert_spin_locked(&res->spinlock); | ||
| 2000 | res->state |= DLM_LOCK_RES_RECOVERING; | 2002 | res->state |= DLM_LOCK_RES_RECOVERING; |
| 2001 | if (!list_empty(&res->recovering)) { | 2003 | if (!list_empty(&res->recovering)) { |
| 2002 | mlog(0, | 2004 | mlog(0, |
| @@ -2326,19 +2328,15 @@ static void dlm_do_local_recovery_cleanup(struct dlm_ctxt *dlm, u8 dead_node) | |||
| 2326 | /* zero the lvb if necessary */ | 2328 | /* zero the lvb if necessary */ |
| 2327 | dlm_revalidate_lvb(dlm, res, dead_node); | 2329 | dlm_revalidate_lvb(dlm, res, dead_node); |
| 2328 | if (res->owner == dead_node) { | 2330 | if (res->owner == dead_node) { |
| 2329 | if (res->state & DLM_LOCK_RES_DROPPING_REF) | 2331 | if (res->state & DLM_LOCK_RES_DROPPING_REF) { |
| 2330 | mlog(0, "%s:%.*s: owned by " | 2332 | mlog(ML_NOTICE, "Ignore %.*s for " |
| 2331 | "dead node %u, this node was " | 2333 | "recovery as it is being freed\n", |
| 2332 | "dropping its ref when it died. " | 2334 | res->lockname.len, |
| 2333 | "continue, dropping the flag.\n", | 2335 | res->lockname.name); |
| 2334 | dlm->name, res->lockname.len, | 2336 | } else |
| 2335 | res->lockname.name, dead_node); | 2337 | dlm_move_lockres_to_recovery_list(dlm, |
| 2336 | 2338 | res); | |
| 2337 | /* the wake_up for this will happen when the | ||
| 2338 | * RECOVERING flag is dropped later */ | ||
| 2339 | res->state &= ~DLM_LOCK_RES_DROPPING_REF; | ||
| 2340 | 2339 | ||
| 2341 | dlm_move_lockres_to_recovery_list(dlm, res); | ||
| 2342 | } else if (res->owner == dlm->node_num) { | 2340 | } else if (res->owner == dlm->node_num) { |
| 2343 | dlm_free_dead_locks(dlm, res, dead_node); | 2341 | dlm_free_dead_locks(dlm, res, dead_node); |
| 2344 | __dlm_lockres_calc_usage(dlm, res); | 2342 | __dlm_lockres_calc_usage(dlm, res); |
diff --git a/fs/ocfs2/dlm/dlmthread.c b/fs/ocfs2/dlm/dlmthread.c index d4f73ca68fe5..2211acf33d9b 100644 --- a/fs/ocfs2/dlm/dlmthread.c +++ b/fs/ocfs2/dlm/dlmthread.c | |||
| @@ -92,19 +92,27 @@ int __dlm_lockres_has_locks(struct dlm_lock_resource *res) | |||
| 92 | * truly ready to be freed. */ | 92 | * truly ready to be freed. */ |
| 93 | int __dlm_lockres_unused(struct dlm_lock_resource *res) | 93 | int __dlm_lockres_unused(struct dlm_lock_resource *res) |
| 94 | { | 94 | { |
| 95 | if (!__dlm_lockres_has_locks(res) && | 95 | int bit; |
| 96 | (list_empty(&res->dirty) && !(res->state & DLM_LOCK_RES_DIRTY))) { | 96 | |
| 97 | /* try not to scan the bitmap unless the first two | 97 | if (__dlm_lockres_has_locks(res)) |
| 98 | * conditions are already true */ | 98 | return 0; |
| 99 | int bit = find_next_bit(res->refmap, O2NM_MAX_NODES, 0); | 99 | |
| 100 | if (bit >= O2NM_MAX_NODES) { | 100 | if (!list_empty(&res->dirty) || res->state & DLM_LOCK_RES_DIRTY) |
| 101 | /* since the bit for dlm->node_num is not | 101 | return 0; |
| 102 | * set, inflight_locks better be zero */ | 102 | |
| 103 | BUG_ON(res->inflight_locks != 0); | 103 | if (res->state & DLM_LOCK_RES_RECOVERING) |
| 104 | return 1; | 104 | return 0; |
| 105 | } | 105 | |
| 106 | } | 106 | bit = find_next_bit(res->refmap, O2NM_MAX_NODES, 0); |
| 107 | return 0; | 107 | if (bit < O2NM_MAX_NODES) |
| 108 | return 0; | ||
| 109 | |||
| 110 | /* | ||
| 111 | * since the bit for dlm->node_num is not set, inflight_locks better | ||
| 112 | * be zero | ||
| 113 | */ | ||
| 114 | BUG_ON(res->inflight_locks != 0); | ||
| 115 | return 1; | ||
| 108 | } | 116 | } |
| 109 | 117 | ||
| 110 | 118 | ||
| @@ -152,45 +160,25 @@ void dlm_lockres_calc_usage(struct dlm_ctxt *dlm, | |||
| 152 | spin_unlock(&dlm->spinlock); | 160 | spin_unlock(&dlm->spinlock); |
| 153 | } | 161 | } |
| 154 | 162 | ||
| 155 | static int dlm_purge_lockres(struct dlm_ctxt *dlm, | 163 | static void dlm_purge_lockres(struct dlm_ctxt *dlm, |
| 156 | struct dlm_lock_resource *res) | 164 | struct dlm_lock_resource *res) |
| 157 | { | 165 | { |
| 158 | int master; | 166 | int master; |
| 159 | int ret = 0; | 167 | int ret = 0; |
| 160 | 168 | ||
| 161 | spin_lock(&res->spinlock); | 169 | assert_spin_locked(&dlm->spinlock); |
| 162 | if (!__dlm_lockres_unused(res)) { | 170 | assert_spin_locked(&res->spinlock); |
| 163 | mlog(0, "%s:%.*s: tried to purge but not unused\n", | ||
| 164 | dlm->name, res->lockname.len, res->lockname.name); | ||
| 165 | __dlm_print_one_lock_resource(res); | ||
| 166 | spin_unlock(&res->spinlock); | ||
| 167 | BUG(); | ||
| 168 | } | ||
| 169 | |||
| 170 | if (res->state & DLM_LOCK_RES_MIGRATING) { | ||
| 171 | mlog(0, "%s:%.*s: Delay dropref as this lockres is " | ||
| 172 | "being remastered\n", dlm->name, res->lockname.len, | ||
| 173 | res->lockname.name); | ||
| 174 | /* Re-add the lockres to the end of the purge list */ | ||
| 175 | if (!list_empty(&res->purge)) { | ||
| 176 | list_del_init(&res->purge); | ||
| 177 | list_add_tail(&res->purge, &dlm->purge_list); | ||
| 178 | } | ||
| 179 | spin_unlock(&res->spinlock); | ||
| 180 | return 0; | ||
| 181 | } | ||
| 182 | 171 | ||
| 183 | master = (res->owner == dlm->node_num); | 172 | master = (res->owner == dlm->node_num); |
| 184 | 173 | ||
| 185 | if (!master) | ||
| 186 | res->state |= DLM_LOCK_RES_DROPPING_REF; | ||
| 187 | spin_unlock(&res->spinlock); | ||
| 188 | 174 | ||
| 189 | mlog(0, "purging lockres %.*s, master = %d\n", res->lockname.len, | 175 | mlog(0, "purging lockres %.*s, master = %d\n", res->lockname.len, |
| 190 | res->lockname.name, master); | 176 | res->lockname.name, master); |
| 191 | 177 | ||
| 192 | if (!master) { | 178 | if (!master) { |
| 179 | res->state |= DLM_LOCK_RES_DROPPING_REF; | ||
| 193 | /* drop spinlock... retake below */ | 180 | /* drop spinlock... retake below */ |
| 181 | spin_unlock(&res->spinlock); | ||
| 194 | spin_unlock(&dlm->spinlock); | 182 | spin_unlock(&dlm->spinlock); |
| 195 | 183 | ||
| 196 | spin_lock(&res->spinlock); | 184 | spin_lock(&res->spinlock); |
| @@ -208,31 +196,35 @@ static int dlm_purge_lockres(struct dlm_ctxt *dlm, | |||
| 208 | mlog(0, "%s:%.*s: dlm_deref_lockres returned %d\n", | 196 | mlog(0, "%s:%.*s: dlm_deref_lockres returned %d\n", |
| 209 | dlm->name, res->lockname.len, res->lockname.name, ret); | 197 | dlm->name, res->lockname.len, res->lockname.name, ret); |
| 210 | spin_lock(&dlm->spinlock); | 198 | spin_lock(&dlm->spinlock); |
| 199 | spin_lock(&res->spinlock); | ||
| 211 | } | 200 | } |
| 212 | 201 | ||
| 213 | spin_lock(&res->spinlock); | ||
| 214 | if (!list_empty(&res->purge)) { | 202 | if (!list_empty(&res->purge)) { |
| 215 | mlog(0, "removing lockres %.*s:%p from purgelist, " | 203 | mlog(0, "removing lockres %.*s:%p from purgelist, " |
| 216 | "master = %d\n", res->lockname.len, res->lockname.name, | 204 | "master = %d\n", res->lockname.len, res->lockname.name, |
| 217 | res, master); | 205 | res, master); |
| 218 | list_del_init(&res->purge); | 206 | list_del_init(&res->purge); |
| 219 | spin_unlock(&res->spinlock); | ||
| 220 | dlm_lockres_put(res); | 207 | dlm_lockres_put(res); |
| 221 | dlm->purge_count--; | 208 | dlm->purge_count--; |
| 222 | } else | 209 | } |
| 223 | spin_unlock(&res->spinlock); | 210 | |
| 211 | if (!__dlm_lockres_unused(res)) { | ||
| 212 | mlog(ML_ERROR, "found lockres %s:%.*s: in use after deref\n", | ||
| 213 | dlm->name, res->lockname.len, res->lockname.name); | ||
| 214 | __dlm_print_one_lock_resource(res); | ||
| 215 | BUG(); | ||
| 216 | } | ||
| 224 | 217 | ||
| 225 | __dlm_unhash_lockres(res); | 218 | __dlm_unhash_lockres(res); |
| 226 | 219 | ||
| 227 | /* lockres is not in the hash now. drop the flag and wake up | 220 | /* lockres is not in the hash now. drop the flag and wake up |
| 228 | * any processes waiting in dlm_get_lock_resource. */ | 221 | * any processes waiting in dlm_get_lock_resource. */ |
| 229 | if (!master) { | 222 | if (!master) { |
| 230 | spin_lock(&res->spinlock); | ||
| 231 | res->state &= ~DLM_LOCK_RES_DROPPING_REF; | 223 | res->state &= ~DLM_LOCK_RES_DROPPING_REF; |
| 232 | spin_unlock(&res->spinlock); | 224 | spin_unlock(&res->spinlock); |
| 233 | wake_up(&res->wq); | 225 | wake_up(&res->wq); |
| 234 | } | 226 | } else |
| 235 | return 0; | 227 | spin_unlock(&res->spinlock); |
| 236 | } | 228 | } |
| 237 | 229 | ||
| 238 | static void dlm_run_purge_list(struct dlm_ctxt *dlm, | 230 | static void dlm_run_purge_list(struct dlm_ctxt *dlm, |
| @@ -251,17 +243,7 @@ static void dlm_run_purge_list(struct dlm_ctxt *dlm, | |||
| 251 | lockres = list_entry(dlm->purge_list.next, | 243 | lockres = list_entry(dlm->purge_list.next, |
| 252 | struct dlm_lock_resource, purge); | 244 | struct dlm_lock_resource, purge); |
| 253 | 245 | ||
| 254 | /* Status of the lockres *might* change so double | ||
| 255 | * check. If the lockres is unused, holding the dlm | ||
| 256 | * spinlock will prevent people from getting and more | ||
| 257 | * refs on it -- there's no need to keep the lockres | ||
| 258 | * spinlock. */ | ||
| 259 | spin_lock(&lockres->spinlock); | 246 | spin_lock(&lockres->spinlock); |
| 260 | unused = __dlm_lockres_unused(lockres); | ||
| 261 | spin_unlock(&lockres->spinlock); | ||
| 262 | |||
| 263 | if (!unused) | ||
| 264 | continue; | ||
| 265 | 247 | ||
| 266 | purge_jiffies = lockres->last_used + | 248 | purge_jiffies = lockres->last_used + |
| 267 | msecs_to_jiffies(DLM_PURGE_INTERVAL_MS); | 249 | msecs_to_jiffies(DLM_PURGE_INTERVAL_MS); |
| @@ -273,15 +255,29 @@ static void dlm_run_purge_list(struct dlm_ctxt *dlm, | |||
| 273 | * in tail order, we can stop at the first | 255 | * in tail order, we can stop at the first |
| 274 | * unpurgable resource -- anyone added after | 256 | * unpurgable resource -- anyone added after |
| 275 | * him will have a greater last_used value */ | 257 | * him will have a greater last_used value */ |
| 258 | spin_unlock(&lockres->spinlock); | ||
| 276 | break; | 259 | break; |
| 277 | } | 260 | } |
| 278 | 261 | ||
| 262 | /* Status of the lockres *might* change so double | ||
| 263 | * check. If the lockres is unused, holding the dlm | ||
| 264 | * spinlock will prevent people from getting and more | ||
| 265 | * refs on it. */ | ||
| 266 | unused = __dlm_lockres_unused(lockres); | ||
| 267 | if (!unused || | ||
| 268 | (lockres->state & DLM_LOCK_RES_MIGRATING)) { | ||
| 269 | mlog(0, "lockres %s:%.*s: is in use or " | ||
| 270 | "being remastered, used %d, state %d\n", | ||
| 271 | dlm->name, lockres->lockname.len, | ||
| 272 | lockres->lockname.name, !unused, lockres->state); | ||
| 273 | list_move_tail(&dlm->purge_list, &lockres->purge); | ||
| 274 | spin_unlock(&lockres->spinlock); | ||
| 275 | continue; | ||
| 276 | } | ||
| 277 | |||
| 279 | dlm_lockres_get(lockres); | 278 | dlm_lockres_get(lockres); |
| 280 | 279 | ||
| 281 | /* This may drop and reacquire the dlm spinlock if it | 280 | dlm_purge_lockres(dlm, lockres); |
| 282 | * has to do migration. */ | ||
| 283 | if (dlm_purge_lockres(dlm, lockres)) | ||
| 284 | BUG(); | ||
| 285 | 281 | ||
| 286 | dlm_lockres_put(lockres); | 282 | dlm_lockres_put(lockres); |
| 287 | 283 | ||
diff --git a/fs/ocfs2/dlmfs/dlmfs.c b/fs/ocfs2/dlmfs/dlmfs.c index bef34d0528d5..c2903b84bb7a 100644 --- a/fs/ocfs2/dlmfs/dlmfs.c +++ b/fs/ocfs2/dlmfs/dlmfs.c | |||
| @@ -213,10 +213,12 @@ static int dlmfs_file_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 213 | 213 | ||
| 214 | attr->ia_valid &= ~ATTR_SIZE; | 214 | attr->ia_valid &= ~ATTR_SIZE; |
| 215 | error = inode_change_ok(inode, attr); | 215 | error = inode_change_ok(inode, attr); |
| 216 | if (!error) | 216 | if (error) |
| 217 | error = inode_setattr(inode, attr); | 217 | return error; |
| 218 | 218 | ||
| 219 | return error; | 219 | setattr_copy(inode, attr); |
| 220 | mark_inode_dirty(inode); | ||
| 221 | return 0; | ||
| 220 | } | 222 | } |
| 221 | 223 | ||
| 222 | static unsigned int dlmfs_file_poll(struct file *file, poll_table *wait) | 224 | static unsigned int dlmfs_file_poll(struct file *file, poll_table *wait) |
| @@ -354,13 +356,12 @@ static void dlmfs_destroy_inode(struct inode *inode) | |||
| 354 | kmem_cache_free(dlmfs_inode_cache, DLMFS_I(inode)); | 356 | kmem_cache_free(dlmfs_inode_cache, DLMFS_I(inode)); |
| 355 | } | 357 | } |
| 356 | 358 | ||
| 357 | static void dlmfs_clear_inode(struct inode *inode) | 359 | static void dlmfs_evict_inode(struct inode *inode) |
| 358 | { | 360 | { |
| 359 | int status; | 361 | int status; |
| 360 | struct dlmfs_inode_private *ip; | 362 | struct dlmfs_inode_private *ip; |
| 361 | 363 | ||
| 362 | if (!inode) | 364 | end_writeback(inode); |
| 363 | return; | ||
| 364 | 365 | ||
| 365 | mlog(0, "inode %lu\n", inode->i_ino); | 366 | mlog(0, "inode %lu\n", inode->i_ino); |
| 366 | 367 | ||
| @@ -630,7 +631,7 @@ static const struct super_operations dlmfs_ops = { | |||
| 630 | .statfs = simple_statfs, | 631 | .statfs = simple_statfs, |
| 631 | .alloc_inode = dlmfs_alloc_inode, | 632 | .alloc_inode = dlmfs_alloc_inode, |
| 632 | .destroy_inode = dlmfs_destroy_inode, | 633 | .destroy_inode = dlmfs_destroy_inode, |
| 633 | .clear_inode = dlmfs_clear_inode, | 634 | .evict_inode = dlmfs_evict_inode, |
| 634 | .drop_inode = generic_delete_inode, | 635 | .drop_inode = generic_delete_inode, |
| 635 | }; | 636 | }; |
| 636 | 637 | ||
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 2b10b36d1577..81296b4e3646 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
| @@ -1233,18 +1233,26 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 1233 | } | 1233 | } |
| 1234 | 1234 | ||
| 1235 | /* | 1235 | /* |
| 1236 | * This will intentionally not wind up calling simple_setsize(), | 1236 | * This will intentionally not wind up calling truncate_setsize(), |
| 1237 | * since all the work for a size change has been done above. | 1237 | * since all the work for a size change has been done above. |
| 1238 | * Otherwise, we could get into problems with truncate as | 1238 | * Otherwise, we could get into problems with truncate as |
| 1239 | * ip_alloc_sem is used there to protect against i_size | 1239 | * ip_alloc_sem is used there to protect against i_size |
| 1240 | * changes. | 1240 | * changes. |
| 1241 | * | ||
| 1242 | * XXX: this means the conditional below can probably be removed. | ||
| 1241 | */ | 1243 | */ |
| 1242 | status = inode_setattr(inode, attr); | 1244 | if ((attr->ia_valid & ATTR_SIZE) && |
| 1243 | if (status < 0) { | 1245 | attr->ia_size != i_size_read(inode)) { |
| 1244 | mlog_errno(status); | 1246 | status = vmtruncate(inode, attr->ia_size); |
| 1245 | goto bail_commit; | 1247 | if (status) { |
| 1248 | mlog_errno(status); | ||
| 1249 | goto bail_commit; | ||
| 1250 | } | ||
| 1246 | } | 1251 | } |
| 1247 | 1252 | ||
| 1253 | setattr_copy(inode, attr); | ||
| 1254 | mark_inode_dirty(inode); | ||
| 1255 | |||
| 1248 | status = ocfs2_mark_inode_dirty(handle, inode, bh); | 1256 | status = ocfs2_mark_inode_dirty(handle, inode, bh); |
| 1249 | if (status < 0) | 1257 | if (status < 0) |
| 1250 | mlog_errno(status); | 1258 | mlog_errno(status); |
| @@ -2300,12 +2308,12 @@ relock: | |||
| 2300 | * blocks outside i_size. Trim these off again. | 2308 | * blocks outside i_size. Trim these off again. |
| 2301 | * Don't need i_size_read because we hold i_mutex. | 2309 | * Don't need i_size_read because we hold i_mutex. |
| 2302 | * | 2310 | * |
| 2303 | * XXX(hch): this looks buggy because ocfs2 did not | 2311 | * XXX(truncate): this looks buggy because ocfs2 did not |
| 2304 | * actually implement ->truncate. Take a look at | 2312 | * actually implement ->truncate. Take a look at |
| 2305 | * the new truncate sequence and update this accordingly | 2313 | * the new truncate sequence and update this accordingly |
| 2306 | */ | 2314 | */ |
| 2307 | if (*ppos + count > inode->i_size) | 2315 | if (*ppos + count > inode->i_size) |
| 2308 | simple_setsize(inode, inode->i_size); | 2316 | truncate_setsize(inode, inode->i_size); |
| 2309 | ret = written; | 2317 | ret = written; |
| 2310 | goto out_dio; | 2318 | goto out_dio; |
| 2311 | } | 2319 | } |
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index abb0a95cc717..0492464916b1 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c | |||
| @@ -969,7 +969,7 @@ static void ocfs2_cleanup_delete_inode(struct inode *inode, | |||
| 969 | truncate_inode_pages(&inode->i_data, 0); | 969 | truncate_inode_pages(&inode->i_data, 0); |
| 970 | } | 970 | } |
| 971 | 971 | ||
| 972 | void ocfs2_delete_inode(struct inode *inode) | 972 | static void ocfs2_delete_inode(struct inode *inode) |
| 973 | { | 973 | { |
| 974 | int wipe, status; | 974 | int wipe, status; |
| 975 | sigset_t oldset; | 975 | sigset_t oldset; |
| @@ -1075,20 +1075,17 @@ bail_unlock_nfs_sync: | |||
| 1075 | bail_unblock: | 1075 | bail_unblock: |
| 1076 | ocfs2_unblock_signals(&oldset); | 1076 | ocfs2_unblock_signals(&oldset); |
| 1077 | bail: | 1077 | bail: |
| 1078 | clear_inode(inode); | ||
| 1079 | mlog_exit_void(); | 1078 | mlog_exit_void(); |
| 1080 | } | 1079 | } |
| 1081 | 1080 | ||
| 1082 | void ocfs2_clear_inode(struct inode *inode) | 1081 | static void ocfs2_clear_inode(struct inode *inode) |
| 1083 | { | 1082 | { |
| 1084 | int status; | 1083 | int status; |
| 1085 | struct ocfs2_inode_info *oi = OCFS2_I(inode); | 1084 | struct ocfs2_inode_info *oi = OCFS2_I(inode); |
| 1086 | 1085 | ||
| 1087 | mlog_entry_void(); | 1086 | mlog_entry_void(); |
| 1088 | 1087 | ||
| 1089 | if (!inode) | 1088 | end_writeback(inode); |
| 1090 | goto bail; | ||
| 1091 | |||
| 1092 | mlog(0, "Clearing inode: %llu, nlink = %u\n", | 1089 | mlog(0, "Clearing inode: %llu, nlink = %u\n", |
| 1093 | (unsigned long long)OCFS2_I(inode)->ip_blkno, inode->i_nlink); | 1090 | (unsigned long long)OCFS2_I(inode)->ip_blkno, inode->i_nlink); |
| 1094 | 1091 | ||
| @@ -1180,16 +1177,27 @@ void ocfs2_clear_inode(struct inode *inode) | |||
| 1180 | jbd2_journal_release_jbd_inode(OCFS2_SB(inode->i_sb)->journal->j_journal, | 1177 | jbd2_journal_release_jbd_inode(OCFS2_SB(inode->i_sb)->journal->j_journal, |
| 1181 | &oi->ip_jinode); | 1178 | &oi->ip_jinode); |
| 1182 | 1179 | ||
| 1183 | bail: | ||
| 1184 | mlog_exit_void(); | 1180 | mlog_exit_void(); |
| 1185 | } | 1181 | } |
| 1186 | 1182 | ||
| 1183 | void ocfs2_evict_inode(struct inode *inode) | ||
| 1184 | { | ||
| 1185 | if (!inode->i_nlink || | ||
| 1186 | (OCFS2_I(inode)->ip_flags & OCFS2_INODE_MAYBE_ORPHANED)) { | ||
| 1187 | ocfs2_delete_inode(inode); | ||
| 1188 | } else { | ||
| 1189 | truncate_inode_pages(&inode->i_data, 0); | ||
| 1190 | } | ||
| 1191 | ocfs2_clear_inode(inode); | ||
| 1192 | } | ||
| 1193 | |||
| 1187 | /* Called under inode_lock, with no more references on the | 1194 | /* Called under inode_lock, with no more references on the |
| 1188 | * struct inode, so it's safe here to check the flags field | 1195 | * struct inode, so it's safe here to check the flags field |
| 1189 | * and to manipulate i_nlink without any other locks. */ | 1196 | * and to manipulate i_nlink without any other locks. */ |
| 1190 | void ocfs2_drop_inode(struct inode *inode) | 1197 | int ocfs2_drop_inode(struct inode *inode) |
| 1191 | { | 1198 | { |
| 1192 | struct ocfs2_inode_info *oi = OCFS2_I(inode); | 1199 | struct ocfs2_inode_info *oi = OCFS2_I(inode); |
| 1200 | int res; | ||
| 1193 | 1201 | ||
| 1194 | mlog_entry_void(); | 1202 | mlog_entry_void(); |
| 1195 | 1203 | ||
| @@ -1197,11 +1205,12 @@ void ocfs2_drop_inode(struct inode *inode) | |||
| 1197 | (unsigned long long)oi->ip_blkno, inode->i_nlink, oi->ip_flags); | 1205 | (unsigned long long)oi->ip_blkno, inode->i_nlink, oi->ip_flags); |
| 1198 | 1206 | ||
| 1199 | if (oi->ip_flags & OCFS2_INODE_MAYBE_ORPHANED) | 1207 | if (oi->ip_flags & OCFS2_INODE_MAYBE_ORPHANED) |
| 1200 | generic_delete_inode(inode); | 1208 | res = 1; |
| 1201 | else | 1209 | else |
| 1202 | generic_drop_inode(inode); | 1210 | res = generic_drop_inode(inode); |
| 1203 | 1211 | ||
| 1204 | mlog_exit_void(); | 1212 | mlog_exit_void(); |
| 1213 | return res; | ||
| 1205 | } | 1214 | } |
| 1206 | 1215 | ||
| 1207 | /* | 1216 | /* |
diff --git a/fs/ocfs2/inode.h b/fs/ocfs2/inode.h index 9f5f5fcadc45..6de5a869db30 100644 --- a/fs/ocfs2/inode.h +++ b/fs/ocfs2/inode.h | |||
| @@ -123,9 +123,8 @@ static inline struct ocfs2_caching_info *INODE_CACHE(struct inode *inode) | |||
| 123 | return &OCFS2_I(inode)->ip_metadata_cache; | 123 | return &OCFS2_I(inode)->ip_metadata_cache; |
| 124 | } | 124 | } |
| 125 | 125 | ||
| 126 | void ocfs2_clear_inode(struct inode *inode); | 126 | void ocfs2_evict_inode(struct inode *inode); |
| 127 | void ocfs2_delete_inode(struct inode *inode); | 127 | int ocfs2_drop_inode(struct inode *inode); |
| 128 | void ocfs2_drop_inode(struct inode *inode); | ||
| 129 | 128 | ||
| 130 | /* Flags for ocfs2_iget() */ | 129 | /* Flags for ocfs2_iget() */ |
| 131 | #define OCFS2_FI_FLAG_SYSFILE 0x1 | 130 | #define OCFS2_FI_FLAG_SYSFILE 0x1 |
diff --git a/fs/ocfs2/refcounttree.c b/fs/ocfs2/refcounttree.c index 3ac5aa733e9c..73a11ccfd4c2 100644 --- a/fs/ocfs2/refcounttree.c +++ b/fs/ocfs2/refcounttree.c | |||
| @@ -2436,16 +2436,26 @@ static int ocfs2_calc_refcount_meta_credits(struct super_block *sb, | |||
| 2436 | len = min((u64)cpos + clusters, le64_to_cpu(rec.r_cpos) + | 2436 | len = min((u64)cpos + clusters, le64_to_cpu(rec.r_cpos) + |
| 2437 | le32_to_cpu(rec.r_clusters)) - cpos; | 2437 | le32_to_cpu(rec.r_clusters)) - cpos; |
| 2438 | /* | 2438 | /* |
| 2439 | * If the refcount rec already exist, cool. We just need | ||
| 2440 | * to check whether there is a split. Otherwise we just need | ||
| 2441 | * to increase the refcount. | ||
| 2442 | * If we will insert one, increases recs_add. | ||
| 2443 | * | ||
| 2444 | * We record all the records which will be inserted to the | 2439 | * We record all the records which will be inserted to the |
| 2445 | * same refcount block, so that we can tell exactly whether | 2440 | * same refcount block, so that we can tell exactly whether |
| 2446 | * we need a new refcount block or not. | 2441 | * we need a new refcount block or not. |
| 2442 | * | ||
| 2443 | * If we will insert a new one, this is easy and only happens | ||
| 2444 | * during adding refcounted flag to the extent, so we don't | ||
| 2445 | * have a chance of spliting. We just need one record. | ||
| 2446 | * | ||
| 2447 | * If the refcount rec already exists, that would be a little | ||
| 2448 | * complicated. we may have to: | ||
| 2449 | * 1) split at the beginning if the start pos isn't aligned. | ||
| 2450 | * we need 1 more record in this case. | ||
| 2451 | * 2) split int the end if the end pos isn't aligned. | ||
| 2452 | * we need 1 more record in this case. | ||
| 2453 | * 3) split in the middle because of file system fragmentation. | ||
| 2454 | * we need 2 more records in this case(we can't detect this | ||
| 2455 | * beforehand, so always think of the worst case). | ||
| 2447 | */ | 2456 | */ |
| 2448 | if (rec.r_refcount) { | 2457 | if (rec.r_refcount) { |
| 2458 | recs_add += 2; | ||
| 2449 | /* Check whether we need a split at the beginning. */ | 2459 | /* Check whether we need a split at the beginning. */ |
| 2450 | if (cpos == start_cpos && | 2460 | if (cpos == start_cpos && |
| 2451 | cpos != le64_to_cpu(rec.r_cpos)) | 2461 | cpos != le64_to_cpu(rec.r_cpos)) |
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 03a799fdd740..fa1be1b304d1 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c | |||
| @@ -145,8 +145,7 @@ static const struct super_operations ocfs2_sops = { | |||
| 145 | .alloc_inode = ocfs2_alloc_inode, | 145 | .alloc_inode = ocfs2_alloc_inode, |
| 146 | .destroy_inode = ocfs2_destroy_inode, | 146 | .destroy_inode = ocfs2_destroy_inode, |
| 147 | .drop_inode = ocfs2_drop_inode, | 147 | .drop_inode = ocfs2_drop_inode, |
| 148 | .clear_inode = ocfs2_clear_inode, | 148 | .evict_inode = ocfs2_evict_inode, |
| 149 | .delete_inode = ocfs2_delete_inode, | ||
| 150 | .sync_fs = ocfs2_sync_fs, | 149 | .sync_fs = ocfs2_sync_fs, |
| 151 | .put_super = ocfs2_put_super, | 150 | .put_super = ocfs2_put_super, |
| 152 | .remount_fs = ocfs2_remount, | 151 | .remount_fs = ocfs2_remount, |
diff --git a/fs/omfs/dir.c b/fs/omfs/dir.c index b42d62419034..393f3f659da7 100644 --- a/fs/omfs/dir.c +++ b/fs/omfs/dir.c | |||
| @@ -25,11 +25,10 @@ static struct buffer_head *omfs_get_bucket(struct inode *dir, | |||
| 25 | const char *name, int namelen, int *ofs) | 25 | const char *name, int namelen, int *ofs) |
| 26 | { | 26 | { |
| 27 | int nbuckets = (dir->i_size - OMFS_DIR_START)/8; | 27 | int nbuckets = (dir->i_size - OMFS_DIR_START)/8; |
| 28 | int block = clus_to_blk(OMFS_SB(dir->i_sb), dir->i_ino); | ||
| 29 | int bucket = omfs_hash(name, namelen, nbuckets); | 28 | int bucket = omfs_hash(name, namelen, nbuckets); |
| 30 | 29 | ||
| 31 | *ofs = OMFS_DIR_START + bucket * 8; | 30 | *ofs = OMFS_DIR_START + bucket * 8; |
| 32 | return sb_bread(dir->i_sb, block); | 31 | return omfs_bread(dir->i_sb, dir->i_ino); |
| 33 | } | 32 | } |
| 34 | 33 | ||
| 35 | static struct buffer_head *omfs_scan_list(struct inode *dir, u64 block, | 34 | static struct buffer_head *omfs_scan_list(struct inode *dir, u64 block, |
| @@ -42,8 +41,7 @@ static struct buffer_head *omfs_scan_list(struct inode *dir, u64 block, | |||
| 42 | *prev_block = ~0; | 41 | *prev_block = ~0; |
| 43 | 42 | ||
| 44 | while (block != ~0) { | 43 | while (block != ~0) { |
| 45 | bh = sb_bread(dir->i_sb, | 44 | bh = omfs_bread(dir->i_sb, block); |
| 46 | clus_to_blk(OMFS_SB(dir->i_sb), block)); | ||
| 47 | if (!bh) { | 45 | if (!bh) { |
| 48 | err = -EIO; | 46 | err = -EIO; |
| 49 | goto err; | 47 | goto err; |
| @@ -86,11 +84,10 @@ static struct buffer_head *omfs_find_entry(struct inode *dir, | |||
| 86 | int omfs_make_empty(struct inode *inode, struct super_block *sb) | 84 | int omfs_make_empty(struct inode *inode, struct super_block *sb) |
| 87 | { | 85 | { |
| 88 | struct omfs_sb_info *sbi = OMFS_SB(sb); | 86 | struct omfs_sb_info *sbi = OMFS_SB(sb); |
| 89 | int block = clus_to_blk(sbi, inode->i_ino); | ||
| 90 | struct buffer_head *bh; | 87 | struct buffer_head *bh; |
| 91 | struct omfs_inode *oi; | 88 | struct omfs_inode *oi; |
| 92 | 89 | ||
| 93 | bh = sb_bread(sb, block); | 90 | bh = omfs_bread(sb, inode->i_ino); |
| 94 | if (!bh) | 91 | if (!bh) |
| 95 | return -ENOMEM; | 92 | return -ENOMEM; |
| 96 | 93 | ||
| @@ -134,7 +131,7 @@ static int omfs_add_link(struct dentry *dentry, struct inode *inode) | |||
| 134 | brelse(bh); | 131 | brelse(bh); |
| 135 | 132 | ||
| 136 | /* now set the sibling and parent pointers on the new inode */ | 133 | /* now set the sibling and parent pointers on the new inode */ |
| 137 | bh = sb_bread(dir->i_sb, clus_to_blk(OMFS_SB(dir->i_sb), inode->i_ino)); | 134 | bh = omfs_bread(dir->i_sb, inode->i_ino); |
| 138 | if (!bh) | 135 | if (!bh) |
| 139 | goto out; | 136 | goto out; |
| 140 | 137 | ||
| @@ -190,8 +187,7 @@ static int omfs_delete_entry(struct dentry *dentry) | |||
| 190 | if (prev != ~0) { | 187 | if (prev != ~0) { |
| 191 | /* found in middle of list, get list ptr */ | 188 | /* found in middle of list, get list ptr */ |
| 192 | brelse(bh); | 189 | brelse(bh); |
| 193 | bh = sb_bread(dir->i_sb, | 190 | bh = omfs_bread(dir->i_sb, prev); |
| 194 | clus_to_blk(OMFS_SB(dir->i_sb), prev)); | ||
| 195 | if (!bh) | 191 | if (!bh) |
| 196 | goto out; | 192 | goto out; |
| 197 | 193 | ||
| @@ -224,8 +220,7 @@ static int omfs_dir_is_empty(struct inode *inode) | |||
| 224 | u64 *ptr; | 220 | u64 *ptr; |
| 225 | int i; | 221 | int i; |
| 226 | 222 | ||
| 227 | bh = sb_bread(inode->i_sb, clus_to_blk(OMFS_SB(inode->i_sb), | 223 | bh = omfs_bread(inode->i_sb, inode->i_ino); |
| 228 | inode->i_ino)); | ||
| 229 | 224 | ||
| 230 | if (!bh) | 225 | if (!bh) |
| 231 | return 0; | 226 | return 0; |
| @@ -353,8 +348,7 @@ static int omfs_fill_chain(struct file *filp, void *dirent, filldir_t filldir, | |||
| 353 | 348 | ||
| 354 | /* follow chain in this bucket */ | 349 | /* follow chain in this bucket */ |
| 355 | while (fsblock != ~0) { | 350 | while (fsblock != ~0) { |
| 356 | bh = sb_bread(dir->i_sb, clus_to_blk(OMFS_SB(dir->i_sb), | 351 | bh = omfs_bread(dir->i_sb, fsblock); |
| 357 | fsblock)); | ||
| 358 | if (!bh) | 352 | if (!bh) |
| 359 | goto out; | 353 | goto out; |
| 360 | 354 | ||
| @@ -466,7 +460,7 @@ static int omfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
| 466 | hchain = (filp->f_pos >> 20) - 1; | 460 | hchain = (filp->f_pos >> 20) - 1; |
| 467 | hindex = filp->f_pos & 0xfffff; | 461 | hindex = filp->f_pos & 0xfffff; |
| 468 | 462 | ||
| 469 | bh = sb_bread(dir->i_sb, clus_to_blk(OMFS_SB(dir->i_sb), dir->i_ino)); | 463 | bh = omfs_bread(dir->i_sb, dir->i_ino); |
| 470 | if (!bh) | 464 | if (!bh) |
| 471 | goto out; | 465 | goto out; |
| 472 | 466 | ||
diff --git a/fs/omfs/file.c b/fs/omfs/file.c index 6e7a3291bbe8..8a6d34fa668a 100644 --- a/fs/omfs/file.c +++ b/fs/omfs/file.c | |||
| @@ -50,7 +50,7 @@ int omfs_shrink_inode(struct inode *inode) | |||
| 50 | if (inode->i_size != 0) | 50 | if (inode->i_size != 0) |
| 51 | goto out; | 51 | goto out; |
| 52 | 52 | ||
| 53 | bh = sb_bread(inode->i_sb, clus_to_blk(sbi, next)); | 53 | bh = omfs_bread(inode->i_sb, next); |
| 54 | if (!bh) | 54 | if (!bh) |
| 55 | goto out; | 55 | goto out; |
| 56 | 56 | ||
| @@ -90,7 +90,7 @@ int omfs_shrink_inode(struct inode *inode) | |||
| 90 | if (next == ~0) | 90 | if (next == ~0) |
| 91 | break; | 91 | break; |
| 92 | 92 | ||
| 93 | bh = sb_bread(inode->i_sb, clus_to_blk(sbi, next)); | 93 | bh = omfs_bread(inode->i_sb, next); |
| 94 | if (!bh) | 94 | if (!bh) |
| 95 | goto out; | 95 | goto out; |
| 96 | oe = (struct omfs_extent *) (&bh->b_data[OMFS_EXTENT_CONT]); | 96 | oe = (struct omfs_extent *) (&bh->b_data[OMFS_EXTENT_CONT]); |
| @@ -222,7 +222,7 @@ static int omfs_get_block(struct inode *inode, sector_t block, | |||
| 222 | struct buffer_head *bh; | 222 | struct buffer_head *bh; |
| 223 | sector_t next, offset; | 223 | sector_t next, offset; |
| 224 | int ret; | 224 | int ret; |
| 225 | u64 new_block; | 225 | u64 uninitialized_var(new_block); |
| 226 | u32 max_extents; | 226 | u32 max_extents; |
| 227 | int extent_count; | 227 | int extent_count; |
| 228 | struct omfs_extent *oe; | 228 | struct omfs_extent *oe; |
| @@ -232,7 +232,7 @@ static int omfs_get_block(struct inode *inode, sector_t block, | |||
| 232 | int remain; | 232 | int remain; |
| 233 | 233 | ||
| 234 | ret = -EIO; | 234 | ret = -EIO; |
| 235 | bh = sb_bread(inode->i_sb, clus_to_blk(sbi, inode->i_ino)); | 235 | bh = omfs_bread(inode->i_sb, inode->i_ino); |
| 236 | if (!bh) | 236 | if (!bh) |
| 237 | goto out; | 237 | goto out; |
| 238 | 238 | ||
| @@ -265,7 +265,7 @@ static int omfs_get_block(struct inode *inode, sector_t block, | |||
| 265 | break; | 265 | break; |
| 266 | 266 | ||
| 267 | brelse(bh); | 267 | brelse(bh); |
| 268 | bh = sb_bread(inode->i_sb, clus_to_blk(sbi, next)); | 268 | bh = omfs_bread(inode->i_sb, next); |
| 269 | if (!bh) | 269 | if (!bh) |
| 270 | goto out; | 270 | goto out; |
| 271 | oe = (struct omfs_extent *) (&bh->b_data[OMFS_EXTENT_CONT]); | 271 | oe = (struct omfs_extent *) (&bh->b_data[OMFS_EXTENT_CONT]); |
| @@ -312,9 +312,17 @@ static int omfs_write_begin(struct file *file, struct address_space *mapping, | |||
| 312 | loff_t pos, unsigned len, unsigned flags, | 312 | loff_t pos, unsigned len, unsigned flags, |
| 313 | struct page **pagep, void **fsdata) | 313 | struct page **pagep, void **fsdata) |
| 314 | { | 314 | { |
| 315 | *pagep = NULL; | 315 | int ret; |
| 316 | return block_write_begin(file, mapping, pos, len, flags, | 316 | |
| 317 | pagep, fsdata, omfs_get_block); | 317 | ret = block_write_begin(mapping, pos, len, flags, pagep, |
| 318 | omfs_get_block); | ||
| 319 | if (unlikely(ret)) { | ||
| 320 | loff_t isize = mapping->host->i_size; | ||
| 321 | if (pos + len > isize) | ||
| 322 | vmtruncate(mapping->host, isize); | ||
| 323 | } | ||
| 324 | |||
| 325 | return ret; | ||
| 318 | } | 326 | } |
| 319 | 327 | ||
| 320 | static sector_t omfs_bmap(struct address_space *mapping, sector_t block) | 328 | static sector_t omfs_bmap(struct address_space *mapping, sector_t block) |
| @@ -333,7 +341,29 @@ const struct file_operations omfs_file_operations = { | |||
| 333 | .splice_read = generic_file_splice_read, | 341 | .splice_read = generic_file_splice_read, |
| 334 | }; | 342 | }; |
| 335 | 343 | ||
| 344 | static int omfs_setattr(struct dentry *dentry, struct iattr *attr) | ||
| 345 | { | ||
| 346 | struct inode *inode = dentry->d_inode; | ||
| 347 | int error; | ||
| 348 | |||
| 349 | error = inode_change_ok(inode, attr); | ||
| 350 | if (error) | ||
| 351 | return error; | ||
| 352 | |||
| 353 | if ((attr->ia_valid & ATTR_SIZE) && | ||
| 354 | attr->ia_size != i_size_read(inode)) { | ||
| 355 | error = vmtruncate(inode, attr->ia_size); | ||
| 356 | if (error) | ||
| 357 | return error; | ||
| 358 | } | ||
| 359 | |||
| 360 | setattr_copy(inode, attr); | ||
| 361 | mark_inode_dirty(inode); | ||
| 362 | return 0; | ||
| 363 | } | ||
| 364 | |||
| 336 | const struct inode_operations omfs_file_inops = { | 365 | const struct inode_operations omfs_file_inops = { |
| 366 | .setattr = omfs_setattr, | ||
| 337 | .truncate = omfs_truncate | 367 | .truncate = omfs_truncate |
| 338 | }; | 368 | }; |
| 339 | 369 | ||
diff --git a/fs/omfs/inode.c b/fs/omfs/inode.c index 089839a6cc64..14a22863291a 100644 --- a/fs/omfs/inode.c +++ b/fs/omfs/inode.c | |||
| @@ -19,6 +19,15 @@ MODULE_AUTHOR("Bob Copeland <me@bobcopeland.com>"); | |||
| 19 | MODULE_DESCRIPTION("OMFS (ReplayTV/Karma) Filesystem for Linux"); | 19 | MODULE_DESCRIPTION("OMFS (ReplayTV/Karma) Filesystem for Linux"); |
| 20 | MODULE_LICENSE("GPL"); | 20 | MODULE_LICENSE("GPL"); |
| 21 | 21 | ||
| 22 | struct buffer_head *omfs_bread(struct super_block *sb, sector_t block) | ||
| 23 | { | ||
| 24 | struct omfs_sb_info *sbi = OMFS_SB(sb); | ||
| 25 | if (block >= sbi->s_num_blocks) | ||
| 26 | return NULL; | ||
| 27 | |||
| 28 | return sb_bread(sb, clus_to_blk(sbi, block)); | ||
| 29 | } | ||
| 30 | |||
| 22 | struct inode *omfs_new_inode(struct inode *dir, int mode) | 31 | struct inode *omfs_new_inode(struct inode *dir, int mode) |
| 23 | { | 32 | { |
| 24 | struct inode *inode; | 33 | struct inode *inode; |
| @@ -93,15 +102,13 @@ static int __omfs_write_inode(struct inode *inode, int wait) | |||
| 93 | struct omfs_inode *oi; | 102 | struct omfs_inode *oi; |
| 94 | struct omfs_sb_info *sbi = OMFS_SB(inode->i_sb); | 103 | struct omfs_sb_info *sbi = OMFS_SB(inode->i_sb); |
| 95 | struct buffer_head *bh, *bh2; | 104 | struct buffer_head *bh, *bh2; |
| 96 | unsigned int block; | ||
| 97 | u64 ctime; | 105 | u64 ctime; |
| 98 | int i; | 106 | int i; |
| 99 | int ret = -EIO; | 107 | int ret = -EIO; |
| 100 | int sync_failed = 0; | 108 | int sync_failed = 0; |
| 101 | 109 | ||
| 102 | /* get current inode since we may have written sibling ptrs etc. */ | 110 | /* get current inode since we may have written sibling ptrs etc. */ |
| 103 | block = clus_to_blk(sbi, inode->i_ino); | 111 | bh = omfs_bread(inode->i_sb, inode->i_ino); |
| 104 | bh = sb_bread(inode->i_sb, block); | ||
| 105 | if (!bh) | 112 | if (!bh) |
| 106 | goto out; | 113 | goto out; |
| 107 | 114 | ||
| @@ -140,8 +147,7 @@ static int __omfs_write_inode(struct inode *inode, int wait) | |||
| 140 | 147 | ||
| 141 | /* if mirroring writes, copy to next fsblock */ | 148 | /* if mirroring writes, copy to next fsblock */ |
| 142 | for (i = 1; i < sbi->s_mirrors; i++) { | 149 | for (i = 1; i < sbi->s_mirrors; i++) { |
| 143 | bh2 = sb_bread(inode->i_sb, block + i * | 150 | bh2 = omfs_bread(inode->i_sb, inode->i_ino + i); |
| 144 | (sbi->s_blocksize / sbi->s_sys_blocksize)); | ||
| 145 | if (!bh2) | 151 | if (!bh2) |
| 146 | goto out_brelse; | 152 | goto out_brelse; |
| 147 | 153 | ||
| @@ -175,9 +181,13 @@ int omfs_sync_inode(struct inode *inode) | |||
| 175 | * called when an entry is deleted, need to clear the bits in the | 181 | * called when an entry is deleted, need to clear the bits in the |
| 176 | * bitmaps. | 182 | * bitmaps. |
| 177 | */ | 183 | */ |
| 178 | static void omfs_delete_inode(struct inode *inode) | 184 | static void omfs_evict_inode(struct inode *inode) |
| 179 | { | 185 | { |
| 180 | truncate_inode_pages(&inode->i_data, 0); | 186 | truncate_inode_pages(&inode->i_data, 0); |
| 187 | end_writeback(inode); | ||
| 188 | |||
| 189 | if (inode->i_nlink) | ||
| 190 | return; | ||
| 181 | 191 | ||
| 182 | if (S_ISREG(inode->i_mode)) { | 192 | if (S_ISREG(inode->i_mode)) { |
| 183 | inode->i_size = 0; | 193 | inode->i_size = 0; |
| @@ -185,7 +195,6 @@ static void omfs_delete_inode(struct inode *inode) | |||
| 185 | } | 195 | } |
| 186 | 196 | ||
| 187 | omfs_clear_range(inode->i_sb, inode->i_ino, 2); | 197 | omfs_clear_range(inode->i_sb, inode->i_ino, 2); |
| 188 | clear_inode(inode); | ||
| 189 | } | 198 | } |
| 190 | 199 | ||
| 191 | struct inode *omfs_iget(struct super_block *sb, ino_t ino) | 200 | struct inode *omfs_iget(struct super_block *sb, ino_t ino) |
| @@ -193,7 +202,6 @@ struct inode *omfs_iget(struct super_block *sb, ino_t ino) | |||
| 193 | struct omfs_sb_info *sbi = OMFS_SB(sb); | 202 | struct omfs_sb_info *sbi = OMFS_SB(sb); |
| 194 | struct omfs_inode *oi; | 203 | struct omfs_inode *oi; |
| 195 | struct buffer_head *bh; | 204 | struct buffer_head *bh; |
| 196 | unsigned int block; | ||
| 197 | u64 ctime; | 205 | u64 ctime; |
| 198 | unsigned long nsecs; | 206 | unsigned long nsecs; |
| 199 | struct inode *inode; | 207 | struct inode *inode; |
| @@ -204,8 +212,7 @@ struct inode *omfs_iget(struct super_block *sb, ino_t ino) | |||
| 204 | if (!(inode->i_state & I_NEW)) | 212 | if (!(inode->i_state & I_NEW)) |
| 205 | return inode; | 213 | return inode; |
| 206 | 214 | ||
| 207 | block = clus_to_blk(sbi, ino); | 215 | bh = omfs_bread(inode->i_sb, ino); |
| 208 | bh = sb_bread(inode->i_sb, block); | ||
| 209 | if (!bh) | 216 | if (!bh) |
| 210 | goto iget_failed; | 217 | goto iget_failed; |
| 211 | 218 | ||
| @@ -284,7 +291,7 @@ static int omfs_statfs(struct dentry *dentry, struct kstatfs *buf) | |||
| 284 | 291 | ||
| 285 | static const struct super_operations omfs_sops = { | 292 | static const struct super_operations omfs_sops = { |
| 286 | .write_inode = omfs_write_inode, | 293 | .write_inode = omfs_write_inode, |
| 287 | .delete_inode = omfs_delete_inode, | 294 | .evict_inode = omfs_evict_inode, |
| 288 | .put_super = omfs_put_super, | 295 | .put_super = omfs_put_super, |
| 289 | .statfs = omfs_statfs, | 296 | .statfs = omfs_statfs, |
| 290 | .show_options = generic_show_options, | 297 | .show_options = generic_show_options, |
| @@ -319,6 +326,9 @@ static int omfs_get_imap(struct super_block *sb) | |||
| 319 | goto nomem; | 326 | goto nomem; |
| 320 | 327 | ||
| 321 | block = clus_to_blk(sbi, sbi->s_bitmap_ino); | 328 | block = clus_to_blk(sbi, sbi->s_bitmap_ino); |
| 329 | if (block >= sbi->s_num_blocks) | ||
| 330 | goto nomem; | ||
| 331 | |||
| 322 | ptr = sbi->s_imap; | 332 | ptr = sbi->s_imap; |
| 323 | for (count = bitmap_size; count > 0; count -= sb->s_blocksize) { | 333 | for (count = bitmap_size; count > 0; count -= sb->s_blocksize) { |
| 324 | bh = sb_bread(sb, block++); | 334 | bh = sb_bread(sb, block++); |
| @@ -417,7 +427,6 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent) | |||
| 417 | struct omfs_root_block *omfs_rb; | 427 | struct omfs_root_block *omfs_rb; |
| 418 | struct omfs_sb_info *sbi; | 428 | struct omfs_sb_info *sbi; |
| 419 | struct inode *root; | 429 | struct inode *root; |
| 420 | sector_t start; | ||
| 421 | int ret = -EINVAL; | 430 | int ret = -EINVAL; |
| 422 | 431 | ||
| 423 | save_mount_options(sb, (char *) data); | 432 | save_mount_options(sb, (char *) data); |
| @@ -486,8 +495,7 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent) | |||
| 486 | sbi->s_block_shift = get_bitmask_order(sbi->s_blocksize) - | 495 | sbi->s_block_shift = get_bitmask_order(sbi->s_blocksize) - |
| 487 | get_bitmask_order(sbi->s_sys_blocksize); | 496 | get_bitmask_order(sbi->s_sys_blocksize); |
| 488 | 497 | ||
| 489 | start = clus_to_blk(sbi, be64_to_cpu(omfs_sb->s_root_block)); | 498 | bh2 = omfs_bread(sb, be64_to_cpu(omfs_sb->s_root_block)); |
| 490 | bh2 = sb_bread(sb, start); | ||
| 491 | if (!bh2) | 499 | if (!bh2) |
| 492 | goto out_brelse_bh; | 500 | goto out_brelse_bh; |
| 493 | 501 | ||
| @@ -504,6 +512,21 @@ static int omfs_fill_super(struct super_block *sb, void *data, int silent) | |||
| 504 | goto out_brelse_bh2; | 512 | goto out_brelse_bh2; |
| 505 | } | 513 | } |
| 506 | 514 | ||
| 515 | if (sbi->s_bitmap_ino != ~0ULL && | ||
| 516 | sbi->s_bitmap_ino > sbi->s_num_blocks) { | ||
| 517 | printk(KERN_ERR "omfs: free space bitmap location is corrupt " | ||
| 518 | "(%llx, total blocks %llx)\n", | ||
| 519 | (unsigned long long) sbi->s_bitmap_ino, | ||
| 520 | (unsigned long long) sbi->s_num_blocks); | ||
| 521 | goto out_brelse_bh2; | ||
| 522 | } | ||
| 523 | if (sbi->s_clustersize < 1 || | ||
| 524 | sbi->s_clustersize > OMFS_MAX_CLUSTER_SIZE) { | ||
| 525 | printk(KERN_ERR "omfs: cluster size out of range (%d)", | ||
| 526 | sbi->s_clustersize); | ||
| 527 | goto out_brelse_bh2; | ||
| 528 | } | ||
| 529 | |||
| 507 | ret = omfs_get_imap(sb); | 530 | ret = omfs_get_imap(sb); |
| 508 | if (ret) | 531 | if (ret) |
| 509 | goto out_brelse_bh2; | 532 | goto out_brelse_bh2; |
| @@ -529,6 +552,8 @@ out_brelse_bh2: | |||
| 529 | out_brelse_bh: | 552 | out_brelse_bh: |
| 530 | brelse(bh); | 553 | brelse(bh); |
| 531 | end: | 554 | end: |
| 555 | if (ret) | ||
| 556 | kfree(sbi); | ||
| 532 | return ret; | 557 | return ret; |
| 533 | } | 558 | } |
| 534 | 559 | ||
diff --git a/fs/omfs/omfs.h b/fs/omfs/omfs.h index ebe2fdbe535e..7d414fef501a 100644 --- a/fs/omfs/omfs.h +++ b/fs/omfs/omfs.h | |||
| @@ -58,6 +58,7 @@ extern void omfs_make_empty_table(struct buffer_head *bh, int offset); | |||
| 58 | extern int omfs_shrink_inode(struct inode *inode); | 58 | extern int omfs_shrink_inode(struct inode *inode); |
| 59 | 59 | ||
| 60 | /* inode.c */ | 60 | /* inode.c */ |
| 61 | extern struct buffer_head *omfs_bread(struct super_block *sb, sector_t block); | ||
| 61 | extern struct inode *omfs_iget(struct super_block *sb, ino_t inode); | 62 | extern struct inode *omfs_iget(struct super_block *sb, ino_t inode); |
| 62 | extern struct inode *omfs_new_inode(struct inode *dir, int mode); | 63 | extern struct inode *omfs_new_inode(struct inode *dir, int mode); |
| 63 | extern int omfs_reserve_block(struct super_block *sb, sector_t block); | 64 | extern int omfs_reserve_block(struct super_block *sb, sector_t block); |
diff --git a/fs/omfs/omfs_fs.h b/fs/omfs/omfs_fs.h index 12cca245d6e8..ee5e4327de92 100644 --- a/fs/omfs/omfs_fs.h +++ b/fs/omfs/omfs_fs.h | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | #define OMFS_EXTENT_CONT 0x40 | 17 | #define OMFS_EXTENT_CONT 0x40 |
| 18 | #define OMFS_XOR_COUNT 19 | 18 | #define OMFS_XOR_COUNT 19 |
| 19 | #define OMFS_MAX_BLOCK_SIZE 8192 | 19 | #define OMFS_MAX_BLOCK_SIZE 8192 |
| 20 | #define OMFS_MAX_CLUSTER_SIZE 8 | ||
| 20 | 21 | ||
| 21 | struct omfs_super_block { | 22 | struct omfs_super_block { |
| 22 | char s_fill1[256]; | 23 | char s_fill1[256]; |
| @@ -29,6 +29,7 @@ | |||
| 29 | #include <linux/falloc.h> | 29 | #include <linux/falloc.h> |
| 30 | #include <linux/fs_struct.h> | 30 | #include <linux/fs_struct.h> |
| 31 | #include <linux/ima.h> | 31 | #include <linux/ima.h> |
| 32 | #include <linux/dnotify.h> | ||
| 32 | 33 | ||
| 33 | #include "internal.h" | 34 | #include "internal.h" |
| 34 | 35 | ||
| @@ -887,7 +888,7 @@ long do_sys_open(int dfd, const char __user *filename, int flags, int mode) | |||
| 887 | put_unused_fd(fd); | 888 | put_unused_fd(fd); |
| 888 | fd = PTR_ERR(f); | 889 | fd = PTR_ERR(f); |
| 889 | } else { | 890 | } else { |
| 890 | fsnotify_open(f->f_path.dentry); | 891 | fsnotify_open(f); |
| 891 | fd_install(fd, f); | 892 | fd_install(fd, f); |
| 892 | } | 893 | } |
| 893 | } | 894 | } |
| @@ -1030,7 +1031,9 @@ EXPORT_SYMBOL(generic_file_open); | |||
| 1030 | 1031 | ||
| 1031 | /* | 1032 | /* |
| 1032 | * This is used by subsystems that don't want seekable | 1033 | * This is used by subsystems that don't want seekable |
| 1033 | * file descriptors | 1034 | * file descriptors. The function is not supposed to ever fail, the only |
| 1035 | * reason it returns an 'int' and not 'void' is so that it can be plugged | ||
| 1036 | * directly into file_operations structure. | ||
| 1034 | */ | 1037 | */ |
| 1035 | int nonseekable_open(struct inode *inode, struct file *filp) | 1038 | int nonseekable_open(struct inode *inode, struct file *filp) |
| 1036 | { | 1039 | { |
diff --git a/fs/partitions/acorn.c b/fs/partitions/acorn.c index 6921e7890be6..fbeb697374d5 100644 --- a/fs/partitions/acorn.c +++ b/fs/partitions/acorn.c | |||
| @@ -45,8 +45,11 @@ adfs_partition(struct parsed_partitions *state, char *name, char *data, | |||
| 45 | nr_sects = (le32_to_cpu(dr->disc_size_high) << 23) | | 45 | nr_sects = (le32_to_cpu(dr->disc_size_high) << 23) | |
| 46 | (le32_to_cpu(dr->disc_size) >> 9); | 46 | (le32_to_cpu(dr->disc_size) >> 9); |
| 47 | 47 | ||
| 48 | if (name) | 48 | if (name) { |
| 49 | printk(" [%s]", name); | 49 | strlcat(state->pp_buf, " [", PAGE_SIZE); |
| 50 | strlcat(state->pp_buf, name, PAGE_SIZE); | ||
| 51 | strlcat(state->pp_buf, "]", PAGE_SIZE); | ||
| 52 | } | ||
| 50 | put_partition(state, slot, first_sector, nr_sects); | 53 | put_partition(state, slot, first_sector, nr_sects); |
| 51 | return dr; | 54 | return dr; |
| 52 | } | 55 | } |
| @@ -81,14 +84,14 @@ static int riscix_partition(struct parsed_partitions *state, | |||
| 81 | if (!rr) | 84 | if (!rr) |
| 82 | return -1; | 85 | return -1; |
| 83 | 86 | ||
| 84 | printk(" [RISCiX]"); | 87 | strlcat(state->pp_buf, " [RISCiX]", PAGE_SIZE); |
| 85 | 88 | ||
| 86 | 89 | ||
| 87 | if (rr->magic == RISCIX_MAGIC) { | 90 | if (rr->magic == RISCIX_MAGIC) { |
| 88 | unsigned long size = nr_sects > 2 ? 2 : nr_sects; | 91 | unsigned long size = nr_sects > 2 ? 2 : nr_sects; |
| 89 | int part; | 92 | int part; |
| 90 | 93 | ||
| 91 | printk(" <"); | 94 | strlcat(state->pp_buf, " <", PAGE_SIZE); |
| 92 | 95 | ||
| 93 | put_partition(state, slot++, first_sect, size); | 96 | put_partition(state, slot++, first_sect, size); |
| 94 | for (part = 0; part < 8; part++) { | 97 | for (part = 0; part < 8; part++) { |
| @@ -97,11 +100,13 @@ static int riscix_partition(struct parsed_partitions *state, | |||
| 97 | put_partition(state, slot++, | 100 | put_partition(state, slot++, |
| 98 | le32_to_cpu(rr->part[part].start), | 101 | le32_to_cpu(rr->part[part].start), |
| 99 | le32_to_cpu(rr->part[part].length)); | 102 | le32_to_cpu(rr->part[part].length)); |
| 100 | printk("(%s)", rr->part[part].name); | 103 | strlcat(state->pp_buf, "(", PAGE_SIZE); |
| 104 | strlcat(state->pp_buf, rr->part[part].name, PAGE_SIZE); | ||
| 105 | strlcat(state->pp_buf, ")", PAGE_SIZE); | ||
| 101 | } | 106 | } |
| 102 | } | 107 | } |
| 103 | 108 | ||
| 104 | printk(" >\n"); | 109 | strlcat(state->pp_buf, " >\n", PAGE_SIZE); |
| 105 | } else { | 110 | } else { |
| 106 | put_partition(state, slot++, first_sect, nr_sects); | 111 | put_partition(state, slot++, first_sect, nr_sects); |
| 107 | } | 112 | } |
| @@ -131,7 +136,7 @@ static int linux_partition(struct parsed_partitions *state, | |||
| 131 | struct linux_part *linuxp; | 136 | struct linux_part *linuxp; |
| 132 | unsigned long size = nr_sects > 2 ? 2 : nr_sects; | 137 | unsigned long size = nr_sects > 2 ? 2 : nr_sects; |
| 133 | 138 | ||
| 134 | printk(" [Linux]"); | 139 | strlcat(state->pp_buf, " [Linux]", PAGE_SIZE); |
| 135 | 140 | ||
| 136 | put_partition(state, slot++, first_sect, size); | 141 | put_partition(state, slot++, first_sect, size); |
| 137 | 142 | ||
| @@ -139,7 +144,7 @@ static int linux_partition(struct parsed_partitions *state, | |||
| 139 | if (!linuxp) | 144 | if (!linuxp) |
| 140 | return -1; | 145 | return -1; |
| 141 | 146 | ||
| 142 | printk(" <"); | 147 | strlcat(state->pp_buf, " <", PAGE_SIZE); |
| 143 | while (linuxp->magic == cpu_to_le32(LINUX_NATIVE_MAGIC) || | 148 | while (linuxp->magic == cpu_to_le32(LINUX_NATIVE_MAGIC) || |
| 144 | linuxp->magic == cpu_to_le32(LINUX_SWAP_MAGIC)) { | 149 | linuxp->magic == cpu_to_le32(LINUX_SWAP_MAGIC)) { |
| 145 | if (slot == state->limit) | 150 | if (slot == state->limit) |
| @@ -149,7 +154,7 @@ static int linux_partition(struct parsed_partitions *state, | |||
| 149 | le32_to_cpu(linuxp->nr_sects)); | 154 | le32_to_cpu(linuxp->nr_sects)); |
| 150 | linuxp ++; | 155 | linuxp ++; |
| 151 | } | 156 | } |
| 152 | printk(" >"); | 157 | strlcat(state->pp_buf, " >", PAGE_SIZE); |
| 153 | 158 | ||
| 154 | put_dev_sector(sect); | 159 | put_dev_sector(sect); |
| 155 | return slot; | 160 | return slot; |
| @@ -294,7 +299,7 @@ int adfspart_check_ADFS(struct parsed_partitions *state) | |||
| 294 | break; | 299 | break; |
| 295 | } | 300 | } |
| 296 | } | 301 | } |
| 297 | printk("\n"); | 302 | strlcat(state->pp_buf, "\n", PAGE_SIZE); |
| 298 | return 1; | 303 | return 1; |
| 299 | } | 304 | } |
| 300 | #endif | 305 | #endif |
| @@ -367,7 +372,7 @@ int adfspart_check_ICS(struct parsed_partitions *state) | |||
| 367 | return 0; | 372 | return 0; |
| 368 | } | 373 | } |
| 369 | 374 | ||
| 370 | printk(" [ICS]"); | 375 | strlcat(state->pp_buf, " [ICS]", PAGE_SIZE); |
| 371 | 376 | ||
| 372 | for (slot = 1, p = (const struct ics_part *)data; p->size; p++) { | 377 | for (slot = 1, p = (const struct ics_part *)data; p->size; p++) { |
| 373 | u32 start = le32_to_cpu(p->start); | 378 | u32 start = le32_to_cpu(p->start); |
| @@ -401,7 +406,7 @@ int adfspart_check_ICS(struct parsed_partitions *state) | |||
| 401 | } | 406 | } |
| 402 | 407 | ||
| 403 | put_dev_sector(sect); | 408 | put_dev_sector(sect); |
| 404 | printk("\n"); | 409 | strlcat(state->pp_buf, "\n", PAGE_SIZE); |
| 405 | return 1; | 410 | return 1; |
| 406 | } | 411 | } |
| 407 | #endif | 412 | #endif |
| @@ -461,7 +466,7 @@ int adfspart_check_POWERTEC(struct parsed_partitions *state) | |||
| 461 | return 0; | 466 | return 0; |
| 462 | } | 467 | } |
| 463 | 468 | ||
| 464 | printk(" [POWERTEC]"); | 469 | strlcat(state->pp_buf, " [POWERTEC]", PAGE_SIZE); |
| 465 | 470 | ||
| 466 | for (i = 0, p = (const struct ptec_part *)data; i < 12; i++, p++) { | 471 | for (i = 0, p = (const struct ptec_part *)data; i < 12; i++, p++) { |
| 467 | u32 start = le32_to_cpu(p->start); | 472 | u32 start = le32_to_cpu(p->start); |
| @@ -472,7 +477,7 @@ int adfspart_check_POWERTEC(struct parsed_partitions *state) | |||
| 472 | } | 477 | } |
| 473 | 478 | ||
| 474 | put_dev_sector(sect); | 479 | put_dev_sector(sect); |
| 475 | printk("\n"); | 480 | strlcat(state->pp_buf, "\n", PAGE_SIZE); |
| 476 | return 1; | 481 | return 1; |
| 477 | } | 482 | } |
| 478 | #endif | 483 | #endif |
| @@ -543,7 +548,7 @@ int adfspart_check_EESOX(struct parsed_partitions *state) | |||
| 543 | 548 | ||
| 544 | size = get_capacity(state->bdev->bd_disk); | 549 | size = get_capacity(state->bdev->bd_disk); |
| 545 | put_partition(state, slot++, start, size - start); | 550 | put_partition(state, slot++, start, size - start); |
| 546 | printk("\n"); | 551 | strlcat(state->pp_buf, "\n", PAGE_SIZE); |
| 547 | } | 552 | } |
| 548 | 553 | ||
| 549 | return i ? 1 : 0; | 554 | return i ? 1 : 0; |
diff --git a/fs/partitions/amiga.c b/fs/partitions/amiga.c index ba443d4229f8..70cbf44a1560 100644 --- a/fs/partitions/amiga.c +++ b/fs/partitions/amiga.c | |||
| @@ -69,7 +69,13 @@ int amiga_partition(struct parsed_partitions *state) | |||
| 69 | /* blksize is blocks per 512 byte standard block */ | 69 | /* blksize is blocks per 512 byte standard block */ |
| 70 | blksize = be32_to_cpu( rdb->rdb_BlockBytes ) / 512; | 70 | blksize = be32_to_cpu( rdb->rdb_BlockBytes ) / 512; |
| 71 | 71 | ||
| 72 | printk(" RDSK (%d)", blksize * 512); /* Be more informative */ | 72 | { |
| 73 | char tmp[7 + 10 + 1 + 1]; | ||
| 74 | |||
| 75 | /* Be more informative */ | ||
| 76 | snprintf(tmp, sizeof(tmp), " RDSK (%d)", blksize * 512); | ||
| 77 | strlcat(state->pp_buf, tmp, PAGE_SIZE); | ||
| 78 | } | ||
| 73 | blk = be32_to_cpu(rdb->rdb_PartitionList); | 79 | blk = be32_to_cpu(rdb->rdb_PartitionList); |
| 74 | put_dev_sector(sect); | 80 | put_dev_sector(sect); |
| 75 | for (part = 1; blk>0 && part<=16; part++, put_dev_sector(sect)) { | 81 | for (part = 1; blk>0 && part<=16; part++, put_dev_sector(sect)) { |
| @@ -106,23 +112,27 @@ int amiga_partition(struct parsed_partitions *state) | |||
| 106 | { | 112 | { |
| 107 | /* Be even more informative to aid mounting */ | 113 | /* Be even more informative to aid mounting */ |
| 108 | char dostype[4]; | 114 | char dostype[4]; |
| 115 | char tmp[42]; | ||
| 116 | |||
| 109 | __be32 *dt = (__be32 *)dostype; | 117 | __be32 *dt = (__be32 *)dostype; |
| 110 | *dt = pb->pb_Environment[16]; | 118 | *dt = pb->pb_Environment[16]; |
| 111 | if (dostype[3] < ' ') | 119 | if (dostype[3] < ' ') |
| 112 | printk(" (%c%c%c^%c)", | 120 | snprintf(tmp, sizeof(tmp), " (%c%c%c^%c)", |
| 113 | dostype[0], dostype[1], | 121 | dostype[0], dostype[1], |
| 114 | dostype[2], dostype[3] + '@' ); | 122 | dostype[2], dostype[3] + '@' ); |
| 115 | else | 123 | else |
| 116 | printk(" (%c%c%c%c)", | 124 | snprintf(tmp, sizeof(tmp), " (%c%c%c%c)", |
| 117 | dostype[0], dostype[1], | 125 | dostype[0], dostype[1], |
| 118 | dostype[2], dostype[3]); | 126 | dostype[2], dostype[3]); |
| 119 | printk("(res %d spb %d)", | 127 | strlcat(state->pp_buf, tmp, PAGE_SIZE); |
| 128 | snprintf(tmp, sizeof(tmp), "(res %d spb %d)", | ||
| 120 | be32_to_cpu(pb->pb_Environment[6]), | 129 | be32_to_cpu(pb->pb_Environment[6]), |
| 121 | be32_to_cpu(pb->pb_Environment[4])); | 130 | be32_to_cpu(pb->pb_Environment[4])); |
| 131 | strlcat(state->pp_buf, tmp, PAGE_SIZE); | ||
| 122 | } | 132 | } |
| 123 | res = 1; | 133 | res = 1; |
| 124 | } | 134 | } |
| 125 | printk("\n"); | 135 | strlcat(state->pp_buf, "\n", PAGE_SIZE); |
| 126 | 136 | ||
| 127 | rdb_done: | 137 | rdb_done: |
| 128 | return res; | 138 | return res; |
diff --git a/fs/partitions/atari.c b/fs/partitions/atari.c index 4439ff1b6cec..9875b05e80a2 100644 --- a/fs/partitions/atari.c +++ b/fs/partitions/atari.c | |||
| @@ -62,7 +62,7 @@ int atari_partition(struct parsed_partitions *state) | |||
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | pi = &rs->part[0]; | 64 | pi = &rs->part[0]; |
| 65 | printk (" AHDI"); | 65 | strlcat(state->pp_buf, " AHDI", PAGE_SIZE); |
| 66 | for (slot = 1; pi < &rs->part[4] && slot < state->limit; slot++, pi++) { | 66 | for (slot = 1; pi < &rs->part[4] && slot < state->limit; slot++, pi++) { |
| 67 | struct rootsector *xrs; | 67 | struct rootsector *xrs; |
| 68 | Sector sect2; | 68 | Sector sect2; |
| @@ -81,7 +81,7 @@ int atari_partition(struct parsed_partitions *state) | |||
| 81 | #ifdef ICD_PARTS | 81 | #ifdef ICD_PARTS |
| 82 | part_fmt = 1; | 82 | part_fmt = 1; |
| 83 | #endif | 83 | #endif |
| 84 | printk(" XGM<"); | 84 | strlcat(state->pp_buf, " XGM<", PAGE_SIZE); |
| 85 | partsect = extensect = be32_to_cpu(pi->st); | 85 | partsect = extensect = be32_to_cpu(pi->st); |
| 86 | while (1) { | 86 | while (1) { |
| 87 | xrs = read_part_sector(state, partsect, §2); | 87 | xrs = read_part_sector(state, partsect, §2); |
| @@ -120,14 +120,14 @@ int atari_partition(struct parsed_partitions *state) | |||
| 120 | break; | 120 | break; |
| 121 | } | 121 | } |
| 122 | } | 122 | } |
| 123 | printk(" >"); | 123 | strlcat(state->pp_buf, " >", PAGE_SIZE); |
| 124 | } | 124 | } |
| 125 | #ifdef ICD_PARTS | 125 | #ifdef ICD_PARTS |
| 126 | if ( part_fmt!=1 ) { /* no extended partitions -> test ICD-format */ | 126 | if ( part_fmt!=1 ) { /* no extended partitions -> test ICD-format */ |
| 127 | pi = &rs->icdpart[0]; | 127 | pi = &rs->icdpart[0]; |
| 128 | /* sanity check: no ICD format if first partition invalid */ | 128 | /* sanity check: no ICD format if first partition invalid */ |
| 129 | if (OK_id(pi->id)) { | 129 | if (OK_id(pi->id)) { |
| 130 | printk(" ICD<"); | 130 | strlcat(state->pp_buf, " ICD<", PAGE_SIZE); |
| 131 | for (; pi < &rs->icdpart[8] && slot < state->limit; slot++, pi++) { | 131 | for (; pi < &rs->icdpart[8] && slot < state->limit; slot++, pi++) { |
| 132 | /* accept only GEM,BGM,RAW,LNX,SWP partitions */ | 132 | /* accept only GEM,BGM,RAW,LNX,SWP partitions */ |
| 133 | if (!((pi->flg & 1) && OK_id(pi->id))) | 133 | if (!((pi->flg & 1) && OK_id(pi->id))) |
| @@ -137,13 +137,13 @@ int atari_partition(struct parsed_partitions *state) | |||
| 137 | be32_to_cpu(pi->st), | 137 | be32_to_cpu(pi->st), |
| 138 | be32_to_cpu(pi->siz)); | 138 | be32_to_cpu(pi->siz)); |
| 139 | } | 139 | } |
| 140 | printk(" >"); | 140 | strlcat(state->pp_buf, " >", PAGE_SIZE); |
| 141 | } | 141 | } |
| 142 | } | 142 | } |
| 143 | #endif | 143 | #endif |
| 144 | put_dev_sector(sect); | 144 | put_dev_sector(sect); |
| 145 | 145 | ||
| 146 | printk ("\n"); | 146 | strlcat(state->pp_buf, "\n", PAGE_SIZE); |
| 147 | 147 | ||
| 148 | return 1; | 148 | return 1; |
| 149 | } | 149 | } |
diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 72c52656dc2e..79fbf3f390f0 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c | |||
| @@ -164,10 +164,16 @@ check_partition(struct gendisk *hd, struct block_device *bdev) | |||
| 164 | state = kzalloc(sizeof(struct parsed_partitions), GFP_KERNEL); | 164 | state = kzalloc(sizeof(struct parsed_partitions), GFP_KERNEL); |
| 165 | if (!state) | 165 | if (!state) |
| 166 | return NULL; | 166 | return NULL; |
| 167 | state->pp_buf = (char *)__get_free_page(GFP_KERNEL); | ||
| 168 | if (!state->pp_buf) { | ||
| 169 | kfree(state); | ||
| 170 | return NULL; | ||
| 171 | } | ||
| 172 | state->pp_buf[0] = '\0'; | ||
| 167 | 173 | ||
| 168 | state->bdev = bdev; | 174 | state->bdev = bdev; |
| 169 | disk_name(hd, 0, state->name); | 175 | disk_name(hd, 0, state->name); |
| 170 | printk(KERN_INFO " %s:", state->name); | 176 | snprintf(state->pp_buf, PAGE_SIZE, " %s:", state->name); |
| 171 | if (isdigit(state->name[strlen(state->name)-1])) | 177 | if (isdigit(state->name[strlen(state->name)-1])) |
| 172 | sprintf(state->name, "p"); | 178 | sprintf(state->name, "p"); |
| 173 | 179 | ||
| @@ -185,17 +191,25 @@ check_partition(struct gendisk *hd, struct block_device *bdev) | |||
| 185 | } | 191 | } |
| 186 | 192 | ||
| 187 | } | 193 | } |
| 188 | if (res > 0) | 194 | if (res > 0) { |
| 195 | printk(KERN_INFO "%s", state->pp_buf); | ||
| 196 | |||
| 197 | free_page((unsigned long)state->pp_buf); | ||
| 189 | return state; | 198 | return state; |
| 199 | } | ||
| 190 | if (state->access_beyond_eod) | 200 | if (state->access_beyond_eod) |
| 191 | err = -ENOSPC; | 201 | err = -ENOSPC; |
| 192 | if (err) | 202 | if (err) |
| 193 | /* The partition is unrecognized. So report I/O errors if there were any */ | 203 | /* The partition is unrecognized. So report I/O errors if there were any */ |
| 194 | res = err; | 204 | res = err; |
| 195 | if (!res) | 205 | if (!res) |
| 196 | printk(" unknown partition table\n"); | 206 | strlcat(state->pp_buf, " unknown partition table\n", PAGE_SIZE); |
| 197 | else if (warn_no_part) | 207 | else if (warn_no_part) |
| 198 | printk(" unable to read partition table\n"); | 208 | strlcat(state->pp_buf, " unable to read partition table\n", PAGE_SIZE); |
| 209 | |||
| 210 | printk(KERN_INFO "%s", state->pp_buf); | ||
| 211 | |||
| 212 | free_page((unsigned long)state->pp_buf); | ||
| 199 | kfree(state); | 213 | kfree(state); |
| 200 | return ERR_PTR(res); | 214 | return ERR_PTR(res); |
| 201 | } | 215 | } |
diff --git a/fs/partitions/check.h b/fs/partitions/check.h index 52f8bd399396..8e4e103ba216 100644 --- a/fs/partitions/check.h +++ b/fs/partitions/check.h | |||
| @@ -16,6 +16,7 @@ struct parsed_partitions { | |||
| 16 | int next; | 16 | int next; |
| 17 | int limit; | 17 | int limit; |
| 18 | bool access_beyond_eod; | 18 | bool access_beyond_eod; |
| 19 | char *pp_buf; | ||
| 19 | }; | 20 | }; |
| 20 | 21 | ||
| 21 | static inline void *read_part_sector(struct parsed_partitions *state, | 22 | static inline void *read_part_sector(struct parsed_partitions *state, |
| @@ -32,9 +33,12 @@ static inline void | |||
| 32 | put_partition(struct parsed_partitions *p, int n, sector_t from, sector_t size) | 33 | put_partition(struct parsed_partitions *p, int n, sector_t from, sector_t size) |
| 33 | { | 34 | { |
| 34 | if (n < p->limit) { | 35 | if (n < p->limit) { |
| 36 | char tmp[1 + BDEVNAME_SIZE + 10 + 1]; | ||
| 37 | |||
| 35 | p->parts[n].from = from; | 38 | p->parts[n].from = from; |
| 36 | p->parts[n].size = size; | 39 | p->parts[n].size = size; |
| 37 | printk(" %s%d", p->name, n); | 40 | snprintf(tmp, sizeof(tmp), " %s%d", p->name, n); |
| 41 | strlcat(p->pp_buf, tmp, PAGE_SIZE); | ||
| 38 | } | 42 | } |
| 39 | } | 43 | } |
| 40 | 44 | ||
diff --git a/fs/partitions/efi.c b/fs/partitions/efi.c index 9efb2cfe2410..dbb44d4bb8a7 100644 --- a/fs/partitions/efi.c +++ b/fs/partitions/efi.c | |||
| @@ -630,6 +630,6 @@ int efi_partition(struct parsed_partitions *state) | |||
| 630 | } | 630 | } |
| 631 | kfree(ptes); | 631 | kfree(ptes); |
| 632 | kfree(gpt); | 632 | kfree(gpt); |
| 633 | printk("\n"); | 633 | strlcat(state->pp_buf, "\n", PAGE_SIZE); |
| 634 | return 1; | 634 | return 1; |
| 635 | } | 635 | } |
diff --git a/fs/partitions/ibm.c b/fs/partitions/ibm.c index fc8497643fd0..d513a07f44bb 100644 --- a/fs/partitions/ibm.c +++ b/fs/partitions/ibm.c | |||
| @@ -75,6 +75,7 @@ int ibm_partition(struct parsed_partitions *state) | |||
| 75 | unsigned char *data; | 75 | unsigned char *data; |
| 76 | Sector sect; | 76 | Sector sect; |
| 77 | sector_t labelsect; | 77 | sector_t labelsect; |
| 78 | char tmp[64]; | ||
| 78 | 79 | ||
| 79 | res = 0; | 80 | res = 0; |
| 80 | blocksize = bdev_logical_block_size(bdev); | 81 | blocksize = bdev_logical_block_size(bdev); |
| @@ -144,13 +145,15 @@ int ibm_partition(struct parsed_partitions *state) | |||
| 144 | */ | 145 | */ |
| 145 | blocksize = label->cms.block_size; | 146 | blocksize = label->cms.block_size; |
| 146 | if (label->cms.disk_offset != 0) { | 147 | if (label->cms.disk_offset != 0) { |
| 147 | printk("CMS1/%8s(MDSK):", name); | 148 | snprintf(tmp, sizeof(tmp), "CMS1/%8s(MDSK):", name); |
| 149 | strlcat(state->pp_buf, tmp, PAGE_SIZE); | ||
| 148 | /* disk is reserved minidisk */ | 150 | /* disk is reserved minidisk */ |
| 149 | offset = label->cms.disk_offset; | 151 | offset = label->cms.disk_offset; |
| 150 | size = (label->cms.block_count - 1) | 152 | size = (label->cms.block_count - 1) |
| 151 | * (blocksize >> 9); | 153 | * (blocksize >> 9); |
| 152 | } else { | 154 | } else { |
| 153 | printk("CMS1/%8s:", name); | 155 | snprintf(tmp, sizeof(tmp), "CMS1/%8s:", name); |
| 156 | strlcat(state->pp_buf, tmp, PAGE_SIZE); | ||
| 154 | offset = (info->label_block + 1); | 157 | offset = (info->label_block + 1); |
| 155 | size = label->cms.block_count | 158 | size = label->cms.block_count |
| 156 | * (blocksize >> 9); | 159 | * (blocksize >> 9); |
| @@ -159,7 +162,8 @@ int ibm_partition(struct parsed_partitions *state) | |||
| 159 | size-offset*(blocksize >> 9)); | 162 | size-offset*(blocksize >> 9)); |
| 160 | } else { | 163 | } else { |
| 161 | if (strncmp(type, "LNX1", 4) == 0) { | 164 | if (strncmp(type, "LNX1", 4) == 0) { |
| 162 | printk("LNX1/%8s:", name); | 165 | snprintf(tmp, sizeof(tmp), "LNX1/%8s:", name); |
| 166 | strlcat(state->pp_buf, tmp, PAGE_SIZE); | ||
| 163 | if (label->lnx.ldl_version == 0xf2) { | 167 | if (label->lnx.ldl_version == 0xf2) { |
| 164 | fmt_size = label->lnx.formatted_blocks | 168 | fmt_size = label->lnx.formatted_blocks |
| 165 | * (blocksize >> 9); | 169 | * (blocksize >> 9); |
| @@ -178,7 +182,7 @@ int ibm_partition(struct parsed_partitions *state) | |||
| 178 | offset = (info->label_block + 1); | 182 | offset = (info->label_block + 1); |
| 179 | } else { | 183 | } else { |
| 180 | /* unlabeled disk */ | 184 | /* unlabeled disk */ |
| 181 | printk("(nonl)"); | 185 | strlcat(state->pp_buf, "(nonl)", PAGE_SIZE); |
| 182 | size = i_size >> 9; | 186 | size = i_size >> 9; |
| 183 | offset = (info->label_block + 1); | 187 | offset = (info->label_block + 1); |
| 184 | } | 188 | } |
| @@ -197,7 +201,8 @@ int ibm_partition(struct parsed_partitions *state) | |||
| 197 | * if not, something is wrong, skipping partition detection | 201 | * if not, something is wrong, skipping partition detection |
| 198 | */ | 202 | */ |
| 199 | if (strncmp(type, "VOL1", 4) == 0) { | 203 | if (strncmp(type, "VOL1", 4) == 0) { |
| 200 | printk("VOL1/%8s:", name); | 204 | snprintf(tmp, sizeof(tmp), "VOL1/%8s:", name); |
| 205 | strlcat(state->pp_buf, tmp, PAGE_SIZE); | ||
| 201 | /* | 206 | /* |
| 202 | * get block number and read then go through format1 | 207 | * get block number and read then go through format1 |
| 203 | * labels | 208 | * labels |
| @@ -253,7 +258,7 @@ int ibm_partition(struct parsed_partitions *state) | |||
| 253 | 258 | ||
| 254 | } | 259 | } |
| 255 | 260 | ||
| 256 | printk("\n"); | 261 | strlcat(state->pp_buf, "\n", PAGE_SIZE); |
| 257 | goto out_freeall; | 262 | goto out_freeall; |
| 258 | 263 | ||
| 259 | 264 | ||
diff --git a/fs/partitions/karma.c b/fs/partitions/karma.c index 1cc928bb762f..0ea19312706b 100644 --- a/fs/partitions/karma.c +++ b/fs/partitions/karma.c | |||
| @@ -50,7 +50,7 @@ int karma_partition(struct parsed_partitions *state) | |||
| 50 | } | 50 | } |
| 51 | slot++; | 51 | slot++; |
| 52 | } | 52 | } |
| 53 | printk("\n"); | 53 | strlcat(state->pp_buf, "\n", PAGE_SIZE); |
| 54 | put_dev_sector(sect); | 54 | put_dev_sector(sect); |
| 55 | return 1; | 55 | return 1; |
| 56 | } | 56 | } |
diff --git a/fs/partitions/ldm.c b/fs/partitions/ldm.c index 648c9d8f3357..5bf8a04b5d9b 100644 --- a/fs/partitions/ldm.c +++ b/fs/partitions/ldm.c | |||
| @@ -643,7 +643,7 @@ static bool ldm_create_data_partitions (struct parsed_partitions *pp, | |||
| 643 | return false; | 643 | return false; |
| 644 | } | 644 | } |
| 645 | 645 | ||
| 646 | printk (" [LDM]"); | 646 | strlcat(pp->pp_buf, " [LDM]", PAGE_SIZE); |
| 647 | 647 | ||
| 648 | /* Create the data partitions */ | 648 | /* Create the data partitions */ |
| 649 | list_for_each (item, &ldb->v_part) { | 649 | list_for_each (item, &ldb->v_part) { |
| @@ -658,7 +658,7 @@ static bool ldm_create_data_partitions (struct parsed_partitions *pp, | |||
| 658 | part_num++; | 658 | part_num++; |
| 659 | } | 659 | } |
| 660 | 660 | ||
| 661 | printk ("\n"); | 661 | strlcat(pp->pp_buf, "\n", PAGE_SIZE); |
| 662 | return true; | 662 | return true; |
| 663 | } | 663 | } |
| 664 | 664 | ||
diff --git a/fs/partitions/mac.c b/fs/partitions/mac.c index 74465ff7c263..68d6a216ee79 100644 --- a/fs/partitions/mac.c +++ b/fs/partitions/mac.c | |||
| @@ -59,7 +59,7 @@ int mac_partition(struct parsed_partitions *state) | |||
| 59 | put_dev_sector(sect); | 59 | put_dev_sector(sect); |
| 60 | return 0; /* not a MacOS disk */ | 60 | return 0; /* not a MacOS disk */ |
| 61 | } | 61 | } |
| 62 | printk(" [mac]"); | 62 | strlcat(state->pp_buf, " [mac]", PAGE_SIZE); |
| 63 | blocks_in_map = be32_to_cpu(part->map_count); | 63 | blocks_in_map = be32_to_cpu(part->map_count); |
| 64 | for (blk = 1; blk <= blocks_in_map; ++blk) { | 64 | for (blk = 1; blk <= blocks_in_map; ++blk) { |
| 65 | int pos = blk * secsize; | 65 | int pos = blk * secsize; |
| @@ -128,6 +128,6 @@ int mac_partition(struct parsed_partitions *state) | |||
| 128 | #endif | 128 | #endif |
| 129 | 129 | ||
| 130 | put_dev_sector(sect); | 130 | put_dev_sector(sect); |
| 131 | printk("\n"); | 131 | strlcat(state->pp_buf, "\n", PAGE_SIZE); |
| 132 | return 1; | 132 | return 1; |
| 133 | } | 133 | } |
diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c index 15bfb7b1e044..5f79a6677c69 100644 --- a/fs/partitions/msdos.c +++ b/fs/partitions/msdos.c | |||
| @@ -213,10 +213,18 @@ static void parse_solaris_x86(struct parsed_partitions *state, | |||
| 213 | put_dev_sector(sect); | 213 | put_dev_sector(sect); |
| 214 | return; | 214 | return; |
| 215 | } | 215 | } |
| 216 | printk(" %s%d: <solaris:", state->name, origin); | 216 | { |
| 217 | char tmp[1 + BDEVNAME_SIZE + 10 + 11 + 1]; | ||
| 218 | |||
| 219 | snprintf(tmp, sizeof(tmp), " %s%d: <solaris:", state->name, origin); | ||
| 220 | strlcat(state->pp_buf, tmp, PAGE_SIZE); | ||
| 221 | } | ||
| 217 | if (le32_to_cpu(v->v_version) != 1) { | 222 | if (le32_to_cpu(v->v_version) != 1) { |
| 218 | printk(" cannot handle version %d vtoc>\n", | 223 | char tmp[64]; |
| 219 | le32_to_cpu(v->v_version)); | 224 | |
| 225 | snprintf(tmp, sizeof(tmp), " cannot handle version %d vtoc>\n", | ||
| 226 | le32_to_cpu(v->v_version)); | ||
| 227 | strlcat(state->pp_buf, tmp, PAGE_SIZE); | ||
| 220 | put_dev_sector(sect); | 228 | put_dev_sector(sect); |
| 221 | return; | 229 | return; |
| 222 | } | 230 | } |
| @@ -224,9 +232,12 @@ static void parse_solaris_x86(struct parsed_partitions *state, | |||
| 224 | max_nparts = le16_to_cpu (v->v_nparts) > 8 ? SOLARIS_X86_NUMSLICE : 8; | 232 | max_nparts = le16_to_cpu (v->v_nparts) > 8 ? SOLARIS_X86_NUMSLICE : 8; |
| 225 | for (i=0; i<max_nparts && state->next<state->limit; i++) { | 233 | for (i=0; i<max_nparts && state->next<state->limit; i++) { |
| 226 | struct solaris_x86_slice *s = &v->v_slice[i]; | 234 | struct solaris_x86_slice *s = &v->v_slice[i]; |
| 235 | char tmp[3 + 10 + 1 + 1]; | ||
| 236 | |||
| 227 | if (s->s_size == 0) | 237 | if (s->s_size == 0) |
| 228 | continue; | 238 | continue; |
| 229 | printk(" [s%d]", i); | 239 | snprintf(tmp, sizeof(tmp), " [s%d]", i); |
| 240 | strlcat(state->pp_buf, tmp, PAGE_SIZE); | ||
| 230 | /* solaris partitions are relative to current MS-DOS | 241 | /* solaris partitions are relative to current MS-DOS |
| 231 | * one; must add the offset of the current partition */ | 242 | * one; must add the offset of the current partition */ |
| 232 | put_partition(state, state->next++, | 243 | put_partition(state, state->next++, |
| @@ -234,7 +245,7 @@ static void parse_solaris_x86(struct parsed_partitions *state, | |||
| 234 | le32_to_cpu(s->s_size)); | 245 | le32_to_cpu(s->s_size)); |
| 235 | } | 246 | } |
| 236 | put_dev_sector(sect); | 247 | put_dev_sector(sect); |
| 237 | printk(" >\n"); | 248 | strlcat(state->pp_buf, " >\n", PAGE_SIZE); |
| 238 | #endif | 249 | #endif |
| 239 | } | 250 | } |
| 240 | 251 | ||
| @@ -250,6 +261,7 @@ static void parse_bsd(struct parsed_partitions *state, | |||
| 250 | Sector sect; | 261 | Sector sect; |
| 251 | struct bsd_disklabel *l; | 262 | struct bsd_disklabel *l; |
| 252 | struct bsd_partition *p; | 263 | struct bsd_partition *p; |
| 264 | char tmp[64]; | ||
| 253 | 265 | ||
| 254 | l = read_part_sector(state, offset + 1, §); | 266 | l = read_part_sector(state, offset + 1, §); |
| 255 | if (!l) | 267 | if (!l) |
| @@ -258,7 +270,9 @@ static void parse_bsd(struct parsed_partitions *state, | |||
| 258 | put_dev_sector(sect); | 270 | put_dev_sector(sect); |
| 259 | return; | 271 | return; |
| 260 | } | 272 | } |
| 261 | printk(" %s%d: <%s:", state->name, origin, flavour); | 273 | |
| 274 | snprintf(tmp, sizeof(tmp), " %s%d: <%s:", state->name, origin, flavour); | ||
| 275 | strlcat(state->pp_buf, tmp, PAGE_SIZE); | ||
| 262 | 276 | ||
| 263 | if (le16_to_cpu(l->d_npartitions) < max_partitions) | 277 | if (le16_to_cpu(l->d_npartitions) < max_partitions) |
| 264 | max_partitions = le16_to_cpu(l->d_npartitions); | 278 | max_partitions = le16_to_cpu(l->d_npartitions); |
| @@ -275,16 +289,18 @@ static void parse_bsd(struct parsed_partitions *state, | |||
| 275 | /* full parent partition, we have it already */ | 289 | /* full parent partition, we have it already */ |
| 276 | continue; | 290 | continue; |
| 277 | if (offset > bsd_start || offset+size < bsd_start+bsd_size) { | 291 | if (offset > bsd_start || offset+size < bsd_start+bsd_size) { |
| 278 | printk("bad subpartition - ignored\n"); | 292 | strlcat(state->pp_buf, "bad subpartition - ignored\n", PAGE_SIZE); |
| 279 | continue; | 293 | continue; |
| 280 | } | 294 | } |
| 281 | put_partition(state, state->next++, bsd_start, bsd_size); | 295 | put_partition(state, state->next++, bsd_start, bsd_size); |
| 282 | } | 296 | } |
| 283 | put_dev_sector(sect); | 297 | put_dev_sector(sect); |
| 284 | if (le16_to_cpu(l->d_npartitions) > max_partitions) | 298 | if (le16_to_cpu(l->d_npartitions) > max_partitions) { |
| 285 | printk(" (ignored %d more)", | 299 | snprintf(tmp, sizeof(tmp), " (ignored %d more)", |
| 286 | le16_to_cpu(l->d_npartitions) - max_partitions); | 300 | le16_to_cpu(l->d_npartitions) - max_partitions); |
| 287 | printk(" >\n"); | 301 | strlcat(state->pp_buf, tmp, PAGE_SIZE); |
| 302 | } | ||
| 303 | strlcat(state->pp_buf, " >\n", PAGE_SIZE); | ||
| 288 | } | 304 | } |
| 289 | #endif | 305 | #endif |
| 290 | 306 | ||
| @@ -333,7 +349,12 @@ static void parse_unixware(struct parsed_partitions *state, | |||
| 333 | put_dev_sector(sect); | 349 | put_dev_sector(sect); |
| 334 | return; | 350 | return; |
| 335 | } | 351 | } |
| 336 | printk(" %s%d: <unixware:", state->name, origin); | 352 | { |
| 353 | char tmp[1 + BDEVNAME_SIZE + 10 + 12 + 1]; | ||
| 354 | |||
| 355 | snprintf(tmp, sizeof(tmp), " %s%d: <unixware:", state->name, origin); | ||
| 356 | strlcat(state->pp_buf, tmp, PAGE_SIZE); | ||
| 357 | } | ||
| 337 | p = &l->vtoc.v_slice[1]; | 358 | p = &l->vtoc.v_slice[1]; |
| 338 | /* I omit the 0th slice as it is the same as whole disk. */ | 359 | /* I omit the 0th slice as it is the same as whole disk. */ |
| 339 | while (p - &l->vtoc.v_slice[0] < UNIXWARE_NUMSLICE) { | 360 | while (p - &l->vtoc.v_slice[0] < UNIXWARE_NUMSLICE) { |
| @@ -347,7 +368,7 @@ static void parse_unixware(struct parsed_partitions *state, | |||
| 347 | p++; | 368 | p++; |
| 348 | } | 369 | } |
| 349 | put_dev_sector(sect); | 370 | put_dev_sector(sect); |
| 350 | printk(" >\n"); | 371 | strlcat(state->pp_buf, " >\n", PAGE_SIZE); |
| 351 | #endif | 372 | #endif |
| 352 | } | 373 | } |
| 353 | 374 | ||
| @@ -376,8 +397,10 @@ static void parse_minix(struct parsed_partitions *state, | |||
| 376 | * the normal boot sector. */ | 397 | * the normal boot sector. */ |
| 377 | if (msdos_magic_present (data + 510) && | 398 | if (msdos_magic_present (data + 510) && |
| 378 | SYS_IND(p) == MINIX_PARTITION) { /* subpartition table present */ | 399 | SYS_IND(p) == MINIX_PARTITION) { /* subpartition table present */ |
| 400 | char tmp[1 + BDEVNAME_SIZE + 10 + 9 + 1]; | ||
| 379 | 401 | ||
| 380 | printk(" %s%d: <minix:", state->name, origin); | 402 | snprintf(tmp, sizeof(tmp), " %s%d: <minix:", state->name, origin); |
| 403 | strlcat(state->pp_buf, tmp, PAGE_SIZE); | ||
| 381 | for (i = 0; i < MINIX_NR_SUBPARTITIONS; i++, p++) { | 404 | for (i = 0; i < MINIX_NR_SUBPARTITIONS; i++, p++) { |
| 382 | if (state->next == state->limit) | 405 | if (state->next == state->limit) |
| 383 | break; | 406 | break; |
| @@ -386,7 +409,7 @@ static void parse_minix(struct parsed_partitions *state, | |||
| 386 | put_partition(state, state->next++, | 409 | put_partition(state, state->next++, |
| 387 | start_sect(p), nr_sects(p)); | 410 | start_sect(p), nr_sects(p)); |
| 388 | } | 411 | } |
| 389 | printk(" >\n"); | 412 | strlcat(state->pp_buf, " >\n", PAGE_SIZE); |
| 390 | } | 413 | } |
| 391 | put_dev_sector(sect); | 414 | put_dev_sector(sect); |
| 392 | #endif /* CONFIG_MINIX_SUBPARTITION */ | 415 | #endif /* CONFIG_MINIX_SUBPARTITION */ |
| @@ -425,7 +448,7 @@ int msdos_partition(struct parsed_partitions *state) | |||
| 425 | 448 | ||
| 426 | if (aix_magic_present(state, data)) { | 449 | if (aix_magic_present(state, data)) { |
| 427 | put_dev_sector(sect); | 450 | put_dev_sector(sect); |
| 428 | printk( " [AIX]"); | 451 | strlcat(state->pp_buf, " [AIX]", PAGE_SIZE); |
| 429 | return 0; | 452 | return 0; |
| 430 | } | 453 | } |
| 431 | 454 | ||
| @@ -446,7 +469,7 @@ int msdos_partition(struct parsed_partitions *state) | |||
| 446 | fb = (struct fat_boot_sector *) data; | 469 | fb = (struct fat_boot_sector *) data; |
| 447 | if (slot == 1 && fb->reserved && fb->fats | 470 | if (slot == 1 && fb->reserved && fb->fats |
| 448 | && fat_valid_media(fb->media)) { | 471 | && fat_valid_media(fb->media)) { |
| 449 | printk("\n"); | 472 | strlcat(state->pp_buf, "\n", PAGE_SIZE); |
| 450 | put_dev_sector(sect); | 473 | put_dev_sector(sect); |
| 451 | return 1; | 474 | return 1; |
| 452 | } else { | 475 | } else { |
| @@ -491,21 +514,21 @@ int msdos_partition(struct parsed_partitions *state) | |||
| 491 | n = min(size, max(sector_size, n)); | 514 | n = min(size, max(sector_size, n)); |
| 492 | put_partition(state, slot, start, n); | 515 | put_partition(state, slot, start, n); |
| 493 | 516 | ||
| 494 | printk(" <"); | 517 | strlcat(state->pp_buf, " <", PAGE_SIZE); |
| 495 | parse_extended(state, start, size); | 518 | parse_extended(state, start, size); |
| 496 | printk(" >"); | 519 | strlcat(state->pp_buf, " >", PAGE_SIZE); |
| 497 | continue; | 520 | continue; |
| 498 | } | 521 | } |
| 499 | put_partition(state, slot, start, size); | 522 | put_partition(state, slot, start, size); |
| 500 | if (SYS_IND(p) == LINUX_RAID_PARTITION) | 523 | if (SYS_IND(p) == LINUX_RAID_PARTITION) |
| 501 | state->parts[slot].flags = ADDPART_FLAG_RAID; | 524 | state->parts[slot].flags = ADDPART_FLAG_RAID; |
| 502 | if (SYS_IND(p) == DM6_PARTITION) | 525 | if (SYS_IND(p) == DM6_PARTITION) |
| 503 | printk("[DM]"); | 526 | strlcat(state->pp_buf, "[DM]", PAGE_SIZE); |
| 504 | if (SYS_IND(p) == EZD_PARTITION) | 527 | if (SYS_IND(p) == EZD_PARTITION) |
| 505 | printk("[EZD]"); | 528 | strlcat(state->pp_buf, "[EZD]", PAGE_SIZE); |
| 506 | } | 529 | } |
| 507 | 530 | ||
| 508 | printk("\n"); | 531 | strlcat(state->pp_buf, "\n", PAGE_SIZE); |
| 509 | 532 | ||
| 510 | /* second pass - output for each on a separate line */ | 533 | /* second pass - output for each on a separate line */ |
| 511 | p = (struct partition *) (0x1be + data); | 534 | p = (struct partition *) (0x1be + data); |
diff --git a/fs/partitions/osf.c b/fs/partitions/osf.c index fc22b85d436a..48cec7cbca17 100644 --- a/fs/partitions/osf.c +++ b/fs/partitions/osf.c | |||
| @@ -72,7 +72,7 @@ int osf_partition(struct parsed_partitions *state) | |||
| 72 | le32_to_cpu(partition->p_size)); | 72 | le32_to_cpu(partition->p_size)); |
| 73 | slot++; | 73 | slot++; |
| 74 | } | 74 | } |
| 75 | printk("\n"); | 75 | strlcat(state->pp_buf, "\n", PAGE_SIZE); |
| 76 | put_dev_sector(sect); | 76 | put_dev_sector(sect); |
| 77 | return 1; | 77 | return 1; |
| 78 | } | 78 | } |
diff --git a/fs/partitions/sgi.c b/fs/partitions/sgi.c index 43b1df9aa16c..ea8a86dceaf4 100644 --- a/fs/partitions/sgi.c +++ b/fs/partitions/sgi.c | |||
| @@ -76,7 +76,7 @@ int sgi_partition(struct parsed_partitions *state) | |||
| 76 | } | 76 | } |
| 77 | slot++; | 77 | slot++; |
| 78 | } | 78 | } |
| 79 | printk("\n"); | 79 | strlcat(state->pp_buf, "\n", PAGE_SIZE); |
| 80 | put_dev_sector(sect); | 80 | put_dev_sector(sect); |
| 81 | return 1; | 81 | return 1; |
| 82 | } | 82 | } |
diff --git a/fs/partitions/sun.c b/fs/partitions/sun.c index a32660e25f7f..b5b6fcfb3d36 100644 --- a/fs/partitions/sun.c +++ b/fs/partitions/sun.c | |||
| @@ -116,7 +116,7 @@ int sun_partition(struct parsed_partitions *state) | |||
| 116 | } | 116 | } |
| 117 | slot++; | 117 | slot++; |
| 118 | } | 118 | } |
| 119 | printk("\n"); | 119 | strlcat(state->pp_buf, "\n", PAGE_SIZE); |
| 120 | put_dev_sector(sect); | 120 | put_dev_sector(sect); |
| 121 | return 1; | 121 | return 1; |
| 122 | } | 122 | } |
diff --git a/fs/partitions/sysv68.c b/fs/partitions/sysv68.c index 9030c864428e..9627ccffc1c4 100644 --- a/fs/partitions/sysv68.c +++ b/fs/partitions/sysv68.c | |||
| @@ -54,6 +54,7 @@ int sysv68_partition(struct parsed_partitions *state) | |||
| 54 | unsigned char *data; | 54 | unsigned char *data; |
| 55 | struct dkblk0 *b; | 55 | struct dkblk0 *b; |
| 56 | struct slice *slice; | 56 | struct slice *slice; |
| 57 | char tmp[64]; | ||
| 57 | 58 | ||
| 58 | data = read_part_sector(state, 0, §); | 59 | data = read_part_sector(state, 0, §); |
| 59 | if (!data) | 60 | if (!data) |
| @@ -73,7 +74,8 @@ int sysv68_partition(struct parsed_partitions *state) | |||
| 73 | return -1; | 74 | return -1; |
| 74 | 75 | ||
| 75 | slices -= 1; /* last slice is the whole disk */ | 76 | slices -= 1; /* last slice is the whole disk */ |
| 76 | printk("sysV68: %s(s%u)", state->name, slices); | 77 | snprintf(tmp, sizeof(tmp), "sysV68: %s(s%u)", state->name, slices); |
| 78 | strlcat(state->pp_buf, tmp, PAGE_SIZE); | ||
| 77 | slice = (struct slice *)data; | 79 | slice = (struct slice *)data; |
| 78 | for (i = 0; i < slices; i++, slice++) { | 80 | for (i = 0; i < slices; i++, slice++) { |
| 79 | if (slot == state->limit) | 81 | if (slot == state->limit) |
| @@ -82,11 +84,12 @@ int sysv68_partition(struct parsed_partitions *state) | |||
| 82 | put_partition(state, slot, | 84 | put_partition(state, slot, |
| 83 | be32_to_cpu(slice->blkoff), | 85 | be32_to_cpu(slice->blkoff), |
| 84 | be32_to_cpu(slice->nblocks)); | 86 | be32_to_cpu(slice->nblocks)); |
| 85 | printk("(s%u)", i); | 87 | snprintf(tmp, sizeof(tmp), "(s%u)", i); |
| 88 | strlcat(state->pp_buf, tmp, PAGE_SIZE); | ||
| 86 | } | 89 | } |
| 87 | slot++; | 90 | slot++; |
| 88 | } | 91 | } |
| 89 | printk("\n"); | 92 | strlcat(state->pp_buf, "\n", PAGE_SIZE); |
| 90 | put_dev_sector(sect); | 93 | put_dev_sector(sect); |
| 91 | return 1; | 94 | return 1; |
| 92 | } | 95 | } |
diff --git a/fs/partitions/ultrix.c b/fs/partitions/ultrix.c index db9eef260364..8dbaf9f77a99 100644 --- a/fs/partitions/ultrix.c +++ b/fs/partitions/ultrix.c | |||
| @@ -39,7 +39,7 @@ int ultrix_partition(struct parsed_partitions *state) | |||
| 39 | label->pt_part[i].pi_blkoff, | 39 | label->pt_part[i].pi_blkoff, |
| 40 | label->pt_part[i].pi_nblocks); | 40 | label->pt_part[i].pi_nblocks); |
| 41 | put_dev_sector(sect); | 41 | put_dev_sector(sect); |
| 42 | printk ("\n"); | 42 | strlcat(state->pp_buf, "\n", PAGE_SIZE); |
| 43 | return 1; | 43 | return 1; |
| 44 | } else { | 44 | } else { |
| 45 | put_dev_sector(sect); | 45 | put_dev_sector(sect); |
diff --git a/fs/proc/Makefile b/fs/proc/Makefile index 11a7b5c68153..2758e2afc518 100644 --- a/fs/proc/Makefile +++ b/fs/proc/Makefile | |||
| @@ -2,7 +2,7 @@ | |||
| 2 | # Makefile for the Linux proc filesystem routines. | 2 | # Makefile for the Linux proc filesystem routines. |
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | obj-$(CONFIG_PROC_FS) += proc.o | 5 | obj-y += proc.o |
| 6 | 6 | ||
| 7 | proc-y := nommu.o task_nommu.o | 7 | proc-y := nommu.o task_nommu.o |
| 8 | proc-$(CONFIG_MMU) := mmu.o task_mmu.o | 8 | proc-$(CONFIG_MMU) := mmu.o task_mmu.o |
diff --git a/fs/proc/base.c b/fs/proc/base.c index 69254a365ce2..a1c43e7c8a7b 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
| @@ -149,18 +149,13 @@ static unsigned int pid_entry_count_dirs(const struct pid_entry *entries, | |||
| 149 | return count; | 149 | return count; |
| 150 | } | 150 | } |
| 151 | 151 | ||
| 152 | static int get_fs_path(struct task_struct *task, struct path *path, bool root) | 152 | static int get_task_root(struct task_struct *task, struct path *root) |
| 153 | { | 153 | { |
| 154 | struct fs_struct *fs; | ||
| 155 | int result = -ENOENT; | 154 | int result = -ENOENT; |
| 156 | 155 | ||
| 157 | task_lock(task); | 156 | task_lock(task); |
| 158 | fs = task->fs; | 157 | if (task->fs) { |
| 159 | if (fs) { | 158 | get_fs_root(task->fs, root); |
| 160 | read_lock(&fs->lock); | ||
| 161 | *path = root ? fs->root : fs->pwd; | ||
| 162 | path_get(path); | ||
| 163 | read_unlock(&fs->lock); | ||
| 164 | result = 0; | 159 | result = 0; |
| 165 | } | 160 | } |
| 166 | task_unlock(task); | 161 | task_unlock(task); |
| @@ -173,7 +168,12 @@ static int proc_cwd_link(struct inode *inode, struct path *path) | |||
| 173 | int result = -ENOENT; | 168 | int result = -ENOENT; |
| 174 | 169 | ||
| 175 | if (task) { | 170 | if (task) { |
| 176 | result = get_fs_path(task, path, 0); | 171 | task_lock(task); |
| 172 | if (task->fs) { | ||
| 173 | get_fs_pwd(task->fs, path); | ||
| 174 | result = 0; | ||
| 175 | } | ||
| 176 | task_unlock(task); | ||
| 177 | put_task_struct(task); | 177 | put_task_struct(task); |
| 178 | } | 178 | } |
| 179 | return result; | 179 | return result; |
| @@ -185,7 +185,7 @@ static int proc_root_link(struct inode *inode, struct path *path) | |||
| 185 | int result = -ENOENT; | 185 | int result = -ENOENT; |
| 186 | 186 | ||
| 187 | if (task) { | 187 | if (task) { |
| 188 | result = get_fs_path(task, path, 1); | 188 | result = get_task_root(task, path); |
| 189 | put_task_struct(task); | 189 | put_task_struct(task); |
| 190 | } | 190 | } |
| 191 | return result; | 191 | return result; |
| @@ -559,9 +559,19 @@ static int proc_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 559 | return -EPERM; | 559 | return -EPERM; |
| 560 | 560 | ||
| 561 | error = inode_change_ok(inode, attr); | 561 | error = inode_change_ok(inode, attr); |
| 562 | if (!error) | 562 | if (error) |
| 563 | error = inode_setattr(inode, attr); | 563 | return error; |
| 564 | return error; | 564 | |
| 565 | if ((attr->ia_valid & ATTR_SIZE) && | ||
| 566 | attr->ia_size != i_size_read(inode)) { | ||
| 567 | error = vmtruncate(inode, attr->ia_size); | ||
| 568 | if (error) | ||
| 569 | return error; | ||
| 570 | } | ||
| 571 | |||
| 572 | setattr_copy(inode, attr); | ||
| 573 | mark_inode_dirty(inode); | ||
| 574 | return 0; | ||
| 565 | } | 575 | } |
| 566 | 576 | ||
| 567 | static const struct inode_operations proc_def_inode_operations = { | 577 | static const struct inode_operations proc_def_inode_operations = { |
| @@ -587,7 +597,7 @@ static int mounts_open_common(struct inode *inode, struct file *file, | |||
| 587 | get_mnt_ns(ns); | 597 | get_mnt_ns(ns); |
| 588 | } | 598 | } |
| 589 | rcu_read_unlock(); | 599 | rcu_read_unlock(); |
| 590 | if (ns && get_fs_path(task, &root, 1) == 0) | 600 | if (ns && get_task_root(task, &root) == 0) |
| 591 | ret = 0; | 601 | ret = 0; |
| 592 | put_task_struct(task); | 602 | put_task_struct(task); |
| 593 | } | 603 | } |
| @@ -1516,7 +1526,7 @@ static int do_proc_readlink(struct path *path, char __user *buffer, int buflen) | |||
| 1516 | if (!tmp) | 1526 | if (!tmp) |
| 1517 | return -ENOMEM; | 1527 | return -ENOMEM; |
| 1518 | 1528 | ||
| 1519 | pathname = d_path(path, tmp, PAGE_SIZE); | 1529 | pathname = d_path_with_unreachable(path, tmp, PAGE_SIZE); |
| 1520 | len = PTR_ERR(pathname); | 1530 | len = PTR_ERR(pathname); |
| 1521 | if (IS_ERR(pathname)) | 1531 | if (IS_ERR(pathname)) |
| 1522 | goto out; | 1532 | goto out; |
diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 2791907744ed..dd29f0337661 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include <linux/time.h> | 12 | #include <linux/time.h> |
| 13 | #include <linux/proc_fs.h> | 13 | #include <linux/proc_fs.h> |
| 14 | #include <linux/stat.h> | 14 | #include <linux/stat.h> |
| 15 | #include <linux/mm.h> | ||
| 15 | #include <linux/module.h> | 16 | #include <linux/module.h> |
| 16 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
| 17 | #include <linux/mount.h> | 18 | #include <linux/mount.h> |
| @@ -258,17 +259,22 @@ static int proc_notify_change(struct dentry *dentry, struct iattr *iattr) | |||
| 258 | 259 | ||
| 259 | error = inode_change_ok(inode, iattr); | 260 | error = inode_change_ok(inode, iattr); |
| 260 | if (error) | 261 | if (error) |
| 261 | goto out; | 262 | return error; |
| 262 | 263 | ||
| 263 | error = inode_setattr(inode, iattr); | 264 | if ((iattr->ia_valid & ATTR_SIZE) && |
| 264 | if (error) | 265 | iattr->ia_size != i_size_read(inode)) { |
| 265 | goto out; | 266 | error = vmtruncate(inode, iattr->ia_size); |
| 267 | if (error) | ||
| 268 | return error; | ||
| 269 | } | ||
| 270 | |||
| 271 | setattr_copy(inode, iattr); | ||
| 272 | mark_inode_dirty(inode); | ||
| 266 | 273 | ||
| 267 | de->uid = inode->i_uid; | 274 | de->uid = inode->i_uid; |
| 268 | de->gid = inode->i_gid; | 275 | de->gid = inode->i_gid; |
| 269 | de->mode = inode->i_mode; | 276 | de->mode = inode->i_mode; |
| 270 | out: | 277 | return 0; |
| 271 | return error; | ||
| 272 | } | 278 | } |
| 273 | 279 | ||
| 274 | static int proc_getattr(struct vfsmount *mnt, struct dentry *dentry, | 280 | static int proc_getattr(struct vfsmount *mnt, struct dentry *dentry, |
diff --git a/fs/proc/inode.c b/fs/proc/inode.c index aea8502e58a3..9c2b5f484879 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c | |||
| @@ -25,11 +25,12 @@ | |||
| 25 | 25 | ||
| 26 | #include "internal.h" | 26 | #include "internal.h" |
| 27 | 27 | ||
| 28 | static void proc_delete_inode(struct inode *inode) | 28 | static void proc_evict_inode(struct inode *inode) |
| 29 | { | 29 | { |
| 30 | struct proc_dir_entry *de; | 30 | struct proc_dir_entry *de; |
| 31 | 31 | ||
| 32 | truncate_inode_pages(&inode->i_data, 0); | 32 | truncate_inode_pages(&inode->i_data, 0); |
| 33 | end_writeback(inode); | ||
| 33 | 34 | ||
| 34 | /* Stop tracking associated processes */ | 35 | /* Stop tracking associated processes */ |
| 35 | put_pid(PROC_I(inode)->pid); | 36 | put_pid(PROC_I(inode)->pid); |
| @@ -40,7 +41,6 @@ static void proc_delete_inode(struct inode *inode) | |||
| 40 | pde_put(de); | 41 | pde_put(de); |
| 41 | if (PROC_I(inode)->sysctl) | 42 | if (PROC_I(inode)->sysctl) |
| 42 | sysctl_head_put(PROC_I(inode)->sysctl); | 43 | sysctl_head_put(PROC_I(inode)->sysctl); |
| 43 | clear_inode(inode); | ||
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | struct vfsmount *proc_mnt; | 46 | struct vfsmount *proc_mnt; |
| @@ -91,7 +91,7 @@ static const struct super_operations proc_sops = { | |||
| 91 | .alloc_inode = proc_alloc_inode, | 91 | .alloc_inode = proc_alloc_inode, |
| 92 | .destroy_inode = proc_destroy_inode, | 92 | .destroy_inode = proc_destroy_inode, |
| 93 | .drop_inode = generic_delete_inode, | 93 | .drop_inode = generic_delete_inode, |
| 94 | .delete_inode = proc_delete_inode, | 94 | .evict_inode = proc_evict_inode, |
| 95 | .statfs = simple_statfs, | 95 | .statfs = simple_statfs, |
| 96 | }; | 96 | }; |
| 97 | 97 | ||
| @@ -214,8 +214,7 @@ static long proc_reg_unlocked_ioctl(struct file *file, unsigned int cmd, unsigne | |||
| 214 | { | 214 | { |
| 215 | struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); | 215 | struct proc_dir_entry *pde = PDE(file->f_path.dentry->d_inode); |
| 216 | long rv = -ENOTTY; | 216 | long rv = -ENOTTY; |
| 217 | long (*unlocked_ioctl)(struct file *, unsigned int, unsigned long); | 217 | long (*ioctl)(struct file *, unsigned int, unsigned long); |
| 218 | int (*ioctl)(struct inode *, struct file *, unsigned int, unsigned long); | ||
| 219 | 218 | ||
| 220 | spin_lock(&pde->pde_unload_lock); | 219 | spin_lock(&pde->pde_unload_lock); |
| 221 | if (!pde->proc_fops) { | 220 | if (!pde->proc_fops) { |
| @@ -223,19 +222,11 @@ static long proc_reg_unlocked_ioctl(struct file *file, unsigned int cmd, unsigne | |||
| 223 | return rv; | 222 | return rv; |
| 224 | } | 223 | } |
| 225 | pde->pde_users++; | 224 | pde->pde_users++; |
| 226 | unlocked_ioctl = pde->proc_fops->unlocked_ioctl; | 225 | ioctl = pde->proc_fops->unlocked_ioctl; |
| 227 | ioctl = pde->proc_fops->ioctl; | ||
| 228 | spin_unlock(&pde->pde_unload_lock); | 226 | spin_unlock(&pde->pde_unload_lock); |
| 229 | 227 | ||
| 230 | if (unlocked_ioctl) { | 228 | if (ioctl) |
| 231 | rv = unlocked_ioctl(file, cmd, arg); | 229 | rv = ioctl(file, cmd, arg); |
| 232 | if (rv == -ENOIOCTLCMD) | ||
| 233 | rv = -EINVAL; | ||
| 234 | } else if (ioctl) { | ||
| 235 | WARN_ONCE(1, "Procfs ioctl handlers must use unlocked_ioctl, " | ||
| 236 | "%pf will be called without the Bkl held\n", ioctl); | ||
| 237 | rv = ioctl(file->f_path.dentry->d_inode, file, cmd, arg); | ||
| 238 | } | ||
| 239 | 230 | ||
| 240 | pde_users_dec(pde); | 231 | pde_users_dec(pde); |
| 241 | return rv; | 232 | return rv; |
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c index 6ff9981f0a18..5be436ea088e 100644 --- a/fs/proc/proc_sysctl.c +++ b/fs/proc/proc_sysctl.c | |||
| @@ -329,10 +329,19 @@ static int proc_sys_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 329 | return -EPERM; | 329 | return -EPERM; |
| 330 | 330 | ||
| 331 | error = inode_change_ok(inode, attr); | 331 | error = inode_change_ok(inode, attr); |
| 332 | if (!error) | 332 | if (error) |
| 333 | error = inode_setattr(inode, attr); | 333 | return error; |
| 334 | |||
| 335 | if ((attr->ia_valid & ATTR_SIZE) && | ||
| 336 | attr->ia_size != i_size_read(inode)) { | ||
| 337 | error = vmtruncate(inode, attr->ia_size); | ||
| 338 | if (error) | ||
| 339 | return error; | ||
| 340 | } | ||
| 334 | 341 | ||
| 335 | return error; | 342 | setattr_copy(inode, attr); |
| 343 | mark_inode_dirty(inode); | ||
| 344 | return 0; | ||
| 336 | } | 345 | } |
| 337 | 346 | ||
| 338 | static int proc_sys_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | 347 | static int proc_sys_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) |
diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index 277575ddc05c..16829722be93 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c | |||
| @@ -320,10 +320,19 @@ static int qnx4_write_begin(struct file *file, struct address_space *mapping, | |||
| 320 | struct page **pagep, void **fsdata) | 320 | struct page **pagep, void **fsdata) |
| 321 | { | 321 | { |
| 322 | struct qnx4_inode_info *qnx4_inode = qnx4_i(mapping->host); | 322 | struct qnx4_inode_info *qnx4_inode = qnx4_i(mapping->host); |
| 323 | int ret; | ||
| 324 | |||
| 323 | *pagep = NULL; | 325 | *pagep = NULL; |
| 324 | return cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, | 326 | ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata, |
| 325 | qnx4_get_block, | 327 | qnx4_get_block, |
| 326 | &qnx4_inode->mmu_private); | 328 | &qnx4_inode->mmu_private); |
| 329 | if (unlikely(ret)) { | ||
| 330 | loff_t isize = mapping->host->i_size; | ||
| 331 | if (pos + len > isize) | ||
| 332 | vmtruncate(mapping->host, isize); | ||
| 333 | } | ||
| 334 | |||
| 335 | return ret; | ||
| 327 | } | 336 | } |
| 328 | static sector_t qnx4_bmap(struct address_space *mapping, sector_t block) | 337 | static sector_t qnx4_bmap(struct address_space *mapping, sector_t block) |
| 329 | { | 338 | { |
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c index ef72b1699429..aad1316a977f 100644 --- a/fs/quota/dquot.c +++ b/fs/quota/dquot.c | |||
| @@ -898,7 +898,7 @@ static void add_dquot_ref(struct super_block *sb, int type) | |||
| 898 | 898 | ||
| 899 | spin_lock(&inode_lock); | 899 | spin_lock(&inode_lock); |
| 900 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { | 900 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { |
| 901 | if (inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE|I_NEW)) | 901 | if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) |
| 902 | continue; | 902 | continue; |
| 903 | #ifdef CONFIG_QUOTA_DEBUG | 903 | #ifdef CONFIG_QUOTA_DEBUG |
| 904 | if (unlikely(inode_get_rsv_space(inode) > 0)) | 904 | if (unlikely(inode_get_rsv_space(inode) > 0)) |
diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c index d532c20fc179..9eead2c796b7 100644 --- a/fs/ramfs/file-nommu.c +++ b/fs/ramfs/file-nommu.c | |||
| @@ -146,9 +146,8 @@ static int ramfs_nommu_resize(struct inode *inode, loff_t newsize, loff_t size) | |||
| 146 | return ret; | 146 | return ret; |
| 147 | } | 147 | } |
| 148 | 148 | ||
| 149 | ret = simple_setsize(inode, newsize); | 149 | truncate_setsize(inode, newsize); |
| 150 | 150 | return 0; | |
| 151 | return ret; | ||
| 152 | } | 151 | } |
| 153 | 152 | ||
| 154 | /*****************************************************************************/ | 153 | /*****************************************************************************/ |
| @@ -183,7 +182,7 @@ static int ramfs_nommu_setattr(struct dentry *dentry, struct iattr *ia) | |||
| 183 | } | 182 | } |
| 184 | } | 183 | } |
| 185 | 184 | ||
| 186 | generic_setattr(inode, ia); | 185 | setattr_copy(inode, ia); |
| 187 | out: | 186 | out: |
| 188 | ia->ia_valid = old_ia_valid; | 187 | ia->ia_valid = old_ia_valid; |
| 189 | return ret; | 188 | return ret; |
diff --git a/fs/read_write.c b/fs/read_write.c index 9c0485236e68..74e36586e4d3 100644 --- a/fs/read_write.c +++ b/fs/read_write.c | |||
| @@ -311,7 +311,7 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) | |||
| 311 | else | 311 | else |
| 312 | ret = do_sync_read(file, buf, count, pos); | 312 | ret = do_sync_read(file, buf, count, pos); |
| 313 | if (ret > 0) { | 313 | if (ret > 0) { |
| 314 | fsnotify_access(file->f_path.dentry); | 314 | fsnotify_access(file); |
| 315 | add_rchar(current, ret); | 315 | add_rchar(current, ret); |
| 316 | } | 316 | } |
| 317 | inc_syscr(current); | 317 | inc_syscr(current); |
| @@ -367,7 +367,7 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_ | |||
| 367 | else | 367 | else |
| 368 | ret = do_sync_write(file, buf, count, pos); | 368 | ret = do_sync_write(file, buf, count, pos); |
| 369 | if (ret > 0) { | 369 | if (ret > 0) { |
| 370 | fsnotify_modify(file->f_path.dentry); | 370 | fsnotify_modify(file); |
| 371 | add_wchar(current, ret); | 371 | add_wchar(current, ret); |
| 372 | } | 372 | } |
| 373 | inc_syscw(current); | 373 | inc_syscw(current); |
| @@ -675,9 +675,9 @@ out: | |||
| 675 | kfree(iov); | 675 | kfree(iov); |
| 676 | if ((ret + (type == READ)) > 0) { | 676 | if ((ret + (type == READ)) > 0) { |
| 677 | if (type == READ) | 677 | if (type == READ) |
| 678 | fsnotify_access(file->f_path.dentry); | 678 | fsnotify_access(file); |
| 679 | else | 679 | else |
| 680 | fsnotify_modify(file->f_path.dentry); | 680 | fsnotify_modify(file); |
| 681 | } | 681 | } |
| 682 | return ret; | 682 | return ret; |
| 683 | } | 683 | } |
diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c index b82cdd8a45dd..6846371498b6 100644 --- a/fs/reiserfs/file.c +++ b/fs/reiserfs/file.c | |||
| @@ -38,20 +38,24 @@ static int reiserfs_file_release(struct inode *inode, struct file *filp) | |||
| 38 | 38 | ||
| 39 | BUG_ON(!S_ISREG(inode->i_mode)); | 39 | BUG_ON(!S_ISREG(inode->i_mode)); |
| 40 | 40 | ||
| 41 | if (atomic_add_unless(&REISERFS_I(inode)->openers, -1, 1)) | ||
| 42 | return 0; | ||
| 43 | |||
| 44 | mutex_lock(&(REISERFS_I(inode)->tailpack)); | ||
| 45 | |||
| 46 | if (!atomic_dec_and_test(&REISERFS_I(inode)->openers)) { | ||
| 47 | mutex_unlock(&(REISERFS_I(inode)->tailpack)); | ||
| 48 | return 0; | ||
| 49 | } | ||
| 50 | |||
| 41 | /* fast out for when nothing needs to be done */ | 51 | /* fast out for when nothing needs to be done */ |
| 42 | if ((atomic_read(&inode->i_count) > 1 || | 52 | if ((!(REISERFS_I(inode)->i_flags & i_pack_on_close_mask) || |
| 43 | !(REISERFS_I(inode)->i_flags & i_pack_on_close_mask) || | ||
| 44 | !tail_has_to_be_packed(inode)) && | 53 | !tail_has_to_be_packed(inode)) && |
| 45 | REISERFS_I(inode)->i_prealloc_count <= 0) { | 54 | REISERFS_I(inode)->i_prealloc_count <= 0) { |
| 55 | mutex_unlock(&(REISERFS_I(inode)->tailpack)); | ||
| 46 | return 0; | 56 | return 0; |
| 47 | } | 57 | } |
| 48 | 58 | ||
| 49 | mutex_lock(&inode->i_mutex); | ||
| 50 | |||
| 51 | mutex_lock(&(REISERFS_I(inode)->i_mmap)); | ||
| 52 | if (REISERFS_I(inode)->i_flags & i_ever_mapped) | ||
| 53 | REISERFS_I(inode)->i_flags &= ~i_pack_on_close_mask; | ||
| 54 | |||
| 55 | reiserfs_write_lock(inode->i_sb); | 59 | reiserfs_write_lock(inode->i_sb); |
| 56 | /* freeing preallocation only involves relogging blocks that | 60 | /* freeing preallocation only involves relogging blocks that |
| 57 | * are already in the current transaction. preallocation gets | 61 | * are already in the current transaction. preallocation gets |
| @@ -94,9 +98,10 @@ static int reiserfs_file_release(struct inode *inode, struct file *filp) | |||
| 94 | if (!err) | 98 | if (!err) |
| 95 | err = jbegin_failure; | 99 | err = jbegin_failure; |
| 96 | 100 | ||
| 97 | if (!err && atomic_read(&inode->i_count) <= 1 && | 101 | if (!err && |
| 98 | (REISERFS_I(inode)->i_flags & i_pack_on_close_mask) && | 102 | (REISERFS_I(inode)->i_flags & i_pack_on_close_mask) && |
| 99 | tail_has_to_be_packed(inode)) { | 103 | tail_has_to_be_packed(inode)) { |
| 104 | |||
| 100 | /* if regular file is released by last holder and it has been | 105 | /* if regular file is released by last holder and it has been |
| 101 | appended (we append by unformatted node only) or its direct | 106 | appended (we append by unformatted node only) or its direct |
| 102 | item(s) had to be converted, then it may have to be | 107 | item(s) had to be converted, then it may have to be |
| @@ -104,27 +109,28 @@ static int reiserfs_file_release(struct inode *inode, struct file *filp) | |||
| 104 | err = reiserfs_truncate_file(inode, 0); | 109 | err = reiserfs_truncate_file(inode, 0); |
| 105 | } | 110 | } |
| 106 | out: | 111 | out: |
| 107 | mutex_unlock(&(REISERFS_I(inode)->i_mmap)); | ||
| 108 | mutex_unlock(&inode->i_mutex); | ||
| 109 | reiserfs_write_unlock(inode->i_sb); | 112 | reiserfs_write_unlock(inode->i_sb); |
| 113 | mutex_unlock(&(REISERFS_I(inode)->tailpack)); | ||
| 110 | return err; | 114 | return err; |
| 111 | } | 115 | } |
| 112 | 116 | ||
| 113 | static int reiserfs_file_mmap(struct file *file, struct vm_area_struct *vma) | 117 | static int reiserfs_file_open(struct inode *inode, struct file *file) |
| 114 | { | 118 | { |
| 115 | struct inode *inode; | 119 | int err = dquot_file_open(inode, file); |
| 116 | 120 | if (!atomic_inc_not_zero(&REISERFS_I(inode)->openers)) { | |
| 117 | inode = file->f_path.dentry->d_inode; | 121 | /* somebody might be tailpacking on final close; wait for it */ |
| 118 | mutex_lock(&(REISERFS_I(inode)->i_mmap)); | 122 | mutex_lock(&(REISERFS_I(inode)->tailpack)); |
| 119 | REISERFS_I(inode)->i_flags |= i_ever_mapped; | 123 | atomic_inc(&REISERFS_I(inode)->openers); |
| 120 | mutex_unlock(&(REISERFS_I(inode)->i_mmap)); | 124 | mutex_unlock(&(REISERFS_I(inode)->tailpack)); |
| 121 | 125 | } | |
| 122 | return generic_file_mmap(file, vma); | 126 | return err; |
| 123 | } | 127 | } |
| 124 | 128 | ||
| 125 | static void reiserfs_vfs_truncate_file(struct inode *inode) | 129 | static void reiserfs_vfs_truncate_file(struct inode *inode) |
| 126 | { | 130 | { |
| 131 | mutex_lock(&(REISERFS_I(inode)->tailpack)); | ||
| 127 | reiserfs_truncate_file(inode, 1); | 132 | reiserfs_truncate_file(inode, 1); |
| 133 | mutex_unlock(&(REISERFS_I(inode)->tailpack)); | ||
| 128 | } | 134 | } |
| 129 | 135 | ||
| 130 | /* Sync a reiserfs file. */ | 136 | /* Sync a reiserfs file. */ |
| @@ -288,8 +294,8 @@ const struct file_operations reiserfs_file_operations = { | |||
| 288 | #ifdef CONFIG_COMPAT | 294 | #ifdef CONFIG_COMPAT |
| 289 | .compat_ioctl = reiserfs_compat_ioctl, | 295 | .compat_ioctl = reiserfs_compat_ioctl, |
| 290 | #endif | 296 | #endif |
| 291 | .mmap = reiserfs_file_mmap, | 297 | .mmap = generic_file_mmap, |
| 292 | .open = dquot_file_open, | 298 | .open = reiserfs_file_open, |
| 293 | .release = reiserfs_file_release, | 299 | .release = reiserfs_file_release, |
| 294 | .fsync = reiserfs_sync_file, | 300 | .fsync = reiserfs_sync_file, |
| 295 | .aio_read = generic_file_aio_read, | 301 | .aio_read = generic_file_aio_read, |
diff --git a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c index 29db72203bde..ae35413dcbe1 100644 --- a/fs/reiserfs/inode.c +++ b/fs/reiserfs/inode.c | |||
| @@ -25,7 +25,7 @@ int reiserfs_commit_write(struct file *f, struct page *page, | |||
| 25 | int reiserfs_prepare_write(struct file *f, struct page *page, | 25 | int reiserfs_prepare_write(struct file *f, struct page *page, |
| 26 | unsigned from, unsigned to); | 26 | unsigned from, unsigned to); |
| 27 | 27 | ||
| 28 | void reiserfs_delete_inode(struct inode *inode) | 28 | void reiserfs_evict_inode(struct inode *inode) |
| 29 | { | 29 | { |
| 30 | /* We need blocks for transaction + (user+group) quota update (possibly delete) */ | 30 | /* We need blocks for transaction + (user+group) quota update (possibly delete) */ |
| 31 | int jbegin_count = | 31 | int jbegin_count = |
| @@ -35,10 +35,12 @@ void reiserfs_delete_inode(struct inode *inode) | |||
| 35 | int depth; | 35 | int depth; |
| 36 | int err; | 36 | int err; |
| 37 | 37 | ||
| 38 | if (!is_bad_inode(inode)) | 38 | if (!inode->i_nlink && !is_bad_inode(inode)) |
| 39 | dquot_initialize(inode); | 39 | dquot_initialize(inode); |
| 40 | 40 | ||
| 41 | truncate_inode_pages(&inode->i_data, 0); | 41 | truncate_inode_pages(&inode->i_data, 0); |
| 42 | if (inode->i_nlink) | ||
| 43 | goto no_delete; | ||
| 42 | 44 | ||
| 43 | depth = reiserfs_write_lock_once(inode->i_sb); | 45 | depth = reiserfs_write_lock_once(inode->i_sb); |
| 44 | 46 | ||
| @@ -77,9 +79,14 @@ void reiserfs_delete_inode(struct inode *inode) | |||
| 77 | ; | 79 | ; |
| 78 | } | 80 | } |
| 79 | out: | 81 | out: |
| 80 | clear_inode(inode); /* note this must go after the journal_end to prevent deadlock */ | 82 | end_writeback(inode); /* note this must go after the journal_end to prevent deadlock */ |
| 83 | dquot_drop(inode); | ||
| 81 | inode->i_blocks = 0; | 84 | inode->i_blocks = 0; |
| 82 | reiserfs_write_unlock_once(inode->i_sb, depth); | 85 | reiserfs_write_unlock_once(inode->i_sb, depth); |
| 86 | |||
| 87 | no_delete: | ||
| 88 | end_writeback(inode); | ||
| 89 | dquot_drop(inode); | ||
| 83 | } | 90 | } |
| 84 | 91 | ||
| 85 | static void _make_cpu_key(struct cpu_key *key, int version, __u32 dirid, | 92 | static void _make_cpu_key(struct cpu_key *key, int version, __u32 dirid, |
| @@ -1138,7 +1145,6 @@ static void init_inode(struct inode *inode, struct treepath *path) | |||
| 1138 | REISERFS_I(inode)->i_prealloc_count = 0; | 1145 | REISERFS_I(inode)->i_prealloc_count = 0; |
| 1139 | REISERFS_I(inode)->i_trans_id = 0; | 1146 | REISERFS_I(inode)->i_trans_id = 0; |
| 1140 | REISERFS_I(inode)->i_jl = NULL; | 1147 | REISERFS_I(inode)->i_jl = NULL; |
| 1141 | mutex_init(&(REISERFS_I(inode)->i_mmap)); | ||
| 1142 | reiserfs_init_xattr_rwsem(inode); | 1148 | reiserfs_init_xattr_rwsem(inode); |
| 1143 | 1149 | ||
| 1144 | if (stat_data_v1(ih)) { | 1150 | if (stat_data_v1(ih)) { |
| @@ -1841,7 +1847,6 @@ int reiserfs_new_inode(struct reiserfs_transaction_handle *th, | |||
| 1841 | REISERFS_I(inode)->i_attrs = | 1847 | REISERFS_I(inode)->i_attrs = |
| 1842 | REISERFS_I(dir)->i_attrs & REISERFS_INHERIT_MASK; | 1848 | REISERFS_I(dir)->i_attrs & REISERFS_INHERIT_MASK; |
| 1843 | sd_attrs_to_i_attrs(REISERFS_I(inode)->i_attrs, inode); | 1849 | sd_attrs_to_i_attrs(REISERFS_I(inode)->i_attrs, inode); |
| 1844 | mutex_init(&(REISERFS_I(inode)->i_mmap)); | ||
| 1845 | reiserfs_init_xattr_rwsem(inode); | 1850 | reiserfs_init_xattr_rwsem(inode); |
| 1846 | 1851 | ||
| 1847 | /* key to search for correct place for new stat data */ | 1852 | /* key to search for correct place for new stat data */ |
| @@ -2587,8 +2592,7 @@ static int reiserfs_write_begin(struct file *file, | |||
| 2587 | old_ref = th->t_refcount; | 2592 | old_ref = th->t_refcount; |
| 2588 | th->t_refcount++; | 2593 | th->t_refcount++; |
| 2589 | } | 2594 | } |
| 2590 | ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata, | 2595 | ret = __block_write_begin(page, pos, len, reiserfs_get_block); |
| 2591 | reiserfs_get_block); | ||
| 2592 | if (ret && reiserfs_transaction_running(inode->i_sb)) { | 2596 | if (ret && reiserfs_transaction_running(inode->i_sb)) { |
| 2593 | struct reiserfs_transaction_handle *th = current->journal_info; | 2597 | struct reiserfs_transaction_handle *th = current->journal_info; |
| 2594 | /* this gets a little ugly. If reiserfs_get_block returned an | 2598 | /* this gets a little ugly. If reiserfs_get_block returned an |
| @@ -3059,10 +3063,25 @@ static ssize_t reiserfs_direct_IO(int rw, struct kiocb *iocb, | |||
| 3059 | { | 3063 | { |
| 3060 | struct file *file = iocb->ki_filp; | 3064 | struct file *file = iocb->ki_filp; |
| 3061 | struct inode *inode = file->f_mapping->host; | 3065 | struct inode *inode = file->f_mapping->host; |
| 3066 | ssize_t ret; | ||
| 3062 | 3067 | ||
| 3063 | return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, | 3068 | ret = blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov, |
| 3064 | offset, nr_segs, | 3069 | offset, nr_segs, |
| 3065 | reiserfs_get_blocks_direct_io, NULL); | 3070 | reiserfs_get_blocks_direct_io, NULL); |
| 3071 | |||
| 3072 | /* | ||
| 3073 | * In case of error extending write may have instantiated a few | ||
| 3074 | * blocks outside i_size. Trim these off again. | ||
| 3075 | */ | ||
| 3076 | if (unlikely((rw & WRITE) && ret < 0)) { | ||
| 3077 | loff_t isize = i_size_read(inode); | ||
| 3078 | loff_t end = offset + iov_length(iov, nr_segs); | ||
| 3079 | |||
| 3080 | if (end > isize) | ||
| 3081 | vmtruncate(inode, isize); | ||
| 3082 | } | ||
| 3083 | |||
| 3084 | return ret; | ||
| 3066 | } | 3085 | } |
| 3067 | 3086 | ||
| 3068 | int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) | 3087 | int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) |
| @@ -3072,6 +3091,10 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 3072 | int depth; | 3091 | int depth; |
| 3073 | int error; | 3092 | int error; |
| 3074 | 3093 | ||
| 3094 | error = inode_change_ok(inode, attr); | ||
| 3095 | if (error) | ||
| 3096 | return error; | ||
| 3097 | |||
| 3075 | /* must be turned off for recursive notify_change calls */ | 3098 | /* must be turned off for recursive notify_change calls */ |
| 3076 | ia_valid = attr->ia_valid &= ~(ATTR_KILL_SUID|ATTR_KILL_SGID); | 3099 | ia_valid = attr->ia_valid &= ~(ATTR_KILL_SUID|ATTR_KILL_SGID); |
| 3077 | 3100 | ||
| @@ -3121,55 +3144,58 @@ int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 3121 | goto out; | 3144 | goto out; |
| 3122 | } | 3145 | } |
| 3123 | 3146 | ||
| 3124 | error = inode_change_ok(inode, attr); | 3147 | if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || |
| 3125 | if (!error) { | 3148 | (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) { |
| 3126 | if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || | 3149 | struct reiserfs_transaction_handle th; |
| 3127 | (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) { | 3150 | int jbegin_count = |
| 3128 | error = reiserfs_chown_xattrs(inode, attr); | 3151 | 2 * |
| 3152 | (REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb) + | ||
| 3153 | REISERFS_QUOTA_DEL_BLOCKS(inode->i_sb)) + | ||
| 3154 | 2; | ||
| 3129 | 3155 | ||
| 3130 | if (!error) { | 3156 | error = reiserfs_chown_xattrs(inode, attr); |
| 3131 | struct reiserfs_transaction_handle th; | 3157 | |
| 3132 | int jbegin_count = | 3158 | if (error) |
| 3133 | 2 * | 3159 | return error; |
| 3134 | (REISERFS_QUOTA_INIT_BLOCKS(inode->i_sb) + | 3160 | |
| 3135 | REISERFS_QUOTA_DEL_BLOCKS(inode->i_sb)) + | 3161 | /* (user+group)*(old+new) structure - we count quota info and , inode write (sb, inode) */ |
| 3136 | 2; | 3162 | error = journal_begin(&th, inode->i_sb, jbegin_count); |
| 3137 | 3163 | if (error) | |
| 3138 | /* (user+group)*(old+new) structure - we count quota info and , inode write (sb, inode) */ | 3164 | goto out; |
| 3139 | error = | 3165 | error = dquot_transfer(inode, attr); |
| 3140 | journal_begin(&th, inode->i_sb, | 3166 | if (error) { |
| 3141 | jbegin_count); | 3167 | journal_end(&th, inode->i_sb, jbegin_count); |
| 3142 | if (error) | 3168 | goto out; |
| 3143 | goto out; | ||
| 3144 | error = dquot_transfer(inode, attr); | ||
| 3145 | if (error) { | ||
| 3146 | journal_end(&th, inode->i_sb, | ||
| 3147 | jbegin_count); | ||
| 3148 | goto out; | ||
| 3149 | } | ||
| 3150 | /* Update corresponding info in inode so that everything is in | ||
| 3151 | * one transaction */ | ||
| 3152 | if (attr->ia_valid & ATTR_UID) | ||
| 3153 | inode->i_uid = attr->ia_uid; | ||
| 3154 | if (attr->ia_valid & ATTR_GID) | ||
| 3155 | inode->i_gid = attr->ia_gid; | ||
| 3156 | mark_inode_dirty(inode); | ||
| 3157 | error = | ||
| 3158 | journal_end(&th, inode->i_sb, jbegin_count); | ||
| 3159 | } | ||
| 3160 | } | ||
| 3161 | if (!error) { | ||
| 3162 | /* | ||
| 3163 | * Relax the lock here, as it might truncate the | ||
| 3164 | * inode pages and wait for inode pages locks. | ||
| 3165 | * To release such page lock, the owner needs the | ||
| 3166 | * reiserfs lock | ||
| 3167 | */ | ||
| 3168 | reiserfs_write_unlock_once(inode->i_sb, depth); | ||
| 3169 | error = inode_setattr(inode, attr); | ||
| 3170 | depth = reiserfs_write_lock_once(inode->i_sb); | ||
| 3171 | } | 3169 | } |
| 3170 | |||
| 3171 | /* Update corresponding info in inode so that everything is in | ||
| 3172 | * one transaction */ | ||
| 3173 | if (attr->ia_valid & ATTR_UID) | ||
| 3174 | inode->i_uid = attr->ia_uid; | ||
| 3175 | if (attr->ia_valid & ATTR_GID) | ||
| 3176 | inode->i_gid = attr->ia_gid; | ||
| 3177 | mark_inode_dirty(inode); | ||
| 3178 | error = journal_end(&th, inode->i_sb, jbegin_count); | ||
| 3179 | if (error) | ||
| 3180 | goto out; | ||
| 3181 | } | ||
| 3182 | |||
| 3183 | /* | ||
| 3184 | * Relax the lock here, as it might truncate the | ||
| 3185 | * inode pages and wait for inode pages locks. | ||
| 3186 | * To release such page lock, the owner needs the | ||
| 3187 | * reiserfs lock | ||
| 3188 | */ | ||
| 3189 | reiserfs_write_unlock_once(inode->i_sb, depth); | ||
| 3190 | if ((attr->ia_valid & ATTR_SIZE) && | ||
| 3191 | attr->ia_size != i_size_read(inode)) | ||
| 3192 | error = vmtruncate(inode, attr->ia_size); | ||
| 3193 | |||
| 3194 | if (!error) { | ||
| 3195 | setattr_copy(inode, attr); | ||
| 3196 | mark_inode_dirty(inode); | ||
| 3172 | } | 3197 | } |
| 3198 | depth = reiserfs_write_lock_once(inode->i_sb); | ||
| 3173 | 3199 | ||
| 3174 | if (!error && reiserfs_posixacl(inode->i_sb)) { | 3200 | if (!error && reiserfs_posixacl(inode->i_sb)) { |
| 3175 | if (attr->ia_valid & ATTR_MODE) | 3201 | if (attr->ia_valid & ATTR_MODE) |
diff --git a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c index 19fbc810e8e7..1ec952b1f036 100644 --- a/fs/reiserfs/journal.c +++ b/fs/reiserfs/journal.c | |||
| @@ -983,7 +983,6 @@ static int flush_older_commits(struct super_block *s, | |||
| 983 | 983 | ||
| 984 | static int reiserfs_async_progress_wait(struct super_block *s) | 984 | static int reiserfs_async_progress_wait(struct super_block *s) |
| 985 | { | 985 | { |
| 986 | DEFINE_WAIT(wait); | ||
| 987 | struct reiserfs_journal *j = SB_JOURNAL(s); | 986 | struct reiserfs_journal *j = SB_JOURNAL(s); |
| 988 | 987 | ||
| 989 | if (atomic_read(&j->j_async_throttle)) { | 988 | if (atomic_read(&j->j_async_throttle)) { |
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 9822fa15118b..e15ff612002d 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c | |||
| @@ -525,6 +525,8 @@ static struct inode *reiserfs_alloc_inode(struct super_block *sb) | |||
| 525 | kmem_cache_alloc(reiserfs_inode_cachep, GFP_KERNEL); | 525 | kmem_cache_alloc(reiserfs_inode_cachep, GFP_KERNEL); |
| 526 | if (!ei) | 526 | if (!ei) |
| 527 | return NULL; | 527 | return NULL; |
| 528 | atomic_set(&ei->openers, 0); | ||
| 529 | mutex_init(&ei->tailpack); | ||
| 528 | return &ei->vfs_inode; | 530 | return &ei->vfs_inode; |
| 529 | } | 531 | } |
| 530 | 532 | ||
| @@ -589,11 +591,6 @@ out: | |||
| 589 | reiserfs_write_unlock_once(inode->i_sb, lock_depth); | 591 | reiserfs_write_unlock_once(inode->i_sb, lock_depth); |
| 590 | } | 592 | } |
| 591 | 593 | ||
| 592 | static void reiserfs_clear_inode(struct inode *inode) | ||
| 593 | { | ||
| 594 | dquot_drop(inode); | ||
| 595 | } | ||
| 596 | |||
| 597 | #ifdef CONFIG_QUOTA | 594 | #ifdef CONFIG_QUOTA |
| 598 | static ssize_t reiserfs_quota_write(struct super_block *, int, const char *, | 595 | static ssize_t reiserfs_quota_write(struct super_block *, int, const char *, |
| 599 | size_t, loff_t); | 596 | size_t, loff_t); |
| @@ -606,8 +603,7 @@ static const struct super_operations reiserfs_sops = { | |||
| 606 | .destroy_inode = reiserfs_destroy_inode, | 603 | .destroy_inode = reiserfs_destroy_inode, |
| 607 | .write_inode = reiserfs_write_inode, | 604 | .write_inode = reiserfs_write_inode, |
| 608 | .dirty_inode = reiserfs_dirty_inode, | 605 | .dirty_inode = reiserfs_dirty_inode, |
| 609 | .clear_inode = reiserfs_clear_inode, | 606 | .evict_inode = reiserfs_evict_inode, |
| 610 | .delete_inode = reiserfs_delete_inode, | ||
| 611 | .put_super = reiserfs_put_super, | 607 | .put_super = reiserfs_put_super, |
| 612 | .write_super = reiserfs_write_super, | 608 | .write_super = reiserfs_write_super, |
| 613 | .sync_fs = reiserfs_sync_fs, | 609 | .sync_fs = reiserfs_sync_fs, |
diff --git a/fs/signalfd.c b/fs/signalfd.c index f329849ce3c0..1c5a6add779d 100644 --- a/fs/signalfd.c +++ b/fs/signalfd.c | |||
| @@ -88,6 +88,7 @@ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo, | |||
| 88 | err |= __put_user(kinfo->si_tid, &uinfo->ssi_tid); | 88 | err |= __put_user(kinfo->si_tid, &uinfo->ssi_tid); |
| 89 | err |= __put_user(kinfo->si_overrun, &uinfo->ssi_overrun); | 89 | err |= __put_user(kinfo->si_overrun, &uinfo->ssi_overrun); |
| 90 | err |= __put_user((long) kinfo->si_ptr, &uinfo->ssi_ptr); | 90 | err |= __put_user((long) kinfo->si_ptr, &uinfo->ssi_ptr); |
| 91 | err |= __put_user(kinfo->si_int, &uinfo->ssi_int); | ||
| 91 | break; | 92 | break; |
| 92 | case __SI_POLL: | 93 | case __SI_POLL: |
| 93 | err |= __put_user(kinfo->si_band, &uinfo->ssi_band); | 94 | err |= __put_user(kinfo->si_band, &uinfo->ssi_band); |
| @@ -111,6 +112,7 @@ static int signalfd_copyinfo(struct signalfd_siginfo __user *uinfo, | |||
| 111 | err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid); | 112 | err |= __put_user(kinfo->si_pid, &uinfo->ssi_pid); |
| 112 | err |= __put_user(kinfo->si_uid, &uinfo->ssi_uid); | 113 | err |= __put_user(kinfo->si_uid, &uinfo->ssi_uid); |
| 113 | err |= __put_user((long) kinfo->si_ptr, &uinfo->ssi_ptr); | 114 | err |= __put_user((long) kinfo->si_ptr, &uinfo->ssi_ptr); |
| 115 | err |= __put_user(kinfo->si_int, &uinfo->ssi_int); | ||
| 114 | break; | 116 | break; |
| 115 | default: | 117 | default: |
| 116 | /* | 118 | /* |
diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index 9551cb6f7fe4..450c91941988 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c | |||
| @@ -46,7 +46,7 @@ | |||
| 46 | 46 | ||
| 47 | #define SMB_TTL_DEFAULT 1000 | 47 | #define SMB_TTL_DEFAULT 1000 |
| 48 | 48 | ||
| 49 | static void smb_delete_inode(struct inode *); | 49 | static void smb_evict_inode(struct inode *); |
| 50 | static void smb_put_super(struct super_block *); | 50 | static void smb_put_super(struct super_block *); |
| 51 | static int smb_statfs(struct dentry *, struct kstatfs *); | 51 | static int smb_statfs(struct dentry *, struct kstatfs *); |
| 52 | static int smb_show_options(struct seq_file *, struct vfsmount *); | 52 | static int smb_show_options(struct seq_file *, struct vfsmount *); |
| @@ -102,7 +102,7 @@ static const struct super_operations smb_sops = | |||
| 102 | .alloc_inode = smb_alloc_inode, | 102 | .alloc_inode = smb_alloc_inode, |
| 103 | .destroy_inode = smb_destroy_inode, | 103 | .destroy_inode = smb_destroy_inode, |
| 104 | .drop_inode = generic_delete_inode, | 104 | .drop_inode = generic_delete_inode, |
| 105 | .delete_inode = smb_delete_inode, | 105 | .evict_inode = smb_evict_inode, |
| 106 | .put_super = smb_put_super, | 106 | .put_super = smb_put_super, |
| 107 | .statfs = smb_statfs, | 107 | .statfs = smb_statfs, |
| 108 | .show_options = smb_show_options, | 108 | .show_options = smb_show_options, |
| @@ -324,15 +324,15 @@ out: | |||
| 324 | * All blocking cleanup operations need to go here to avoid races. | 324 | * All blocking cleanup operations need to go here to avoid races. |
| 325 | */ | 325 | */ |
| 326 | static void | 326 | static void |
| 327 | smb_delete_inode(struct inode *ino) | 327 | smb_evict_inode(struct inode *ino) |
| 328 | { | 328 | { |
| 329 | DEBUG1("ino=%ld\n", ino->i_ino); | 329 | DEBUG1("ino=%ld\n", ino->i_ino); |
| 330 | truncate_inode_pages(&ino->i_data, 0); | 330 | truncate_inode_pages(&ino->i_data, 0); |
| 331 | end_writeback(ino); | ||
| 331 | lock_kernel(); | 332 | lock_kernel(); |
| 332 | if (smb_close(ino)) | 333 | if (smb_close(ino)) |
| 333 | PARANOIA("could not close inode %ld\n", ino->i_ino); | 334 | PARANOIA("could not close inode %ld\n", ino->i_ino); |
| 334 | unlock_kernel(); | 335 | unlock_kernel(); |
| 335 | clear_inode(ino); | ||
| 336 | } | 336 | } |
| 337 | 337 | ||
| 338 | static struct option opts[] = { | 338 | static struct option opts[] = { |
| @@ -714,9 +714,7 @@ smb_notify_change(struct dentry *dentry, struct iattr *attr) | |||
| 714 | error = server->ops->truncate(inode, attr->ia_size); | 714 | error = server->ops->truncate(inode, attr->ia_size); |
| 715 | if (error) | 715 | if (error) |
| 716 | goto out; | 716 | goto out; |
| 717 | error = simple_setsize(inode, attr->ia_size); | 717 | truncate_setsize(inode, attr->ia_size); |
| 718 | if (error) | ||
| 719 | goto out; | ||
| 720 | refresh = 1; | 718 | refresh = 1; |
| 721 | } | 719 | } |
| 722 | 720 | ||
diff --git a/fs/splice.c b/fs/splice.c index efdbfece9932..8f1dfaecc8f0 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
| @@ -399,17 +399,7 @@ __generic_file_splice_read(struct file *in, loff_t *ppos, | |||
| 399 | * If the page isn't uptodate, we may need to start io on it | 399 | * If the page isn't uptodate, we may need to start io on it |
| 400 | */ | 400 | */ |
| 401 | if (!PageUptodate(page)) { | 401 | if (!PageUptodate(page)) { |
| 402 | /* | 402 | lock_page(page); |
| 403 | * If in nonblock mode then dont block on waiting | ||
| 404 | * for an in-flight io page | ||
| 405 | */ | ||
| 406 | if (flags & SPLICE_F_NONBLOCK) { | ||
| 407 | if (!trylock_page(page)) { | ||
| 408 | error = -EAGAIN; | ||
| 409 | break; | ||
| 410 | } | ||
| 411 | } else | ||
| 412 | lock_page(page); | ||
| 413 | 403 | ||
| 414 | /* | 404 | /* |
| 415 | * Page was truncated, or invalidated by the | 405 | * Page was truncated, or invalidated by the |
| @@ -597,7 +587,6 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos, | |||
| 597 | struct page *pages[PIPE_DEF_BUFFERS]; | 587 | struct page *pages[PIPE_DEF_BUFFERS]; |
| 598 | struct partial_page partial[PIPE_DEF_BUFFERS]; | 588 | struct partial_page partial[PIPE_DEF_BUFFERS]; |
| 599 | struct iovec *vec, __vec[PIPE_DEF_BUFFERS]; | 589 | struct iovec *vec, __vec[PIPE_DEF_BUFFERS]; |
| 600 | pgoff_t index; | ||
| 601 | ssize_t res; | 590 | ssize_t res; |
| 602 | size_t this_len; | 591 | size_t this_len; |
| 603 | int error; | 592 | int error; |
| @@ -621,7 +610,6 @@ ssize_t default_file_splice_read(struct file *in, loff_t *ppos, | |||
| 621 | goto shrink_ret; | 610 | goto shrink_ret; |
| 622 | } | 611 | } |
| 623 | 612 | ||
| 624 | index = *ppos >> PAGE_CACHE_SHIFT; | ||
| 625 | offset = *ppos & ~PAGE_CACHE_MASK; | 613 | offset = *ppos & ~PAGE_CACHE_MASK; |
| 626 | nr_pages = (len + offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | 614 | nr_pages = (len + offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; |
| 627 | 615 | ||
diff --git a/fs/squashfs/Kconfig b/fs/squashfs/Kconfig index cc6ce8a84c21..e5f63da64d04 100644 --- a/fs/squashfs/Kconfig +++ b/fs/squashfs/Kconfig | |||
| @@ -5,13 +5,13 @@ config SQUASHFS | |||
| 5 | help | 5 | help |
| 6 | Saying Y here includes support for SquashFS 4.0 (a Compressed | 6 | Saying Y here includes support for SquashFS 4.0 (a Compressed |
| 7 | Read-Only File System). Squashfs is a highly compressed read-only | 7 | Read-Only File System). Squashfs is a highly compressed read-only |
| 8 | filesystem for Linux. It uses zlib compression to compress both | 8 | filesystem for Linux. It uses zlib/lzo compression to compress both |
| 9 | files, inodes and directories. Inodes in the system are very small | 9 | files, inodes and directories. Inodes in the system are very small |
| 10 | and all blocks are packed to minimise data overhead. Block sizes | 10 | and all blocks are packed to minimise data overhead. Block sizes |
| 11 | greater than 4K are supported up to a maximum of 1 Mbytes (default | 11 | greater than 4K are supported up to a maximum of 1 Mbytes (default |
| 12 | block size 128K). SquashFS 4.0 supports 64 bit filesystems and files | 12 | block size 128K). SquashFS 4.0 supports 64 bit filesystems and files |
| 13 | (larger than 4GB), full uid/gid information, hard links and | 13 | (larger than 4GB), full uid/gid information, hard links and |
| 14 | timestamps. | 14 | timestamps. |
| 15 | 15 | ||
| 16 | Squashfs is intended for general read-only filesystem use, for | 16 | Squashfs is intended for general read-only filesystem use, for |
| 17 | archival use (i.e. in cases where a .tar.gz file may be used), and in | 17 | archival use (i.e. in cases where a .tar.gz file may be used), and in |
| @@ -26,7 +26,7 @@ config SQUASHFS | |||
| 26 | 26 | ||
| 27 | If unsure, say N. | 27 | If unsure, say N. |
| 28 | 28 | ||
| 29 | config SQUASHFS_XATTRS | 29 | config SQUASHFS_XATTR |
| 30 | bool "Squashfs XATTR support" | 30 | bool "Squashfs XATTR support" |
| 31 | depends on SQUASHFS | 31 | depends on SQUASHFS |
| 32 | default n | 32 | default n |
| @@ -37,9 +37,24 @@ config SQUASHFS_XATTRS | |||
| 37 | 37 | ||
| 38 | If unsure, say N. | 38 | If unsure, say N. |
| 39 | 39 | ||
| 40 | config SQUASHFS_EMBEDDED | 40 | config SQUASHFS_LZO |
| 41 | bool "Include support for LZO compressed file systems" | ||
| 42 | depends on SQUASHFS | ||
| 43 | default n | ||
| 44 | select LZO_DECOMPRESS | ||
| 45 | help | ||
| 46 | Saying Y here includes support for reading Squashfs file systems | ||
| 47 | compressed with LZO compresssion. LZO compression is mainly | ||
| 48 | aimed at embedded systems with slower CPUs where the overheads | ||
| 49 | of zlib are too high. | ||
| 41 | 50 | ||
| 42 | bool "Additional option for memory-constrained systems" | 51 | LZO is not the standard compression used in Squashfs and so most |
| 52 | file systems will be readable without selecting this option. | ||
| 53 | |||
| 54 | If unsure, say N. | ||
| 55 | |||
| 56 | config SQUASHFS_EMBEDDED | ||
| 57 | bool "Additional option for memory-constrained systems" | ||
| 43 | depends on SQUASHFS | 58 | depends on SQUASHFS |
| 44 | default n | 59 | default n |
| 45 | help | 60 | help |
diff --git a/fs/squashfs/Makefile b/fs/squashfs/Makefile index 2cee3e9fa452..7672bac8d328 100644 --- a/fs/squashfs/Makefile +++ b/fs/squashfs/Makefile | |||
| @@ -5,5 +5,5 @@ | |||
| 5 | obj-$(CONFIG_SQUASHFS) += squashfs.o | 5 | obj-$(CONFIG_SQUASHFS) += squashfs.o |
| 6 | squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o | 6 | squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o |
| 7 | squashfs-y += namei.o super.o symlink.o zlib_wrapper.o decompressor.o | 7 | squashfs-y += namei.o super.o symlink.o zlib_wrapper.o decompressor.o |
| 8 | squashfs-$(CONFIG_SQUASHFS_XATTRS) += xattr.o xattr_id.o | 8 | squashfs-$(CONFIG_SQUASHFS_XATTR) += xattr.o xattr_id.o |
| 9 | 9 | squashfs-$(CONFIG_SQUASHFS_LZO) += lzo_wrapper.o | |
diff --git a/fs/squashfs/decompressor.c b/fs/squashfs/decompressor.c index 157478da6ac9..24af9ce9722f 100644 --- a/fs/squashfs/decompressor.c +++ b/fs/squashfs/decompressor.c | |||
| @@ -40,9 +40,11 @@ static const struct squashfs_decompressor squashfs_lzma_unsupported_comp_ops = { | |||
| 40 | NULL, NULL, NULL, LZMA_COMPRESSION, "lzma", 0 | 40 | NULL, NULL, NULL, LZMA_COMPRESSION, "lzma", 0 |
| 41 | }; | 41 | }; |
| 42 | 42 | ||
| 43 | #ifndef CONFIG_SQUASHFS_LZO | ||
| 43 | static const struct squashfs_decompressor squashfs_lzo_unsupported_comp_ops = { | 44 | static const struct squashfs_decompressor squashfs_lzo_unsupported_comp_ops = { |
| 44 | NULL, NULL, NULL, LZO_COMPRESSION, "lzo", 0 | 45 | NULL, NULL, NULL, LZO_COMPRESSION, "lzo", 0 |
| 45 | }; | 46 | }; |
| 47 | #endif | ||
| 46 | 48 | ||
| 47 | static const struct squashfs_decompressor squashfs_unknown_comp_ops = { | 49 | static const struct squashfs_decompressor squashfs_unknown_comp_ops = { |
| 48 | NULL, NULL, NULL, 0, "unknown", 0 | 50 | NULL, NULL, NULL, 0, "unknown", 0 |
| @@ -51,7 +53,11 @@ static const struct squashfs_decompressor squashfs_unknown_comp_ops = { | |||
| 51 | static const struct squashfs_decompressor *decompressor[] = { | 53 | static const struct squashfs_decompressor *decompressor[] = { |
| 52 | &squashfs_zlib_comp_ops, | 54 | &squashfs_zlib_comp_ops, |
| 53 | &squashfs_lzma_unsupported_comp_ops, | 55 | &squashfs_lzma_unsupported_comp_ops, |
| 56 | #ifdef CONFIG_SQUASHFS_LZO | ||
| 57 | &squashfs_lzo_comp_ops, | ||
| 58 | #else | ||
| 54 | &squashfs_lzo_unsupported_comp_ops, | 59 | &squashfs_lzo_unsupported_comp_ops, |
| 60 | #endif | ||
| 55 | &squashfs_unknown_comp_ops | 61 | &squashfs_unknown_comp_ops |
| 56 | }; | 62 | }; |
| 57 | 63 | ||
diff --git a/fs/squashfs/lzo_wrapper.c b/fs/squashfs/lzo_wrapper.c new file mode 100644 index 000000000000..5d87789bf1c1 --- /dev/null +++ b/fs/squashfs/lzo_wrapper.c | |||
| @@ -0,0 +1,136 @@ | |||
| 1 | /* | ||
| 2 | * Squashfs - a compressed read only filesystem for Linux | ||
| 3 | * | ||
| 4 | * Copyright (c) 2010 LG Electronics | ||
| 5 | * Chan Jeong <chan.jeong@lge.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License | ||
| 9 | * as published by the Free Software Foundation; either version 2, | ||
| 10 | * or (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
| 20 | * | ||
| 21 | * lzo_wrapper.c | ||
| 22 | */ | ||
| 23 | |||
| 24 | #include <linux/mutex.h> | ||
| 25 | #include <linux/buffer_head.h> | ||
| 26 | #include <linux/slab.h> | ||
| 27 | #include <linux/vmalloc.h> | ||
| 28 | #include <linux/lzo.h> | ||
| 29 | |||
| 30 | #include "squashfs_fs.h" | ||
| 31 | #include "squashfs_fs_sb.h" | ||
| 32 | #include "squashfs_fs_i.h" | ||
| 33 | #include "squashfs.h" | ||
| 34 | #include "decompressor.h" | ||
| 35 | |||
| 36 | struct squashfs_lzo { | ||
| 37 | void *input; | ||
| 38 | void *output; | ||
| 39 | }; | ||
| 40 | |||
| 41 | static void *lzo_init(struct squashfs_sb_info *msblk) | ||
| 42 | { | ||
| 43 | int block_size = max_t(int, msblk->block_size, SQUASHFS_METADATA_SIZE); | ||
| 44 | |||
| 45 | struct squashfs_lzo *stream = kzalloc(sizeof(*stream), GFP_KERNEL); | ||
| 46 | if (stream == NULL) | ||
| 47 | goto failed; | ||
| 48 | stream->input = vmalloc(block_size); | ||
| 49 | if (stream->input == NULL) | ||
| 50 | goto failed; | ||
| 51 | stream->output = vmalloc(block_size); | ||
| 52 | if (stream->output == NULL) | ||
| 53 | goto failed2; | ||
| 54 | |||
| 55 | return stream; | ||
| 56 | |||
| 57 | failed2: | ||
| 58 | vfree(stream->input); | ||
| 59 | failed: | ||
| 60 | ERROR("Failed to allocate lzo workspace\n"); | ||
| 61 | kfree(stream); | ||
| 62 | return NULL; | ||
| 63 | } | ||
| 64 | |||
| 65 | |||
| 66 | static void lzo_free(void *strm) | ||
| 67 | { | ||
| 68 | struct squashfs_lzo *stream = strm; | ||
| 69 | |||
| 70 | if (stream) { | ||
| 71 | vfree(stream->input); | ||
| 72 | vfree(stream->output); | ||
| 73 | } | ||
| 74 | kfree(stream); | ||
| 75 | } | ||
| 76 | |||
| 77 | |||
| 78 | static int lzo_uncompress(struct squashfs_sb_info *msblk, void **buffer, | ||
| 79 | struct buffer_head **bh, int b, int offset, int length, int srclength, | ||
| 80 | int pages) | ||
| 81 | { | ||
| 82 | struct squashfs_lzo *stream = msblk->stream; | ||
| 83 | void *buff = stream->input; | ||
| 84 | int avail, i, bytes = length, res; | ||
| 85 | size_t out_len = srclength; | ||
| 86 | |||
| 87 | mutex_lock(&msblk->read_data_mutex); | ||
| 88 | |||
| 89 | for (i = 0; i < b; i++) { | ||
| 90 | wait_on_buffer(bh[i]); | ||
| 91 | if (!buffer_uptodate(bh[i])) | ||
| 92 | goto block_release; | ||
| 93 | |||
| 94 | avail = min(bytes, msblk->devblksize - offset); | ||
| 95 | memcpy(buff, bh[i]->b_data + offset, avail); | ||
| 96 | buff += avail; | ||
| 97 | bytes -= avail; | ||
| 98 | offset = 0; | ||
| 99 | put_bh(bh[i]); | ||
| 100 | } | ||
| 101 | |||
| 102 | res = lzo1x_decompress_safe(stream->input, (size_t)length, | ||
| 103 | stream->output, &out_len); | ||
| 104 | if (res != LZO_E_OK) | ||
| 105 | goto failed; | ||
| 106 | |||
| 107 | res = bytes = (int)out_len; | ||
| 108 | for (i = 0, buff = stream->output; bytes && i < pages; i++) { | ||
| 109 | avail = min_t(int, bytes, PAGE_CACHE_SIZE); | ||
| 110 | memcpy(buffer[i], buff, avail); | ||
| 111 | buff += avail; | ||
| 112 | bytes -= avail; | ||
| 113 | } | ||
| 114 | |||
| 115 | mutex_unlock(&msblk->read_data_mutex); | ||
| 116 | return res; | ||
| 117 | |||
| 118 | block_release: | ||
| 119 | for (; i < b; i++) | ||
| 120 | put_bh(bh[i]); | ||
| 121 | |||
| 122 | failed: | ||
| 123 | mutex_unlock(&msblk->read_data_mutex); | ||
| 124 | |||
| 125 | ERROR("lzo decompression failed, data probably corrupt\n"); | ||
| 126 | return -EIO; | ||
| 127 | } | ||
| 128 | |||
| 129 | const struct squashfs_decompressor squashfs_lzo_comp_ops = { | ||
| 130 | .init = lzo_init, | ||
| 131 | .free = lzo_free, | ||
| 132 | .decompress = lzo_uncompress, | ||
| 133 | .id = LZO_COMPRESSION, | ||
| 134 | .name = "lzo", | ||
| 135 | .supported = 1 | ||
| 136 | }; | ||
diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h index 733a17c42945..5d45569d5f72 100644 --- a/fs/squashfs/squashfs.h +++ b/fs/squashfs/squashfs.h | |||
| @@ -104,3 +104,6 @@ extern const struct xattr_handler *squashfs_xattr_handlers[]; | |||
| 104 | 104 | ||
| 105 | /* zlib_wrapper.c */ | 105 | /* zlib_wrapper.c */ |
| 106 | extern const struct squashfs_decompressor squashfs_zlib_comp_ops; | 106 | extern const struct squashfs_decompressor squashfs_zlib_comp_ops; |
| 107 | |||
| 108 | /* lzo_wrapper.c */ | ||
| 109 | extern const struct squashfs_decompressor squashfs_lzo_comp_ops; | ||
diff --git a/fs/squashfs/squashfs_fs.h b/fs/squashfs/squashfs_fs.h index 8eabb808b78d..c5137fc9ab11 100644 --- a/fs/squashfs/squashfs_fs.h +++ b/fs/squashfs/squashfs_fs.h | |||
| @@ -274,7 +274,7 @@ struct squashfs_base_inode { | |||
| 274 | __le16 uid; | 274 | __le16 uid; |
| 275 | __le16 guid; | 275 | __le16 guid; |
| 276 | __le32 mtime; | 276 | __le32 mtime; |
| 277 | __le32 inode_number; | 277 | __le32 inode_number; |
| 278 | }; | 278 | }; |
| 279 | 279 | ||
| 280 | struct squashfs_ipc_inode { | 280 | struct squashfs_ipc_inode { |
| @@ -283,7 +283,7 @@ struct squashfs_ipc_inode { | |||
| 283 | __le16 uid; | 283 | __le16 uid; |
| 284 | __le16 guid; | 284 | __le16 guid; |
| 285 | __le32 mtime; | 285 | __le32 mtime; |
| 286 | __le32 inode_number; | 286 | __le32 inode_number; |
| 287 | __le32 nlink; | 287 | __le32 nlink; |
| 288 | }; | 288 | }; |
| 289 | 289 | ||
| @@ -293,7 +293,7 @@ struct squashfs_lipc_inode { | |||
| 293 | __le16 uid; | 293 | __le16 uid; |
| 294 | __le16 guid; | 294 | __le16 guid; |
| 295 | __le32 mtime; | 295 | __le32 mtime; |
| 296 | __le32 inode_number; | 296 | __le32 inode_number; |
| 297 | __le32 nlink; | 297 | __le32 nlink; |
| 298 | __le32 xattr; | 298 | __le32 xattr; |
| 299 | }; | 299 | }; |
| @@ -304,7 +304,7 @@ struct squashfs_dev_inode { | |||
| 304 | __le16 uid; | 304 | __le16 uid; |
| 305 | __le16 guid; | 305 | __le16 guid; |
| 306 | __le32 mtime; | 306 | __le32 mtime; |
| 307 | __le32 inode_number; | 307 | __le32 inode_number; |
| 308 | __le32 nlink; | 308 | __le32 nlink; |
| 309 | __le32 rdev; | 309 | __le32 rdev; |
| 310 | }; | 310 | }; |
| @@ -315,7 +315,7 @@ struct squashfs_ldev_inode { | |||
| 315 | __le16 uid; | 315 | __le16 uid; |
| 316 | __le16 guid; | 316 | __le16 guid; |
| 317 | __le32 mtime; | 317 | __le32 mtime; |
| 318 | __le32 inode_number; | 318 | __le32 inode_number; |
| 319 | __le32 nlink; | 319 | __le32 nlink; |
| 320 | __le32 rdev; | 320 | __le32 rdev; |
| 321 | __le32 xattr; | 321 | __le32 xattr; |
| @@ -327,7 +327,7 @@ struct squashfs_symlink_inode { | |||
| 327 | __le16 uid; | 327 | __le16 uid; |
| 328 | __le16 guid; | 328 | __le16 guid; |
| 329 | __le32 mtime; | 329 | __le32 mtime; |
| 330 | __le32 inode_number; | 330 | __le32 inode_number; |
| 331 | __le32 nlink; | 331 | __le32 nlink; |
| 332 | __le32 symlink_size; | 332 | __le32 symlink_size; |
| 333 | char symlink[0]; | 333 | char symlink[0]; |
| @@ -339,7 +339,7 @@ struct squashfs_reg_inode { | |||
| 339 | __le16 uid; | 339 | __le16 uid; |
| 340 | __le16 guid; | 340 | __le16 guid; |
| 341 | __le32 mtime; | 341 | __le32 mtime; |
| 342 | __le32 inode_number; | 342 | __le32 inode_number; |
| 343 | __le32 start_block; | 343 | __le32 start_block; |
| 344 | __le32 fragment; | 344 | __le32 fragment; |
| 345 | __le32 offset; | 345 | __le32 offset; |
| @@ -353,7 +353,7 @@ struct squashfs_lreg_inode { | |||
| 353 | __le16 uid; | 353 | __le16 uid; |
| 354 | __le16 guid; | 354 | __le16 guid; |
| 355 | __le32 mtime; | 355 | __le32 mtime; |
| 356 | __le32 inode_number; | 356 | __le32 inode_number; |
| 357 | __le64 start_block; | 357 | __le64 start_block; |
| 358 | __le64 file_size; | 358 | __le64 file_size; |
| 359 | __le64 sparse; | 359 | __le64 sparse; |
| @@ -370,7 +370,7 @@ struct squashfs_dir_inode { | |||
| 370 | __le16 uid; | 370 | __le16 uid; |
| 371 | __le16 guid; | 371 | __le16 guid; |
| 372 | __le32 mtime; | 372 | __le32 mtime; |
| 373 | __le32 inode_number; | 373 | __le32 inode_number; |
| 374 | __le32 start_block; | 374 | __le32 start_block; |
| 375 | __le32 nlink; | 375 | __le32 nlink; |
| 376 | __le16 file_size; | 376 | __le16 file_size; |
| @@ -384,7 +384,7 @@ struct squashfs_ldir_inode { | |||
| 384 | __le16 uid; | 384 | __le16 uid; |
| 385 | __le16 guid; | 385 | __le16 guid; |
| 386 | __le32 mtime; | 386 | __le32 mtime; |
| 387 | __le32 inode_number; | 387 | __le32 inode_number; |
| 388 | __le32 nlink; | 388 | __le32 nlink; |
| 389 | __le32 file_size; | 389 | __le32 file_size; |
| 390 | __le32 start_block; | 390 | __le32 start_block; |
diff --git a/fs/squashfs/xattr.c b/fs/squashfs/xattr.c index c7655e8b31cd..652b8541f9c6 100644 --- a/fs/squashfs/xattr.c +++ b/fs/squashfs/xattr.c | |||
| @@ -18,7 +18,7 @@ | |||
| 18 | * along with this program; if not, write to the Free Software | 18 | * along with this program; if not, write to the Free Software |
| 19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| 20 | * | 20 | * |
| 21 | * xattr_id.c | 21 | * xattr.c |
| 22 | */ | 22 | */ |
| 23 | 23 | ||
| 24 | #include <linux/init.h> | 24 | #include <linux/init.h> |
| @@ -295,7 +295,7 @@ static const struct xattr_handler squashfs_xattr_security_handler = { | |||
| 295 | .get = squashfs_security_get | 295 | .get = squashfs_security_get |
| 296 | }; | 296 | }; |
| 297 | 297 | ||
| 298 | static inline const struct xattr_handler *squashfs_xattr_handler(int type) | 298 | static const struct xattr_handler *squashfs_xattr_handler(int type) |
| 299 | { | 299 | { |
| 300 | if (type & ~(SQUASHFS_XATTR_PREFIX_MASK | SQUASHFS_XATTR_VALUE_OOL)) | 300 | if (type & ~(SQUASHFS_XATTR_PREFIX_MASK | SQUASHFS_XATTR_VALUE_OOL)) |
| 301 | /* ignore unrecognised type */ | 301 | /* ignore unrecognised type */ |
diff --git a/fs/squashfs/xattr.h b/fs/squashfs/xattr.h index 9da071ae181c..49fe0d719fbf 100644 --- a/fs/squashfs/xattr.h +++ b/fs/squashfs/xattr.h | |||
| @@ -21,7 +21,7 @@ | |||
| 21 | * xattr.h | 21 | * xattr.h |
| 22 | */ | 22 | */ |
| 23 | 23 | ||
| 24 | #ifdef CONFIG_SQUASHFS_XATTRS | 24 | #ifdef CONFIG_SQUASHFS_XATTR |
| 25 | extern __le64 *squashfs_read_xattr_id_table(struct super_block *, u64, | 25 | extern __le64 *squashfs_read_xattr_id_table(struct super_block *, u64, |
| 26 | u64 *, int *); | 26 | u64 *, int *); |
| 27 | extern int squashfs_xattr_lookup(struct super_block *, unsigned int, int *, | 27 | extern int squashfs_xattr_lookup(struct super_block *, unsigned int, int *, |
| @@ -68,7 +68,8 @@ int vfs_fstat(unsigned int fd, struct kstat *stat) | |||
| 68 | } | 68 | } |
| 69 | EXPORT_SYMBOL(vfs_fstat); | 69 | EXPORT_SYMBOL(vfs_fstat); |
| 70 | 70 | ||
| 71 | int vfs_fstatat(int dfd, char __user *filename, struct kstat *stat, int flag) | 71 | int vfs_fstatat(int dfd, const char __user *filename, struct kstat *stat, |
| 72 | int flag) | ||
| 72 | { | 73 | { |
| 73 | struct path path; | 74 | struct path path; |
| 74 | int error = -EINVAL; | 75 | int error = -EINVAL; |
| @@ -91,13 +92,13 @@ out: | |||
| 91 | } | 92 | } |
| 92 | EXPORT_SYMBOL(vfs_fstatat); | 93 | EXPORT_SYMBOL(vfs_fstatat); |
| 93 | 94 | ||
| 94 | int vfs_stat(char __user *name, struct kstat *stat) | 95 | int vfs_stat(const char __user *name, struct kstat *stat) |
| 95 | { | 96 | { |
| 96 | return vfs_fstatat(AT_FDCWD, name, stat, 0); | 97 | return vfs_fstatat(AT_FDCWD, name, stat, 0); |
| 97 | } | 98 | } |
| 98 | EXPORT_SYMBOL(vfs_stat); | 99 | EXPORT_SYMBOL(vfs_stat); |
| 99 | 100 | ||
| 100 | int vfs_lstat(char __user *name, struct kstat *stat) | 101 | int vfs_lstat(const char __user *name, struct kstat *stat) |
| 101 | { | 102 | { |
| 102 | return vfs_fstatat(AT_FDCWD, name, stat, AT_SYMLINK_NOFOLLOW); | 103 | return vfs_fstatat(AT_FDCWD, name, stat, AT_SYMLINK_NOFOLLOW); |
| 103 | } | 104 | } |
| @@ -147,7 +148,8 @@ static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat __user * sta | |||
| 147 | return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; | 148 | return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; |
| 148 | } | 149 | } |
| 149 | 150 | ||
| 150 | SYSCALL_DEFINE2(stat, char __user *, filename, struct __old_kernel_stat __user *, statbuf) | 151 | SYSCALL_DEFINE2(stat, const char __user *, filename, |
| 152 | struct __old_kernel_stat __user *, statbuf) | ||
| 151 | { | 153 | { |
| 152 | struct kstat stat; | 154 | struct kstat stat; |
| 153 | int error; | 155 | int error; |
| @@ -159,7 +161,8 @@ SYSCALL_DEFINE2(stat, char __user *, filename, struct __old_kernel_stat __user * | |||
| 159 | return cp_old_stat(&stat, statbuf); | 161 | return cp_old_stat(&stat, statbuf); |
| 160 | } | 162 | } |
| 161 | 163 | ||
| 162 | SYSCALL_DEFINE2(lstat, char __user *, filename, struct __old_kernel_stat __user *, statbuf) | 164 | SYSCALL_DEFINE2(lstat, const char __user *, filename, |
| 165 | struct __old_kernel_stat __user *, statbuf) | ||
| 163 | { | 166 | { |
| 164 | struct kstat stat; | 167 | struct kstat stat; |
| 165 | int error; | 168 | int error; |
| @@ -234,7 +237,8 @@ static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf) | |||
| 234 | return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; | 237 | return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; |
| 235 | } | 238 | } |
| 236 | 239 | ||
| 237 | SYSCALL_DEFINE2(newstat, char __user *, filename, struct stat __user *, statbuf) | 240 | SYSCALL_DEFINE2(newstat, const char __user *, filename, |
| 241 | struct stat __user *, statbuf) | ||
| 238 | { | 242 | { |
| 239 | struct kstat stat; | 243 | struct kstat stat; |
| 240 | int error = vfs_stat(filename, &stat); | 244 | int error = vfs_stat(filename, &stat); |
| @@ -244,7 +248,8 @@ SYSCALL_DEFINE2(newstat, char __user *, filename, struct stat __user *, statbuf) | |||
| 244 | return cp_new_stat(&stat, statbuf); | 248 | return cp_new_stat(&stat, statbuf); |
| 245 | } | 249 | } |
| 246 | 250 | ||
| 247 | SYSCALL_DEFINE2(newlstat, char __user *, filename, struct stat __user *, statbuf) | 251 | SYSCALL_DEFINE2(newlstat, const char __user *, filename, |
| 252 | struct stat __user *, statbuf) | ||
| 248 | { | 253 | { |
| 249 | struct kstat stat; | 254 | struct kstat stat; |
| 250 | int error; | 255 | int error; |
| @@ -257,7 +262,7 @@ SYSCALL_DEFINE2(newlstat, char __user *, filename, struct stat __user *, statbuf | |||
| 257 | } | 262 | } |
| 258 | 263 | ||
| 259 | #if !defined(__ARCH_WANT_STAT64) || defined(__ARCH_WANT_SYS_NEWFSTATAT) | 264 | #if !defined(__ARCH_WANT_STAT64) || defined(__ARCH_WANT_SYS_NEWFSTATAT) |
| 260 | SYSCALL_DEFINE4(newfstatat, int, dfd, char __user *, filename, | 265 | SYSCALL_DEFINE4(newfstatat, int, dfd, const char __user *, filename, |
| 261 | struct stat __user *, statbuf, int, flag) | 266 | struct stat __user *, statbuf, int, flag) |
| 262 | { | 267 | { |
| 263 | struct kstat stat; | 268 | struct kstat stat; |
| @@ -355,7 +360,8 @@ static long cp_new_stat64(struct kstat *stat, struct stat64 __user *statbuf) | |||
| 355 | return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; | 360 | return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0; |
| 356 | } | 361 | } |
| 357 | 362 | ||
| 358 | SYSCALL_DEFINE2(stat64, char __user *, filename, struct stat64 __user *, statbuf) | 363 | SYSCALL_DEFINE2(stat64, const char __user *, filename, |
| 364 | struct stat64 __user *, statbuf) | ||
| 359 | { | 365 | { |
| 360 | struct kstat stat; | 366 | struct kstat stat; |
| 361 | int error = vfs_stat(filename, &stat); | 367 | int error = vfs_stat(filename, &stat); |
| @@ -366,7 +372,8 @@ SYSCALL_DEFINE2(stat64, char __user *, filename, struct stat64 __user *, statbuf | |||
| 366 | return error; | 372 | return error; |
| 367 | } | 373 | } |
| 368 | 374 | ||
| 369 | SYSCALL_DEFINE2(lstat64, char __user *, filename, struct stat64 __user *, statbuf) | 375 | SYSCALL_DEFINE2(lstat64, const char __user *, filename, |
| 376 | struct stat64 __user *, statbuf) | ||
| 370 | { | 377 | { |
| 371 | struct kstat stat; | 378 | struct kstat stat; |
| 372 | int error = vfs_lstat(filename, &stat); | 379 | int error = vfs_lstat(filename, &stat); |
| @@ -388,7 +395,7 @@ SYSCALL_DEFINE2(fstat64, unsigned long, fd, struct stat64 __user *, statbuf) | |||
| 388 | return error; | 395 | return error; |
| 389 | } | 396 | } |
| 390 | 397 | ||
| 391 | SYSCALL_DEFINE4(fstatat64, int, dfd, char __user *, filename, | 398 | SYSCALL_DEFINE4(fstatat64, int, dfd, const char __user *, filename, |
| 392 | struct stat64 __user *, statbuf, int, flag) | 399 | struct stat64 __user *, statbuf, int, flag) |
| 393 | { | 400 | { |
| 394 | struct kstat stat; | 401 | struct kstat stat; |
diff --git a/fs/statfs.c b/fs/statfs.c index 4ef021f3b612..30ea8c8a996b 100644 --- a/fs/statfs.c +++ b/fs/statfs.c | |||
| @@ -2,38 +2,83 @@ | |||
| 2 | #include <linux/module.h> | 2 | #include <linux/module.h> |
| 3 | #include <linux/fs.h> | 3 | #include <linux/fs.h> |
| 4 | #include <linux/file.h> | 4 | #include <linux/file.h> |
| 5 | #include <linux/mount.h> | ||
| 5 | #include <linux/namei.h> | 6 | #include <linux/namei.h> |
| 6 | #include <linux/statfs.h> | 7 | #include <linux/statfs.h> |
| 7 | #include <linux/security.h> | 8 | #include <linux/security.h> |
| 8 | #include <linux/uaccess.h> | 9 | #include <linux/uaccess.h> |
| 9 | 10 | ||
| 10 | int vfs_statfs(struct dentry *dentry, struct kstatfs *buf) | 11 | static int flags_by_mnt(int mnt_flags) |
| 11 | { | 12 | { |
| 12 | int retval = -ENODEV; | 13 | int flags = 0; |
| 13 | 14 | ||
| 14 | if (dentry) { | 15 | if (mnt_flags & MNT_READONLY) |
| 15 | retval = -ENOSYS; | 16 | flags |= ST_RDONLY; |
| 16 | if (dentry->d_sb->s_op->statfs) { | 17 | if (mnt_flags & MNT_NOSUID) |
| 17 | memset(buf, 0, sizeof(*buf)); | 18 | flags |= ST_NOSUID; |
| 18 | retval = security_sb_statfs(dentry); | 19 | if (mnt_flags & MNT_NODEV) |
| 19 | if (retval) | 20 | flags |= ST_NODEV; |
| 20 | return retval; | 21 | if (mnt_flags & MNT_NOEXEC) |
| 21 | retval = dentry->d_sb->s_op->statfs(dentry, buf); | 22 | flags |= ST_NOEXEC; |
| 22 | if (retval == 0 && buf->f_frsize == 0) | 23 | if (mnt_flags & MNT_NOATIME) |
| 23 | buf->f_frsize = buf->f_bsize; | 24 | flags |= ST_NOATIME; |
| 24 | } | 25 | if (mnt_flags & MNT_NODIRATIME) |
| 25 | } | 26 | flags |= ST_NODIRATIME; |
| 27 | if (mnt_flags & MNT_RELATIME) | ||
| 28 | flags |= ST_RELATIME; | ||
| 29 | return flags; | ||
| 30 | } | ||
| 31 | |||
| 32 | static int flags_by_sb(int s_flags) | ||
| 33 | { | ||
| 34 | int flags = 0; | ||
| 35 | if (s_flags & MS_SYNCHRONOUS) | ||
| 36 | flags |= ST_SYNCHRONOUS; | ||
| 37 | if (s_flags & MS_MANDLOCK) | ||
| 38 | flags |= ST_MANDLOCK; | ||
| 39 | return flags; | ||
| 40 | } | ||
| 41 | |||
| 42 | static int calculate_f_flags(struct vfsmount *mnt) | ||
| 43 | { | ||
| 44 | return ST_VALID | flags_by_mnt(mnt->mnt_flags) | | ||
| 45 | flags_by_sb(mnt->mnt_sb->s_flags); | ||
| 46 | } | ||
| 47 | |||
| 48 | int statfs_by_dentry(struct dentry *dentry, struct kstatfs *buf) | ||
| 49 | { | ||
| 50 | int retval; | ||
| 51 | |||
| 52 | if (!dentry->d_sb->s_op->statfs) | ||
| 53 | return -ENOSYS; | ||
| 54 | |||
| 55 | memset(buf, 0, sizeof(*buf)); | ||
| 56 | retval = security_sb_statfs(dentry); | ||
| 57 | if (retval) | ||
| 58 | return retval; | ||
| 59 | retval = dentry->d_sb->s_op->statfs(dentry, buf); | ||
| 60 | if (retval == 0 && buf->f_frsize == 0) | ||
| 61 | buf->f_frsize = buf->f_bsize; | ||
| 26 | return retval; | 62 | return retval; |
| 27 | } | 63 | } |
| 28 | 64 | ||
| 65 | int vfs_statfs(struct path *path, struct kstatfs *buf) | ||
| 66 | { | ||
| 67 | int error; | ||
| 68 | |||
| 69 | error = statfs_by_dentry(path->dentry, buf); | ||
| 70 | if (!error) | ||
| 71 | buf->f_flags = calculate_f_flags(path->mnt); | ||
| 72 | return error; | ||
| 73 | } | ||
| 29 | EXPORT_SYMBOL(vfs_statfs); | 74 | EXPORT_SYMBOL(vfs_statfs); |
| 30 | 75 | ||
| 31 | static int vfs_statfs_native(struct dentry *dentry, struct statfs *buf) | 76 | static int do_statfs_native(struct path *path, struct statfs *buf) |
| 32 | { | 77 | { |
| 33 | struct kstatfs st; | 78 | struct kstatfs st; |
| 34 | int retval; | 79 | int retval; |
| 35 | 80 | ||
| 36 | retval = vfs_statfs(dentry, &st); | 81 | retval = vfs_statfs(path, &st); |
| 37 | if (retval) | 82 | if (retval) |
| 38 | return retval; | 83 | return retval; |
| 39 | 84 | ||
| @@ -67,17 +112,18 @@ static int vfs_statfs_native(struct dentry *dentry, struct statfs *buf) | |||
| 67 | buf->f_fsid = st.f_fsid; | 112 | buf->f_fsid = st.f_fsid; |
| 68 | buf->f_namelen = st.f_namelen; | 113 | buf->f_namelen = st.f_namelen; |
| 69 | buf->f_frsize = st.f_frsize; | 114 | buf->f_frsize = st.f_frsize; |
| 115 | buf->f_flags = st.f_flags; | ||
| 70 | memset(buf->f_spare, 0, sizeof(buf->f_spare)); | 116 | memset(buf->f_spare, 0, sizeof(buf->f_spare)); |
| 71 | } | 117 | } |
| 72 | return 0; | 118 | return 0; |
| 73 | } | 119 | } |
| 74 | 120 | ||
| 75 | static int vfs_statfs64(struct dentry *dentry, struct statfs64 *buf) | 121 | static int do_statfs64(struct path *path, struct statfs64 *buf) |
| 76 | { | 122 | { |
| 77 | struct kstatfs st; | 123 | struct kstatfs st; |
| 78 | int retval; | 124 | int retval; |
| 79 | 125 | ||
| 80 | retval = vfs_statfs(dentry, &st); | 126 | retval = vfs_statfs(path, &st); |
| 81 | if (retval) | 127 | if (retval) |
| 82 | return retval; | 128 | return retval; |
| 83 | 129 | ||
| @@ -94,6 +140,7 @@ static int vfs_statfs64(struct dentry *dentry, struct statfs64 *buf) | |||
| 94 | buf->f_fsid = st.f_fsid; | 140 | buf->f_fsid = st.f_fsid; |
| 95 | buf->f_namelen = st.f_namelen; | 141 | buf->f_namelen = st.f_namelen; |
| 96 | buf->f_frsize = st.f_frsize; | 142 | buf->f_frsize = st.f_frsize; |
| 143 | buf->f_flags = st.f_flags; | ||
| 97 | memset(buf->f_spare, 0, sizeof(buf->f_spare)); | 144 | memset(buf->f_spare, 0, sizeof(buf->f_spare)); |
| 98 | } | 145 | } |
| 99 | return 0; | 146 | return 0; |
| @@ -107,7 +154,7 @@ SYSCALL_DEFINE2(statfs, const char __user *, pathname, struct statfs __user *, b | |||
| 107 | error = user_path(pathname, &path); | 154 | error = user_path(pathname, &path); |
| 108 | if (!error) { | 155 | if (!error) { |
| 109 | struct statfs tmp; | 156 | struct statfs tmp; |
| 110 | error = vfs_statfs_native(path.dentry, &tmp); | 157 | error = do_statfs_native(&path, &tmp); |
| 111 | if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) | 158 | if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) |
| 112 | error = -EFAULT; | 159 | error = -EFAULT; |
| 113 | path_put(&path); | 160 | path_put(&path); |
| @@ -125,7 +172,7 @@ SYSCALL_DEFINE3(statfs64, const char __user *, pathname, size_t, sz, struct stat | |||
| 125 | error = user_path(pathname, &path); | 172 | error = user_path(pathname, &path); |
| 126 | if (!error) { | 173 | if (!error) { |
| 127 | struct statfs64 tmp; | 174 | struct statfs64 tmp; |
| 128 | error = vfs_statfs64(path.dentry, &tmp); | 175 | error = do_statfs64(&path, &tmp); |
| 129 | if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) | 176 | if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) |
| 130 | error = -EFAULT; | 177 | error = -EFAULT; |
| 131 | path_put(&path); | 178 | path_put(&path); |
| @@ -143,7 +190,7 @@ SYSCALL_DEFINE2(fstatfs, unsigned int, fd, struct statfs __user *, buf) | |||
| 143 | file = fget(fd); | 190 | file = fget(fd); |
| 144 | if (!file) | 191 | if (!file) |
| 145 | goto out; | 192 | goto out; |
| 146 | error = vfs_statfs_native(file->f_path.dentry, &tmp); | 193 | error = do_statfs_native(&file->f_path, &tmp); |
| 147 | if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) | 194 | if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) |
| 148 | error = -EFAULT; | 195 | error = -EFAULT; |
| 149 | fput(file); | 196 | fput(file); |
| @@ -164,7 +211,7 @@ SYSCALL_DEFINE3(fstatfs64, unsigned int, fd, size_t, sz, struct statfs64 __user | |||
| 164 | file = fget(fd); | 211 | file = fget(fd); |
| 165 | if (!file) | 212 | if (!file) |
| 166 | goto out; | 213 | goto out; |
| 167 | error = vfs_statfs64(file->f_path.dentry, &tmp); | 214 | error = do_statfs64(&file->f_path, &tmp); |
| 168 | if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) | 215 | if (!error && copy_to_user(buf, &tmp, sizeof(tmp))) |
| 169 | error = -EFAULT; | 216 | error = -EFAULT; |
| 170 | fput(file); | 217 | fput(file); |
| @@ -183,7 +230,7 @@ SYSCALL_DEFINE2(ustat, unsigned, dev, struct ustat __user *, ubuf) | |||
| 183 | if (!s) | 230 | if (!s) |
| 184 | return -EINVAL; | 231 | return -EINVAL; |
| 185 | 232 | ||
| 186 | err = vfs_statfs(s->s_root, &sbuf); | 233 | err = statfs_by_dentry(s->s_root, &sbuf); |
| 187 | drop_super(s); | 234 | drop_super(s); |
| 188 | if (err) | 235 | if (err) |
| 189 | return err; | 236 | return err; |
diff --git a/fs/super.c b/fs/super.c index 938119ab8dcb..9674ab2c8718 100644 --- a/fs/super.c +++ b/fs/super.c | |||
| @@ -305,8 +305,13 @@ retry: | |||
| 305 | if (s) { | 305 | if (s) { |
| 306 | up_write(&s->s_umount); | 306 | up_write(&s->s_umount); |
| 307 | destroy_super(s); | 307 | destroy_super(s); |
| 308 | s = NULL; | ||
| 308 | } | 309 | } |
| 309 | down_write(&old->s_umount); | 310 | down_write(&old->s_umount); |
| 311 | if (unlikely(!(old->s_flags & MS_BORN))) { | ||
| 312 | deactivate_locked_super(old); | ||
| 313 | goto retry; | ||
| 314 | } | ||
| 310 | return old; | 315 | return old; |
| 311 | } | 316 | } |
| 312 | } | 317 | } |
| @@ -358,10 +363,10 @@ EXPORT_SYMBOL(drop_super); | |||
| 358 | */ | 363 | */ |
| 359 | void sync_supers(void) | 364 | void sync_supers(void) |
| 360 | { | 365 | { |
| 361 | struct super_block *sb, *n; | 366 | struct super_block *sb, *p = NULL; |
| 362 | 367 | ||
| 363 | spin_lock(&sb_lock); | 368 | spin_lock(&sb_lock); |
| 364 | list_for_each_entry_safe(sb, n, &super_blocks, s_list) { | 369 | list_for_each_entry(sb, &super_blocks, s_list) { |
| 365 | if (list_empty(&sb->s_instances)) | 370 | if (list_empty(&sb->s_instances)) |
| 366 | continue; | 371 | continue; |
| 367 | if (sb->s_op->write_super && sb->s_dirt) { | 372 | if (sb->s_op->write_super && sb->s_dirt) { |
| @@ -374,11 +379,13 @@ void sync_supers(void) | |||
| 374 | up_read(&sb->s_umount); | 379 | up_read(&sb->s_umount); |
| 375 | 380 | ||
| 376 | spin_lock(&sb_lock); | 381 | spin_lock(&sb_lock); |
| 377 | /* lock was dropped, must reset next */ | 382 | if (p) |
| 378 | list_safe_reset_next(sb, n, s_list); | 383 | __put_super(p); |
| 379 | __put_super(sb); | 384 | p = sb; |
| 380 | } | 385 | } |
| 381 | } | 386 | } |
| 387 | if (p) | ||
| 388 | __put_super(p); | ||
| 382 | spin_unlock(&sb_lock); | 389 | spin_unlock(&sb_lock); |
| 383 | } | 390 | } |
| 384 | 391 | ||
| @@ -392,10 +399,10 @@ void sync_supers(void) | |||
| 392 | */ | 399 | */ |
| 393 | void iterate_supers(void (*f)(struct super_block *, void *), void *arg) | 400 | void iterate_supers(void (*f)(struct super_block *, void *), void *arg) |
| 394 | { | 401 | { |
| 395 | struct super_block *sb, *n; | 402 | struct super_block *sb, *p = NULL; |
| 396 | 403 | ||
| 397 | spin_lock(&sb_lock); | 404 | spin_lock(&sb_lock); |
| 398 | list_for_each_entry_safe(sb, n, &super_blocks, s_list) { | 405 | list_for_each_entry(sb, &super_blocks, s_list) { |
| 399 | if (list_empty(&sb->s_instances)) | 406 | if (list_empty(&sb->s_instances)) |
| 400 | continue; | 407 | continue; |
| 401 | sb->s_count++; | 408 | sb->s_count++; |
| @@ -407,10 +414,12 @@ void iterate_supers(void (*f)(struct super_block *, void *), void *arg) | |||
| 407 | up_read(&sb->s_umount); | 414 | up_read(&sb->s_umount); |
| 408 | 415 | ||
| 409 | spin_lock(&sb_lock); | 416 | spin_lock(&sb_lock); |
| 410 | /* lock was dropped, must reset next */ | 417 | if (p) |
| 411 | list_safe_reset_next(sb, n, s_list); | 418 | __put_super(p); |
| 412 | __put_super(sb); | 419 | p = sb; |
| 413 | } | 420 | } |
| 421 | if (p) | ||
| 422 | __put_super(p); | ||
| 414 | spin_unlock(&sb_lock); | 423 | spin_unlock(&sb_lock); |
| 415 | } | 424 | } |
| 416 | 425 | ||
| @@ -572,10 +581,10 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force) | |||
| 572 | 581 | ||
| 573 | static void do_emergency_remount(struct work_struct *work) | 582 | static void do_emergency_remount(struct work_struct *work) |
| 574 | { | 583 | { |
| 575 | struct super_block *sb, *n; | 584 | struct super_block *sb, *p = NULL; |
| 576 | 585 | ||
| 577 | spin_lock(&sb_lock); | 586 | spin_lock(&sb_lock); |
| 578 | list_for_each_entry_safe(sb, n, &super_blocks, s_list) { | 587 | list_for_each_entry(sb, &super_blocks, s_list) { |
| 579 | if (list_empty(&sb->s_instances)) | 588 | if (list_empty(&sb->s_instances)) |
| 580 | continue; | 589 | continue; |
| 581 | sb->s_count++; | 590 | sb->s_count++; |
| @@ -589,10 +598,12 @@ static void do_emergency_remount(struct work_struct *work) | |||
| 589 | } | 598 | } |
| 590 | up_write(&sb->s_umount); | 599 | up_write(&sb->s_umount); |
| 591 | spin_lock(&sb_lock); | 600 | spin_lock(&sb_lock); |
| 592 | /* lock was dropped, must reset next */ | 601 | if (p) |
| 593 | list_safe_reset_next(sb, n, s_list); | 602 | __put_super(p); |
| 594 | __put_super(sb); | 603 | p = sb; |
| 595 | } | 604 | } |
| 605 | if (p) | ||
| 606 | __put_super(p); | ||
| 596 | spin_unlock(&sb_lock); | 607 | spin_unlock(&sb_lock); |
| 597 | kfree(work); | 608 | kfree(work); |
| 598 | printk("Emergency Remount complete\n"); | 609 | printk("Emergency Remount complete\n"); |
| @@ -773,7 +784,16 @@ int get_sb_bdev(struct file_system_type *fs_type, | |||
| 773 | goto error_bdev; | 784 | goto error_bdev; |
| 774 | } | 785 | } |
| 775 | 786 | ||
| 787 | /* | ||
| 788 | * s_umount nests inside bd_mutex during | ||
| 789 | * __invalidate_device(). close_bdev_exclusive() | ||
| 790 | * acquires bd_mutex and can't be called under | ||
| 791 | * s_umount. Drop s_umount temporarily. This is safe | ||
| 792 | * as we're holding an active reference. | ||
| 793 | */ | ||
| 794 | up_write(&s->s_umount); | ||
| 776 | close_bdev_exclusive(bdev, mode); | 795 | close_bdev_exclusive(bdev, mode); |
| 796 | down_write(&s->s_umount); | ||
| 777 | } else { | 797 | } else { |
| 778 | char b[BDEVNAME_SIZE]; | 798 | char b[BDEVNAME_SIZE]; |
| 779 | 799 | ||
| @@ -909,6 +929,7 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void | |||
| 909 | goto out_free_secdata; | 929 | goto out_free_secdata; |
| 910 | BUG_ON(!mnt->mnt_sb); | 930 | BUG_ON(!mnt->mnt_sb); |
| 911 | WARN_ON(!mnt->mnt_sb->s_bdi); | 931 | WARN_ON(!mnt->mnt_sb->s_bdi); |
| 932 | mnt->mnt_sb->s_flags |= MS_BORN; | ||
| 912 | 933 | ||
| 913 | error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata); | 934 | error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata); |
| 914 | if (error) | 935 | if (error) |
| @@ -128,31 +128,6 @@ void emergency_sync(void) | |||
| 128 | } | 128 | } |
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | /* | ||
| 132 | * Generic function to fsync a file. | ||
| 133 | */ | ||
| 134 | int file_fsync(struct file *filp, int datasync) | ||
| 135 | { | ||
| 136 | struct inode *inode = filp->f_mapping->host; | ||
| 137 | struct super_block * sb; | ||
| 138 | int ret, err; | ||
| 139 | |||
| 140 | /* sync the inode to buffers */ | ||
| 141 | ret = write_inode_now(inode, 0); | ||
| 142 | |||
| 143 | /* sync the superblock to buffers */ | ||
| 144 | sb = inode->i_sb; | ||
| 145 | if (sb->s_dirt && sb->s_op->write_super) | ||
| 146 | sb->s_op->write_super(sb); | ||
| 147 | |||
| 148 | /* .. finally sync the buffers to disk */ | ||
| 149 | err = sync_blockdev(sb->s_bdev); | ||
| 150 | if (!ret) | ||
| 151 | ret = err; | ||
| 152 | return ret; | ||
| 153 | } | ||
| 154 | EXPORT_SYMBOL(file_fsync); | ||
| 155 | |||
| 156 | /** | 131 | /** |
| 157 | * vfs_fsync_range - helper to sync a range of data & metadata to disk | 132 | * vfs_fsync_range - helper to sync a range of data & metadata to disk |
| 158 | * @file: file to sync | 133 | * @file: file to sync |
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 0835a3b70e03..cffb1fd8ba33 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c | |||
| @@ -122,7 +122,7 @@ int sysfs_setattr(struct dentry *dentry, struct iattr *iattr) | |||
| 122 | goto out; | 122 | goto out; |
| 123 | 123 | ||
| 124 | /* this ignores size changes */ | 124 | /* this ignores size changes */ |
| 125 | generic_setattr(inode, iattr); | 125 | setattr_copy(inode, iattr); |
| 126 | 126 | ||
| 127 | out: | 127 | out: |
| 128 | mutex_unlock(&sysfs_mutex); | 128 | mutex_unlock(&sysfs_mutex); |
| @@ -312,15 +312,15 @@ struct inode * sysfs_get_inode(struct super_block *sb, struct sysfs_dirent *sd) | |||
| 312 | * The sysfs_dirent serves as both an inode and a directory entry for sysfs. | 312 | * The sysfs_dirent serves as both an inode and a directory entry for sysfs. |
| 313 | * To prevent the sysfs inode numbers from being freed prematurely we take a | 313 | * To prevent the sysfs inode numbers from being freed prematurely we take a |
| 314 | * reference to sysfs_dirent from the sysfs inode. A | 314 | * reference to sysfs_dirent from the sysfs inode. A |
| 315 | * super_operations.delete_inode() implementation is needed to drop that | 315 | * super_operations.evict_inode() implementation is needed to drop that |
| 316 | * reference upon inode destruction. | 316 | * reference upon inode destruction. |
| 317 | */ | 317 | */ |
| 318 | void sysfs_delete_inode(struct inode *inode) | 318 | void sysfs_evict_inode(struct inode *inode) |
| 319 | { | 319 | { |
| 320 | struct sysfs_dirent *sd = inode->i_private; | 320 | struct sysfs_dirent *sd = inode->i_private; |
| 321 | 321 | ||
| 322 | truncate_inode_pages(&inode->i_data, 0); | 322 | truncate_inode_pages(&inode->i_data, 0); |
| 323 | clear_inode(inode); | 323 | end_writeback(inode); |
| 324 | sysfs_put(sd); | 324 | sysfs_put(sd); |
| 325 | } | 325 | } |
| 326 | 326 | ||
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 281c0c9bc39f..f2af22574c50 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c | |||
| @@ -29,7 +29,7 @@ struct kmem_cache *sysfs_dir_cachep; | |||
| 29 | static const struct super_operations sysfs_ops = { | 29 | static const struct super_operations sysfs_ops = { |
| 30 | .statfs = simple_statfs, | 30 | .statfs = simple_statfs, |
| 31 | .drop_inode = generic_delete_inode, | 31 | .drop_inode = generic_delete_inode, |
| 32 | .delete_inode = sysfs_delete_inode, | 32 | .evict_inode = sysfs_evict_inode, |
| 33 | }; | 33 | }; |
| 34 | 34 | ||
| 35 | struct sysfs_dirent sysfs_root = { | 35 | struct sysfs_dirent sysfs_root = { |
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 6a13105b5594..d9be60a2e956 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h | |||
| @@ -198,7 +198,7 @@ static inline void __sysfs_put(struct sysfs_dirent *sd) | |||
| 198 | * inode.c | 198 | * inode.c |
| 199 | */ | 199 | */ |
| 200 | struct inode *sysfs_get_inode(struct super_block *sb, struct sysfs_dirent *sd); | 200 | struct inode *sysfs_get_inode(struct super_block *sb, struct sysfs_dirent *sd); |
| 201 | void sysfs_delete_inode(struct inode *inode); | 201 | void sysfs_evict_inode(struct inode *inode); |
| 202 | int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr *iattr); | 202 | int sysfs_sd_setattr(struct sysfs_dirent *sd, struct iattr *iattr); |
| 203 | int sysfs_permission(struct inode *inode, int mask); | 203 | int sysfs_permission(struct inode *inode, int mask); |
| 204 | int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); | 204 | int sysfs_setattr(struct dentry *dentry, struct iattr *iattr); |
diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c index 79941e4964a4..a77c42157620 100644 --- a/fs/sysv/dir.c +++ b/fs/sysv/dir.c | |||
| @@ -218,8 +218,7 @@ got_it: | |||
| 218 | pos = page_offset(page) + | 218 | pos = page_offset(page) + |
| 219 | (char*)de - (char*)page_address(page); | 219 | (char*)de - (char*)page_address(page); |
| 220 | lock_page(page); | 220 | lock_page(page); |
| 221 | err = __sysv_write_begin(NULL, page->mapping, pos, SYSV_DIRSIZE, | 221 | err = sysv_prepare_chunk(page, pos, SYSV_DIRSIZE); |
| 222 | AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); | ||
| 223 | if (err) | 222 | if (err) |
| 224 | goto out_unlock; | 223 | goto out_unlock; |
| 225 | memcpy (de->name, name, namelen); | 224 | memcpy (de->name, name, namelen); |
| @@ -239,15 +238,13 @@ out_unlock: | |||
| 239 | 238 | ||
| 240 | int sysv_delete_entry(struct sysv_dir_entry *de, struct page *page) | 239 | int sysv_delete_entry(struct sysv_dir_entry *de, struct page *page) |
| 241 | { | 240 | { |
| 242 | struct address_space *mapping = page->mapping; | 241 | struct inode *inode = page->mapping->host; |
| 243 | struct inode *inode = (struct inode*)mapping->host; | ||
| 244 | char *kaddr = (char*)page_address(page); | 242 | char *kaddr = (char*)page_address(page); |
| 245 | loff_t pos = page_offset(page) + (char *)de - kaddr; | 243 | loff_t pos = page_offset(page) + (char *)de - kaddr; |
| 246 | int err; | 244 | int err; |
| 247 | 245 | ||
| 248 | lock_page(page); | 246 | lock_page(page); |
| 249 | err = __sysv_write_begin(NULL, mapping, pos, SYSV_DIRSIZE, | 247 | err = sysv_prepare_chunk(page, pos, SYSV_DIRSIZE); |
| 250 | AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); | ||
| 251 | BUG_ON(err); | 248 | BUG_ON(err); |
| 252 | de->inode = 0; | 249 | de->inode = 0; |
| 253 | err = dir_commit_chunk(page, pos, SYSV_DIRSIZE); | 250 | err = dir_commit_chunk(page, pos, SYSV_DIRSIZE); |
| @@ -259,16 +256,14 @@ int sysv_delete_entry(struct sysv_dir_entry *de, struct page *page) | |||
| 259 | 256 | ||
| 260 | int sysv_make_empty(struct inode *inode, struct inode *dir) | 257 | int sysv_make_empty(struct inode *inode, struct inode *dir) |
| 261 | { | 258 | { |
| 262 | struct address_space *mapping = inode->i_mapping; | 259 | struct page *page = grab_cache_page(inode->i_mapping, 0); |
| 263 | struct page *page = grab_cache_page(mapping, 0); | ||
| 264 | struct sysv_dir_entry * de; | 260 | struct sysv_dir_entry * de; |
| 265 | char *base; | 261 | char *base; |
| 266 | int err; | 262 | int err; |
| 267 | 263 | ||
| 268 | if (!page) | 264 | if (!page) |
| 269 | return -ENOMEM; | 265 | return -ENOMEM; |
| 270 | err = __sysv_write_begin(NULL, mapping, 0, 2 * SYSV_DIRSIZE, | 266 | err = sysv_prepare_chunk(page, 0, 2 * SYSV_DIRSIZE); |
| 271 | AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); | ||
| 272 | if (err) { | 267 | if (err) { |
| 273 | unlock_page(page); | 268 | unlock_page(page); |
| 274 | goto fail; | 269 | goto fail; |
| @@ -341,15 +336,13 @@ not_empty: | |||
| 341 | void sysv_set_link(struct sysv_dir_entry *de, struct page *page, | 336 | void sysv_set_link(struct sysv_dir_entry *de, struct page *page, |
| 342 | struct inode *inode) | 337 | struct inode *inode) |
| 343 | { | 338 | { |
| 344 | struct address_space *mapping = page->mapping; | 339 | struct inode *dir = page->mapping->host; |
| 345 | struct inode *dir = mapping->host; | ||
| 346 | loff_t pos = page_offset(page) + | 340 | loff_t pos = page_offset(page) + |
| 347 | (char *)de-(char*)page_address(page); | 341 | (char *)de-(char*)page_address(page); |
| 348 | int err; | 342 | int err; |
| 349 | 343 | ||
| 350 | lock_page(page); | 344 | lock_page(page); |
| 351 | err = __sysv_write_begin(NULL, mapping, pos, SYSV_DIRSIZE, | 345 | err = sysv_prepare_chunk(page, pos, SYSV_DIRSIZE); |
| 352 | AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); | ||
| 353 | BUG_ON(err); | 346 | BUG_ON(err); |
| 354 | de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), inode->i_ino); | 347 | de->inode = cpu_to_fs16(SYSV_SB(inode->i_sb), inode->i_ino); |
| 355 | err = dir_commit_chunk(page, pos, SYSV_DIRSIZE); | 348 | err = dir_commit_chunk(page, pos, SYSV_DIRSIZE); |
diff --git a/fs/sysv/file.c b/fs/sysv/file.c index 750cc22349bd..0a65939508e9 100644 --- a/fs/sysv/file.c +++ b/fs/sysv/file.c | |||
| @@ -30,7 +30,29 @@ const struct file_operations sysv_file_operations = { | |||
| 30 | .splice_read = generic_file_splice_read, | 30 | .splice_read = generic_file_splice_read, |
| 31 | }; | 31 | }; |
| 32 | 32 | ||
| 33 | static int sysv_setattr(struct dentry *dentry, struct iattr *attr) | ||
| 34 | { | ||
| 35 | struct inode *inode = dentry->d_inode; | ||
| 36 | int error; | ||
| 37 | |||
| 38 | error = inode_change_ok(inode, attr); | ||
| 39 | if (error) | ||
| 40 | return error; | ||
| 41 | |||
| 42 | if ((attr->ia_valid & ATTR_SIZE) && | ||
| 43 | attr->ia_size != i_size_read(inode)) { | ||
| 44 | error = vmtruncate(inode, attr->ia_size); | ||
| 45 | if (error) | ||
| 46 | return error; | ||
| 47 | } | ||
| 48 | |||
| 49 | setattr_copy(inode, attr); | ||
| 50 | mark_inode_dirty(inode); | ||
| 51 | return 0; | ||
| 52 | } | ||
| 53 | |||
| 33 | const struct inode_operations sysv_file_inode_operations = { | 54 | const struct inode_operations sysv_file_inode_operations = { |
| 34 | .truncate = sysv_truncate, | 55 | .truncate = sysv_truncate, |
| 56 | .setattr = sysv_setattr, | ||
| 35 | .getattr = sysv_getattr, | 57 | .getattr = sysv_getattr, |
| 36 | }; | 58 | }; |
diff --git a/fs/sysv/ialloc.c b/fs/sysv/ialloc.c index fcc498ec9b33..0c96c98bd1db 100644 --- a/fs/sysv/ialloc.c +++ b/fs/sysv/ialloc.c | |||
| @@ -113,7 +113,6 @@ void sysv_free_inode(struct inode * inode) | |||
| 113 | return; | 113 | return; |
| 114 | } | 114 | } |
| 115 | raw_inode = sysv_raw_inode(sb, ino, &bh); | 115 | raw_inode = sysv_raw_inode(sb, ino, &bh); |
| 116 | clear_inode(inode); | ||
| 117 | if (!raw_inode) { | 116 | if (!raw_inode) { |
| 118 | printk("sysv_free_inode: unable to read inode block on device " | 117 | printk("sysv_free_inode: unable to read inode block on device " |
| 119 | "%s\n", inode->i_sb->s_id); | 118 | "%s\n", inode->i_sb->s_id); |
diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index d4a5380b5669..de44d067b9e6 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c | |||
| @@ -71,8 +71,8 @@ static int sysv_remount(struct super_block *sb, int *flags, char *data) | |||
| 71 | lock_super(sb); | 71 | lock_super(sb); |
| 72 | if (sbi->s_forced_ro) | 72 | if (sbi->s_forced_ro) |
| 73 | *flags |= MS_RDONLY; | 73 | *flags |= MS_RDONLY; |
| 74 | if (!(*flags & MS_RDONLY)) | 74 | if (*flags & MS_RDONLY) |
| 75 | sb->s_dirt = 1; | 75 | sysv_write_super(sb); |
| 76 | unlock_super(sb); | 76 | unlock_super(sb); |
| 77 | return 0; | 77 | return 0; |
| 78 | } | 78 | } |
| @@ -308,12 +308,17 @@ int sysv_sync_inode(struct inode *inode) | |||
| 308 | return __sysv_write_inode(inode, 1); | 308 | return __sysv_write_inode(inode, 1); |
| 309 | } | 309 | } |
| 310 | 310 | ||
| 311 | static void sysv_delete_inode(struct inode *inode) | 311 | static void sysv_evict_inode(struct inode *inode) |
| 312 | { | 312 | { |
| 313 | truncate_inode_pages(&inode->i_data, 0); | 313 | truncate_inode_pages(&inode->i_data, 0); |
| 314 | inode->i_size = 0; | 314 | if (!inode->i_nlink) { |
| 315 | sysv_truncate(inode); | 315 | inode->i_size = 0; |
| 316 | sysv_free_inode(inode); | 316 | sysv_truncate(inode); |
| 317 | } | ||
| 318 | invalidate_inode_buffers(inode); | ||
| 319 | end_writeback(inode); | ||
| 320 | if (!inode->i_nlink) | ||
| 321 | sysv_free_inode(inode); | ||
| 317 | } | 322 | } |
| 318 | 323 | ||
| 319 | static struct kmem_cache *sysv_inode_cachep; | 324 | static struct kmem_cache *sysv_inode_cachep; |
| @@ -344,7 +349,7 @@ const struct super_operations sysv_sops = { | |||
| 344 | .alloc_inode = sysv_alloc_inode, | 349 | .alloc_inode = sysv_alloc_inode, |
| 345 | .destroy_inode = sysv_destroy_inode, | 350 | .destroy_inode = sysv_destroy_inode, |
| 346 | .write_inode = sysv_write_inode, | 351 | .write_inode = sysv_write_inode, |
| 347 | .delete_inode = sysv_delete_inode, | 352 | .evict_inode = sysv_evict_inode, |
| 348 | .put_super = sysv_put_super, | 353 | .put_super = sysv_put_super, |
| 349 | .write_super = sysv_write_super, | 354 | .write_super = sysv_write_super, |
| 350 | .sync_fs = sysv_sync_fs, | 355 | .sync_fs = sysv_sync_fs, |
diff --git a/fs/sysv/itree.c b/fs/sysv/itree.c index f042eec464c2..9ca66276315e 100644 --- a/fs/sysv/itree.c +++ b/fs/sysv/itree.c | |||
| @@ -459,20 +459,25 @@ static int sysv_readpage(struct file *file, struct page *page) | |||
| 459 | return block_read_full_page(page,get_block); | 459 | return block_read_full_page(page,get_block); |
| 460 | } | 460 | } |
| 461 | 461 | ||
| 462 | int __sysv_write_begin(struct file *file, struct address_space *mapping, | 462 | int sysv_prepare_chunk(struct page *page, loff_t pos, unsigned len) |
| 463 | loff_t pos, unsigned len, unsigned flags, | ||
| 464 | struct page **pagep, void **fsdata) | ||
| 465 | { | 463 | { |
| 466 | return block_write_begin(file, mapping, pos, len, flags, pagep, fsdata, | 464 | return __block_write_begin(page, pos, len, get_block); |
| 467 | get_block); | ||
| 468 | } | 465 | } |
| 469 | 466 | ||
| 470 | static int sysv_write_begin(struct file *file, struct address_space *mapping, | 467 | static int sysv_write_begin(struct file *file, struct address_space *mapping, |
| 471 | loff_t pos, unsigned len, unsigned flags, | 468 | loff_t pos, unsigned len, unsigned flags, |
| 472 | struct page **pagep, void **fsdata) | 469 | struct page **pagep, void **fsdata) |
| 473 | { | 470 | { |
| 474 | *pagep = NULL; | 471 | int ret; |
| 475 | return __sysv_write_begin(file, mapping, pos, len, flags, pagep, fsdata); | 472 | |
| 473 | ret = block_write_begin(mapping, pos, len, flags, pagep, get_block); | ||
| 474 | if (unlikely(ret)) { | ||
| 475 | loff_t isize = mapping->host->i_size; | ||
| 476 | if (pos + len > isize) | ||
| 477 | vmtruncate(mapping->host, isize); | ||
| 478 | } | ||
| 479 | |||
| 480 | return ret; | ||
| 476 | } | 481 | } |
| 477 | 482 | ||
| 478 | static sector_t sysv_bmap(struct address_space *mapping, sector_t block) | 483 | static sector_t sysv_bmap(struct address_space *mapping, sector_t block) |
diff --git a/fs/sysv/super.c b/fs/sysv/super.c index 5a903da54551..a0b0cda6927e 100644 --- a/fs/sysv/super.c +++ b/fs/sysv/super.c | |||
| @@ -347,7 +347,6 @@ static int complete_read_super(struct super_block *sb, int silent, int size) | |||
| 347 | sb->s_flags |= MS_RDONLY; | 347 | sb->s_flags |= MS_RDONLY; |
| 348 | if (sbi->s_truncate) | 348 | if (sbi->s_truncate) |
| 349 | sb->s_root->d_op = &sysv_dentry_operations; | 349 | sb->s_root->d_op = &sysv_dentry_operations; |
| 350 | sb->s_dirt = 1; | ||
| 351 | return 1; | 350 | return 1; |
| 352 | } | 351 | } |
| 353 | 352 | ||
| @@ -435,12 +434,46 @@ Ebadsize: | |||
| 435 | goto failed; | 434 | goto failed; |
| 436 | } | 435 | } |
| 437 | 436 | ||
| 438 | static int v7_fill_super(struct super_block *sb, void *data, int silent) | 437 | static int v7_sanity_check(struct super_block *sb, struct buffer_head *bh) |
| 439 | { | 438 | { |
| 440 | struct sysv_sb_info *sbi; | ||
| 441 | struct buffer_head *bh, *bh2 = NULL; | ||
| 442 | struct v7_super_block *v7sb; | 439 | struct v7_super_block *v7sb; |
| 443 | struct sysv_inode *v7i; | 440 | struct sysv_inode *v7i; |
| 441 | struct buffer_head *bh2; | ||
| 442 | struct sysv_sb_info *sbi; | ||
| 443 | |||
| 444 | sbi = sb->s_fs_info; | ||
| 445 | |||
| 446 | /* plausibility check on superblock */ | ||
| 447 | v7sb = (struct v7_super_block *) bh->b_data; | ||
| 448 | if (fs16_to_cpu(sbi, v7sb->s_nfree) > V7_NICFREE || | ||
| 449 | fs16_to_cpu(sbi, v7sb->s_ninode) > V7_NICINOD || | ||
| 450 | fs32_to_cpu(sbi, v7sb->s_fsize) > V7_MAXSIZE) | ||
| 451 | return 0; | ||
| 452 | |||
| 453 | /* plausibility check on root inode: it is a directory, | ||
| 454 | with a nonzero size that is a multiple of 16 */ | ||
| 455 | bh2 = sb_bread(sb, 2); | ||
| 456 | if (bh2 == NULL) | ||
| 457 | return 0; | ||
| 458 | |||
| 459 | v7i = (struct sysv_inode *)(bh2->b_data + 64); | ||
| 460 | if ((fs16_to_cpu(sbi, v7i->i_mode) & ~0777) != S_IFDIR || | ||
| 461 | (fs32_to_cpu(sbi, v7i->i_size) == 0) || | ||
| 462 | (fs32_to_cpu(sbi, v7i->i_size) & 017) || | ||
| 463 | (fs32_to_cpu(sbi, v7i->i_size) > V7_NFILES * | ||
| 464 | sizeof(struct sysv_dir_entry))) { | ||
| 465 | brelse(bh2); | ||
| 466 | return 0; | ||
| 467 | } | ||
| 468 | |||
| 469 | brelse(bh2); | ||
| 470 | return 1; | ||
| 471 | } | ||
| 472 | |||
| 473 | static int v7_fill_super(struct super_block *sb, void *data, int silent) | ||
| 474 | { | ||
| 475 | struct sysv_sb_info *sbi; | ||
| 476 | struct buffer_head *bh; | ||
| 444 | 477 | ||
| 445 | if (440 != sizeof (struct v7_super_block)) | 478 | if (440 != sizeof (struct v7_super_block)) |
| 446 | panic("V7 FS: bad super-block size"); | 479 | panic("V7 FS: bad super-block size"); |
| @@ -454,7 +487,6 @@ static int v7_fill_super(struct super_block *sb, void *data, int silent) | |||
| 454 | sbi->s_sb = sb; | 487 | sbi->s_sb = sb; |
| 455 | sbi->s_block_base = 0; | 488 | sbi->s_block_base = 0; |
| 456 | sbi->s_type = FSTYPE_V7; | 489 | sbi->s_type = FSTYPE_V7; |
| 457 | sbi->s_bytesex = BYTESEX_PDP; | ||
| 458 | sb->s_fs_info = sbi; | 490 | sb->s_fs_info = sbi; |
| 459 | 491 | ||
| 460 | sb_set_blocksize(sb, 512); | 492 | sb_set_blocksize(sb, 512); |
| @@ -466,32 +498,27 @@ static int v7_fill_super(struct super_block *sb, void *data, int silent) | |||
| 466 | goto failed; | 498 | goto failed; |
| 467 | } | 499 | } |
| 468 | 500 | ||
| 469 | /* plausibility check on superblock */ | 501 | /* Try PDP-11 UNIX */ |
| 470 | v7sb = (struct v7_super_block *) bh->b_data; | 502 | sbi->s_bytesex = BYTESEX_PDP; |
| 471 | if (fs16_to_cpu(sbi, v7sb->s_nfree) > V7_NICFREE || | 503 | if (v7_sanity_check(sb, bh)) |
| 472 | fs16_to_cpu(sbi, v7sb->s_ninode) > V7_NICINOD || | 504 | goto detected; |
| 473 | fs32_to_cpu(sbi, v7sb->s_time) == 0) | ||
| 474 | goto failed; | ||
| 475 | 505 | ||
| 476 | /* plausibility check on root inode: it is a directory, | 506 | /* Try PC/IX, v7/x86 */ |
| 477 | with a nonzero size that is a multiple of 16 */ | 507 | sbi->s_bytesex = BYTESEX_LE; |
| 478 | if ((bh2 = sb_bread(sb, 2)) == NULL) | 508 | if (v7_sanity_check(sb, bh)) |
| 479 | goto failed; | 509 | goto detected; |
| 480 | v7i = (struct sysv_inode *)(bh2->b_data + 64); | ||
| 481 | if ((fs16_to_cpu(sbi, v7i->i_mode) & ~0777) != S_IFDIR || | ||
| 482 | (fs32_to_cpu(sbi, v7i->i_size) == 0) || | ||
| 483 | (fs32_to_cpu(sbi, v7i->i_size) & 017) != 0) | ||
| 484 | goto failed; | ||
| 485 | brelse(bh2); | ||
| 486 | bh2 = NULL; | ||
| 487 | 510 | ||
| 511 | goto failed; | ||
| 512 | |||
| 513 | detected: | ||
| 488 | sbi->s_bh1 = bh; | 514 | sbi->s_bh1 = bh; |
| 489 | sbi->s_bh2 = bh; | 515 | sbi->s_bh2 = bh; |
| 490 | if (complete_read_super(sb, silent, 1)) | 516 | if (complete_read_super(sb, silent, 1)) |
| 491 | return 0; | 517 | return 0; |
| 492 | 518 | ||
| 493 | failed: | 519 | failed: |
| 494 | brelse(bh2); | 520 | printk(KERN_ERR "VFS: could not find a valid V7 on %s.\n", |
| 521 | sb->s_id); | ||
| 495 | brelse(bh); | 522 | brelse(bh); |
| 496 | kfree(sbi); | 523 | kfree(sbi); |
| 497 | return -EINVAL; | 524 | return -EINVAL; |
| @@ -560,4 +587,5 @@ static void __exit exit_sysv_fs(void) | |||
| 560 | 587 | ||
| 561 | module_init(init_sysv_fs) | 588 | module_init(init_sysv_fs) |
| 562 | module_exit(exit_sysv_fs) | 589 | module_exit(exit_sysv_fs) |
| 590 | MODULE_ALIAS("v7"); | ||
| 563 | MODULE_LICENSE("GPL"); | 591 | MODULE_LICENSE("GPL"); |
diff --git a/fs/sysv/sysv.h b/fs/sysv/sysv.h index 94cb9b4d76c2..bb55cdb394bf 100644 --- a/fs/sysv/sysv.h +++ b/fs/sysv/sysv.h | |||
| @@ -136,9 +136,7 @@ extern unsigned long sysv_count_free_blocks(struct super_block *); | |||
| 136 | 136 | ||
| 137 | /* itree.c */ | 137 | /* itree.c */ |
| 138 | extern void sysv_truncate(struct inode *); | 138 | extern void sysv_truncate(struct inode *); |
| 139 | extern int __sysv_write_begin(struct file *file, struct address_space *mapping, | 139 | extern int sysv_prepare_chunk(struct page *page, loff_t pos, unsigned len); |
| 140 | loff_t pos, unsigned len, unsigned flags, | ||
| 141 | struct page **pagep, void **fsdata); | ||
| 142 | 140 | ||
| 143 | /* inode.c */ | 141 | /* inode.c */ |
| 144 | extern struct inode *sysv_iget(struct super_block *, unsigned int); | 142 | extern struct inode *sysv_iget(struct super_block *, unsigned int); |
diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c index 12f445cee9f7..03ae894c45de 100644 --- a/fs/ubifs/file.c +++ b/fs/ubifs/file.c | |||
| @@ -967,14 +967,15 @@ static int do_writepage(struct page *page, int len) | |||
| 967 | * the page locked, and it locks @ui_mutex. However, write-back does take inode | 967 | * the page locked, and it locks @ui_mutex. However, write-back does take inode |
| 968 | * @i_mutex, which means other VFS operations may be run on this inode at the | 968 | * @i_mutex, which means other VFS operations may be run on this inode at the |
| 969 | * same time. And the problematic one is truncation to smaller size, from where | 969 | * same time. And the problematic one is truncation to smaller size, from where |
| 970 | * we have to call 'simple_setsize()', which first changes @inode->i_size, then | 970 | * we have to call 'truncate_setsize()', which first changes @inode->i_size, then |
| 971 | * drops the truncated pages. And while dropping the pages, it takes the page | 971 | * drops the truncated pages. And while dropping the pages, it takes the page |
| 972 | * lock. This means that 'do_truncation()' cannot call 'simple_setsize()' with | 972 | * lock. This means that 'do_truncation()' cannot call 'truncate_setsize()' with |
| 973 | * @ui_mutex locked, because it would deadlock with 'ubifs_writepage()'. This | 973 | * @ui_mutex locked, because it would deadlock with 'ubifs_writepage()'. This |
| 974 | * means that @inode->i_size is changed while @ui_mutex is unlocked. | 974 | * means that @inode->i_size is changed while @ui_mutex is unlocked. |
| 975 | * | 975 | * |
| 976 | * XXX: with the new truncate the above is not true anymore, the simple_setsize | 976 | * XXX(truncate): with the new truncate sequence this is not true anymore, |
| 977 | * calls can be replaced with the individual components. | 977 | * and the calls to truncate_setsize can be move around freely. They should |
| 978 | * be moved to the very end of the truncate sequence. | ||
| 978 | * | 979 | * |
| 979 | * But in 'ubifs_writepage()' we have to guarantee that we do not write beyond | 980 | * But in 'ubifs_writepage()' we have to guarantee that we do not write beyond |
| 980 | * inode size. How do we do this if @inode->i_size may became smaller while we | 981 | * inode size. How do we do this if @inode->i_size may became smaller while we |
| @@ -1128,9 +1129,7 @@ static int do_truncation(struct ubifs_info *c, struct inode *inode, | |||
| 1128 | budgeted = 0; | 1129 | budgeted = 0; |
| 1129 | } | 1130 | } |
| 1130 | 1131 | ||
| 1131 | err = simple_setsize(inode, new_size); | 1132 | truncate_setsize(inode, new_size); |
| 1132 | if (err) | ||
| 1133 | goto out_budg; | ||
| 1134 | 1133 | ||
| 1135 | if (offset) { | 1134 | if (offset) { |
| 1136 | pgoff_t index = new_size >> PAGE_CACHE_SHIFT; | 1135 | pgoff_t index = new_size >> PAGE_CACHE_SHIFT; |
| @@ -1217,16 +1216,14 @@ static int do_setattr(struct ubifs_info *c, struct inode *inode, | |||
| 1217 | 1216 | ||
| 1218 | if (attr->ia_valid & ATTR_SIZE) { | 1217 | if (attr->ia_valid & ATTR_SIZE) { |
| 1219 | dbg_gen("size %lld -> %lld", inode->i_size, new_size); | 1218 | dbg_gen("size %lld -> %lld", inode->i_size, new_size); |
| 1220 | err = simple_setsize(inode, new_size); | 1219 | truncate_setsize(inode, new_size); |
| 1221 | if (err) | ||
| 1222 | goto out; | ||
| 1223 | } | 1220 | } |
| 1224 | 1221 | ||
| 1225 | mutex_lock(&ui->ui_mutex); | 1222 | mutex_lock(&ui->ui_mutex); |
| 1226 | if (attr->ia_valid & ATTR_SIZE) { | 1223 | if (attr->ia_valid & ATTR_SIZE) { |
| 1227 | /* Truncation changes inode [mc]time */ | 1224 | /* Truncation changes inode [mc]time */ |
| 1228 | inode->i_mtime = inode->i_ctime = ubifs_current_time(inode); | 1225 | inode->i_mtime = inode->i_ctime = ubifs_current_time(inode); |
| 1229 | /* 'simple_setsize()' changed @i_size, update @ui_size */ | 1226 | /* 'truncate_setsize()' changed @i_size, update @ui_size */ |
| 1230 | ui->ui_size = inode->i_size; | 1227 | ui->ui_size = inode->i_size; |
| 1231 | } | 1228 | } |
| 1232 | 1229 | ||
| @@ -1248,10 +1245,6 @@ static int do_setattr(struct ubifs_info *c, struct inode *inode, | |||
| 1248 | if (IS_SYNC(inode)) | 1245 | if (IS_SYNC(inode)) |
| 1249 | err = inode->i_sb->s_op->write_inode(inode, NULL); | 1246 | err = inode->i_sb->s_op->write_inode(inode, NULL); |
| 1250 | return err; | 1247 | return err; |
| 1251 | |||
| 1252 | out: | ||
| 1253 | ubifs_release_budget(c, &req); | ||
| 1254 | return err; | ||
| 1255 | } | 1248 | } |
| 1256 | 1249 | ||
| 1257 | int ubifs_setattr(struct dentry *dentry, struct iattr *attr) | 1250 | int ubifs_setattr(struct dentry *dentry, struct iattr *attr) |
diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index 5fc5a0988970..cd5900b85d38 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c | |||
| @@ -327,7 +327,7 @@ static int ubifs_write_inode(struct inode *inode, struct writeback_control *wbc) | |||
| 327 | return err; | 327 | return err; |
| 328 | } | 328 | } |
| 329 | 329 | ||
| 330 | static void ubifs_delete_inode(struct inode *inode) | 330 | static void ubifs_evict_inode(struct inode *inode) |
| 331 | { | 331 | { |
| 332 | int err; | 332 | int err; |
| 333 | struct ubifs_info *c = inode->i_sb->s_fs_info; | 333 | struct ubifs_info *c = inode->i_sb->s_fs_info; |
| @@ -343,9 +343,12 @@ static void ubifs_delete_inode(struct inode *inode) | |||
| 343 | 343 | ||
| 344 | dbg_gen("inode %lu, mode %#x", inode->i_ino, (int)inode->i_mode); | 344 | dbg_gen("inode %lu, mode %#x", inode->i_ino, (int)inode->i_mode); |
| 345 | ubifs_assert(!atomic_read(&inode->i_count)); | 345 | ubifs_assert(!atomic_read(&inode->i_count)); |
| 346 | ubifs_assert(inode->i_nlink == 0); | ||
| 347 | 346 | ||
| 348 | truncate_inode_pages(&inode->i_data, 0); | 347 | truncate_inode_pages(&inode->i_data, 0); |
| 348 | |||
| 349 | if (inode->i_nlink) | ||
| 350 | goto done; | ||
| 351 | |||
| 349 | if (is_bad_inode(inode)) | 352 | if (is_bad_inode(inode)) |
| 350 | goto out; | 353 | goto out; |
| 351 | 354 | ||
| @@ -367,7 +370,8 @@ out: | |||
| 367 | c->nospace = c->nospace_rp = 0; | 370 | c->nospace = c->nospace_rp = 0; |
| 368 | smp_wmb(); | 371 | smp_wmb(); |
| 369 | } | 372 | } |
| 370 | clear_inode(inode); | 373 | done: |
| 374 | end_writeback(inode); | ||
| 371 | } | 375 | } |
| 372 | 376 | ||
| 373 | static void ubifs_dirty_inode(struct inode *inode) | 377 | static void ubifs_dirty_inode(struct inode *inode) |
| @@ -1826,7 +1830,7 @@ const struct super_operations ubifs_super_operations = { | |||
| 1826 | .destroy_inode = ubifs_destroy_inode, | 1830 | .destroy_inode = ubifs_destroy_inode, |
| 1827 | .put_super = ubifs_put_super, | 1831 | .put_super = ubifs_put_super, |
| 1828 | .write_inode = ubifs_write_inode, | 1832 | .write_inode = ubifs_write_inode, |
| 1829 | .delete_inode = ubifs_delete_inode, | 1833 | .evict_inode = ubifs_evict_inode, |
| 1830 | .statfs = ubifs_statfs, | 1834 | .statfs = ubifs_statfs, |
| 1831 | .dirty_inode = ubifs_dirty_inode, | 1835 | .dirty_inode = ubifs_dirty_inode, |
| 1832 | .remount_fs = ubifs_remount_fs, | 1836 | .remount_fs = ubifs_remount_fs, |
diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index 04310878f449..0c9876b396dd 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h | |||
| @@ -379,7 +379,7 @@ struct ubifs_gced_idx_leb { | |||
| 379 | * The @ui_size is a "shadow" variable for @inode->i_size and UBIFS uses | 379 | * The @ui_size is a "shadow" variable for @inode->i_size and UBIFS uses |
| 380 | * @ui_size instead of @inode->i_size. The reason for this is that UBIFS cannot | 380 | * @ui_size instead of @inode->i_size. The reason for this is that UBIFS cannot |
| 381 | * make sure @inode->i_size is always changed under @ui_mutex, because it | 381 | * make sure @inode->i_size is always changed under @ui_mutex, because it |
| 382 | * cannot call 'simple_setsize()' with @ui_mutex locked, because it would deadlock | 382 | * cannot call 'truncate_setsize()' with @ui_mutex locked, because it would deadlock |
| 383 | * with 'ubifs_writepage()' (see file.c). All the other inode fields are | 383 | * with 'ubifs_writepage()' (see file.c). All the other inode fields are |
| 384 | * changed under @ui_mutex, so they do not need "shadow" fields. Note, one | 384 | * changed under @ui_mutex, so they do not need "shadow" fields. Note, one |
| 385 | * could consider to rework locking and base it on "shadow" fields. | 385 | * could consider to rework locking and base it on "shadow" fields. |
diff --git a/fs/udf/file.c b/fs/udf/file.c index 6e450e01a1bb..66b9e7e7e4c5 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c | |||
| @@ -227,6 +227,28 @@ const struct file_operations udf_file_operations = { | |||
| 227 | .llseek = generic_file_llseek, | 227 | .llseek = generic_file_llseek, |
| 228 | }; | 228 | }; |
| 229 | 229 | ||
| 230 | static int udf_setattr(struct dentry *dentry, struct iattr *attr) | ||
| 231 | { | ||
| 232 | struct inode *inode = dentry->d_inode; | ||
| 233 | int error; | ||
| 234 | |||
| 235 | error = inode_change_ok(inode, attr); | ||
| 236 | if (error) | ||
| 237 | return error; | ||
| 238 | |||
| 239 | if ((attr->ia_valid & ATTR_SIZE) && | ||
| 240 | attr->ia_size != i_size_read(inode)) { | ||
| 241 | error = vmtruncate(inode, attr->ia_size); | ||
| 242 | if (error) | ||
| 243 | return error; | ||
| 244 | } | ||
| 245 | |||
| 246 | setattr_copy(inode, attr); | ||
| 247 | mark_inode_dirty(inode); | ||
| 248 | return 0; | ||
| 249 | } | ||
| 250 | |||
| 230 | const struct inode_operations udf_file_inode_operations = { | 251 | const struct inode_operations udf_file_inode_operations = { |
| 252 | .setattr = udf_setattr, | ||
| 231 | .truncate = udf_truncate, | 253 | .truncate = udf_truncate, |
| 232 | }; | 254 | }; |
diff --git a/fs/udf/ialloc.c b/fs/udf/ialloc.c index 18cd7111185d..75d9304d0dc3 100644 --- a/fs/udf/ialloc.c +++ b/fs/udf/ialloc.c | |||
| @@ -31,8 +31,6 @@ void udf_free_inode(struct inode *inode) | |||
| 31 | struct super_block *sb = inode->i_sb; | 31 | struct super_block *sb = inode->i_sb; |
| 32 | struct udf_sb_info *sbi = UDF_SB(sb); | 32 | struct udf_sb_info *sbi = UDF_SB(sb); |
| 33 | 33 | ||
| 34 | clear_inode(inode); | ||
| 35 | |||
| 36 | mutex_lock(&sbi->s_alloc_mutex); | 34 | mutex_lock(&sbi->s_alloc_mutex); |
| 37 | if (sbi->s_lvid_bh) { | 35 | if (sbi->s_lvid_bh) { |
| 38 | struct logicalVolIntegrityDescImpUse *lvidiu = | 36 | struct logicalVolIntegrityDescImpUse *lvidiu = |
diff --git a/fs/udf/inode.c b/fs/udf/inode.c index 124852bcf6fe..fc48f37aa2dd 100644 --- a/fs/udf/inode.c +++ b/fs/udf/inode.c | |||
| @@ -68,37 +68,23 @@ static void udf_update_extents(struct inode *, | |||
| 68 | static int udf_get_block(struct inode *, sector_t, struct buffer_head *, int); | 68 | static int udf_get_block(struct inode *, sector_t, struct buffer_head *, int); |
| 69 | 69 | ||
| 70 | 70 | ||
| 71 | void udf_delete_inode(struct inode *inode) | 71 | void udf_evict_inode(struct inode *inode) |
| 72 | { | ||
| 73 | truncate_inode_pages(&inode->i_data, 0); | ||
| 74 | |||
| 75 | if (is_bad_inode(inode)) | ||
| 76 | goto no_delete; | ||
| 77 | |||
| 78 | inode->i_size = 0; | ||
| 79 | udf_truncate(inode); | ||
| 80 | lock_kernel(); | ||
| 81 | |||
| 82 | udf_update_inode(inode, IS_SYNC(inode)); | ||
| 83 | udf_free_inode(inode); | ||
| 84 | |||
| 85 | unlock_kernel(); | ||
| 86 | return; | ||
| 87 | |||
| 88 | no_delete: | ||
| 89 | clear_inode(inode); | ||
| 90 | } | ||
| 91 | |||
| 92 | /* | ||
| 93 | * If we are going to release inode from memory, we truncate last inode extent | ||
| 94 | * to proper length. We could use drop_inode() but it's called under inode_lock | ||
| 95 | * and thus we cannot mark inode dirty there. We use clear_inode() but we have | ||
| 96 | * to make sure to write inode as it's not written automatically. | ||
| 97 | */ | ||
| 98 | void udf_clear_inode(struct inode *inode) | ||
| 99 | { | 72 | { |
| 100 | struct udf_inode_info *iinfo = UDF_I(inode); | 73 | struct udf_inode_info *iinfo = UDF_I(inode); |
| 74 | int want_delete = 0; | ||
| 75 | |||
| 76 | truncate_inode_pages(&inode->i_data, 0); | ||
| 101 | 77 | ||
| 78 | if (!inode->i_nlink && !is_bad_inode(inode)) { | ||
| 79 | want_delete = 1; | ||
| 80 | inode->i_size = 0; | ||
| 81 | udf_truncate(inode); | ||
| 82 | lock_kernel(); | ||
| 83 | udf_update_inode(inode, IS_SYNC(inode)); | ||
| 84 | unlock_kernel(); | ||
| 85 | } | ||
| 86 | invalidate_inode_buffers(inode); | ||
| 87 | end_writeback(inode); | ||
| 102 | if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB && | 88 | if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB && |
| 103 | inode->i_size != iinfo->i_lenExtents) { | 89 | inode->i_size != iinfo->i_lenExtents) { |
| 104 | printk(KERN_WARNING "UDF-fs (%s): Inode %lu (mode %o) has " | 90 | printk(KERN_WARNING "UDF-fs (%s): Inode %lu (mode %o) has " |
| @@ -108,9 +94,13 @@ void udf_clear_inode(struct inode *inode) | |||
| 108 | (unsigned long long)inode->i_size, | 94 | (unsigned long long)inode->i_size, |
| 109 | (unsigned long long)iinfo->i_lenExtents); | 95 | (unsigned long long)iinfo->i_lenExtents); |
| 110 | } | 96 | } |
| 111 | |||
| 112 | kfree(iinfo->i_ext.i_data); | 97 | kfree(iinfo->i_ext.i_data); |
| 113 | iinfo->i_ext.i_data = NULL; | 98 | iinfo->i_ext.i_data = NULL; |
| 99 | if (want_delete) { | ||
| 100 | lock_kernel(); | ||
| 101 | udf_free_inode(inode); | ||
| 102 | unlock_kernel(); | ||
| 103 | } | ||
| 114 | } | 104 | } |
| 115 | 105 | ||
| 116 | static int udf_writepage(struct page *page, struct writeback_control *wbc) | 106 | static int udf_writepage(struct page *page, struct writeback_control *wbc) |
| @@ -127,9 +117,16 @@ static int udf_write_begin(struct file *file, struct address_space *mapping, | |||
| 127 | loff_t pos, unsigned len, unsigned flags, | 117 | loff_t pos, unsigned len, unsigned flags, |
| 128 | struct page **pagep, void **fsdata) | 118 | struct page **pagep, void **fsdata) |
| 129 | { | 119 | { |
| 130 | *pagep = NULL; | 120 | int ret; |
| 131 | return block_write_begin(file, mapping, pos, len, flags, pagep, fsdata, | 121 | |
| 132 | udf_get_block); | 122 | ret = block_write_begin(mapping, pos, len, flags, pagep, udf_get_block); |
| 123 | if (unlikely(ret)) { | ||
| 124 | loff_t isize = mapping->host->i_size; | ||
| 125 | if (pos + len > isize) | ||
| 126 | vmtruncate(mapping->host, isize); | ||
| 127 | } | ||
| 128 | |||
| 129 | return ret; | ||
| 133 | } | 130 | } |
| 134 | 131 | ||
| 135 | static sector_t udf_bmap(struct address_space *mapping, sector_t block) | 132 | static sector_t udf_bmap(struct address_space *mapping, sector_t block) |
diff --git a/fs/udf/super.c b/fs/udf/super.c index 12bb651e5400..65412d84a45d 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c | |||
| @@ -175,8 +175,7 @@ static const struct super_operations udf_sb_ops = { | |||
| 175 | .alloc_inode = udf_alloc_inode, | 175 | .alloc_inode = udf_alloc_inode, |
| 176 | .destroy_inode = udf_destroy_inode, | 176 | .destroy_inode = udf_destroy_inode, |
| 177 | .write_inode = udf_write_inode, | 177 | .write_inode = udf_write_inode, |
| 178 | .delete_inode = udf_delete_inode, | 178 | .evict_inode = udf_evict_inode, |
| 179 | .clear_inode = udf_clear_inode, | ||
| 180 | .put_super = udf_put_super, | 179 | .put_super = udf_put_super, |
| 181 | .sync_fs = udf_sync_fs, | 180 | .sync_fs = udf_sync_fs, |
| 182 | .statfs = udf_statfs, | 181 | .statfs = udf_statfs, |
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index 2bac0354891f..6995ab1f4305 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h | |||
| @@ -139,8 +139,7 @@ extern struct buffer_head *udf_expand_dir_adinicb(struct inode *, int *, int *); | |||
| 139 | extern struct buffer_head *udf_bread(struct inode *, int, int, int *); | 139 | extern struct buffer_head *udf_bread(struct inode *, int, int, int *); |
| 140 | extern void udf_truncate(struct inode *); | 140 | extern void udf_truncate(struct inode *); |
| 141 | extern void udf_read_inode(struct inode *); | 141 | extern void udf_read_inode(struct inode *); |
| 142 | extern void udf_delete_inode(struct inode *); | 142 | extern void udf_evict_inode(struct inode *); |
| 143 | extern void udf_clear_inode(struct inode *); | ||
| 144 | extern int udf_write_inode(struct inode *, struct writeback_control *wbc); | 143 | extern int udf_write_inode(struct inode *, struct writeback_control *wbc); |
| 145 | extern long udf_block_map(struct inode *, sector_t); | 144 | extern long udf_block_map(struct inode *, sector_t); |
| 146 | extern int udf_extend_file(struct inode *, struct extent_position *, | 145 | extern int udf_extend_file(struct inode *, struct extent_position *, |
diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c index ec784756dc65..dbc90994715a 100644 --- a/fs/ufs/dir.c +++ b/fs/ufs/dir.c | |||
| @@ -95,8 +95,7 @@ void ufs_set_link(struct inode *dir, struct ufs_dir_entry *de, | |||
| 95 | int err; | 95 | int err; |
| 96 | 96 | ||
| 97 | lock_page(page); | 97 | lock_page(page); |
| 98 | err = __ufs_write_begin(NULL, page->mapping, pos, len, | 98 | err = ufs_prepare_chunk(page, pos, len); |
| 99 | AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); | ||
| 100 | BUG_ON(err); | 99 | BUG_ON(err); |
| 101 | 100 | ||
| 102 | de->d_ino = cpu_to_fs32(dir->i_sb, inode->i_ino); | 101 | de->d_ino = cpu_to_fs32(dir->i_sb, inode->i_ino); |
| @@ -381,8 +380,7 @@ int ufs_add_link(struct dentry *dentry, struct inode *inode) | |||
| 381 | got_it: | 380 | got_it: |
| 382 | pos = page_offset(page) + | 381 | pos = page_offset(page) + |
| 383 | (char*)de - (char*)page_address(page); | 382 | (char*)de - (char*)page_address(page); |
| 384 | err = __ufs_write_begin(NULL, page->mapping, pos, rec_len, | 383 | err = ufs_prepare_chunk(page, pos, rec_len); |
| 385 | AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); | ||
| 386 | if (err) | 384 | if (err) |
| 387 | goto out_unlock; | 385 | goto out_unlock; |
| 388 | if (de->d_ino) { | 386 | if (de->d_ino) { |
| @@ -518,7 +516,6 @@ int ufs_delete_entry(struct inode *inode, struct ufs_dir_entry *dir, | |||
| 518 | struct page * page) | 516 | struct page * page) |
| 519 | { | 517 | { |
| 520 | struct super_block *sb = inode->i_sb; | 518 | struct super_block *sb = inode->i_sb; |
| 521 | struct address_space *mapping = page->mapping; | ||
| 522 | char *kaddr = page_address(page); | 519 | char *kaddr = page_address(page); |
| 523 | unsigned from = ((char*)dir - kaddr) & ~(UFS_SB(sb)->s_uspi->s_dirblksize - 1); | 520 | unsigned from = ((char*)dir - kaddr) & ~(UFS_SB(sb)->s_uspi->s_dirblksize - 1); |
| 524 | unsigned to = ((char*)dir - kaddr) + fs16_to_cpu(sb, dir->d_reclen); | 521 | unsigned to = ((char*)dir - kaddr) + fs16_to_cpu(sb, dir->d_reclen); |
| @@ -549,8 +546,7 @@ int ufs_delete_entry(struct inode *inode, struct ufs_dir_entry *dir, | |||
| 549 | 546 | ||
| 550 | pos = page_offset(page) + from; | 547 | pos = page_offset(page) + from; |
| 551 | lock_page(page); | 548 | lock_page(page); |
| 552 | err = __ufs_write_begin(NULL, mapping, pos, to - from, | 549 | err = ufs_prepare_chunk(page, pos, to - from); |
| 553 | AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); | ||
| 554 | BUG_ON(err); | 550 | BUG_ON(err); |
| 555 | if (pde) | 551 | if (pde) |
| 556 | pde->d_reclen = cpu_to_fs16(sb, to - from); | 552 | pde->d_reclen = cpu_to_fs16(sb, to - from); |
| @@ -577,8 +573,7 @@ int ufs_make_empty(struct inode * inode, struct inode *dir) | |||
| 577 | if (!page) | 573 | if (!page) |
| 578 | return -ENOMEM; | 574 | return -ENOMEM; |
| 579 | 575 | ||
| 580 | err = __ufs_write_begin(NULL, mapping, 0, chunk_size, | 576 | err = ufs_prepare_chunk(page, 0, chunk_size); |
| 581 | AOP_FLAG_UNINTERRUPTIBLE, &page, NULL); | ||
| 582 | if (err) { | 577 | if (err) { |
| 583 | unlock_page(page); | 578 | unlock_page(page); |
| 584 | goto fail; | 579 | goto fail; |
diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c index 594480e537d2..428017e018fe 100644 --- a/fs/ufs/ialloc.c +++ b/fs/ufs/ialloc.c | |||
| @@ -94,8 +94,6 @@ void ufs_free_inode (struct inode * inode) | |||
| 94 | 94 | ||
| 95 | is_directory = S_ISDIR(inode->i_mode); | 95 | is_directory = S_ISDIR(inode->i_mode); |
| 96 | 96 | ||
| 97 | clear_inode (inode); | ||
| 98 | |||
| 99 | if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_iusedoff, bit)) | 97 | if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_iusedoff, bit)) |
| 100 | ufs_error(sb, "ufs_free_inode", "bit already cleared for inode %u", ino); | 98 | ufs_error(sb, "ufs_free_inode", "bit already cleared for inode %u", ino); |
| 101 | else { | 99 | else { |
diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 73fe773aa034..2b251f2093af 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c | |||
| @@ -558,20 +558,26 @@ static int ufs_readpage(struct file *file, struct page *page) | |||
| 558 | return block_read_full_page(page,ufs_getfrag_block); | 558 | return block_read_full_page(page,ufs_getfrag_block); |
| 559 | } | 559 | } |
| 560 | 560 | ||
| 561 | int __ufs_write_begin(struct file *file, struct address_space *mapping, | 561 | int ufs_prepare_chunk(struct page *page, loff_t pos, unsigned len) |
| 562 | loff_t pos, unsigned len, unsigned flags, | ||
| 563 | struct page **pagep, void **fsdata) | ||
| 564 | { | 562 | { |
| 565 | return block_write_begin(file, mapping, pos, len, flags, pagep, fsdata, | 563 | return __block_write_begin(page, pos, len, ufs_getfrag_block); |
| 566 | ufs_getfrag_block); | ||
| 567 | } | 564 | } |
| 568 | 565 | ||
| 569 | static int ufs_write_begin(struct file *file, struct address_space *mapping, | 566 | static int ufs_write_begin(struct file *file, struct address_space *mapping, |
| 570 | loff_t pos, unsigned len, unsigned flags, | 567 | loff_t pos, unsigned len, unsigned flags, |
| 571 | struct page **pagep, void **fsdata) | 568 | struct page **pagep, void **fsdata) |
| 572 | { | 569 | { |
| 573 | *pagep = NULL; | 570 | int ret; |
| 574 | return __ufs_write_begin(file, mapping, pos, len, flags, pagep, fsdata); | 571 | |
| 572 | ret = block_write_begin(mapping, pos, len, flags, pagep, | ||
| 573 | ufs_getfrag_block); | ||
| 574 | if (unlikely(ret)) { | ||
| 575 | loff_t isize = mapping->host->i_size; | ||
| 576 | if (pos + len > isize) | ||
| 577 | vmtruncate(mapping->host, isize); | ||
| 578 | } | ||
| 579 | |||
| 580 | return ret; | ||
| 575 | } | 581 | } |
| 576 | 582 | ||
| 577 | static sector_t ufs_bmap(struct address_space *mapping, sector_t block) | 583 | static sector_t ufs_bmap(struct address_space *mapping, sector_t block) |
| @@ -905,24 +911,33 @@ int ufs_sync_inode (struct inode *inode) | |||
| 905 | return ufs_update_inode (inode, 1); | 911 | return ufs_update_inode (inode, 1); |
| 906 | } | 912 | } |
| 907 | 913 | ||
| 908 | void ufs_delete_inode (struct inode * inode) | 914 | void ufs_evict_inode(struct inode * inode) |
| 909 | { | 915 | { |
| 910 | loff_t old_i_size; | 916 | int want_delete = 0; |
| 917 | |||
| 918 | if (!inode->i_nlink && !is_bad_inode(inode)) | ||
| 919 | want_delete = 1; | ||
| 911 | 920 | ||
| 912 | truncate_inode_pages(&inode->i_data, 0); | 921 | truncate_inode_pages(&inode->i_data, 0); |
| 913 | if (is_bad_inode(inode)) | 922 | if (want_delete) { |
| 914 | goto no_delete; | 923 | loff_t old_i_size; |
| 915 | /*UFS_I(inode)->i_dtime = CURRENT_TIME;*/ | 924 | /*UFS_I(inode)->i_dtime = CURRENT_TIME;*/ |
| 916 | lock_kernel(); | 925 | lock_kernel(); |
| 917 | mark_inode_dirty(inode); | 926 | mark_inode_dirty(inode); |
| 918 | ufs_update_inode(inode, IS_SYNC(inode)); | 927 | ufs_update_inode(inode, IS_SYNC(inode)); |
| 919 | old_i_size = inode->i_size; | 928 | old_i_size = inode->i_size; |
| 920 | inode->i_size = 0; | 929 | inode->i_size = 0; |
| 921 | if (inode->i_blocks && ufs_truncate(inode, old_i_size)) | 930 | if (inode->i_blocks && ufs_truncate(inode, old_i_size)) |
| 922 | ufs_warning(inode->i_sb, __func__, "ufs_truncate failed\n"); | 931 | ufs_warning(inode->i_sb, __func__, "ufs_truncate failed\n"); |
| 923 | ufs_free_inode (inode); | 932 | unlock_kernel(); |
| 924 | unlock_kernel(); | 933 | } |
| 925 | return; | 934 | |
| 926 | no_delete: | 935 | invalidate_inode_buffers(inode); |
| 927 | clear_inode(inode); /* We must guarantee clearing of inode... */ | 936 | end_writeback(inode); |
| 937 | |||
| 938 | if (want_delete) { | ||
| 939 | lock_kernel(); | ||
| 940 | ufs_free_inode (inode); | ||
| 941 | unlock_kernel(); | ||
| 942 | } | ||
| 928 | } | 943 | } |
diff --git a/fs/ufs/super.c b/fs/ufs/super.c index 3ec5a9eb6efb..d510c1b91817 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c | |||
| @@ -1440,7 +1440,7 @@ static const struct super_operations ufs_super_ops = { | |||
| 1440 | .alloc_inode = ufs_alloc_inode, | 1440 | .alloc_inode = ufs_alloc_inode, |
| 1441 | .destroy_inode = ufs_destroy_inode, | 1441 | .destroy_inode = ufs_destroy_inode, |
| 1442 | .write_inode = ufs_write_inode, | 1442 | .write_inode = ufs_write_inode, |
| 1443 | .delete_inode = ufs_delete_inode, | 1443 | .evict_inode = ufs_evict_inode, |
| 1444 | .put_super = ufs_put_super, | 1444 | .put_super = ufs_put_super, |
| 1445 | .write_super = ufs_write_super, | 1445 | .write_super = ufs_write_super, |
| 1446 | .sync_fs = ufs_sync_fs, | 1446 | .sync_fs = ufs_sync_fs, |
diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c index 589e01a465ba..34d5cb135320 100644 --- a/fs/ufs/truncate.c +++ b/fs/ufs/truncate.c | |||
| @@ -500,11 +500,6 @@ out: | |||
| 500 | return err; | 500 | return err; |
| 501 | } | 501 | } |
| 502 | 502 | ||
| 503 | /* | ||
| 504 | * TODO: | ||
| 505 | * - truncate case should use proper ordering instead of using | ||
| 506 | * simple_setsize | ||
| 507 | */ | ||
| 508 | int ufs_setattr(struct dentry *dentry, struct iattr *attr) | 503 | int ufs_setattr(struct dentry *dentry, struct iattr *attr) |
| 509 | { | 504 | { |
| 510 | struct inode *inode = dentry->d_inode; | 505 | struct inode *inode = dentry->d_inode; |
| @@ -518,14 +513,17 @@ int ufs_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 518 | if (ia_valid & ATTR_SIZE && attr->ia_size != inode->i_size) { | 513 | if (ia_valid & ATTR_SIZE && attr->ia_size != inode->i_size) { |
| 519 | loff_t old_i_size = inode->i_size; | 514 | loff_t old_i_size = inode->i_size; |
| 520 | 515 | ||
| 521 | error = simple_setsize(inode, attr->ia_size); | 516 | /* XXX(truncate): truncate_setsize should be called last */ |
| 522 | if (error) | 517 | truncate_setsize(inode, attr->ia_size); |
| 523 | return error; | 518 | |
| 524 | error = ufs_truncate(inode, old_i_size); | 519 | error = ufs_truncate(inode, old_i_size); |
| 525 | if (error) | 520 | if (error) |
| 526 | return error; | 521 | return error; |
| 527 | } | 522 | } |
| 528 | return inode_setattr(inode, attr); | 523 | |
| 524 | setattr_copy(inode, attr); | ||
| 525 | mark_inode_dirty(inode); | ||
| 526 | return 0; | ||
| 529 | } | 527 | } |
| 530 | 528 | ||
| 531 | const struct inode_operations ufs_file_inode_operations = { | 529 | const struct inode_operations ufs_file_inode_operations = { |
diff --git a/fs/ufs/ufs.h b/fs/ufs/ufs.h index 179ae6b3180a..c08782e1b48a 100644 --- a/fs/ufs/ufs.h +++ b/fs/ufs/ufs.h | |||
| @@ -108,7 +108,7 @@ extern struct inode * ufs_new_inode (struct inode *, int); | |||
| 108 | extern struct inode *ufs_iget(struct super_block *, unsigned long); | 108 | extern struct inode *ufs_iget(struct super_block *, unsigned long); |
| 109 | extern int ufs_write_inode (struct inode *, struct writeback_control *); | 109 | extern int ufs_write_inode (struct inode *, struct writeback_control *); |
| 110 | extern int ufs_sync_inode (struct inode *); | 110 | extern int ufs_sync_inode (struct inode *); |
| 111 | extern void ufs_delete_inode (struct inode *); | 111 | extern void ufs_evict_inode (struct inode *); |
| 112 | extern struct buffer_head * ufs_bread (struct inode *, unsigned, int, int *); | 112 | extern struct buffer_head * ufs_bread (struct inode *, unsigned, int, int *); |
| 113 | extern int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create); | 113 | extern int ufs_getfrag_block (struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create); |
| 114 | 114 | ||
diff --git a/fs/ufs/util.h b/fs/ufs/util.h index 23ceed8c8fb9..0466036912f1 100644 --- a/fs/ufs/util.h +++ b/fs/ufs/util.h | |||
| @@ -257,9 +257,7 @@ ufs_set_inode_gid(struct super_block *sb, struct ufs_inode *inode, u32 value) | |||
| 257 | 257 | ||
| 258 | extern dev_t ufs_get_inode_dev(struct super_block *, struct ufs_inode_info *); | 258 | extern dev_t ufs_get_inode_dev(struct super_block *, struct ufs_inode_info *); |
| 259 | extern void ufs_set_inode_dev(struct super_block *, struct ufs_inode_info *, dev_t); | 259 | extern void ufs_set_inode_dev(struct super_block *, struct ufs_inode_info *, dev_t); |
| 260 | extern int __ufs_write_begin(struct file *file, struct address_space *mapping, | 260 | extern int ufs_prepare_chunk(struct page *page, loff_t pos, unsigned len); |
| 261 | loff_t pos, unsigned len, unsigned flags, | ||
| 262 | struct page **pagep, void **fsdata); | ||
| 263 | 261 | ||
| 264 | /* | 262 | /* |
| 265 | * These functions manipulate ufs buffers | 263 | * These functions manipulate ufs buffers |
diff --git a/fs/utimes.c b/fs/utimes.c index e4c75db5d373..179b58690657 100644 --- a/fs/utimes.c +++ b/fs/utimes.c | |||
| @@ -126,7 +126,8 @@ out: | |||
| 126 | * must be owner or have write permission. | 126 | * must be owner or have write permission. |
| 127 | * Else, update from *times, must be owner or super user. | 127 | * Else, update from *times, must be owner or super user. |
| 128 | */ | 128 | */ |
| 129 | long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags) | 129 | long do_utimes(int dfd, const char __user *filename, struct timespec *times, |
| 130 | int flags) | ||
| 130 | { | 131 | { |
| 131 | int error = -EINVAL; | 132 | int error = -EINVAL; |
| 132 | 133 | ||
| @@ -170,7 +171,7 @@ out: | |||
| 170 | return error; | 171 | return error; |
| 171 | } | 172 | } |
| 172 | 173 | ||
| 173 | SYSCALL_DEFINE4(utimensat, int, dfd, char __user *, filename, | 174 | SYSCALL_DEFINE4(utimensat, int, dfd, const char __user *, filename, |
| 174 | struct timespec __user *, utimes, int, flags) | 175 | struct timespec __user *, utimes, int, flags) |
| 175 | { | 176 | { |
| 176 | struct timespec tstimes[2]; | 177 | struct timespec tstimes[2]; |
| @@ -188,7 +189,7 @@ SYSCALL_DEFINE4(utimensat, int, dfd, char __user *, filename, | |||
| 188 | return do_utimes(dfd, filename, utimes ? tstimes : NULL, flags); | 189 | return do_utimes(dfd, filename, utimes ? tstimes : NULL, flags); |
| 189 | } | 190 | } |
| 190 | 191 | ||
| 191 | SYSCALL_DEFINE3(futimesat, int, dfd, char __user *, filename, | 192 | SYSCALL_DEFINE3(futimesat, int, dfd, const char __user *, filename, |
| 192 | struct timeval __user *, utimes) | 193 | struct timeval __user *, utimes) |
| 193 | { | 194 | { |
| 194 | struct timeval times[2]; | 195 | struct timeval times[2]; |
diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index d24e78f32f3e..15412fe15c3a 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c | |||
| @@ -1478,22 +1478,38 @@ xfs_vm_direct_IO( | |||
| 1478 | if (rw & WRITE) { | 1478 | if (rw & WRITE) { |
| 1479 | iocb->private = xfs_alloc_ioend(inode, IO_NEW); | 1479 | iocb->private = xfs_alloc_ioend(inode, IO_NEW); |
| 1480 | 1480 | ||
| 1481 | ret = blockdev_direct_IO_no_locking(rw, iocb, inode, bdev, iov, | 1481 | ret = __blockdev_direct_IO(rw, iocb, inode, bdev, iov, |
| 1482 | offset, nr_segs, | 1482 | offset, nr_segs, |
| 1483 | xfs_get_blocks_direct, | 1483 | xfs_get_blocks_direct, |
| 1484 | xfs_end_io_direct_write); | 1484 | xfs_end_io_direct_write, NULL, 0); |
| 1485 | if (ret != -EIOCBQUEUED && iocb->private) | 1485 | if (ret != -EIOCBQUEUED && iocb->private) |
| 1486 | xfs_destroy_ioend(iocb->private); | 1486 | xfs_destroy_ioend(iocb->private); |
| 1487 | } else { | 1487 | } else { |
| 1488 | ret = blockdev_direct_IO_no_locking(rw, iocb, inode, bdev, iov, | 1488 | ret = __blockdev_direct_IO(rw, iocb, inode, bdev, iov, |
| 1489 | offset, nr_segs, | 1489 | offset, nr_segs, |
| 1490 | xfs_get_blocks_direct, | 1490 | xfs_get_blocks_direct, |
| 1491 | NULL); | 1491 | NULL, NULL, 0); |
| 1492 | } | 1492 | } |
| 1493 | 1493 | ||
| 1494 | return ret; | 1494 | return ret; |
| 1495 | } | 1495 | } |
| 1496 | 1496 | ||
| 1497 | STATIC void | ||
| 1498 | xfs_vm_write_failed( | ||
| 1499 | struct address_space *mapping, | ||
| 1500 | loff_t to) | ||
| 1501 | { | ||
| 1502 | struct inode *inode = mapping->host; | ||
| 1503 | |||
| 1504 | if (to > inode->i_size) { | ||
| 1505 | struct iattr ia = { | ||
| 1506 | .ia_valid = ATTR_SIZE | ATTR_FORCE, | ||
| 1507 | .ia_size = inode->i_size, | ||
| 1508 | }; | ||
| 1509 | xfs_setattr(XFS_I(inode), &ia, XFS_ATTR_NOLOCK); | ||
| 1510 | } | ||
| 1511 | } | ||
| 1512 | |||
| 1497 | STATIC int | 1513 | STATIC int |
| 1498 | xfs_vm_write_begin( | 1514 | xfs_vm_write_begin( |
| 1499 | struct file *file, | 1515 | struct file *file, |
| @@ -1504,9 +1520,31 @@ xfs_vm_write_begin( | |||
| 1504 | struct page **pagep, | 1520 | struct page **pagep, |
| 1505 | void **fsdata) | 1521 | void **fsdata) |
| 1506 | { | 1522 | { |
| 1507 | *pagep = NULL; | 1523 | int ret; |
| 1508 | return block_write_begin(file, mapping, pos, len, flags | AOP_FLAG_NOFS, | 1524 | |
| 1509 | pagep, fsdata, xfs_get_blocks); | 1525 | ret = block_write_begin(mapping, pos, len, flags | AOP_FLAG_NOFS, |
| 1526 | pagep, xfs_get_blocks); | ||
| 1527 | if (unlikely(ret)) | ||
| 1528 | xfs_vm_write_failed(mapping, pos + len); | ||
| 1529 | return ret; | ||
| 1530 | } | ||
| 1531 | |||
| 1532 | STATIC int | ||
| 1533 | xfs_vm_write_end( | ||
| 1534 | struct file *file, | ||
| 1535 | struct address_space *mapping, | ||
| 1536 | loff_t pos, | ||
| 1537 | unsigned len, | ||
| 1538 | unsigned copied, | ||
| 1539 | struct page *page, | ||
| 1540 | void *fsdata) | ||
| 1541 | { | ||
| 1542 | int ret; | ||
| 1543 | |||
| 1544 | ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata); | ||
| 1545 | if (unlikely(ret < len)) | ||
| 1546 | xfs_vm_write_failed(mapping, pos + len); | ||
| 1547 | return ret; | ||
| 1510 | } | 1548 | } |
| 1511 | 1549 | ||
| 1512 | STATIC sector_t | 1550 | STATIC sector_t |
| @@ -1551,7 +1589,7 @@ const struct address_space_operations xfs_address_space_operations = { | |||
| 1551 | .releasepage = xfs_vm_releasepage, | 1589 | .releasepage = xfs_vm_releasepage, |
| 1552 | .invalidatepage = xfs_vm_invalidatepage, | 1590 | .invalidatepage = xfs_vm_invalidatepage, |
| 1553 | .write_begin = xfs_vm_write_begin, | 1591 | .write_begin = xfs_vm_write_begin, |
| 1554 | .write_end = generic_write_end, | 1592 | .write_end = xfs_vm_write_end, |
| 1555 | .bmap = xfs_vm_bmap, | 1593 | .bmap = xfs_vm_bmap, |
| 1556 | .direct_IO = xfs_vm_direct_IO, | 1594 | .direct_IO = xfs_vm_direct_IO, |
| 1557 | .migratepage = buffer_migrate_page, | 1595 | .migratepage = buffer_migrate_page, |
diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index 536b81e63a3d..68be25dcd301 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c | |||
| @@ -80,7 +80,7 @@ xfs_mark_inode_dirty_sync( | |||
| 80 | { | 80 | { |
| 81 | struct inode *inode = VFS_I(ip); | 81 | struct inode *inode = VFS_I(ip); |
| 82 | 82 | ||
| 83 | if (!(inode->i_state & (I_WILL_FREE|I_FREEING|I_CLEAR))) | 83 | if (!(inode->i_state & (I_WILL_FREE|I_FREEING))) |
| 84 | mark_inode_dirty_sync(inode); | 84 | mark_inode_dirty_sync(inode); |
| 85 | } | 85 | } |
| 86 | 86 | ||
| @@ -90,7 +90,7 @@ xfs_mark_inode_dirty( | |||
| 90 | { | 90 | { |
| 91 | struct inode *inode = VFS_I(ip); | 91 | struct inode *inode = VFS_I(ip); |
| 92 | 92 | ||
| 93 | if (!(inode->i_state & (I_WILL_FREE|I_FREEING|I_CLEAR))) | 93 | if (!(inode->i_state & (I_WILL_FREE|I_FREEING))) |
| 94 | mark_inode_dirty(inode); | 94 | mark_inode_dirty(inode); |
| 95 | } | 95 | } |
| 96 | 96 | ||
| @@ -540,21 +540,6 @@ xfs_vn_setattr( | |||
| 540 | return -xfs_setattr(XFS_I(dentry->d_inode), iattr, 0); | 540 | return -xfs_setattr(XFS_I(dentry->d_inode), iattr, 0); |
| 541 | } | 541 | } |
| 542 | 542 | ||
| 543 | /* | ||
| 544 | * block_truncate_page can return an error, but we can't propagate it | ||
| 545 | * at all here. Leave a complaint + stack trace in the syslog because | ||
| 546 | * this could be bad. If it is bad, we need to propagate the error further. | ||
| 547 | */ | ||
| 548 | STATIC void | ||
| 549 | xfs_vn_truncate( | ||
| 550 | struct inode *inode) | ||
| 551 | { | ||
| 552 | int error; | ||
| 553 | error = block_truncate_page(inode->i_mapping, inode->i_size, | ||
| 554 | xfs_get_blocks); | ||
| 555 | WARN_ON(error); | ||
| 556 | } | ||
| 557 | |||
| 558 | STATIC long | 543 | STATIC long |
| 559 | xfs_vn_fallocate( | 544 | xfs_vn_fallocate( |
| 560 | struct inode *inode, | 545 | struct inode *inode, |
| @@ -694,7 +679,6 @@ xfs_vn_fiemap( | |||
| 694 | 679 | ||
| 695 | static const struct inode_operations xfs_inode_operations = { | 680 | static const struct inode_operations xfs_inode_operations = { |
| 696 | .check_acl = xfs_check_acl, | 681 | .check_acl = xfs_check_acl, |
| 697 | .truncate = xfs_vn_truncate, | ||
| 698 | .getattr = xfs_vn_getattr, | 682 | .getattr = xfs_vn_getattr, |
| 699 | .setattr = xfs_vn_setattr, | 683 | .setattr = xfs_vn_setattr, |
| 700 | .setxattr = generic_setxattr, | 684 | .setxattr = generic_setxattr, |
diff --git a/fs/xfs/linux-2.6/xfs_linux.h b/fs/xfs/linux-2.6/xfs_linux.h index 998a9d7fb9c8..2fa0bd9ebc7f 100644 --- a/fs/xfs/linux-2.6/xfs_linux.h +++ b/fs/xfs/linux-2.6/xfs_linux.h | |||
| @@ -156,8 +156,6 @@ | |||
| 156 | */ | 156 | */ |
| 157 | #define xfs_sort(a,n,s,fn) sort(a,n,s,fn,NULL) | 157 | #define xfs_sort(a,n,s,fn) sort(a,n,s,fn,NULL) |
| 158 | #define xfs_stack_trace() dump_stack() | 158 | #define xfs_stack_trace() dump_stack() |
| 159 | #define xfs_itruncate_data(ip, off) \ | ||
| 160 | (-vmtruncate(VFS_I(ip), (off))) | ||
| 161 | 159 | ||
| 162 | 160 | ||
| 163 | /* Move the kernel do_div definition off to one side */ | 161 | /* Move the kernel do_div definition off to one side */ |
diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 758df94690ed..15c35b62ff14 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c | |||
| @@ -1100,13 +1100,15 @@ xfs_fs_write_inode( | |||
| 1100 | } | 1100 | } |
| 1101 | 1101 | ||
| 1102 | STATIC void | 1102 | STATIC void |
| 1103 | xfs_fs_clear_inode( | 1103 | xfs_fs_evict_inode( |
| 1104 | struct inode *inode) | 1104 | struct inode *inode) |
| 1105 | { | 1105 | { |
| 1106 | xfs_inode_t *ip = XFS_I(inode); | 1106 | xfs_inode_t *ip = XFS_I(inode); |
| 1107 | 1107 | ||
| 1108 | trace_xfs_clear_inode(ip); | 1108 | trace_xfs_evict_inode(ip); |
| 1109 | 1109 | ||
| 1110 | truncate_inode_pages(&inode->i_data, 0); | ||
| 1111 | end_writeback(inode); | ||
| 1110 | XFS_STATS_INC(vn_rele); | 1112 | XFS_STATS_INC(vn_rele); |
| 1111 | XFS_STATS_INC(vn_remove); | 1113 | XFS_STATS_INC(vn_remove); |
| 1112 | XFS_STATS_DEC(vn_active); | 1114 | XFS_STATS_DEC(vn_active); |
| @@ -1622,7 +1624,7 @@ static const struct super_operations xfs_super_operations = { | |||
| 1622 | .destroy_inode = xfs_fs_destroy_inode, | 1624 | .destroy_inode = xfs_fs_destroy_inode, |
| 1623 | .dirty_inode = xfs_fs_dirty_inode, | 1625 | .dirty_inode = xfs_fs_dirty_inode, |
| 1624 | .write_inode = xfs_fs_write_inode, | 1626 | .write_inode = xfs_fs_write_inode, |
| 1625 | .clear_inode = xfs_fs_clear_inode, | 1627 | .evict_inode = xfs_fs_evict_inode, |
| 1626 | .put_super = xfs_fs_put_super, | 1628 | .put_super = xfs_fs_put_super, |
| 1627 | .sync_fs = xfs_fs_sync_fs, | 1629 | .sync_fs = xfs_fs_sync_fs, |
| 1628 | .freeze_fs = xfs_fs_freeze, | 1630 | .freeze_fs = xfs_fs_freeze, |
diff --git a/fs/xfs/linux-2.6/xfs_trace.h b/fs/xfs/linux-2.6/xfs_trace.h index c657cdca2cd2..be5dffd282a1 100644 --- a/fs/xfs/linux-2.6/xfs_trace.h +++ b/fs/xfs/linux-2.6/xfs_trace.h | |||
| @@ -581,7 +581,7 @@ DEFINE_INODE_EVENT(xfs_ioctl_setattr); | |||
| 581 | DEFINE_INODE_EVENT(xfs_file_fsync); | 581 | DEFINE_INODE_EVENT(xfs_file_fsync); |
| 582 | DEFINE_INODE_EVENT(xfs_destroy_inode); | 582 | DEFINE_INODE_EVENT(xfs_destroy_inode); |
| 583 | DEFINE_INODE_EVENT(xfs_write_inode); | 583 | DEFINE_INODE_EVENT(xfs_write_inode); |
| 584 | DEFINE_INODE_EVENT(xfs_clear_inode); | 584 | DEFINE_INODE_EVENT(xfs_evict_inode); |
| 585 | 585 | ||
| 586 | DEFINE_INODE_EVENT(xfs_dquot_dqalloc); | 586 | DEFINE_INODE_EVENT(xfs_dquot_dqalloc); |
| 587 | DEFINE_INODE_EVENT(xfs_dquot_dqdetach); | 587 | DEFINE_INODE_EVENT(xfs_dquot_dqdetach); |
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 3ac137dd531b..66d585c6917c 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c | |||
| @@ -221,8 +221,11 @@ xfs_setattr( | |||
| 221 | * transaction to modify the i_size. | 221 | * transaction to modify the i_size. |
| 222 | */ | 222 | */ |
| 223 | code = xfs_zero_eof(ip, iattr->ia_size, ip->i_size); | 223 | code = xfs_zero_eof(ip, iattr->ia_size, ip->i_size); |
| 224 | if (code) | ||
| 225 | goto error_return; | ||
| 224 | } | 226 | } |
| 225 | xfs_iunlock(ip, XFS_ILOCK_EXCL); | 227 | xfs_iunlock(ip, XFS_ILOCK_EXCL); |
| 228 | lock_flags &= ~XFS_ILOCK_EXCL; | ||
| 226 | 229 | ||
| 227 | /* | 230 | /* |
| 228 | * We are going to log the inode size change in this | 231 | * We are going to log the inode size change in this |
| @@ -236,36 +239,35 @@ xfs_setattr( | |||
| 236 | * really care about here and prevents waiting for other data | 239 | * really care about here and prevents waiting for other data |
| 237 | * not within the range we care about here. | 240 | * not within the range we care about here. |
| 238 | */ | 241 | */ |
| 239 | if (!code && | 242 | if (ip->i_size != ip->i_d.di_size && |
| 240 | ip->i_size != ip->i_d.di_size && | ||
| 241 | iattr->ia_size > ip->i_d.di_size) { | 243 | iattr->ia_size > ip->i_d.di_size) { |
| 242 | code = xfs_flush_pages(ip, | 244 | code = xfs_flush_pages(ip, |
| 243 | ip->i_d.di_size, iattr->ia_size, | 245 | ip->i_d.di_size, iattr->ia_size, |
| 244 | XBF_ASYNC, FI_NONE); | 246 | XBF_ASYNC, FI_NONE); |
| 247 | if (code) | ||
| 248 | goto error_return; | ||
| 245 | } | 249 | } |
| 246 | 250 | ||
| 247 | /* wait for all I/O to complete */ | 251 | /* wait for all I/O to complete */ |
| 248 | xfs_ioend_wait(ip); | 252 | xfs_ioend_wait(ip); |
| 249 | 253 | ||
| 250 | if (!code) | 254 | code = -block_truncate_page(inode->i_mapping, iattr->ia_size, |
| 251 | code = xfs_itruncate_data(ip, iattr->ia_size); | 255 | xfs_get_blocks); |
| 252 | if (code) { | 256 | if (code) |
| 253 | ASSERT(tp == NULL); | ||
| 254 | lock_flags &= ~XFS_ILOCK_EXCL; | ||
| 255 | ASSERT(lock_flags == XFS_IOLOCK_EXCL || !need_iolock); | ||
| 256 | goto error_return; | 257 | goto error_return; |
| 257 | } | 258 | |
| 258 | tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_SIZE); | 259 | tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_SIZE); |
| 259 | if ((code = xfs_trans_reserve(tp, 0, | 260 | code = xfs_trans_reserve(tp, 0, XFS_ITRUNCATE_LOG_RES(mp), 0, |
| 260 | XFS_ITRUNCATE_LOG_RES(mp), 0, | 261 | XFS_TRANS_PERM_LOG_RES, |
| 261 | XFS_TRANS_PERM_LOG_RES, | 262 | XFS_ITRUNCATE_LOG_COUNT); |
| 262 | XFS_ITRUNCATE_LOG_COUNT))) { | 263 | if (code) |
| 263 | xfs_trans_cancel(tp, 0); | 264 | goto error_return; |
| 264 | if (need_iolock) | 265 | |
| 265 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); | 266 | truncate_setsize(inode, iattr->ia_size); |
| 266 | return code; | 267 | |
| 267 | } | ||
| 268 | commit_flags = XFS_TRANS_RELEASE_LOG_RES; | 268 | commit_flags = XFS_TRANS_RELEASE_LOG_RES; |
| 269 | lock_flags |= XFS_ILOCK_EXCL; | ||
| 270 | |||
| 269 | xfs_ilock(ip, XFS_ILOCK_EXCL); | 271 | xfs_ilock(ip, XFS_ILOCK_EXCL); |
| 270 | 272 | ||
| 271 | xfs_trans_ijoin(tp, ip); | 273 | xfs_trans_ijoin(tp, ip); |
