Commit dc522adb authored by Linus Torvalds's avatar Linus Torvalds

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()
parents df3256f9 c2b67735
...@@ -898,7 +898,8 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) ...@@ -898,7 +898,8 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
brelse(bh); brelse(bh);
if (!sb_set_blocksize(sb, blocksize)) { 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; goto failed_sbi;
} }
......
...@@ -1416,10 +1416,19 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry, ...@@ -1416,10 +1416,19 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
frame->at = entries; frame->at = entries;
frame->bh = bh; frame->bh = bh;
bh = bh2; 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); 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; return retval;
}
dx_release(frames);
return add_dirent_to_buf(handle, dentry, inode, de, bh); return add_dirent_to_buf(handle, dentry, inode, de, bh);
} }
...@@ -2189,6 +2198,7 @@ static int ext3_symlink (struct inode * dir, ...@@ -2189,6 +2198,7 @@ static int ext3_symlink (struct inode * dir,
handle_t *handle; handle_t *handle;
struct inode * inode; struct inode * inode;
int l, err, retries = 0; int l, err, retries = 0;
int credits;
l = strlen(symname)+1; l = strlen(symname)+1;
if (l > dir->i_sb->s_blocksize) if (l > dir->i_sb->s_blocksize)
...@@ -2196,10 +2206,26 @@ static int ext3_symlink (struct inode * dir, ...@@ -2196,10 +2206,26 @@ static int ext3_symlink (struct inode * dir,
dquot_initialize(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: retry:
handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + handle = ext3_journal_start(dir, credits);
EXT3_INDEX_EXTRA_TRANS_BLOCKS + 5 +
EXT3_MAXQUOTAS_INIT_BLOCKS(dir->i_sb));
if (IS_ERR(handle)) if (IS_ERR(handle))
return PTR_ERR(handle); return PTR_ERR(handle);
...@@ -2211,21 +2237,45 @@ static int ext3_symlink (struct inode * dir, ...@@ -2211,21 +2237,45 @@ static int ext3_symlink (struct inode * dir,
if (IS_ERR(inode)) if (IS_ERR(inode))
goto out_stop; goto out_stop;
if (l > sizeof (EXT3_I(inode)->i_data)) { if (l > EXT3_N_BLOCKS * 4) {
inode->i_op = &ext3_symlink_inode_operations; inode->i_op = &ext3_symlink_inode_operations;
ext3_set_aops(inode); ext3_set_aops(inode);
/* /*
* page_symlink() calls into ext3_prepare/commit_write. * We cannot call page_symlink() with transaction started
* We have a transaction open. All is sweetness. It also sets * because it calls into ext3_write_begin() which acquires page
* i_size in generic_commit_write(). * 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); 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) { if (err) {
ext3_journal_stop(handle);
drop_nlink(inode); drop_nlink(inode);
unlock_new_inode(inode); goto err_drop_inode;
ext3_mark_inode_dirty(handle, inode);
iput (inode);
goto out_stop;
} }
} else { } else {
inode->i_op = &ext3_fast_symlink_inode_operations; inode->i_op = &ext3_fast_symlink_inode_operations;
...@@ -2239,6 +2289,10 @@ static int ext3_symlink (struct inode * dir, ...@@ -2239,6 +2289,10 @@ static int ext3_symlink (struct inode * dir,
if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries)) if (err == -ENOSPC && ext3_should_retry_alloc(dir->i_sb, &retries))
goto retry; goto retry;
return err; return err;
err_drop_inode:
unlock_new_inode(inode);
iput(inode);
return err;
} }
static int ext3_link (struct dentry * old_dentry, static int ext3_link (struct dentry * old_dentry,
......
...@@ -302,12 +302,6 @@ void journal_commit_transaction(journal_t *journal) ...@@ -302,12 +302,6 @@ void journal_commit_transaction(journal_t *journal)
* all outstanding updates to complete. * 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? */ /* Do we need to erase the effects of a prior journal_flush? */
if (journal->j_flags & JFS_FLUSHED) { if (journal->j_flags & JFS_FLUSHED) {
jbd_debug(3, "super block updated\n"); jbd_debug(3, "super block updated\n");
...@@ -722,8 +716,13 @@ void journal_commit_transaction(journal_t *journal) ...@@ -722,8 +716,13 @@ void journal_commit_transaction(journal_t *journal)
required. */ required. */
JBUFFER_TRACE(jh, "file as BJ_Forget"); JBUFFER_TRACE(jh, "file as BJ_Forget");
journal_file_buffer(jh, commit_transaction, 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); wake_up_bit(&bh->b_state, BH_Unshadow);
JBUFFER_TRACE(jh, "brelse shadowed buffer"); JBUFFER_TRACE(jh, "brelse shadowed buffer");
__brelse(bh); __brelse(bh);
......
...@@ -437,9 +437,12 @@ int __log_space_left(journal_t *journal) ...@@ -437,9 +437,12 @@ int __log_space_left(journal_t *journal)
int __log_start_commit(journal_t *journal, tid_t target) 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 * We want a new commit: OK, mark the request and wakeup the
* commit thread. We do _not_ do the commit ourselves. * commit thread. We do _not_ do the commit ourselves.
...@@ -451,7 +454,14 @@ int __log_start_commit(journal_t *journal, tid_t target) ...@@ -451,7 +454,14 @@ int __log_start_commit(journal_t *journal, tid_t target)
journal->j_commit_sequence); journal->j_commit_sequence);
wake_up(&journal->j_wait_commit); wake_up(&journal->j_wait_commit);
return 1; 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; return 0;
} }
......
...@@ -266,7 +266,8 @@ static handle_t *new_handle(int nblocks) ...@@ -266,7 +266,8 @@ static handle_t *new_handle(int nblocks)
* This function is visible to journal users (like ext3fs), so is not * This function is visible to journal users (like ext3fs), so is not
* called with the journal already locked. * 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) handle_t *journal_start(journal_t *journal, int nblocks)
{ {
......
...@@ -338,12 +338,6 @@ void jbd2_journal_commit_transaction(journal_t *journal) ...@@ -338,12 +338,6 @@ void jbd2_journal_commit_transaction(journal_t *journal)
* all outstanding updates to complete. * 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? */ /* Do we need to erase the effects of a prior jbd2_journal_flush? */
if (journal->j_flags & JBD2_FLUSHED) { if (journal->j_flags & JBD2_FLUSHED) {
jbd_debug(3, "super block updated\n"); jbd_debug(3, "super block updated\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment