/* * 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 */ #ifdef __KERNEL__ #include #include #include #include #include #include #include #include #else #include "nokernel.h" #include // for simple_strtoul #endif #define SUPPORT_OLD_FORMAT #define REISERFS_OLD_BLOCKSIZE 4096 #define REISERFS_SUPER_MAGIC_STRING_OFFSET_NJ 20 #if 0 // this one is not used currently inline void reiserfs_mark_buffer_dirty (struct buffer_head * bh, int flag) { mark_buffer_dirty (bh, flag); } #endif // // 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. // 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. // 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) ; 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) ; } // // 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. // /* there should be no suspected recipients already. True and cautious bitmaps should not differ. We only have to free preserve list and write both bitmaps */ 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) ; s->u.reiserfs_sb.s_rs->s_state = le16_to_cpu (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: aloocated memory left %d\n", s->u.reiserfs_sb.s_kmallocs); } return; } struct super_operations reiserfs_sops = { read_inode: reiserfs_read_inode, read_inode2: reiserfs_read_inode2, write_inode: reiserfs_write_inode, dirty_inode: reiserfs_dirty_inode, delete_inode: reiserfs_delete_inode, put_super: reiserfs_put_super, write_super: reiserfs_write_super, write_super_lockfs: reiserfs_write_super_lockfs, unlockfs: reiserfs_unlockfs, statfs: reiserfs_statfs, remount_fs: reiserfs_remount, }; /* this was (ext2)parse_options */ static int parse_options (char * options, unsigned long * mount_options, unsigned long * blocks) { char * this_char; char * value; *blocks = 0; if (!options) /* use default configuration: create tails, journaling on, no conversion to newest format */ return 1; for (this_char = strtok (options, ","); this_char != NULL; this_char = strtok (NULL, ",")) { if ((value = strchr (this_char, '=')) != NULL) *value++ = 0; if (!strcmp (this_char, "notail")) { set_bit (NOTAIL, mount_options); } else if (!strcmp (this_char, "conv")) { // if this is set, we update super block such that // the partition will not be mounable by 3.5.x anymore set_bit (REISERFS_CONVERT, mount_options); } else if (!strcmp (this_char, "noborder")) { /* this is used for benchmarking experimental variations, it is not intended for users to use, only for developers who want to casually hack in something to test */ set_bit (REISERFS_NO_BORDER, mount_options); } else if (!strcmp (this_char, "no_unhashed_relocation")) { set_bit (REISERFS_NO_UNHASHED_RELOCATION, mount_options); } else if (!strcmp (this_char, "hashed_relocation")) { set_bit (REISERFS_HASHED_RELOCATION, mount_options); } else if (!strcmp (this_char, "test4")) { set_bit (REISERFS_TEST4, mount_options); } else if (!strcmp (this_char, "nolog")) { reiserfs_warning("reiserfs: nolog mount option not supported yet\n"); } else if (!strcmp (this_char, "replayonly")) { set_bit (REPLAYONLY, mount_options); } else if (!strcmp (this_char, "resize")) { if (value && *value){ *blocks = simple_strtoul (value, &value, 0); } else { printk("reiserfs: resize option requires a value\n"); return 0; } } else if (!strcmp (this_char, "hash")) { if (value && *value) { /* if they specify any hash option, we force detection ** to make sure they aren't using the wrong hash */ if (!strcmp(value, "rupasov")) { set_bit (FORCE_RUPASOV_HASH, mount_options); set_bit (FORCE_HASH_DETECT, mount_options); } else if (!strcmp(value, "tea")) { set_bit (FORCE_TEA_HASH, mount_options); set_bit (FORCE_HASH_DETECT, mount_options); } else if (!strcmp(value, "r5")) { set_bit (FORCE_R5_HASH, mount_options); set_bit (FORCE_HASH_DETECT, mount_options); } else if (!strcmp(value, "detect")) { set_bit (FORCE_HASH_DETECT, mount_options); } else { printk("reiserfs: invalid hash function specified\n") ; return 0 ; } } else { printk("reiserfs: hash option requires a value\n"); return 0 ; } } else { printk ("reiserfs: Unrecognized mount option %s\n", this_char); return 0; } } return 1; } int reiserfs_is_super(struct super_block *s) { return (s->s_dev != 0 && s->s_op == &reiserfs_sops) ; } // // 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. // int reiserfs_remount (struct super_block * s, int * flags, char * data) { struct reiserfs_super_block * rs; struct reiserfs_transaction_handle th ; unsigned long blocks; unsigned long mount_options; rs = SB_DISK_SUPER_BLOCK (s); if (!parse_options(data, &mount_options, &blocks)) return 0; if(blocks) { int rc = reiserfs_resize(s, blocks); if (rc != 0) return rc; } if ((unsigned long)(*flags & MS_RDONLY) == (s->s_flags & MS_RDONLY)) { /* there is nothing to do to remount read-only fs as read-only fs */ return 0; } if (*flags & MS_RDONLY) { /* try to remount file system with read-only permissions */ if (le16_to_cpu (rs->s_state) == REISERFS_VALID_FS || s->u.reiserfs_sb.s_mount_state != REISERFS_VALID_FS) { return 0; } journal_begin(&th, s, 10) ; /* Mounting a rw partition read-only. */ reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ; rs->s_state = cpu_to_le16 (s->u.reiserfs_sb.s_mount_state); journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s)); s->s_dirt = 0; } else { s->u.reiserfs_sb.s_mount_state = le16_to_cpu(rs->s_state) ; s->s_flags &= ~MS_RDONLY ; /* now it is safe to call journal_begin */ journal_begin(&th, s, 10) ; /* Mount a partition which is read-only, read-write */ reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ; s->u.reiserfs_sb.s_mount_state = le16_to_cpu (rs->s_state); s->s_flags &= ~MS_RDONLY; rs->s_state = cpu_to_le16 (REISERFS_ERROR_FS); /* mark_buffer_dirty (SB_BUFFER_WITH_SB (s), 1); */ journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s)); s->s_dirt = 0; s->u.reiserfs_sb.s_mount_state = REISERFS_VALID_FS ; } /* this will force a full flush of all journal lists */ SB_JOURNAL(s)->j_must_wait = 1 ; journal_end(&th, s, 10) ; return 0; } static int read_bitmaps (struct super_block * s) { int i, bmp, dl ; struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK(s); SB_AP_BITMAP (s) = reiserfs_kmalloc (sizeof (struct buffer_head *) * le16_to_cpu (rs->s_bmap_nr), GFP_BUFFER, s); if (SB_AP_BITMAP (s) == 0) return 1; memset (SB_AP_BITMAP (s), 0, sizeof (struct buffer_head *) * le16_to_cpu (rs->s_bmap_nr)); /* reiserfs leaves the first 64k unused so that any partition labeling scheme currently used will have enough space. Then we need one block for the super. -Hans */ bmp = (REISERFS_DISK_OFFSET_IN_BYTES / s->s_blocksize) + 1; /* first of bitmap blocks */ SB_AP_BITMAP (s)[0] = reiserfs_bread (s->s_dev, bmp, s->s_blocksize); if(!SB_AP_BITMAP(s)[0]) return 1; for (i = 1, bmp = dl = rs->s_blocksize * 8; i < le16_to_cpu (rs->s_bmap_nr); i ++) { SB_AP_BITMAP (s)[i] = reiserfs_bread (s->s_dev, bmp, s->s_blocksize); if (!SB_AP_BITMAP (s)[i]) return 1; bmp += dl; } return 0; } static int read_old_bitmaps (struct super_block * s) { int i ; struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK(s); int bmp1 = (REISERFS_OLD_DISK_OFFSET_IN_BYTES / s->s_blocksize) + 1; /* first of bitmap blocks */ /* read true bitmap */ SB_AP_BITMAP (s) = reiserfs_kmalloc (sizeof (struct buffer_head *) * le16_to_cpu (rs->s_bmap_nr), GFP_BUFFER, s); if (SB_AP_BITMAP (s) == 0) return 1; memset (SB_AP_BITMAP (s), 0, sizeof (struct buffer_head *) * le16_to_cpu (rs->s_bmap_nr)); for (i = 0; i < le16_to_cpu (rs->s_bmap_nr); i ++) { SB_AP_BITMAP (s)[i] = reiserfs_bread (s->s_dev, bmp1 + i, s->s_blocksize); if (!SB_AP_BITMAP (s)[i]) return 1; } return 0; } void check_bitmap (struct super_block * s) { int i = 0; int free = 0; char * buf; while (i < SB_BLOCK_COUNT (s)) { buf = SB_AP_BITMAP (s)[i / (s->s_blocksize * 8)]->b_data; if (!reiserfs_test_le_bit (i % (s->s_blocksize * 8), buf)) free ++; i ++; } if (free != SB_FREE_BLOCKS (s)) reiserfs_warning ("vs-4000: check_bitmap: %d free blocks, must be %d\n", free, SB_FREE_BLOCKS (s)); } #ifdef SUPPORT_OLD_FORMAT /* support old disk layout */ static int read_old_super_block (struct super_block * s, int size) { struct buffer_head * bh; struct reiserfs_super_block * rs; printk("read_old_super_block: try to find super block in old location\n"); /* there are only 4k-sized blocks in v3.5.10 */ if (size != REISERFS_OLD_BLOCKSIZE) set_blocksize(s->s_dev, REISERFS_OLD_BLOCKSIZE); bh = bread (s->s_dev, REISERFS_OLD_DISK_OFFSET_IN_BYTES / REISERFS_OLD_BLOCKSIZE, REISERFS_OLD_BLOCKSIZE); if (!bh) { printk("read_old_super_block: unable to read superblock on dev %s\n", kdevname(s->s_dev)); return 1; } rs = (struct reiserfs_super_block *)bh->b_data; if (strncmp (rs->s_magic, REISERFS_SUPER_MAGIC_STRING, strlen ( REISERFS_SUPER_MAGIC_STRING))) { /* pre-journaling version check */ if(!strncmp((char*)rs + REISERFS_SUPER_MAGIC_STRING_OFFSET_NJ, REISERFS_SUPER_MAGIC_STRING, strlen(REISERFS_SUPER_MAGIC_STRING))) { printk("read_old_super_blockr: a pre-journaling reiserfs filesystem isn't suitable there.\n"); brelse(bh); return 1; } brelse (bh); printk ("read_old_super_block: can't find a reiserfs filesystem on dev %s.\n", kdevname(s->s_dev)); return 1; } if(REISERFS_OLD_BLOCKSIZE != le16_to_cpu (rs->s_blocksize)) { printk("read_old_super_block: blocksize mismatch, super block corrupted\n"); brelse(bh); return 1; } s->s_blocksize = REISERFS_OLD_BLOCKSIZE; s->s_blocksize_bits = 0; while ((1 << s->s_blocksize_bits) != s->s_blocksize) s->s_blocksize_bits ++; SB_BUFFER_WITH_SB (s) = bh; SB_DISK_SUPER_BLOCK (s) = rs; s->s_op = &reiserfs_sops; return 0; } #endif // // FIXME: mounting old filesystems we _must_ change magic string to // make then unmountable by reiserfs of 3.5.x // static int read_super_block (struct super_block * s, int size) { struct buffer_head * bh; struct reiserfs_super_block * rs; bh = bread (s->s_dev, REISERFS_DISK_OFFSET_IN_BYTES / size, size); if (!bh) { printk("read_super_block: unable to read superblock on dev %s\n", kdevname(s->s_dev)); return 1; } rs = (struct reiserfs_super_block *)bh->b_data; if (!is_reiserfs_magic_string (rs)) { printk ("read_super_block: can't find a reiserfs filesystem on dev %s\n", kdevname(s->s_dev)); brelse (bh); return 1; } // // ok, reiserfs signature (old or new) found in 64-th 1k block of // the device // #ifndef SUPPORT_OLD_FORMAT // with SUPPORT_OLD_FORMAT undefined - detect old format by // checking super block version if (le16_to_cpu (rs->s_version) != REISERFS_VERSION_2) { brelse (bh); printk ("read_super_block: unsupported version (%d) of reiserfs found on dev %s\n", le16_to_cpu (rs->s_version), kdevname(s->s_dev)); return 1; } #endif s->s_blocksize = le16_to_cpu (rs->s_blocksize); s->s_blocksize_bits = 0; while ((1 << s->s_blocksize_bits) != s->s_blocksize) s->s_blocksize_bits ++; brelse (bh); if (s->s_blocksize != size) set_blocksize (s->s_dev, s->s_blocksize); bh = reiserfs_bread (s->s_dev, REISERFS_DISK_OFFSET_IN_BYTES / s->s_blocksize, s->s_blocksize); if (!bh) { printk("read_super_block: unable to read superblock on dev %s\n", kdevname(s->s_dev)); return 1; } rs = (struct reiserfs_super_block *)bh->b_data; if (!is_reiserfs_magic_string (rs) || le16_to_cpu (rs->s_blocksize) != s->s_blocksize) { brelse (bh); printk ("read_super_block: can't find a reiserfs filesystem on dev %s.\n", kdevname(s->s_dev)); return 1; } /* must check to be sure we haven't pulled an old format super out ** of the old format's log. This is a kludge of a check, but it ** will work. If block we've just read in is inside the ** journal for that super, it can't be valid. */ if (bh->b_blocknr >= le32_to_cpu(rs->s_journal_block) && bh->b_blocknr < (le32_to_cpu(rs->s_journal_block) + JOURNAL_BLOCK_COUNT)) { brelse(bh) ; printk("super-459: read_super_block: super found at block %lu is within its own log. " "It must not be of this format type.\n", bh->b_blocknr) ; return 1 ; } SB_BUFFER_WITH_SB (s) = bh; SB_DISK_SUPER_BLOCK (s) = rs; s->s_op = &reiserfs_sops; s->s_maxbytes = 0xFFFFFFFF; /* 4Gig */ return 0; } /* after journal replay, reread all bitmap and super blocks */ static int reread_meta_blocks(struct super_block *s) { int i ; ll_rw_block(READ, 1, &(SB_BUFFER_WITH_SB(s))) ; wait_on_buffer(SB_BUFFER_WITH_SB(s)) ; if (!buffer_uptodate(SB_BUFFER_WITH_SB(s))) { printk("reread_meta_blocks, error reading the super\n") ; return 1 ; } for (i = 0; i < SB_BMAP_NR(s) ; i++) { ll_rw_block(READ, 1, &(SB_AP_BITMAP(s)[i])) ; wait_on_buffer(SB_AP_BITMAP(s)[i]) ; if (!buffer_uptodate(SB_AP_BITMAP(s)[i])) { printk("reread_meta_blocks, error reading bitmap block number %d at %ld\n", i, SB_AP_BITMAP(s)[i]->b_blocknr) ; return 1 ; } } return 0 ; } ///////////////////////////////////////////////////// // hash detection stuff // if root directory is empty - we set default - Yura's - hash and // warn about it // FIXME: we look for only one name in a directory. If tea and yura // bith have the same value - we ask user to send report to the // mailing list __u32 find_hash_out (struct super_block * s) { int retval; struct inode * inode; struct cpu_key key; INITIALIZE_PATH (path); struct reiserfs_dir_entry de; __u32 hash = DEFAULT_HASH; inode = s->s_root->d_inode; while (1) { make_cpu_key (&key, inode, ~0, TYPE_DIRENTRY, 3); retval = search_by_entry_key (s, &key, &path, &de); if (retval == IO_ERROR) { pathrelse (&path); return UNSET_HASH ; } if (retval == NAME_NOT_FOUND) de.de_entry_num --; set_de_name_and_namelen (&de); if (le32_to_cpu (de.de_deh[de.de_entry_num].deh_offset) == DOT_DOT_OFFSET) { /* allow override in this case */ if (reiserfs_rupasov_hash(s)) { hash = YURA_HASH ; } reiserfs_warning("reiserfs: FS seems to be empty, autodetect " "is using the default hash\n"); break; } if (GET_HASH_VALUE(yura_hash (de.de_name, de.de_namelen)) == GET_HASH_VALUE(keyed_hash (de.de_name, de.de_namelen))) { reiserfs_warning ("reiserfs: Could not detect hash function " "please mount with -o hash={tea,rupasov,r5}\n") ; hash = UNSET_HASH ; break; } if (GET_HASH_VALUE(le32_to_cpu(de.de_deh[de.de_entry_num].deh_offset))== GET_HASH_VALUE (yura_hash (de.de_name, de.de_namelen))) hash = YURA_HASH; else hash = TEA_HASH; break; } pathrelse (&path); return hash; } // finds out which hash names are sorted with static int what_hash (struct super_block * s) { __u32 code; code = le32_to_cpu (s->u.reiserfs_sb.s_rs->s_hash_function_code); /* reiserfs_hash_detect() == true if any of the hash mount options ** were used. We must check them to make sure the user isn't ** using a bad hash value */ if (code == UNSET_HASH || reiserfs_hash_detect(s)) code = find_hash_out (s); if (code != UNSET_HASH && reiserfs_hash_detect(s)) { /* detection has found the hash, and we must check against the ** mount options */ if (reiserfs_rupasov_hash(s) && code != YURA_HASH) { printk("REISERFS: Error, tea hash detected, " "unable to force rupasov hash\n") ; code = UNSET_HASH ; } else if (reiserfs_tea_hash(s) && code != TEA_HASH) { printk("REISERFS: Error, rupasov hash detected, " "unable to force tea hash\n") ; code = UNSET_HASH ; } else if (reiserfs_r5_hash(s) && code != R5_HASH) { printk("REISERFS: Error, r5 hash detected, " "unable to force r5 hash\n") ; code = UNSET_HASH ; } } else { /* find_hash_out was not called or could not determine the hash */ if (reiserfs_rupasov_hash(s)) { code = YURA_HASH ; } else if (reiserfs_tea_hash(s)) { code = TEA_HASH ; } else if (reiserfs_r5_hash(s)) { code = R5_HASH ; } } /* if we are mounted RW, and we have a new valid hash code, update ** the super */ if (code != UNSET_HASH && !(s->s_flags & MS_RDONLY) && code != le32_to_cpu (s->u.reiserfs_sb.s_rs->s_hash_function_code)) { s->u.reiserfs_sb.s_rs->s_hash_function_code = cpu_to_le32(code) ; } return code; } // return pointer to appropriate function static hashf_t hash_function (struct super_block * s) { switch (what_hash (s)) { case TEA_HASH: reiserfs_warning ("Using tea hash to sort names\n"); return keyed_hash; case YURA_HASH: reiserfs_warning ("Using rupasov hash to sort names\n"); return yura_hash; case R5_HASH: reiserfs_warning ("Using r5 hash to sort names\n"); return r5_hash; } return NULL; } // this is used to set up correct value for old partitions int function2code (hashf_t func) { if (func == keyed_hash) return TEA_HASH; if (func == yura_hash) return YURA_HASH; if (func == r5_hash) return R5_HASH; BUG() ; // should never happen return 0; } // // 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. // struct super_block * reiserfs_read_super (struct super_block * s, void * data, int silent) { int size; struct inode *root_inode; kdev_t dev = s->s_dev; int j; extern int *blksize_size[]; struct reiserfs_transaction_handle th ; int old_format = 0; unsigned long blocks; int jinit_done = 0 ; struct reiserfs_iget4_args args ; memset (&s->u.reiserfs_sb, 0, sizeof (struct reiserfs_sb_info)); if (parse_options ((char *) data, &(s->u.reiserfs_sb.s_mount_opt), &blocks) == 0) { return NULL; } if (blocks) { printk("reserfs: resize option for remount only\n"); return NULL; } if (blksize_size[MAJOR(dev)] && blksize_size[MAJOR(dev)][MINOR(dev)] != 0) { /* as blocksize is set for partition we use it */ size = blksize_size[MAJOR(dev)][MINOR(dev)]; } else { size = BLOCK_SIZE; set_blocksize (s->s_dev, BLOCK_SIZE); } /* read block (64-th 1k block), which can contain reiserfs super block */ if (read_super_block (s, size)) { #ifdef SUPPORT_OLD_FORMAT // try old format (undistributed bitmap, super block in 8-th 1k block of a device) if(read_old_super_block(s,size)) goto error; else old_format = 1; #endif goto error ; } s->u.reiserfs_sb.s_mount_state = le16_to_cpu (SB_DISK_SUPER_BLOCK (s)->s_state); /* journal victim */ s->u.reiserfs_sb.s_mount_state = REISERFS_VALID_FS ; if (old_format ? read_old_bitmaps(s) : read_bitmaps(s)) { printk ("reiserfs_read_super: unable to read bitmap\n"); goto error; } #ifdef CONFIG_REISERFS_CHECK printk("reiserfs:warning: CONFIG_REISERFS_CHECK is set ON\n"); printk("reiserfs:warning: - it is slow mode for debugging.\n"); #endif // set_device_ro(s->s_dev, 1) ; if (journal_init(s)) { printk("reiserfs_read_super: unable to initialize journal space\n") ; goto error ; } else { jinit_done = 1 ; /* once this is set, journal_release must be called ** if we error out of the mount */ } if (reread_meta_blocks(s)) { printk("reiserfs_read_super: unable to reread meta blocks after journal init\n") ; goto error ; } if (replay_only (s)) goto error; if (is_read_only(s->s_dev) && !(s->s_flags & MS_RDONLY)) { printk("clm-7000: Detected readonly device, marking FS readonly\n") ; s->s_flags |= MS_RDONLY ; } args.objectid = REISERFS_ROOT_PARENT_OBJECTID ; root_inode = iget4 (s, REISERFS_ROOT_OBJECTID, 0, (void *)(&args)); if (!root_inode) { printk ("reiserfs_read_super: get root inode failed\n"); goto error; } s->s_root = d_alloc_root(root_inode); if (!s->s_root) { iput(root_inode); goto error; } // define and initialize hash function s->u.reiserfs_sb.s_hash_function = hash_function (s); if (s->u.reiserfs_sb.s_hash_function == NULL) { dput(s->s_root) ; s->s_root = NULL ; goto error ; } if (!(s->s_flags & MS_RDONLY)) { struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK (s); journal_begin(&th, s, 1) ; reiserfs_prepare_for_journal(s, SB_BUFFER_WITH_SB(s), 1) ; rs->s_state = cpu_to_le16 (REISERFS_ERROR_FS); if (strncmp (rs->s_magic, REISER2FS_SUPER_MAGIC_STRING, strlen ( REISER2FS_SUPER_MAGIC_STRING))) { if (le16_to_cpu(rs->s_version) != 0) BUG (); // filesystem created under 3.5.x found if (!old_format_only (s)) { reiserfs_warning("reiserfs: converting 3.5.x filesystem to the new format\n") ; // after this 3.5.x will not be able to mount this partition memcpy (rs->s_magic, REISER2FS_SUPER_MAGIC_STRING, sizeof (REISER2FS_SUPER_MAGIC_STRING)); reiserfs_convert_objectid_map_v1(s) ; } else { reiserfs_warning("reiserfs: using 3.5.x disk format\n") ; } } else { // new format found set_bit (REISERFS_CONVERT, &(s->u.reiserfs_sb.s_mount_opt)); } // mark hash in super block: it could be unset. overwrite should be ok rs->s_hash_function_code = cpu_to_le32 (function2code (s->u.reiserfs_sb.s_hash_function)); journal_mark_dirty(&th, s, SB_BUFFER_WITH_SB (s)); journal_end(&th, s, 1) ; s->s_dirt = 0; } else { struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK (s); if (strncmp (rs->s_magic, REISER2FS_SUPER_MAGIC_STRING, strlen ( REISER2FS_SUPER_MAGIC_STRING))) { reiserfs_warning("reiserfs: using 3.5.x disk format\n") ; } } init_waitqueue_head (&(s->u.reiserfs_sb.s_wait)); printk("%s\n", reiserfs_get_version_string()) ; return s; error: if (jinit_done) { /* kill the commit thread, free journal ram */ journal_release_error(NULL, s) ; } if (SB_DISK_SUPER_BLOCK (s)) { for (j = 0; j < SB_BMAP_NR (s); j ++) { if (SB_AP_BITMAP (s)) brelse (SB_AP_BITMAP (s)[j]); } if (SB_AP_BITMAP (s)) reiserfs_kfree (SB_AP_BITMAP (s), sizeof (struct buffer_head *) * SB_BMAP_NR (s), s); } if (SB_BUFFER_WITH_SB (s)) brelse(SB_BUFFER_WITH_SB (s)); return NULL; } // // 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. // int reiserfs_statfs (struct super_block * s, struct statfs * buf) { struct reiserfs_super_block * rs = SB_DISK_SUPER_BLOCK (s); /* changed to accomodate gcc folks.*/ buf->f_type = REISERFS_SUPER_MAGIC; buf->f_bsize = le32_to_cpu (s->s_blocksize); buf->f_blocks = le32_to_cpu (rs->s_block_count) - le16_to_cpu (rs->s_bmap_nr) - 1; buf->f_bfree = le32_to_cpu (rs->s_free_blocks); buf->f_bavail = buf->f_bfree; buf->f_files = -1; buf->f_ffree = -1; buf->f_namelen = (REISERFS_MAX_NAME_LEN (s->s_blocksize)); return 0; } #ifdef __KERNEL__ static DECLARE_FSTYPE_DEV(reiserfs_fs_type,"reiserfs",reiserfs_read_super); // // this is exactly what 2.3.99-pre9's init_ext2_fs is // static int __init init_reiserfs_fs (void) { return register_filesystem(&reiserfs_fs_type); } EXPORT_NO_SYMBOLS; // // this is exactly what 2.3.99-pre9's init_ext2_fs is // static void __exit exit_reiserfs_fs(void) { unregister_filesystem(&reiserfs_fs_type); } module_init(init_reiserfs_fs) ; module_exit(exit_reiserfs_fs) ; #endif