mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
Merge with /home/shaggy/git/linus-clean/
Signed-off-by: Dave Kleikamp <shaggy@austin.ibm.com>
This commit is contained in:
+47
-34
@@ -15,66 +15,79 @@
|
||||
#include "xip.h"
|
||||
|
||||
static inline int
|
||||
__inode_direct_access(struct inode *inode, sector_t sector, unsigned long *data) {
|
||||
__inode_direct_access(struct inode *inode, sector_t sector,
|
||||
unsigned long *data)
|
||||
{
|
||||
BUG_ON(!inode->i_sb->s_bdev->bd_disk->fops->direct_access);
|
||||
return inode->i_sb->s_bdev->bd_disk->fops
|
||||
->direct_access(inode->i_sb->s_bdev,sector,data);
|
||||
}
|
||||
|
||||
static inline int
|
||||
__ext2_get_sector(struct inode *inode, sector_t offset, int create,
|
||||
sector_t *result)
|
||||
{
|
||||
struct buffer_head tmp;
|
||||
int rc;
|
||||
|
||||
memset(&tmp, 0, sizeof(struct buffer_head));
|
||||
rc = ext2_get_block(inode, offset/ (PAGE_SIZE/512), &tmp,
|
||||
create);
|
||||
*result = tmp.b_blocknr;
|
||||
|
||||
/* did we get a sparse block (hole in the file)? */
|
||||
if (!(*result)) {
|
||||
BUG_ON(create);
|
||||
rc = -ENODATA;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
ext2_clear_xip_target(struct inode *inode, int block) {
|
||||
sector_t sector = block*(PAGE_SIZE/512);
|
||||
ext2_clear_xip_target(struct inode *inode, int block)
|
||||
{
|
||||
sector_t sector = block * (PAGE_SIZE/512);
|
||||
unsigned long data;
|
||||
int rc;
|
||||
|
||||
rc = __inode_direct_access(inode, sector, &data);
|
||||
if (rc)
|
||||
return rc;
|
||||
clear_page((void*)data);
|
||||
return 0;
|
||||
if (!rc)
|
||||
clear_page((void*)data);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void ext2_xip_verify_sb(struct super_block *sb)
|
||||
{
|
||||
struct ext2_sb_info *sbi = EXT2_SB(sb);
|
||||
|
||||
if ((sbi->s_mount_opt & EXT2_MOUNT_XIP)) {
|
||||
if ((sb->s_bdev == NULL) ||
|
||||
sb->s_bdev->bd_disk == NULL ||
|
||||
sb->s_bdev->bd_disk->fops == NULL ||
|
||||
sb->s_bdev->bd_disk->fops->direct_access == NULL) {
|
||||
sbi->s_mount_opt &= (~EXT2_MOUNT_XIP);
|
||||
ext2_warning(sb, __FUNCTION__,
|
||||
"ignoring xip option - not supported by bdev");
|
||||
}
|
||||
if ((sbi->s_mount_opt & EXT2_MOUNT_XIP) &&
|
||||
!sb->s_bdev->bd_disk->fops->direct_access) {
|
||||
sbi->s_mount_opt &= (~EXT2_MOUNT_XIP);
|
||||
ext2_warning(sb, __FUNCTION__,
|
||||
"ignoring xip option - not supported by bdev");
|
||||
}
|
||||
}
|
||||
|
||||
struct page*
|
||||
ext2_get_xip_page(struct address_space *mapping, sector_t blockno,
|
||||
struct page *
|
||||
ext2_get_xip_page(struct address_space *mapping, sector_t offset,
|
||||
int create)
|
||||
{
|
||||
int rc;
|
||||
unsigned long data;
|
||||
struct buffer_head tmp;
|
||||
sector_t sector;
|
||||
|
||||
tmp.b_state = 0;
|
||||
tmp.b_blocknr = 0;
|
||||
rc = ext2_get_block(mapping->host, blockno/(PAGE_SIZE/512) , &tmp,
|
||||
create);
|
||||
/* first, retrieve the sector number */
|
||||
rc = __ext2_get_sector(mapping->host, offset, create, §or);
|
||||
if (rc)
|
||||
return ERR_PTR(rc);
|
||||
if (tmp.b_blocknr == 0) {
|
||||
/* SPARSE block */
|
||||
BUG_ON(create);
|
||||
return ERR_PTR(-ENODATA);
|
||||
}
|
||||
goto error;
|
||||
|
||||
/* retrieve address of the target data */
|
||||
rc = __inode_direct_access
|
||||
(mapping->host,tmp.b_blocknr*(PAGE_SIZE/512) ,&data);
|
||||
if (rc)
|
||||
return ERR_PTR(rc);
|
||||
(mapping->host, sector * (PAGE_SIZE/512), &data);
|
||||
if (!rc)
|
||||
return virt_to_page(data);
|
||||
|
||||
SetPageUptodate(virt_to_page(data));
|
||||
return virt_to_page(data);
|
||||
error:
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
+96
-86
@@ -7,7 +7,7 @@
|
||||
*
|
||||
* For licensing information, see the file 'LICENCE' in this directory.
|
||||
*
|
||||
* $Id: erase.c,v 1.76 2005/05/03 15:11:40 dedekind Exp $
|
||||
* $Id: erase.c,v 1.80 2005/07/14 19:46:24 joern Exp $
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -300,100 +300,86 @@ static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_erase
|
||||
jeb->last_node = NULL;
|
||||
}
|
||||
|
||||
static int jffs2_block_check_erase(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t *bad_offset)
|
||||
{
|
||||
void *ebuf;
|
||||
uint32_t ofs;
|
||||
size_t retlen;
|
||||
int ret = -EIO;
|
||||
|
||||
ebuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
if (!ebuf) {
|
||||
printk(KERN_WARNING "Failed to allocate page buffer for verifying erase at 0x%08x. Refiling\n", jeb->offset);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
D1(printk(KERN_DEBUG "Verifying erase at 0x%08x\n", jeb->offset));
|
||||
|
||||
for (ofs = jeb->offset; ofs < jeb->offset + c->sector_size; ) {
|
||||
uint32_t readlen = min((uint32_t)PAGE_SIZE, jeb->offset + c->sector_size - ofs);
|
||||
int i;
|
||||
|
||||
*bad_offset = ofs;
|
||||
|
||||
ret = jffs2_flash_read(c, ofs, readlen, &retlen, ebuf);
|
||||
if (ret) {
|
||||
printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret);
|
||||
goto fail;
|
||||
}
|
||||
if (retlen != readlen) {
|
||||
printk(KERN_WARNING "Short read from newly-erased block at 0x%08x. Wanted %d, got %zd\n", ofs, readlen, retlen);
|
||||
goto fail;
|
||||
}
|
||||
for (i=0; i<readlen; i += sizeof(unsigned long)) {
|
||||
/* It's OK. We know it's properly aligned */
|
||||
unsigned long *datum = ebuf + i;
|
||||
if (*datum + 1) {
|
||||
*bad_offset += i;
|
||||
printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", *datum, *bad_offset);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
ofs += readlen;
|
||||
cond_resched();
|
||||
}
|
||||
ret = 0;
|
||||
fail:
|
||||
kfree(ebuf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb)
|
||||
{
|
||||
struct jffs2_raw_node_ref *marker_ref = NULL;
|
||||
unsigned char *ebuf;
|
||||
size_t retlen;
|
||||
int ret;
|
||||
uint32_t bad_offset;
|
||||
|
||||
if ((!jffs2_cleanmarker_oob(c)) && (c->cleanmarker_size > 0)) {
|
||||
marker_ref = jffs2_alloc_raw_node_ref();
|
||||
if (!marker_ref) {
|
||||
printk(KERN_WARNING "Failed to allocate raw node ref for clean marker\n");
|
||||
/* Stick it back on the list from whence it came and come back later */
|
||||
jffs2_erase_pending_trigger(c);
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
list_add(&jeb->list, &c->erase_complete_list);
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
return;
|
||||
}
|
||||
switch (jffs2_block_check_erase(c, jeb, &bad_offset)) {
|
||||
case -EAGAIN: goto refile;
|
||||
case -EIO: goto filebad;
|
||||
}
|
||||
ebuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
|
||||
if (!ebuf) {
|
||||
printk(KERN_WARNING "Failed to allocate page buffer for verifying erase at 0x%08x. Assuming it worked\n", jeb->offset);
|
||||
} else {
|
||||
uint32_t ofs = jeb->offset;
|
||||
|
||||
D1(printk(KERN_DEBUG "Verifying erase at 0x%08x\n", jeb->offset));
|
||||
while(ofs < jeb->offset + c->sector_size) {
|
||||
uint32_t readlen = min((uint32_t)PAGE_SIZE, jeb->offset + c->sector_size - ofs);
|
||||
int i;
|
||||
|
||||
bad_offset = ofs;
|
||||
|
||||
ret = c->mtd->read(c->mtd, ofs, readlen, &retlen, ebuf);
|
||||
|
||||
if (ret) {
|
||||
printk(KERN_WARNING "Read of newly-erased block at 0x%08x failed: %d. Putting on bad_list\n", ofs, ret);
|
||||
goto bad;
|
||||
}
|
||||
if (retlen != readlen) {
|
||||
printk(KERN_WARNING "Short read from newly-erased block at 0x%08x. Wanted %d, got %zd\n", ofs, readlen, retlen);
|
||||
goto bad;
|
||||
}
|
||||
for (i=0; i<readlen; i += sizeof(unsigned long)) {
|
||||
/* It's OK. We know it's properly aligned */
|
||||
unsigned long datum = *(unsigned long *)(&ebuf[i]);
|
||||
if (datum + 1) {
|
||||
bad_offset += i;
|
||||
printk(KERN_WARNING "Newly-erased block contained word 0x%lx at offset 0x%08x\n", datum, bad_offset);
|
||||
bad:
|
||||
if ((!jffs2_cleanmarker_oob(c)) && (c->cleanmarker_size > 0))
|
||||
jffs2_free_raw_node_ref(marker_ref);
|
||||
kfree(ebuf);
|
||||
bad2:
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
/* Stick it on a list (any list) so
|
||||
erase_failed can take it right off
|
||||
again. Silly, but shouldn't happen
|
||||
often. */
|
||||
list_add(&jeb->list, &c->erasing_list);
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
jffs2_erase_failed(c, jeb, bad_offset);
|
||||
return;
|
||||
}
|
||||
}
|
||||
ofs += readlen;
|
||||
cond_resched();
|
||||
}
|
||||
kfree(ebuf);
|
||||
}
|
||||
|
||||
bad_offset = jeb->offset;
|
||||
|
||||
/* Write the erase complete marker */
|
||||
D1(printk(KERN_DEBUG "Writing erased marker to block at 0x%08x\n", jeb->offset));
|
||||
if (jffs2_cleanmarker_oob(c)) {
|
||||
bad_offset = jeb->offset;
|
||||
|
||||
/* Cleanmarker in oob area or no cleanmarker at all ? */
|
||||
if (jffs2_cleanmarker_oob(c) || c->cleanmarker_size == 0) {
|
||||
|
||||
if (jffs2_cleanmarker_oob(c)) {
|
||||
if (jffs2_write_nand_cleanmarker(c, jeb))
|
||||
goto filebad;
|
||||
}
|
||||
|
||||
if (jffs2_write_nand_cleanmarker(c, jeb))
|
||||
goto bad2;
|
||||
|
||||
jeb->first_node = jeb->last_node = NULL;
|
||||
|
||||
jeb->free_size = c->sector_size;
|
||||
jeb->used_size = 0;
|
||||
jeb->dirty_size = 0;
|
||||
jeb->wasted_size = 0;
|
||||
} else if (c->cleanmarker_size == 0) {
|
||||
jeb->first_node = jeb->last_node = NULL;
|
||||
|
||||
jeb->free_size = c->sector_size;
|
||||
jeb->used_size = 0;
|
||||
jeb->dirty_size = 0;
|
||||
jeb->wasted_size = 0;
|
||||
} else {
|
||||
|
||||
struct kvec vecs[1];
|
||||
struct jffs2_unknown_node marker = {
|
||||
.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK),
|
||||
@@ -401,21 +387,28 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
|
||||
.totlen = cpu_to_je32(c->cleanmarker_size)
|
||||
};
|
||||
|
||||
marker_ref = jffs2_alloc_raw_node_ref();
|
||||
if (!marker_ref) {
|
||||
printk(KERN_WARNING "Failed to allocate raw node ref for clean marker. Refiling\n");
|
||||
goto refile;
|
||||
}
|
||||
|
||||
marker.hdr_crc = cpu_to_je32(crc32(0, &marker, sizeof(struct jffs2_unknown_node)-4));
|
||||
|
||||
vecs[0].iov_base = (unsigned char *) ▮
|
||||
vecs[0].iov_len = sizeof(marker);
|
||||
ret = jffs2_flash_direct_writev(c, vecs, 1, jeb->offset, &retlen);
|
||||
|
||||
if (ret) {
|
||||
printk(KERN_WARNING "Write clean marker to block at 0x%08x failed: %d\n",
|
||||
jeb->offset, ret);
|
||||
goto bad2;
|
||||
}
|
||||
if (retlen != sizeof(marker)) {
|
||||
printk(KERN_WARNING "Short write to newly-erased block at 0x%08x: Wanted %zd, got %zd\n",
|
||||
jeb->offset, sizeof(marker), retlen);
|
||||
goto bad2;
|
||||
if (ret || retlen != sizeof(marker)) {
|
||||
if (ret)
|
||||
printk(KERN_WARNING "Write clean marker to block at 0x%08x failed: %d\n",
|
||||
jeb->offset, ret);
|
||||
else
|
||||
printk(KERN_WARNING "Short write to newly-erased block at 0x%08x: Wanted %zd, got %zd\n",
|
||||
jeb->offset, sizeof(marker), retlen);
|
||||
|
||||
jffs2_free_raw_node_ref(marker_ref);
|
||||
goto filebad;
|
||||
}
|
||||
|
||||
marker_ref->next_in_ino = NULL;
|
||||
@@ -444,5 +437,22 @@ static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseb
|
||||
c->nr_free_blocks++;
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
wake_up(&c->erase_wait);
|
||||
}
|
||||
return;
|
||||
|
||||
filebad:
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
/* Stick it on a list (any list) so erase_failed can take it
|
||||
right off again. Silly, but shouldn't happen often. */
|
||||
list_add(&jeb->list, &c->erasing_list);
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
jffs2_erase_failed(c, jeb, bad_offset);
|
||||
return;
|
||||
|
||||
refile:
|
||||
/* Stick it back on the list from whence it came and come back later */
|
||||
jffs2_erase_pending_trigger(c);
|
||||
spin_lock(&c->erase_completion_lock);
|
||||
list_add(&jeb->list, &c->erase_complete_list);
|
||||
spin_unlock(&c->erase_completion_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
+161
-18
@@ -1,21 +1,18 @@
|
||||
ToDo/Notes:
|
||||
- Find and fix bugs.
|
||||
- Checkpoint or disable the user space journal ($UsnJrnl).
|
||||
- In between ntfs_prepare/commit_write, need exclusion between
|
||||
simultaneous file extensions. Need perhaps an NInoResizeUnderway()
|
||||
flag which we can set in ntfs_prepare_write() and clear again in
|
||||
ntfs_commit_write(). Just have to be careful in readpage/writepage,
|
||||
as well as in truncate, that we play nice... We might need to have
|
||||
a data_size field in the ntfs_inode to store the real attribute
|
||||
length. Also need to be careful with initialized_size extention in
|
||||
simultaneous file extensions. This is given to us by holding i_sem
|
||||
on the inode. The only places in the kernel when a file is resized
|
||||
are prepare/commit write and truncate for both of which i_sem is
|
||||
held. Just have to be careful in readpage/writepage and all other
|
||||
helpers not running under i_sem that we play nice...
|
||||
Also need to be careful with initialized_size extention in
|
||||
ntfs_prepare_write. Basically, just be _very_ careful in this code...
|
||||
OTOH, perhaps i_sem, which is held accross generic_file_write is
|
||||
sufficient for synchronisation here. We then just need to make sure
|
||||
ntfs_readpage/writepage/truncate interoperate properly with us.
|
||||
UPDATE: The above is all ok as it is due to i_sem held. The only
|
||||
thing that needs to be checked is ntfs_writepage() which does not
|
||||
hold i_sem. It cannot change i_size but it needs to cope with a
|
||||
concurrent i_size change.
|
||||
UPDATE: The only things that need to be checked are read/writepage
|
||||
which do not hold i_sem. Note writepage cannot change i_size but it
|
||||
needs to cope with a concurrent i_size change, just like readpage.
|
||||
Also both need to cope with concurrent changes to the other sizes,
|
||||
i.e. initialized/allocated/compressed size, as well.
|
||||
- Implement mft.c::sync_mft_mirror_umount(). We currently will just
|
||||
leave the volume dirty on umount if the final iput(vol->mft_ino)
|
||||
causes a write of any mirrored mft records due to the mft mirror
|
||||
@@ -25,12 +22,158 @@ ToDo/Notes:
|
||||
- Enable the code for setting the NT4 compatibility flag when we start
|
||||
making NTFS 1.2 specific modifications.
|
||||
|
||||
2.1.23-WIP
|
||||
2.1.23 - Implement extension of resident files and make writing safe as well as
|
||||
many bug fixes, cleanups, and enhancements...
|
||||
|
||||
- Add printk rate limiting for ntfs_warning() and ntfs_error() when
|
||||
compiled without debug. This avoids a possible denial of service
|
||||
attack. Thanks to Carl-Daniel Hailfinger from SuSE for pointing this
|
||||
out.
|
||||
- Fix compilation warnings on ia64. (Randy Dunlap)
|
||||
- Use i_size_{read,write}() instead of reading i_size by hand and cache
|
||||
the value where apropriate.
|
||||
- Add size_lock to the ntfs_inode structure. This is an rw spinlock
|
||||
and it locks against access to the inode sizes. Note, ->size_lock
|
||||
is also accessed from irq context so you must use the _irqsave and
|
||||
_irqrestore lock and unlock functions, respectively. Protect all
|
||||
accesses to allocated_size, initialized_size, and compressed_size.
|
||||
- Minor optimization to fs/ntfs/super.c::ntfs_statfs() and its helpers.
|
||||
- Implement extension of resident files in the regular file write code
|
||||
paths (fs/ntfs/aops.c::ntfs_{prepare,commit}_write()). At present
|
||||
this only works until the data attribute becomes too big for the mft
|
||||
record after which we abort the write returning -EOPNOTSUPP from
|
||||
ntfs_prepare_write().
|
||||
- Add disable_sparse mount option together with a per volume sparse
|
||||
enable bit which is set appropriately and a per inode sparse disable
|
||||
bit which is preset on some system file inodes as appropriate.
|
||||
- Enforce that sparse support is disabled on NTFS volumes pre 3.0.
|
||||
- Fix a bug in fs/ntfs/runlist.c::ntfs_mapping_pairs_decompress() in
|
||||
the creation of the unmapped runlist element for the base attribute
|
||||
extent.
|
||||
- Split ntfs_map_runlist() into ntfs_map_runlist() and a non-locking
|
||||
helper ntfs_map_runlist_nolock() which is used by ntfs_map_runlist().
|
||||
This allows us to map runlist fragments with the runlist lock already
|
||||
held without having to drop and reacquire it around the call. Adapt
|
||||
all callers.
|
||||
- Change ntfs_find_vcn() to ntfs_find_vcn_nolock() which takes a locked
|
||||
runlist. This allows us to find runlist elements with the runlist
|
||||
lock already held without having to drop and reacquire it around the
|
||||
call. Adapt all callers.
|
||||
- Change time to u64 in time.h::ntfs2utc() as it otherwise generates a
|
||||
warning in the do_div() call on sparc32. Thanks to Meelis Roos for
|
||||
the report and analysis of the warning.
|
||||
- Fix a nasty runlist merge bug when merging two holes.
|
||||
- Set the ntfs_inode->allocated_size to the real allocated size in the
|
||||
mft record for resident attributes (fs/ntfs/inode.c).
|
||||
- Small readability cleanup to use "a" instead of "ctx->attr"
|
||||
everywhere (fs/ntfs/inode.c).
|
||||
- Make fs/ntfs/namei.c::ntfs_get_{parent,dentry} static and move the
|
||||
definition of ntfs_export_ops from fs/ntfs/super.c to namei.c. Also,
|
||||
declare ntfs_export_ops in fs/ntfs/ntfs.h.
|
||||
- Correct sparse file handling. The compressed values need to be
|
||||
checked and set in the ntfs inode as done for compressed files and
|
||||
the compressed size needs to be used for vfs inode->i_blocks instead
|
||||
of the allocated size, again, as done for compressed files.
|
||||
- Add AT_EA in addition to AT_DATA to whitelist for being allowed to be
|
||||
non-resident in fs/ntfs/attrib.c::ntfs_attr_can_be_non_resident().
|
||||
- Add fs/ntfs/attrib.c::ntfs_attr_vcn_to_lcn_nolock() used by the new
|
||||
write code.
|
||||
- Fix bug in fs/ntfs/attrib.c::ntfs_find_vcn_nolock() where after
|
||||
dropping the read lock and taking the write lock we were not checking
|
||||
whether someone else did not already do the work we wanted to do.
|
||||
- Rename fs/ntfs/attrib.c::ntfs_find_vcn_nolock() to
|
||||
ntfs_attr_find_vcn_nolock() and update all callers.
|
||||
- Add fs/ntfs/attrib.[hc]::ntfs_attr_make_non_resident().
|
||||
- Fix sign of various error return values to be negative in
|
||||
fs/ntfs/lcnalloc.c.
|
||||
- Modify ->readpage and ->writepage (fs/ntfs/aops.c) so they detect and
|
||||
handle the case where an attribute is converted from resident to
|
||||
non-resident by a concurrent file write.
|
||||
- Remove checks for NULL before calling kfree() since kfree() does the
|
||||
checking itself. (Jesper Juhl)
|
||||
- Some utilities modify the boot sector but do not update the checksum.
|
||||
Thus, relax the checking in fs/ntfs/super.c::is_boot_sector_ntfs() to
|
||||
only emit a warning when the checksum is incorrect rather than
|
||||
refusing the mount. Thanks to Bernd Casimir for pointing this
|
||||
problem out.
|
||||
- Update attribute definition handling.
|
||||
- Add NTFS_MAX_CLUSTER_SIZE and NTFS_MAX_PAGES_PER_CLUSTER constants.
|
||||
- Use NTFS_MAX_CLUSTER_SIZE in super.c instead of hard coding 0x10000.
|
||||
- Use MAX_BUF_PER_PAGE instead of variable sized array allocation for
|
||||
better code generation and one less sparse warning in fs/ntfs/aops.c.
|
||||
- Remove spurious void pointer casts from fs/ntfs/. (Pekka Enberg)
|
||||
- Use C99 style structure initialization after memory allocation where
|
||||
possible (fs/ntfs/{attrib.c,index.c,super.c}). Thanks to Al Viro and
|
||||
Pekka Enberg.
|
||||
- Stamp the transaction log ($UsnJrnl), aka user space journal, if it
|
||||
is active on the volume and we are mounting read-write or remounting
|
||||
from read-only to read-write.
|
||||
- Fix a bug in address space operations error recovery code paths where
|
||||
if the runlist was not mapped at all and a mapping error occured we
|
||||
would leave the runlist locked on exit to the function so that the
|
||||
next access to the same file would try to take the lock and deadlock.
|
||||
- Detect the case when Windows has been suspended to disk on the volume
|
||||
to be mounted and if this is the case do not allow (re)mounting
|
||||
read-write. This is done by parsing hiberfil.sys if present.
|
||||
- Fix several occurences of a bug where we would perform 'var & ~const'
|
||||
with a 64-bit variable and a int, i.e. 32-bit, constant. This causes
|
||||
the higher order 32-bits of the 64-bit variable to be zeroed. To fix
|
||||
this cast the 'const' to the same 64-bit type as 'var'.
|
||||
- Change the runlist terminator of the newly allocated cluster(s) to
|
||||
LCN_ENOENT in ntfs_attr_make_non_resident(). Otherwise the runlist
|
||||
code gets confused.
|
||||
- Add an extra parameter @last_vcn to ntfs_get_size_for_mapping_pairs()
|
||||
and ntfs_mapping_pairs_build() to allow the runlist encoding to be
|
||||
partial which is desirable when filling holes in sparse attributes.
|
||||
Update all callers.
|
||||
- Change ntfs_map_runlist_nolock() to only decompress the mapping pairs
|
||||
if the requested vcn is inside it. Otherwise we get into problems
|
||||
when we try to map an out of bounds vcn because we then try to map
|
||||
the already mapped runlist fragment which causes
|
||||
ntfs_mapping_pairs_decompress() to fail and return error. Update
|
||||
ntfs_attr_find_vcn_nolock() accordingly.
|
||||
- Fix a nasty deadlock that appeared in recent kernels.
|
||||
The situation: VFS inode X on a mounted ntfs volume is dirty. For
|
||||
same inode X, the ntfs_inode is dirty and thus corresponding on-disk
|
||||
inode, i.e. mft record, which is in a dirty PAGE_CACHE_PAGE belonging
|
||||
to the table of inodes, i.e. $MFT, inode 0.
|
||||
What happens:
|
||||
Process 1: sys_sync()/umount()/whatever... calls
|
||||
__sync_single_inode() for $MFT -> do_writepages() -> write_page for
|
||||
the dirty page containing the on-disk inode X, the page is now locked
|
||||
-> ntfs_write_mst_block() which clears PageUptodate() on the page to
|
||||
prevent anyone else getting hold of it whilst it does the write out.
|
||||
This is necessary as the on-disk inode needs "fixups" applied before
|
||||
the write to disk which are removed again after the write and
|
||||
PageUptodate is then set again. It then analyses the page looking
|
||||
for dirty on-disk inodes and when it finds one it calls
|
||||
ntfs_may_write_mft_record() to see if it is safe to write this
|
||||
on-disk inode. This then calls ilookup5() to check if the
|
||||
corresponding VFS inode is in icache(). This in turn calls ifind()
|
||||
which waits on the inode lock via wait_on_inode whilst holding the
|
||||
global inode_lock.
|
||||
Process 2: pdflush results in a call to __sync_single_inode for the
|
||||
same VFS inode X on the ntfs volume. This locks the inode (I_LOCK)
|
||||
then calls write-inode -> ntfs_write_inode -> map_mft_record() ->
|
||||
read_cache_page() for the page (in page cache of table of inodes
|
||||
$MFT, inode 0) containing the on-disk inode. This page has
|
||||
PageUptodate() clear because of Process 1 (see above) so
|
||||
read_cache_page() blocks when it tries to take the page lock for the
|
||||
page so it can call ntfs_read_page().
|
||||
Thus Process 1 is holding the page lock on the page containing the
|
||||
on-disk inode X and it is waiting on the inode X to be unlocked in
|
||||
ifind() so it can write the page out and then unlock the page.
|
||||
And Process 2 is holding the inode lock on inode X and is waiting for
|
||||
the page to be unlocked so it can call ntfs_readpage() or discover
|
||||
that Process 1 set PageUptodate() again and use the page.
|
||||
Thus we have a deadlock due to ifind() waiting on the inode lock.
|
||||
The solution: The fix is to use the newly introduced
|
||||
ilookup5_nowait() which does not wait on the inode's lock and hence
|
||||
avoids the deadlock. This is safe as we do not care about the VFS
|
||||
inode and only use the fact that it is in the VFS inode cache and the
|
||||
fact that the vfs and ntfs inodes are one struct in memory to find
|
||||
the ntfs inode in memory if present. Also, the ntfs inode has its
|
||||
own locking so it does not matter if the vfs inode is locked.
|
||||
|
||||
2.1.22 - Many bug and race fixes and error handling improvements.
|
||||
|
||||
@@ -1037,7 +1180,7 @@ tng-0.0.8 - 08/03/2002 - Now using BitKeeper, http://linux-ntfs.bkbits.net/
|
||||
- Further runlist merging work. (Richard Russon)
|
||||
- Backwards compatibility for gcc-2.95. (Richard Russon)
|
||||
- Update to kernel 2.5.5-pre1 and rediff the now tiny patch.
|
||||
- Convert to new file system declaration using ->ntfs_get_sb() and
|
||||
- Convert to new filesystem declaration using ->ntfs_get_sb() and
|
||||
replacing ntfs_read_super() with ntfs_fill_super().
|
||||
- Set s_maxbytes to MAX_LFS_FILESIZE to avoid page cache page index
|
||||
overflow on 32-bit architectures.
|
||||
@@ -1333,7 +1476,7 @@ tng-0.0.1 - The first useful version.
|
||||
The driver is now actually useful! Yey. (-: It undoubtedly has got bugs
|
||||
though and it doesn't implement accesssing compressed files yet. Also,
|
||||
accessing files with attribute list attributes is not implemented yet
|
||||
either. But for small or simple file systems it should work and allow
|
||||
either. But for small or simple filesystems it should work and allow
|
||||
you to list directories, use stat on directory entries and the file
|
||||
system, open, read, mmap and llseek around in files. A big mile stone
|
||||
has been reached!
|
||||
@@ -1341,7 +1484,7 @@ tng-0.0.1 - The first useful version.
|
||||
tng-0.0.0 - Initial version tag.
|
||||
|
||||
Initial driver implementation. The driver can mount and umount simple
|
||||
NTFS file systems (i.e. ones without attribute lists in the system
|
||||
NTFS filesystems (i.e. ones without attribute lists in the system
|
||||
files). If the mount fails there might be problems in the error handling
|
||||
code paths, so be warned. Otherwise it seems to be loading the system
|
||||
files nicely and the mft record read mapping/unmapping seems to be
|
||||
|
||||
+2
-2
@@ -6,7 +6,7 @@ ntfs-objs := aops.o attrib.o collate.o compress.o debug.o dir.o file.o \
|
||||
index.o inode.o mft.o mst.o namei.o runlist.o super.o sysctl.o \
|
||||
unistr.o upcase.o
|
||||
|
||||
EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.22\"
|
||||
EXTRA_CFLAGS = -DNTFS_VERSION=\"2.1.23\"
|
||||
|
||||
ifeq ($(CONFIG_NTFS_DEBUG),y)
|
||||
EXTRA_CFLAGS += -DDEBUG
|
||||
@@ -15,5 +15,5 @@ endif
|
||||
ifeq ($(CONFIG_NTFS_RW),y)
|
||||
EXTRA_CFLAGS += -DNTFS_RW
|
||||
|
||||
ntfs-objs += bitmap.o lcnalloc.o logfile.o quota.o
|
||||
ntfs-objs += bitmap.o lcnalloc.o logfile.o quota.o usnjrnl.o
|
||||
endif
|
||||
|
||||
+110
-56
@@ -2,7 +2,7 @@
|
||||
* aops.c - NTFS kernel address space operations and page cache handling.
|
||||
* Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2001-2004 Anton Altaparmakov
|
||||
* Copyright (c) 2001-2005 Anton Altaparmakov
|
||||
* Copyright (c) 2002 Richard Russon
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
@@ -66,19 +66,22 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate)
|
||||
ni = NTFS_I(page->mapping->host);
|
||||
|
||||
if (likely(uptodate)) {
|
||||
s64 file_ofs;
|
||||
s64 file_ofs, initialized_size;
|
||||
|
||||
set_buffer_uptodate(bh);
|
||||
|
||||
file_ofs = ((s64)page->index << PAGE_CACHE_SHIFT) +
|
||||
bh_offset(bh);
|
||||
read_lock_irqsave(&ni->size_lock, flags);
|
||||
initialized_size = ni->initialized_size;
|
||||
read_unlock_irqrestore(&ni->size_lock, flags);
|
||||
/* Check for the current buffer head overflowing. */
|
||||
if (file_ofs + bh->b_size > ni->initialized_size) {
|
||||
if (file_ofs + bh->b_size > initialized_size) {
|
||||
char *addr;
|
||||
int ofs = 0;
|
||||
|
||||
if (file_ofs < ni->initialized_size)
|
||||
ofs = ni->initialized_size - file_ofs;
|
||||
if (file_ofs < initialized_size)
|
||||
ofs = 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);
|
||||
@@ -132,7 +135,7 @@ static void ntfs_end_buffer_async_read(struct buffer_head *bh, int uptodate)
|
||||
i * rec_size), rec_size);
|
||||
flush_dcache_page(page);
|
||||
kunmap_atomic(addr, KM_BIO_SRC_IRQ);
|
||||
if (likely(!PageError(page) && page_uptodate))
|
||||
if (likely(page_uptodate && !PageError(page)))
|
||||
SetPageUptodate(page);
|
||||
}
|
||||
unlock_page(page);
|
||||
@@ -168,6 +171,7 @@ static int ntfs_read_block(struct page *page)
|
||||
runlist_element *rl;
|
||||
struct buffer_head *bh, *head, *arr[MAX_BUF_PER_PAGE];
|
||||
sector_t iblock, lblock, zblock;
|
||||
unsigned long flags;
|
||||
unsigned int blocksize, vcn_ofs;
|
||||
int i, nr;
|
||||
unsigned char blocksize_bits;
|
||||
@@ -190,8 +194,10 @@ static int ntfs_read_block(struct page *page)
|
||||
}
|
||||
|
||||
iblock = (s64)page->index << (PAGE_CACHE_SHIFT - blocksize_bits);
|
||||
read_lock_irqsave(&ni->size_lock, flags);
|
||||
lblock = (ni->allocated_size + blocksize - 1) >> blocksize_bits;
|
||||
zblock = (ni->initialized_size + blocksize - 1) >> blocksize_bits;
|
||||
read_unlock_irqrestore(&ni->size_lock, flags);
|
||||
|
||||
/* Loop through all the buffers in the page. */
|
||||
rl = NULL;
|
||||
@@ -258,7 +264,8 @@ lock_retry_remap:
|
||||
goto lock_retry_remap;
|
||||
rl = NULL;
|
||||
lcn = err;
|
||||
}
|
||||
} else if (!rl)
|
||||
up_read(&ni->runlist.lock);
|
||||
/* Hard error, zero out region. */
|
||||
bh->b_blocknr = -1;
|
||||
SetPageError(page);
|
||||
@@ -341,14 +348,15 @@ handle_zblock:
|
||||
*/
|
||||
static int ntfs_readpage(struct file *file, struct page *page)
|
||||
{
|
||||
loff_t i_size;
|
||||
ntfs_inode *ni, *base_ni;
|
||||
u8 *kaddr;
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
MFT_RECORD *mrec;
|
||||
unsigned long flags;
|
||||
u32 attr_len;
|
||||
int err = 0;
|
||||
|
||||
retry_readpage:
|
||||
BUG_ON(!PageLocked(page));
|
||||
/*
|
||||
* This can potentially happen because we clear PageUptodate() during
|
||||
@@ -383,9 +391,9 @@ static int ntfs_readpage(struct file *file, struct page *page)
|
||||
* Attribute is resident, implying it is not compressed or encrypted.
|
||||
* This also means the attribute is smaller than an mft record and
|
||||
* hence smaller than a page, so can simply zero out any pages with
|
||||
* index above 0. We can also do this if the file size is 0.
|
||||
* index above 0.
|
||||
*/
|
||||
if (unlikely(page->index > 0 || !i_size_read(VFS_I(ni)))) {
|
||||
if (unlikely(page->index > 0)) {
|
||||
kaddr = kmap_atomic(page, KM_USER0);
|
||||
memset(kaddr, 0, PAGE_CACHE_SIZE);
|
||||
flush_dcache_page(page);
|
||||
@@ -402,6 +410,14 @@ static int ntfs_readpage(struct file *file, struct page *page)
|
||||
err = PTR_ERR(mrec);
|
||||
goto err_out;
|
||||
}
|
||||
/*
|
||||
* If a parallel write made the attribute non-resident, drop the mft
|
||||
* record and retry the readpage.
|
||||
*/
|
||||
if (unlikely(NInoNonResident(ni))) {
|
||||
unmap_mft_record(base_ni);
|
||||
goto retry_readpage;
|
||||
}
|
||||
ctx = ntfs_attr_get_search_ctx(base_ni, mrec);
|
||||
if (unlikely(!ctx)) {
|
||||
err = -ENOMEM;
|
||||
@@ -412,9 +428,10 @@ static int ntfs_readpage(struct file *file, struct page *page)
|
||||
if (unlikely(err))
|
||||
goto put_unm_err_out;
|
||||
attr_len = le32_to_cpu(ctx->attr->data.resident.value_length);
|
||||
i_size = i_size_read(VFS_I(ni));
|
||||
if (unlikely(attr_len > i_size))
|
||||
attr_len = i_size;
|
||||
read_lock_irqsave(&ni->size_lock, flags);
|
||||
if (unlikely(attr_len > ni->initialized_size))
|
||||
attr_len = ni->initialized_size;
|
||||
read_unlock_irqrestore(&ni->size_lock, flags);
|
||||
kaddr = kmap_atomic(page, KM_USER0);
|
||||
/* Copy the data to the page. */
|
||||
memcpy(kaddr, (u8*)ctx->attr +
|
||||
@@ -463,12 +480,15 @@ static int ntfs_write_block(struct page *page, struct writeback_control *wbc)
|
||||
{
|
||||
VCN vcn;
|
||||
LCN lcn;
|
||||
s64 initialized_size;
|
||||
loff_t i_size;
|
||||
sector_t block, dblock, iblock;
|
||||
struct inode *vi;
|
||||
ntfs_inode *ni;
|
||||
ntfs_volume *vol;
|
||||
runlist_element *rl;
|
||||
struct buffer_head *bh, *head;
|
||||
unsigned long flags;
|
||||
unsigned int blocksize, vcn_ofs;
|
||||
int err;
|
||||
BOOL need_end_writeback;
|
||||
@@ -510,11 +530,16 @@ static int ntfs_write_block(struct page *page, struct writeback_control *wbc)
|
||||
/* The first block in the page. */
|
||||
block = (s64)page->index << (PAGE_CACHE_SHIFT - blocksize_bits);
|
||||
|
||||
read_lock_irqsave(&ni->size_lock, flags);
|
||||
i_size = i_size_read(vi);
|
||||
initialized_size = ni->initialized_size;
|
||||
read_unlock_irqrestore(&ni->size_lock, flags);
|
||||
|
||||
/* The first out of bounds block for the data size. */
|
||||
dblock = (vi->i_size + blocksize - 1) >> blocksize_bits;
|
||||
dblock = (i_size + blocksize - 1) >> blocksize_bits;
|
||||
|
||||
/* The last (fully or partially) initialized block. */
|
||||
iblock = ni->initialized_size >> blocksize_bits;
|
||||
iblock = initialized_size >> blocksize_bits;
|
||||
|
||||
/*
|
||||
* Be very careful. We have no exclusion from __set_page_dirty_buffers
|
||||
@@ -559,7 +584,7 @@ static int ntfs_write_block(struct page *page, struct writeback_control *wbc)
|
||||
|
||||
/* Make sure we have enough initialized size. */
|
||||
if (unlikely((block >= iblock) &&
|
||||
(ni->initialized_size < vi->i_size))) {
|
||||
(initialized_size < i_size))) {
|
||||
/*
|
||||
* If this page is fully outside initialized size, zero
|
||||
* out all pages between the current initialized size
|
||||
@@ -666,7 +691,8 @@ lock_retry_remap:
|
||||
goto lock_retry_remap;
|
||||
rl = NULL;
|
||||
lcn = err;
|
||||
}
|
||||
} else if (!rl)
|
||||
up_read(&ni->runlist.lock);
|
||||
/* Failed to map the buffer, even after retrying. */
|
||||
bh->b_blocknr = -1;
|
||||
ntfs_error(vol->sb, "Failed to write to inode 0x%lx, "
|
||||
@@ -801,17 +827,15 @@ static int ntfs_write_mst_block(struct page *page,
|
||||
ntfs_inode *ni = NTFS_I(vi);
|
||||
ntfs_volume *vol = ni->vol;
|
||||
u8 *kaddr;
|
||||
unsigned char bh_size_bits = vi->i_blkbits;
|
||||
unsigned int bh_size = 1 << bh_size_bits;
|
||||
unsigned int rec_size = ni->itype.index.block_size;
|
||||
ntfs_inode *locked_nis[PAGE_CACHE_SIZE / rec_size];
|
||||
struct buffer_head *bh, *head, *tbh, *rec_start_bh;
|
||||
int max_bhs = PAGE_CACHE_SIZE / bh_size;
|
||||
struct buffer_head *bhs[max_bhs];
|
||||
struct buffer_head *bhs[MAX_BUF_PER_PAGE];
|
||||
runlist_element *rl;
|
||||
int i, nr_locked_nis, nr_recs, nr_bhs, bhs_per_rec, err, err2;
|
||||
unsigned rec_size_bits;
|
||||
int i, nr_locked_nis, nr_recs, nr_bhs, max_bhs, bhs_per_rec, err, err2;
|
||||
unsigned bh_size, rec_size_bits;
|
||||
BOOL sync, is_mft, page_is_dirty, rec_is_dirty;
|
||||
unsigned char bh_size_bits;
|
||||
|
||||
ntfs_debug("Entering for inode 0x%lx, attribute type 0x%x, page index "
|
||||
"0x%lx.", vi->i_ino, ni->type, page->index);
|
||||
@@ -826,7 +850,11 @@ static int ntfs_write_mst_block(struct page *page,
|
||||
*/
|
||||
BUG_ON(!(is_mft || S_ISDIR(vi->i_mode) ||
|
||||
(NInoAttr(ni) && ni->type == AT_INDEX_ALLOCATION)));
|
||||
bh_size_bits = vi->i_blkbits;
|
||||
bh_size = 1 << bh_size_bits;
|
||||
max_bhs = PAGE_CACHE_SIZE / bh_size;
|
||||
BUG_ON(!max_bhs);
|
||||
BUG_ON(max_bhs > MAX_BUF_PER_PAGE);
|
||||
|
||||
/* Were we called for sync purposes? */
|
||||
sync = (wbc->sync_mode == WB_SYNC_ALL);
|
||||
@@ -846,7 +874,7 @@ static int ntfs_write_mst_block(struct page *page,
|
||||
(PAGE_CACHE_SHIFT - bh_size_bits);
|
||||
|
||||
/* The first out of bounds block for the data size. */
|
||||
dblock = (vi->i_size + bh_size - 1) >> bh_size_bits;
|
||||
dblock = (i_size_read(vi) + bh_size - 1) >> bh_size_bits;
|
||||
|
||||
rl = NULL;
|
||||
err = err2 = nr_bhs = nr_recs = nr_locked_nis = 0;
|
||||
@@ -858,6 +886,7 @@ static int ntfs_write_mst_block(struct page *page,
|
||||
if (likely(block < rec_block)) {
|
||||
if (unlikely(block >= dblock)) {
|
||||
clear_buffer_dirty(bh);
|
||||
set_buffer_uptodate(bh);
|
||||
continue;
|
||||
}
|
||||
/*
|
||||
@@ -938,8 +967,11 @@ lock_retry_remap:
|
||||
if (err2 == -ENOMEM)
|
||||
page_is_dirty = TRUE;
|
||||
lcn = err2;
|
||||
} else
|
||||
} else {
|
||||
err2 = -EIO;
|
||||
if (!rl)
|
||||
up_read(&ni->runlist.lock);
|
||||
}
|
||||
/* Hard error. Abort writing this record. */
|
||||
if (!err || err == -ENOMEM)
|
||||
err = err2;
|
||||
@@ -949,7 +981,8 @@ lock_retry_remap:
|
||||
"attribute type 0x%x) because "
|
||||
"its location on disk could "
|
||||
"not be determined (error "
|
||||
"code %lli).", (s64)block <<
|
||||
"code %lli).",
|
||||
(long long)block <<
|
||||
bh_size_bits >>
|
||||
vol->mft_record_size_bits,
|
||||
ni->mft_no, ni->type,
|
||||
@@ -1223,19 +1256,17 @@ done:
|
||||
static int ntfs_writepage(struct page *page, struct writeback_control *wbc)
|
||||
{
|
||||
loff_t i_size;
|
||||
struct inode *vi;
|
||||
ntfs_inode *ni, *base_ni;
|
||||
struct inode *vi = page->mapping->host;
|
||||
ntfs_inode *base_ni = NULL, *ni = NTFS_I(vi);
|
||||
char *kaddr;
|
||||
ntfs_attr_search_ctx *ctx;
|
||||
MFT_RECORD *m;
|
||||
ntfs_attr_search_ctx *ctx = NULL;
|
||||
MFT_RECORD *m = NULL;
|
||||
u32 attr_len;
|
||||
int err;
|
||||
|
||||
retry_writepage:
|
||||
BUG_ON(!PageLocked(page));
|
||||
|
||||
vi = page->mapping->host;
|
||||
i_size = i_size_read(vi);
|
||||
|
||||
/* Is the page fully outside i_size? (truncate in progress) */
|
||||
if (unlikely(page->index >= (i_size + PAGE_CACHE_SIZE - 1) >>
|
||||
PAGE_CACHE_SHIFT)) {
|
||||
@@ -1248,8 +1279,6 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc)
|
||||
ntfs_debug("Write outside i_size - truncated?");
|
||||
return 0;
|
||||
}
|
||||
ni = NTFS_I(vi);
|
||||
|
||||
/* NInoNonResident() == NInoIndexAllocPresent() */
|
||||
if (NInoNonResident(ni)) {
|
||||
/*
|
||||
@@ -1326,6 +1355,14 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc)
|
||||
ctx = NULL;
|
||||
goto err_out;
|
||||
}
|
||||
/*
|
||||
* If a parallel write made the attribute non-resident, drop the mft
|
||||
* record and retry the writepage.
|
||||
*/
|
||||
if (unlikely(NInoNonResident(ni))) {
|
||||
unmap_mft_record(base_ni);
|
||||
goto retry_writepage;
|
||||
}
|
||||
ctx = ntfs_attr_get_search_ctx(base_ni, m);
|
||||
if (unlikely(!ctx)) {
|
||||
err = -ENOMEM;
|
||||
@@ -1367,15 +1404,12 @@ static int ntfs_writepage(struct page *page, struct writeback_control *wbc)
|
||||
*/
|
||||
|
||||
attr_len = le32_to_cpu(ctx->attr->data.resident.value_length);
|
||||
i_size = i_size_read(VFS_I(ni));
|
||||
kaddr = kmap_atomic(page, KM_USER0);
|
||||
i_size = i_size_read(vi);
|
||||
if (unlikely(attr_len > i_size)) {
|
||||
/* Zero out of bounds area in the mft record. */
|
||||
memset((u8*)ctx->attr + le16_to_cpu(
|
||||
ctx->attr->data.resident.value_offset) +
|
||||
i_size, 0, attr_len - i_size);
|
||||
attr_len = i_size;
|
||||
ctx->attr->data.resident.value_length = cpu_to_le32(attr_len);
|
||||
}
|
||||
kaddr = kmap_atomic(page, KM_USER0);
|
||||
/* Copy the data from the page to the mft record. */
|
||||
memcpy((u8*)ctx->attr +
|
||||
le16_to_cpu(ctx->attr->data.resident.value_offset),
|
||||
@@ -1405,8 +1439,10 @@ err_out:
|
||||
err = 0;
|
||||
} else {
|
||||
ntfs_error(vi->i_sb, "Resident attribute write failed with "
|
||||
"error %i. Setting page error flag.", err);
|
||||
"error %i.", err);
|
||||
SetPageError(page);
|
||||
NVolSetErrors(ni->vol);
|
||||
make_bad_inode(vi);
|
||||
}
|
||||
unlock_page(page);
|
||||
if (ctx)
|
||||
@@ -1425,12 +1461,15 @@ static int ntfs_prepare_nonresident_write(struct page *page,
|
||||
{
|
||||
VCN vcn;
|
||||
LCN lcn;
|
||||
s64 initialized_size;
|
||||
loff_t i_size;
|
||||
sector_t block, ablock, iblock;
|
||||
struct inode *vi;
|
||||
ntfs_inode *ni;
|
||||
ntfs_volume *vol;
|
||||
runlist_element *rl;
|
||||
struct buffer_head *bh, *head, *wait[2], **wait_bh = wait;
|
||||
unsigned long flags;
|
||||
unsigned int vcn_ofs, block_start, block_end, blocksize;
|
||||
int err;
|
||||
BOOL is_retry;
|
||||
@@ -1462,16 +1501,20 @@ static int ntfs_prepare_nonresident_write(struct page *page,
|
||||
/* The first block in the page. */
|
||||
block = (s64)page->index << (PAGE_CACHE_SHIFT - blocksize_bits);
|
||||
|
||||
read_lock_irqsave(&ni->size_lock, flags);
|
||||
/*
|
||||
* The first out of bounds block for the allocated size. No need to
|
||||
* The first out of bounds block for the allocated size. No need to
|
||||
* round up as allocated_size is in multiples of cluster size and the
|
||||
* minimum cluster size is 512 bytes, which is equal to the smallest
|
||||
* blocksize.
|
||||
*/
|
||||
ablock = ni->allocated_size >> blocksize_bits;
|
||||
i_size = i_size_read(vi);
|
||||
initialized_size = ni->initialized_size;
|
||||
read_unlock_irqrestore(&ni->size_lock, flags);
|
||||
|
||||
/* The last (fully or partially) initialized block. */
|
||||
iblock = ni->initialized_size >> blocksize_bits;
|
||||
iblock = initialized_size >> blocksize_bits;
|
||||
|
||||
/* Loop through all the buffers in the page. */
|
||||
block_start = 0;
|
||||
@@ -1518,7 +1561,7 @@ static int ntfs_prepare_nonresident_write(struct page *page,
|
||||
* request, i.e. block < ablock is true.
|
||||
*/
|
||||
if (unlikely((block >= iblock) &&
|
||||
(ni->initialized_size < vi->i_size))) {
|
||||
(initialized_size < i_size))) {
|
||||
/*
|
||||
* If this page is fully outside initialized size, zero
|
||||
* out all pages between the current initialized size
|
||||
@@ -1622,6 +1665,8 @@ lock_retry_remap:
|
||||
"not supported yet. "
|
||||
"Sorry.");
|
||||
err = -EOPNOTSUPP;
|
||||
if (!rl)
|
||||
up_read(&ni->runlist.lock);
|
||||
goto err_out;
|
||||
} else if (!is_retry &&
|
||||
lcn == LCN_RL_NOT_MAPPED) {
|
||||
@@ -1636,7 +1681,8 @@ lock_retry_remap:
|
||||
goto lock_retry_remap;
|
||||
rl = NULL;
|
||||
lcn = err;
|
||||
}
|
||||
} else if (!rl)
|
||||
up_read(&ni->runlist.lock);
|
||||
/*
|
||||
* Failed to map the buffer, even after
|
||||
* retrying.
|
||||
@@ -1797,6 +1843,7 @@ static int ntfs_prepare_write(struct file *file, struct page *page,
|
||||
unsigned from, unsigned to)
|
||||
{
|
||||
s64 new_size;
|
||||
loff_t i_size;
|
||||
struct inode *vi = page->mapping->host;
|
||||
ntfs_inode *base_ni = NULL, *ni = NTFS_I(vi);
|
||||
ntfs_volume *vol = ni->vol;
|
||||
@@ -1868,14 +1915,8 @@ static int ntfs_prepare_write(struct file *file, struct page *page,
|
||||
BUG_ON(page_has_buffers(page));
|
||||
new_size = ((s64)page->index << PAGE_CACHE_SHIFT) + to;
|
||||
/* If we do not need to resize the attribute allocation we are done. */
|
||||
if (new_size <= vi->i_size)
|
||||
if (new_size <= i_size_read(vi))
|
||||
goto done;
|
||||
|
||||
// FIXME: We abort for now as this code is not safe.
|
||||
ntfs_error(vi->i_sb, "Changing the file size is not supported yet. "
|
||||
"Sorry.");
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* Map, pin, and lock the (base) mft record. */
|
||||
if (!NInoAttr(ni))
|
||||
base_ni = ni;
|
||||
@@ -1904,7 +1945,15 @@ static int ntfs_prepare_write(struct file *file, struct page *page,
|
||||
a = ctx->attr;
|
||||
/* The total length of the attribute value. */
|
||||
attr_len = le32_to_cpu(a->data.resident.value_length);
|
||||
BUG_ON(vi->i_size != attr_len);
|
||||
/* Fix an eventual previous failure of ntfs_commit_write(). */
|
||||
i_size = i_size_read(vi);
|
||||
if (unlikely(attr_len > i_size)) {
|
||||
attr_len = i_size;
|
||||
a->data.resident.value_length = cpu_to_le32(attr_len);
|
||||
}
|
||||
/* If we do not need to resize the attribute allocation we are done. */
|
||||
if (new_size <= attr_len)
|
||||
goto done_unm;
|
||||
/* Check if new size is allowed in $AttrDef. */
|
||||
err = ntfs_attr_size_bounds_check(vol, ni->type, new_size);
|
||||
if (unlikely(err)) {
|
||||
@@ -1962,6 +2011,7 @@ static int ntfs_prepare_write(struct file *file, struct page *page,
|
||||
}
|
||||
flush_dcache_mft_record_page(ctx->ntfs_ino);
|
||||
mark_mft_record_dirty(ctx->ntfs_ino);
|
||||
done_unm:
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
unmap_mft_record(base_ni);
|
||||
/*
|
||||
@@ -2047,7 +2097,7 @@ static int ntfs_commit_nonresident_write(struct page *page,
|
||||
* now we know ntfs_prepare_write() would have failed in the write
|
||||
* exceeds i_size case, so this will never trigger which is fine.
|
||||
*/
|
||||
if (pos > vi->i_size) {
|
||||
if (pos > i_size_read(vi)) {
|
||||
ntfs_error(vi->i_sb, "Writing beyond the existing file size is "
|
||||
"not supported yet. Sorry.");
|
||||
return -EOPNOTSUPP;
|
||||
@@ -2183,9 +2233,13 @@ static int ntfs_commit_write(struct file *file, struct page *page,
|
||||
}
|
||||
kunmap_atomic(kaddr, KM_USER0);
|
||||
/* Update i_size if necessary. */
|
||||
if (vi->i_size < attr_len) {
|
||||
if (i_size_read(vi) < attr_len) {
|
||||
unsigned long flags;
|
||||
|
||||
write_lock_irqsave(&ni->size_lock, flags);
|
||||
ni->allocated_size = ni->initialized_size = attr_len;
|
||||
i_size_write(vi, attr_len);
|
||||
write_unlock_irqrestore(&ni->size_lock, flags);
|
||||
}
|
||||
/* Mark the mft record dirty, so it gets written back. */
|
||||
flush_dcache_mft_record_page(ctx->ntfs_ino);
|
||||
|
||||
+557
-99
File diff suppressed because it is too large
Load Diff
+13
-3
@@ -2,7 +2,7 @@
|
||||
* attrib.h - Defines for attribute handling in NTFS Linux kernel driver.
|
||||
* Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2001-2004 Anton Altaparmakov
|
||||
* Copyright (c) 2001-2005 Anton Altaparmakov
|
||||
* Copyright (c) 2002 Richard Russon
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
@@ -60,10 +60,14 @@ typedef struct {
|
||||
ATTR_RECORD *base_attr;
|
||||
} ntfs_attr_search_ctx;
|
||||
|
||||
extern int ntfs_map_runlist_nolock(ntfs_inode *ni, VCN vcn);
|
||||
extern int ntfs_map_runlist(ntfs_inode *ni, VCN vcn);
|
||||
|
||||
extern runlist_element *ntfs_find_vcn(ntfs_inode *ni, const VCN vcn,
|
||||
const BOOL need_write);
|
||||
extern LCN ntfs_attr_vcn_to_lcn_nolock(ntfs_inode *ni, const VCN vcn,
|
||||
const BOOL write_locked);
|
||||
|
||||
extern runlist_element *ntfs_attr_find_vcn_nolock(ntfs_inode *ni,
|
||||
const VCN vcn, const BOOL write_locked);
|
||||
|
||||
int ntfs_attr_lookup(const ATTR_TYPE type, const ntfschar *name,
|
||||
const u32 name_len, const IGNORE_CASE_BOOL ic,
|
||||
@@ -85,6 +89,8 @@ extern ntfs_attr_search_ctx *ntfs_attr_get_search_ctx(ntfs_inode *ni,
|
||||
MFT_RECORD *mrec);
|
||||
extern void ntfs_attr_put_search_ctx(ntfs_attr_search_ctx *ctx);
|
||||
|
||||
#ifdef NTFS_RW
|
||||
|
||||
extern int ntfs_attr_size_bounds_check(const ntfs_volume *vol,
|
||||
const ATTR_TYPE type, const s64 size);
|
||||
extern int ntfs_attr_can_be_non_resident(const ntfs_volume *vol,
|
||||
@@ -94,7 +100,11 @@ extern int ntfs_attr_can_be_resident(const ntfs_volume *vol,
|
||||
|
||||
extern int ntfs_attr_record_resize(MFT_RECORD *m, ATTR_RECORD *a, u32 new_size);
|
||||
|
||||
extern int ntfs_attr_make_non_resident(ntfs_inode *ni);
|
||||
|
||||
extern int ntfs_attr_set(ntfs_inode *ni, const s64 ofs, const s64 cnt,
|
||||
const u8 val);
|
||||
|
||||
#endif /* NTFS_RW */
|
||||
|
||||
#endif /* _LINUX_NTFS_ATTRIB_H */
|
||||
|
||||
+28
-18
@@ -96,13 +96,14 @@ void free_compression_buffers(void)
|
||||
/**
|
||||
* zero_partial_compressed_page - zero out of bounds compressed page region
|
||||
*/
|
||||
static void zero_partial_compressed_page(ntfs_inode *ni, struct page *page)
|
||||
static void zero_partial_compressed_page(struct page *page,
|
||||
const s64 initialized_size)
|
||||
{
|
||||
u8 *kp = page_address(page);
|
||||
unsigned int kp_ofs;
|
||||
|
||||
ntfs_debug("Zeroing page region outside initialized size.");
|
||||
if (((s64)page->index << PAGE_CACHE_SHIFT) >= ni->initialized_size) {
|
||||
if (((s64)page->index << PAGE_CACHE_SHIFT) >= initialized_size) {
|
||||
/*
|
||||
* FIXME: Using clear_page() will become wrong when we get
|
||||
* PAGE_CACHE_SIZE != PAGE_SIZE but for now there is no problem.
|
||||
@@ -110,7 +111,7 @@ static void zero_partial_compressed_page(ntfs_inode *ni, struct page *page)
|
||||
clear_page(kp);
|
||||
return;
|
||||
}
|
||||
kp_ofs = ni->initialized_size & ~PAGE_CACHE_MASK;
|
||||
kp_ofs = initialized_size & ~PAGE_CACHE_MASK;
|
||||
memset(kp + kp_ofs, 0, PAGE_CACHE_SIZE - kp_ofs);
|
||||
return;
|
||||
}
|
||||
@@ -118,12 +119,12 @@ static void zero_partial_compressed_page(ntfs_inode *ni, struct page *page)
|
||||
/**
|
||||
* handle_bounds_compressed_page - test for&handle out of bounds compressed page
|
||||
*/
|
||||
static inline void handle_bounds_compressed_page(ntfs_inode *ni,
|
||||
struct page *page)
|
||||
static inline void handle_bounds_compressed_page(struct page *page,
|
||||
const loff_t i_size, const s64 initialized_size)
|
||||
{
|
||||
if ((page->index >= (ni->initialized_size >> PAGE_CACHE_SHIFT)) &&
|
||||
(ni->initialized_size < VFS_I(ni)->i_size))
|
||||
zero_partial_compressed_page(ni, page);
|
||||
if ((page->index >= (initialized_size >> PAGE_CACHE_SHIFT)) &&
|
||||
(initialized_size < i_size))
|
||||
zero_partial_compressed_page(page, initialized_size);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -138,6 +139,8 @@ static inline void handle_bounds_compressed_page(ntfs_inode *ni,
|
||||
* @xpage_done: set to 1 if xpage was completed successfully (IN/OUT)
|
||||
* @cb_start: compression block to decompress (IN)
|
||||
* @cb_size: size of compression block @cb_start in bytes (IN)
|
||||
* @i_size: file size when we started the read (IN)
|
||||
* @initialized_size: initialized file size when we started the read (IN)
|
||||
*
|
||||
* The caller must have disabled preemption. ntfs_decompress() reenables it when
|
||||
* the critical section is finished.
|
||||
@@ -165,7 +168,8 @@ static inline void handle_bounds_compressed_page(ntfs_inode *ni,
|
||||
static int ntfs_decompress(struct page *dest_pages[], int *dest_index,
|
||||
int *dest_ofs, const int dest_max_index, const int dest_max_ofs,
|
||||
const int xpage, char *xpage_done, u8 *const cb_start,
|
||||
const u32 cb_size)
|
||||
const u32 cb_size, const loff_t i_size,
|
||||
const s64 initialized_size)
|
||||
{
|
||||
/*
|
||||
* Pointers into the compressed data, i.e. the compression block (cb),
|
||||
@@ -219,9 +223,6 @@ return_error:
|
||||
spin_unlock(&ntfs_cb_lock);
|
||||
/* Second stage: finalize completed pages. */
|
||||
if (nr_completed_pages > 0) {
|
||||
struct page *page = dest_pages[completed_pages[0]];
|
||||
ntfs_inode *ni = NTFS_I(page->mapping->host);
|
||||
|
||||
for (i = 0; i < nr_completed_pages; i++) {
|
||||
int di = completed_pages[i];
|
||||
|
||||
@@ -230,7 +231,8 @@ return_error:
|
||||
* If we are outside the initialized size, zero
|
||||
* the out of bounds page range.
|
||||
*/
|
||||
handle_bounds_compressed_page(ni, dp);
|
||||
handle_bounds_compressed_page(dp, i_size,
|
||||
initialized_size);
|
||||
flush_dcache_page(dp);
|
||||
kunmap(dp);
|
||||
SetPageUptodate(dp);
|
||||
@@ -478,12 +480,14 @@ return_overflow:
|
||||
*/
|
||||
int ntfs_read_compressed_block(struct page *page)
|
||||
{
|
||||
loff_t i_size;
|
||||
s64 initialized_size;
|
||||
struct address_space *mapping = page->mapping;
|
||||
ntfs_inode *ni = NTFS_I(mapping->host);
|
||||
ntfs_volume *vol = ni->vol;
|
||||
struct super_block *sb = vol->sb;
|
||||
runlist_element *rl;
|
||||
unsigned long block_size = sb->s_blocksize;
|
||||
unsigned long flags, block_size = sb->s_blocksize;
|
||||
unsigned char block_size_bits = sb->s_blocksize_bits;
|
||||
u8 *cb, *cb_pos, *cb_end;
|
||||
struct buffer_head **bhs;
|
||||
@@ -552,8 +556,12 @@ int ntfs_read_compressed_block(struct page *page)
|
||||
* The remaining pages need to be allocated and inserted into the page
|
||||
* cache, alignment guarantees keep all the below much simpler. (-8
|
||||
*/
|
||||
max_page = ((VFS_I(ni)->i_size + PAGE_CACHE_SIZE - 1) >>
|
||||
PAGE_CACHE_SHIFT) - offset;
|
||||
read_lock_irqsave(&ni->size_lock, flags);
|
||||
i_size = i_size_read(VFS_I(ni));
|
||||
initialized_size = ni->initialized_size;
|
||||
read_unlock_irqrestore(&ni->size_lock, flags);
|
||||
max_page = ((i_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT) -
|
||||
offset;
|
||||
if (nr_pages < max_page)
|
||||
max_page = nr_pages;
|
||||
for (i = 0; i < max_page; i++, offset++) {
|
||||
@@ -824,7 +832,8 @@ lock_retry_remap:
|
||||
* If we are outside the initialized size, zero
|
||||
* the out of bounds page range.
|
||||
*/
|
||||
handle_bounds_compressed_page(ni, page);
|
||||
handle_bounds_compressed_page(page, i_size,
|
||||
initialized_size);
|
||||
flush_dcache_page(page);
|
||||
kunmap(page);
|
||||
SetPageUptodate(page);
|
||||
@@ -847,7 +856,8 @@ lock_retry_remap:
|
||||
ntfs_debug("Found compressed compression block.");
|
||||
err = ntfs_decompress(pages, &cur_page, &cur_ofs,
|
||||
cb_max_page, cb_max_ofs, xpage, &xpage_done,
|
||||
cb_pos, cb_size - (cb_pos - cb));
|
||||
cb_pos, cb_size - (cb_pos - cb), i_size,
|
||||
initialized_size);
|
||||
/*
|
||||
* We can sleep from now on, lock already dropped by
|
||||
* ntfs_decompress().
|
||||
|
||||
+9
-6
@@ -164,14 +164,17 @@ void ntfs_debug_dump_runlist(const runlist_element *rl)
|
||||
if (index > -LCN_ENOENT - 1)
|
||||
index = 3;
|
||||
printk(KERN_DEBUG "%-16Lx %s %-16Lx%s\n",
|
||||
(rl + i)->vcn, lcn_str[index],
|
||||
(rl + i)->length, (rl + i)->length ?
|
||||
"" : " (runlist end)");
|
||||
(long long)(rl + i)->vcn, lcn_str[index],
|
||||
(long long)(rl + i)->length,
|
||||
(rl + i)->length ? "" :
|
||||
" (runlist end)");
|
||||
} else
|
||||
printk(KERN_DEBUG "%-16Lx %-16Lx %-16Lx%s\n",
|
||||
(rl + i)->vcn, (rl + i)->lcn,
|
||||
(rl + i)->length, (rl + i)->length ?
|
||||
"" : " (runlist end)");
|
||||
(long long)(rl + i)->vcn,
|
||||
(long long)(rl + i)->lcn,
|
||||
(long long)(rl + i)->length,
|
||||
(rl + i)->length ? "" :
|
||||
" (runlist end)");
|
||||
if (!(rl + i)->length)
|
||||
break;
|
||||
}
|
||||
|
||||
+15
-17
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* dir.c - NTFS kernel directory operations. Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2001-2004 Anton Altaparmakov
|
||||
* Copyright (c) 2001-2005 Anton Altaparmakov
|
||||
* Copyright (c) 2002 Richard Russon
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
@@ -183,8 +183,7 @@ found_it:
|
||||
name->len = 0;
|
||||
*res = name;
|
||||
} else {
|
||||
if (name)
|
||||
kfree(name);
|
||||
kfree(name);
|
||||
*res = NULL;
|
||||
}
|
||||
mref = le64_to_cpu(ie->data.dir.indexed_file);
|
||||
@@ -444,8 +443,7 @@ found_it2:
|
||||
name->len = 0;
|
||||
*res = name;
|
||||
} else {
|
||||
if (name)
|
||||
kfree(name);
|
||||
kfree(name);
|
||||
*res = NULL;
|
||||
}
|
||||
mref = le64_to_cpu(ie->data.dir.indexed_file);
|
||||
@@ -610,7 +608,7 @@ dir_err_out:
|
||||
// TODO: (AIA)
|
||||
// The algorithm embedded in this code will be required for the time when we
|
||||
// want to support adding of entries to directories, where we require correct
|
||||
// collation of file names in order not to cause corruption of the file system.
|
||||
// collation of file names in order not to cause corruption of the filesystem.
|
||||
|
||||
/**
|
||||
* ntfs_lookup_inode_by_name - find an inode in a directory given its name
|
||||
@@ -1101,7 +1099,7 @@ static inline int ntfs_filldir(ntfs_volume *vol, loff_t fpos,
|
||||
static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||
{
|
||||
s64 ia_pos, ia_start, prev_ia_pos, bmp_pos;
|
||||
loff_t fpos;
|
||||
loff_t fpos, i_size;
|
||||
struct inode *bmp_vi, *vdir = filp->f_dentry->d_inode;
|
||||
struct super_block *sb = vdir->i_sb;
|
||||
ntfs_inode *ndir = NTFS_I(vdir);
|
||||
@@ -1122,7 +1120,8 @@ static int ntfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
||||
vdir->i_ino, fpos);
|
||||
rc = err = 0;
|
||||
/* Are we at end of dir yet? */
|
||||
if (fpos >= vdir->i_size + vol->mft_record_size)
|
||||
i_size = i_size_read(vdir);
|
||||
if (fpos >= i_size + vol->mft_record_size)
|
||||
goto done;
|
||||
/* Emulate . and .. for all directories. */
|
||||
if (!fpos) {
|
||||
@@ -1264,7 +1263,7 @@ skip_index_root:
|
||||
bmp_mapping = bmp_vi->i_mapping;
|
||||
/* Get the starting bitmap bit position and sanity check it. */
|
||||
bmp_pos = ia_pos >> ndir->itype.index.block_size_bits;
|
||||
if (unlikely(bmp_pos >> 3 >= bmp_vi->i_size)) {
|
||||
if (unlikely(bmp_pos >> 3 >= i_size_read(bmp_vi))) {
|
||||
ntfs_error(sb, "Current index allocation position exceeds "
|
||||
"index bitmap size.");
|
||||
goto err_out;
|
||||
@@ -1301,7 +1300,7 @@ find_next_index_buffer:
|
||||
goto get_next_bmp_page;
|
||||
}
|
||||
/* If we have reached the end of the bitmap, we are done. */
|
||||
if (unlikely(((bmp_pos + cur_bmp_pos) >> 3) >= vdir->i_size))
|
||||
if (unlikely(((bmp_pos + cur_bmp_pos) >> 3) >= i_size))
|
||||
goto unm_EOD;
|
||||
ia_pos = (bmp_pos + cur_bmp_pos) <<
|
||||
ndir->itype.index.block_size_bits;
|
||||
@@ -1309,7 +1308,8 @@ find_next_index_buffer:
|
||||
ntfs_debug("Handling index buffer 0x%llx.",
|
||||
(unsigned long long)bmp_pos + cur_bmp_pos);
|
||||
/* If the current index buffer is in the same page we reuse the page. */
|
||||
if ((prev_ia_pos & PAGE_CACHE_MASK) != (ia_pos & PAGE_CACHE_MASK)) {
|
||||
if ((prev_ia_pos & (s64)PAGE_CACHE_MASK) !=
|
||||
(ia_pos & (s64)PAGE_CACHE_MASK)) {
|
||||
prev_ia_pos = ia_pos;
|
||||
if (likely(ia_page != NULL)) {
|
||||
unlock_page(ia_page);
|
||||
@@ -1441,7 +1441,7 @@ unm_EOD:
|
||||
ntfs_unmap_page(bmp_page);
|
||||
EOD:
|
||||
/* We are finished, set fpos to EOD. */
|
||||
fpos = vdir->i_size + vol->mft_record_size;
|
||||
fpos = i_size + vol->mft_record_size;
|
||||
abort:
|
||||
kfree(name);
|
||||
done:
|
||||
@@ -1461,10 +1461,8 @@ err_out:
|
||||
unlock_page(ia_page);
|
||||
ntfs_unmap_page(ia_page);
|
||||
}
|
||||
if (ir)
|
||||
kfree(ir);
|
||||
if (name)
|
||||
kfree(name);
|
||||
kfree(ir);
|
||||
kfree(name);
|
||||
if (ctx)
|
||||
ntfs_attr_put_search_ctx(ctx);
|
||||
if (m)
|
||||
@@ -1495,7 +1493,7 @@ err_out:
|
||||
static int ntfs_dir_open(struct inode *vi, struct file *filp)
|
||||
{
|
||||
if (sizeof(unsigned long) < 8) {
|
||||
if (vi->i_size > MAX_LFS_FILESIZE)
|
||||
if (i_size_read(vi) > MAX_LFS_FILESIZE)
|
||||
return -EFBIG;
|
||||
}
|
||||
return 0;
|
||||
|
||||
+1
-1
@@ -47,7 +47,7 @@
|
||||
static int ntfs_file_open(struct inode *vi, struct file *filp)
|
||||
{
|
||||
if (sizeof(unsigned long) < 8) {
|
||||
if (vi->i_size > MAX_LFS_FILESIZE)
|
||||
if (i_size_read(vi) > MAX_LFS_FILESIZE)
|
||||
return -EFBIG;
|
||||
}
|
||||
return generic_file_open(vi, filp);
|
||||
|
||||
+3
-13
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* index.c - NTFS kernel index handling. Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2004 Anton Altaparmakov
|
||||
* Copyright (c) 2004-2005 Anton Altaparmakov
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
@@ -39,18 +39,8 @@ ntfs_index_context *ntfs_index_ctx_get(ntfs_inode *idx_ni)
|
||||
ntfs_index_context *ictx;
|
||||
|
||||
ictx = kmem_cache_alloc(ntfs_index_ctx_cache, SLAB_NOFS);
|
||||
if (ictx) {
|
||||
ictx->idx_ni = idx_ni;
|
||||
ictx->entry = NULL;
|
||||
ictx->data = NULL;
|
||||
ictx->data_len = 0;
|
||||
ictx->is_in_root = 0;
|
||||
ictx->ir = NULL;
|
||||
ictx->actx = NULL;
|
||||
ictx->base_ni = NULL;
|
||||
ictx->ia = NULL;
|
||||
ictx->page = NULL;
|
||||
}
|
||||
if (ictx)
|
||||
*ictx = (ntfs_index_context){ .idx_ni = idx_ni };
|
||||
return ictx;
|
||||
}
|
||||
|
||||
|
||||
+262
-268
File diff suppressed because it is too large
Load Diff
+5
-2
@@ -2,7 +2,7 @@
|
||||
* inode.h - Defines for inode structures NTFS Linux kernel driver. Part of
|
||||
* the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2001-2004 Anton Altaparmakov
|
||||
* Copyright (c) 2001-2005 Anton Altaparmakov
|
||||
* Copyright (c) 2002 Richard Russon
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
@@ -44,6 +44,7 @@ typedef struct _ntfs_inode ntfs_inode;
|
||||
* fields already provided in the VFS inode.
|
||||
*/
|
||||
struct _ntfs_inode {
|
||||
rwlock_t size_lock; /* Lock serializing access to inode sizes. */
|
||||
s64 initialized_size; /* Copy from the attribute record. */
|
||||
s64 allocated_size; /* Copy from the attribute record. */
|
||||
unsigned long state; /* NTFS specific flags describing this inode.
|
||||
@@ -109,7 +110,7 @@ struct _ntfs_inode {
|
||||
u8 block_size_bits; /* Log2 of the above. */
|
||||
u8 vcn_size_bits; /* Log2 of the above. */
|
||||
} index;
|
||||
struct { /* It is a compressed file or an attribute inode. */
|
||||
struct { /* It is a compressed/sparse file/attribute inode. */
|
||||
s64 size; /* Copy of compressed_size from
|
||||
$DATA. */
|
||||
u32 block_size; /* Size of a compression block
|
||||
@@ -165,6 +166,7 @@ typedef enum {
|
||||
NI_Sparse, /* 1: Unnamed data attr is sparse (f).
|
||||
1: Create sparse files by default (d).
|
||||
1: Attribute is sparse (a). */
|
||||
NI_SparseDisabled, /* 1: May not create sparse regions. */
|
||||
NI_TruncateFailed, /* 1: Last ntfs_truncate() call failed. */
|
||||
} ntfs_inode_state_bits;
|
||||
|
||||
@@ -217,6 +219,7 @@ NINO_FNS(IndexAllocPresent)
|
||||
NINO_FNS(Compressed)
|
||||
NINO_FNS(Encrypted)
|
||||
NINO_FNS(Sparse)
|
||||
NINO_FNS(SparseDisabled)
|
||||
NINO_FNS(TruncateFailed)
|
||||
|
||||
/*
|
||||
|
||||
+47
-36
@@ -2,7 +2,7 @@
|
||||
* layout.h - All NTFS associated on-disk structures. Part of the Linux-NTFS
|
||||
* project.
|
||||
*
|
||||
* Copyright (c) 2001-2004 Anton Altaparmakov
|
||||
* Copyright (c) 2001-2005 Anton Altaparmakov
|
||||
* Copyright (c) 2002 Richard Russon
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
@@ -547,26 +547,44 @@ enum {
|
||||
COLLATION_NTOFS_ULONG = const_cpu_to_le32(0x10),
|
||||
COLLATION_NTOFS_SID = const_cpu_to_le32(0x11),
|
||||
COLLATION_NTOFS_SECURITY_HASH = const_cpu_to_le32(0x12),
|
||||
COLLATION_NTOFS_ULONGS = const_cpu_to_le32(0x13)
|
||||
COLLATION_NTOFS_ULONGS = const_cpu_to_le32(0x13),
|
||||
};
|
||||
|
||||
typedef le32 COLLATION_RULE;
|
||||
|
||||
/*
|
||||
* The flags (32-bit) describing attribute properties in the attribute
|
||||
* definition structure. FIXME: This information is from Regis's information
|
||||
* and, according to him, it is not certain and probably incomplete.
|
||||
* The INDEXABLE flag is fairly certainly correct as only the file name
|
||||
* attribute has this flag set and this is the only attribute indexed in NT4.
|
||||
* definition structure. FIXME: This information is based on Regis's
|
||||
* information and, according to him, it is not certain and probably
|
||||
* incomplete. The INDEXABLE flag is fairly certainly correct as only the file
|
||||
* name attribute has this flag set and this is the only attribute indexed in
|
||||
* NT4.
|
||||
*/
|
||||
enum {
|
||||
INDEXABLE = const_cpu_to_le32(0x02), /* Attribute can be
|
||||
indexed. */
|
||||
NEED_TO_REGENERATE = const_cpu_to_le32(0x40), /* Need to regenerate
|
||||
during regeneration
|
||||
phase. */
|
||||
CAN_BE_NON_RESIDENT = const_cpu_to_le32(0x80), /* Attribute can be
|
||||
non-resident. */
|
||||
ATTR_DEF_INDEXABLE = const_cpu_to_le32(0x02), /* Attribute can be
|
||||
indexed. */
|
||||
ATTR_DEF_MULTIPLE = const_cpu_to_le32(0x04), /* Attribute type
|
||||
can be present multiple times in the
|
||||
mft records of an inode. */
|
||||
ATTR_DEF_NOT_ZERO = const_cpu_to_le32(0x08), /* Attribute value
|
||||
must contain at least one non-zero
|
||||
byte. */
|
||||
ATTR_DEF_INDEXED_UNIQUE = const_cpu_to_le32(0x10), /* Attribute must be
|
||||
indexed and the attribute value must be
|
||||
unique for the attribute type in all of
|
||||
the mft records of an inode. */
|
||||
ATTR_DEF_NAMED_UNIQUE = const_cpu_to_le32(0x20), /* Attribute must be
|
||||
named and the name must be unique for
|
||||
the attribute type in all of the mft
|
||||
records of an inode. */
|
||||
ATTR_DEF_RESIDENT = const_cpu_to_le32(0x40), /* Attribute must be
|
||||
resident. */
|
||||
ATTR_DEF_ALWAYS_LOG = const_cpu_to_le32(0x80), /* Always log
|
||||
modifications to this attribute,
|
||||
regardless of whether it is resident or
|
||||
non-resident. Without this, only log
|
||||
modifications if the attribute is
|
||||
resident. */
|
||||
};
|
||||
|
||||
typedef le32 ATTR_DEF_FLAGS;
|
||||
@@ -749,10 +767,11 @@ typedef struct {
|
||||
record header aligned to 8-byte boundary. */
|
||||
/* 34*/ u8 compression_unit; /* The compression unit expressed
|
||||
as the log to the base 2 of the number of
|
||||
clusters in a compression unit. 0 means not
|
||||
compressed. (This effectively limits the
|
||||
clusters in a compression unit. 0 means not
|
||||
compressed. (This effectively limits the
|
||||
compression unit size to be a power of two
|
||||
clusters.) WinNT4 only uses a value of 4. */
|
||||
clusters.) WinNT4 only uses a value of 4.
|
||||
Sparse files also have this set to 4. */
|
||||
/* 35*/ u8 reserved[5]; /* Align to 8-byte boundary. */
|
||||
/* The sizes below are only used when lowest_vcn is zero, as otherwise it would
|
||||
be difficult to keep them up-to-date.*/
|
||||
@@ -772,10 +791,10 @@ typedef struct {
|
||||
data_size. */
|
||||
/* sizeof(uncompressed attr) = 64*/
|
||||
/* 64*/ sle64 compressed_size; /* Byte size of the attribute
|
||||
value after compression. Only present when
|
||||
compressed. Always is a multiple of the
|
||||
cluster size. Represents the actual amount of
|
||||
disk space being used on the disk. */
|
||||
value after compression. Only present when
|
||||
compressed or sparse. Always is a multiple of
|
||||
the cluster size. Represents the actual amount
|
||||
of disk space being used on the disk. */
|
||||
/* sizeof(compressed attr) = 72*/
|
||||
} __attribute__ ((__packed__)) non_resident;
|
||||
} __attribute__ ((__packed__)) data;
|
||||
@@ -834,7 +853,7 @@ enum {
|
||||
/* Note, this is a copy of the corresponding bit from the mft record,
|
||||
telling us whether this file has a view index present (eg. object id
|
||||
index, quota index, one of the security indexes or the encrypting
|
||||
file system related indexes). */
|
||||
filesystem related indexes). */
|
||||
};
|
||||
|
||||
typedef le32 FILE_ATTR_FLAGS;
|
||||
@@ -917,20 +936,12 @@ typedef struct {
|
||||
/* 56*/ le64 quota_charged; /* Byte size of the charge to
|
||||
the quota for all streams of the file. Note: Is
|
||||
zero if quotas are disabled. */
|
||||
/* 64*/ le64 usn; /* Last update sequence number
|
||||
of the file. This is a direct index into the
|
||||
change (aka usn) journal file. It is zero if
|
||||
the usn journal is disabled.
|
||||
NOTE: To disable the journal need to delete
|
||||
the journal file itself and to then walk the
|
||||
whole mft and set all Usn entries in all mft
|
||||
records to zero! (This can take a while!)
|
||||
The journal is FILE_Extend/$UsnJrnl. Win2k
|
||||
will recreate the journal and initiate
|
||||
logging if necessary when mounting the
|
||||
partition. This, in contrast to disabling the
|
||||
journal is a very fast process, so the user
|
||||
won't even notice it. */
|
||||
/* 64*/ leUSN usn; /* Last update sequence number
|
||||
of the file. This is a direct index into the
|
||||
transaction log file ($UsnJrnl). It is zero if
|
||||
the usn journal is disabled or this file has
|
||||
not been subject to logging yet. See usnjrnl.h
|
||||
for details. */
|
||||
} __attribute__ ((__packed__)) v3;
|
||||
/* sizeof() = 72 bytes (NTFS 3.x) */
|
||||
} __attribute__ ((__packed__)) ver;
|
||||
@@ -1893,7 +1904,7 @@ enum {
|
||||
VOLUME_FLAGS_MASK = const_cpu_to_le16(0x803f),
|
||||
|
||||
/* To make our life easier when checking if we must mount read-only. */
|
||||
VOLUME_MUST_MOUNT_RO_MASK = const_cpu_to_le16(0x8037),
|
||||
VOLUME_MUST_MOUNT_RO_MASK = const_cpu_to_le16(0x8027),
|
||||
} __attribute__ ((__packed__));
|
||||
|
||||
typedef le16 VOLUME_FLAGS;
|
||||
|
||||
+29
-43
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* lcnalloc.c - Cluster (de)allocation code. Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2004 Anton Altaparmakov
|
||||
* Copyright (c) 2004-2005 Anton Altaparmakov
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
@@ -60,7 +60,7 @@ int ntfs_cluster_free_from_rl_nolock(ntfs_volume *vol,
|
||||
if (rl->lcn < 0)
|
||||
continue;
|
||||
err = ntfs_bitmap_clear_run(lcnbmp_vi, rl->lcn, rl->length);
|
||||
if (unlikely(err && (!ret || ret == ENOMEM) && ret != err))
|
||||
if (unlikely(err && (!ret || ret == -ENOMEM) && ret != err))
|
||||
ret = err;
|
||||
}
|
||||
ntfs_debug("Done.");
|
||||
@@ -140,6 +140,7 @@ runlist_element *ntfs_cluster_alloc(ntfs_volume *vol, const VCN start_vcn,
|
||||
LCN zone_start, zone_end, bmp_pos, bmp_initial_pos, last_read_pos, lcn;
|
||||
LCN prev_lcn = 0, prev_run_len = 0, mft_zone_size;
|
||||
s64 clusters;
|
||||
loff_t i_size;
|
||||
struct inode *lcnbmp_vi;
|
||||
runlist_element *rl = NULL;
|
||||
struct address_space *mapping;
|
||||
@@ -249,6 +250,7 @@ runlist_element *ntfs_cluster_alloc(ntfs_volume *vol, const VCN start_vcn,
|
||||
clusters = count;
|
||||
rlpos = rlsize = 0;
|
||||
mapping = lcnbmp_vi->i_mapping;
|
||||
i_size = i_size_read(lcnbmp_vi);
|
||||
while (1) {
|
||||
ntfs_debug("Start of outer while loop: done_zones 0x%x, "
|
||||
"search_zone %i, pass %i, zone_start 0x%llx, "
|
||||
@@ -263,7 +265,7 @@ runlist_element *ntfs_cluster_alloc(ntfs_volume *vol, const VCN start_vcn,
|
||||
last_read_pos = bmp_pos >> 3;
|
||||
ntfs_debug("last_read_pos 0x%llx.",
|
||||
(unsigned long long)last_read_pos);
|
||||
if (last_read_pos > lcnbmp_vi->i_size) {
|
||||
if (last_read_pos > i_size) {
|
||||
ntfs_debug("End of attribute reached. "
|
||||
"Skipping to zone_pass_done.");
|
||||
goto zone_pass_done;
|
||||
@@ -287,11 +289,11 @@ runlist_element *ntfs_cluster_alloc(ntfs_volume *vol, const VCN start_vcn,
|
||||
buf_size = last_read_pos & ~PAGE_CACHE_MASK;
|
||||
buf = page_address(page) + buf_size;
|
||||
buf_size = PAGE_CACHE_SIZE - buf_size;
|
||||
if (unlikely(last_read_pos + buf_size > lcnbmp_vi->i_size))
|
||||
buf_size = lcnbmp_vi->i_size - last_read_pos;
|
||||
if (unlikely(last_read_pos + buf_size > i_size))
|
||||
buf_size = i_size - last_read_pos;
|
||||
buf_size <<= 3;
|
||||
lcn = bmp_pos & 7;
|
||||
bmp_pos &= ~7;
|
||||
bmp_pos &= ~(LCN)7;
|
||||
ntfs_debug("Before inner while loop: buf_size %i, lcn 0x%llx, "
|
||||
"bmp_pos 0x%llx, need_writeback %i.", buf_size,
|
||||
(unsigned long long)lcn,
|
||||
@@ -309,7 +311,7 @@ runlist_element *ntfs_cluster_alloc(ntfs_volume *vol, const VCN start_vcn,
|
||||
(unsigned int)*byte);
|
||||
/* Skip full bytes. */
|
||||
if (*byte == 0xff) {
|
||||
lcn = (lcn + 8) & ~7;
|
||||
lcn = (lcn + 8) & ~(LCN)7;
|
||||
ntfs_debug("Continuing while loop 1.");
|
||||
continue;
|
||||
}
|
||||
@@ -691,7 +693,7 @@ switch_to_data1_zone: search_zone = 2;
|
||||
if (zone == MFT_ZONE || mft_zone_size <= 0) {
|
||||
ntfs_debug("No free clusters left, going to out.");
|
||||
/* Really no more space left on device. */
|
||||
err = ENOSPC;
|
||||
err = -ENOSPC;
|
||||
goto out;
|
||||
} /* zone == DATA_ZONE && mft_zone_size > 0 */
|
||||
ntfs_debug("Shrinking mft zone.");
|
||||
@@ -755,13 +757,13 @@ out:
|
||||
if (rl) {
|
||||
int err2;
|
||||
|
||||
if (err == ENOSPC)
|
||||
if (err == -ENOSPC)
|
||||
ntfs_debug("Not enough space to complete allocation, "
|
||||
"err ENOSPC, first free lcn 0x%llx, "
|
||||
"err -ENOSPC, first free lcn 0x%llx, "
|
||||
"could allocate up to 0x%llx "
|
||||
"clusters.",
|
||||
(unsigned long long)rl[0].lcn,
|
||||
(unsigned long long)count - clusters);
|
||||
(unsigned long long)(count - clusters));
|
||||
/* Deallocate all allocated clusters. */
|
||||
ntfs_debug("Attempting rollback...");
|
||||
err2 = ntfs_cluster_free_from_rl_nolock(vol, rl);
|
||||
@@ -773,10 +775,10 @@ out:
|
||||
}
|
||||
/* Free the runlist. */
|
||||
ntfs_free(rl);
|
||||
} else if (err == ENOSPC)
|
||||
ntfs_debug("No space left at all, err = ENOSPC, "
|
||||
"first free lcn = 0x%llx.",
|
||||
(unsigned long long)vol->data1_zone_pos);
|
||||
} else if (err == -ENOSPC)
|
||||
ntfs_debug("No space left at all, err = -ENOSPC, first free "
|
||||
"lcn = 0x%llx.",
|
||||
(long long)vol->data1_zone_pos);
|
||||
up_write(&vol->lcnbmp_lock);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
@@ -846,8 +848,8 @@ s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count,
|
||||
|
||||
total_freed = real_freed = 0;
|
||||
|
||||
/* This returns with ni->runlist locked for reading on success. */
|
||||
rl = ntfs_find_vcn(ni, start_vcn, FALSE);
|
||||
down_read(&ni->runlist.lock);
|
||||
rl = ntfs_attr_find_vcn_nolock(ni, start_vcn, FALSE);
|
||||
if (IS_ERR(rl)) {
|
||||
if (!is_rollback)
|
||||
ntfs_error(vol->sb, "Failed to find first runlist "
|
||||
@@ -861,7 +863,7 @@ s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count,
|
||||
ntfs_error(vol->sb, "First runlist element has "
|
||||
"invalid lcn, aborting.");
|
||||
err = -EIO;
|
||||
goto unl_err_out;
|
||||
goto err_out;
|
||||
}
|
||||
/* Find the starting cluster inside the run that needs freeing. */
|
||||
delta = start_vcn - rl->vcn;
|
||||
@@ -879,7 +881,7 @@ s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count,
|
||||
if (!is_rollback)
|
||||
ntfs_error(vol->sb, "Failed to clear first run "
|
||||
"(error %i), aborting.", err);
|
||||
goto unl_err_out;
|
||||
goto err_out;
|
||||
}
|
||||
/* We have freed @to_free real clusters. */
|
||||
real_freed = to_free;
|
||||
@@ -899,30 +901,15 @@ s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count,
|
||||
if (unlikely(rl->lcn < LCN_HOLE)) {
|
||||
VCN vcn;
|
||||
|
||||
/*
|
||||
* Attempt to map runlist, dropping runlist lock for
|
||||
* the duration.
|
||||
*/
|
||||
/* Attempt to map runlist. */
|
||||
vcn = rl->vcn;
|
||||
up_read(&ni->runlist.lock);
|
||||
err = ntfs_map_runlist(ni, vcn);
|
||||
if (err) {
|
||||
if (!is_rollback)
|
||||
ntfs_error(vol->sb, "Failed to map "
|
||||
"runlist fragment.");
|
||||
if (err == -EINVAL || err == -ENOENT)
|
||||
err = -EIO;
|
||||
goto err_out;
|
||||
}
|
||||
/*
|
||||
* This returns with ni->runlist locked for reading on
|
||||
* success.
|
||||
*/
|
||||
rl = ntfs_find_vcn(ni, vcn, FALSE);
|
||||
rl = ntfs_attr_find_vcn_nolock(ni, vcn, FALSE);
|
||||
if (IS_ERR(rl)) {
|
||||
err = PTR_ERR(rl);
|
||||
if (!is_rollback)
|
||||
ntfs_error(vol->sb, "Failed to find "
|
||||
ntfs_error(vol->sb, "Failed to map "
|
||||
"runlist fragment or "
|
||||
"failed to find "
|
||||
"subsequent runlist "
|
||||
"element.");
|
||||
goto err_out;
|
||||
@@ -935,7 +922,7 @@ s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count,
|
||||
(unsigned long long)
|
||||
rl->lcn);
|
||||
err = -EIO;
|
||||
goto unl_err_out;
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
/* The number of clusters in this run that need freeing. */
|
||||
@@ -951,7 +938,7 @@ s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count,
|
||||
if (!is_rollback)
|
||||
ntfs_error(vol->sb, "Failed to clear "
|
||||
"subsequent run.");
|
||||
goto unl_err_out;
|
||||
goto err_out;
|
||||
}
|
||||
/* We have freed @to_free real clusters. */
|
||||
real_freed += to_free;
|
||||
@@ -972,9 +959,8 @@ s64 __ntfs_cluster_free(struct inode *vi, const VCN start_vcn, s64 count,
|
||||
/* We are done. Return the number of actually freed clusters. */
|
||||
ntfs_debug("Done.");
|
||||
return real_freed;
|
||||
unl_err_out:
|
||||
up_read(&ni->runlist.lock);
|
||||
err_out:
|
||||
up_read(&ni->runlist.lock);
|
||||
if (is_rollback)
|
||||
return err;
|
||||
/* If no real clusters were freed, no need to rollback. */
|
||||
|
||||
+6
-5
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* logfile.c - NTFS kernel journal handling. Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2002-2004 Anton Altaparmakov
|
||||
* Copyright (c) 2002-2005 Anton Altaparmakov
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as published
|
||||
@@ -410,7 +410,7 @@ err_out:
|
||||
}
|
||||
|
||||
/**
|
||||
* ntfs_ckeck_logfile - check in the journal if the volume is consistent
|
||||
* ntfs_check_logfile - check the journal for consistency
|
||||
* @log_vi: struct inode of loaded journal $LogFile to check
|
||||
*
|
||||
* Check the $LogFile journal for consistency and return TRUE if it is
|
||||
@@ -443,7 +443,7 @@ BOOL ntfs_check_logfile(struct inode *log_vi)
|
||||
/* An empty $LogFile must have been clean before it got emptied. */
|
||||
if (NVolLogFileEmpty(vol))
|
||||
goto is_empty;
|
||||
size = log_vi->i_size;
|
||||
size = i_size_read(log_vi);
|
||||
/* Make sure the file doesn't exceed the maximum allowed size. */
|
||||
if (size > MaxLogFileSize)
|
||||
size = MaxLogFileSize;
|
||||
@@ -464,7 +464,7 @@ BOOL ntfs_check_logfile(struct inode *log_vi)
|
||||
* optimize log_page_size and log_page_bits into constants.
|
||||
*/
|
||||
log_page_bits = generic_ffs(log_page_size) - 1;
|
||||
size &= ~(log_page_size - 1);
|
||||
size &= ~(s64)(log_page_size - 1);
|
||||
/*
|
||||
* Ensure the log file is big enough to store at least the two restart
|
||||
* pages and the minimum number of log record pages.
|
||||
@@ -689,7 +689,8 @@ BOOL ntfs_empty_logfile(struct inode *log_vi)
|
||||
if (!NVolLogFileEmpty(vol)) {
|
||||
int err;
|
||||
|
||||
err = ntfs_attr_set(NTFS_I(log_vi), 0, log_vi->i_size, 0xff);
|
||||
err = ntfs_attr_set(NTFS_I(log_vi), 0, i_size_read(log_vi),
|
||||
0xff);
|
||||
if (unlikely(err)) {
|
||||
ntfs_error(vol->sb, "Failed to fill $LogFile with "
|
||||
"0xff bytes (error code %i).", err);
|
||||
|
||||
+155
-72
File diff suppressed because it is too large
Load Diff
+30
-4
@@ -153,8 +153,7 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent,
|
||||
ntfs_error(vol->sb, "ntfs_iget(0x%lx) failed with "
|
||||
"error code %li.", dent_ino,
|
||||
PTR_ERR(dent_inode));
|
||||
if (name)
|
||||
kfree(name);
|
||||
kfree(name);
|
||||
/* Return the error code. */
|
||||
return (struct dentry *)dent_inode;
|
||||
}
|
||||
@@ -380,7 +379,7 @@ struct inode_operations ntfs_dir_inode_ops = {
|
||||
* Return the dentry of the parent directory on success or the error code on
|
||||
* error (IS_ERR() is true).
|
||||
*/
|
||||
struct dentry *ntfs_get_parent(struct dentry *child_dent)
|
||||
static struct dentry *ntfs_get_parent(struct dentry *child_dent)
|
||||
{
|
||||
struct inode *vi = child_dent->d_inode;
|
||||
ntfs_inode *ni = NTFS_I(vi);
|
||||
@@ -465,7 +464,7 @@ try_next:
|
||||
*
|
||||
* Return the dentry on success or the error code on error (IS_ERR() is true).
|
||||
*/
|
||||
struct dentry *ntfs_get_dentry(struct super_block *sb, void *fh)
|
||||
static struct dentry *ntfs_get_dentry(struct super_block *sb, void *fh)
|
||||
{
|
||||
struct inode *vi;
|
||||
struct dentry *dent;
|
||||
@@ -496,3 +495,30 @@ struct dentry *ntfs_get_dentry(struct super_block *sb, void *fh)
|
||||
ntfs_debug("Done for inode 0x%lx, generation 0x%x.", ino, gen);
|
||||
return dent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Export operations allowing NFS exporting of mounted NTFS partitions.
|
||||
*
|
||||
* We use the default ->decode_fh() and ->encode_fh() for now. Note that they
|
||||
* use 32 bits to store the inode number which is an unsigned long so on 64-bit
|
||||
* architectures is usually 64 bits so it would all fail horribly on huge
|
||||
* volumes. I guess we need to define our own encode and decode fh functions
|
||||
* that store 64-bit inode numbers at some point but for now we will ignore the
|
||||
* problem...
|
||||
*
|
||||
* We also use the default ->get_name() helper (used by ->decode_fh() via
|
||||
* fs/exportfs/expfs.c::find_exported_dentry()) as that is completely fs
|
||||
* independent.
|
||||
*
|
||||
* The default ->get_parent() just returns -EACCES so we have to provide our
|
||||
* own and the default ->get_dentry() is incompatible with NTFS due to not
|
||||
* allowing the inode number 0 which is used in NTFS for the system file $MFT
|
||||
* and due to using iget() whereas NTFS needs ntfs_iget().
|
||||
*/
|
||||
struct export_operations ntfs_export_ops = {
|
||||
.get_parent = ntfs_get_parent, /* Find the parent of a given
|
||||
directory. */
|
||||
.get_dentry = ntfs_get_dentry, /* Find a dentry for the inode
|
||||
given a file handle
|
||||
sub-fragment. */
|
||||
};
|
||||
|
||||
+7
-1
@@ -2,7 +2,7 @@
|
||||
* ntfs.h - Defines for NTFS Linux kernel driver. Part of the Linux-NTFS
|
||||
* project.
|
||||
*
|
||||
* Copyright (c) 2001-2004 Anton Altaparmakov
|
||||
* Copyright (c) 2001-2005 Anton Altaparmakov
|
||||
* Copyright (C) 2002 Richard Russon
|
||||
*
|
||||
* This program/include file is free software; you can redistribute it and/or
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <linux/fs.h>
|
||||
#include <linux/nls.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/pagemap.h>
|
||||
|
||||
#include "types.h"
|
||||
#include "volume.h"
|
||||
@@ -41,6 +42,9 @@ typedef enum {
|
||||
NTFS_BLOCK_SIZE_BITS = 9,
|
||||
NTFS_SB_MAGIC = 0x5346544e, /* 'NTFS' */
|
||||
NTFS_MAX_NAME_LEN = 255,
|
||||
NTFS_MAX_ATTR_NAME_LEN = 255,
|
||||
NTFS_MAX_CLUSTER_SIZE = 64 * 1024, /* 64kiB */
|
||||
NTFS_MAX_PAGES_PER_CLUSTER = NTFS_MAX_CLUSTER_SIZE / PAGE_CACHE_SIZE,
|
||||
} NTFS_CONSTANTS;
|
||||
|
||||
/* Global variables. */
|
||||
@@ -65,6 +69,8 @@ extern struct inode_operations ntfs_dir_inode_ops;
|
||||
extern struct file_operations ntfs_empty_file_ops;
|
||||
extern struct inode_operations ntfs_empty_inode_ops;
|
||||
|
||||
extern struct export_operations ntfs_export_ops;
|
||||
|
||||
/**
|
||||
* NTFS_SB - return the ntfs volume given a vfs super block
|
||||
* @sb: VFS super block
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user