X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fext3%2Fnamei.c;h=36e5b4ec3daffbd9ae0d99f02f0bb783f5b057e1;hb=9bf4aaab3e101692164d49b7ca357651eb691cb6;hp=6ed3d4ff2bd9f981e5b521c4506563d1b1618152;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index 6ed3d4ff2..36e5b4ec3 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c @@ -557,6 +557,8 @@ static int htree_dirblock_to_tree(struct file *dir_file, ((hinfo->hash == start_hash) && (hinfo->minor_hash < start_minor_hash))) continue; + if (de->inode == 0) + continue; if ((err = ext3_htree_store_dirent(dir_file, hinfo->hash, hinfo->minor_hash, de)) != 0) { brelse(bh); @@ -602,7 +604,7 @@ int ext3_htree_fill_tree(struct file *dir_file, __u32 start_hash, } hinfo.hash = start_hash; hinfo.minor_hash = 0; - frame = dx_probe(0, dir_file->f_dentry->d_inode, &hinfo, frames, &err); + frame = dx_probe(NULL, dir_file->f_dentry->d_inode, &hinfo, frames, &err); if (!frame) return err; @@ -872,6 +874,8 @@ restart: wait_on_buffer(bh); if (!buffer_uptodate(bh)) { /* read error, skip block & hope for the best */ + ext3_error(sb, __FUNCTION__, "reading directory #%lu " + "offset %lu\n", dir->i_ino, block); brelse(bh); goto next; } @@ -926,7 +930,7 @@ static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry, struct inode *dir = dentry->d_parent->d_inode; sb = dir->i_sb; - if (!(frame = dx_probe (dentry, 0, &hinfo, frames, err))) + if (!(frame = dx_probe(dentry, NULL, &hinfo, frames, err))) return NULL; hash = hinfo.hash; do { @@ -952,7 +956,7 @@ static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry, brelse (bh); /* Check to see if we should continue to search */ retval = ext3_htree_next_block(dir, hash, frame, - frames, 0); + frames, NULL); if (retval < 0) { ext3_warning(sb, __FUNCTION__, "error reading index page in directory #%lu", @@ -1388,7 +1392,7 @@ static int ext3_add_entry (handle_t *handle, struct dentry *dentry, bh = ext3_bread(handle, dir, block, 0, &retval); if(!bh) return retval; - retval = add_dirent_to_buf(handle, dentry, inode, 0, bh); + retval = add_dirent_to_buf(handle, dentry, inode, NULL, bh); if (retval != -ENOSPC) return retval; @@ -1425,7 +1429,7 @@ static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry, struct ext3_dir_entry_2 *de; int err; - frame = dx_probe(dentry, 0, &hinfo, frames, &err); + frame = dx_probe(dentry, NULL, &hinfo, frames, &err); if (!frame) return err; entries = frame->entries; @@ -1439,9 +1443,9 @@ static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry, if (err) goto journal_error; - err = add_dirent_to_buf(handle, dentry, inode, 0, bh); + err = add_dirent_to_buf(handle, dentry, inode, NULL, bh); if (err != -ENOSPC) { - bh = 0; + bh = NULL; goto cleanup; } @@ -1533,7 +1537,7 @@ static int ext3_dx_add_entry(handle_t *handle, struct dentry *dentry, if (!de) goto cleanup; err = add_dirent_to_buf(handle, dentry, inode, de, bh); - bh = 0; + bh = NULL; goto cleanup; journal_error: @@ -1628,8 +1632,9 @@ static int ext3_create (struct inode * dir, struct dentry * dentry, int mode, { handle_t *handle; struct inode * inode; - int err; + int err, retries = 0; +retry: handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 + 2*EXT3_QUOTA_INIT_BLOCKS); @@ -1648,6 +1653,8 @@ static int ext3_create (struct inode * dir, struct dentry * dentry, int mode, err = ext3_add_nondir(handle, dentry, inode); } ext3_journal_stop(handle); + if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries)) + goto retry; return err; } @@ -1656,11 +1663,12 @@ static int ext3_mknod (struct inode * dir, struct dentry *dentry, { handle_t *handle; struct inode *inode; - int err; + int err, retries = 0; if (!new_valid_dev(rdev)) return -EINVAL; +retry: handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 + 2*EXT3_QUOTA_INIT_BLOCKS); @@ -1680,6 +1688,8 @@ static int ext3_mknod (struct inode * dir, struct dentry *dentry, err = ext3_add_nondir(handle, dentry, inode); } ext3_journal_stop(handle); + if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries)) + goto retry; return err; } @@ -1689,11 +1699,12 @@ static int ext3_mkdir(struct inode * dir, struct dentry * dentry, int mode) struct inode * inode; struct buffer_head * dir_block; struct ext3_dir_entry_2 * de; - int err; + int err, retries = 0; if (dir->i_nlink >= EXT3_LINK_MAX) return -EMLINK; +retry: handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 + 2*EXT3_QUOTA_INIT_BLOCKS); @@ -1751,6 +1762,8 @@ static int ext3_mkdir(struct inode * dir, struct dentry * dentry, int mode) d_instantiate(dentry, inode); out_stop: ext3_journal_stop(handle); + if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries)) + goto retry; return err; } @@ -1763,14 +1776,19 @@ static int empty_dir (struct inode * inode) struct buffer_head * bh; struct ext3_dir_entry_2 * de, * de1; struct super_block * sb; - int err; + int err = 0; sb = inode->i_sb; if (inode->i_size < EXT3_DIR_REC_LEN(1) + EXT3_DIR_REC_LEN(2) || !(bh = ext3_bread (NULL, inode, 0, 0, &err))) { - ext3_warning (inode->i_sb, "empty_dir", - "bad directory (dir #%lu) - no data block", - inode->i_ino); + if (err) + ext3_error(inode->i_sb, __FUNCTION__, + "error %d reading directory #%lu offset 0", + err, inode->i_ino); + else + ext3_warning(inode->i_sb, __FUNCTION__, + "bad directory (dir #%lu) - no data block", + inode->i_ino); return 1; } de = (struct ext3_dir_entry_2 *) bh->b_data; @@ -1792,24 +1810,26 @@ static int empty_dir (struct inode * inode) while (offset < inode->i_size ) { if (!bh || (void *) de >= (void *) (bh->b_data+sb->s_blocksize)) { + err = 0; brelse (bh); bh = ext3_bread (NULL, inode, offset >> EXT3_BLOCK_SIZE_BITS(sb), 0, &err); if (!bh) { -#if 0 - ext3_error (sb, "empty_dir", - "directory #%lu contains a hole at offset %lu", - inode->i_ino, offset); -#endif + if (err) + ext3_error(sb, __FUNCTION__, + "error %d reading directory" + " #%lu offset %lu", + err, inode->i_ino, offset); offset += sb->s_blocksize; continue; } de = (struct ext3_dir_entry_2 *) bh->b_data; } - if (!ext3_check_dir_entry ("empty_dir", inode, de, bh, - offset)) { - brelse (bh); - return 1; + if (!ext3_check_dir_entry("empty_dir", inode, de, bh, offset)) { + de = (struct ext3_dir_entry_2 *)(bh->b_data + + sb->s_blocksize); + offset = (offset | (sb->s_blocksize - 1)) + 1; + continue; } if (le32_to_cpu(de->inode)) { brelse (bh); @@ -1953,8 +1973,6 @@ int ext3_orphan_del(handle_t *handle, struct inode *inode) goto out_brelse; NEXT_ORPHAN(inode) = 0; err = ext3_mark_iloc_dirty(handle, inode, &iloc); - if (err) - goto out_brelse; out_err: ext3_std_error(inode->i_sb, err); @@ -2085,12 +2103,13 @@ static int ext3_symlink (struct inode * dir, { handle_t *handle; struct inode * inode; - int l, err; + int l, err, retries = 0; l = strlen(symname)+1; if (l > dir->i_sb->s_blocksize) return -ENAMETOOLONG; +retry: handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + EXT3_INDEX_EXTRA_TRANS_BLOCKS + 5 + 2*EXT3_QUOTA_INIT_BLOCKS); @@ -2129,6 +2148,8 @@ static int ext3_symlink (struct inode * dir, err = ext3_add_nondir(handle, dentry, inode); out_stop: ext3_journal_stop(handle); + if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries)) + goto retry; return err; } @@ -2137,11 +2158,12 @@ static int ext3_link (struct dentry * old_dentry, { handle_t *handle; struct inode *inode = old_dentry->d_inode; - int err; + int err, retries = 0; if (inode->i_nlink >= EXT3_LINK_MAX) return -EMLINK; +retry: handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS + EXT3_INDEX_EXTRA_TRANS_BLOCKS); if (IS_ERR(handle)) @@ -2156,6 +2178,8 @@ static int ext3_link (struct dentry * old_dentry, err = ext3_add_nondir(handle, dentry, inode); ext3_journal_stop(handle); + if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries)) + goto retry; return err; } @@ -2255,11 +2279,15 @@ static int ext3_rename (struct inode * old_dir, struct dentry *old_dentry, /* * ok, that's it */ - retval = ext3_delete_entry(handle, old_dir, old_de, old_bh); - if (retval == -ENOENT) { - /* - * old_de could have moved out from under us. - */ + if (le32_to_cpu(old_de->inode) != old_inode->i_ino || + old_de->name_len != old_dentry->d_name.len || + strncmp(old_de->name, old_dentry->d_name.name, old_de->name_len) || + (retval = ext3_delete_entry(handle, old_dir, + old_de, old_bh)) == -ENOENT) { + /* old_de could have moved from under us during htree split, so + * make sure that we are deleting the right entry. We might + * also be pointing to a stale entry in the unused part of + * old_bh so just checking inum and the name isn't enough. */ struct buffer_head *old_bh2; struct ext3_dir_entry_2 *old_de2;