static int get_root_node(struct reiserfs_mount *rmp, struct reiserfs_node **root) { struct reiserfs_node *ip; struct reiserfs_iget_args args; /* Allocate the node structure */ reiserfs_log(LOG_DEBUG, "malloc(struct reiserfs_node)\n"); ip = malloc(sizeof(struct reiserfs_node), M_REISERFSNODE, M_WAITOK | M_ZERO); /* Fill the structure */ reiserfs_log(LOG_DEBUG, "filling *ip\n"); ip->i_dev = rmp->rm_dev; ip->i_number = REISERFS_ROOT_OBJECTID; ip->i_ino = REISERFS_ROOT_PARENT_OBJECTID; ip->i_reiserfs = rmp->rm_reiserfs; /* Read the inode */ args.objectid = ip->i_number; args.dirid = ip->i_ino; reiserfs_log(LOG_DEBUG, "call reiserfs_read_locked_inode(" "objectid=%d,dirid=%d)\n", args.objectid, args.dirid); reiserfs_read_locked_inode(ip, &args); ip->i_devvp = rmp->rm_devvp; //XXX VREF(ip->i_devvp); Is it necessary ? *root = ip; return (0); }
/* Returns 1 if buf looks like an internal node, 0 otherwise */ static int is_internal(char *buf, int blocksize, struct buf *bp) { int nr, used_space; struct block_head *blkh; blkh = (struct block_head *)buf; nr = blkh_level(blkh); if (nr <= DISK_LEAF_NODE_LEVEL || nr > MAX_HEIGHT) { /* This level is not possible for internal nodes */ reiserfs_log(LOG_WARNING, "this should be caught earlier\n"); return (0); } nr = blkh_nr_item(blkh); if (nr > (blocksize - BLKH_SIZE - DC_SIZE) / (KEY_SIZE + DC_SIZE)) { /* * For internal which is not root we might check min * number of keys */ reiserfs_log(LOG_WARNING, "number of key seems wrong\n"); return (0); } used_space = BLKH_SIZE + KEY_SIZE * nr + DC_SIZE * (nr + 1); if (used_space != blocksize - blkh_free_space(blkh)) { reiserfs_log(LOG_WARNING, "is_internal: free space seems wrong\n"); return (0); } /* One may imagine much more checks */ return (1); }
/* * May return NAME_FOUND, NAME_FOUND_INVISIBLE, NAME_NOT_FOUND * FIXME: should add something like IOERROR */ static int reiserfs_find_entry(struct reiserfs_node *dp, const char *name, int namelen, struct path * path_to_entry, struct reiserfs_dir_entry *de) { struct cpu_key key_to_search; int retval; if (namelen > REISERFS_MAX_NAME(dp->i_reiserfs->s_blocksize)) return NAME_NOT_FOUND; /* We will search for this key in the tree */ make_cpu_key(&key_to_search, dp, get_third_component(dp->i_reiserfs, name, namelen), TYPE_DIRENTRY, 3); while (1) { reiserfs_log(LOG_DEBUG, "search by entry key\n"); retval = search_by_entry_key(dp->i_reiserfs, &key_to_search, path_to_entry, de); if (retval == IO_ERROR) { reiserfs_log(LOG_DEBUG, "IO error in %s\n", __FUNCTION__); return IO_ERROR; } /* Compare names for all entries having given hash value */ reiserfs_log(LOG_DEBUG, "linear search for `%s'\n", name); retval = linear_search_in_dir_item(&key_to_search, de, name, namelen); if (retval != GOTO_PREVIOUS_ITEM) { /* * There is no need to scan directory anymore. * Given entry found or does not exist */ reiserfs_log(LOG_DEBUG, "linear search returned " "(objectid=%d,dirid=%d)\n", de->de_objectid, de->de_dir_id); path_to_entry->pos_in_item = de->de_entry_num; return retval; } /* * There is left neighboring item of this directory and * given entry can be there */ set_cpu_key_k_offset(&key_to_search, le_ih_k_offset(de->de_ih) - 1); pathrelse(path_to_entry); } /* while (1) */ }
static int direntry_bytes_number(struct item_head *ih, int block_size) { reiserfs_log(LOG_WARNING, "bytes number is asked for direntry\n"); return (0); }
static int errcatch_bytes_number(struct item_head *ih, int block_size) { reiserfs_log(LOG_WARNING, "invalid item type observed, run fsck ASAP"); return (0); }
int reiserfs_check_path(struct path *p) { if (p->path_length != ILLEGAL_PATH_ELEMENT_OFFSET) reiserfs_log(LOG_WARNING, "path not properly relsed\n"); return (0); }
/* Return target name of a symbolic link */ static int reiserfs_readlink(struct vop_readlink_args *ap) { struct vnode *vp = ap->a_vp; reiserfs_log(LOG_DEBUG, "redirect to VOP_READ()\n"); return (VOP_READ(vp, ap->a_uio, 0, ap->a_cred)); }
/* * We assign a key to each directory item, and place multiple entries in * a single directory item. A directory item has a key equal to the key * of the first directory entry in it. * * This function first calls search_by_key, then, if item whose first * entry matches is not found it looks for the entry inside directory * item found by search_by_key. Fills the path to the entry, and to the * entry position in the item */ int search_by_entry_key(struct reiserfs_sb_info *sbi, const struct cpu_key *key, struct path *path, struct reiserfs_dir_entry *de) { int retval; reiserfs_log(LOG_DEBUG, "searching in (objectid=%d,dirid=%d)\n", key->on_disk_key.k_objectid, key->on_disk_key.k_dir_id); retval = search_item(sbi, key, path); switch (retval) { case ITEM_NOT_FOUND: if (!PATH_LAST_POSITION(path)) { reiserfs_log(LOG_DEBUG, "search_by_key returned item position == 0"); pathrelse(path); return (IO_ERROR); } PATH_LAST_POSITION(path)--; reiserfs_log(LOG_DEBUG, "search_by_key did not found it\n"); break; case ITEM_FOUND: reiserfs_log(LOG_DEBUG, "search_by_key found it\n"); break; case IO_ERROR: return (retval); default: pathrelse(path); reiserfs_log(LOG_DEBUG, "no path to here"); return (IO_ERROR); } reiserfs_log(LOG_DEBUG, "set item location\n"); set_de_item_location(de, path); /* * Binary search in directory item by third component of the * key. Sets de->de_entry_num of de */ reiserfs_log(LOG_DEBUG, "bin_search_in_dir_item\n"); retval = bin_search_in_dir_item(de, cpu_key_k_offset(key)); path->pos_in_item = de->de_entry_num; if (retval != NAME_NOT_FOUND) { /* * Ugly, but rename needs de_bp, de_deh, de_name, de_namelen, * de_objectid set */ set_de_name_and_namelen(de); set_de_object_key(de); reiserfs_log(LOG_DEBUG, "set (objectid=%d,dirid=%d)\n", de->de_objectid, de->de_dir_id); } return (retval); }
/* * File handle to vnode * * Have to be really careful about stale file handles: * - check that the inode key is valid * - call ffs_vget() to get the locked inode * - check for an unallocated inode (i_mode == 0) * - check that the given client host has export rights and return * those rights via. exflagsp and credanonp */ static int reiserfs_fhtovp(struct mount *mp, struct fid *fhp, int flags, struct vnode **vpp) { int error; struct rfid *rfhp; struct vnode *nvp; struct cpu_key key; struct reiserfs_node *ip; struct reiserfs_sb_info *sbi; struct thread *td = curthread; rfhp = (struct rfid *)fhp; sbi = VFSTOREISERFS(mp)->rm_reiserfs; /* Check that the key is valid */ if (rfhp->rfid_dirid < REISERFS_ROOT_PARENT_OBJECTID && rfhp->rfid_objectid < REISERFS_ROOT_OBJECTID) return (ESTALE); reiserfs_log(LOG_DEBUG, "file handle key is (dirid=%d, objectid=%d)\n", rfhp->rfid_dirid, rfhp->rfid_objectid); key.on_disk_key.k_dir_id = rfhp->rfid_dirid; key.on_disk_key.k_objectid = rfhp->rfid_objectid; reiserfs_log(LOG_DEBUG, "read this inode\n"); error = reiserfs_iget(mp, &key, &nvp, td); if (error) { *vpp = NULLVP; return (error); } reiserfs_log(LOG_DEBUG, "check validity\n"); ip = VTOI(nvp); if (ip->i_mode == 0 || ip->i_generation != rfhp->rfid_gen) { vput(nvp); *vpp = NULLVP; return (ESTALE); } reiserfs_log(LOG_DEBUG, "return it\n"); *vpp = nvp; return (0); }
/* Return pointer to appropriate function */ static hashf_t hash_function(struct reiserfs_mount *rmp) { switch (what_hash(rmp)) { case TEA_HASH: reiserfs_log(LOG_INFO, "using tea hash to sort names\n"); return (keyed_hash); case YURA_HASH: reiserfs_log(LOG_INFO, "using rupasov hash to sort names\n"); return (yura_hash); case R5_HASH: reiserfs_log(LOG_INFO, "using r5 hash to sort names\n"); return (r5_hash); } return (NULL); }
/* What entry points to */ static inline void set_de_object_key(struct reiserfs_dir_entry *de) { if (de->de_entry_num >= ih_entry_count(de->de_ih)) { reiserfs_log(LOG_DEBUG, "BUG\n"); return; } de->de_dir_id = deh_dir_id(&(de->de_deh[de->de_entry_num])); de->de_objectid = deh_objectid(&(de->de_deh[de->de_entry_num])); }
/* * Read the bitmaps */ static int read_bitmaps(struct reiserfs_mount *rmp) { int i, bmap_nr; struct buf *bp = NULL; struct reiserfs_sb_info *sbi = rmp->rm_reiserfs; /* Allocate memory for the table of bitmaps */ SB_AP_BITMAP(sbi) = malloc(sizeof(struct reiserfs_bitmap_info) * SB_BMAP_NR(sbi), M_REISERFSMNT, M_WAITOK | M_ZERO); if (!SB_AP_BITMAP(sbi)) return (ENOMEM); /* Read all the bitmaps */ for (i = 0, bmap_nr = (REISERFS_DISK_OFFSET_IN_BYTES / sbi->s_blocksize + 1) * btodb(sbi->s_blocksize); i < SB_BMAP_NR(sbi); i++, bmap_nr = sbi->s_blocksize * 8 * i) { SB_AP_BITMAP(sbi)[i].bp_data = malloc(sbi->s_blocksize, M_REISERFSMNT, M_WAITOK | M_ZERO); if (!SB_AP_BITMAP(sbi)[i].bp_data) return (ENOMEM); bread(rmp->rm_devvp, bmap_nr, sbi->s_blocksize, NOCRED, &bp); bcopy(bp->b_data, SB_AP_BITMAP(sbi)[i].bp_data, sbi->s_blocksize); brelse(bp); bp = NULL; /*if (!buffer_uptodate(SB_AP_BITMAP(s)[i].bh)) ll_rw_block(READ, 1, &SB_AP_BITMAP(s)[i].bh);*/ } for (i = 0; i < SB_BMAP_NR(sbi); i++) { /*if (!buffer_uptodate(SB_AP_BITMAP(s)[i].bh)) { reiserfs_warning(s,"sh-2029: reiserfs read_bitmaps: " "bitmap block (#%lu) reading failed", SB_AP_BITMAP(s)[i].bh->b_blocknr); for (i = 0; i < SB_BMAP_NR(s); i++) brelse(SB_AP_BITMAP(s)[i].bh); vfree(SB_AP_BITMAP(s)); SB_AP_BITMAP(s) = NULL; return 1; }*/ load_bitmap_info_data(sbi, SB_AP_BITMAP(sbi) + i); reiserfs_log(LOG_DEBUG, "%d free blocks (starting at block %ld)\n", SB_AP_BITMAP(sbi)[i].free_count, (long)SB_AP_BITMAP(sbi)[i].first_zero_hint); } return (0); }
static int reiserfs_access(struct vop_access_args *ap) { int error; struct vnode *vp = ap->a_vp; struct reiserfs_node *ip = VTOI(vp); accmode_t accmode = ap->a_accmode; /* * Disallow write attempts on read-only file systems; unless the file * is a socket, fifo, or a block or character device resident on the * file system. */ if (accmode & VWRITE) { switch (vp->v_type) { case VDIR: case VLNK: case VREG: if (vp->v_mount->mnt_flag & MNT_RDONLY) { reiserfs_log(LOG_DEBUG, "no write access (read-only fs)\n"); return (EROFS); } break; default: break; } } /* If immutable bit set, nobody gets to write it. */ if ((accmode & VWRITE) && (ip->i_flags & (IMMUTABLE | SF_SNAPSHOT))) { reiserfs_log(LOG_DEBUG, "no write access (immutable)\n"); return (EPERM); } error = vaccess(vp->v_type, ip->i_mode, ip->i_uid, ip->i_gid, ap->a_accmode, ap->a_cred, NULL); return (error); }
/* * Make sure that bh contains formatted node of reiserfs tree of * 'level'-th level */ static int is_tree_node(struct buf *bp, int level) { if (B_LEVEL(bp) != level) { reiserfs_log(LOG_WARNING, "node level (%d) doesn't match to the " "expected one (%d)\n", B_LEVEL (bp), level); return (0); } if (level == DISK_LEAF_NODE_LEVEL) return (is_leaf(bp->b_data, bp->b_bcount, bp)); return (is_internal(bp->b_data, bp->b_bcount, bp)); }
/* * de_bh, de_ih, de_deh (points to first element of array), de_item_num * is set */ void set_de_name_and_namelen(struct reiserfs_dir_entry *de) { struct reiserfs_de_head *deh = de->de_deh + de->de_entry_num; if (de->de_entry_num >= ih_entry_count(de->de_ih)) { reiserfs_log(LOG_DEBUG, "BUG\n"); return; } de->de_entrylen = entry_length(de->de_bp, de->de_ih, de->de_entry_num); de->de_namelen = de->de_entrylen - (de_with_sd(deh) ? SD_SIZE : 0); de->de_name = B_I_PITEM(de->de_bp, de->de_ih) + deh_location(deh); if (de->de_name[de->de_namelen - 1] == 0) de->de_namelen = strlen(de->de_name); }
static inline void store_de_entry_key(struct reiserfs_dir_entry *de) { struct reiserfs_de_head *deh = de->de_deh + de->de_entry_num; if (de->de_entry_num >= ih_entry_count(de->de_ih)) { reiserfs_log(LOG_DEBUG, "BUG\n"); return; } /* Store key of the found entry */ de->de_entry_key.version = KEY_FORMAT_3_5; de->de_entry_key.on_disk_key.k_dir_id = le32toh(de->de_ih->ih_key.k_dir_id); de->de_entry_key.on_disk_key.k_objectid = le32toh(de->de_ih->ih_key.k_objectid); set_cpu_key_k_offset(&(de->de_entry_key), deh_offset(deh)); set_cpu_key_k_type(&(de->de_entry_key), TYPE_DIRENTRY); }
/* The function is NOT SCHEDULE-SAFE! */ int search_for_position_by_key(struct reiserfs_sb_info *p_s_sbi, const struct cpu_key *p_cpu_key, /* Key to search (cpu variable) */ struct path *p_s_search_path) /* Filled up by this function. */ { int retval, n_blk_size; off_t item_offset, offset; struct item_head *p_le_ih; /* Pointer to on-disk structure */ struct reiserfs_dir_entry de; /* If searching for directory entry. */ if (is_direntry_cpu_key(p_cpu_key)) return (search_by_entry_key(p_s_sbi, p_cpu_key, p_s_search_path, &de)); /* If not searching for directory entry. */ /* If item is found. */ retval = search_item(p_s_sbi, p_cpu_key, p_s_search_path); if (retval == IO_ERROR) return (retval); if (retval == ITEM_FOUND) { if (ih_item_len(B_N_PITEM_HEAD( PATH_PLAST_BUFFER(p_s_search_path), PATH_LAST_POSITION(p_s_search_path))) == 0) { reiserfs_log(LOG_WARNING, "item length equals zero\n"); } pos_in_item(p_s_search_path) = 0; return (POSITION_FOUND); } if (PATH_LAST_POSITION(p_s_search_path) == 0) { reiserfs_log(LOG_WARNING, "position equals zero\n"); } /* Item is not found. Set path to the previous item. */ p_le_ih = B_N_PITEM_HEAD(PATH_PLAST_BUFFER(p_s_search_path), --PATH_LAST_POSITION(p_s_search_path)); n_blk_size = p_s_sbi->s_blocksize; if (comp_short_keys(&(p_le_ih->ih_key), p_cpu_key)) { return (FILE_NOT_FOUND); } item_offset = le_ih_k_offset(p_le_ih); offset = cpu_key_k_offset(p_cpu_key); /* Needed byte is contained in the item pointed to by the path.*/ if (item_offset <= offset && item_offset + op_bytes_number(p_le_ih, n_blk_size) > offset) { pos_in_item(p_s_search_path) = offset - item_offset; if (is_indirect_le_ih(p_le_ih)) { pos_in_item(p_s_search_path) /= n_blk_size; } return (POSITION_FOUND); } /* Needed byte is not contained in the item pointed to by the * path. Set pos_in_item out of the item. */ if (is_indirect_le_ih(p_le_ih)) pos_in_item(p_s_search_path) = ih_item_len(p_le_ih) / UNFM_P_SIZE; else pos_in_item(p_s_search_path) = ih_item_len(p_le_ih); return (POSITION_NOT_FOUND); }
int search_by_key(struct reiserfs_sb_info *p_s_sbi, const struct cpu_key * p_s_key, /* Key to search. */ struct path * p_s_search_path, /* This structure was allocated and initialized by the calling function. It is filled up by this function. */ int n_stop_level) /* How far down the tree to search. To stop at leaf level - set to DISK_LEAF_NODE_LEVEL */ { int error; int n_node_level, n_retval; int n_block_number, expected_level, fs_gen; struct path_element *p_s_last_element; struct buf *p_s_bp, *tmp_bp; /* * As we add each node to a path we increase its count. This means that * we must be careful to release all nodes in a path before we either * discard the path struct or re-use the path struct, as we do here. */ decrement_counters_in_path(p_s_search_path); /* * With each iteration of this loop we search through the items in the * current node, and calculate the next current node(next path element) * for the next iteration of this loop... */ n_block_number = SB_ROOT_BLOCK(p_s_sbi); expected_level = -1; reiserfs_log(LOG_DEBUG, "root block: #%d\n", n_block_number); while (1) { /* Prep path to have another element added to it. */ reiserfs_log(LOG_DEBUG, "path element #%d\n", p_s_search_path->path_length); p_s_last_element = PATH_OFFSET_PELEMENT(p_s_search_path, ++p_s_search_path->path_length); fs_gen = get_generation(p_s_sbi); /* * Read the next tree node, and set the last element in the * path to have a pointer to it. */ reiserfs_log(LOG_DEBUG, "reading block #%d\n", n_block_number); if ((error = bread(p_s_sbi->s_devvp, n_block_number * btodb(p_s_sbi->s_blocksize), p_s_sbi->s_blocksize, NOCRED, &tmp_bp)) != 0) { reiserfs_log(LOG_DEBUG, "error reading block\n"); p_s_search_path->path_length--; pathrelse(p_s_search_path); return (IO_ERROR); } reiserfs_log(LOG_DEBUG, "blkno = %ju, lblkno = %ju\n", (intmax_t)tmp_bp->b_blkno, (intmax_t)tmp_bp->b_lblkno); /* * As i didn't found a way to handle the lock correctly, * i copy the data into a fake buffer */ reiserfs_log(LOG_DEBUG, "allocating p_s_bp\n"); p_s_bp = malloc(sizeof *p_s_bp, M_REISERFSPATH, M_WAITOK); if (!p_s_bp) { reiserfs_log(LOG_DEBUG, "error allocating memory\n"); p_s_search_path->path_length--; pathrelse(p_s_search_path); brelse(tmp_bp); return (IO_ERROR); } reiserfs_log(LOG_DEBUG, "copying struct buf\n"); bcopy(tmp_bp, p_s_bp, sizeof(struct buf)); reiserfs_log(LOG_DEBUG, "allocating p_s_bp->b_data\n"); p_s_bp->b_data = malloc(p_s_sbi->s_blocksize, M_REISERFSPATH, M_WAITOK); if (!p_s_bp->b_data) { reiserfs_log(LOG_DEBUG, "error allocating memory\n"); p_s_search_path->path_length--; pathrelse(p_s_search_path); free(p_s_bp, M_REISERFSPATH); brelse(tmp_bp); return (IO_ERROR); } reiserfs_log(LOG_DEBUG, "copying buffer data\n"); bcopy(tmp_bp->b_data, p_s_bp->b_data, p_s_sbi->s_blocksize); brelse(tmp_bp); tmp_bp = NULL; reiserfs_log(LOG_DEBUG, "...done\n"); p_s_last_element->pe_buffer = p_s_bp; if (expected_level == -1) expected_level = SB_TREE_HEIGHT(p_s_sbi); expected_level--; reiserfs_log(LOG_DEBUG, "expected level: %d (%d)\n", expected_level, SB_TREE_HEIGHT(p_s_sbi)); /* XXX */ /* * It is possible that schedule occurred. We must check * whether the key to search is still in the tree rooted * from the current buffer. If not then repeat search * from the root. */ if (fs_changed(fs_gen, p_s_sbi) && (!B_IS_IN_TREE(p_s_bp) || B_LEVEL(p_s_bp) != expected_level || !key_in_buffer(p_s_search_path, p_s_key, p_s_sbi))) { reiserfs_log(LOG_DEBUG, "the key isn't in the tree anymore\n"); decrement_counters_in_path(p_s_search_path); /* * Get the root block number so that we can repeat * the search starting from the root. */ n_block_number = SB_ROOT_BLOCK(p_s_sbi); expected_level = -1; /* Repeat search from the root */ continue; } /* * Make sure, that the node contents look like a node of * certain level */ if (!is_tree_node(p_s_bp, expected_level)) { reiserfs_log(LOG_WARNING, "invalid format found in block %ju. Fsck?", (intmax_t)p_s_bp->b_blkno); pathrelse (p_s_search_path); return (IO_ERROR); } /* Ok, we have acquired next formatted node in the tree */ n_node_level = B_LEVEL(p_s_bp); reiserfs_log(LOG_DEBUG, "block info:\n"); reiserfs_log(LOG_DEBUG, " node level: %d\n", n_node_level); reiserfs_log(LOG_DEBUG, " nb of items: %d\n", B_NR_ITEMS(p_s_bp)); reiserfs_log(LOG_DEBUG, " free space: %d bytes\n", B_FREE_SPACE(p_s_bp)); reiserfs_log(LOG_DEBUG, "bin_search with :\n" " p_s_key = (objectid=%d, dirid=%d)\n" " B_NR_ITEMS(p_s_bp) = %d\n" " p_s_last_element->pe_position = %d (path_length = %d)\n", p_s_key->on_disk_key.k_objectid, p_s_key->on_disk_key.k_dir_id, B_NR_ITEMS(p_s_bp), p_s_last_element->pe_position, p_s_search_path->path_length); n_retval = bin_search(p_s_key, B_N_PITEM_HEAD(p_s_bp, 0), B_NR_ITEMS(p_s_bp), (n_node_level == DISK_LEAF_NODE_LEVEL) ? IH_SIZE : KEY_SIZE, &(p_s_last_element->pe_position)); reiserfs_log(LOG_DEBUG, "bin_search result: %d\n", n_retval); if (n_node_level == n_stop_level) { reiserfs_log(LOG_DEBUG, "stop level reached (%s)\n", n_retval == ITEM_FOUND ? "found" : "not found"); return (n_retval); } /* We are not in the stop level */ if (n_retval == ITEM_FOUND) /* * Item has been found, so we choose the pointer * which is to the right of the found one */ p_s_last_element->pe_position++; /* * If item was not found we choose the position which is * to the left of the found item. This requires no code, * bin_search did it already. */ /* * So we have chosen a position in the current node which * is an internal node. Now we calculate child block number * by position in the node. */ n_block_number = B_N_CHILD_NUM(p_s_bp, p_s_last_element->pe_position); } reiserfs_log(LOG_DEBUG, "done\n"); return (0); }
/* Finds out which hash names are sorted with */ static int what_hash(struct reiserfs_mount *rmp) { uint32_t code; struct reiserfs_sb_info *sbi = rmp->rm_reiserfs; find_hash_out(rmp); code = sb_hash_function_code(SB_DISK_SUPER_BLOCK(sbi)); /* * 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(sbi)) code = find_hash_out(rmp); if (code != UNSET_HASH && reiserfs_hash_detect(sbi)) { /* * Detection has found the hash, and we must check against * the mount options */ if (reiserfs_rupasov_hash(sbi) && code != YURA_HASH) { reiserfs_log(LOG_ERR, "error, %s hash detected, " "unable to force rupasov hash", reiserfs_hashname(code)); code = UNSET_HASH; } else if (reiserfs_tea_hash(sbi) && code != TEA_HASH) { reiserfs_log(LOG_ERR, "error, %s hash detected, " "unable to force tea hash", reiserfs_hashname(code)); code = UNSET_HASH; } else if (reiserfs_r5_hash(sbi) && code != R5_HASH) { reiserfs_log(LOG_ERR, "error, %s hash detected, " "unable to force r5 hash", reiserfs_hashname(code)); code = UNSET_HASH; } } else { /* * Find_hash_out was not called or could not determine * the hash */ if (reiserfs_rupasov_hash(sbi)) { code = YURA_HASH; } else if (reiserfs_tea_hash(sbi)) { code = TEA_HASH; } else if (reiserfs_r5_hash(sbi)) { code = R5_HASH; } } /* TODO Not supported yet */ #if 0 /* 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 != sb_hash_function_code(SB_DISK_SUPER_BLOCK(s))) { set_sb_hash_function_code(SB_DISK_SUPER_BLOCK(s), code); } #endif return (code); }
static int is_leaf(char *buf, int blocksize, struct buf *bp) { struct item_head *ih; struct block_head *blkh; int used_space, prev_location, i, nr; blkh = (struct block_head *)buf; if (blkh_level(blkh) != DISK_LEAF_NODE_LEVEL) { reiserfs_log(LOG_WARNING, "this should be caught earlier"); return (0); } nr = blkh_nr_item(blkh); if (nr < 1 || nr > ((blocksize - BLKH_SIZE) / (IH_SIZE + MIN_ITEM_LEN))) { /* Item number is too big or too small */ reiserfs_log(LOG_WARNING, "nr_item seems wrong\n"); return (0); } ih = (struct item_head *)(buf + BLKH_SIZE) + nr - 1; used_space = BLKH_SIZE + IH_SIZE * nr + (blocksize - ih_location(ih)); if (used_space != blocksize - blkh_free_space(blkh)) { /* * Free space does not match to calculated amount of * use space */ reiserfs_log(LOG_WARNING, "free space seems wrong\n"); return (0); } /* FIXME: it is_leaf will hit performance too much - we may have * return 1 here */ /* Check tables of item heads */ ih = (struct item_head *)(buf + BLKH_SIZE); prev_location = blocksize; for (i = 0; i < nr; i++, ih++) { if (le_ih_k_type(ih) == TYPE_ANY) { reiserfs_log(LOG_WARNING, "wrong item type for item\n"); return (0); } if (ih_location(ih) >= blocksize || ih_location(ih) < IH_SIZE * nr) { reiserfs_log(LOG_WARNING, "item location seems wrong\n"); return (0); } if (ih_item_len(ih) < 1 || ih_item_len(ih) > MAX_ITEM_LEN(blocksize)) { reiserfs_log(LOG_WARNING, "item length seems wrong\n"); return (0); } if (prev_location - ih_location(ih) != ih_item_len(ih)) { reiserfs_log(LOG_WARNING, "item location seems wrong (second one)\n"); return (0); } prev_location = ih_location(ih); } /* One may imagine much more checks */ return 1; }
/* * Unmount system call */ static int reiserfs_unmount(struct mount *mp, int mntflags) { int error, flags = 0; struct reiserfs_mount *rmp; struct reiserfs_sb_info *sbi; reiserfs_log(LOG_DEBUG, "get private data\n"); rmp = VFSTOREISERFS(mp); sbi = rmp->rm_reiserfs; /* Flangs handling */ reiserfs_log(LOG_DEBUG, "handle mntflags\n"); if (mntflags & MNT_FORCE) flags |= FORCECLOSE; /* Flush files -> vflush */ reiserfs_log(LOG_DEBUG, "flush vnodes\n"); if ((error = vflush(mp, 0, flags, curthread))) return (error); /* XXX Super block update */ if (sbi) { if (SB_AP_BITMAP(sbi)) { int i; reiserfs_log(LOG_DEBUG, "release bitmap buffers (total: %d)\n", SB_BMAP_NR(sbi)); for (i = 0; i < SB_BMAP_NR(sbi); i++) { if (SB_AP_BITMAP(sbi)[i].bp_data) { free(SB_AP_BITMAP(sbi)[i].bp_data, M_REISERFSMNT); SB_AP_BITMAP(sbi)[i].bp_data = NULL; } } reiserfs_log(LOG_DEBUG, "free bitmaps structure\n"); free(SB_AP_BITMAP(sbi), M_REISERFSMNT); SB_AP_BITMAP(sbi) = NULL; } if (sbi->s_rs) { reiserfs_log(LOG_DEBUG, "free super block data\n"); free(sbi->s_rs, M_REISERFSMNT); sbi->s_rs = NULL; } } reiserfs_log(LOG_DEBUG, "close device\n"); #if defined(si_mountpoint) rmp->rm_devvp->v_rdev->si_mountpoint = NULL; #endif DROP_GIANT(); g_topology_lock(); g_vfs_close(rmp->rm_cp); g_topology_unlock(); PICKUP_GIANT(); vrele(rmp->rm_devvp); dev_rel(rmp->rm_dev); if (sbi) { reiserfs_log(LOG_DEBUG, "free sbi\n"); free(sbi, M_REISERFSMNT); sbi = rmp->rm_reiserfs = NULL; } if (rmp) { reiserfs_log(LOG_DEBUG, "free rmp\n"); free(rmp, M_REISERFSMNT); rmp = NULL; } mp->mnt_data = 0; MNT_ILOCK(mp); mp->mnt_flag &= ~MNT_LOCAL; MNT_IUNLOCK(mp); reiserfs_log(LOG_DEBUG, "done\n"); return (error); }
/* * The statfs syscall */ static int reiserfs_statfs(struct mount *mp, struct statfs *sbp) { struct reiserfs_mount *rmp; struct reiserfs_sb_info *sbi; struct reiserfs_super_block *rs; reiserfs_log(LOG_DEBUG, "get private data\n"); rmp = VFSTOREISERFS(mp); sbi = rmp->rm_reiserfs; rs = sbi->s_rs; reiserfs_log(LOG_DEBUG, "fill statfs structure\n"); sbp->f_bsize = sbi->s_blocksize; sbp->f_iosize = sbp->f_bsize; sbp->f_blocks = sb_block_count(rs) - sb_bmap_nr(rs) - 1; sbp->f_bfree = sb_free_blocks(rs); sbp->f_bavail = sbp->f_bfree; sbp->f_files = 0; sbp->f_ffree = 0; reiserfs_log(LOG_DEBUG, " block size = %ju\n", (intmax_t)sbp->f_bsize); reiserfs_log(LOG_DEBUG, " IO size = %ju\n", (intmax_t)sbp->f_iosize); reiserfs_log(LOG_DEBUG, " block count = %ju\n", (intmax_t)sbp->f_blocks); reiserfs_log(LOG_DEBUG, " free blocks = %ju\n", (intmax_t)sbp->f_bfree); reiserfs_log(LOG_DEBUG, " avail blocks = %ju\n", (intmax_t)sbp->f_bavail); reiserfs_log(LOG_DEBUG, "...done\n"); if (sbp != &mp->mnt_stat) { reiserfs_log(LOG_DEBUG, "copying monut point info\n"); sbp->f_type = mp->mnt_vfc->vfc_typenum; bcopy((caddr_t)mp->mnt_stat.f_mntonname, (caddr_t)&sbp->f_mntonname[0], MNAMELEN); bcopy((caddr_t)mp->mnt_stat.f_mntfromname, (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); reiserfs_log(LOG_DEBUG, " mount from: %s\n", sbp->f_mntfromname); reiserfs_log(LOG_DEBUG, " mount on: %s\n", sbp->f_mntonname); reiserfs_log(LOG_DEBUG, "...done\n"); } return (0); }
/* * de's de_bh, de_ih, de_deh, de_item_num, de_entry_num are set already * Used when hash collisions exist */ static int linear_search_in_dir_item(struct cpu_key *key, struct reiserfs_dir_entry *de, const char *name, int namelen) { int i; int retval; struct reiserfs_de_head * deh = de->de_deh; i = de->de_entry_num; if (i == I_ENTRY_COUNT(de->de_ih) || GET_HASH_VALUE(deh_offset(deh + i)) != GET_HASH_VALUE(cpu_key_k_offset(key))) { i--; } /*RFALSE( de->de_deh != B_I_DEH (de->de_bh, de->de_ih), "vs-7010: array of entry headers not found");*/ deh += i; for (; i >= 0; i--, deh--) { if (GET_HASH_VALUE(deh_offset(deh)) != GET_HASH_VALUE(cpu_key_k_offset(key))) { /* * Hash value does not match, no need to check * whole name */ reiserfs_log(LOG_DEBUG, "name `%s' not found\n", name); return (NAME_NOT_FOUND); } /* Mark that this generation number is used */ if (de->de_gen_number_bit_string) set_bit(GET_GENERATION_NUMBER(deh_offset(deh)), (unsigned long *)de->de_gen_number_bit_string); /* Calculate pointer to name and namelen */ de->de_entry_num = i; set_de_name_and_namelen(de); if ((retval = reiserfs_match(de, name, namelen)) != NAME_NOT_FOUND) { /* * de's de_name, de_namelen, de_recordlen are set. * Fill the rest: */ /* key of pointed object */ set_de_object_key(de); store_de_entry_key(de); /* retval can be NAME_FOUND or NAME_FOUND_INVISIBLE */ reiserfs_log(LOG_DEBUG, "reiserfs_match answered `%d'\n", retval); return (retval); } } if (GET_GENERATION_NUMBER(le_ih_k_offset(de->de_ih)) == 0) /* * We have reached left most entry in the node. In common * we have to go to the left neighbor, but if generation * counter is 0 already, we know for sure, that there is * no name with the same hash value */ /* FIXME: this work correctly only because hash value can * not be 0. Btw, in case of Yura's hash it is probably * possible, so, this is a bug */ return (NAME_NOT_FOUND); /*RFALSE(de->de_item_num, "vs-7015: two diritems of the same directory in one node?");*/ return (GOTO_PREVIOUS_ITEM); }
/* * 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); }
/* * Read the super block */ static int read_super_block(struct reiserfs_mount *rmp, int offset) { struct buf *bp; int error, bits; struct reiserfs_super_block *rs; struct reiserfs_sb_info *sbi; uint16_t fs_blocksize; if (offset == REISERFS_OLD_DISK_OFFSET) { reiserfs_log(LOG_DEBUG, "reiserfs/super: read old format super block\n"); } else { reiserfs_log(LOG_DEBUG, "reiserfs/super: read new format super block\n"); } /* Read the super block */ if ((error = bread(rmp->rm_devvp, offset * btodb(REISERFS_BSIZE), REISERFS_BSIZE, NOCRED, &bp)) != 0) { reiserfs_log(LOG_ERR, "can't read device\n"); return (error); } /* Get it from the buffer data */ rs = (struct reiserfs_super_block *)bp->b_data; if (!is_any_reiserfs_magic_string(rs)) { brelse(bp); return (EINVAL); } fs_blocksize = sb_blocksize(rs); brelse(bp); bp = NULL; if (fs_blocksize <= 0) { reiserfs_log(LOG_ERR, "unexpected null block size"); return (EINVAL); } /* Read the super block (for double check) * We can't read the same blkno with a different size: it causes * panic() if INVARIANTS is set. So we keep REISERFS_BSIZE */ if ((error = bread(rmp->rm_devvp, offset * REISERFS_BSIZE / fs_blocksize * btodb(fs_blocksize), REISERFS_BSIZE, NOCRED, &bp)) != 0) { reiserfs_log(LOG_ERR, "can't reread the super block\n"); return (error); } rs = (struct reiserfs_super_block *)bp->b_data; if (sb_blocksize(rs) != fs_blocksize) { reiserfs_log(LOG_ERR, "unexpected block size " "(found=%u, expected=%u)\n", sb_blocksize(rs), fs_blocksize); brelse(bp); return (EINVAL); } reiserfs_log(LOG_DEBUG, "magic: `%s'\n", rs->s_v1.s_magic); reiserfs_log(LOG_DEBUG, "label: `%s'\n", rs->s_label); reiserfs_log(LOG_DEBUG, "block size: %6d\n", sb_blocksize(rs)); reiserfs_log(LOG_DEBUG, "block count: %6u\n", rs->s_v1.s_block_count); reiserfs_log(LOG_DEBUG, "bitmaps number: %6u\n", rs->s_v1.s_bmap_nr); if (rs->s_v1.s_root_block == -1) { log(LOG_ERR, "reiserfs: Unfinished reiserfsck --rebuild-tree run " "detected. Please\n" "run reiserfsck --rebuild-tree and wait for a " "completion. If that\n" "fails, get newer reiserfsprogs package"); brelse(bp); return (EINVAL); } sbi = rmp->rm_reiserfs; sbi->s_blocksize = fs_blocksize; for (bits = 9, fs_blocksize >>= 9; fs_blocksize >>= 1; bits++) ; sbi->s_blocksize_bits = bits; /* Copy the buffer and release it */ sbi->s_rs = malloc(sizeof *rs, M_REISERFSMNT, M_WAITOK | M_ZERO); if (!sbi->s_rs) { reiserfs_log(LOG_ERR, "can not read the super block\n"); brelse(bp); return (ENOMEM); } bcopy(rs, sbi->s_rs, sizeof(struct reiserfs_super_block)); brelse(bp); if (is_reiserfs_jr(rs)) { if (sb_version(rs) == REISERFS_VERSION_2) reiserfs_log(LOG_INFO, "found reiserfs format \"3.6\"" " with non-standard journal"); else if (sb_version(rs) == REISERFS_VERSION_1) reiserfs_log(LOG_INFO, "found reiserfs format \"3.5\"" " with non-standard journal"); else { reiserfs_log(LOG_ERR, "found unknown " "format \"%u\" of reiserfs with non-standard magic", sb_version(rs)); return (EINVAL); } } else { /* * s_version of standard format may contain incorrect * information, so we just look at the magic string */ reiserfs_log(LOG_INFO, "found reiserfs format \"%s\" with standard journal\n", is_reiserfs_3_5(rs) ? "3.5" : "3.6"); } return (0); }
int reiserfs_lookup(struct vop_cachedlookup_args *ap) { int error, retval; struct vnode *vdp = ap->a_dvp; struct vnode **vpp = ap->a_vpp; struct componentname *cnp = ap->a_cnp; int flags = cnp->cn_flags; struct thread *td = cnp->cn_thread; struct cpu_key *saved_ino; struct vnode *vp; struct vnode *pdp; /* Saved dp during symlink work */ struct reiserfs_node *dp; struct reiserfs_dir_entry de; INITIALIZE_PATH(path_to_entry); char c = cnp->cn_nameptr[cnp->cn_namelen]; cnp->cn_nameptr[cnp->cn_namelen] = '\0'; reiserfs_log(LOG_DEBUG, "looking for `%s', %ld (%s)\n", cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_pnbuf); cnp->cn_nameptr[cnp->cn_namelen] = c; vp = NULL; dp = VTOI(vdp); if (REISERFS_MAX_NAME(dp->i_reiserfs->s_blocksize) < cnp->cn_namelen) return (ENAMETOOLONG); reiserfs_log(LOG_DEBUG, "searching entry\n"); de.de_gen_number_bit_string = 0; retval = reiserfs_find_entry(dp, cnp->cn_nameptr, cnp->cn_namelen, &path_to_entry, &de); pathrelse(&path_to_entry); if (retval == NAME_FOUND) { reiserfs_log(LOG_DEBUG, "found\n"); } else { reiserfs_log(LOG_DEBUG, "not found\n"); } if (retval == NAME_FOUND) { #if 0 /* Hide the .reiserfs_priv directory */ if (reiserfs_xattrs(dp->i_reiserfs) && !old_format_only(dp->i_reiserfs) && REISERFS_SB(dp->i_reiserfs)->priv_root && REISERFS_SB(dp->i_reiserfs)->priv_root->d_inode && de.de_objectid == le32toh(INODE_PKEY(REISERFS_SB( dp->i_reiserfs)->priv_root->d_inode)->k_objectid)) { return (EACCES); } #endif reiserfs_log(LOG_DEBUG, "reading vnode\n"); pdp = vdp; if (flags & ISDOTDOT) { saved_ino = (struct cpu_key *)&(de.de_dir_id); VOP_UNLOCK(pdp, 0); error = reiserfs_iget(vdp->v_mount, saved_ino, &vp, td); vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY); if (error != 0) return (error); *vpp = vp; } else if (de.de_objectid == dp->i_number && de.de_dir_id == dp->i_ino) { VREF(vdp); /* We want ourself, ie "." */ *vpp = vdp; } else { if ((error = reiserfs_iget(vdp->v_mount, (struct cpu_key *)&(de.de_dir_id), &vp, td)) != 0) return (error); *vpp = vp; } /* * Propogate the priv_object flag so we know we're in the * priv tree */ /*if (is_reiserfs_priv_object(dir)) REISERFS_I(inode)->i_flags |= i_priv_object;*/ } else { if (retval == IO_ERROR) { reiserfs_log(LOG_DEBUG, "IO error\n"); return (EIO); } return (ENOENT); } /* Insert name into cache if appropriate. */ if (cnp->cn_flags & MAKEENTRY) cache_enter(vdp, *vpp, cnp); reiserfs_log(LOG_DEBUG, "done\n"); return (0); }
int reiserfs_readdir(struct vop_readdir_args /* { struct vnode *a_vp; struct uio *a_uio; struct ucred *a_cred; int *a_eofflag; int *a_ncookies; u_long **a_cookies; } */*ap) { int error = 0; struct dirent dstdp; struct uio *uio = ap->a_uio; off_t next_pos; struct buf *bp; struct item_head *ih; struct cpu_key pos_key; const struct key *rkey; struct reiserfs_node *ip; struct reiserfs_dir_entry de; INITIALIZE_PATH(path_to_entry); int entry_num, item_num, search_res; /* The NFS part */ int ncookies = 0; u_long *cookies = NULL; /* * Form key for search the next directory entry using f_pos field of * file structure */ ip = VTOI(ap->a_vp); make_cpu_key(&pos_key, ip, uio->uio_offset ? uio->uio_offset : DOT_OFFSET, TYPE_DIRENTRY, 3); next_pos = cpu_key_k_offset(&pos_key); reiserfs_log(LOG_DEBUG, "listing entries for " "(objectid=%d, dirid=%d)\n", pos_key.on_disk_key.k_objectid, pos_key.on_disk_key.k_dir_id); reiserfs_log(LOG_DEBUG, "uio_offset = %jd, uio_resid = %d\n", (intmax_t)uio->uio_offset, uio->uio_resid); if (ap->a_ncookies && ap->a_cookies) { cookies = (u_long *)malloc( uio->uio_resid / 16 * sizeof(u_long), M_REISERFSCOOKIES, M_WAITOK); } while (1) { //research: /* * Search the directory item, containing entry with * specified key */ reiserfs_log(LOG_DEBUG, "search directory to read\n"); search_res = search_by_entry_key(ip->i_reiserfs, &pos_key, &path_to_entry, &de); if (search_res == IO_ERROR) { error = EIO; goto out; } entry_num = de.de_entry_num; item_num = de.de_item_num; bp = de.de_bp; ih = de.de_ih; if (search_res == POSITION_FOUND || entry_num < I_ENTRY_COUNT(ih)) { /* * Go through all entries in the directory item * beginning from the entry, that has been found. */ struct reiserfs_de_head *deh = B_I_DEH(bp, ih) + entry_num; if (ap->a_ncookies == NULL) { cookies = NULL; } else { //ncookies = } reiserfs_log(LOG_DEBUG, "walking through directory entries\n"); for (; entry_num < I_ENTRY_COUNT(ih); entry_num++, deh++) { int d_namlen; char *d_name; off_t d_off; ino_t d_ino; if (!de_visible(deh)) { /* It is hidden entry */ continue; } d_namlen = entry_length(bp, ih, entry_num); d_name = B_I_DEH_ENTRY_FILE_NAME(bp, ih, deh); if (!d_name[d_namlen - 1]) d_namlen = strlen(d_name); reiserfs_log(LOG_DEBUG, " - `%s' (len=%d)\n", d_name, d_namlen); if (d_namlen > REISERFS_MAX_NAME( ip->i_reiserfs->s_blocksize)) { /* Too big to send back to VFS */ continue; } #if 0 /* Ignore the .reiserfs_priv entry */ if (reiserfs_xattrs(ip->i_reiserfs) && !old_format_only(ip->i_reiserfs) && filp->f_dentry == ip->i_reiserfs->s_root && REISERFS_SB(ip->i_reiserfs)->priv_root && REISERFS_SB(ip->i_reiserfs)->priv_root->d_inode && deh_objectid(deh) == le32toh(INODE_PKEY(REISERFS_SB( ip->i_reiserfs)->priv_root->d_inode)->k_objectid)) { continue; } #endif d_off = deh_offset(deh); d_ino = deh_objectid(deh); uio->uio_offset = d_off; /* Copy to user land */ dstdp.d_fileno = d_ino; dstdp.d_type = DT_UNKNOWN; dstdp.d_namlen = d_namlen; dstdp.d_reclen = GENERIC_DIRSIZ(&dstdp); bcopy(d_name, dstdp.d_name, dstdp.d_namlen); bzero(dstdp.d_name + dstdp.d_namlen, dstdp.d_reclen - offsetof(struct dirent, d_name) - dstdp.d_namlen); if (d_namlen > 0) { if (dstdp.d_reclen <= uio->uio_resid) { reiserfs_log(LOG_DEBUG, " copying to user land\n"); error = uiomove(&dstdp, dstdp.d_reclen, uio); if (error) goto end; if (cookies != NULL) { cookies[ncookies] = d_off; ncookies++; } } else break; } else { error = EIO; break; } next_pos = deh_offset(deh) + 1; } reiserfs_log(LOG_DEBUG, "...done\n"); } reiserfs_log(LOG_DEBUG, "checking item num (%d == %d ?)\n", item_num, B_NR_ITEMS(bp) - 1); if (item_num != B_NR_ITEMS(bp) - 1) { /* End of directory has been reached */ reiserfs_log(LOG_DEBUG, "end reached\n"); if (ap->a_eofflag) *ap->a_eofflag = 1; goto end; } /* * Item we went through is last item of node. Using right * delimiting key check is it directory end */ reiserfs_log(LOG_DEBUG, "get right key\n"); rkey = get_rkey(&path_to_entry, ip->i_reiserfs); reiserfs_log(LOG_DEBUG, "right key = (objectid=%d, dirid=%d)\n", rkey->k_objectid, rkey->k_dir_id); reiserfs_log(LOG_DEBUG, "compare it to MIN_KEY\n"); reiserfs_log(LOG_DEBUG, "MIN KEY = (objectid=%d, dirid=%d)\n", MIN_KEY.k_objectid, MIN_KEY.k_dir_id); if (comp_le_keys(rkey, &MIN_KEY) == 0) { /* Set pos_key to key, that is the smallest and greater * that key of the last entry in the item */ reiserfs_log(LOG_DEBUG, "continuing on the right\n"); set_cpu_key_k_offset(&pos_key, next_pos); continue; } reiserfs_log(LOG_DEBUG, "compare it to pos_key\n"); reiserfs_log(LOG_DEBUG, "pos key = (objectid=%d, dirid=%d)\n", pos_key.on_disk_key.k_objectid, pos_key.on_disk_key.k_dir_id); if (COMP_SHORT_KEYS(rkey, &pos_key)) { /* End of directory has been reached */ reiserfs_log(LOG_DEBUG, "end reached (right)\n"); if (ap->a_eofflag) *ap->a_eofflag = 1; goto end; } /* Directory continues in the right neighboring block */ reiserfs_log(LOG_DEBUG, "continuing with a new offset\n"); set_cpu_key_k_offset(&pos_key, le_key_k_offset(KEY_FORMAT_3_5, rkey)); reiserfs_log(LOG_DEBUG, "new pos key = (objectid=%d, dirid=%d)\n", pos_key.on_disk_key.k_objectid, pos_key.on_disk_key.k_dir_id); } end: uio->uio_offset = next_pos; pathrelse(&path_to_entry); reiserfs_check_path(&path_to_entry); out: if (error && cookies != NULL) { free(cookies, M_REISERFSCOOKIES); } else if (ap->a_ncookies != NULL && ap->a_cookies != NULL) { *ap->a_ncookies = ncookies; *ap->a_cookies = cookies; } return (error); }
/* * Mount system call */ static int reiserfs_mount(struct mount *mp) { size_t size; int error, len; accmode_t accmode; char *path, *fspec; struct vnode *devvp; struct vfsoptlist *opts; struct reiserfs_mount *rmp; struct reiserfs_sb_info *sbi; struct nameidata nd, *ndp = &nd; struct thread *td; td = curthread; if (!(mp->mnt_flag & MNT_RDONLY)) return EROFS; /* Get the new options passed to mount */ opts = mp->mnt_optnew; /* `fspath' contains the mount point (eg. /mnt/linux); REQUIRED */ vfs_getopt(opts, "fspath", (void **)&path, NULL); reiserfs_log(LOG_INFO, "mount point is `%s'\n", path); /* `from' contains the device name (eg. /dev/ad0s1); REQUIRED */ fspec = NULL; error = vfs_getopt(opts, "from", (void **)&fspec, &len); if (!error && fspec[len - 1] != '\0') return (EINVAL); reiserfs_log(LOG_INFO, "device is `%s'\n", fspec); /* Handle MNT_UPDATE (mp->mnt_flag) */ if (mp->mnt_flag & MNT_UPDATE) { /* For now, only NFS export is supported. */ if (vfs_flagopt(opts, "export", NULL, 0)) return (0); } /* Not an update, or updating the name: look up the name * and verify that it refers to a sensible disk device. */ if (fspec == NULL) return (EINVAL); NDINIT(ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspec, td); if ((error = namei(ndp)) != 0) return (error); NDFREE(ndp, NDF_ONLY_PNBUF); devvp = ndp->ni_vp; if (!vn_isdisk(devvp, &error)) { vput(devvp); return (error); } /* If mount by non-root, then verify that user has necessary * permissions on the device. */ accmode = VREAD; if ((mp->mnt_flag & MNT_RDONLY) == 0) accmode |= VWRITE; error = VOP_ACCESS(devvp, accmode, td->td_ucred, td); if (error) error = priv_check(td, PRIV_VFS_MOUNT_PERM); if (error) { vput(devvp); return (error); } if ((mp->mnt_flag & MNT_UPDATE) == 0) { error = reiserfs_mountfs(devvp, mp, td); } else { /* TODO Handle MNT_UPDATE */ vput(devvp); return (EOPNOTSUPP); } if (error) { vrele(devvp); return (error); } rmp = VFSTOREISERFS(mp); sbi = rmp->rm_reiserfs; /* * Note that this strncpy() is ok because of a check at the start * of reiserfs_mount(). */ reiserfs_log(LOG_DEBUG, "prepare statfs data\n"); (void)copystr(fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size); bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); (void)reiserfs_statfs(mp, &mp->mnt_stat); reiserfs_log(LOG_DEBUG, "done\n"); return (0); }
/* * 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 both * have the same value - we ask user to send report to the mailing list */ uint32_t find_hash_out(struct reiserfs_mount *rmp) { int retval; struct cpu_key key; INITIALIZE_PATH(path); struct reiserfs_node *ip; struct reiserfs_sb_info *sbi; struct reiserfs_dir_entry de; uint32_t hash = DEFAULT_HASH; get_root_node(rmp, &ip); if (!ip) return (UNSET_HASH); sbi = rmp->rm_reiserfs; do { uint32_t teahash, r5hash, yurahash; reiserfs_log(LOG_DEBUG, "make_cpu_key\n"); make_cpu_key(&key, ip, ~0, TYPE_DIRENTRY, 3); reiserfs_log(LOG_DEBUG, "search_by_entry_key for " "key(objectid=%d,dirid=%d)\n", key.on_disk_key.k_objectid, key.on_disk_key.k_dir_id); retval = search_by_entry_key(sbi, &key, &path, &de); if (retval == IO_ERROR) { pathrelse(&path); return (UNSET_HASH); } if (retval == NAME_NOT_FOUND) de.de_entry_num--; reiserfs_log(LOG_DEBUG, "name found\n"); set_de_name_and_namelen(&de); if (deh_offset(&(de.de_deh[de.de_entry_num])) == DOT_DOT_OFFSET) { /* Allow override in this case */ if (reiserfs_rupasov_hash(sbi)) { hash = YURA_HASH; } reiserfs_log(LOG_DEBUG, "FS seems to be empty, autodetect " "is using the default hash"); break; } r5hash = GET_HASH_VALUE(r5_hash(de.de_name, de.de_namelen)); teahash = GET_HASH_VALUE(keyed_hash(de.de_name, de.de_namelen)); yurahash = GET_HASH_VALUE(yura_hash(de.de_name, de.de_namelen)); if (((teahash == r5hash) && (GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num]))) == r5hash)) || ((teahash == yurahash) && (yurahash == GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num]))))) || ((r5hash == yurahash) && (yurahash == GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num])))))) { reiserfs_log(LOG_ERR, "unable to automatically detect hash " "function. Please mount with -o " "hash={tea,rupasov,r5}"); hash = UNSET_HASH; break; } if (GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num]))) == yurahash) { reiserfs_log(LOG_DEBUG, "detected YURA hash\n"); hash = YURA_HASH; } else if (GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num]))) == teahash) { reiserfs_log(LOG_DEBUG, "detected TEA hash\n"); hash = TEA_HASH; } else if (GET_HASH_VALUE( deh_offset(&(de.de_deh[de.de_entry_num]))) == r5hash) { reiserfs_log(LOG_DEBUG, "detected R5 hash\n"); hash = R5_HASH; } else { reiserfs_log(LOG_WARNING, "unrecognised hash function"); hash = UNSET_HASH; } } while (0); pathrelse(&path); return (hash); }