diff options
Diffstat (limited to 'fs/exofs/inode.c')
-rw-r--r-- | fs/exofs/inode.c | 127 |
1 files changed, 53 insertions, 74 deletions
diff --git a/fs/exofs/inode.c b/fs/exofs/inode.c index 4bb6ef822e46..088cb476b68a 100644 --- a/fs/exofs/inode.c +++ b/fs/exofs/inode.c | |||
@@ -697,6 +697,13 @@ static int exofs_writepage(struct page *page, struct writeback_control *wbc) | |||
697 | return write_exec(&pcol); | 697 | return write_exec(&pcol); |
698 | } | 698 | } |
699 | 699 | ||
700 | /* i_mutex held using inode->i_size directly */ | ||
701 | static void _write_failed(struct inode *inode, loff_t to) | ||
702 | { | ||
703 | if (to > inode->i_size) | ||
704 | truncate_pagecache(inode, to, inode->i_size); | ||
705 | } | ||
706 | |||
700 | int exofs_write_begin(struct file *file, struct address_space *mapping, | 707 | int exofs_write_begin(struct file *file, struct address_space *mapping, |
701 | loff_t pos, unsigned len, unsigned flags, | 708 | loff_t pos, unsigned len, unsigned flags, |
702 | struct page **pagep, void **fsdata) | 709 | struct page **pagep, void **fsdata) |
@@ -710,7 +717,7 @@ int exofs_write_begin(struct file *file, struct address_space *mapping, | |||
710 | fsdata); | 717 | fsdata); |
711 | if (ret) { | 718 | if (ret) { |
712 | EXOFS_DBGMSG("simple_write_begin faild\n"); | 719 | EXOFS_DBGMSG("simple_write_begin faild\n"); |
713 | return ret; | 720 | goto out; |
714 | } | 721 | } |
715 | 722 | ||
716 | page = *pagep; | 723 | page = *pagep; |
@@ -725,6 +732,9 @@ int exofs_write_begin(struct file *file, struct address_space *mapping, | |||
725 | EXOFS_DBGMSG("__readpage_filler faild\n"); | 732 | EXOFS_DBGMSG("__readpage_filler faild\n"); |
726 | } | 733 | } |
727 | } | 734 | } |
735 | out: | ||
736 | if (unlikely(ret)) | ||
737 | _write_failed(mapping->host, pos + len); | ||
728 | 738 | ||
729 | return ret; | 739 | return ret; |
730 | } | 740 | } |
@@ -750,6 +760,10 @@ static int exofs_write_end(struct file *file, struct address_space *mapping, | |||
750 | int ret; | 760 | int ret; |
751 | 761 | ||
752 | ret = simple_write_end(file, mapping,pos, len, copied, page, fsdata); | 762 | ret = simple_write_end(file, mapping,pos, len, copied, page, fsdata); |
763 | if (unlikely(ret)) | ||
764 | _write_failed(inode, pos + len); | ||
765 | |||
766 | /* TODO: once simple_write_end marks inode dirty remove */ | ||
753 | if (i_size != inode->i_size) | 767 | if (i_size != inode->i_size) |
754 | mark_inode_dirty(inode); | 768 | mark_inode_dirty(inode); |
755 | return ret; | 769 | return ret; |
@@ -808,87 +822,55 @@ static inline int exofs_inode_is_fast_symlink(struct inode *inode) | |||
808 | return S_ISLNK(inode->i_mode) && (oi->i_data[0] != 0); | 822 | return S_ISLNK(inode->i_mode) && (oi->i_data[0] != 0); |
809 | } | 823 | } |
810 | 824 | ||
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( | 825 | const struct osd_attr g_attr_logical_length = ATTR_DEF( |
826 | OSD_APAGE_OBJECT_INFORMATION, OSD_ATTR_OI_LOGICAL_LENGTH, 8); | 826 | OSD_APAGE_OBJECT_INFORMATION, OSD_ATTR_OI_LOGICAL_LENGTH, 8); |
827 | 827 | ||
828 | static int _do_truncate(struct inode *inode) | 828 | static int _do_truncate(struct inode *inode, loff_t newsize) |
829 | { | 829 | { |
830 | struct exofs_i_info *oi = exofs_i(inode); | 830 | struct exofs_i_info *oi = exofs_i(inode); |
831 | loff_t isize = i_size_read(inode); | ||
832 | int ret; | 831 | int ret; |
833 | 832 | ||
834 | inode->i_mtime = inode->i_ctime = CURRENT_TIME; | 833 | inode->i_mtime = inode->i_ctime = CURRENT_TIME; |
835 | 834 | ||
836 | nobh_truncate_page(inode->i_mapping, isize, exofs_get_block); | 835 | ret = exofs_oi_truncate(oi, (u64)newsize); |
836 | if (likely(!ret)) | ||
837 | truncate_setsize(inode, newsize); | ||
837 | 838 | ||
838 | ret = exofs_oi_truncate(oi, (u64)isize); | 839 | EXOFS_DBGMSG("(0x%lx) size=0x%llx ret=>%d\n", |
839 | EXOFS_DBGMSG("(0x%lx) size=0x%llx\n", inode->i_ino, isize); | 840 | inode->i_ino, newsize, ret); |
840 | return ret; | 841 | return ret; |
841 | } | 842 | } |
842 | 843 | ||
843 | /* | 844 | /* |
844 | * Truncate a file to the specified size - all we have to do is set the size | 845 | * Set inode attributes - update size attribute on OSD if needed, |
845 | * attribute. We make sure the object exists first. | 846 | * 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 | */ | 847 | */ |
881 | int exofs_setattr(struct dentry *dentry, struct iattr *iattr) | 848 | int exofs_setattr(struct dentry *dentry, struct iattr *iattr) |
882 | { | 849 | { |
883 | struct inode *inode = dentry->d_inode; | 850 | struct inode *inode = dentry->d_inode; |
884 | int error; | 851 | int error; |
885 | 852 | ||
853 | /* if we are about to modify an object, and it hasn't been | ||
854 | * created yet, wait | ||
855 | */ | ||
856 | error = wait_obj_created(exofs_i(inode)); | ||
857 | if (unlikely(error)) | ||
858 | return error; | ||
859 | |||
886 | error = inode_change_ok(inode, iattr); | 860 | error = inode_change_ok(inode, iattr); |
887 | if (error) | 861 | if (unlikely(error)) |
888 | return error; | 862 | return error; |
889 | 863 | ||
890 | error = inode_setattr(inode, iattr); | 864 | if ((iattr->ia_valid & ATTR_SIZE) && |
891 | return error; | 865 | iattr->ia_size != i_size_read(inode)) { |
866 | error = _do_truncate(inode, iattr->ia_size); | ||
867 | if (unlikely(error)) | ||
868 | return error; | ||
869 | } | ||
870 | |||
871 | setattr_copy(inode, iattr); | ||
872 | mark_inode_dirty(inode); | ||
873 | return 0; | ||
892 | } | 874 | } |
893 | 875 | ||
894 | static const struct osd_attr g_attr_inode_file_layout = ATTR_DEF( | 876 | static const struct osd_attr g_attr_inode_file_layout = ATTR_DEF( |
@@ -1325,7 +1307,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 | 1307 | * from the OSD here. We make sure the object was created before we try and |
1326 | * delete it. | 1308 | * delete it. |
1327 | */ | 1309 | */ |
1328 | void exofs_delete_inode(struct inode *inode) | 1310 | void exofs_evict_inode(struct inode *inode) |
1329 | { | 1311 | { |
1330 | struct exofs_i_info *oi = exofs_i(inode); | 1312 | struct exofs_i_info *oi = exofs_i(inode); |
1331 | struct super_block *sb = inode->i_sb; | 1313 | struct super_block *sb = inode->i_sb; |
@@ -1335,30 +1317,27 @@ void exofs_delete_inode(struct inode *inode) | |||
1335 | 1317 | ||
1336 | truncate_inode_pages(&inode->i_data, 0); | 1318 | truncate_inode_pages(&inode->i_data, 0); |
1337 | 1319 | ||
1338 | if (is_bad_inode(inode)) | 1320 | /* TODO: should do better here */ |
1321 | if (inode->i_nlink || is_bad_inode(inode)) | ||
1339 | goto no_delete; | 1322 | goto no_delete; |
1340 | 1323 | ||
1341 | mark_inode_dirty(inode); | ||
1342 | exofs_update_inode(inode, inode_needs_sync(inode)); | ||
1343 | |||
1344 | inode->i_size = 0; | 1324 | inode->i_size = 0; |
1345 | if (inode->i_blocks) | 1325 | end_writeback(inode); |
1346 | exofs_truncate(inode); | ||
1347 | 1326 | ||
1348 | clear_inode(inode); | 1327 | /* if we are deleting an obj that hasn't been created yet, wait */ |
1328 | if (!obj_created(oi)) { | ||
1329 | BUG_ON(!obj_2bcreated(oi)); | ||
1330 | wait_event(oi->i_wq, obj_created(oi)); | ||
1331 | /* ignore the error attempt a remove anyway */ | ||
1332 | } | ||
1349 | 1333 | ||
1334 | /* Now Remove the OSD objects */ | ||
1350 | ret = exofs_get_io_state(&sbi->layout, &ios); | 1335 | ret = exofs_get_io_state(&sbi->layout, &ios); |
1351 | if (unlikely(ret)) { | 1336 | if (unlikely(ret)) { |
1352 | EXOFS_ERR("%s: exofs_get_io_state failed\n", __func__); | 1337 | EXOFS_ERR("%s: exofs_get_io_state failed\n", __func__); |
1353 | return; | 1338 | return; |
1354 | } | 1339 | } |
1355 | 1340 | ||
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); | 1341 | ios->obj.id = exofs_oi_objno(oi); |
1363 | ios->done = delete_done; | 1342 | ios->done = delete_done; |
1364 | ios->private = sbi; | 1343 | ios->private = sbi; |
@@ -1374,5 +1353,5 @@ void exofs_delete_inode(struct inode *inode) | |||
1374 | return; | 1353 | return; |
1375 | 1354 | ||
1376 | no_delete: | 1355 | no_delete: |
1377 | clear_inode(inode); | 1356 | end_writeback(inode); |
1378 | } | 1357 | } |