/* add new name into a directory. If it exists in a directory - do
   nothing */
int reiserfs_add_entry (reiserfs_filsys_t fs, struct key * dir, char * name,
			 struct key * key, int fsck_need)
{
    struct item_head entry_ih = {{0,}, };
    char * entry;
    int retval;
    INITIALIZE_PATH(path);
    int gen_counter;
    int item_len;
    __u32 hash;

    if (reiserfs_find_entry (fs, dir, name, &gen_counter))
	return 0;

    /* compose entry key to look for its place in the tree */
    entry_ih.ih_key.k_dir_id = cpu_to_le32 (dir->k_dir_id);
    entry_ih.ih_key.k_objectid = cpu_to_le32 (dir->k_objectid);
    hash = hash_value (fs, name) + gen_counter;
    if (!strcmp (name, "."))
	hash = DOT_OFFSET;
    if (!strcmp (name, ".."))
	hash = DOT_DOT_OFFSET;
    set_type_and_offset (KEY_FORMAT_1, &(entry_ih.ih_key),
			 hash, TYPE_DIRENTRY);
    set_ih_key_format (&entry_ih, KEY_FORMAT_1);
    set_entry_count (&entry_ih, 1);
    if (SB_VERSION (fs) == REISERFS_VERSION_2)
	item_len = DEH_SIZE + ROUND_UP (strlen (name));
    else
	item_len = DEH_SIZE + strlen (name);
    set_ih_item_len (&entry_ih, item_len);

    /* fsck may need to insert item which was not reached yet */
    set_ih_fsck_need( &entry_ih, fsck_need );

    entry = make_entry (0, name, key, get_offset (&(entry_ih.ih_key)));

    retval = _search_by_entry_key (fs, &(entry_ih.ih_key), &path);
    switch (retval) {
    case POSITION_NOT_FOUND:
	reiserfs_paste_into_item (fs, &path, entry, item_len);
	break;

    case DIRECTORY_NOT_FOUND:
        set_deh_location( (struct reiserfs_de_head *)entry, DEH_SIZE );
	reiserfs_insert_item (fs, &path, &entry_ih, entry);
	break;

    default:
	reiserfs_panic ("reiserfs_add_entry: looking for %k (inserting name \"%s\") "
			"search_by_entry_key returned %d",
			&(entry_ih.ih_key), name, retval);
    }

    freemem (entry);
    return item_len;
}
Beispiel #2
0
/* check directory item and try to recover something */
static int verify_directory_item (reiserfs_filsys_t fs, struct buffer_head * bh,
				  int item_num)
{
    struct item_head * ih;
    struct item_head tmp;
    char * item;
    struct reiserfs_de_head * deh;
    char * name;
    int name_len;
    int bad;
    int i, j;
#if 0
    int bad_entries; /* how many bad neighboring entries */
    int total_entry_len;
    char * entries, * end;
#endif
    int dirty;
    int entry_count;
    int hash_code;
    int bad_locations;

#ifdef DEBUG_VERIFY_DENTRY
    char * direntries;
#endif


    ih = B_N_PITEM_HEAD (bh, item_num);
    item = B_I_PITEM (bh,ih);
    deh = (struct reiserfs_de_head *)item;

    dirty = 0;
    bad_locations = 0;
    entry_count = ih_entry_count (ih);


    /* check deh_location */
    for (i = 0; i < ih_entry_count (ih); i ++) {
	/* silently fix deh_state */
	if (deh [i].deh_state != (1 << DEH_Visible)) {
	    deh [i].deh_state = cpu_to_le16 (1 << DEH_Visible);
	    mark_buffer_dirty (bh);
	}
	if (dir_entry_bad_location (deh + i, ih, !i))
	    mark_de_bad_location (deh + i);
    }

#ifdef DEBUG_VERIFY_DENTRY
    direntries = getmem (ih_entry_count (ih) * sizeof (int));

    printf ("entries with bad locations: ");
    for (i = 0; i < ih_entry_count (ih); i ++) {
	if (de_bad_location (deh + i))
	    printf ("%d ", i);
    }
    printf ("\n");
#endif /* DEBUG_VERIFY_DENTRY */


    /* find entries names in which have mismatching deh_offset */
    for (i = ih_entry_count (ih) - 1; i >= 0; i --) {
	if (de_bad (deh + i))
	    /* bad location */
	    continue;

	if (i) {
	    if (deh_location (deh + i - 1) < deh_location (deh + i))
		mark_de_bad_location (deh + i - 1);
	}

	name = name_in_entry (deh + i, i);
	/* we found a name, but we not always we can get its length as
           it depends on deh_location of previous entry */
	name_len = try_to_get_name_length (ih, deh + i, i);

#ifdef DEBUG_VERIFY_DENTRY
	if (name_len == 0)
	    printf ("trying to find name length for %d-th entry\n", i);
#endif /* DEBUG_VERIFY_DENTRY */
	if (is_dot (name, name_len)) {
	    if (i != 0)
		fsck_log ("block %lu: item %d: \".\" is %d-th entry\n",
			  bh->b_blocknr, item_num, i);
	    /* check and fix "." */
	    
	    if (deh_offset (deh + i) != DOT_OFFSET) {
		set_deh_offset(&(deh[i]), DOT_OFFSET);
		mark_buffer_dirty (bh);
	    }
	    /* "." must point to the directory it is in */
	    if (not_of_one_file (&(deh[i].deh_dir_id), &(ih->ih_key))) { /* endian safe */
		fsck_log ("verify_direntry: block %lu, item %H has entry \".\" "
			  "pointing to (%K) instead of (%K)\n", 
			  bh->b_blocknr, ih,
			  &(deh[i].deh_dir_id), &(ih->ih_key));
		deh[i].deh_dir_id = ih->ih_key.k_dir_id; /* both LE */
		deh[i].deh_objectid = ih->ih_key.k_objectid; /* both LE */
		mark_buffer_dirty (bh);
	    }
	} else if (is_dot_dot (name, name_len)) {
	    if (i != 1)
		fsck_log ("block %lu: item %d: \"..\" is %d-th entry\n",
			  bh->b_blocknr, item_num, i);
	    
	    /* check and fix ".." */
	    if (deh_offset (deh + i) != DOT_DOT_OFFSET)
		set_deh_offset(&(deh[i]), DOT_DOT_OFFSET);
	} else {
	    int min_length, max_length;

	    /* check other name */

	    if (name_len == 0) {
		/* we do not know the length of name - we will try to find it */
		min_length = 1;
		max_length = item + ih_item_len (ih) - name;
	    } else
		/* we kow name length, so we will try only one name length */
		min_length = max_length = name_len;

	    for (j = min_length; j <= max_length; j ++) {
		hash_code = find_hash_in_use (name, j,
					      GET_HASH_VALUE (deh_offset (deh + i)),
					      rs_hash (fs->s_rs));
		add_hash_hit (fs, hash_code);
		if (code2func (hash_code) != 0) {
		    /* deh_offset matches to some hash of the name */
		    if (!name_len) {
			fsck_log ("pass0: block %lu, item %H: entry %d. found a name \"%.*s\" "
				  "matching to deh_offset %u. FIXME: should set deh_location "
				  "of previous entry (not ready)\n",
				  bh->b_blocknr, ih, i, j, name, deh_offset (deh + i));
			/* FIXME: if next byte is 0 we think that the name is aligned to 8 byte boundary */
			if (i) {
			    set_deh_location( &(deh[i - 1]),
                                deh_location (deh + i) +
                                ((name[j] || SB_VERSION (fs) ==
                                REISERFS_VERSION_1) ? j : ROUND_UP (j)));
			    mark_de_good_location (deh + i - 1);
			    mark_buffer_dirty (bh);
			}
		    }
		    break;
		}
	    }
	    if (j == max_length + 1) {
		/* deh_offset does not match to anything. it will be
		   deleted for now, but maybe we could just fix a
		   deh_offset if it is in ordeer */
		mark_de_bad_offset (deh + i);
	    }
	}
    } /* for */



#if 0
    /* find entries names in which have mismatching deh_offset */
    for (i = 0; i < ih_entry_count (ih); i ++) {
	if (de_bad (deh + i))
	    /* bad location */
	    continue;

	name = name_in_entry (deh + i, i);
	/* we found a name, but we not always we can get its length as
           it depends on deh_location of previous entry */
	name_len = try_to_get_name_length (ih, deh + i, i);

	if (i == 0 && is_dot (name, name_len)) {
	    
	    /* check and fix "." */
	    
	    if (deh_offset (deh + i) != DOT_OFFSET) {
		deh[i].deh_offset = cpu_to_le32 (DOT_OFFSET);
	    }
	    /* "." must point to the directory it is in */
	    if (not_of_one_file (&(deh[i].deh_dir_id), &(ih->ih_key))) {
		fsck_log ("verify_direntry: block %lu, item %H has entry \".\" "
			  "pointing to (%K) instead of (%K)\n", 
			  bh->b_blocknr, ih,
			  &(deh[i].deh_dir_id), &(ih->ih_key));
		deh[i].deh_dir_id = ih->ih_key.k_dir_id; /* both 32 bit LE */
		deh[i].deh_objectid = ih->ih_key.k_objectid; /* both 32 bit LE */
		mark_buffer_dirty (bh);
	    }
	} else if (i == 1 && is_dot_dot (name, name_len)) {
	    
	    /* check and fix ".." */

	    if (deh_offset (deh + i) != DOT_DOT_OFFSET)
		deh[i].deh_offset = cpu_to_le32 (DOT_DOT_OFFSET);
	} else {
	    int min_length, max_length;

	    /* check other name */

	    if (name_len == 0) {
		/* we do not know the length of name - we will try to find it */
		min_length = 1;
		max_length = item + ih_item_len (ih) - name;
	    } else
		/* we kow name length, so we will try only one name length */
		min_length = max_length = name_len;

	    for (j = min_length; j <= max_length; j ++) {
		hash_code = find_hash_in_use (name, j,
					      GET_HASH_VALUE (deh_offset (deh + i)),
					      rs_hash (fs->s_rs));
		add_hash_hit (fs, hash_code);
		if (code2func (hash_code) != 0) {
		    /* deh_offset matches to some hash of the name */
		    if (!name_len) {
			fsck_log ("pass0: block %lu, item %H: entry %d. found a name \"%.*s\" "
				  "matching to deh_offset %u. FIXME: should set deh_location "
				  "of previous entry (not ready)\n",
				  bh->b_blocknr, ih, i, j, name, deh_offset (deh + i));
			/* FIXME: if next byte is 0 we think that the name is aligned to 8 byte boundary */
			deh[i - 1].deh_location = cpu_to_le16 (deh_location (deh + i) +
							       ((name[j] || SB_VERSION (fs) == REISERFS_VERSION_1) ? j : ROUND_UP (j)));
		    }
		    break;
		}
	    }
	    if (j == max_length + 1) {
		/* deh_offset does not match to anything. it will be
		   deleted for now, but maybe we could just fix a
		   deh_offset if it is in ordeer */
		mark_de_bad_offset (deh + i);
	    }
	}
   }
 #endif

 #ifdef DEBUG_VERIFY_DENTRY
     printf ("entries with mismatching deh_offsets: ");
     for (i = 0; i < ih_entry_count (ih); i ++) {
       if (de_bad_offset (deh + i))
           printf ("%d ", i);
     }
     printf ("\n");
 #endif /* DEBUG_VERIFY_DENTRY */


     /* correct deh_locations such that code cutting entries will not get
        screwed up */
     {
       int prev_loc;
       int loc_fixed;


       prev_loc = ih_item_len (ih);
       for (i = 0; i < ih_entry_count (ih); i ++) {
           loc_fixed = 0;
           if (de_bad_location (deh + i)) {
               set_deh_location(&(deh[i]), prev_loc/* - 1*/);
               mark_buffer_dirty (bh);
               loc_fixed = 1;
           } else {
               if (deh_location (deh + i) >= prev_loc) {
                   set_deh_location(&(deh[i]), prev_loc/* - 1*/);
                   mark_buffer_dirty (bh);
                   loc_fixed = 1;
               }
           }

           prev_loc = deh_location (deh + i);

           if (i == ih_entry_count (ih) - 1) {
               /* last entry starts right after an array of dir entry headers */
               if (!de_bad (deh + i) &&
                   deh_location (deh + i) != (DEH_SIZE * ih_entry_count (ih))) {

                   /* free space in the directory item */
                   fsck_log ("verify_direntry: block %lu, item %H has free
pace\n",
                             bh->b_blocknr, ih);
                   cut_entry (fs, bh, item_num, ih_entry_count (ih), 0);
               }
               if (deh_location (deh + i) != (DEH_SIZE * ih_entry_count (ih)))
               {

                   set_deh_location(&(deh[i]), DEH_SIZE * ih_entry_count (ih));
                   loc_fixed = 1;
                   mark_buffer_dirty (bh);
               }
           }

 #ifdef DEBUG_VERIFY_DENTRY
           if (loc_fixed)
               direntries [i] = 1;
 #endif
       } /* for */

 #ifdef DEBUG_VERIFY_DENTRY
       printf ("entries with fixed deh_locations: ");
       for (i = 0; i < ih_entry_count (ih); i ++) {
           if (direntries [i])
               printf ("%d ", i);
       }
       printf ("\n");
 #endif /* DEBUG_VERIFY_DENTRY */

     }

 #ifdef DEBUG_VERIFY_DENTRY
     printf (" N  location name\n");
     for (i = 0; i < ih_entry_count (ih); i ++) {
       if (de_bad (deh + i) ||
           (i && de_bad (deh + i - 1)) || /* previous entry marked bad */
           (i < ih_entry_count (ih) - 1 && de_bad (deh + i + 1))) { /* next
ntry is marked bad */
           /* print only entries to be deleted and their nearest neighbors */
           printf ("%3d: %8d ", i, deh_location (deh + i));
           if (de_bad (deh + i))
               printf ("will be deleted\n");
           else
               printf ("\"%.*s\"\n", name_length (ih, deh + i, i),
                       name_in_entry (deh + i, i));
       }
     }
 #endif

     bad = 0;
     tmp = *ih;

     /* delete entries which are marked bad */
     for (i = 0; i < ih_entry_count (ih); i ++) {
       deh = B_I_DEH (bh, ih) + i;
       if (de_bad (deh)) {
           bad ++;
           if (ih_entry_count (ih) == 1) {
               delete_item (fs, bh, item_num);
               break;
           } else {
               cut_entry (fs, bh, item_num, i, 1);
           }
	   i --;
	}
    }
    
    if (bad == ih_entry_count (&tmp)) {
	fsck_log ("pass0: block %lu, item %H - all entries were deleted\n", bh->b_blocknr, &tmp);
	return 0;
    }

    deh = B_I_DEH (bh, ih);
    if (get_offset (&ih->ih_key) != deh_offset (deh)) {
	fsck_log ("verify_direntry: block %lu, item %H:  k_offset and deh_offset %u mismatched\n",
		  bh->b_blocknr, ih, deh_offset (deh));
	set_offset (KEY_FORMAT_1, &ih->ih_key, deh_offset (deh));
	mark_buffer_dirty (bh);
    }
    
    if (bad)
	fsck_log ("pass0: block %lu, item %H: %d entries were deleted of \n",
		  bh->b_blocknr, &tmp, bad);
	
    return 0;

#if 0

    /* FIXME: temporary */
    if (bad_locations > ih_entry_count (ih) / 2) {
	fsck_log ("pass0: block %u: item %d (%H) had too bad directory - deleted\n",
		  bh->b_blocknr, item_num, ih);
	delete_item (fs, bh, item_num);
	return 0;
    }

    if (!dirty)
	return 0;
    
    /* something is broken */

    fsck_log ("pass0: block %lu: %d-th item (%H) has %d bad entries..",
	      bh->b_blocknr, item_num, ih, dirty);

    if (get_offset (&ih->ih_key) == DOT_OFFSET) {
	/* first item of directory - make sure that "." and ".." are in place */
	if (deh_offset (deh) != DOT_OFFSET || name_in_entry (deh, 0)[0] != '.') {
	    set_deh_offset(deh, DOT_OFFSET);
	    name_in_entry (deh, 0)[0] = '.';
	}
	if (deh_offset (deh + 1) != DOT_DOT_OFFSET ||
	    name_in_entry (deh + 1, 1)[0] != '.' || name_in_entry (deh + 1, 1)[1] != '.') {
	    set_deh_offset((deh + 1), DOT_DOT_OFFSET);
	    name_in_entry (deh + 1, 1)[0] = '.';
	    name_in_entry (deh + 1, 1)[1] = '.';
	}
    }

    end = item + ih_item_len (ih);
    deh += ih_entry_count (ih);
    entries = (char *)deh;
    total_entry_len = ih_item_len (ih) - DEH_SIZE * ih_entry_count (ih);
    i = ih_entry_count (ih);

    bad_entries = 0;
    do {
	i --;
	deh --;
	name_len = prob_name (fs, &entries, total_entry_len, deh_offset (deh));
	if (!name_len) {
	    if (!bad_entries) {
                set_deh_location(deh, entries - item);
	    } else {
                set_deh_location(deh, deh_location((deh + 1)) + 1 );
	    }
	    bad_entries ++;
	    
	    /*fsck_log ("verify_directory_item: entry %d: in string \'%s\' there is no substring matching hash %ld\n",
	      i, bad_name (entries, total_entry_len), masked_offset);*/
	    mark_de_bad (deh);
	    continue;
	}
	bad_entries = 0;
	/*fsck_log ("verify_directory_item: entry %d: found \"%s\" name matching hash %ld\n",
	  i, bad_name (entries, name_len), masked_offset);*/
	
	/* 'entries' points now to the name which match given offset -
           so, set deh_location */
        set_deh_location(deh, entries - item);
	deh->deh_state = 0;
	mark_de_visible (deh);
	
	entries += name_len;
	total_entry_len = end - entries;
	/* skip padding zeros */
	while (!*entries) {
	    entries ++;
	    total_entry_len --;
	}
	/* 'entries' points now at the place where next (previous)
           entry should start */
    } while ((char *)deh != item);
    
    
    /* fixme: this will not work if all entries are to be deleted */
    for (i = 0; i < ih_entry_count (ih); i ++, deh ++) {
	deh = (struct reiserfs_de_head *)B_I_PITEM (bh, ih) + i;
	if (de_bad (deh)) {
	    if (ih_entry_count (ih) == 1) {
		delete_item (fs, bh, i);
		break;
	    } else {
		cut_entry (fs, bh, item_num, i);
	    }
	    i --;
	}
/*
  fsck_log ("verify_directory_item: %d-th entry is to be deleted: "
  "\"%s\" does not match to hash %lu\n", 
  i, bad_name (name_in_entry (deh, i), name_length (ih, deh, i)),
  deh_offset (deh));
*/
    }
    
    fsck_log ("%d entries were deleted\n", entry_count - ih_entry_count (ih));
    mark_buffer_dirty (bh);

    
    return 0;

#endif
}
Beispiel #3
0
/*
 * Common code for mount and mountroot
 */ 
static int
reiserfs_mountfs(struct vnode *devvp, struct mount *mp, struct thread *td)
{
	int error, old_format = 0;
	struct reiserfs_mount *rmp;
	struct reiserfs_sb_info *sbi;
	struct reiserfs_super_block *rs;
	struct cdev *dev;

	struct g_consumer *cp;
	struct bufobj *bo;

	//ronly = (mp->mnt_flag & MNT_RDONLY) != 0;

	dev = devvp->v_rdev;
	dev_ref(dev);
	DROP_GIANT();
	g_topology_lock();
	error = g_vfs_open(devvp, &cp, "reiserfs", /* read-only */ 0);
	g_topology_unlock();
	PICKUP_GIANT();
	VOP_UNLOCK(devvp, 0);
	if (error) {
		dev_rel(dev);
		return (error);
	}

	bo = &devvp->v_bufobj;
	bo->bo_private = cp;
	bo->bo_ops = g_vfs_bufops;

	if (devvp->v_rdev->si_iosize_max != 0)
		mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max;
	if (mp->mnt_iosize_max > MAXPHYS)
		mp->mnt_iosize_max = MAXPHYS;

	rmp = NULL;
	sbi = NULL;

	/* rmp contains any information about this specific mount */
	rmp = malloc(sizeof *rmp, M_REISERFSMNT, M_WAITOK | M_ZERO);
	if (!rmp) {
		error = (ENOMEM);
		goto out;
	}
	sbi = malloc(sizeof *sbi, M_REISERFSMNT, M_WAITOK | M_ZERO);
	if (!sbi) {
		error = (ENOMEM);
		goto out;
	}
	rmp->rm_reiserfs = sbi;
	rmp->rm_mountp   = mp;
	rmp->rm_devvp    = devvp;
	rmp->rm_dev      = dev;
	rmp->rm_bo       = &devvp->v_bufobj;
	rmp->rm_cp       = cp;

	/* Set default values for options: non-aggressive tails */
	REISERFS_SB(sbi)->s_mount_opt = (1 << REISERFS_SMALLTAIL);
	REISERFS_SB(sbi)->s_rd_only   = 1;
	REISERFS_SB(sbi)->s_devvp     = devvp;

	/* Read the super block */
	if ((error = read_super_block(rmp, REISERFS_OLD_DISK_OFFSET)) == 0) {
		/* The read process succeeded, it's an old format */
		old_format = 1;
	} else if ((error = read_super_block(rmp, REISERFS_DISK_OFFSET)) != 0) {
		reiserfs_log(LOG_ERR, "can not find a ReiserFS filesystem\n");
		goto out;
	}

	rs = SB_DISK_SUPER_BLOCK(sbi);

	/*
	 * Let's do basic sanity check to verify that underlying device is
	 * not smaller than the filesystem. If the check fails then abort and
	 * scream, because bad stuff will happen otherwise.
	 */
#if 0
	if (s->s_bdev && s->s_bdev->bd_inode &&
	    i_size_read(s->s_bdev->bd_inode) <
	    sb_block_count(rs) * sb_blocksize(rs)) {
		reiserfs_log(LOG_ERR,
		    "reiserfs: filesystem cannot be mounted because it is "
		    "bigger than the device.\n");
		reiserfs_log(LOG_ERR, "reiserfs: you may need to run fsck "
		    "rr may be you forgot to reboot after fdisk when it "
		    "told you to.\n");
		goto out;
	}
#endif

	/*
	 * XXX This is from the original Linux code, but why affecting 2 values
	 * to the same variable?
	 */
	sbi->s_mount_state = SB_REISERFS_STATE(sbi);
	sbi->s_mount_state = REISERFS_VALID_FS;

	if ((error = (old_format ?
	    read_old_bitmaps(rmp) : read_bitmaps(rmp)))) {
		reiserfs_log(LOG_ERR, "unable to read bitmap\n");
		goto out;
	}

	/* Make data=ordered the default */
	if (!reiserfs_data_log(sbi) && !reiserfs_data_ordered(sbi) &&
	    !reiserfs_data_writeback(sbi)) {
		REISERFS_SB(sbi)->s_mount_opt |= (1 << REISERFS_DATA_ORDERED);
	}

	if (reiserfs_data_log(sbi)) {
		reiserfs_log(LOG_INFO, "using journaled data mode\n");
	} else if (reiserfs_data_ordered(sbi)) {
		reiserfs_log(LOG_INFO, "using ordered data mode\n");
	} else {
		reiserfs_log(LOG_INFO, "using writeback data mode\n");
	}

	/* TODO Not yet supported */
#if 0
	if(journal_init(sbi, jdev_name, old_format, commit_max_age)) {
		reiserfs_log(LOG_ERR, "unable to initialize journal space\n");
		goto out;
	} else {
		jinit_done = 1 ; /* once this is set, journal_release must
				    be called if we error out of the mount */
	}

	if (reread_meta_blocks(sbi)) {
		reiserfs_log(LOG_ERR,
		    "unable to reread meta blocks after journal init\n");
		goto out;
	}
#endif

	/* Define and initialize hash function */
	sbi->s_hash_function = hash_function(rmp);

	if (sbi->s_hash_function == NULL) {
		reiserfs_log(LOG_ERR, "couldn't determined hash function\n");
		error = (EINVAL);
		goto out;
	}

	if (is_reiserfs_3_5(rs) ||
	    (is_reiserfs_jr(rs) && SB_VERSION(sbi) == REISERFS_VERSION_1))
		bit_set(&(sbi->s_properties), REISERFS_3_5);
	else
		bit_set(&(sbi->s_properties), REISERFS_3_6);

	mp->mnt_data = rmp;
	mp->mnt_stat.f_fsid.val[0] = dev2udev(dev);
	mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
	MNT_ILOCK(mp);
	mp->mnt_flag |= MNT_LOCAL;
	mp->mnt_kern_flag |= MNTK_MPSAFE;
	MNT_IUNLOCK(mp);
#if defined(si_mountpoint)
	devvp->v_rdev->si_mountpoint = mp;
#endif

	return (0);

out:
	reiserfs_log(LOG_INFO, "*** error during mount ***\n");
	if (sbi) {
		if (SB_AP_BITMAP(sbi)) {
			int i;
			for (i = 0; i < SB_BMAP_NR(sbi); i++) {
				if (!SB_AP_BITMAP(sbi)[i].bp_data)
					break;
				free(SB_AP_BITMAP(sbi)[i].bp_data,
				    M_REISERFSMNT);
			}
			free(SB_AP_BITMAP(sbi), M_REISERFSMNT);
		}

		if (sbi->s_rs) {
			free(sbi->s_rs, M_REISERFSMNT);
			sbi->s_rs = NULL;
		}
	}

	if (cp != NULL) {
		DROP_GIANT();
		g_topology_lock();
		g_vfs_close(cp);
		g_topology_unlock();
		PICKUP_GIANT();
	}

	if (sbi)
		free(sbi, M_REISERFSMNT);
	if (rmp)
		free(rmp, M_REISERFSMNT);
	dev_rel(dev);
	return (error);
}