Commit 824b005c authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'hpfs' (patches from Mikulas)

Merge hpfs upddate from Mikulas Patocka.

* emailed patches from Mikulas Patocka <mikulas@twibright.com>:
  hpfs: update ctime and mtime on directory modification
  hpfs: support hotfixes
parents dd5cdb48 f49a26e7
...@@ -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
*/ */
......
...@@ -8,6 +8,17 @@ ...@@ -8,6 +8,17 @@
#include <linux/sched.h> #include <linux/sched.h>
#include "hpfs_fn.h" #include "hpfs_fn.h"
static void hpfs_update_directory_times(struct inode *dir)
{
time_t t = get_seconds();
if (t == dir->i_mtime.tv_sec &&
t == dir->i_ctime.tv_sec)
return;
dir->i_mtime.tv_sec = dir->i_ctime.tv_sec = t;
dir->i_mtime.tv_nsec = dir->i_ctime.tv_nsec = 0;
hpfs_write_inode_nolock(dir);
}
static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
{ {
const unsigned char *name = dentry->d_name.name; const unsigned char *name = dentry->d_name.name;
...@@ -99,6 +110,7 @@ static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode) ...@@ -99,6 +110,7 @@ static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
result->i_mode = mode | S_IFDIR; result->i_mode = mode | S_IFDIR;
hpfs_write_inode_nolock(result); hpfs_write_inode_nolock(result);
} }
hpfs_update_directory_times(dir);
d_instantiate(dentry, result); d_instantiate(dentry, result);
hpfs_unlock(dir->i_sb); hpfs_unlock(dir->i_sb);
return 0; return 0;
...@@ -187,6 +199,7 @@ static int hpfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, b ...@@ -187,6 +199,7 @@ static int hpfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, b
result->i_mode = mode | S_IFREG; result->i_mode = mode | S_IFREG;
hpfs_write_inode_nolock(result); hpfs_write_inode_nolock(result);
} }
hpfs_update_directory_times(dir);
d_instantiate(dentry, result); d_instantiate(dentry, result);
hpfs_unlock(dir->i_sb); hpfs_unlock(dir->i_sb);
return 0; return 0;
...@@ -262,6 +275,7 @@ static int hpfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, de ...@@ -262,6 +275,7 @@ static int hpfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, de
insert_inode_hash(result); insert_inode_hash(result);
hpfs_write_inode_nolock(result); hpfs_write_inode_nolock(result);
hpfs_update_directory_times(dir);
d_instantiate(dentry, result); d_instantiate(dentry, result);
brelse(bh); brelse(bh);
hpfs_unlock(dir->i_sb); hpfs_unlock(dir->i_sb);
...@@ -340,6 +354,7 @@ static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *sy ...@@ -340,6 +354,7 @@ static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *sy
insert_inode_hash(result); insert_inode_hash(result);
hpfs_write_inode_nolock(result); hpfs_write_inode_nolock(result);
hpfs_update_directory_times(dir);
d_instantiate(dentry, result); d_instantiate(dentry, result);
hpfs_unlock(dir->i_sb); hpfs_unlock(dir->i_sb);
return 0; return 0;
...@@ -423,6 +438,8 @@ static int hpfs_unlink(struct inode *dir, struct dentry *dentry) ...@@ -423,6 +438,8 @@ static int hpfs_unlink(struct inode *dir, struct dentry *dentry)
out1: out1:
hpfs_brelse4(&qbh); hpfs_brelse4(&qbh);
out: out:
if (!err)
hpfs_update_directory_times(dir);
hpfs_unlock(dir->i_sb); hpfs_unlock(dir->i_sb);
return err; return err;
} }
...@@ -477,6 +494,8 @@ static int hpfs_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -477,6 +494,8 @@ static int hpfs_rmdir(struct inode *dir, struct dentry *dentry)
out1: out1:
hpfs_brelse4(&qbh); hpfs_brelse4(&qbh);
out: out:
if (!err)
hpfs_update_directory_times(dir);
hpfs_unlock(dir->i_sb); hpfs_unlock(dir->i_sb);
return err; return err;
} }
...@@ -595,7 +614,7 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -595,7 +614,7 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
goto end1; goto end1;
} }
end: end:
hpfs_i(i)->i_parent_dir = new_dir->i_ino; hpfs_i(i)->i_parent_dir = new_dir->i_ino;
if (S_ISDIR(i->i_mode)) { if (S_ISDIR(i->i_mode)) {
inc_nlink(new_dir); inc_nlink(new_dir);
...@@ -610,6 +629,10 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry, ...@@ -610,6 +629,10 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
brelse(bh); brelse(bh);
} }
end1: end1:
if (!err) {
hpfs_update_directory_times(old_dir);
hpfs_update_directory_times(new_dir);
}
hpfs_unlock(i->i_sb); hpfs_unlock(i->i_sb);
return err; return err;
} }
......
...@@ -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