Commit 600a1382 authored by Anton Altaparmakov's avatar Anton Altaparmakov

NTFS: 2.0.16 - Convert access to $MFT/$BITMAP to attribute inode API.

- Fix a stupid bug introduced in 2.0.15 where we were unmapping the
  wrong inode in fs/ntfs/inode.c::ntfs_attr_iget().
- Convert $MFT/$BITMAP access to attribute inode API and remove all
  remnants of the ugly mftbmp address space and operations hack. This
  means we finally have only one readpage function as well as only one
  async io completion handler. Yey! The mft bitmap is now just an
  attribute inode and is accessed from vol->mftbmp_ino just as if it
  were a normal file. Fake inodes rule. (-:
parent db05cffc
......@@ -247,6 +247,10 @@ ChangeLog
Note, a technical ChangeLog aimed at kernel hackers is in fs/ntfs/ChangeLog.
2.0.16:
- Fix stupid bug introduced in 2.0.15 in new attribute inode API.
- Big internal cleanup replacing the mftbmp access hacks by using the
new attribute inode API instead.
2.0.15:
- Bug fix in parsing of remount options.
- Internal changes implementing attribute (fake) inodes allowing all
......
......@@ -17,9 +17,6 @@ ToDo:
- Consider if ntfs_file_read_compressed_block() shouldn't be coping
with initialized_size < data_size. I don't think it can happen but
it requires more careful consideration.
- CLEANUP: At the moment we have two copies of almost identical
functions in aops.c, can merge them once fake inode address space
based attribute i/o is further developed.
- CLEANUP: Modularising code in aops.c a bit, e.g. a-la get_block(),
will be cleaner and make code reuse easier.
- Modify ntfs_read_locked_inode() to return an error code and update
......@@ -27,6 +24,17 @@ ToDo:
using -EIO.
- Enable NFS exporting of NTFS.
2.0.16 - Convert access to $MFT/$BITMAP to attribute inode API.
- Fix a stupid bug introduced in 2.0.15 where we were unmapping the
wrong inode in fs/ntfs/inode.c::ntfs_attr_iget().
- Convert $MFT/$BITMAP access to attribute inode API and remove all
remnants of the ugly mftbmp address space and operations hack. This
means we finally have only one readpage function as well as only one
async io completion handler. Yey! The mft bitmap is now just an
attribute inode and is accessed from vol->mftbmp_ino just as if it
were a normal file. Fake inodes rule. (-:
2.0.15 - Fake inodes based attribute i/o via the pagecache, fixes and cleanups.
- Fix silly bug in fs/ntfs/super.c::parse_options() which was causing
......
......@@ -5,7 +5,7 @@ obj-$(CONFIG_NTFS_FS) += ntfs.o
ntfs-objs := aops.o attrib.o compress.o debug.o dir.o file.o inode.o mft.o \
mst.o namei.o super.o sysctl.o time.o unistr.o upcase.o
EXTRA_CFLAGS = -DNTFS_VERSION=\"2.0.15\"
EXTRA_CFLAGS = -DNTFS_VERSION=\"2.0.16\"
ifeq ($(CONFIG_NTFS_DEBUG),y)
EXTRA_CFLAGS += -DDEBUG
......
......@@ -391,187 +391,6 @@ int ntfs_readpage(struct file *file, struct page *page)
return err;
}
/**
* end_buffer_read_mftbmp_async -
*
* Async io completion handler for accessing mft bitmap. Adapted from
* end_buffer_read_mst_async().
*/
static void end_buffer_read_mftbmp_async(struct buffer_head *bh, int uptodate)
{
static spinlock_t page_uptodate_lock = SPIN_LOCK_UNLOCKED;
unsigned long flags;
struct buffer_head *tmp;
struct page *page;
if (likely(uptodate))
set_buffer_uptodate(bh);
else
clear_buffer_uptodate(bh);
page = bh->b_page;
if (likely(uptodate)) {
s64 file_ofs;
/* Host is the ntfs volume. Our mft bitmap access kludge... */
ntfs_volume *vol = (ntfs_volume*)page->mapping->host;
file_ofs = (page->index << PAGE_CACHE_SHIFT) + bh_offset(bh);
if (file_ofs + bh->b_size > vol->mftbmp_initialized_size) {
char *addr;
int ofs = 0;
if (file_ofs < vol->mftbmp_initialized_size)
ofs = vol->mftbmp_initialized_size - file_ofs;
addr = kmap_atomic(page, KM_BIO_SRC_IRQ);
memset(addr + bh_offset(bh) + ofs, 0, bh->b_size - ofs);
flush_dcache_page(page);
kunmap_atomic(addr, KM_BIO_SRC_IRQ);
}
} else
SetPageError(page);
spin_lock_irqsave(&page_uptodate_lock, flags);
clear_buffer_async_read(bh);
unlock_buffer(bh);
tmp = bh->b_this_page;
while (tmp != bh) {
if (buffer_locked(tmp)) {
if (buffer_async_read(tmp))
goto still_busy;
} else if (!buffer_uptodate(tmp))
SetPageError(page);
tmp = tmp->b_this_page;
}
spin_unlock_irqrestore(&page_uptodate_lock, flags);
if (likely(!PageError(page)))
SetPageUptodate(page);
unlock_page(page);
return;
still_busy:
spin_unlock_irqrestore(&page_uptodate_lock, flags);
return;
}
/**
* ntfs_mftbmp_readpage -
*
* Readpage for accessing mft bitmap.
*/
static int ntfs_mftbmp_readpage(ntfs_volume *vol, struct page *page)
{
VCN vcn;
LCN lcn;
struct buffer_head *bh, *head, *arr[MAX_BUF_PER_PAGE];
sector_t iblock, lblock, zblock;
unsigned int blocksize, blocks, vcn_ofs;
int nr, i;
unsigned char blocksize_bits;
if (unlikely(!PageLocked(page)))
PAGE_BUG(page);
blocksize = vol->sb->s_blocksize;
blocksize_bits = vol->sb->s_blocksize_bits;
if (!page_has_buffers(page))
create_empty_buffers(page, blocksize, 0);
bh = head = page_buffers(page);
if (unlikely(!bh))
return -ENOMEM;
blocks = PAGE_CACHE_SIZE >> blocksize_bits;
iblock = page->index << (PAGE_CACHE_SHIFT - blocksize_bits);
lblock = (vol->mftbmp_allocated_size + blocksize - 1) >> blocksize_bits;
zblock = (vol->mftbmp_initialized_size + blocksize - 1) >>
blocksize_bits;
/* Loop through all the buffers in the page. */
nr = i = 0;
do {
if (unlikely(buffer_uptodate(bh)))
continue;
if (unlikely(buffer_mapped(bh))) {
arr[nr++] = bh;
continue;
}
bh->b_bdev = vol->sb->s_bdev;
/* Is the block within the allowed limits? */
if (iblock < lblock) {
/* Convert iblock into corresponding vcn and offset. */
vcn = (VCN)iblock << blocksize_bits >>
vol->cluster_size_bits;
vcn_ofs = ((VCN)iblock << blocksize_bits) &
vol->cluster_size_mask;
/* Convert the vcn to the corresponding lcn. */
down_read(&vol->mftbmp_rl.lock);
lcn = vcn_to_lcn(vol->mftbmp_rl.rl, vcn);
up_read(&vol->mftbmp_rl.lock);
/* Successful remap. */
if (lcn >= 0) {
/* Setup buffer head to correct block. */
bh->b_blocknr = ((lcn << vol->cluster_size_bits)
+ vcn_ofs) >> blocksize_bits;
set_buffer_mapped(bh);
/* Only read initialized data blocks. */
if (iblock < zblock) {
arr[nr++] = bh;
continue;
}
/* Fully non-initialized data block, zero it. */
goto handle_zblock;
}
if (lcn != LCN_HOLE) {
/* Hard error, zero out region. */
SetPageError(page);
ntfs_error(vol->sb, "vcn_to_lcn(vcn = 0x%Lx) "
"failed with error code "
"0x%Lx.", (long long)vcn,
(long long)-lcn);
// FIXME: Depending on vol->on_errors, do
// something.
}
}
/*
* Either iblock was outside lblock limits or vcn_to_lcn()
* returned error. Just zero that portion of the page and set
* the buffer uptodate.
*/
bh->b_blocknr = -1UL;
clear_buffer_mapped(bh);
handle_zblock:
memset(kmap(page) + i * blocksize, 0, blocksize);
flush_dcache_page(page);
kunmap(page);
set_buffer_uptodate(bh);
} while (i++, iblock++, (bh = bh->b_this_page) != head);
/* Check we have at least one buffer ready for i/o. */
if (nr) {
/* Lock the buffers. */
for (i = 0; i < nr; i++) {
struct buffer_head *tbh = arr[i];
lock_buffer(tbh);
tbh->b_end_io = end_buffer_read_mftbmp_async;
set_buffer_async_read(tbh);
}
/* Finally, start i/o on the buffers. */
for (i = 0; i < nr; i++)
submit_bh(READ, arr[i]);
return 0;
}
/* No i/o was scheduled on any of the buffers. */
if (likely(!PageError(page)))
SetPageUptodate(page);
else /* Signal synchronous i/o error. */
nr = -EIO;
unlock_page(page);
return nr;
}
/**
* ntfs_aops - general address space operations for inodes and attributes
*/
......@@ -584,18 +403,3 @@ struct address_space_operations ntfs_aops = {
commit_write: NULL, /* . */
};
typedef int readpage_t(struct file *, struct page *);
/**
* ntfs_mftbmp_aops - address space operations for accessing mftbmp
*/
struct address_space_operations ntfs_mftbmp_aops = {
writepage: NULL, /* Write dirty page to disk. */
readpage: (readpage_t*)ntfs_mftbmp_readpage, /* Fill page with
data. */
sync_page: block_sync_page, /* Currently, just unplugs the
disk request queue. */
prepare_write: NULL, /* . */
commit_write: NULL, /* . */
};
......@@ -1316,7 +1316,7 @@ static int ntfs_read_locked_attr_inode(struct inode *base_vi, struct inode *vi)
ni->nr_extents = -1;
put_attr_search_ctx(ctx);
unmap_mft_record(READ, ni);
unmap_mft_record(READ, base_ni);
ntfs_debug("Done.");
return 0;
......
......@@ -232,6 +232,8 @@ static inline struct inode *VFS_I(ntfs_inode *ni)
}
extern struct inode *ntfs_iget(struct super_block *sb, unsigned long mft_no);
extern struct inode *ntfs_attr_iget(struct inode *base_vi, ATTR_TYPES type,
uchar_t *name, u32 name_len);
extern struct inode *ntfs_alloc_big_inode(struct super_block *sb);
extern void ntfs_destroy_big_inode(struct inode *inode);
......
......@@ -67,7 +67,6 @@ extern struct super_operations ntfs_mount_sops;
extern struct address_space_operations ntfs_aops;
extern struct address_space_operations ntfs_mft_aops;
extern struct address_space_operations ntfs_mftbmp_aops;
extern struct file_operations ntfs_file_ops;
extern struct inode_operations ntfs_file_inode_ops;
......
This diff is collapsed.
......@@ -75,15 +75,13 @@ typedef struct {
LCN mft_zone_start; /* First cluster of the mft zone. */
LCN mft_zone_end; /* First cluster beyond the mft zone. */
struct inode *mft_ino; /* The VFS inode of $MFT. */
struct inode *mftbmp_ino; /* Attribute inode for $MFT/$BITMAP. */
struct rw_semaphore mftbmp_lock; /* Lock for serializing accesses to the
mft record bitmap ($MFT/$BITMAP). */
unsigned long nr_mft_records; /* Number of mft records == number of
bits in mft bitmap. */
struct address_space mftbmp_mapping; /* Page cache for $MFT/$BITMAP. */
run_list mftbmp_rl; /* Run list for $MFT/$BITMAP. */
s64 mftbmp_size; /* Data size of $MFT/$BITMAP. */
s64 mftbmp_initialized_size; /* Initialized size of $MFT/$BITMAP. */
s64 mftbmp_allocated_size; /* Allocated size of $MFT/$BITMAP. */
struct inode *mftmirr_ino; /* The VFS inode of $MFTMirr. */
struct inode *lcnbmp_ino; /* The VFS inode of $Bitmap. */
struct rw_semaphore lcnbmp_lock; /* Lock for serializing accesses to the
......
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