Commit a64eefaa authored by Mikulas Patocka's avatar Mikulas Patocka Committed by Linus Torvalds

hpfs: support hotfixes

When the OS/2 driver hits a disk write error, it writes the sector to
another location and adds the sector mapping to the hotfix map.

This patch makes the hpfs driver understand the hotfix map and remap
accesses accoring to it.
Signed-off-by: default avatarMikulas Patocka <mikulas@twibright.com>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 64291f7d
...@@ -10,6 +10,30 @@ ...@@ -10,6 +10,30 @@
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include "hpfs_fn.h" #include "hpfs_fn.h"
secno hpfs_search_hotfix_map(struct super_block *s, secno sec)
{
unsigned i;
struct hpfs_sb_info *sbi = hpfs_sb(s);
for (i = 0; unlikely(i < sbi->n_hotfixes); i++) {
if (sbi->hotfix_from[i] == sec) {
return sbi->hotfix_to[i];
}
}
return sec;
}
unsigned hpfs_search_hotfix_map_for_range(struct super_block *s, secno sec, unsigned n)
{
unsigned i;
struct hpfs_sb_info *sbi = hpfs_sb(s);
for (i = 0; unlikely(i < sbi->n_hotfixes); i++) {
if (sbi->hotfix_from[i] >= sec && sbi->hotfix_from[i] < sec + n) {
n = sbi->hotfix_from[i] - sec;
}
}
return n;
}
void hpfs_prefetch_sectors(struct super_block *s, unsigned secno, int n) void hpfs_prefetch_sectors(struct super_block *s, unsigned secno, int n)
{ {
struct buffer_head *bh; struct buffer_head *bh;
...@@ -18,6 +42,9 @@ void hpfs_prefetch_sectors(struct super_block *s, unsigned secno, int n) ...@@ -18,6 +42,9 @@ void hpfs_prefetch_sectors(struct super_block *s, unsigned secno, int n)
if (n <= 0 || unlikely(secno >= hpfs_sb(s)->sb_fs_size)) if (n <= 0 || unlikely(secno >= hpfs_sb(s)->sb_fs_size))
return; return;
if (unlikely(hpfs_search_hotfix_map_for_range(s, secno, n) != n))
return;
bh = sb_find_get_block(s, secno); bh = sb_find_get_block(s, secno);
if (bh) { if (bh) {
if (buffer_uptodate(bh)) { if (buffer_uptodate(bh)) {
...@@ -51,7 +78,7 @@ void *hpfs_map_sector(struct super_block *s, unsigned secno, struct buffer_head ...@@ -51,7 +78,7 @@ void *hpfs_map_sector(struct super_block *s, unsigned secno, struct buffer_head
cond_resched(); cond_resched();
*bhp = bh = sb_bread(s, secno); *bhp = bh = sb_bread(s, hpfs_search_hotfix_map(s, secno));
if (bh != NULL) if (bh != NULL)
return bh->b_data; return bh->b_data;
else { else {
...@@ -71,7 +98,7 @@ void *hpfs_get_sector(struct super_block *s, unsigned secno, struct buffer_head ...@@ -71,7 +98,7 @@ void *hpfs_get_sector(struct super_block *s, unsigned secno, struct buffer_head
cond_resched(); cond_resched();
if ((*bhp = bh = sb_getblk(s, secno)) != NULL) { if ((*bhp = bh = sb_getblk(s, hpfs_search_hotfix_map(s, secno))) != NULL) {
if (!buffer_uptodate(bh)) wait_on_buffer(bh); if (!buffer_uptodate(bh)) wait_on_buffer(bh);
set_buffer_uptodate(bh); set_buffer_uptodate(bh);
return bh->b_data; return bh->b_data;
...@@ -99,10 +126,10 @@ void *hpfs_map_4sectors(struct super_block *s, unsigned secno, struct quad_buffe ...@@ -99,10 +126,10 @@ void *hpfs_map_4sectors(struct super_block *s, unsigned secno, struct quad_buffe
hpfs_prefetch_sectors(s, secno, 4 + ahead); hpfs_prefetch_sectors(s, secno, 4 + ahead);
if (!(qbh->bh[0] = sb_bread(s, secno + 0))) goto bail0; if (!hpfs_map_sector(s, secno + 0, &qbh->bh[0], 0)) goto bail0;
if (!(qbh->bh[1] = sb_bread(s, secno + 1))) goto bail1; if (!hpfs_map_sector(s, secno + 1, &qbh->bh[1], 0)) goto bail1;
if (!(qbh->bh[2] = sb_bread(s, secno + 2))) goto bail2; if (!hpfs_map_sector(s, secno + 2, &qbh->bh[2], 0)) goto bail2;
if (!(qbh->bh[3] = sb_bread(s, secno + 3))) goto bail3; if (!hpfs_map_sector(s, secno + 3, &qbh->bh[3], 0)) goto bail3;
if (likely(qbh->bh[1]->b_data == qbh->bh[0]->b_data + 1 * 512) && if (likely(qbh->bh[1]->b_data == qbh->bh[0]->b_data + 1 * 512) &&
likely(qbh->bh[2]->b_data == qbh->bh[0]->b_data + 2 * 512) && likely(qbh->bh[2]->b_data == qbh->bh[0]->b_data + 2 * 512) &&
......
...@@ -83,6 +83,11 @@ static int hpfs_get_block(struct inode *inode, sector_t iblock, struct buffer_he ...@@ -83,6 +83,11 @@ static int hpfs_get_block(struct inode *inode, sector_t iblock, struct buffer_he
if (s) { if (s) {
if (bh_result->b_size >> 9 < n_secs) if (bh_result->b_size >> 9 < n_secs)
n_secs = bh_result->b_size >> 9; n_secs = bh_result->b_size >> 9;
n_secs = hpfs_search_hotfix_map_for_range(inode->i_sb, s, n_secs);
if (unlikely(!n_secs)) {
s = hpfs_search_hotfix_map(inode->i_sb, s);
n_secs = 1;
}
map_bh(bh_result, inode->i_sb, s); map_bh(bh_result, inode->i_sb, s);
bh_result->b_size = n_secs << 9; bh_result->b_size = n_secs << 9;
goto ret_0; goto ret_0;
...@@ -101,7 +106,7 @@ static int hpfs_get_block(struct inode *inode, sector_t iblock, struct buffer_he ...@@ -101,7 +106,7 @@ static int hpfs_get_block(struct inode *inode, sector_t iblock, struct buffer_he
inode->i_blocks++; inode->i_blocks++;
hpfs_i(inode)->mmu_private += 512; hpfs_i(inode)->mmu_private += 512;
set_buffer_new(bh_result); set_buffer_new(bh_result);
map_bh(bh_result, inode->i_sb, s); map_bh(bh_result, inode->i_sb, hpfs_search_hotfix_map(inode->i_sb, s));
ret_0: ret_0:
r = 0; r = 0;
ret_r: ret_r:
...@@ -181,7 +186,7 @@ static int hpfs_write_end(struct file *file, struct address_space *mapping, ...@@ -181,7 +186,7 @@ static int hpfs_write_end(struct file *file, struct address_space *mapping,
static sector_t _hpfs_bmap(struct address_space *mapping, sector_t block) static sector_t _hpfs_bmap(struct address_space *mapping, sector_t block)
{ {
return generic_block_bmap(mapping,block,hpfs_get_block); return generic_block_bmap(mapping, block, hpfs_get_block);
} }
const struct address_space_operations hpfs_aops = { const struct address_space_operations hpfs_aops = {
......
...@@ -88,6 +88,10 @@ struct hpfs_sb_info { ...@@ -88,6 +88,10 @@ struct hpfs_sb_info {
unsigned sb_max_fwd_alloc; /* max forwad allocation */ unsigned sb_max_fwd_alloc; /* max forwad allocation */
int sb_timeshift; int sb_timeshift;
struct rcu_head rcu; struct rcu_head rcu;
unsigned n_hotfixes;
secno hotfix_from[256];
secno hotfix_to[256];
}; };
/* Four 512-byte buffers and the 2k block obtained by concatenating them */ /* Four 512-byte buffers and the 2k block obtained by concatenating them */
...@@ -217,6 +221,8 @@ void hpfs_remove_fnode(struct super_block *, fnode_secno fno); ...@@ -217,6 +221,8 @@ void hpfs_remove_fnode(struct super_block *, fnode_secno fno);
/* buffer.c */ /* buffer.c */
secno hpfs_search_hotfix_map(struct super_block *s, secno sec);
unsigned hpfs_search_hotfix_map_for_range(struct super_block *s, secno sec, unsigned n);
void hpfs_prefetch_sectors(struct super_block *, unsigned, int); void hpfs_prefetch_sectors(struct super_block *, unsigned, int);
void *hpfs_map_sector(struct super_block *, unsigned, struct buffer_head **, int); void *hpfs_map_sector(struct super_block *, unsigned, struct buffer_head **, int);
void *hpfs_get_sector(struct super_block *, unsigned, struct buffer_head **); void *hpfs_get_sector(struct super_block *, unsigned, struct buffer_head **);
...@@ -285,6 +291,7 @@ __le32 *hpfs_map_bitmap(struct super_block *, unsigned, struct quad_buffer_head ...@@ -285,6 +291,7 @@ __le32 *hpfs_map_bitmap(struct super_block *, unsigned, struct quad_buffer_head
void hpfs_prefetch_bitmap(struct super_block *, unsigned); void hpfs_prefetch_bitmap(struct super_block *, unsigned);
unsigned char *hpfs_load_code_page(struct super_block *, secno); unsigned char *hpfs_load_code_page(struct super_block *, secno);
__le32 *hpfs_load_bitmap_directory(struct super_block *, secno bmp); __le32 *hpfs_load_bitmap_directory(struct super_block *, secno bmp);
void hpfs_load_hotfix_map(struct super_block *s, struct hpfs_spare_block *spareblock);
struct fnode *hpfs_map_fnode(struct super_block *s, ino_t, struct buffer_head **); struct fnode *hpfs_map_fnode(struct super_block *s, ino_t, struct buffer_head **);
struct anode *hpfs_map_anode(struct super_block *s, anode_secno, struct buffer_head **); struct anode *hpfs_map_anode(struct super_block *s, anode_secno, struct buffer_head **);
struct dnode *hpfs_map_dnode(struct super_block *s, dnode_secno, struct quad_buffer_head *); struct dnode *hpfs_map_dnode(struct super_block *s, dnode_secno, struct quad_buffer_head *);
......
...@@ -130,6 +130,32 @@ __le32 *hpfs_load_bitmap_directory(struct super_block *s, secno bmp) ...@@ -130,6 +130,32 @@ __le32 *hpfs_load_bitmap_directory(struct super_block *s, secno bmp)
return b; return b;
} }
void hpfs_load_hotfix_map(struct super_block *s, struct hpfs_spare_block *spareblock)
{
struct quad_buffer_head qbh;
u32 *directory;
u32 n_hotfixes, n_used_hotfixes;
unsigned i;
n_hotfixes = le32_to_cpu(spareblock->n_spares);
n_used_hotfixes = le32_to_cpu(spareblock->n_spares_used);
if (n_hotfixes > 256 || n_used_hotfixes > n_hotfixes) {
hpfs_error(s, "invalid number of hotfixes: %u, used: %u", n_hotfixes, n_used_hotfixes);
return;
}
if (!(directory = hpfs_map_4sectors(s, le32_to_cpu(spareblock->hotfix_map), &qbh, 0))) {
hpfs_error(s, "can't load hotfix map");
return;
}
for (i = 0; i < n_used_hotfixes; i++) {
hpfs_sb(s)->hotfix_from[i] = le32_to_cpu(directory[i]);
hpfs_sb(s)->hotfix_to[i] = le32_to_cpu(directory[n_hotfixes + i]);
}
hpfs_sb(s)->n_hotfixes = n_used_hotfixes;
hpfs_brelse4(&qbh);
}
/* /*
* Load fnode to memory * Load fnode to memory
*/ */
......
...@@ -628,6 +628,9 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent) ...@@ -628,6 +628,9 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent)
goto bail4; goto bail4;
} }
if (spareblock->n_spares_used)
hpfs_load_hotfix_map(s, spareblock);
/* Load bitmap directory */ /* Load bitmap directory */
if (!(sbi->sb_bmp_dir = hpfs_load_bitmap_directory(s, le32_to_cpu(superblock->bitmaps)))) if (!(sbi->sb_bmp_dir = hpfs_load_bitmap_directory(s, le32_to_cpu(superblock->bitmaps))))
goto bail4; goto bail4;
...@@ -647,18 +650,6 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent) ...@@ -647,18 +650,6 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent)
mark_buffer_dirty(bh2); mark_buffer_dirty(bh2);
} }
if (spareblock->hotfixes_used || spareblock->n_spares_used) {
if (errs >= 2) {
pr_err("Hotfixes not supported here, try chkdsk\n");
mark_dirty(s, 0);
goto bail4;
}
hpfs_error(s, "hotfixes not supported here, try chkdsk");
if (errs == 0)
pr_err("Proceeding, but your filesystem will be probably corrupted by this driver...\n");
else
pr_err("This driver may read bad files or crash when operating on disk with hotfixes.\n");
}
if (le32_to_cpu(spareblock->n_dnode_spares) != le32_to_cpu(spareblock->n_dnode_spares_free)) { if (le32_to_cpu(spareblock->n_dnode_spares) != le32_to_cpu(spareblock->n_dnode_spares_free)) {
if (errs >= 2) { if (errs >= 2) {
pr_err("Spare dnodes used, try chkdsk\n"); pr_err("Spare dnodes used, try chkdsk\n");
......
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