aboutsummaryrefslogtreecommitdiff
path: root/ext2fs/truncate.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext2fs/truncate.c')
-rw-r--r--ext2fs/truncate.c51
1 files changed, 37 insertions, 14 deletions
diff --git a/ext2fs/truncate.c b/ext2fs/truncate.c
index ebe8f374..077225b0 100644
--- a/ext2fs/truncate.c
+++ b/ext2fs/truncate.c
@@ -1,8 +1,8 @@
/* File truncation
- Copyright (C) 1995, 1996 Free Software Foundation, Inc.
+ Copyright (C) 1995,96,97,99,2000 Free Software Foundation, Inc.
- Written by Miles Bader <miles@gnu.ai.mit.edu>
+ Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@@ -102,7 +102,7 @@ trunc_direct (struct node *node, block_t end, struct free_block_run *fbr)
{
block_t *blocks = node->dn->info.i_data;
- ext2_debug ("truncating direct blocks from %ld", end);
+ ext2_debug ("truncating direct blocks from %d", end);
while (end < EXT2_NDIR_BLOCKS)
free_block_run_free_ptr (fbr, blocks + end++);
@@ -138,7 +138,10 @@ trunc_indirect (struct node *node, block_t end,
}
if (first == 0 && all_freed)
- free_block_run_free_ptr (fbr, p);
+ {
+ pager_flush_some (diskfs_disk_pager, boffs (*p), block_size, 1);
+ free_block_run_free_ptr (fbr, p);
+ }
else if (modified)
record_indir_poke (node, ind_bh);
}
@@ -205,7 +208,7 @@ poke_pages (memory_object_t obj, vm_offset_t start, vm_offset_t end)
vm_address_t poke;
for (poke = addr; poke < addr + len; poke += vm_page_size)
*(volatile int *)poke = *(volatile int *)poke;
- vm_deallocate (mach_task_self (), addr, len);
+ munmap ((caddr_t) addr, len);
}
start += len;
@@ -226,16 +229,22 @@ force_delayed_copies (struct node *node, off_t length)
if (pager)
ports_port_ref (pager);
spin_unlock (&node_to_page_lock);
-
+
if (pager)
{
mach_port_t obj;
-
+
pager_change_attributes (pager, MAY_CACHE, MEMORY_OBJECT_COPY_NONE, 1);
obj = diskfs_get_filemap (node, VM_PROT_READ);
- poke_pages (obj, round_page (length), round_page (node->allocsize));
- mach_port_deallocate (mach_task_self (), obj);
- pager_flush_some (pager, round_page(length), node->allocsize - length, 1);
+ if (obj != MACH_PORT_NULL)
+ {
+ /* XXX should cope with errors from diskfs_get_filemap */
+ poke_pages (obj, round_page (length), round_page (node->allocsize));
+ mach_port_deallocate (mach_task_self (), obj);
+ pager_flush_some (pager, round_page(length),
+ node->allocsize - length, 1);
+ }
+
ports_port_deref (pager);
}
}
@@ -263,7 +272,7 @@ enable_delayed_copies (struct node *node)
/* The user must define this function. Truncate locked node NODE to be SIZE
bytes long. (If NODE is already less than or equal to SIZE bytes
long, do nothing.) If this is a symlink (and diskfs_shortcut_symlink
- is set) then this should clear the symlink, even if
+ is set) then this should clear the symlink, even if
diskfs_create_symlink_hook stores the link target elsewhere. */
error_t
diskfs_truncate (struct node *node, off_t length)
@@ -277,13 +286,25 @@ diskfs_truncate (struct node *node, off_t length)
if (length >= node->dn_stat.st_size)
return 0;
+ if (! node->dn_stat.st_blocks)
+ /* There aren't really any blocks allocated, so just frob the size. This
+ is true for fast symlinks, and also apparently for some device nodes
+ in linux. */
+ {
+ node->dn_stat.st_size = length;
+ node->dn_set_mtime = 1;
+ node->dn_set_ctime = 1;
+ diskfs_node_update (node, 1);
+ return 0;
+ }
+
/*
* If the file is not being truncated to a block boundary, the
* contents of the partial block following the end of the file must be
* zeroed in case it ever becomes accessible again because of
* subsequent file growth.
*/
- offset = length % block_size;
+ offset = length & (block_size - 1);
if (offset > 0)
{
diskfs_node_rdwr (node, (void *)zeroblock, length, block_size - offset,
@@ -291,7 +312,7 @@ diskfs_truncate (struct node *node, off_t length)
diskfs_file_update (node, 1);
}
- ext2_discard_prealloc(node);
+ ext2_discard_prealloc (node);
force_delayed_copies (node, length);
@@ -304,7 +325,7 @@ diskfs_truncate (struct node *node, off_t length)
node->dn_set_ctime = 1;
diskfs_node_update (node, 1);
- err = diskfs_catch_exception();
+ err = diskfs_catch_exception ();
if (!err)
{
block_t end = boffs_block (round_block (length)), offs;
@@ -330,6 +351,8 @@ diskfs_truncate (struct node *node, off_t length)
won't hurt if is wrong. */
node->dn->last_page_partially_writable =
trunc_page (node->allocsize) != node->allocsize;
+
+ diskfs_end_catch_exception ();
}
node->dn_set_mtime = 1;