📄 super.c
字号:
/* * Copyright 2000 by Hans Reiser, licensing governed by reiserfs/README * * Trivial changes by Alan Cox to add the LFS fixes * * Trivial Changes: * Rights granted to Hans Reiser to redistribute under other terms providing * he accepts all liability including but not limited to patent, fitness * for purpose, and direct or indirect claims arising from failure to perform. * * NO WARRANTY */#include <linux/config.h>#include <linux/module.h>#include <linux/sched.h>#include <asm/uaccess.h>#include <linux/reiserfs_fs.h>#include <linux/smp_lock.h>#include <linux/locks.h>#include <linux/init.h>#define REISERFS_OLD_BLOCKSIZE 4096#define REISERFS_SUPER_MAGIC_STRING_OFFSET_NJ 20char reiserfs_super_magic_string[] = REISERFS_SUPER_MAGIC_STRING;char reiser2fs_super_magic_string[] = REISER2FS_SUPER_MAGIC_STRING;static int reiserfs_remount (struct super_block * s, int * flags, char * data);static int reiserfs_statfs (struct super_block * s, struct statfs * buf);//// a portion of this function, particularly the VFS interface portion,// was derived from minix or ext2's analog and evolved as the// prototype did. You should be able to tell which portion by looking// at the ext2 code and comparing. It's subfunctions contain no code// used as a template unless they are so labeled.//static void reiserfs_write_super (struct super_block * s){ int dirty = 0 ; lock_kernel() ; if (!(s->s_flags & MS_RDONLY)) { dirty = flush_old_commits(s, 1) ; } s->s_dirt = dirty; unlock_kernel() ;}//// a portion of this function, particularly the VFS interface portion,// was derived from minix or ext2's analog and evolved as the// prototype did. You should be able to tell which portion by looking// at the ext2 code and comparing. It's subfunctions contain no code// used as a template unless they are so labeled.//static void reiserfs_write_super_lockfs (struct super_block * s){ int dirty = 0 ; struct reiserfs_transaction_handle th ; lock_kernel() ; if (!(s->s_flags & MS_RDONLY)) { journal_begin(&th, s, 1) ; reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1); journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s)); reiserfs_block_writes(&th) ; journal_end(&th, s, 1) ; } s->s_dirt = dirty; unlock_kernel() ;}void reiserfs_unlockfs(struct super_block *s) { reiserfs_allow_writes(s) ;}extern const struct key MAX_KEY;/* this is used to delete "save link" when there are no items of a file it points to. It can either happen if unlink is completed but "save unlink" removal, or if file has both unlink and truncate pending and as unlink completes first (because key of "save link" protecting unlink is bigger that a key lf "save link" which protects truncate), so there left no items to make truncate completion on */static void remove_save_link_only (struct super_block * s, struct key * key, int oid_free){ struct reiserfs_transaction_handle th; /* we are going to do one balancing */ journal_begin (&th, s, JOURNAL_PER_BALANCE_CNT); reiserfs_delete_solid_item (&th, key); if (oid_free) /* removals are protected by direct items */ reiserfs_release_objectid (&th, le32_to_cpu (key->k_objectid)); journal_end (&th, s, JOURNAL_PER_BALANCE_CNT);} /* look for uncompleted unlinks and truncates and complete them */static void finish_unfinished (struct super_block * s){ INITIALIZE_PATH (path); struct cpu_key max_cpu_key, obj_key; struct key save_link_key; int retval; struct item_head * ih; struct buffer_head * bh; int item_pos; char * item; int done; struct inode * inode; int truncate; /* compose key to look for "save" links */ max_cpu_key.version = KEY_FORMAT_3_5; max_cpu_key.on_disk_key = MAX_KEY; max_cpu_key.key_length = 3; done = 0; s -> u.reiserfs_sb.s_is_unlinked_ok = 1; while (1) { retval = search_item (s, &max_cpu_key, &path); if (retval != ITEM_NOT_FOUND) { reiserfs_warning ("vs-2140: finish_unfinished: search_by_key returned %d\n", retval); break; } bh = get_last_bh (&path); item_pos = get_item_pos (&path); if (item_pos != B_NR_ITEMS (bh)) { reiserfs_warning ("vs-2060: finish_unfinished: wrong position found\n"); break; } item_pos --; ih = B_N_PITEM_HEAD (bh, item_pos); if (le32_to_cpu (ih->ih_key.k_dir_id) != MAX_KEY_OBJECTID) /* there are no "save" links anymore */ break; save_link_key = ih->ih_key; if (is_indirect_le_ih (ih)) truncate = 1; else truncate = 0; /* reiserfs_iget needs k_dirid and k_objectid only */ item = B_I_PITEM (bh, ih); obj_key.on_disk_key.k_dir_id = le32_to_cpu (*(__u32 *)item); obj_key.on_disk_key.k_objectid = le32_to_cpu (ih->ih_key.k_objectid); obj_key.on_disk_key.u.k_offset_v1.k_offset = 0; obj_key.on_disk_key.u.k_offset_v1.k_uniqueness = 0; pathrelse (&path); inode = reiserfs_iget (s, &obj_key); if (!inode) { /* the unlink almost completed, it just did not manage to remove "save" link and release objectid */ reiserfs_warning ("vs-2180: finish_unfinished: iget failed for %K\n", &obj_key); remove_save_link_only (s, &save_link_key, 1); continue; } if (!truncate && inode->i_nlink) { /* file is not unlinked */ reiserfs_warning ("vs-2185: finish_unfinished: file %K is not unlinked\n", &obj_key); remove_save_link_only (s, &save_link_key, 0); continue; } if (truncate && S_ISDIR (inode->i_mode) ) { /* We got a truncate request for a dir which is impossible. The only imaginable way is to execute unfinished truncate request then boot into old kernel, remove the file and create dir with the same key. */ reiserfs_warning("green-2101: impossible truncate on a directory %k. Please report\n", INODE_PKEY (inode)); remove_save_link_only (s, &save_link_key, 0); truncate = 0; iput (inode); continue; } if (truncate) { inode -> u.reiserfs_i.i_flags |= i_link_saved_truncate_mask; /* not completed truncate found. New size was committed together with "save" link */ reiserfs_warning ("Truncating %k to %Ld ..", INODE_PKEY (inode), inode->i_size); reiserfs_truncate_file (inode, 0/*don't update modification time*/); remove_save_link (inode, truncate); } else { inode -> u.reiserfs_i.i_flags |= i_link_saved_unlink_mask; /* not completed unlink (rmdir) found */ reiserfs_warning ("Removing %k..", INODE_PKEY (inode)); /* removal gets completed in iput */ } iput (inode); reiserfs_warning ("done\n"); done ++; } s -> u.reiserfs_sb.s_is_unlinked_ok = 0; pathrelse (&path); if (done) reiserfs_warning ("There were %d uncompleted unlinks/truncates. " "Completed\n", done);} /* to protect file being unlinked from getting lost we "safe" link files being unlinked. This link will be deleted in the same transaction with last item of file. mounting the filesytem we scan all these links and remove files which almost got lost */void add_save_link (struct reiserfs_transaction_handle * th, struct inode * inode, int truncate){ INITIALIZE_PATH (path); int retval; struct cpu_key key; struct item_head ih; __u32 link; /* file can only get one "save link" of each kind */ RFALSE( truncate && ( inode -> u.reiserfs_i.i_flags & i_link_saved_truncate_mask ), "saved link already exists for truncated inode %lx", ( long ) inode -> i_ino ); RFALSE( !truncate && ( inode -> u.reiserfs_i.i_flags & i_link_saved_unlink_mask ), "saved link already exists for unlinked inode %lx", ( long ) inode -> i_ino ); /* setup key of "save" link */ key.version = KEY_FORMAT_3_5; key.on_disk_key.k_dir_id = MAX_KEY_OBJECTID; key.on_disk_key.k_objectid = inode->i_ino; if (!truncate) { /* unlink, rmdir, rename */ set_cpu_key_k_offset (&key, 1 + inode->i_sb->s_blocksize); set_cpu_key_k_type (&key, TYPE_DIRECT); /* item head of "safe" link */ make_le_item_head (&ih, &key, key.version, 1 + inode->i_sb->s_blocksize, TYPE_DIRECT, 4/*length*/, 0xffff/*free space*/); } else { /* truncate */ if (S_ISDIR (inode->i_mode)) reiserfs_warning("green-2102: Adding a truncate savelink for a directory %k! Please report\n", INODE_PKEY(inode)); set_cpu_key_k_offset (&key, 1); set_cpu_key_k_type (&key, TYPE_INDIRECT); /* item head of "safe" link */ make_le_item_head (&ih, &key, key.version, 1, TYPE_INDIRECT, 4/*length*/, 0/*free space*/); } key.key_length = 3; /* look for its place in the tree */ retval = search_item (inode->i_sb, &key, &path); if (retval != ITEM_NOT_FOUND) { reiserfs_warning ("vs-2100: add_save_link:" "search_by_key (%K) returned %d\n", &key, retval); pathrelse (&path); return; } /* body of "save" link */ link = cpu_to_le32 (INODE_PKEY (inode)->k_dir_id); /* put "save" link inot tree */ retval = reiserfs_insert_item (th, &path, &key, &ih, (char *)&link); if (retval) reiserfs_warning ("vs-2120: add_save_link: insert_item returned %d\n", retval); else { if( truncate ) inode -> u.reiserfs_i.i_flags |= i_link_saved_truncate_mask; else inode -> u.reiserfs_i.i_flags |= i_link_saved_unlink_mask; }}/* this opens transaction unlike add_save_link */void remove_save_link (struct inode * inode, int truncate){ struct reiserfs_transaction_handle th; struct key key; /* we are going to do one balancing only */ journal_begin (&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT); /* setup key of "save" link */ key.k_dir_id = cpu_to_le32 (MAX_KEY_OBJECTID); key.k_objectid = INODE_PKEY (inode)->k_objectid; if (!truncate) { /* unlink, rmdir, rename */ set_le_key_k_offset (KEY_FORMAT_3_5, &key, 1 + inode->i_sb->s_blocksize); set_le_key_k_type (KEY_FORMAT_3_5, &key, TYPE_DIRECT); } else { /* truncate */ set_le_key_k_offset (KEY_FORMAT_3_5, &key, 1); set_le_key_k_type (KEY_FORMAT_3_5, &key, TYPE_INDIRECT); } if( ( truncate && ( inode -> u.reiserfs_i.i_flags & i_link_saved_truncate_mask ) ) || ( !truncate && ( inode -> u.reiserfs_i.i_flags & i_link_saved_unlink_mask ) ) ) reiserfs_delete_solid_item (&th, &key); if (!truncate) { reiserfs_release_objectid (&th, inode->i_ino); inode -> u.reiserfs_i.i_flags &= ~i_link_saved_unlink_mask; } else inode -> u.reiserfs_i.i_flags &= ~i_link_saved_truncate_mask; journal_end (&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT);}//// a portion of this function, particularly the VFS interface portion,// was derived from minix or ext2's analog and evolved as the// prototype did. You should be able to tell which portion by looking// at the ext2 code and comparing. It's subfunctions contain no code// used as a template unless they are so labeled.//static void reiserfs_put_super (struct super_block * s){ int i; struct reiserfs_transaction_handle th ; /* change file system state to current state if it was mounted with read-write permissions */ if (!(s->s_flags & MS_RDONLY)) { journal_begin(&th, s, 10) ; reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ; set_sb_state( SB_DISK_SUPER_BLOCK(s), s->u.reiserfs_sb.s_mount_state ); journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s)); } /* note, journal_release checks for readonly mount, and can decide not ** to do a journal_end */ journal_release(&th, s) ; for (i = 0; i < SB_BMAP_NR (s); i ++) brelse (SB_AP_BITMAP (s)[i]); reiserfs_kfree (SB_AP_BITMAP (s), sizeof (struct buffer_head *) * SB_BMAP_NR (s), s); brelse (SB_BUFFER_WITH_SB (s)); print_statistics (s); if (s->u.reiserfs_sb.s_kmallocs != 0) { reiserfs_warning ("vs-2004: reiserfs_put_super: allocated memory left %d\n", s->u.reiserfs_sb.s_kmallocs); } reiserfs_proc_unregister( s, "journal" ); reiserfs_proc_unregister( s, "oidmap" ); reiserfs_proc_unregister( s, "on-disk-super" ); reiserfs_proc_unregister( s, "bitmap" );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -