VServer 1.9.2 (patch-2.6.8.1-vs1.9.2.diff)
[linux-2.6.git] / fs / ext3 / namei.c
index 6ed3d4f..36e5b4e 100644 (file)
@@ -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;