📄 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/module.h>#include <linux/vmalloc.h>#include <linux/time.h>#include <asm/uaccess.h>#include <linux/reiserfs_fs.h>#include <linux/reiserfs_acl.h>#include <linux/reiserfs_xattr.h>#include <linux/init.h>#include <linux/blkdev.h>#include <linux/buffer_head.h>#include <linux/exportfs.h>#include <linux/vfs.h>#include <linux/mnt_namespace.h>#include <linux/mount.h>#include <linux/namei.h>#include <linux/quotaops.h>struct file_system_type reiserfs_fs_type;static const char reiserfs_3_5_magic_string[] = REISERFS_SUPER_MAGIC_STRING;static const char reiserfs_3_6_magic_string[] = REISER2FS_SUPER_MAGIC_STRING;static const char reiserfs_jr_magic_string[] = REISER2FS_JR_SUPER_MAGIC_STRING;int is_reiserfs_3_5(struct reiserfs_super_block *rs){ return !strncmp(rs->s_v1.s_magic, reiserfs_3_5_magic_string, strlen(reiserfs_3_5_magic_string));}int is_reiserfs_3_6(struct reiserfs_super_block *rs){ return !strncmp(rs->s_v1.s_magic, reiserfs_3_6_magic_string, strlen(reiserfs_3_6_magic_string));}int is_reiserfs_jr(struct reiserfs_super_block *rs){ return !strncmp(rs->s_v1.s_magic, reiserfs_jr_magic_string, strlen(reiserfs_jr_magic_string));}static int is_any_reiserfs_magic_string(struct reiserfs_super_block *rs){ return (is_reiserfs_3_5(rs) || is_reiserfs_3_6(rs) || is_reiserfs_jr(rs));}static int reiserfs_remount(struct super_block *s, int *flags, char *data);static int reiserfs_statfs(struct dentry *dentry, struct kstatfs *buf);static int reiserfs_sync_fs(struct super_block *s, int wait){ if (!(s->s_flags & MS_RDONLY)) { struct reiserfs_transaction_handle th; reiserfs_write_lock(s); if (!journal_begin(&th, s, 1)) if (!journal_end_sync(&th, s, 1)) reiserfs_flush_old_commits(s); s->s_dirt = 0; /* Even if it's not true. * We'll loop forever in sync_supers otherwise */ reiserfs_write_unlock(s); } else { s->s_dirt = 0; } return 0;}static void reiserfs_write_super(struct super_block *s){ reiserfs_sync_fs(s, 1);}static void reiserfs_write_super_lockfs(struct super_block *s){ struct reiserfs_transaction_handle th; reiserfs_write_lock(s); if (!(s->s_flags & MS_RDONLY)) { int err = journal_begin(&th, s, 1); if (err) { reiserfs_block_writes(&th); } else { 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_sync(&th, s, 1); } } s->s_dirt = 0; reiserfs_write_unlock(s);}static void reiserfs_unlockfs(struct super_block *s){ reiserfs_allow_writes(s);}extern const struct in_core_key MAX_IN_CORE_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 int remove_save_link_only(struct super_block *s, struct reiserfs_key *key, int oid_free){ struct reiserfs_transaction_handle th; int err; /* we are going to do one balancing */ err = journal_begin(&th, s, JOURNAL_PER_BALANCE_CNT); if (err) return err; reiserfs_delete_solid_item(&th, NULL, key); if (oid_free) /* removals are protected by direct items */ reiserfs_release_objectid(&th, le32_to_cpu(key->k_objectid)); return journal_end(&th, s, JOURNAL_PER_BALANCE_CNT);}#ifdef CONFIG_QUOTAstatic int reiserfs_quota_on_mount(struct super_block *, int);#endif/* look for uncompleted unlinks and truncates and complete them */static int finish_unfinished(struct super_block *s){ INITIALIZE_PATH(path); struct cpu_key max_cpu_key, obj_key; struct reiserfs_key save_link_key, last_inode_key; int retval = 0; struct item_head *ih; struct buffer_head *bh; int item_pos; char *item; int done; struct inode *inode; int truncate;#ifdef CONFIG_QUOTA int i; int ms_active_set;#endif /* compose key to look for "save" links */ max_cpu_key.version = KEY_FORMAT_3_5; max_cpu_key.on_disk_key.k_dir_id = ~0U; max_cpu_key.on_disk_key.k_objectid = ~0U; set_cpu_key_k_offset(&max_cpu_key, ~0U); max_cpu_key.key_length = 3; memset(&last_inode_key, 0, sizeof(last_inode_key));#ifdef CONFIG_QUOTA /* Needed for iput() to work correctly and not trash data */ if (s->s_flags & MS_ACTIVE) { ms_active_set = 0; } else { ms_active_set = 1; s->s_flags |= MS_ACTIVE; } /* Turn on quotas so that they are updated correctly */ for (i = 0; i < MAXQUOTAS; i++) { if (REISERFS_SB(s)->s_qf_names[i]) { int ret = reiserfs_quota_on_mount(s, i); if (ret < 0) reiserfs_warning(s, "reiserfs: cannot turn on journalled quota: error %d", ret); } }#endif done = 0; REISERFS_SB(s)->s_is_unlinked_ok = 1; while (!retval) { retval = search_item(s, &max_cpu_key, &path); if (retval != ITEM_NOT_FOUND) { reiserfs_warning(s, "vs-2140: finish_unfinished: search_by_key returned %d", retval); break; } bh = get_last_bh(&path); item_pos = get_item_pos(&path); if (item_pos != B_NR_ITEMS(bh)) { reiserfs_warning(s, "vs-2060: finish_unfinished: wrong position found"); 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(*(__le32 *) item); obj_key.on_disk_key.k_objectid = le32_to_cpu(ih->ih_key.k_objectid); obj_key.on_disk_key.k_offset = 0; obj_key.on_disk_key.k_type = 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(s, "vs-2180: finish_unfinished: iget failed for %K", &obj_key); retval = remove_save_link_only(s, &save_link_key, 1); continue; } if (!truncate && inode->i_nlink) { /* file is not unlinked */ reiserfs_warning(s, "vs-2185: finish_unfinished: file %K is not unlinked", &obj_key); retval = remove_save_link_only(s, &save_link_key, 0); continue; } DQUOT_INIT(inode); 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(s, "green-2101: impossible truncate on a directory %k. Please report", INODE_PKEY(inode)); retval = remove_save_link_only(s, &save_link_key, 0); truncate = 0; iput(inode); continue; } if (truncate) { REISERFS_I(inode)->i_flags |= i_link_saved_truncate_mask; /* not completed truncate found. New size was committed together with "save" link */ reiserfs_info(s, "Truncating %k to %Ld ..", INODE_PKEY(inode), inode->i_size); reiserfs_truncate_file(inode, 0 /*don't update modification time */ ); retval = remove_save_link(inode, truncate); } else { REISERFS_I(inode)->i_flags |= i_link_saved_unlink_mask; /* not completed unlink (rmdir) found */ reiserfs_info(s, "Removing %k..", INODE_PKEY(inode)); if (memcmp(&last_inode_key, INODE_PKEY(inode), sizeof(last_inode_key))){ last_inode_key = *INODE_PKEY(inode); /* removal gets completed in iput */ retval = 0; } else { reiserfs_warning(s, "Dead loop in " "finish_unfinished detected, " "just remove save link\n"); retval = remove_save_link_only(s, &save_link_key, 0); } } iput(inode); printk("done\n"); done++; } REISERFS_SB(s)->s_is_unlinked_ok = 0;#ifdef CONFIG_QUOTA /* Turn quotas off */ for (i = 0; i < MAXQUOTAS; i++) { if (sb_dqopt(s)->files[i]) vfs_quota_off_mount(s, i); } if (ms_active_set) /* Restore the flag back */ s->s_flags &= ~MS_ACTIVE;#endif pathrelse(&path); if (done) reiserfs_info(s, "There were %d uncompleted unlinks/truncates. " "Completed\n", done); return retval;}/* 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 filesystem 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; __le32 link; BUG_ON(!th->t_trans_id); /* file can only get one "save link" of each kind */ RFALSE(truncate && (REISERFS_I(inode)->i_flags & i_link_saved_truncate_mask), "saved link already exists for truncated inode %lx", (long)inode->i_ino); RFALSE(!truncate && (REISERFS_I(inode)->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(inode->i_sb, "green-2102: Adding a truncate savelink for a directory %k! Please report", 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) { if (retval != -ENOSPC) reiserfs_warning(inode->i_sb, "vs-2100: add_save_link:" "search_by_key (%K) returned %d", &key, retval); pathrelse(&path); return; } /* body of "save" link */ link = INODE_PKEY(inode)->k_dir_id; /* put "save" link inot tree, don't charge quota to anyone */ retval = reiserfs_insert_item(th, &path, &key, &ih, NULL, (char *)&link); if (retval) { if (retval != -ENOSPC) reiserfs_warning(inode->i_sb, "vs-2120: add_save_link: insert_item returned %d", retval); } else { if (truncate) REISERFS_I(inode)->i_flags |= i_link_saved_truncate_mask; else REISERFS_I(inode)->i_flags |= i_link_saved_unlink_mask; }}/* this opens transaction unlike add_save_link */int remove_save_link(struct inode *inode, int truncate){ struct reiserfs_transaction_handle th; struct reiserfs_key key; int err; /* we are going to do one balancing only */ err = journal_begin(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT); if (err) return err; /* 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 && (REISERFS_I(inode)->i_flags & i_link_saved_truncate_mask)) || (!truncate && (REISERFS_I(inode)->i_flags & i_link_saved_unlink_mask))) /* don't take quota bytes from anywhere */ reiserfs_delete_solid_item(&th, NULL, &key); if (!truncate) { reiserfs_release_objectid(&th, inode->i_ino); REISERFS_I(inode)->i_flags &= ~i_link_saved_unlink_mask; } else REISERFS_I(inode)->i_flags &= ~i_link_saved_truncate_mask; return journal_end(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -