Merge branch 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs-2.6
* 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs-2.6: jbd: Fix comment to match the code in journal_start() jbd/jbd2: remove obsolete summarise_journal_usage. jbd: Fix forever sleeping process in do_get_write_access() ext2: fix error msg when mounting fs with too-large blocksize jbd: fix fsync() tid wraparound bug ext3: Fix fs corruption when make_indexed_dir() fails ext3: Fix lock inversion in ext3_symlink()
This commit is contained in:
commit
dc522adbee
@ -898,7 +898,8 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
|
||||
brelse(bh);
|
||||
|
||||
if (!sb_set_blocksize(sb, blocksize)) {
|
||||
ext2_msg(sb, KERN_ERR, "error: blocksize is too small");
|
||||
ext2_msg(sb, KERN_ERR,
|
||||
"error: bad blocksize %d", blocksize);
|
||||
goto failed_sbi;
|
||||
}
|
||||
|
||||
|
@ -1416,10 +1416,19 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
|
||||
frame->at = entries;
|
||||
frame->bh = bh;
|
||||
bh = bh2;
|
||||
/*
|
||||
* Mark buffers dirty here so that if do_split() fails we write a
|
||||
* consistent set of buffers to disk.
|
||||
*/
|
||||
ext3_journal_dirty_metadata(handle, frame->bh);
|
||||
ext3_journal_dirty_metadata(handle, bh);
|
||||
de = do_split(handle,dir, &bh, frame, &hinfo, &retval);
|
||||
dx_release (frames);
|
||||
if (!(de))
|
||||
if (!de) {
|
||||
ext3_mark_inode_dirty(handle, dir);
|
||||
dx_release(frames);
|
||||
return retval;
|
||||
}
|
||||
dx_release(frames);
|
||||
|
||||
return add_dirent_to_buf(handle, dentry, inode, de, bh);
|
||||
}
|
||||
@ -2189,6 +2198,7 @@ static int ext3_symlink (struct inode * dir,
|
||||
handle_t *handle;
|
||||
struct inode * inode;
|
||||
int l, err, retries = 0;
|
||||
int credits;
|
||||
|
||||
l = strlen(symname)+1;
|
||||
if (l > dir->i_sb->s_blocksize)
|
||||
@ -2196,10 +2206,26 @@ static int ext3_symlink (struct inode * dir,
|
||||
|
||||
dquot_initialize(dir);
|
||||
|
||||
if (l > EXT3_N_BLOCKS * 4) {
|
||||
/*
|
||||
* For non-fast symlinks, we just allocate inode and put it on
|
||||
* orphan list in the first transaction => we need bitmap,
|
||||
* group descriptor, sb, inode block, quota blocks.
|
||||
*/
|
||||
credits = 4 + EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb);
|
||||
} else {
|
||||
/*
|
||||
* Fast symlink. We have to add entry to directory
|
||||
* (EXT3_DATA_TRANS_BLOCKS + EXT3_INDEX_EXTRA_TRANS_BLOCKS),
|
||||
* allocate new inode (bitmap, group descriptor, inode block,
|
||||
* quota blocks, sb is already counted in previous macros).
|
||||
*/
|
||||
credits = EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
|
||||
EXT3_INDEX_EXTRA_TRANS_BLOCKS + 3 +
|
||||
EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb);
|
||||
}
|
||||
retry:
|
||||
handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
|
||||
EXT3_INDEX_EXTRA_TRANS_BLOCKS + 5 +
|
||||
EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb));
|
||||
handle = ext3_journal_start(dir, credits);
|
||||
if (IS_ERR(handle))
|
||||
return PTR_ERR(handle);
|
||||
|
||||
@ -2211,21 +2237,45 @@ static int ext3_symlink (struct inode * dir,
|
||||
if (IS_ERR(inode))
|
||||
goto out_stop;
|
||||
|
||||
if (l > sizeof (EXT3_I(inode)->i_data)) {
|
||||
if (l > EXT3_N_BLOCKS * 4) {
|
||||
inode->i_op = &ext3_symlink_inode_operations;
|
||||
ext3_set_aops(inode);
|
||||
/*
|
||||
* page_symlink() calls into ext3_prepare/commit_write.
|
||||
* We have a transaction open. All is sweetness. It also sets
|
||||
* i_size in generic_commit_write().
|
||||
* We cannot call page_symlink() with transaction started
|
||||
* because it calls into ext3_write_begin() which acquires page
|
||||
* lock which ranks below transaction start (and it can also
|
||||
* wait for journal commit if we are running out of space). So
|
||||
* we have to stop transaction now and restart it when symlink
|
||||
* contents is written.
|
||||
*
|
||||
* To keep fs consistent in case of crash, we have to put inode
|
||||
* to orphan list in the mean time.
|
||||
*/
|
||||
drop_nlink(inode);
|
||||
err = ext3_orphan_add(handle, inode);
|
||||
ext3_journal_stop(handle);
|
||||
if (err)
|
||||
goto err_drop_inode;
|
||||
err = __page_symlink(inode, symname, l, 1);
|
||||
if (err)
|
||||
goto err_drop_inode;
|
||||
/*
|
||||
* Now inode is being linked into dir (EXT3_DATA_TRANS_BLOCKS
|
||||
* + EXT3_INDEX_EXTRA_TRANS_BLOCKS), inode is also modified
|
||||
*/
|
||||
handle = ext3_journal_start(dir,
|
||||
EXT3_DATA_TRANS_BLOCKS(dir->i_sb) +
|
||||
EXT3_INDEX_EXTRA_TRANS_BLOCKS + 1);
|
||||
if (IS_ERR(handle)) {
|
||||
err = PTR_ERR(handle);
|
||||
goto err_drop_inode;
|
||||
}
|
||||
inc_nlink(inode);
|
||||
err = ext3_orphan_del(handle, inode);
|
||||
if (err) {
|
||||
ext3_journal_stop(handle);
|
||||
drop_nlink(inode);
|
||||
unlock_new_inode(inode);
|
||||
ext3_mark_inode_dirty(handle, inode);
|
||||
iput (inode);
|
||||
goto out_stop;
|
||||
goto err_drop_inode;
|
||||
}
|
||||
} else {
|
||||
inode->i_op = &ext3_fast_symlink_inode_operations;
|
||||
@ -2239,6 +2289,10 @@ static int ext3_symlink (struct inode * dir,
|
||||
if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries))
|
||||
goto retry;
|
||||
return err;
|
||||
err_drop_inode:
|
||||
unlock_new_inode(inode);
|
||||
iput(inode);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ext3_link (struct dentry * old_dentry,
|
||||
|
@ -302,12 +302,6 @@ void journal_commit_transaction(journal_t *journal)
|
||||
* all outstanding updates to complete.
|
||||
*/
|
||||
|
||||
#ifdef COMMIT_STATS
|
||||
spin_lock(&journal->j_list_lock);
|
||||
summarise_journal_usage(journal);
|
||||
spin_unlock(&journal->j_list_lock);
|
||||
#endif
|
||||
|
||||
/* Do we need to erase the effects of a prior journal_flush? */
|
||||
if (journal->j_flags & JFS_FLUSHED) {
|
||||
jbd_debug(3, "super block updated\n");
|
||||
@ -722,8 +716,13 @@ void journal_commit_transaction(journal_t *journal)
|
||||
required. */
|
||||
JBUFFER_TRACE(jh, "file as BJ_Forget");
|
||||
journal_file_buffer(jh, commit_transaction, BJ_Forget);
|
||||
/* Wake up any transactions which were waiting for this
|
||||
IO to complete */
|
||||
/*
|
||||
* Wake up any transactions which were waiting for this
|
||||
* IO to complete. The barrier must be here so that changes
|
||||
* by journal_file_buffer() take effect before wake_up_bit()
|
||||
* does the waitqueue check.
|
||||
*/
|
||||
smp_mb();
|
||||
wake_up_bit(&bh->b_state, BH_Unshadow);
|
||||
JBUFFER_TRACE(jh, "brelse shadowed buffer");
|
||||
__brelse(bh);
|
||||
|
@ -437,9 +437,12 @@ int __log_space_left(journal_t *journal)
|
||||
int __log_start_commit(journal_t *journal, tid_t target)
|
||||
{
|
||||
/*
|
||||
* Are we already doing a recent enough commit?
|
||||
* The only transaction we can possibly wait upon is the
|
||||
* currently running transaction (if it exists). Otherwise,
|
||||
* the target tid must be an old one.
|
||||
*/
|
||||
if (!tid_geq(journal->j_commit_request, target)) {
|
||||
if (journal->j_running_transaction &&
|
||||
journal->j_running_transaction->t_tid == target) {
|
||||
/*
|
||||
* We want a new commit: OK, mark the request and wakeup the
|
||||
* commit thread. We do _not_ do the commit ourselves.
|
||||
@ -451,7 +454,14 @@ int __log_start_commit(journal_t *journal, tid_t target)
|
||||
journal->j_commit_sequence);
|
||||
wake_up(&journal->j_wait_commit);
|
||||
return 1;
|
||||
}
|
||||
} else if (!tid_geq(journal->j_commit_request, target))
|
||||
/* This should never happen, but if it does, preserve
|
||||
the evidence before kjournald goes into a loop and
|
||||
increments j_commit_sequence beyond all recognition. */
|
||||
WARN_ONCE(1, "jbd: bad log_start_commit: %u %u %u %u\n",
|
||||
journal->j_commit_request, journal->j_commit_sequence,
|
||||
target, journal->j_running_transaction ?
|
||||
journal->j_running_transaction->t_tid : 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -266,7 +266,8 @@ static handle_t *new_handle(int nblocks)
|
||||
* This function is visible to journal users (like ext3fs), so is not
|
||||
* called with the journal already locked.
|
||||
*
|
||||
* Return a pointer to a newly allocated handle, or NULL on failure
|
||||
* Return a pointer to a newly allocated handle, or an ERR_PTR() value
|
||||
* on failure.
|
||||
*/
|
||||
handle_t *journal_start(journal_t *journal, int nblocks)
|
||||
{
|
||||
|
@ -338,12 +338,6 @@ void jbd2_journal_commit_transaction(journal_t *journal)
|
||||
* all outstanding updates to complete.
|
||||
*/
|
||||
|
||||
#ifdef COMMIT_STATS
|
||||
spin_lock(&journal->j_list_lock);
|
||||
summarise_journal_usage(journal);
|
||||
spin_unlock(&journal->j_list_lock);
|
||||
#endif
|
||||
|
||||
/* Do we need to erase the effects of a prior jbd2_journal_flush? */
|
||||
if (journal->j_flags & JBD2_FLUSHED) {
|
||||
jbd_debug(3, "super block updated\n");
|
||||
|
Loading…
Reference in New Issue
Block a user