aboutsummaryrefslogtreecommitdiffstats
path: root/fs/udf
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2009-03-16 13:27:37 -0400
committerJan Kara <jack@suse.cz>2009-04-02 07:36:28 -0400
commit146bca72c7e6ba52de82a63b1fce7934dc103dbc (patch)
treefee0aff001a5d5226518f0b67232f083f0931209 /fs/udf
parent40346005166329bc4b53e0c564aff3968c1ddaa0 (diff)
udf: Don't write integrity descriptor too often
We update information in logical volume integrity descriptor after each allocation (as LVID contains free space, number of directories and files on disk etc.). If the filesystem is on some phase change media, this leads to its quick degradation as such media is able to handle only 10000 overwrites or so. We solve the problem by writing new information into LVID only on umount, remount-ro and sync. This solves the problem at the price of longer media inconsistency (previously media became consistent after pdflush flushed dirty LVID buffer) but that should be acceptable. Report by and patch written in cooperation with Rich Coe <Richard.Coe@med.ge.com>. Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs/udf')
-rw-r--r--fs/udf/balloc.c37
-rw-r--r--fs/udf/ialloc.c5
-rw-r--r--fs/udf/super.c44
-rw-r--r--fs/udf/udf_sb.h2
-rw-r--r--fs/udf/udfdecl.h11
5 files changed, 52 insertions, 47 deletions
diff --git a/fs/udf/balloc.c b/fs/udf/balloc.c
index 58be702cb42d..e48e9a3af763 100644
--- a/fs/udf/balloc.c
+++ b/fs/udf/balloc.c
@@ -140,17 +140,17 @@ static inline int load_block_bitmap(struct super_block *sb,
140 return slot; 140 return slot;
141} 141}
142 142
143static bool udf_add_free_space(struct udf_sb_info *sbi, 143static void udf_add_free_space(struct super_block *sb, u16 partition, u32 cnt)
144 u16 partition, u32 cnt)
145{ 144{
145 struct udf_sb_info *sbi = UDF_SB(sb);
146 struct logicalVolIntegrityDesc *lvid; 146 struct logicalVolIntegrityDesc *lvid;
147 147
148 if (sbi->s_lvid_bh == NULL) 148 if (!sbi->s_lvid_bh)
149 return false; 149 return;
150 150
151 lvid = (struct logicalVolIntegrityDesc *)sbi->s_lvid_bh->b_data; 151 lvid = (struct logicalVolIntegrityDesc *)sbi->s_lvid_bh->b_data;
152 le32_add_cpu(&lvid->freeSpaceTable[partition], cnt); 152 le32_add_cpu(&lvid->freeSpaceTable[partition], cnt);
153 return true; 153 udf_updated_lvid(sb);
154} 154}
155 155
156static void udf_bitmap_free_blocks(struct super_block *sb, 156static void udf_bitmap_free_blocks(struct super_block *sb,
@@ -209,7 +209,7 @@ static void udf_bitmap_free_blocks(struct super_block *sb,
209 } else { 209 } else {
210 if (inode) 210 if (inode)
211 vfs_dq_free_block(inode, 1); 211 vfs_dq_free_block(inode, 1);
212 udf_add_free_space(sbi, sbi->s_partition, 1); 212 udf_add_free_space(sb, sbi->s_partition, 1);
213 } 213 }
214 } 214 }
215 mark_buffer_dirty(bh); 215 mark_buffer_dirty(bh);
@@ -220,9 +220,6 @@ static void udf_bitmap_free_blocks(struct super_block *sb,
220 } while (overflow); 220 } while (overflow);
221 221
222error_return: 222error_return:
223 sb->s_dirt = 1;
224 if (sbi->s_lvid_bh)
225 mark_buffer_dirty(sbi->s_lvid_bh);
226 mutex_unlock(&sbi->s_alloc_mutex); 223 mutex_unlock(&sbi->s_alloc_mutex);
227} 224}
228 225
@@ -279,9 +276,7 @@ static int udf_bitmap_prealloc_blocks(struct super_block *sb,
279 } while (block_count > 0); 276 } while (block_count > 0);
280 277
281out: 278out:
282 if (udf_add_free_space(sbi, partition, -alloc_count)) 279 udf_add_free_space(sb, partition, -alloc_count);
283 mark_buffer_dirty(sbi->s_lvid_bh);
284 sb->s_dirt = 1;
285 mutex_unlock(&sbi->s_alloc_mutex); 280 mutex_unlock(&sbi->s_alloc_mutex);
286 return alloc_count; 281 return alloc_count;
287} 282}
@@ -411,9 +406,7 @@ got_block:
411 406
412 mark_buffer_dirty(bh); 407 mark_buffer_dirty(bh);
413 408
414 if (udf_add_free_space(sbi, partition, -1)) 409 udf_add_free_space(sb, partition, -1);
415 mark_buffer_dirty(sbi->s_lvid_bh);
416 sb->s_dirt = 1;
417 mutex_unlock(&sbi->s_alloc_mutex); 410 mutex_unlock(&sbi->s_alloc_mutex);
418 *err = 0; 411 *err = 0;
419 return newblock; 412 return newblock;
@@ -457,8 +450,7 @@ static void udf_table_free_blocks(struct super_block *sb,
457 could occure, but.. oh well */ 450 could occure, but.. oh well */
458 if (inode) 451 if (inode)
459 vfs_dq_free_block(inode, count); 452 vfs_dq_free_block(inode, count);
460 if (udf_add_free_space(sbi, sbi->s_partition, count)) 453 udf_add_free_space(sb, sbi->s_partition, count);
461 mark_buffer_dirty(sbi->s_lvid_bh);
462 454
463 start = bloc->logicalBlockNum + offset; 455 start = bloc->logicalBlockNum + offset;
464 end = bloc->logicalBlockNum + offset + count - 1; 456 end = bloc->logicalBlockNum + offset + count - 1;
@@ -657,7 +649,6 @@ static void udf_table_free_blocks(struct super_block *sb,
657 brelse(oepos.bh); 649 brelse(oepos.bh);
658 650
659error_return: 651error_return:
660 sb->s_dirt = 1;
661 mutex_unlock(&sbi->s_alloc_mutex); 652 mutex_unlock(&sbi->s_alloc_mutex);
662 return; 653 return;
663} 654}
@@ -722,10 +713,8 @@ static int udf_table_prealloc_blocks(struct super_block *sb,
722 713
723 brelse(epos.bh); 714 brelse(epos.bh);
724 715
725 if (alloc_count && udf_add_free_space(sbi, partition, -alloc_count)) { 716 if (alloc_count)
726 mark_buffer_dirty(sbi->s_lvid_bh); 717 udf_add_free_space(sb, partition, -alloc_count);
727 sb->s_dirt = 1;
728 }
729 mutex_unlock(&sbi->s_alloc_mutex); 718 mutex_unlock(&sbi->s_alloc_mutex);
730 return alloc_count; 719 return alloc_count;
731} 720}
@@ -823,10 +812,8 @@ static int udf_table_new_block(struct super_block *sb,
823 udf_delete_aext(table, goal_epos, goal_eloc, goal_elen); 812 udf_delete_aext(table, goal_epos, goal_eloc, goal_elen);
824 brelse(goal_epos.bh); 813 brelse(goal_epos.bh);
825 814
826 if (udf_add_free_space(sbi, partition, -1)) 815 udf_add_free_space(sb, partition, -1);
827 mark_buffer_dirty(sbi->s_lvid_bh);
828 816
829 sb->s_dirt = 1;
830 mutex_unlock(&sbi->s_alloc_mutex); 817 mutex_unlock(&sbi->s_alloc_mutex);
831 *err = 0; 818 *err = 0;
832 return newblock; 819 return newblock;
diff --git a/fs/udf/ialloc.c b/fs/udf/ialloc.c
index 6eb279d5f4fb..c10fa39f97e2 100644
--- a/fs/udf/ialloc.c
+++ b/fs/udf/ialloc.c
@@ -49,8 +49,7 @@ void udf_free_inode(struct inode *inode)
49 le32_add_cpu(&lvidiu->numDirs, -1); 49 le32_add_cpu(&lvidiu->numDirs, -1);
50 else 50 else
51 le32_add_cpu(&lvidiu->numFiles, -1); 51 le32_add_cpu(&lvidiu->numFiles, -1);
52 52 udf_updated_lvid(sb);
53 mark_buffer_dirty(sbi->s_lvid_bh);
54 } 53 }
55 mutex_unlock(&sbi->s_alloc_mutex); 54 mutex_unlock(&sbi->s_alloc_mutex);
56 55
@@ -122,7 +121,7 @@ struct inode *udf_new_inode(struct inode *dir, int mode, int *err)
122 if (!(++uniqueID & 0x00000000FFFFFFFFUL)) 121 if (!(++uniqueID & 0x00000000FFFFFFFFUL))
123 uniqueID += 16; 122 uniqueID += 16;
124 lvhd->uniqueID = cpu_to_le64(uniqueID); 123 lvhd->uniqueID = cpu_to_le64(uniqueID);
125 mark_buffer_dirty(sbi->s_lvid_bh); 124 udf_updated_lvid(sb);
126 } 125 }
127 mutex_unlock(&sbi->s_alloc_mutex); 126 mutex_unlock(&sbi->s_alloc_mutex);
128 inode->i_mode = mode; 127 inode->i_mode = mode;
diff --git a/fs/udf/super.c b/fs/udf/super.c
index cae079eb5dd9..72348cc855a4 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -81,7 +81,7 @@ static char error_buf[1024];
81/* These are the "meat" - everything else is stuffing */ 81/* These are the "meat" - everything else is stuffing */
82static int udf_fill_super(struct super_block *, void *, int); 82static int udf_fill_super(struct super_block *, void *, int);
83static void udf_put_super(struct super_block *); 83static void udf_put_super(struct super_block *);
84static void udf_write_super(struct super_block *); 84static int udf_sync_fs(struct super_block *, int);
85static int udf_remount_fs(struct super_block *, int *, char *); 85static int udf_remount_fs(struct super_block *, int *, char *);
86static void udf_load_logicalvolint(struct super_block *, struct kernel_extent_ad); 86static void udf_load_logicalvolint(struct super_block *, struct kernel_extent_ad);
87static int udf_find_fileset(struct super_block *, struct kernel_lb_addr *, 87static int udf_find_fileset(struct super_block *, struct kernel_lb_addr *,
@@ -178,7 +178,7 @@ static const struct super_operations udf_sb_ops = {
178 .delete_inode = udf_delete_inode, 178 .delete_inode = udf_delete_inode,
179 .clear_inode = udf_clear_inode, 179 .clear_inode = udf_clear_inode,
180 .put_super = udf_put_super, 180 .put_super = udf_put_super,
181 .write_super = udf_write_super, 181 .sync_fs = udf_sync_fs,
182 .statfs = udf_statfs, 182 .statfs = udf_statfs,
183 .remount_fs = udf_remount_fs, 183 .remount_fs = udf_remount_fs,
184 .show_options = udf_show_options, 184 .show_options = udf_show_options,
@@ -553,17 +553,6 @@ static int udf_parse_options(char *options, struct udf_options *uopt,
553 return 1; 553 return 1;
554} 554}
555 555
556static void udf_write_super(struct super_block *sb)
557{
558 lock_kernel();
559
560 if (!(sb->s_flags & MS_RDONLY))
561 udf_open_lvid(sb);
562 sb->s_dirt = 0;
563
564 unlock_kernel();
565}
566
567static int udf_remount_fs(struct super_block *sb, int *flags, char *options) 556static int udf_remount_fs(struct super_block *sb, int *flags, char *options)
568{ 557{
569 struct udf_options uopt; 558 struct udf_options uopt;
@@ -1753,9 +1742,9 @@ static void udf_open_lvid(struct super_block *sb)
1753 struct buffer_head *bh = sbi->s_lvid_bh; 1742 struct buffer_head *bh = sbi->s_lvid_bh;
1754 struct logicalVolIntegrityDesc *lvid; 1743 struct logicalVolIntegrityDesc *lvid;
1755 struct logicalVolIntegrityDescImpUse *lvidiu; 1744 struct logicalVolIntegrityDescImpUse *lvidiu;
1745
1756 if (!bh) 1746 if (!bh)
1757 return; 1747 return;
1758
1759 lvid = (struct logicalVolIntegrityDesc *)bh->b_data; 1748 lvid = (struct logicalVolIntegrityDesc *)bh->b_data;
1760 lvidiu = udf_sb_lvidiu(sbi); 1749 lvidiu = udf_sb_lvidiu(sbi);
1761 1750
@@ -1763,7 +1752,7 @@ static void udf_open_lvid(struct super_block *sb)
1763 lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; 1752 lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
1764 udf_time_to_disk_stamp(&lvid->recordingDateAndTime, 1753 udf_time_to_disk_stamp(&lvid->recordingDateAndTime,
1765 CURRENT_TIME); 1754 CURRENT_TIME);
1766 lvid->integrityType = LVID_INTEGRITY_TYPE_OPEN; 1755 lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_OPEN);
1767 1756
1768 lvid->descTag.descCRC = cpu_to_le16( 1757 lvid->descTag.descCRC = cpu_to_le16(
1769 crc_itu_t(0, (char *)lvid + sizeof(struct tag), 1758 crc_itu_t(0, (char *)lvid + sizeof(struct tag),
@@ -1771,6 +1760,7 @@ static void udf_open_lvid(struct super_block *sb)
1771 1760
1772 lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag); 1761 lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag);
1773 mark_buffer_dirty(bh); 1762 mark_buffer_dirty(bh);
1763 sbi->s_lvid_dirty = 0;
1774} 1764}
1775 1765
1776static void udf_close_lvid(struct super_block *sb) 1766static void udf_close_lvid(struct super_block *sb)
@@ -1784,10 +1774,6 @@ static void udf_close_lvid(struct super_block *sb)
1784 return; 1774 return;
1785 1775
1786 lvid = (struct logicalVolIntegrityDesc *)bh->b_data; 1776 lvid = (struct logicalVolIntegrityDesc *)bh->b_data;
1787
1788 if (lvid->integrityType != LVID_INTEGRITY_TYPE_OPEN)
1789 return;
1790
1791 lvidiu = udf_sb_lvidiu(sbi); 1777 lvidiu = udf_sb_lvidiu(sbi);
1792 lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; 1778 lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
1793 lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; 1779 lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
@@ -1806,6 +1792,7 @@ static void udf_close_lvid(struct super_block *sb)
1806 1792
1807 lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag); 1793 lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag);
1808 mark_buffer_dirty(bh); 1794 mark_buffer_dirty(bh);
1795 sbi->s_lvid_dirty = 0;
1809} 1796}
1810 1797
1811static void udf_sb_free_bitmap(struct udf_bitmap *bitmap) 1798static void udf_sb_free_bitmap(struct udf_bitmap *bitmap)
@@ -2092,6 +2079,25 @@ static void udf_put_super(struct super_block *sb)
2092 sb->s_fs_info = NULL; 2079 sb->s_fs_info = NULL;
2093} 2080}
2094 2081
2082static int udf_sync_fs(struct super_block *sb, int wait)
2083{
2084 struct udf_sb_info *sbi = UDF_SB(sb);
2085
2086 mutex_lock(&sbi->s_alloc_mutex);
2087 if (sbi->s_lvid_dirty) {
2088 /*
2089 * Blockdevice will be synced later so we don't have to submit
2090 * the buffer for IO
2091 */
2092 mark_buffer_dirty(sbi->s_lvid_bh);
2093 sb->s_dirt = 0;
2094 sbi->s_lvid_dirty = 0;
2095 }
2096 mutex_unlock(&sbi->s_alloc_mutex);
2097
2098 return 0;
2099}
2100
2095static int udf_statfs(struct dentry *dentry, struct kstatfs *buf) 2101static int udf_statfs(struct dentry *dentry, struct kstatfs *buf)
2096{ 2102{
2097 struct super_block *sb = dentry->d_sb; 2103 struct super_block *sb = dentry->d_sb;
diff --git a/fs/udf/udf_sb.h b/fs/udf/udf_sb.h
index 46fea3ea70a9..d113b72c2768 100644
--- a/fs/udf/udf_sb.h
+++ b/fs/udf/udf_sb.h
@@ -148,6 +148,8 @@ struct udf_sb_info {
148 struct inode *s_vat_inode; 148 struct inode *s_vat_inode;
149 149
150 struct mutex s_alloc_mutex; 150 struct mutex s_alloc_mutex;
151 /* Protected by s_alloc_mutex */
152 unsigned int s_lvid_dirty;
151}; 153};
152 154
153static inline struct udf_sb_info *UDF_SB(struct super_block *sb) 155static inline struct udf_sb_info *UDF_SB(struct super_block *sb)
diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h
index 9a2a9b61413e..cac51b77a5d1 100644
--- a/fs/udf/udfdecl.h
+++ b/fs/udf/udfdecl.h
@@ -111,6 +111,17 @@ struct extent_position {
111 111
112/* super.c */ 112/* super.c */
113extern void udf_warning(struct super_block *, const char *, const char *, ...); 113extern void udf_warning(struct super_block *, const char *, const char *, ...);
114static inline void udf_updated_lvid(struct super_block *sb)
115{
116 struct buffer_head *bh = UDF_SB(sb)->s_lvid_bh;
117
118 BUG_ON(!bh);
119 WARN_ON_ONCE(((struct logicalVolIntegrityDesc *)
120 bh->b_data)->integrityType !=
121 cpu_to_le32(LVID_INTEGRITY_TYPE_OPEN));
122 sb->s_dirt = 1;
123 UDF_SB(sb)->s_lvid_dirty = 1;
124}
114 125
115/* namei.c */ 126/* namei.c */
116extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *, 127extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *,