Commit e1f8826f authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs

Pull reiserfs and UDF fixes from Jan Kara:
 "The contains fix of an UDF oops when mounting corrupted media and a
  fix of a race in reiserfs leading to oops"

* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs:
  reiserfs: fix race with flush_used_journal_lists and flush_journal_list
  reiserfs: remove useless flush_old_journal_lists
  udf: Fortify LVID loading
parents 730d7d33 721a769c
...@@ -1163,21 +1163,6 @@ static struct reiserfs_journal_list *find_newer_jl_for_cn(struct ...@@ -1163,21 +1163,6 @@ static struct reiserfs_journal_list *find_newer_jl_for_cn(struct
return NULL; return NULL;
} }
static int newer_jl_done(struct reiserfs_journal_cnode *cn)
{
struct super_block *sb = cn->sb;
b_blocknr_t blocknr = cn->blocknr;
cn = cn->hprev;
while (cn) {
if (cn->sb == sb && cn->blocknr == blocknr && cn->jlist &&
atomic_read(&cn->jlist->j_commit_left) != 0)
return 0;
cn = cn->hprev;
}
return 1;
}
static void remove_journal_hash(struct super_block *, static void remove_journal_hash(struct super_block *,
struct reiserfs_journal_cnode **, struct reiserfs_journal_cnode **,
struct reiserfs_journal_list *, unsigned long, struct reiserfs_journal_list *, unsigned long,
...@@ -1353,7 +1338,6 @@ static int flush_journal_list(struct super_block *s, ...@@ -1353,7 +1338,6 @@ static int flush_journal_list(struct super_block *s,
reiserfs_warning(s, "clm-2048", "called with wcount %d", reiserfs_warning(s, "clm-2048", "called with wcount %d",
atomic_read(&journal->j_wcount)); atomic_read(&journal->j_wcount));
} }
BUG_ON(jl->j_trans_id == 0);
/* if flushall == 0, the lock is already held */ /* if flushall == 0, the lock is already held */
if (flushall) { if (flushall) {
...@@ -1593,31 +1577,6 @@ static int flush_journal_list(struct super_block *s, ...@@ -1593,31 +1577,6 @@ static int flush_journal_list(struct super_block *s,
return err; return err;
} }
static int test_transaction(struct super_block *s,
struct reiserfs_journal_list *jl)
{
struct reiserfs_journal_cnode *cn;
if (jl->j_len == 0 || atomic_read(&jl->j_nonzerolen) == 0)
return 1;
cn = jl->j_realblock;
while (cn) {
/* if the blocknr == 0, this has been cleared from the hash,
** skip it
*/
if (cn->blocknr == 0) {
goto next;
}
if (cn->bh && !newer_jl_done(cn))
return 0;
next:
cn = cn->next;
cond_resched();
}
return 0;
}
static int write_one_transaction(struct super_block *s, static int write_one_transaction(struct super_block *s,
struct reiserfs_journal_list *jl, struct reiserfs_journal_list *jl,
struct buffer_chunk *chunk) struct buffer_chunk *chunk)
...@@ -1805,6 +1764,8 @@ static int flush_used_journal_lists(struct super_block *s, ...@@ -1805,6 +1764,8 @@ static int flush_used_journal_lists(struct super_block *s,
break; break;
tjl = JOURNAL_LIST_ENTRY(tjl->j_list.next); tjl = JOURNAL_LIST_ENTRY(tjl->j_list.next);
} }
get_journal_list(jl);
get_journal_list(flush_jl);
/* try to find a group of blocks we can flush across all the /* try to find a group of blocks we can flush across all the
** transactions, but only bother if we've actually spanned ** transactions, but only bother if we've actually spanned
** across multiple lists ** across multiple lists
...@@ -1813,6 +1774,8 @@ static int flush_used_journal_lists(struct super_block *s, ...@@ -1813,6 +1774,8 @@ static int flush_used_journal_lists(struct super_block *s,
ret = kupdate_transactions(s, jl, &tjl, &trans_id, len, i); ret = kupdate_transactions(s, jl, &tjl, &trans_id, len, i);
} }
flush_journal_list(s, flush_jl, 1); flush_journal_list(s, flush_jl, 1);
put_journal_list(s, flush_jl);
put_journal_list(s, jl);
return 0; return 0;
} }
...@@ -3868,27 +3831,6 @@ int reiserfs_prepare_for_journal(struct super_block *sb, ...@@ -3868,27 +3831,6 @@ int reiserfs_prepare_for_journal(struct super_block *sb,
return 1; return 1;
} }
static void flush_old_journal_lists(struct super_block *s)
{
struct reiserfs_journal *journal = SB_JOURNAL(s);
struct reiserfs_journal_list *jl;
struct list_head *entry;
time_t now = get_seconds();
while (!list_empty(&journal->j_journal_list)) {
entry = journal->j_journal_list.next;
jl = JOURNAL_LIST_ENTRY(entry);
/* this check should always be run, to send old lists to disk */
if (jl->j_timestamp < (now - (JOURNAL_MAX_TRANS_AGE * 4)) &&
atomic_read(&jl->j_commit_left) == 0 &&
test_transaction(s, jl)) {
flush_used_journal_lists(s, jl);
} else {
break;
}
}
}
/* /*
** long and ugly. If flush, will not return until all commit ** long and ugly. If flush, will not return until all commit
** blocks and all real buffers in the trans are on disk. ** blocks and all real buffers in the trans are on disk.
...@@ -4232,7 +4174,6 @@ static int do_journal_end(struct reiserfs_transaction_handle *th, ...@@ -4232,7 +4174,6 @@ static int do_journal_end(struct reiserfs_transaction_handle *th,
} }
} }
} }
flush_old_journal_lists(sb);
journal->j_current_jl->j_list_bitmap = journal->j_current_jl->j_list_bitmap =
get_list_bitmap(sb, journal->j_current_jl); get_list_bitmap(sb, journal->j_current_jl);
......
...@@ -30,18 +30,17 @@ void udf_free_inode(struct inode *inode) ...@@ -30,18 +30,17 @@ void udf_free_inode(struct inode *inode)
{ {
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
struct udf_sb_info *sbi = UDF_SB(sb); struct udf_sb_info *sbi = UDF_SB(sb);
struct logicalVolIntegrityDescImpUse *lvidiu = udf_sb_lvidiu(sb);
mutex_lock(&sbi->s_alloc_mutex); if (lvidiu) {
if (sbi->s_lvid_bh) { mutex_lock(&sbi->s_alloc_mutex);
struct logicalVolIntegrityDescImpUse *lvidiu =
udf_sb_lvidiu(sbi);
if (S_ISDIR(inode->i_mode)) if (S_ISDIR(inode->i_mode))
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); udf_updated_lvid(sb);
mutex_unlock(&sbi->s_alloc_mutex);
} }
mutex_unlock(&sbi->s_alloc_mutex);
udf_free_blocks(sb, NULL, &UDF_I(inode)->i_location, 0, 1); udf_free_blocks(sb, NULL, &UDF_I(inode)->i_location, 0, 1);
} }
...@@ -55,6 +54,7 @@ struct inode *udf_new_inode(struct inode *dir, umode_t mode, int *err) ...@@ -55,6 +54,7 @@ struct inode *udf_new_inode(struct inode *dir, umode_t mode, int *err)
uint32_t start = UDF_I(dir)->i_location.logicalBlockNum; uint32_t start = UDF_I(dir)->i_location.logicalBlockNum;
struct udf_inode_info *iinfo; struct udf_inode_info *iinfo;
struct udf_inode_info *dinfo = UDF_I(dir); struct udf_inode_info *dinfo = UDF_I(dir);
struct logicalVolIntegrityDescImpUse *lvidiu;
inode = new_inode(sb); inode = new_inode(sb);
...@@ -92,12 +92,10 @@ struct inode *udf_new_inode(struct inode *dir, umode_t mode, int *err) ...@@ -92,12 +92,10 @@ struct inode *udf_new_inode(struct inode *dir, umode_t mode, int *err)
return NULL; return NULL;
} }
if (sbi->s_lvid_bh) { lvidiu = udf_sb_lvidiu(sb);
struct logicalVolIntegrityDescImpUse *lvidiu; if (lvidiu) {
iinfo->i_unique = lvid_get_unique_id(sb); iinfo->i_unique = lvid_get_unique_id(sb);
mutex_lock(&sbi->s_alloc_mutex); mutex_lock(&sbi->s_alloc_mutex);
lvidiu = udf_sb_lvidiu(sbi);
if (S_ISDIR(mode)) if (S_ISDIR(mode))
le32_add_cpu(&lvidiu->numDirs, 1); le32_add_cpu(&lvidiu->numDirs, 1);
else else
......
...@@ -94,13 +94,25 @@ static unsigned int udf_count_free(struct super_block *); ...@@ -94,13 +94,25 @@ static unsigned int udf_count_free(struct super_block *);
static int udf_statfs(struct dentry *, struct kstatfs *); static int udf_statfs(struct dentry *, struct kstatfs *);
static int udf_show_options(struct seq_file *, struct dentry *); static int udf_show_options(struct seq_file *, struct dentry *);
struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct udf_sb_info *sbi) struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct super_block *sb)
{ {
struct logicalVolIntegrityDesc *lvid = struct logicalVolIntegrityDesc *lvid;
(struct logicalVolIntegrityDesc *)sbi->s_lvid_bh->b_data; unsigned int partnum;
__u32 number_of_partitions = le32_to_cpu(lvid->numOfPartitions); unsigned int offset;
__u32 offset = number_of_partitions * 2 *
sizeof(uint32_t)/sizeof(uint8_t); if (!UDF_SB(sb)->s_lvid_bh)
return NULL;
lvid = (struct logicalVolIntegrityDesc *)UDF_SB(sb)->s_lvid_bh->b_data;
partnum = le32_to_cpu(lvid->numOfPartitions);
if ((sb->s_blocksize - sizeof(struct logicalVolIntegrityDescImpUse) -
offsetof(struct logicalVolIntegrityDesc, impUse)) /
(2 * sizeof(uint32_t)) < partnum) {
udf_err(sb, "Logical volume integrity descriptor corrupted "
"(numOfPartitions = %u)!\n", partnum);
return NULL;
}
/* The offset is to skip freeSpaceTable and sizeTable arrays */
offset = partnum * 2 * sizeof(uint32_t);
return (struct logicalVolIntegrityDescImpUse *)&(lvid->impUse[offset]); return (struct logicalVolIntegrityDescImpUse *)&(lvid->impUse[offset]);
} }
...@@ -629,9 +641,10 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options) ...@@ -629,9 +641,10 @@ static int udf_remount_fs(struct super_block *sb, int *flags, char *options)
struct udf_options uopt; struct udf_options uopt;
struct udf_sb_info *sbi = UDF_SB(sb); struct udf_sb_info *sbi = UDF_SB(sb);
int error = 0; int error = 0;
struct logicalVolIntegrityDescImpUse *lvidiu = udf_sb_lvidiu(sb);
if (sbi->s_lvid_bh) { if (lvidiu) {
int write_rev = le16_to_cpu(udf_sb_lvidiu(sbi)->minUDFWriteRev); int write_rev = le16_to_cpu(lvidiu->minUDFWriteRev);
if (write_rev > UDF_MAX_WRITE_VERSION && !(*flags & MS_RDONLY)) if (write_rev > UDF_MAX_WRITE_VERSION && !(*flags & MS_RDONLY))
return -EACCES; return -EACCES;
} }
...@@ -1905,11 +1918,12 @@ static void udf_open_lvid(struct super_block *sb) ...@@ -1905,11 +1918,12 @@ static void udf_open_lvid(struct super_block *sb)
if (!bh) if (!bh)
return; return;
mutex_lock(&sbi->s_alloc_mutex);
lvid = (struct logicalVolIntegrityDesc *)bh->b_data; lvid = (struct logicalVolIntegrityDesc *)bh->b_data;
lvidiu = udf_sb_lvidiu(sbi); lvidiu = udf_sb_lvidiu(sb);
if (!lvidiu)
return;
mutex_lock(&sbi->s_alloc_mutex);
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;
udf_time_to_disk_stamp(&lvid->recordingDateAndTime, udf_time_to_disk_stamp(&lvid->recordingDateAndTime,
...@@ -1937,10 +1951,12 @@ static void udf_close_lvid(struct super_block *sb) ...@@ -1937,10 +1951,12 @@ static void udf_close_lvid(struct super_block *sb)
if (!bh) if (!bh)
return; return;
lvid = (struct logicalVolIntegrityDesc *)bh->b_data;
lvidiu = udf_sb_lvidiu(sb);
if (!lvidiu)
return;
mutex_lock(&sbi->s_alloc_mutex); mutex_lock(&sbi->s_alloc_mutex);
lvid = (struct logicalVolIntegrityDesc *)bh->b_data;
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;
udf_time_to_disk_stamp(&lvid->recordingDateAndTime, CURRENT_TIME); udf_time_to_disk_stamp(&lvid->recordingDateAndTime, CURRENT_TIME);
...@@ -2093,15 +2109,19 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent) ...@@ -2093,15 +2109,19 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
if (sbi->s_lvid_bh) { if (sbi->s_lvid_bh) {
struct logicalVolIntegrityDescImpUse *lvidiu = struct logicalVolIntegrityDescImpUse *lvidiu =
udf_sb_lvidiu(sbi); udf_sb_lvidiu(sb);
uint16_t minUDFReadRev = le16_to_cpu(lvidiu->minUDFReadRev); uint16_t minUDFReadRev;
uint16_t minUDFWriteRev = le16_to_cpu(lvidiu->minUDFWriteRev); uint16_t minUDFWriteRev;
/* uint16_t maxUDFWriteRev =
le16_to_cpu(lvidiu->maxUDFWriteRev); */
if (!lvidiu) {
ret = -EINVAL;
goto error_out;
}
minUDFReadRev = le16_to_cpu(lvidiu->minUDFReadRev);
minUDFWriteRev = le16_to_cpu(lvidiu->minUDFWriteRev);
if (minUDFReadRev > UDF_MAX_READ_VERSION) { if (minUDFReadRev > UDF_MAX_READ_VERSION) {
udf_err(sb, "minUDFReadRev=%x (max is %x)\n", udf_err(sb, "minUDFReadRev=%x (max is %x)\n",
le16_to_cpu(lvidiu->minUDFReadRev), minUDFReadRev,
UDF_MAX_READ_VERSION); UDF_MAX_READ_VERSION);
ret = -EINVAL; ret = -EINVAL;
goto error_out; goto error_out;
...@@ -2265,11 +2285,7 @@ static int udf_statfs(struct dentry *dentry, struct kstatfs *buf) ...@@ -2265,11 +2285,7 @@ static int udf_statfs(struct dentry *dentry, struct kstatfs *buf)
struct logicalVolIntegrityDescImpUse *lvidiu; struct logicalVolIntegrityDescImpUse *lvidiu;
u64 id = huge_encode_dev(sb->s_bdev->bd_dev); u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
if (sbi->s_lvid_bh != NULL) lvidiu = udf_sb_lvidiu(sb);
lvidiu = udf_sb_lvidiu(sbi);
else
lvidiu = NULL;
buf->f_type = UDF_SUPER_MAGIC; buf->f_type = UDF_SUPER_MAGIC;
buf->f_bsize = sb->s_blocksize; buf->f_bsize = sb->s_blocksize;
buf->f_blocks = sbi->s_partmaps[sbi->s_partition].s_partition_len; buf->f_blocks = sbi->s_partmaps[sbi->s_partition].s_partition_len;
......
...@@ -162,7 +162,7 @@ static inline struct udf_sb_info *UDF_SB(struct super_block *sb) ...@@ -162,7 +162,7 @@ static inline struct udf_sb_info *UDF_SB(struct super_block *sb)
return sb->s_fs_info; return sb->s_fs_info;
} }
struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct udf_sb_info *sbi); struct logicalVolIntegrityDescImpUse *udf_sb_lvidiu(struct super_block *sb);
int udf_compute_nr_groups(struct super_block *sb, u32 partition); int udf_compute_nr_groups(struct super_block *sb, u32 partition);
......
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