G-safe-unlink.patch
Fixes long-standing problem in reiserfs, when disk space gets leaked
if crash occurred when some process hold a reference to unlinked file.
diff -rup linux-2.4.6/fs/reiserfs/inode.c linux-2.4.6.cleanup/fs/reiserfs/inode.c
--- linux-2.4.6/fs/reiserfs/inode.c Wed Jul 11 23:05:13 2001
+++ linux-2.4.6.cleanup/fs/reiserfs/inode.c Wed Jul 11 21:48:10 2001
@@ -44,14 +44,21 @@ void reiserfs_delete_inode (struct inode
journal_end(&th, inode->i_sb, jbegin_count) ;
up (&inode->i_sem);
+
+ /* all items of file are deleted, so we can remove "save" link */
+ remove_save_link (inode);
+
} else {
/* no object items are in the tree */
;
}
+
clear_inode (inode); /* note this must go after the journal_end to prevent deadlock */
- unlock_kernel() ;
+
+ unlock_kernel ();
}
+
static void _make_cpu_key (struct cpu_key * key, int version, __u32 dirid, __u32 objectid,
loff_t offset, int type, int length)
{
@@ -1664,11 +1671,21 @@ void reiserfs_truncate_file(struct inode
** (it will unmap bh if it packs).
*/
prevent_flush_page_lock(page, p_s_inode) ;
- journal_begin(&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 ) ;
+
+ /* it is enough to reserve space in transaction for 2 balancings: one for
+ "save" link adding and another for the first cut_from_item. 1 is for
+ update_sd */
+ journal_begin(&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 + 1) ;
windex = push_journal_writer("reiserfs_vfs_truncate_file") ;
+
+
reiserfs_do_truncate (&th, p_s_inode, page, update_timestamps) ;
pop_journal_writer(windex) ;
- journal_end(&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 ) ;
+ journal_end(&th, p_s_inode->i_sb, JOURNAL_PER_BALANCE_CNT * 2 + 1 ) ;
+
+ if (update_timestamps)
+ remove_save_link (p_s_inode);
+
allow_flush_page_lock(page, p_s_inode) ;
+ /* prevent empty directory from getting lost */
+ add_save_link (&th, inode);
+
pop_journal_writer(windex) ;
journal_end(&th, dir->i_sb, jbegin_count) ;
reiserfs_check_path(&path) ;
@@ -787,7 +793,16 @@ int reiserfs_unlink (struct inode * dir,
INITIALIZE_PATH (path);
int windex ;
struct reiserfs_transaction_handle th ;
- int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3;
+ int jbegin_count;
+
+ inode = dentry->d_inode;
+
+ /* in this transaction we will be doing at least one balancing and update
+ two stat datas */
+ jbegin_count = JOURNAL_PER_BALANCE_CNT + 2;
+ if (inode->i_nlink < 2)
+ /* reserve space in the transaction for adding "save" link */
+ jbegin_count += JOURNAL_PER_BALANCE_CNT;
if (de.de_objectid != inode->i_ino) {
// FIXME: compare key of an object and a key found in the
@@ -825,6 +839,10 @@ int reiserfs_unlink (struct inode * dir,
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
reiserfs_update_sd (&th, dir);
+ if (!inode->i_nlink)
+ /* prevent file from getting lost */
+ add_save_link (&th, inode);
+
pop_journal_writer(windex) ;
journal_end(&th, dir->i_sb, jbegin_count) ;
reiserfs_check_path(&path) ;
@@ -1027,9 +1045,14 @@ int reiserfs_rename (struct inode * old_
struct inode * old_inode, * new_inode;
int windex ;
struct reiserfs_transaction_handle th ;
- int jbegin_count = JOURNAL_PER_BALANCE_CNT * 3;
+ int jbegin_count ;
+ /* two balancings: old name removal, new name insertion or "save" link,
+ stat data updates: old directory and new directory and maybe block
+ containing ".." of renamed directory */
+ jbegin_count = JOURNAL_PER_BALANCE_CNT * 3 + 3;
+
old_inode = old_dentry->d_inode;
new_inode = new_dentry->d_inode;
@@ -1137,13 +1160,6 @@ int reiserfs_rename (struct inode * old_
reiserfs_restore_prepared_buffer (old_inode->i_sb, new_de.de_bh);
if (S_ISDIR(old_inode->i_mode))
reiserfs_restore_prepared_buffer (old_inode->i_sb, dot_dot_de.de_bh);
-#if 0
- // FIXME: do we need this? shouldn't we simply continue?
- run_task_queue(&tq_disk);
- current->policy |= SCHED_YIELD;
- /*current->counter = 0;*/
- schedule();
-#endif
continue;
}
if (new_inode) {
- // adjust link number of the victim
+ /* if it is empty directory or file with link count == 1 - we have to
+ "save" link it to garantee file body removal */
if (S_ISDIR(new_inode->i_mode)) {
- DEC_DIR_INODE_NLINK(new_inode)
+ new_inode->i_nlink = 0;
} else {
new_inode->i_nlink--;
}
@@ -1176,21 +1193,17 @@ int reiserfs_rename (struct inode * old_
}
if (S_ISDIR(old_inode->i_mode)) {
- //if (dot_dot_de.de_bh) {
- // adjust ".." of renamed directory
+ /* adjust ".." of renamed directory */
set_ino_in_dir_entry (&dot_dot_de, INODE_PKEY (new_dir));
journal_mark_dirty (&th, new_dir->i_sb, dot_dot_de.de_bh);
- DEC_DIR_INODE_NLINK(old_dir)
- if (new_inode) {
- if (S_ISDIR(new_inode->i_mode)) {
- DEC_DIR_INODE_NLINK(new_inode)
- } else {
- new_inode->i_nlink--;
- }
- } else {
+ if (!new_inode)
+ /* there (in new_dir) was no directory, so it got new link (".."
+ of renamed directory) */
INC_DIR_INODE_NLINK(new_dir)
- }
+
+ /* this is removal of ".." of the renames dir */
+ DEC_DIR_INODE_NLINK(old_dir);
}
// looks like in 2.3.99pre3 brelse is atomic. so we can use pathrelse
@@ -1208,8 +1221,12 @@ int reiserfs_rename (struct inode * old_
reiserfs_update_sd (&th, old_dir);
reiserfs_update_sd (&th, new_dir);
- if (new_inode)
+
+ if (new_inode) {
+ if (new_inode->i_nlink == 0)
+ add_save_link (&th, new_inode);
reiserfs_update_sd (&th, new_inode);
+ }
- RFALSE( ! key_in_buffer(p_s_search_path, p_s_key, p_s_sb),
- "PAP-5130: key is not in the buffer");
+ /* only check that key is in buffer if p_s_key is not equal to the
+ MAX_KEY. Latter case is only possible in "finish_unfinished()"
+ processing during mount. */
+ RFALSE( COMP_KEYS( &MAX_KEY, p_s_key ) &&
+ ! key_in_buffer(p_s_search_path, p_s_key, p_s_sb),
+ "PAP-5130: key is not in the buffer" );
#ifdef CONFIG_REISERFS_CHECK
if ( cur_tb ) {
print_cur_tb ("5140");
@@ -1401,7 +1405,7 @@ int reiserfs_delete_item (struct reiserf
// IO_ERROR, NO_DISK_SPACE, etc
- reiserfs_warning ("vs-: reiserfs_delete_solid_item: "
+ reiserfs_warning ("vs-5400: reiserfs_delete_solid_item: "
"could not delete %K due to fix_nodes failure\n", &cpu_key);
unfix_nodes (&tb);
break;
@@ -1783,6 +1788,15 @@ void reiserfs_do_truncate (struct reiser
pathrelse(&s_search_path);
return;
}
+
+
+ if (update_timestamps)
+ /* we are doing real truncate: if the system crashes before the last
+ transaction of truncating gets committed - on reboot the file
+ either appears truncated properly or not truncated at all */
+ add_save_link (th, p_s_inode);
+
+
/* Update key to search for the last file item. */
set_cpu_key_k_offset (&s_item_key, n_file_size);
-/*#define COMP_KEYS(p_s_key1, p_s_key2) comp_keys((unsigned long *)(p_s_key1), (unsigned long *)(p_s_key2))
-#define COMP_SHORT_KEYS(p_s_key1, p_s_key2) comp_short_keys((unsigned long *)(p_s_key1), (unsigned long *)(p_s_key2))*/
-
-
/* number of blocks pointed to by the indirect item */
#define I_UNFM_NUM(p_s_ih) ( (p_s_ih)->ih_item_len / UNFM_P_SIZE )