/* * k1 is pointer to on-disk structure which is stored in little-endian * form. k2 is pointer to cpu variable. Compare keys using all 4 key * fields. * Returns: -1 if key1 < key2, 0 if key1 = key2 or 1 if key1 > key2 */ /*inline*/ int comp_keys(const struct key *le_key, const struct cpu_key *cpu_key) { int retval; retval = comp_short_keys(le_key, cpu_key); if (retval) return retval; if (le_key_k_offset(le_key_version(le_key), le_key) < cpu_key_k_offset(cpu_key)) return (-1); if (le_key_k_offset(le_key_version(le_key), le_key) > cpu_key_k_offset(cpu_key)) return (1); if (cpu_key->key_length == 3) return (0); /* This part is needed only when tail conversion is in progress */ if (le_key_k_type(le_key_version(le_key), le_key) < cpu_key_k_type(cpu_key)) return (-1); if (le_key_k_type(le_key_version(le_key), le_key) > cpu_key_k_type(cpu_key)) return (1); return (0); }
/* k1 is pointer to on-disk structure which is stored in little-endian form. k2 is pointer to cpu variable. Compare keys using all 4 key fields. Returns: -1 if key1 < key2 0 if key1 = key2 1 if key1 > key2 */ static inline int comp_keys(const struct reiserfs_key *le_key, const struct cpu_key *cpu_key) { int retval; retval = comp_short_keys(le_key, cpu_key); if (retval) return retval; if (le_key_k_offset(le_key_version(le_key), le_key) < cpu_key_k_offset(cpu_key)) return -1; if (le_key_k_offset(le_key_version(le_key), le_key) > cpu_key_k_offset(cpu_key)) return 1; if (cpu_key->key_length == 3) return 0; /* this part is needed only when tail conversion is in progress */ if (le_key_k_type(le_key_version(le_key), le_key) < cpu_key_k_type(cpu_key)) return -1; if (le_key_k_type(le_key_version(le_key), le_key) > cpu_key_k_type(cpu_key)) return 1; return 0; }
static char * le_offset (struct key * key) { int version; version = le_key_version (key); if (le_key_k_type (version, key) == TYPE_DIRENTRY) sprintf (off_buf, "%Lu(%Lu)", (unsigned long long)GET_HASH_VALUE (le_key_k_offset (version, key)), (unsigned long long)GET_GENERATION_NUMBER (le_key_k_offset (version, key))); else sprintf (off_buf, "0x%Lx", (unsigned long long)le_key_k_offset (version, key)); return off_buf; }
inline void le_key2cpu_key(struct cpu_key *to, const struct reiserfs_key *from) { int version; to->on_disk_key.k_dir_id = le32_to_cpu(from->k_dir_id); to->on_disk_key.k_objectid = le32_to_cpu(from->k_objectid); // find out version of the key version = le_key_version(from); to->version = version; to->on_disk_key.k_offset = le_key_k_offset(version, from); to->on_disk_key.k_type = le_key_k_type(version, from); }
static int reiserfs_readdir (struct file * filp, void * dirent, filldir_t filldir) { struct inode *inode = filp->f_dentry->d_inode; struct cpu_key pos_key; /* key of current position in the directory (key of directory entry) */ INITIALIZE_PATH (path_to_entry); struct buffer_head * bh; int item_num, entry_num; const struct key * rkey; struct item_head * ih, tmp_ih; int search_res; char * local_buf; loff_t next_pos; char small_buf[32] ; /* avoid kmalloc if we can */ struct reiserfs_dir_entry de; reiserfs_check_lock_depth("readdir") ; /* form key for search the next directory entry using f_pos field of file structure */ make_cpu_key (&pos_key, inode, (filp->f_pos) ? (filp->f_pos) : DOT_OFFSET, TYPE_DIRENTRY, 3); next_pos = cpu_key_k_offset (&pos_key); /* reiserfs_warning ("reiserfs_readdir 1: f_pos = %Ld\n", filp->f_pos);*/ while (1) { research: /* search the directory item, containing entry with specified key */ search_res = search_by_entry_key (inode->i_sb, &pos_key, &path_to_entry, &de); if (search_res == IO_ERROR) { // FIXME: we could just skip part of directory which could // not be read return -EIO; } entry_num = de.de_entry_num; bh = de.de_bh; item_num = de.de_item_num; ih = de.de_ih; store_ih (&tmp_ih, ih); /* we must have found item, that is item of this directory, */ RFALSE( COMP_SHORT_KEYS (&(ih->ih_key), &pos_key), "vs-9000: found item %h does not match to dir we readdir %K", ih, &pos_key); RFALSE( item_num > B_NR_ITEMS (bh) - 1, "vs-9005 item_num == %d, item amount == %d", item_num, B_NR_ITEMS (bh)); /* and entry must be not more than number of entries in the item */ RFALSE( I_ENTRY_COUNT (ih) < entry_num, "vs-9010: entry number is too big %d (%d)", entry_num, I_ENTRY_COUNT (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 (bh, ih) + entry_num; for (; entry_num < I_ENTRY_COUNT (ih); entry_num ++, deh ++) { int d_reclen; char * d_name; off_t d_off; ino_t d_ino; if (!de_visible (deh)) /* it is hidden entry */ continue; d_reclen = entry_length (bh, ih, entry_num); d_name = B_I_DEH_ENTRY_FILE_NAME (bh, ih, deh); if (!d_name[d_reclen - 1]) d_reclen = strlen (d_name); if (d_reclen > REISERFS_MAX_NAME_LEN(inode->i_sb->s_blocksize)){ /* too big to send back to VFS */ continue ; } d_off = deh_offset (deh); filp->f_pos = d_off ; d_ino = deh_objectid (deh); if (d_reclen <= 32) { local_buf = small_buf ; } else { local_buf = reiserfs_kmalloc(d_reclen, GFP_NOFS, inode->i_sb) ; if (!local_buf) { pathrelse (&path_to_entry); return -ENOMEM ; } if (item_moved (&tmp_ih, &path_to_entry)) { reiserfs_kfree(local_buf, d_reclen, inode->i_sb) ; goto research; } } // Note, that we copy name to user space via temporary // buffer (local_buf) because filldir will block if // user space buffer is swapped out. At that time // entry can move to somewhere else memcpy (local_buf, d_name, d_reclen); if (filldir (dirent, local_buf, d_reclen, d_off, d_ino, DT_UNKNOWN) < 0) { if (local_buf != small_buf) { reiserfs_kfree(local_buf, d_reclen, inode->i_sb) ; } goto end; } if (local_buf != small_buf) { reiserfs_kfree(local_buf, d_reclen, inode->i_sb) ; } // next entry should be looked for with such offset next_pos = deh_offset (deh) + 1; if (item_moved (&tmp_ih, &path_to_entry)) { goto research; } } /* for */ } if (item_num != B_NR_ITEMS (bh) - 1) // end of directory has been reached goto end; /* item we went through is last item of node. Using right delimiting key check is it directory end */ rkey = get_rkey (&path_to_entry, inode->i_sb); if (! comp_le_keys (rkey, &MIN_KEY)) { /* set pos_key to key, that is the smallest and greater that key of the last entry in the item */ set_cpu_key_k_offset (&pos_key, next_pos); continue; } if ( COMP_SHORT_KEYS (rkey, &pos_key)) { // end of directory has been reached goto end; } /* directory continues in the right neighboring block */ set_cpu_key_k_offset (&pos_key, le_key_k_offset (KEY_FORMAT_3_5, rkey)); } /* while */ end: // FIXME: ext2_readdir does not reset f_pos filp->f_pos = next_pos; pathrelse (&path_to_entry); reiserfs_check_path(&path_to_entry) ; UPDATE_ATIME(inode) ; 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); }
/* Allocates blocks for a file to fulfil write request. Maps all unmapped but prepared pages from the list. Updates metadata with newly allocated blocknumbers as needed */ int reiserfs_allocate_blocks_for_region( struct reiserfs_transaction_handle *th, struct inode *inode, /* Inode we work with */ loff_t pos, /* Writing position */ int num_pages, /* number of pages write going to touch */ int write_bytes, /* amount of bytes to write */ struct page **prepared_pages, /* array of prepared pages */ int blocks_to_allocate /* Amount of blocks we need to allocate to fit the data into file */ ) { struct cpu_key key; // cpu key of item that we are going to deal with struct item_head *ih; // pointer to item head that we are going to deal with struct buffer_head *bh; // Buffer head that contains items that we are going to deal with __u32 * item; // pointer to item we are going to deal with INITIALIZE_PATH(path); // path to item, that we are going to deal with. b_blocknr_t *allocated_blocks; // Pointer to a place where allocated blocknumbers would be stored. reiserfs_blocknr_hint_t hint; // hint structure for block allocator. size_t res; // return value of various functions that we call. int curr_block; // current block used to keep track of unmapped blocks. int i; // loop counter int itempos; // position in item unsigned int from = (pos & (PAGE_CACHE_SIZE - 1)); // writing position in // first page unsigned int to = ((pos + write_bytes - 1) & (PAGE_CACHE_SIZE - 1)) + 1; /* last modified byte offset in last page */ __u64 hole_size ; // amount of blocks for a file hole, if it needed to be created. int modifying_this_item = 0; // Flag for items traversal code to keep track // of the fact that we already prepared // current block for journal int will_prealloc = 0; RFALSE(!blocks_to_allocate, "green-9004: tried to allocate zero blocks?"); /* only preallocate if this is a small write */ if (REISERFS_I(inode)->i_prealloc_count || (!(write_bytes & (inode->i_sb->s_blocksize -1)) && blocks_to_allocate < REISERFS_SB(inode->i_sb)->s_alloc_options.preallocsize)) will_prealloc = REISERFS_SB(inode->i_sb)->s_alloc_options.preallocsize; allocated_blocks = kmalloc((blocks_to_allocate + will_prealloc) * sizeof(b_blocknr_t), GFP_NOFS); /* First we compose a key to point at the writing position, we want to do that outside of any locking region. */ make_cpu_key (&key, inode, pos+1, TYPE_ANY, 3/*key length*/); /* If we came here, it means we absolutely need to open a transaction, since we need to allocate some blocks */ reiserfs_write_lock(inode->i_sb); // Journaling stuff and we need that. journal_begin(th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3 + 1); // Wish I know if this number enough reiserfs_update_inode_transaction(inode) ; /* Look for the in-tree position of our write, need path for block allocator */ res = search_for_position_by_key(inode->i_sb, &key, &path); if ( res == IO_ERROR ) { res = -EIO; goto error_exit; } /* Allocate blocks */ /* First fill in "hint" structure for block allocator */ hint.th = th; // transaction handle. hint.path = &path; // Path, so that block allocator can determine packing locality or whatever it needs to determine. hint.inode = inode; // Inode is needed by block allocator too. hint.search_start = 0; // We have no hint on where to search free blocks for block allocator. hint.key = key.on_disk_key; // on disk key of file. hint.block = inode->i_blocks>>(inode->i_sb->s_blocksize_bits-9); // Number of disk blocks this file occupies already. hint.formatted_node = 0; // We are allocating blocks for unformatted node. hint.preallocate = will_prealloc; /* Call block allocator to allocate blocks */ res = reiserfs_allocate_blocknrs(&hint, allocated_blocks, blocks_to_allocate, blocks_to_allocate); if ( res != CARRY_ON ) { if ( res == NO_DISK_SPACE ) { /* We flush the transaction in case of no space. This way some blocks might become free */ SB_JOURNAL(inode->i_sb)->j_must_wait = 1; restart_transaction(th, inode, &path); /* We might have scheduled, so search again */ res = search_for_position_by_key(inode->i_sb, &key, &path); if ( res == IO_ERROR ) { res = -EIO; goto error_exit; } /* update changed info for hint structure. */ res = reiserfs_allocate_blocknrs(&hint, allocated_blocks, blocks_to_allocate, blocks_to_allocate); if ( res != CARRY_ON ) { res = -ENOSPC; pathrelse(&path); goto error_exit; } } else { res = -ENOSPC; pathrelse(&path); goto error_exit; } } #ifdef __BIG_ENDIAN // Too bad, I have not found any way to convert a given region from // cpu format to little endian format { int i; for ( i = 0; i < blocks_to_allocate ; i++) allocated_blocks[i]=cpu_to_le32(allocated_blocks[i]); } #endif /* Blocks allocating well might have scheduled and tree might have changed, let's search the tree again */ /* find where in the tree our write should go */ res = search_for_position_by_key(inode->i_sb, &key, &path); if ( res == IO_ERROR ) { res = -EIO; goto error_exit_free_blocks; } bh = get_last_bh( &path ); // Get a bufferhead for last element in path. ih = get_ih( &path ); // Get a pointer to last item head in path. item = get_item( &path ); // Get a pointer to last item in path /* Let's see what we have found */ if ( res != POSITION_FOUND ) { /* position not found, this means that we might need to append file with holes first */ // Since we are writing past the file's end, we need to find out if // there is a hole that needs to be inserted before our writing // position, and how many blocks it is going to cover (we need to // populate pointers to file blocks representing the hole with zeros) { int item_offset = 1; /* * if ih is stat data, its offset is 0 and we don't want to * add 1 to pos in the hole_size calculation */ if (is_statdata_le_ih(ih)) item_offset = 0; hole_size = (pos + item_offset - (le_key_k_offset( get_inode_item_key_version(inode), &(ih->ih_key)) + op_bytes_number(ih, inode->i_sb->s_blocksize))) >> inode->i_sb->s_blocksize_bits; }
int reiserfs_readdir_dentry(struct dentry *dentry, void *dirent, filldir_t filldir, loff_t *pos) { struct inode *inode = dentry->d_inode; struct cpu_key pos_key; INITIALIZE_PATH(path_to_entry); struct buffer_head *bh; int item_num, entry_num; const struct reiserfs_key *rkey; struct item_head *ih, tmp_ih; int search_res; char *local_buf; loff_t next_pos; char small_buf[32]; struct reiserfs_dir_entry de; int ret = 0; reiserfs_write_lock(inode->i_sb); reiserfs_check_lock_depth(inode->i_sb, "readdir"); make_cpu_key(&pos_key, inode, *pos ?: DOT_OFFSET, TYPE_DIRENTRY, 3); next_pos = cpu_key_k_offset(&pos_key); path_to_entry.reada = PATH_READA; while (1) { research: search_res = search_by_entry_key(inode->i_sb, &pos_key, &path_to_entry, &de); if (search_res == IO_ERROR) { ret = -EIO; goto out; } entry_num = de.de_entry_num; bh = de.de_bh; item_num = de.de_item_num; ih = de.de_ih; store_ih(&tmp_ih, ih); RFALSE(COMP_SHORT_KEYS(&(ih->ih_key), &pos_key), "vs-9000: found item %h does not match to dir we readdir %K", ih, &pos_key); RFALSE(item_num > B_NR_ITEMS(bh) - 1, "vs-9005 item_num == %d, item amount == %d", item_num, B_NR_ITEMS(bh)); RFALSE(I_ENTRY_COUNT(ih) < entry_num, "vs-9010: entry number is too big %d (%d)", entry_num, I_ENTRY_COUNT(ih)); if (search_res == POSITION_FOUND || entry_num < I_ENTRY_COUNT(ih)) { struct reiserfs_de_head *deh = B_I_DEH(bh, ih) + entry_num; for (; entry_num < I_ENTRY_COUNT(ih); entry_num++, deh++) { int d_reclen; char *d_name; off_t d_off; ino_t d_ino; if (!de_visible(deh)) continue; d_reclen = entry_length(bh, ih, entry_num); d_name = B_I_DEH_ENTRY_FILE_NAME(bh, ih, deh); if (d_reclen <= 0 || d_name + d_reclen > bh->b_data + bh->b_size) { pathrelse(&path_to_entry); ret = -EIO; goto out; } if (!d_name[d_reclen - 1]) d_reclen = strlen(d_name); if (d_reclen > REISERFS_MAX_NAME(inode->i_sb-> s_blocksize)) { continue; } if (is_privroot_deh(dentry, deh)) continue; d_off = deh_offset(deh); *pos = d_off; d_ino = deh_objectid(deh); if (d_reclen <= 32) { local_buf = small_buf; } else { local_buf = kmalloc(d_reclen, GFP_NOFS); if (!local_buf) { pathrelse(&path_to_entry); ret = -ENOMEM; goto out; } if (item_moved(&tmp_ih, &path_to_entry)) { kfree(local_buf); goto research; } } memcpy(local_buf, d_name, d_reclen); reiserfs_write_unlock(inode->i_sb); if (filldir (dirent, local_buf, d_reclen, d_off, d_ino, DT_UNKNOWN) < 0) { reiserfs_write_lock(inode->i_sb); if (local_buf != small_buf) { kfree(local_buf); } goto end; } reiserfs_write_lock(inode->i_sb); if (local_buf != small_buf) { kfree(local_buf); } next_pos = deh_offset(deh) + 1; if (item_moved(&tmp_ih, &path_to_entry)) { goto research; } } } if (item_num != B_NR_ITEMS(bh) - 1) goto end; rkey = get_rkey(&path_to_entry, inode->i_sb); if (!comp_le_keys(rkey, &MIN_KEY)) { set_cpu_key_k_offset(&pos_key, next_pos); continue; } if (COMP_SHORT_KEYS(rkey, &pos_key)) { goto end; } set_cpu_key_k_offset(&pos_key, le_key_k_offset(KEY_FORMAT_3_5, rkey)); } end: *pos = next_pos; pathrelse(&path_to_entry); reiserfs_check_path(&path_to_entry); out: reiserfs_write_unlock(inode->i_sb); return ret; }
// if it is not first item of the body, then it is mergeable static int indirect_is_left_mergeable(struct reiserfs_key *key, unsigned long bsize) { int version = le_key_version(key); return (le_key_k_offset(version, key) != 1); }
static int direct_is_left_mergeable (struct key * key, unsigned long bsize) { int version = le_key_version (key); return ((le_key_k_offset (version, key) & (bsize - 1)) != 1); }
int reiserfs_readdir_dentry(struct dentry *dentry, void *dirent, filldir_t filldir, loff_t *pos) { struct inode *inode = dentry->d_inode; struct cpu_key pos_key; /* key of current position in the directory (key of directory entry) */ INITIALIZE_PATH(path_to_entry); struct buffer_head *bh; int item_num, entry_num; const struct reiserfs_key *rkey; struct item_head *ih, tmp_ih; int search_res; char *local_buf; loff_t next_pos; char small_buf[32]; /* avoid kmalloc if we can */ struct reiserfs_dir_entry de; int ret = 0; reiserfs_write_lock(inode->i_sb); reiserfs_check_lock_depth(inode->i_sb, "readdir"); /* form key for search the next directory entry using f_pos field of file structure */ make_cpu_key(&pos_key, inode, *pos ?: DOT_OFFSET, TYPE_DIRENTRY, 3); next_pos = cpu_key_k_offset(&pos_key); path_to_entry.reada = PATH_READA; while (1) { research: /* search the directory item, containing entry with specified key */ search_res = search_by_entry_key(inode->i_sb, &pos_key, &path_to_entry, &de); if (search_res == IO_ERROR) { // FIXME: we could just skip part of directory which could // not be read ret = -EIO; goto out; } entry_num = de.de_entry_num; bh = de.de_bh; item_num = de.de_item_num; ih = de.de_ih; store_ih(&tmp_ih, ih); /* we must have found item, that is item of this directory, */ RFALSE(COMP_SHORT_KEYS(&(ih->ih_key), &pos_key), "vs-9000: found item %h does not match to dir we readdir %K", ih, &pos_key); RFALSE(item_num > B_NR_ITEMS(bh) - 1, "vs-9005 item_num == %d, item amount == %d", item_num, B_NR_ITEMS(bh)); /* and entry must be not more than number of entries in the item */ RFALSE(I_ENTRY_COUNT(ih) < entry_num, "vs-9010: entry number is too big %d (%d)", entry_num, I_ENTRY_COUNT(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(bh, ih) + entry_num; for (; entry_num < I_ENTRY_COUNT(ih); entry_num++, deh++) { int d_reclen; char *d_name; off_t d_off; ino_t d_ino; loff_t cur_pos = deh_offset(deh); if (!de_visible(deh)) /* it is hidden entry */ continue; d_reclen = entry_length(bh, ih, entry_num); d_name = B_I_DEH_ENTRY_FILE_NAME(bh, ih, deh); if (d_reclen <= 0 || d_name + d_reclen > bh->b_data + bh->b_size) { /* There is corrupted data in entry, * We'd better stop here */ pathrelse(&path_to_entry); ret = -EIO; goto out; } if (!d_name[d_reclen - 1]) d_reclen = strlen(d_name); if (d_reclen > REISERFS_MAX_NAME(inode->i_sb-> s_blocksize)) { /* too big to send back to VFS */ continue; } /* Ignore the .reiserfs_priv entry */ if (is_privroot_deh(dentry, deh)) continue; d_off = deh_offset(deh); *pos = d_off; d_ino = deh_objectid(deh); if (d_reclen <= 32) { local_buf = small_buf; } else { local_buf = kmalloc(d_reclen, GFP_NOFS); if (!local_buf) { pathrelse(&path_to_entry); ret = -ENOMEM; goto out; } if (item_moved(&tmp_ih, &path_to_entry)) { kfree(local_buf); goto research; } } // Note, that we copy name to user space via temporary // buffer (local_buf) because filldir will block if // user space buffer is swapped out. At that time // entry can move to somewhere else memcpy(local_buf, d_name, d_reclen); /* * Since filldir might sleep, we can release * the write lock here for other waiters */ reiserfs_write_unlock(inode->i_sb); if (filldir (dirent, local_buf, d_reclen, d_off, d_ino, DT_UNKNOWN) < 0) { reiserfs_write_lock(inode->i_sb); if (local_buf != small_buf) { kfree(local_buf); } goto end; } reiserfs_write_lock(inode->i_sb); if (local_buf != small_buf) { kfree(local_buf); } /* deh_offset(deh) may be invalid now. */ next_pos = cur_pos + 1; if (item_moved(&tmp_ih, &path_to_entry)) { set_cpu_key_k_offset(&pos_key, next_pos); goto research; } } /* for */ } if (item_num != B_NR_ITEMS(bh) - 1) // end of directory has been reached goto end; /* item we went through is last item of node. Using right delimiting key check is it directory end */ rkey = get_rkey(&path_to_entry, inode->i_sb); if (!comp_le_keys(rkey, &MIN_KEY)) { /* set pos_key to key, that is the smallest and greater that key of the last entry in the item */ set_cpu_key_k_offset(&pos_key, next_pos); continue; } if (COMP_SHORT_KEYS(rkey, &pos_key)) { // end of directory has been reached goto end; } /* directory continues in the right neighboring block */ set_cpu_key_k_offset(&pos_key, le_key_k_offset(KEY_FORMAT_3_5, rkey)); } /* while */ end: *pos = next_pos; pathrelse(&path_to_entry); reiserfs_check_path(&path_to_entry); out: reiserfs_write_unlock(inode->i_sb); return ret; }