Commit 146bca72 authored by Jan Kara's avatar Jan Kara

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: default avatarJan Kara <jack@suse.cz>
parent 40346005
...@@ -140,17 +140,17 @@ static inline int load_block_bitmap(struct super_block *sb, ...@@ -140,17 +140,17 @@ static inline int load_block_bitmap(struct super_block *sb,
return slot; return slot;
} }
static bool udf_add_free_space(struct udf_sb_info *sbi, static void udf_add_free_space(struct super_block *sb, u16 partition, u32 cnt)
u16 partition, u32 cnt)
{ {
struct udf_sb_info *sbi = UDF_SB(sb);
struct logicalVolIntegrityDesc *lvid; struct logicalVolIntegrityDesc *lvid;
if (sbi->s_lvid_bh == NULL) if (!sbi->s_lvid_bh)
return false; return;
lvid = (struct logicalVolIntegrityDesc *)sbi->s_lvid_bh->b_data; lvid = (struct logicalVolIntegrityDesc *)sbi->s_lvid_bh->b_data;
le32_add_cpu(&lvid->freeSpaceTable[partition], cnt); le32_add_cpu(&lvid->freeSpaceTable[partition], cnt);
return true; udf_updated_lvid(sb);
} }
static void udf_bitmap_free_blocks(struct super_block *sb, static void udf_bitmap_free_blocks(struct super_block *sb,
...@@ -209,7 +209,7 @@ static void udf_bitmap_free_blocks(struct super_block *sb, ...@@ -209,7 +209,7 @@ static void udf_bitmap_free_blocks(struct super_block *sb,
} else { } else {
if (inode) if (inode)
vfs_dq_free_block(inode, 1); vfs_dq_free_block(inode, 1);
udf_add_free_space(sbi, sbi->s_partition, 1); udf_add_free_space(sb, sbi->s_partition, 1);
} }
} }
mark_buffer_dirty(bh); mark_buffer_dirty(bh);
...@@ -220,9 +220,6 @@ static void udf_bitmap_free_blocks(struct super_block *sb, ...@@ -220,9 +220,6 @@ static void udf_bitmap_free_blocks(struct super_block *sb,
} while (overflow); } while (overflow);
error_return: error_return:
sb->s_dirt = 1;
if (sbi->s_lvid_bh)
mark_buffer_dirty(sbi->s_lvid_bh);
mutex_unlock(&sbi->s_alloc_mutex); mutex_unlock(&sbi->s_alloc_mutex);
} }
...@@ -279,9 +276,7 @@ static int udf_bitmap_prealloc_blocks(struct super_block *sb, ...@@ -279,9 +276,7 @@ static int udf_bitmap_prealloc_blocks(struct super_block *sb,
} while (block_count > 0); } while (block_count > 0);
out: out:
if (udf_add_free_space(sbi, partition, -alloc_count)) udf_add_free_space(sb, partition, -alloc_count);
mark_buffer_dirty(sbi->s_lvid_bh);
sb->s_dirt = 1;
mutex_unlock(&sbi->s_alloc_mutex); mutex_unlock(&sbi->s_alloc_mutex);
return alloc_count; return alloc_count;
} }
...@@ -411,9 +406,7 @@ static int udf_bitmap_new_block(struct super_block *sb, ...@@ -411,9 +406,7 @@ static int udf_bitmap_new_block(struct super_block *sb,
mark_buffer_dirty(bh); mark_buffer_dirty(bh);
if (udf_add_free_space(sbi, partition, -1)) udf_add_free_space(sb, partition, -1);
mark_buffer_dirty(sbi->s_lvid_bh);
sb->s_dirt = 1;
mutex_unlock(&sbi->s_alloc_mutex); mutex_unlock(&sbi->s_alloc_mutex);
*err = 0; *err = 0;
return newblock; return newblock;
...@@ -457,8 +450,7 @@ static void udf_table_free_blocks(struct super_block *sb, ...@@ -457,8 +450,7 @@ static void udf_table_free_blocks(struct super_block *sb,
could occure, but.. oh well */ could occure, but.. oh well */
if (inode) if (inode)
vfs_dq_free_block(inode, count); vfs_dq_free_block(inode, count);
if (udf_add_free_space(sbi, sbi->s_partition, count)) udf_add_free_space(sb, sbi->s_partition, count);
mark_buffer_dirty(sbi->s_lvid_bh);
start = bloc->logicalBlockNum + offset; start = bloc->logicalBlockNum + offset;
end = bloc->logicalBlockNum + offset + count - 1; end = bloc->logicalBlockNum + offset + count - 1;
...@@ -657,7 +649,6 @@ static void udf_table_free_blocks(struct super_block *sb, ...@@ -657,7 +649,6 @@ static void udf_table_free_blocks(struct super_block *sb,
brelse(oepos.bh); brelse(oepos.bh);
error_return: error_return:
sb->s_dirt = 1;
mutex_unlock(&sbi->s_alloc_mutex); mutex_unlock(&sbi->s_alloc_mutex);
return; return;
} }
...@@ -722,10 +713,8 @@ static int udf_table_prealloc_blocks(struct super_block *sb, ...@@ -722,10 +713,8 @@ static int udf_table_prealloc_blocks(struct super_block *sb,
brelse(epos.bh); brelse(epos.bh);
if (alloc_count && udf_add_free_space(sbi, partition, -alloc_count)) { if (alloc_count)
mark_buffer_dirty(sbi->s_lvid_bh); udf_add_free_space(sb, partition, -alloc_count);
sb->s_dirt = 1;
}
mutex_unlock(&sbi->s_alloc_mutex); mutex_unlock(&sbi->s_alloc_mutex);
return alloc_count; return alloc_count;
} }
...@@ -823,10 +812,8 @@ static int udf_table_new_block(struct super_block *sb, ...@@ -823,10 +812,8 @@ static int udf_table_new_block(struct super_block *sb,
udf_delete_aext(table, goal_epos, goal_eloc, goal_elen); udf_delete_aext(table, goal_epos, goal_eloc, goal_elen);
brelse(goal_epos.bh); brelse(goal_epos.bh);
if (udf_add_free_space(sbi, partition, -1)) udf_add_free_space(sb, partition, -1);
mark_buffer_dirty(sbi->s_lvid_bh);
sb->s_dirt = 1;
mutex_unlock(&sbi->s_alloc_mutex); mutex_unlock(&sbi->s_alloc_mutex);
*err = 0; *err = 0;
return newblock; return newblock;
......
...@@ -49,8 +49,7 @@ void udf_free_inode(struct inode *inode) ...@@ -49,8 +49,7 @@ void udf_free_inode(struct inode *inode)
le32_add_cpu(&lvidiu->numDirs, -1); le32_add_cpu(&lvidiu->numDirs, -1);
else else
le32_add_cpu(&lvidiu->numFiles, -1); le32_add_cpu(&lvidiu->numFiles, -1);
udf_updated_lvid(sb);
mark_buffer_dirty(sbi->s_lvid_bh);
} }
mutex_unlock(&sbi->s_alloc_mutex); mutex_unlock(&sbi->s_alloc_mutex);
...@@ -122,7 +121,7 @@ struct inode *udf_new_inode(struct inode *dir, int mode, int *err) ...@@ -122,7 +121,7 @@ struct inode *udf_new_inode(struct inode *dir, int mode, int *err)
if (!(++uniqueID & 0x00000000FFFFFFFFUL)) if (!(++uniqueID & 0x00000000FFFFFFFFUL))
uniqueID += 16; uniqueID += 16;
lvhd->uniqueID = cpu_to_le64(uniqueID); lvhd->uniqueID = cpu_to_le64(uniqueID);
mark_buffer_dirty(sbi->s_lvid_bh); udf_updated_lvid(sb);
} }
mutex_unlock(&sbi->s_alloc_mutex); mutex_unlock(&sbi->s_alloc_mutex);
inode->i_mode = mode; inode->i_mode = mode;
......
...@@ -81,7 +81,7 @@ static char error_buf[1024]; ...@@ -81,7 +81,7 @@ static char error_buf[1024];
/* These are the "meat" - everything else is stuffing */ /* These are the "meat" - everything else is stuffing */
static int udf_fill_super(struct super_block *, void *, int); static int udf_fill_super(struct super_block *, void *, int);
static void udf_put_super(struct super_block *); static void udf_put_super(struct super_block *);
static void udf_write_super(struct super_block *); static int udf_sync_fs(struct super_block *, int);
static int udf_remount_fs(struct super_block *, int *, char *); static int udf_remount_fs(struct super_block *, int *, char *);
static void udf_load_logicalvolint(struct super_block *, struct kernel_extent_ad); static void udf_load_logicalvolint(struct super_block *, struct kernel_extent_ad);
static int udf_find_fileset(struct super_block *, struct kernel_lb_addr *, static int udf_find_fileset(struct super_block *, struct kernel_lb_addr *,
...@@ -178,7 +178,7 @@ static const struct super_operations udf_sb_ops = { ...@@ -178,7 +178,7 @@ static const struct super_operations udf_sb_ops = {
.delete_inode = udf_delete_inode, .delete_inode = udf_delete_inode,
.clear_inode = udf_clear_inode, .clear_inode = udf_clear_inode,
.put_super = udf_put_super, .put_super = udf_put_super,
.write_super = udf_write_super, .sync_fs = udf_sync_fs,
.statfs = udf_statfs, .statfs = udf_statfs,
.remount_fs = udf_remount_fs, .remount_fs = udf_remount_fs,
.show_options = udf_show_options, .show_options = udf_show_options,
...@@ -553,17 +553,6 @@ static int udf_parse_options(char *options, struct udf_options *uopt, ...@@ -553,17 +553,6 @@ static int udf_parse_options(char *options, struct udf_options *uopt,
return 1; return 1;
} }
static void udf_write_super(struct super_block *sb)
{
lock_kernel();
if (!(sb->s_flags & MS_RDONLY))
udf_open_lvid(sb);
sb->s_dirt = 0;
unlock_kernel();
}
static int udf_remount_fs(struct super_block *sb, int *flags, char *options) static int udf_remount_fs(struct super_block *sb, int *flags, char *options)
{ {
struct udf_options uopt; struct udf_options uopt;
...@@ -1753,9 +1742,9 @@ static void udf_open_lvid(struct super_block *sb) ...@@ -1753,9 +1742,9 @@ static void udf_open_lvid(struct super_block *sb)
struct buffer_head *bh = sbi->s_lvid_bh; struct buffer_head *bh = sbi->s_lvid_bh;
struct logicalVolIntegrityDesc *lvid; struct logicalVolIntegrityDesc *lvid;
struct logicalVolIntegrityDescImpUse *lvidiu; struct logicalVolIntegrityDescImpUse *lvidiu;
if (!bh) if (!bh)
return; return;
lvid = (struct logicalVolIntegrityDesc *)bh->b_data; lvid = (struct logicalVolIntegrityDesc *)bh->b_data;
lvidiu = udf_sb_lvidiu(sbi); lvidiu = udf_sb_lvidiu(sbi);
...@@ -1763,7 +1752,7 @@ static void udf_open_lvid(struct super_block *sb) ...@@ -1763,7 +1752,7 @@ static void udf_open_lvid(struct super_block *sb)
lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
udf_time_to_disk_stamp(&lvid->recordingDateAndTime, udf_time_to_disk_stamp(&lvid->recordingDateAndTime,
CURRENT_TIME); CURRENT_TIME);
lvid->integrityType = LVID_INTEGRITY_TYPE_OPEN; lvid->integrityType = cpu_to_le32(LVID_INTEGRITY_TYPE_OPEN);
lvid->descTag.descCRC = cpu_to_le16( lvid->descTag.descCRC = cpu_to_le16(
crc_itu_t(0, (char *)lvid + sizeof(struct tag), crc_itu_t(0, (char *)lvid + sizeof(struct tag),
...@@ -1771,6 +1760,7 @@ static void udf_open_lvid(struct super_block *sb) ...@@ -1771,6 +1760,7 @@ static void udf_open_lvid(struct super_block *sb)
lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag); lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag);
mark_buffer_dirty(bh); mark_buffer_dirty(bh);
sbi->s_lvid_dirty = 0;
} }
static void udf_close_lvid(struct super_block *sb) static void udf_close_lvid(struct super_block *sb)
...@@ -1784,10 +1774,6 @@ static void udf_close_lvid(struct super_block *sb) ...@@ -1784,10 +1774,6 @@ static void udf_close_lvid(struct super_block *sb)
return; return;
lvid = (struct logicalVolIntegrityDesc *)bh->b_data; lvid = (struct logicalVolIntegrityDesc *)bh->b_data;
if (lvid->integrityType != LVID_INTEGRITY_TYPE_OPEN)
return;
lvidiu = udf_sb_lvidiu(sbi); lvidiu = udf_sb_lvidiu(sbi);
lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX; lvidiu->impIdent.identSuffix[0] = UDF_OS_CLASS_UNIX;
lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX; lvidiu->impIdent.identSuffix[1] = UDF_OS_ID_LINUX;
...@@ -1806,6 +1792,7 @@ static void udf_close_lvid(struct super_block *sb) ...@@ -1806,6 +1792,7 @@ static void udf_close_lvid(struct super_block *sb)
lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag); lvid->descTag.tagChecksum = udf_tag_checksum(&lvid->descTag);
mark_buffer_dirty(bh); mark_buffer_dirty(bh);
sbi->s_lvid_dirty = 0;
} }
static void udf_sb_free_bitmap(struct udf_bitmap *bitmap) static void udf_sb_free_bitmap(struct udf_bitmap *bitmap)
...@@ -2092,6 +2079,25 @@ static void udf_put_super(struct super_block *sb) ...@@ -2092,6 +2079,25 @@ static void udf_put_super(struct super_block *sb)
sb->s_fs_info = NULL; sb->s_fs_info = NULL;
} }
static int udf_sync_fs(struct super_block *sb, int wait)
{
struct udf_sb_info *sbi = UDF_SB(sb);
mutex_lock(&sbi->s_alloc_mutex);
if (sbi->s_lvid_dirty) {
/*
* Blockdevice will be synced later so we don't have to submit
* the buffer for IO
*/
mark_buffer_dirty(sbi->s_lvid_bh);
sb->s_dirt = 0;
sbi->s_lvid_dirty = 0;
}
mutex_unlock(&sbi->s_alloc_mutex);
return 0;
}
static int udf_statfs(struct dentry *dentry, struct kstatfs *buf) static int udf_statfs(struct dentry *dentry, struct kstatfs *buf)
{ {
struct super_block *sb = dentry->d_sb; struct super_block *sb = dentry->d_sb;
......
...@@ -148,6 +148,8 @@ struct udf_sb_info { ...@@ -148,6 +148,8 @@ struct udf_sb_info {
struct inode *s_vat_inode; struct inode *s_vat_inode;
struct mutex s_alloc_mutex; struct mutex s_alloc_mutex;
/* Protected by s_alloc_mutex */
unsigned int s_lvid_dirty;
}; };
static inline struct udf_sb_info *UDF_SB(struct super_block *sb) static inline struct udf_sb_info *UDF_SB(struct super_block *sb)
......
...@@ -111,6 +111,17 @@ struct extent_position { ...@@ -111,6 +111,17 @@ struct extent_position {
/* super.c */ /* super.c */
extern void udf_warning(struct super_block *, const char *, const char *, ...); extern void udf_warning(struct super_block *, const char *, const char *, ...);
static inline void udf_updated_lvid(struct super_block *sb)
{
struct buffer_head *bh = UDF_SB(sb)->s_lvid_bh;
BUG_ON(!bh);
WARN_ON_ONCE(((struct logicalVolIntegrityDesc *)
bh->b_data)->integrityType !=
cpu_to_le32(LVID_INTEGRITY_TYPE_OPEN));
sb->s_dirt = 1;
UDF_SB(sb)->s_lvid_dirty = 1;
}
/* namei.c */ /* namei.c */
extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *, extern int udf_write_fi(struct inode *inode, struct fileIdentDesc *,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment