static int reiserfs_find_entry (struct inode * dir, const char * name, int namelen, struct path * path_to_entry, struct reiserfs_dir_entry * de) { struct key key_to_search; int repeat; int retval; if (!dir || !dir->i_sb) return POSITION_NOT_FOUND; if ((unsigned int)namelen > REISERFS_MAX_NAME_LEN (dir->i_sb->s_blocksize)) return POSITION_NOT_FOUND; /* there are no entries having the same third component of key, so fourth key component is not used */ copy_key (&key_to_search, INODE_PKEY (dir)); key_to_search.k_offset = get_third_component (name, namelen); key_to_search.k_uniqueness = DIRENTRY_UNIQUENESS; while (1) { /* search for a directory item using the formed key */ if (search_by_key (dir->i_sb, &key_to_search, path_to_entry, &repeat, DISK_LEAF_NODE_LEVEL, READ_BLOCKS) == ITEM_NOT_FOUND) { /* take previous item */ #ifdef REISERFS_CHECK if (!PATH_LAST_POSITION (path_to_entry)) reiserfs_panic (dir->i_sb, "vs-7010: reiserfs_find_entry: search_by_key returned bad position == 0"); #endif /* REISERFS_CHECK */ PATH_LAST_POSITION (path_to_entry) --; } de->de_bh = PATH_PLAST_BUFFER (path_to_entry); de->de_item_num = PATH_LAST_POSITION (path_to_entry); de->de_ih = B_N_PITEM_HEAD (de->de_bh, de->de_item_num); de->de_deh = B_I_DEH (de->de_bh, de->de_ih); #ifdef REISERFS_CHECK if (!I_IS_DIRECTORY_ITEM (de->de_ih) || COMP_SHORT_KEYS (&(de->de_ih->ih_key), INODE_PKEY (dir))) reiserfs_panic (dir->i_sb, "vs-7020: reiserfs_find_entry: item must be an item of the same directory item as inode"); #endif /* REISERFS_CHECK */ /* we do not check whether bin_search_in_dir_item found the given key, even if so, we still have to compare names */ bin_search_in_dir_item (de->de_ih, de->de_deh, &key_to_search, &(de->de_entry_num)); /* compare names for all entries having given hash value */ 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 */ return retval; /* there is left neighboring item of this directory and given entry can be there */ key_to_search.k_offset = de->de_ih->ih_key.k_offset - 1; pathrelse (path_to_entry); } /* while (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) */ }
/* * may return NAME_FOUND, NAME_FOUND_INVISIBLE, NAME_NOT_FOUND * FIXME: should add something like IOERROR */ static int reiserfs_find_entry(struct inode *dir, const char *name, int namelen, struct treepath *path_to_entry, struct reiserfs_dir_entry *de) { struct cpu_key key_to_search; int retval; if (namelen > REISERFS_MAX_NAME(dir->i_sb->s_blocksize)) return NAME_NOT_FOUND; /* we will search for this key in the tree */ make_cpu_key(&key_to_search, dir, get_third_component(dir->i_sb, name, namelen), TYPE_DIRENTRY, 3); while (1) { retval = search_by_entry_key(dir->i_sb, &key_to_search, path_to_entry, de); if (retval == IO_ERROR) { reiserfs_error(dir->i_sb, "zam-7001", "io error"); return IO_ERROR; } /* compare names for all entries having given hash value */ retval = linear_search_in_dir_item(&key_to_search, de, name, namelen); /* * there is no need to scan directory anymore. * Given entry found or does not exist */ if (retval != GOTO_PREVIOUS_ITEM) { 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 reiserfs_add_entry(struct reiserfs_transaction_handle *th, struct inode *dir, const char *name, int namelen, struct inode *inode, int visible) { struct cpu_key entry_key; struct reiserfs_de_head *deh; INITIALIZE_PATH(path); struct reiserfs_dir_entry de; DECLARE_BITMAP(bit_string, MAX_GENERATION_NUMBER + 1); int gen_number; char small_buf[32 + DEH_SIZE]; /* 48 bytes now and we avoid kmalloc if we create file with short name */ char *buffer; int buflen, paste_size; int retval; BUG_ON(!th->t_trans_id); /* cannot allow items to be added into a busy deleted directory */ if (!namelen) return -EINVAL; if (namelen > REISERFS_MAX_NAME(dir->i_sb->s_blocksize)) return -ENAMETOOLONG; /* each entry has unique key. compose it */ make_cpu_key(&entry_key, dir, get_third_component(dir->i_sb, name, namelen), TYPE_DIRENTRY, 3); /* get memory for composing the entry */ buflen = DEH_SIZE + ROUND_UP(namelen); if (buflen > sizeof(small_buf)) { buffer = kmalloc(buflen, GFP_NOFS); if (!buffer) return -ENOMEM; } else buffer = small_buf; paste_size = (get_inode_sd_version(dir) == STAT_DATA_V1) ? (DEH_SIZE + namelen) : buflen; /* fill buffer : directory entry head, name[, dir objectid | , stat data | ,stat data, dir objectid ] */ deh = (struct reiserfs_de_head *)buffer; deh->deh_location = 0; /* JDM Endian safe if 0 */ put_deh_offset(deh, cpu_key_k_offset(&entry_key)); deh->deh_state = 0; /* JDM Endian safe if 0 */ /* put key (ino analog) to de */ deh->deh_dir_id = INODE_PKEY(inode)->k_dir_id; /* safe: k_dir_id is le */ deh->deh_objectid = INODE_PKEY(inode)->k_objectid; /* safe: k_objectid is le */ /* copy name */ memcpy((char *)(deh + 1), name, namelen); /* padd by 0s to the 4 byte boundary */ padd_item((char *)(deh + 1), ROUND_UP(namelen), namelen); /* entry is ready to be pasted into tree, set 'visibility' and 'stat data in entry' attributes */ mark_de_without_sd(deh); visible ? mark_de_visible(deh) : mark_de_hidden(deh); /* find the proper place for the new entry */ memset(bit_string, 0, sizeof(bit_string)); de.de_gen_number_bit_string = bit_string; retval = reiserfs_find_entry(dir, name, namelen, &path, &de); if (retval != NAME_NOT_FOUND) { if (buffer != small_buf) kfree(buffer); pathrelse(&path); if (retval == IO_ERROR) { return -EIO; } if (retval != NAME_FOUND) { reiserfs_error(dir->i_sb, "zam-7002", "reiserfs_find_entry() returned " "unexpected value (%d)", retval); } return -EEXIST; } gen_number = find_first_zero_bit(bit_string, MAX_GENERATION_NUMBER + 1); if (gen_number > MAX_GENERATION_NUMBER) { /* there is no free generation number */ reiserfs_warning(dir->i_sb, "reiserfs-7010", "Congratulations! we have got hash function " "screwed up"); if (buffer != small_buf) kfree(buffer); pathrelse(&path); return -EBUSY; } /* adjust offset of directory enrty */ put_deh_offset(deh, SET_GENERATION_NUMBER(deh_offset(deh), gen_number)); set_cpu_key_k_offset(&entry_key, deh_offset(deh)); /* update max-hash-collisions counter in reiserfs_sb_info */ PROC_INFO_MAX(th->t_super, max_hash_collisions, gen_number); if (gen_number != 0) { /* we need to re-search for the insertion point */ if (search_by_entry_key(dir->i_sb, &entry_key, &path, &de) != NAME_NOT_FOUND) { reiserfs_warning(dir->i_sb, "vs-7032", "entry with this key (%K) already " "exists", &entry_key); if (buffer != small_buf) kfree(buffer); pathrelse(&path); return -EBUSY; } } /* perform the insertion of the entry that we have prepared */ retval = reiserfs_paste_into_item(th, &path, &entry_key, dir, buffer, paste_size); if (buffer != small_buf) kfree(buffer); if (retval) { reiserfs_check_path(&path); return retval; } dir->i_size += paste_size; dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; if (!S_ISDIR(inode->i_mode) && visible) // reiserfs_mkdir or reiserfs_rename will do that by itself reiserfs_update_sd(th, dir); reiserfs_check_path(&path); return 0; }
/* add entry to the directory (entry can be hidden). Does not mark dir inode dirty, do it after successesfull call to it */ static int reiserfs_add_entry (struct reiserfs_transaction_handle *th, struct inode * dir, const char * name, int namelen, struct key * object_key, struct reiserfs_dir_entry * de, int visible ) { struct key entry_key; char * buffer; int buflen; struct reiserfs_de_head * deh; struct path path; char bit_string [MAX_GEN_NUMBER / 8 + 1]; int gen_number; int repeat; #ifdef REISERFS_ALIGNED int aligned_namelen = (namelen+3) & ~3; #endif init_path (&path); if (!dir || !dir->i_sb) return -ENOENT; if ((unsigned int)namelen > REISERFS_MAX_NAME_LEN (dir->i_sb->s_blocksize)) return -ENAMETOOLONG; /* each entry has unique key. compose it */ copy_key (&entry_key, INODE_PKEY(dir)); entry_key.k_offset = get_third_component (name, namelen); entry_key.k_uniqueness = DIRENTRY_UNIQUENESS; /* get memory for composing the entry */ #ifdef REISERFS_ALIGNED buflen = DEH_SIZE + aligned_namelen; #else buflen = DEH_SIZE + namelen; #endif buffer = reiserfs_kmalloc (buflen, GFP_KERNEL, dir->i_sb); if (buffer == 0) return -ENOMEM; /* fill buffer : directory entry head, name[, dir objectid | , stat data | ,stat data, dir objectid ] */ deh = (struct reiserfs_de_head *)buffer; deh->deh_location = 0; deh->deh_offset = entry_key.k_offset; deh->deh_state = 0; /* put key (ino analog) to de */ deh->deh_dir_id = object_key->k_dir_id; deh->deh_objectid = object_key->k_objectid; /* copy name */ #ifdef REISERFS_ALIGNED memset( (char*)(deh+1), '\0', aligned_namelen ); #endif memcpy ((char *)(deh + 1), name, namelen); /* entry is ready to be pasted into tree, set 'visibility' and 'stat data in entry' attributes */ mark_de_without_sd (deh); visible ? mark_de_visible (deh) : mark_de_hidden (deh); /* find the proper place for the new entry */ memset (bit_string, 0, sizeof (bit_string)); de->de_gen_number_bit_string = bit_string; if (reiserfs_find_entry (dir, name, namelen, &path, de) == POSITION_FOUND) { reiserfs_panic (dir->i_sb, "vs-7030: reiserfs_add_entry: entry with this key %k already exists", &entry_key); } if (find_first_nonzero_bit (bit_string, MAX_GEN_NUMBER + 1) < MAX_GEN_NUMBER + 1) { /* there are few names with given hash value */ gen_number = find_first_zero_bit (bit_string, MAX_GEN_NUMBER + 1); if (gen_number > MAX_GEN_NUMBER) { /* there is no free generation number */ reiserfs_kfree (buffer, buflen, dir->i_sb); pathrelse (&path); return -EHASHCOLLISION; } /* adjust offset of directory enrty */ deh->deh_offset = SET_GENERATION_NUMBER (deh->deh_offset, gen_number); entry_key.k_offset = deh->deh_offset; /* find place for new entry */ if (search_by_entry_key (dir->i_sb, &entry_key, &path, &(de->de_entry_num), &repeat)) { reiserfs_panic (dir->i_sb, "reiserfs_add_entry: 7032: entry with this key (%k) already exists", &entry_key); } } else { deh->deh_offset = SET_GENERATION_NUMBER (deh->deh_offset, 0); entry_key.k_offset = deh->deh_offset; } /* perform the insertion of the entry that we have prepared */ if (reiserfs_paste_into_item (th, dir->i_sb, &path, &(de->de_entry_num), &entry_key, buffer, buflen, REISERFS_KERNEL_MEM, 0) == -1) { reiserfs_kfree (buffer, buflen, dir->i_sb); return -ENOSPC; } reiserfs_kfree (buffer, buflen, dir->i_sb); dir->i_size += buflen; dir->i_mtime = dir->i_ctime = CURRENT_TIME; return 0; }