Commit 2ac232f3 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: change the field "b_cow_tid" of struct journal_head from type unsigned to tid_t
  ext3.txt: update the links in the section "useful links" to the latest ones
  ext3: Fix data corruption in inodes with journalled data
  ext2: check xattr name_len before acquiring xattr_sem in ext2_xattr_get
  ext3: Fix compilation with -DDX_DEBUG
  quota: Remove unused declaration
  jbd: Use WRITE_SYNC in journal checkpoint.
  jbd: Fix oops in journal_remove_journal_head()
  ext3: Return -EINVAL when start is beyond the end of fs in ext3_trim_fs()
  ext3/ioctl.c: silence sparse warnings about different address spaces
  ext3/ext4 Documentation: remove bh/nobh since it has been deprecated
  ext3: Improve truncate error handling
  ext3: use proper little-endian bitops
  ext2: include fs.h into ext2_fs.h
  ext3: Fix oops in ext3_try_to_allocate_with_rsv()
  jbd: fix a bug of leaking jh->b_jcount
  jbd: remove dependency on __GFP_NOFAIL
  ext3: Convert ext3 to new truncate calling convention
  jbd: Add fixed tracepoints
  ext3: Add fixed tracepoints

Resolve conflicts in fs/ext3/fsync.c due to fsync locking push-down and
new fixed tracepoints.
parents fa8f53ac 5cf49d76
...@@ -147,15 +147,6 @@ grpjquota=<file> during journal replay. They replace the above ...@@ -147,15 +147,6 @@ grpjquota=<file> during journal replay. They replace the above
package for more details package for more details
(http://sourceforge.net/projects/linuxquota). (http://sourceforge.net/projects/linuxquota).
bh (*) ext3 associates buffer heads to data pages to
nobh (a) cache disk block mapping information
(b) link pages into transaction to provide
ordering guarantees.
"bh" option forces use of buffer heads.
"nobh" option tries to avoid associating buffer
heads (supported only for "writeback" mode).
Specification Specification
============= =============
Ext3 shares all disk implementation with the ext2 filesystem, and adds Ext3 shares all disk implementation with the ext2 filesystem, and adds
...@@ -227,5 +218,5 @@ kernel source: <file:fs/ext3/> ...@@ -227,5 +218,5 @@ kernel source: <file:fs/ext3/>
programs: http://e2fsprogs.sourceforge.net/ programs: http://e2fsprogs.sourceforge.net/
http://ext2resize.sourceforge.net http://ext2resize.sourceforge.net
useful links: http://www.ibm.com/developerworks/library/l-fs7.html useful links: http://www.ibm.com/developerworks/library/l-fs7/index.html
http://www.ibm.com/developerworks/library/l-fs8.html http://www.ibm.com/developerworks/library/l-fs8/index.html
...@@ -68,12 +68,12 @@ Note: More extensive information for getting started with ext4 can be ...@@ -68,12 +68,12 @@ Note: More extensive information for getting started with ext4 can be
'-o barriers=[0|1]' mount option for both ext3 and ext4 filesystems '-o barriers=[0|1]' mount option for both ext3 and ext4 filesystems
for a fair comparison. When tuning ext3 for best benchmark numbers, for a fair comparison. When tuning ext3 for best benchmark numbers,
it is often worthwhile to try changing the data journaling mode; '-o it is often worthwhile to try changing the data journaling mode; '-o
data=writeback,nobh' can be faster for some workloads. (Note data=writeback' can be faster for some workloads. (Note however that
however that running mounted with data=writeback can potentially running mounted with data=writeback can potentially leave stale data
leave stale data exposed in recently written files in case of an exposed in recently written files in case of an unclean shutdown,
unclean shutdown, which could be a security exposure in some which could be a security exposure in some situations.) Configuring
situations.) Configuring the filesystem with a large journal can the filesystem with a large journal can also be helpful for
also be helpful for metadata-intensive workloads. metadata-intensive workloads.
2. Features 2. Features
=========== ===========
...@@ -272,14 +272,6 @@ grpjquota=<file> during journal replay. They replace the above ...@@ -272,14 +272,6 @@ grpjquota=<file> during journal replay. They replace the above
package for more details package for more details
(http://sourceforge.net/projects/linuxquota). (http://sourceforge.net/projects/linuxquota).
bh (*) ext4 associates buffer heads to data pages to
nobh (a) cache disk block mapping information
(b) link pages into transaction to provide
ordering guarantees.
"bh" option forces use of buffer heads.
"nobh" option tries to avoid associating buffer
heads (supported only for "writeback" mode).
stripe=n Number of filesystem blocks that mballoc will try stripe=n Number of filesystem blocks that mballoc will try
to use for allocation size and alignment. For RAID5/6 to use for allocation size and alignment. For RAID5/6
systems this should be the number of data systems this should be the number of data
...@@ -393,8 +385,7 @@ dioread_nolock locking. If the dioread_nolock option is specified ...@@ -393,8 +385,7 @@ dioread_nolock locking. If the dioread_nolock option is specified
write and convert the extent to initialized after IO write and convert the extent to initialized after IO
completes. This approach allows ext4 code to avoid completes. This approach allows ext4 code to avoid
using inode mutex, which improves scalability on high using inode mutex, which improves scalability on high
speed storages. However this does not work with nobh speed storages. However this does not work with
option and the mount will fail. Nor does it work with
data journaling and dioread_nolock option will be data journaling and dioread_nolock option will be
ignored with kernel warning. Note that dioread_nolock ignored with kernel warning. Note that dioread_nolock
code path is only used for extent-based files. code path is only used for extent-based files.
......
...@@ -161,6 +161,10 @@ ext2_xattr_get(struct inode *inode, int name_index, const char *name, ...@@ -161,6 +161,10 @@ ext2_xattr_get(struct inode *inode, int name_index, const char *name,
if (name == NULL) if (name == NULL)
return -EINVAL; return -EINVAL;
name_len = strlen(name);
if (name_len > 255)
return -ERANGE;
down_read(&EXT2_I(inode)->xattr_sem); down_read(&EXT2_I(inode)->xattr_sem);
error = -ENODATA; error = -ENODATA;
if (!EXT2_I(inode)->i_file_acl) if (!EXT2_I(inode)->i_file_acl)
...@@ -181,12 +185,8 @@ bad_block: ext2_error(inode->i_sb, "ext2_xattr_get", ...@@ -181,12 +185,8 @@ bad_block: ext2_error(inode->i_sb, "ext2_xattr_get",
error = -EIO; error = -EIO;
goto cleanup; goto cleanup;
} }
/* find named attribute */
name_len = strlen(name);
error = -ERANGE; /* find named attribute */
if (name_len > 255)
goto cleanup;
entry = FIRST_ENTRY(bh); entry = FIRST_ENTRY(bh);
while (!IS_LAST_ENTRY(entry)) { while (!IS_LAST_ENTRY(entry)) {
struct ext2_xattr_entry *next = struct ext2_xattr_entry *next =
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/quotaops.h> #include <linux/quotaops.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <trace/events/ext3.h>
/* /*
* balloc.c contains the blocks allocation and deallocation routines * balloc.c contains the blocks allocation and deallocation routines
...@@ -161,6 +162,7 @@ read_block_bitmap(struct super_block *sb, unsigned int block_group) ...@@ -161,6 +162,7 @@ read_block_bitmap(struct super_block *sb, unsigned int block_group)
desc = ext3_get_group_desc(sb, block_group, NULL); desc = ext3_get_group_desc(sb, block_group, NULL);
if (!desc) if (!desc)
return NULL; return NULL;
trace_ext3_read_block_bitmap(sb, block_group);
bitmap_blk = le32_to_cpu(desc->bg_block_bitmap); bitmap_blk = le32_to_cpu(desc->bg_block_bitmap);
bh = sb_getblk(sb, bitmap_blk); bh = sb_getblk(sb, bitmap_blk);
if (unlikely(!bh)) { if (unlikely(!bh)) {
...@@ -351,6 +353,7 @@ void ext3_rsv_window_add(struct super_block *sb, ...@@ -351,6 +353,7 @@ void ext3_rsv_window_add(struct super_block *sb,
struct rb_node * parent = NULL; struct rb_node * parent = NULL;
struct ext3_reserve_window_node *this; struct ext3_reserve_window_node *this;
trace_ext3_rsv_window_add(sb, rsv);
while (*p) while (*p)
{ {
parent = *p; parent = *p;
...@@ -476,8 +479,10 @@ void ext3_discard_reservation(struct inode *inode) ...@@ -476,8 +479,10 @@ void ext3_discard_reservation(struct inode *inode)
rsv = &block_i->rsv_window_node; rsv = &block_i->rsv_window_node;
if (!rsv_is_empty(&rsv->rsv_window)) { if (!rsv_is_empty(&rsv->rsv_window)) {
spin_lock(rsv_lock); spin_lock(rsv_lock);
if (!rsv_is_empty(&rsv->rsv_window)) if (!rsv_is_empty(&rsv->rsv_window)) {
trace_ext3_discard_reservation(inode, rsv);
rsv_window_remove(inode->i_sb, rsv); rsv_window_remove(inode->i_sb, rsv);
}
spin_unlock(rsv_lock); spin_unlock(rsv_lock);
} }
} }
...@@ -683,14 +688,10 @@ void ext3_free_blocks_sb(handle_t *handle, struct super_block *sb, ...@@ -683,14 +688,10 @@ void ext3_free_blocks_sb(handle_t *handle, struct super_block *sb,
void ext3_free_blocks(handle_t *handle, struct inode *inode, void ext3_free_blocks(handle_t *handle, struct inode *inode,
ext3_fsblk_t block, unsigned long count) ext3_fsblk_t block, unsigned long count)
{ {
struct super_block * sb; struct super_block *sb = inode->i_sb;
unsigned long dquot_freed_blocks; unsigned long dquot_freed_blocks;
sb = inode->i_sb; trace_ext3_free_blocks(inode, block, count);
if (!sb) {
printk ("ext3_free_blocks: nonexistent device");
return;
}
ext3_free_blocks_sb(handle, sb, block, count, &dquot_freed_blocks); ext3_free_blocks_sb(handle, sb, block, count, &dquot_freed_blocks);
if (dquot_freed_blocks) if (dquot_freed_blocks)
dquot_free_block(inode, dquot_freed_blocks); dquot_free_block(inode, dquot_freed_blocks);
...@@ -1136,6 +1137,7 @@ static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv, ...@@ -1136,6 +1137,7 @@ static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv,
else else
start_block = grp_goal + group_first_block; start_block = grp_goal + group_first_block;
trace_ext3_alloc_new_reservation(sb, start_block);
size = my_rsv->rsv_goal_size; size = my_rsv->rsv_goal_size;
if (!rsv_is_empty(&my_rsv->rsv_window)) { if (!rsv_is_empty(&my_rsv->rsv_window)) {
...@@ -1230,8 +1232,11 @@ static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv, ...@@ -1230,8 +1232,11 @@ static int alloc_new_reservation(struct ext3_reserve_window_node *my_rsv,
* check if the first free block is within the * check if the first free block is within the
* free space we just reserved * free space we just reserved
*/ */
if (start_block >= my_rsv->rsv_start && start_block <= my_rsv->rsv_end) if (start_block >= my_rsv->rsv_start &&
start_block <= my_rsv->rsv_end) {
trace_ext3_reserved(sb, start_block, my_rsv);
return 0; /* success */ return 0; /* success */
}
/* /*
* if the first free bit we found is out of the reservable space * if the first free bit we found is out of the reservable space
* continue search for next reservable space, * continue search for next reservable space,
...@@ -1514,10 +1519,6 @@ ext3_fsblk_t ext3_new_blocks(handle_t *handle, struct inode *inode, ...@@ -1514,10 +1519,6 @@ ext3_fsblk_t ext3_new_blocks(handle_t *handle, struct inode *inode,
*errp = -ENOSPC; *errp = -ENOSPC;
sb = inode->i_sb; sb = inode->i_sb;
if (!sb) {
printk("ext3_new_block: nonexistent device");
return 0;
}
/* /*
* Check quota for allocation of this block. * Check quota for allocation of this block.
...@@ -1528,8 +1529,10 @@ ext3_fsblk_t ext3_new_blocks(handle_t *handle, struct inode *inode, ...@@ -1528,8 +1529,10 @@ ext3_fsblk_t ext3_new_blocks(handle_t *handle, struct inode *inode,
return 0; return 0;
} }
trace_ext3_request_blocks(inode, goal, num);
sbi = EXT3_SB(sb); sbi = EXT3_SB(sb);
es = EXT3_SB(sb)->s_es; es = sbi->s_es;
ext3_debug("goal=%lu.\n", goal); ext3_debug("goal=%lu.\n", goal);
/* /*
* Allocate a block from reservation only when * Allocate a block from reservation only when
...@@ -1742,6 +1745,10 @@ ext3_fsblk_t ext3_new_blocks(handle_t *handle, struct inode *inode, ...@@ -1742,6 +1745,10 @@ ext3_fsblk_t ext3_new_blocks(handle_t *handle, struct inode *inode,
brelse(bitmap_bh); brelse(bitmap_bh);
dquot_free_block(inode, *count-num); dquot_free_block(inode, *count-num);
*count = num; *count = num;
trace_ext3_allocate_blocks(inode, goal, num,
(unsigned long long)ret_block);
return ret_block; return ret_block;
io_error: io_error:
...@@ -1996,6 +2003,7 @@ ext3_grpblk_t ext3_trim_all_free(struct super_block *sb, unsigned int group, ...@@ -1996,6 +2003,7 @@ ext3_grpblk_t ext3_trim_all_free(struct super_block *sb, unsigned int group,
if ((next - start) < minblocks) if ((next - start) < minblocks)
goto free_extent; goto free_extent;
trace_ext3_discard_blocks(sb, discard_block, next - start);
/* Send the TRIM command down to the device */ /* Send the TRIM command down to the device */
err = sb_issue_discard(sb, discard_block, next - start, err = sb_issue_discard(sb, discard_block, next - start,
GFP_NOFS, 0); GFP_NOFS, 0);
...@@ -2100,7 +2108,7 @@ int ext3_trim_fs(struct super_block *sb, struct fstrim_range *range) ...@@ -2100,7 +2108,7 @@ int ext3_trim_fs(struct super_block *sb, struct fstrim_range *range)
if (unlikely(minlen > EXT3_BLOCKS_PER_GROUP(sb))) if (unlikely(minlen > EXT3_BLOCKS_PER_GROUP(sb)))
return -EINVAL; return -EINVAL;
if (start >= max_blks) if (start >= max_blks)
goto out; return -EINVAL;
if (start + len > max_blks) if (start + len > max_blks)
len = max_blks - start; len = max_blks - start;
...@@ -2148,8 +2156,6 @@ int ext3_trim_fs(struct super_block *sb, struct fstrim_range *range) ...@@ -2148,8 +2156,6 @@ int ext3_trim_fs(struct super_block *sb, struct fstrim_range *range)
if (ret >= 0) if (ret >= 0)
ret = 0; ret = 0;
out:
range->len = trimmed * sb->s_blocksize; range->len = trimmed * sb->s_blocksize;
return ret; return ret;
......
...@@ -71,7 +71,6 @@ const struct file_operations ext3_file_operations = { ...@@ -71,7 +71,6 @@ const struct file_operations ext3_file_operations = {
}; };
const struct inode_operations ext3_file_inode_operations = { const struct inode_operations ext3_file_inode_operations = {
.truncate = ext3_truncate,
.setattr = ext3_setattr, .setattr = ext3_setattr,
#ifdef CONFIG_EXT3_FS_XATTR #ifdef CONFIG_EXT3_FS_XATTR
.setxattr = generic_setxattr, .setxattr = generic_setxattr,
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <linux/jbd.h> #include <linux/jbd.h>
#include <linux/ext3_fs.h> #include <linux/ext3_fs.h>
#include <linux/ext3_jbd.h> #include <linux/ext3_jbd.h>
#include <trace/events/ext3.h>
/* /*
* akpm: A new design for ext3_sync_file(). * akpm: A new design for ext3_sync_file().
...@@ -51,12 +52,14 @@ int ext3_sync_file(struct file *file, loff_t start, loff_t end, int datasync) ...@@ -51,12 +52,14 @@ int ext3_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
int ret, needs_barrier = 0; int ret, needs_barrier = 0;
tid_t commit_tid; tid_t commit_tid;
trace_ext3_sync_file_enter(file, datasync);
if (inode->i_sb->s_flags & MS_RDONLY) if (inode->i_sb->s_flags & MS_RDONLY)
return 0; return 0;
ret = filemap_write_and_wait_range(inode->i_mapping, start, end); ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
if (ret) if (ret)
return ret; goto out;
/* /*
* Taking the mutex here just to keep consistent with how fsync was * Taking the mutex here just to keep consistent with how fsync was
...@@ -83,7 +86,8 @@ int ext3_sync_file(struct file *file, loff_t start, loff_t end, int datasync) ...@@ -83,7 +86,8 @@ int ext3_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
*/ */
if (ext3_should_journal_data(inode)) { if (ext3_should_journal_data(inode)) {
mutex_unlock(&inode->i_mutex); mutex_unlock(&inode->i_mutex);
return ext3_force_commit(inode->i_sb); ret = ext3_force_commit(inode->i_sb);
goto out;
} }
if (datasync) if (datasync)
...@@ -104,6 +108,9 @@ int ext3_sync_file(struct file *file, loff_t start, loff_t end, int datasync) ...@@ -104,6 +108,9 @@ int ext3_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
*/ */
if (needs_barrier) if (needs_barrier)
blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL); blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
mutex_unlock(&inode->i_mutex); mutex_unlock(&inode->i_mutex);
out:
trace_ext3_sync_file_exit(inode, ret);
return ret; return ret;
} }
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/random.h> #include <linux/random.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <trace/events/ext3.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
...@@ -118,6 +119,7 @@ void ext3_free_inode (handle_t *handle, struct inode * inode) ...@@ -118,6 +119,7 @@ void ext3_free_inode (handle_t *handle, struct inode * inode)
ino = inode->i_ino; ino = inode->i_ino;
ext3_debug ("freeing inode %lu\n", ino); ext3_debug ("freeing inode %lu\n", ino);
trace_ext3_free_inode(inode);
is_directory = S_ISDIR(inode->i_mode); is_directory = S_ISDIR(inode->i_mode);
...@@ -426,6 +428,7 @@ struct inode *ext3_new_inode(handle_t *handle, struct inode * dir, ...@@ -426,6 +428,7 @@ struct inode *ext3_new_inode(handle_t *handle, struct inode * dir,
return ERR_PTR(-EPERM); return ERR_PTR(-EPERM);
sb = dir->i_sb; sb = dir->i_sb;
trace_ext3_request_inode(dir, mode);
inode = new_inode(sb); inode = new_inode(sb);
if (!inode) if (!inode)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -601,6 +604,7 @@ struct inode *ext3_new_inode(handle_t *handle, struct inode * dir, ...@@ -601,6 +604,7 @@ struct inode *ext3_new_inode(handle_t *handle, struct inode * dir,
} }
ext3_debug("allocating inode %lu\n", inode->i_ino); ext3_debug("allocating inode %lu\n", inode->i_ino);
trace_ext3_allocate_inode(inode, dir, mode);
goto really_out; goto really_out;
fail: fail:
ext3_std_error(sb, err); ext3_std_error(sb, err);
......
This diff is collapsed.
...@@ -285,7 +285,7 @@ long ext3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ...@@ -285,7 +285,7 @@ long ext3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (!capable(CAP_SYS_ADMIN)) if (!capable(CAP_SYS_ADMIN))
return -EPERM; return -EPERM;
if (copy_from_user(&range, (struct fstrim_range *)arg, if (copy_from_user(&range, (struct fstrim_range __user *)arg,
sizeof(range))) sizeof(range)))
return -EFAULT; return -EFAULT;
...@@ -293,7 +293,7 @@ long ext3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ...@@ -293,7 +293,7 @@ long ext3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
if (ret < 0) if (ret < 0)
return ret; return ret;
if (copy_to_user((struct fstrim_range *)arg, &range, if (copy_to_user((struct fstrim_range __user *)arg, &range,
sizeof(range))) sizeof(range)))
return -EFAULT; return -EFAULT;
......
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <linux/quotaops.h> #include <linux/quotaops.h>
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include <linux/bio.h> #include <linux/bio.h>
#include <trace/events/ext3.h>
#include "namei.h" #include "namei.h"
#include "xattr.h" #include "xattr.h"
...@@ -287,7 +288,7 @@ static struct stats dx_show_leaf(struct dx_hash_info *hinfo, struct ext3_dir_ent ...@@ -287,7 +288,7 @@ static struct stats dx_show_leaf(struct dx_hash_info *hinfo, struct ext3_dir_ent
while (len--) printk("%c", *name++); while (len--) printk("%c", *name++);
ext3fs_dirhash(de->name, de->name_len, &h); ext3fs_dirhash(de->name, de->name_len, &h);
printk(":%x.%u ", h.hash, printk(":%x.%u ", h.hash,
((char *) de - base)); (unsigned) ((char *) de - base));
} }
space += EXT3_DIR_REC_LEN(de->name_len); space += EXT3_DIR_REC_LEN(de->name_len);
names++; names++;
...@@ -1013,7 +1014,7 @@ static struct buffer_head * ext3_dx_find_entry(struct inode *dir, ...@@ -1013,7 +1014,7 @@ static struct buffer_head * ext3_dx_find_entry(struct inode *dir,
*err = -ENOENT; *err = -ENOENT;
errout: errout:
dxtrace(printk("%s not found\n", name)); dxtrace(printk("%s not found\n", entry->name));
dx_release (frames); dx_release (frames);
return NULL; return NULL;
} }
...@@ -2140,6 +2141,7 @@ static int ext3_unlink(struct inode * dir, struct dentry *dentry) ...@@ -2140,6 +2141,7 @@ static int ext3_unlink(struct inode * dir, struct dentry *dentry)
struct ext3_dir_entry_2 * de; struct ext3_dir_entry_2 * de;
handle_t *handle; handle_t *handle;
trace_ext3_unlink_enter(dir, dentry);
/* Initialize quotas before so that eventual writes go /* Initialize quotas before so that eventual writes go
* in separate transaction */ * in separate transaction */
dquot_initialize(dir); dquot_initialize(dir);
...@@ -2185,6 +2187,7 @@ static int ext3_unlink(struct inode * dir, struct dentry *dentry) ...@@ -2185,6 +2187,7 @@ static int ext3_unlink(struct inode * dir, struct dentry *dentry)
end_unlink: end_unlink:
ext3_journal_stop(handle); ext3_journal_stop(handle);
brelse (bh); brelse (bh);
trace_ext3_unlink_exit(dentry, retval);
return retval; return retval;
} }
......
...@@ -44,6 +44,9 @@ ...@@ -44,6 +44,9 @@
#include "acl.h" #include "acl.h"
#include "namei.h" #include "namei.h"
#define CREATE_TRACE_POINTS
#include <trace/events/ext3.h>
#ifdef CONFIG_EXT3_DEFAULTS_TO_ORDERED #ifdef CONFIG_EXT3_DEFAULTS_TO_ORDERED
#define EXT3_MOUNT_DEFAULT_DATA_MODE EXT3_MOUNT_ORDERED_DATA #define EXT3_MOUNT_DEFAULT_DATA_MODE EXT3_MOUNT_ORDERED_DATA
#else #else
...@@ -497,6 +500,14 @@ static struct inode *ext3_alloc_inode(struct super_block *sb) ...@@ -497,6 +500,14 @@ static struct inode *ext3_alloc_inode(struct super_block *sb)
return &ei->vfs_inode; return &ei->vfs_inode;
} }
static int ext3_drop_inode(struct inode *inode)
{
int drop = generic_drop_inode(inode);
trace_ext3_drop_inode(inode, drop);
return drop;
}
static void ext3_i_callback(struct rcu_head *head) static void ext3_i_callback(struct rcu_head *head)
{ {
struct inode *inode = container_of(head, struct inode, i_rcu); struct inode *inode = container_of(head, struct inode, i_rcu);
...@@ -788,6 +799,7 @@ static const struct super_operations ext3_sops = { ...@@ -788,6 +799,7 @@ static const struct super_operations ext3_sops = {
.destroy_inode = ext3_destroy_inode, .destroy_inode = ext3_destroy_inode,
.write_inode = ext3_write_inode, .write_inode = ext3_write_inode,
.dirty_inode = ext3_dirty_inode, .dirty_inode = ext3_dirty_inode,
.drop_inode = ext3_drop_inode,
.evict_inode = ext3_evict_inode, .evict_inode = ext3_evict_inode,
.put_super = ext3_put_super, .put_super = ext3_put_super,
.sync_fs = ext3_sync_fs, .sync_fs = ext3_sync_fs,
...@@ -2509,6 +2521,7 @@ static int ext3_sync_fs(struct super_block *sb, int wait) ...@@ -2509,6 +2521,7 @@ static int ext3_sync_fs(struct super_block *sb, int wait)
{ {
tid_t target; tid_t target;
trace_ext3_sync_fs(sb, wait);
if (journal_start_commit(EXT3_SB(sb)->s_journal, &target)) { if (journal_start_commit(EXT3_SB(sb)->s_journal, &target)) {
if (wait) if (wait)
log_wait_commit(EXT3_SB(sb)->s_journal, target); log_wait_commit(EXT3_SB(sb)->s_journal, target);
......
...@@ -803,8 +803,16 @@ ext3_xattr_block_set(handle_t *handle, struct inode *inode, ...@@ -803,8 +803,16 @@ ext3_xattr_block_set(handle_t *handle, struct inode *inode,
/* We need to allocate a new block */ /* We need to allocate a new block */
ext3_fsblk_t goal = ext3_group_first_block_no(sb, ext3_fsblk_t goal = ext3_group_first_block_no(sb,
EXT3_I(inode)->i_block_group); EXT3_I(inode)->i_block_group);
ext3_fsblk_t block = ext3_new_block(handle, inode, ext3_fsblk_t block;
goal, &error);
/*
* Protect us agaist concurrent allocations to the
* same inode from ext3_..._writepage(). Reservation
* code does not expect racing allocations.
*/
mutex_lock(&EXT3_I(inode)->truncate_mutex);
block = ext3_new_block(handle, inode, goal, &error);
mutex_unlock(&EXT3_I(inode)->truncate_mutex);
if (error) if (error)
goto cleanup; goto cleanup;
ea_idebug(inode, "creating block %d", block); ea_idebug(inode, "creating block %d", block);
......
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
#include <linux/jbd.h> #include <linux/jbd.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/blkdev.h>
#include <trace/events/jbd.h>
/* /*
* Unlink a buffer from a transaction checkpoint list. * Unlink a buffer from a transaction checkpoint list.
...@@ -95,10 +97,14 @@ static int __try_to_free_cp_buf(struct journal_head *jh) ...@@ -95,10 +97,14 @@ static int __try_to_free_cp_buf(struct journal_head *jh)
if (jh->b_jlist == BJ_None && !buffer_locked(bh) && if (jh->b_jlist == BJ_None && !buffer_locked(bh) &&
!buffer_dirty(bh) && !buffer_write_io_error(bh)) { !buffer_dirty(bh) && !buffer_write_io_error(bh)) {
/*
* Get our reference so that bh cannot be freed before
* we unlock it
*/
get_bh(bh);
JBUFFER_TRACE(jh, "remove from checkpoint list"); JBUFFER_TRACE(jh, "remove from checkpoint list");
ret = __journal_remove_checkpoint(jh) + 1; ret = __journal_remove_checkpoint(jh) + 1;
jbd_unlock_bh_state(bh); jbd_unlock_bh_state(bh);
journal_remove_journal_head(bh);
BUFFER_TRACE(bh, "release"); BUFFER_TRACE(bh, "release");
__brelse(bh); __brelse(bh);
} else { } else {
...@@ -220,8 +226,8 @@ static int __wait_cp_io(journal_t *journal, transaction_t *transaction) ...@@ -220,8 +226,8 @@ static int __wait_cp_io(journal_t *journal, transaction_t *transaction)
spin_lock(&journal->j_list_lock); spin_lock(&journal->j_list_lock);
goto restart; goto restart;
} }
get_bh(bh);
if (buffer_locked(bh)) { if (buffer_locked(bh)) {
get_bh(bh);
spin_unlock(&journal->j_list_lock); spin_unlock(&journal->j_list_lock);
jbd_unlock_bh_state(bh); jbd_unlock_bh_state(bh);
wait_on_buffer(bh); wait_on_buffer(bh);
...@@ -240,7 +246,6 @@ static int __wait_cp_io(journal_t *journal, transaction_t *transaction) ...@@ -240,7 +246,6 @@ static int __wait_cp_io(journal_t *journal, transaction_t *transaction)
*/ */
released = __journal_remove_checkpoint(jh); released = __journal_remove_checkpoint(jh);
jbd_unlock_bh_state(bh); jbd_unlock_bh_state(bh);
journal_remove_journal_head(bh);
__brelse(bh); __brelse(bh);
} }
...@@ -253,9 +258,12 @@ static void ...@@ -253,9 +258,12 @@ static void
__flush_batch(journal_t *journal, struct buffer_head **bhs, int *batch_count) __flush_batch(journal_t *journal, struct buffer_head **bhs, int *batch_count)
{ {
int i; int i;
struct blk_plug plug;
blk_start_plug(&plug);
for (i = 0; i < *batch_count; i++) for (i = 0; i < *batch_count; i++)
write_dirty_buffer(bhs[i], WRITE); write_dirty_buffer(bhs[i], WRITE_SYNC);
blk_finish_plug(&plug);
for (i = 0; i < *batch_count; i++) { for (i = 0; i < *batch_count; i++) {
struct buffer_head *bh = bhs[i]; struct buffer_head *bh = bhs[i];
...@@ -304,12 +312,12 @@ static int __process_buffer(journal_t *journal, struct journal_head *jh, ...@@ -304,12 +312,12 @@ static int __process_buffer(journal_t *journal, struct journal_head *jh,
ret = 1; ret = 1;
if (unlikely(buffer_write_io_error(bh))) if (unlikely(buffer_write_io_error(bh)))
ret = -EIO; ret = -EIO;
get_bh(bh);
J_ASSERT_JH(jh, !buffer_jbddirty(bh)); J_ASSERT_JH(jh, !buffer_jbddirty(bh));
BUFFER_TRACE(bh, "remove from checkpoint"); BUFFER_TRACE(bh, "remove from checkpoint");
__journal_remove_checkpoint(jh); __journal_remove_checkpoint(jh);
spin_unlock(&journal->j_list_lock); spin_unlock(&journal->j_list_lock);
jbd_unlock_bh_state(bh); jbd_unlock_bh_state(bh);
journal_remove_journal_head(bh);
__brelse(bh); __brelse(bh);
} else { } else {
/* /*
...@@ -358,6 +366,7 @@ int log_do_checkpoint(journal_t *journal) ...@@ -358,6 +366,7 @@ int log_do_checkpoint(journal_t *journal)
* journal straight away. * journal straight away.
*/ */
result = cleanup_journal_tail(journal); result = cleanup_journal_tail(journal);
trace_jbd_checkpoint(journal, result);
jbd_debug(1, "cleanup_journal_tail returned %d\n", result); jbd_debug(1, "cleanup_journal_tail returned %d\n", result);
if (result <= 0) if (result <= 0)
return result; return result;
...@@ -503,6 +512,7 @@ int cleanup_journal_tail(journal_t *journal) ...@@ -503,6 +512,7 @@ int cleanup_journal_tail(journal_t *journal)
if (blocknr < journal->j_tail) if (blocknr < journal->j_tail)
freed = freed + journal->j_last - journal->j_first; freed = freed + journal->j_last - journal->j_first;
trace_jbd_cleanup_journal_tail(journal, first_tid, blocknr, freed);
jbd_debug(1, jbd_debug(1,
"Cleaning journal tail from %d to %d (offset %u), " "Cleaning journal tail from %d to %d (offset %u), "
"freeing %u\n", "freeing %u\n",
...@@ -523,9 +533,9 @@ int cleanup_journal_tail(journal_t *journal) ...@@ -523,9 +533,9 @@ int cleanup_journal_tail(journal_t *journal)
/* /*
* journal_clean_one_cp_list * journal_clean_one_cp_list
* *
* Find all the written-back checkpoint buffers in the given list and release them. * Find all the written-back checkpoint buffers in the given list and release
* them.
* *
* Called with the journal locked.
* Called with j_list_lock held. * Called with j_list_lock held.
* Returns number of bufers reaped (for debug) * Returns number of bufers reaped (for debug)
*/ */
...@@ -632,8 +642,8 @@ int __journal_clean_checkpoint_list(journal_t *journal) ...@@ -632,8 +642,8 @@ int __journal_clean_checkpoint_list(journal_t *journal)
* checkpoint lists. * checkpoint lists.
* *
* The function returns 1 if it frees the transaction, 0 otherwise. * The function returns 1 if it frees the transaction, 0 otherwise.
* The function can free jh and bh.
* *
* This function is called with the journal locked.
* This function is called with j_list_lock held. * This function is called with j_list_lock held.
* This function is called with jbd_lock_bh_state(jh2bh(jh)) * This function is called with jbd_lock_bh_state(jh2bh(jh))
*/ */
...@@ -652,13 +662,14 @@ int __journal_remove_checkpoint(struct journal_head *jh) ...@@ -652,13 +662,14 @@ int __journal_remove_checkpoint(struct journal_head *jh)
} }
journal = transaction->t_journal; journal = transaction->t_journal;
JBUFFER_TRACE(jh, "removing from transaction");
__buffer_unlink(jh); __buffer_unlink(jh);
jh->b_cp_transaction = NULL; jh->b_cp_transaction = NULL;
journal_put_journal_head(jh);
if (transaction->t_checkpoint_list != NULL || if (transaction->t_checkpoint_list != NULL ||
transaction->t_checkpoint_io_list != NULL) transaction->t_checkpoint_io_list != NULL)
goto out; goto out;
JBUFFER_TRACE(jh, "transaction has no more buffers");
/* /*
* There is one special case to worry about: if we have just pulled the * There is one special case to worry about: if we have just pulled the
...@@ -669,10 +680,8 @@ int __journal_remove_checkpoint(struct journal_head *jh) ...@@ -669,10 +680,8 @@ int __journal_remove_checkpoint(struct journal_head *jh)
* The locking here around t_state is a bit sleazy. * The locking here around t_state is a bit sleazy.
* See the comment at the end of journal_commit_transaction(). * See the comment at the end of journal_commit_transaction().
*/ */
if (transaction->t_state != T_FINISHED) { if (transaction->t_state != T_FINISHED)
JBUFFER_TRACE(jh, "belongs to running/committing transaction");
goto out; goto out;
}
/* OK, that was the last buffer for the transaction: we can now /* OK, that was the last buffer for the transaction: we can now
safely remove this transaction from the log */ safely remove this transaction from the log */
...@@ -684,7 +693,6 @@ int __journal_remove_checkpoint(struct journal_head *jh) ...@@ -684,7 +693,6 @@ int __journal_remove_checkpoint(struct journal_head *jh)
wake_up(&journal->j_wait_logspace); wake_up(&journal->j_wait_logspace);
ret = 1; ret = 1;
out: out:
JBUFFER_TRACE(jh, "exit");
return ret; return ret;
} }
...@@ -703,6 +711,8 @@ void __journal_insert_checkpoint(struct journal_head *jh, ...@@ -703,6 +711,8 @@ void __journal_insert_checkpoint(struct journal_head *jh,
J_ASSERT_JH(jh, buffer_dirty(jh2bh(jh)) || buffer_jbddirty(jh2bh(jh))); J_ASSERT_JH(jh, buffer_dirty(jh2bh(jh)) || buffer_jbddirty(jh2bh(jh)));
J_ASSERT_JH(jh, jh->b_cp_transaction == NULL); J_ASSERT_JH(jh, jh->b_cp_transaction == NULL);
/* Get reference for checkpointing transaction */
journal_grab_journal_head(jh2bh(jh));
jh->b_cp_transaction = transaction; jh->b_cp_transaction = transaction;
if (!transaction->t_checkpoint_list) { if (!transaction->t_checkpoint_list) {
...@@ -752,6 +762,7 @@ void __journal_drop_transaction(journal_t *journal, transaction_t *transaction) ...@@ -752,6 +762,7 @@ void __journal_drop_transaction(journal_t *journal, transaction_t *transaction)
J_ASSERT(journal->j_committing_transaction != transaction); J_ASSERT(journal->j_committing_transaction != transaction);
J_ASSERT(journal->j_running_transaction != transaction); J_ASSERT(journal->j_running_transaction != transaction);
trace_jbd_drop_transaction(journal, transaction);
jbd_debug(1, "Dropping transaction %d, all done\n", transaction->t_tid); jbd_debug(1, "Dropping transaction %d, all done\n", transaction->t_tid);
kfree(transaction); kfree(transaction);
} }
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/bio.h> #include <linux/bio.h>
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <trace/events/jbd.h>
/* /*
* Default IO end handler for temporary BJ_IO buffer_heads. * Default IO end handler for temporary BJ_IO buffer_heads.
...@@ -204,6 +205,8 @@ static int journal_submit_data_buffers(journal_t *journal, ...@@ -204,6 +205,8 @@ static int journal_submit_data_buffers(journal_t *journal,
if (!trylock_buffer(bh)) { if (!trylock_buffer(bh)) {
BUFFER_TRACE(bh, "needs blocking lock"); BUFFER_TRACE(bh, "needs blocking lock");
spin_unlock(&journal->j_list_lock); spin_unlock(&journal->j_list_lock);
trace_jbd_do_submit_data(journal,
commit_transaction);
/* Write out all data to prevent deadlocks */ /* Write out all data to prevent deadlocks */
journal_do_submit_data(wbuf, bufs, write_op); journal_do_submit_data(wbuf, bufs, write_op);
bufs = 0; bufs = 0;
...@@ -236,6 +239,8 @@ static int journal_submit_data_buffers(journal_t *journal, ...@@ -236,6 +239,8 @@ static int journal_submit_data_buffers(journal_t *journal,
jbd_unlock_bh_state(bh); jbd_unlock_bh_state(bh);
if (bufs == journal->j_wbufsize) { if (bufs == journal->j_wbufsize) {
spin_unlock(&journal->j_list_lock); spin_unlock(&journal->j_list_lock);
trace_jbd_do_submit_data(journal,
commit_transaction);
journal_do_submit_data(wbuf, bufs, write_op); journal_do_submit_data(wbuf, bufs, write_op);
bufs = 0; bufs = 0;
goto write_out_data; goto write_out_data;
...@@ -253,10 +258,6 @@ static int journal_submit_data_buffers(journal_t *journal, ...@@ -253,10 +258,6 @@ static int journal_submit_data_buffers(journal_t *journal,
jbd_unlock_bh_state(bh); jbd_unlock_bh_state(bh);
if (locked) if (locked)
unlock_buffer(bh); unlock_buffer(bh);
journal_remove_journal_head(bh);
/* One for our safety reference, other for
* journal_remove_journal_head() */
put_bh(bh);
release_data_buffer(bh); release_data_buffer(bh);
} }
...@@ -266,6 +267,7 @@ static int journal_submit_data_buffers(journal_t *journal, ...@@ -266,6 +267,7 @@ static int journal_submit_data_buffers(journal_t *journal,
} }
} }
spin_unlock(&journal->j_list_lock); spin_unlock(&journal->j_list_lock);
trace_jbd_do_submit_data(journal, commit_transaction);
journal_do_submit_data(wbuf, bufs, write_op); journal_do_submit_data(wbuf, bufs, write_op);
return err; return err;
...@@ -316,12 +318,14 @@ void journal_commit_transaction(journal_t *journal) ...@@ -316,12 +318,14 @@ void journal_commit_transaction(journal_t *journal)
commit_transaction = journal->j_running_transaction; commit_transaction = journal->j_running_transaction;
J_ASSERT(commit_transaction->t_state == T_RUNNING); J_ASSERT(commit_transaction->t_state == T_RUNNING);
trace_jbd_start_commit(journal, commit_transaction);
jbd_debug(1, "JBD: starting commit of transaction %d\n", jbd_debug(1, "JBD: starting commit of transaction %d\n",
commit_transaction->t_tid); commit_transaction->t_tid);
spin_lock(&journal->j_state_lock); spin_lock(&journal->j_state_lock);
commit_transaction->t_state = T_LOCKED; commit_transaction->t_state = T_LOCKED;
trace_jbd_commit_locking(journal, commit_transaction);
spin_lock(&commit_transaction->t_handle_lock); spin_lock(&commit_transaction->t_handle_lock);
while (commit_transaction->t_updates) { while (commit_transaction->t_updates) {
DEFINE_WAIT(wait); DEFINE_WAIT(wait);
...@@ -392,6 +396,7 @@ void journal_commit_transaction(journal_t *journal) ...@@ -392,6 +396,7 @@ void journal_commit_transaction(journal_t *journal)
*/ */
journal_switch_revoke_table(journal); journal_switch_revoke_table(journal);
trace_jbd_commit_flushing(journal, commit_transaction);
commit_transaction->t_state = T_FLUSH; commit_transaction->t_state = T_FLUSH;
journal->j_committing_transaction = commit_transaction; journal->j_committing_transaction = commit_transaction;
journal->j_running_transaction = NULL; journal->j_running_transaction = NULL;
...@@ -446,14 +451,9 @@ void journal_commit_transaction(journal_t *journal) ...@@ -446,14 +451,9 @@ void journal_commit_transaction(journal_t *journal)
} }
if (buffer_jbd(bh) && bh2jh(bh) == jh && if (buffer_jbd(bh) && bh2jh(bh) == jh &&
jh->b_transaction == commit_transaction && jh->b_transaction == commit_transaction &&
jh->b_jlist == BJ_Locked) { jh->b_jlist == BJ_Locked)
__journal_unfile_buffer(jh); __journal_unfile_buffer(jh);
jbd_unlock_bh_state(bh); jbd_unlock_bh_state(bh);
journal_remove_journal_head(bh);
put_bh(bh);
} else {
jbd_unlock_bh_state(bh);
}
release_data_buffer(bh); release_data_buffer(bh);
cond_resched_lock(&journal->j_list_lock); cond_resched_lock(&journal->j_list_lock);
} }
...@@ -493,6 +493,7 @@ void journal_commit_transaction(journal_t *journal) ...@@ -493,6 +493,7 @@ void journal_commit_transaction(journal_t *journal)
commit_transaction->t_state = T_COMMIT; commit_transaction->t_state = T_COMMIT;
spin_unlock(&journal->j_state_lock); spin_unlock(&journal->j_state_lock);
trace_jbd_commit_logging(journal, commit_transaction);
J_ASSERT(commit_transaction->t_nr_buffers <= J_ASSERT(commit_transaction->t_nr_buffers <=
commit_transaction->t_outstanding_credits); commit_transaction->t_outstanding_credits);
...@@ -797,10 +798,16 @@ void journal_commit_transaction(journal_t *journal) ...@@ -797,10 +798,16 @@ void journal_commit_transaction(journal_t *journal)
while (commit_transaction->t_forget) { while (commit_transaction->t_forget) {
transaction_t *cp_transaction; transaction_t *cp_transaction;
struct buffer_head *bh; struct buffer_head *bh;
int try_to_free = 0;
jh = commit_transaction->t_forget; jh = commit_transaction->t_forget;
spin_unlock(&journal->j_list_lock); spin_unlock(&journal->j_list_lock);
bh = jh2bh(jh); bh = jh2bh(jh);
/*
* Get a reference so that bh cannot be freed before we are
* done with it.
*/
get_bh(bh);
jbd_lock_bh_state(bh); jbd_lock_bh_state(bh);
J_ASSERT_JH(jh, jh->b_transaction == commit_transaction || J_ASSERT_JH(jh, jh->b_transaction == commit_transaction ||
jh->b_transaction == journal->j_running_transaction); jh->b_transaction == journal->j_running_transaction);
...@@ -858,28 +865,27 @@ void journal_commit_transaction(journal_t *journal) ...@@ -858,28 +865,27 @@ void journal_commit_transaction(journal_t *journal)
__journal_insert_checkpoint(jh, commit_transaction); __journal_insert_checkpoint(jh, commit_transaction);
if (is_journal_aborted(journal)) if (is_journal_aborted(journal))
clear_buffer_jbddirty(bh); clear_buffer_jbddirty(bh);
JBUFFER_TRACE(jh, "refile for checkpoint writeback");
__journal_refile_buffer(jh);
jbd_unlock_bh_state(bh);
} else { } else {
J_ASSERT_BH(bh, !buffer_dirty(bh)); J_ASSERT_BH(bh, !buffer_dirty(bh));
/* The buffer on BJ_Forget list and not jbddirty means /*
* The buffer on BJ_Forget list and not jbddirty means
* it has been freed by this transaction and hence it * it has been freed by this transaction and hence it
* could not have been reallocated until this * could not have been reallocated until this
* transaction has committed. *BUT* it could be * transaction has committed. *BUT* it could be
* reallocated once we have written all the data to * reallocated once we have written all the data to
* disk and before we process the buffer on BJ_Forget * disk and before we process the buffer on BJ_Forget
* list. */ * list.
JBUFFER_TRACE(jh, "refile or unfile freed buffer"); */
__journal_refile_buffer(jh); if (!jh->b_next_transaction)
if (!jh->b_transaction) { try_to_free = 1;
jbd_unlock_bh_state(bh);
/* needs a brelse */
journal_remove_journal_head(bh);
release_buffer_page(bh);
} else
jbd_unlock_bh_state(bh);
} }
JBUFFER_TRACE(jh, "refile or unfile freed buffer");
__journal_refile_buffer(jh);
jbd_unlock_bh_state(bh);
if (try_to_free)
release_buffer_page(bh);
else
__brelse(bh);
cond_resched_lock(&journal->j_list_lock); cond_resched_lock(&journal->j_list_lock);
} }
spin_unlock(&journal->j_list_lock); spin_unlock(&journal->j_list_lock);
...@@ -946,6 +952,7 @@ void journal_commit_transaction(journal_t *journal) ...@@ -946,6 +952,7 @@ void journal_commit_transaction(journal_t *journal)
} }
spin_unlock(&journal->j_list_lock); spin_unlock(&journal->j_list_lock);
trace_jbd_end_commit(journal, commit_transaction);
jbd_debug(1, "JBD: commit %d complete, head %d\n", jbd_debug(1, "JBD: commit %d complete, head %d\n",
journal->j_commit_sequence, journal->j_tail_sequence); journal->j_commit_sequence, journal->j_tail_sequence);
......
...@@ -38,6 +38,9 @@ ...@@ -38,6 +38,9 @@
#include <linux/debugfs.h> #include <linux/debugfs.h>
#include <linux/ratelimit.h> #include <linux/ratelimit.h>
#define CREATE_TRACE_POINTS
#include <trace/events/jbd.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/page.h> #include <asm/page.h>
...@@ -1065,6 +1068,7 @@ void journal_update_superblock(journal_t *journal, int wait) ...@@ -1065,6 +1068,7 @@ void journal_update_superblock(journal_t *journal, int wait)
} else } else
write_dirty_buffer(bh, WRITE); write_dirty_buffer(bh, WRITE);
trace_jbd_update_superblock_end(journal, wait);
out: out:
/* If we have just flushed the log (by marking s_start==0), then /* If we have just flushed the log (by marking s_start==0), then
* any future commit will have to be careful to update the * any future commit will have to be careful to update the
...@@ -1799,10 +1803,9 @@ static void journal_free_journal_head(struct journal_head *jh) ...@@ -1799,10 +1803,9 @@ static void journal_free_journal_head(struct journal_head *jh)
* When a buffer has its BH_JBD bit set it is immune from being released by * When a buffer has its BH_JBD bit set it is immune from being released by
* core kernel code, mainly via ->b_count. * core kernel code, mainly via ->b_count.
* *
* A journal_head may be detached from its buffer_head when the journal_head's * A journal_head is detached from its buffer_head when the journal_head's
* b_transaction, b_cp_transaction and b_next_transaction pointers are NULL. * b_jcount reaches zero. Running transaction (b_transaction) and checkpoint
* Various places in JBD call journal_remove_journal_head() to indicate that the * transaction (b_cp_transaction) hold their references to b_jcount.
* journal_head can be dropped if needed.
* *
* Various places in the kernel want to attach a journal_head to a buffer_head * Various places in the kernel want to attach a journal_head to a buffer_head
* _before_ attaching the journal_head to a transaction. To protect the * _before_ attaching the journal_head to a transaction. To protect the
...@@ -1815,17 +1818,16 @@ static void journal_free_journal_head(struct journal_head *jh) ...@@ -1815,17 +1818,16 @@ static void journal_free_journal_head(struct journal_head *jh)
* (Attach a journal_head if needed. Increments b_jcount) * (Attach a journal_head if needed. Increments b_jcount)
* struct journal_head *jh = journal_add_journal_head(bh); * struct journal_head *jh = journal_add_journal_head(bh);
* ... * ...
* jh->b_transaction = xxx; * (Get another reference for transaction)
* journal_put_journal_head(jh); * journal_grab_journal_head(bh);
* * jh->b_transaction = xxx;
* Now, the journal_head's b_jcount is zero, but it is safe from being released * (Put original reference)
* because it has a non-zero b_transaction. * journal_put_journal_head(jh);
*/ */
/* /*
* Give a buffer_head a journal_head. * Give a buffer_head a journal_head.
* *
* Doesn't need the journal lock.
* May sleep. * May sleep.
*/ */
struct journal_head *journal_add_journal_head(struct buffer_head *bh) struct journal_head *journal_add_journal_head(struct buffer_head *bh)
...@@ -1889,61 +1891,29 @@ static void __journal_remove_journal_head(struct buffer_head *bh) ...@@ -1889,61 +1891,29 @@ static void __journal_remove_journal_head(struct buffer_head *bh)
struct journal_head *jh = bh2jh(bh); struct journal_head *jh = bh2jh(bh);
J_ASSERT_JH(jh, jh->b_jcount >= 0); J_ASSERT_JH(jh, jh->b_jcount >= 0);
J_ASSERT_JH(jh, jh->b_transaction == NULL);
get_bh(bh); J_ASSERT_JH(jh, jh->b_next_transaction == NULL);
if (jh->b_jcount == 0) { J_ASSERT_JH(jh, jh->b_cp_transaction == NULL);
if (jh->b_transaction == NULL && J_ASSERT_JH(jh, jh->b_jlist == BJ_None);
jh->b_next_transaction == NULL && J_ASSERT_BH(bh, buffer_jbd(bh));
jh->b_cp_transaction == NULL) { J_ASSERT_BH(bh, jh2bh(jh) == bh);
J_ASSERT_JH(jh, jh->b_jlist == BJ_None); BUFFER_TRACE(bh, "remove journal_head");
J_ASSERT_BH(bh, buffer_jbd(bh)); if (jh->b_frozen_data) {
J_ASSERT_BH(bh, jh2bh(jh) == bh); printk(KERN_WARNING "%s: freeing b_frozen_data\n", __func__);
BUFFER_TRACE(bh, "remove journal_head"); jbd_free(jh->b_frozen_data, bh->b_size);
if (jh->b_frozen_data) {
printk(KERN_WARNING "%s: freeing "
"b_frozen_data\n",
__func__);
jbd_free(jh->b_frozen_data, bh->b_size);
}
if (jh->b_committed_data) {
printk(KERN_WARNING "%s: freeing "
"b_committed_data\n",
__func__);
jbd_free(jh->b_committed_data, bh->b_size);
}
bh->b_private = NULL;
jh->b_bh = NULL; /* debug, really */
clear_buffer_jbd(bh);
__brelse(bh);
journal_free_journal_head(jh);
} else {
BUFFER_TRACE(bh, "journal_head was locked");
}
} }
if (jh->b_committed_data) {
printk(KERN_WARNING "%s: freeing b_committed_data\n", __func__);
jbd_free(jh->b_committed_data, bh->b_size);
}
bh->b_private = NULL;
jh->b_bh = NULL; /* debug, really */
clear_buffer_jbd(bh);
journal_free_journal_head(jh);
} }
/* /*
* journal_remove_journal_head(): if the buffer isn't attached to a transaction * Drop a reference on the passed journal_head. If it fell to zero then
* and has a zero b_jcount then remove and release its journal_head. If we did
* see that the buffer is not used by any transaction we also "logically"
* decrement ->b_count.
*
* We in fact take an additional increment on ->b_count as a convenience,
* because the caller usually wants to do additional things with the bh
* after calling here.
* The caller of journal_remove_journal_head() *must* run __brelse(bh) at some
* time. Once the caller has run __brelse(), the buffer is eligible for
* reaping by try_to_free_buffers().
*/
void journal_remove_journal_head(struct buffer_head *bh)
{
jbd_lock_bh_journal_head(bh);
__journal_remove_journal_head(bh);
jbd_unlock_bh_journal_head(bh);
}
/*
* Drop a reference on the passed journal_head. If it fell to zero then try to
* release the journal_head from the buffer_head. * release the journal_head from the buffer_head.
*/ */
void journal_put_journal_head(struct journal_head *jh) void journal_put_journal_head(struct journal_head *jh)
...@@ -1953,11 +1923,12 @@ void journal_put_journal_head(struct journal_head *jh) ...@@ -1953,11 +1923,12 @@ void journal_put_journal_head(struct journal_head *jh)
jbd_lock_bh_journal_head(bh); jbd_lock_bh_journal_head(bh);
J_ASSERT_JH(jh, jh->b_jcount > 0); J_ASSERT_JH(jh, jh->b_jcount > 0);
--jh->b_jcount; --jh->b_jcount;
if (!jh->b_jcount && !jh->b_transaction) { if (!jh->b_jcount) {
__journal_remove_journal_head(bh); __journal_remove_journal_head(bh);
jbd_unlock_bh_journal_head(bh);
__brelse(bh); __brelse(bh);
} } else
jbd_unlock_bh_journal_head(bh); jbd_unlock_bh_journal_head(bh);
} }
/* /*
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/hrtimer.h> #include <linux/hrtimer.h>
#include <linux/backing-dev.h>
static void __journal_temp_unlink_buffer(struct journal_head *jh); static void __journal_temp_unlink_buffer(struct journal_head *jh);
...@@ -99,11 +100,10 @@ static int start_this_handle(journal_t *journal, handle_t *handle) ...@@ -99,11 +100,10 @@ static int start_this_handle(journal_t *journal, handle_t *handle)
alloc_transaction: alloc_transaction:
if (!journal->j_running_transaction) { if (!journal->j_running_transaction) {
new_transaction = kzalloc(sizeof(*new_transaction), new_transaction = kzalloc(sizeof(*new_transaction), GFP_NOFS);
GFP_NOFS|__GFP_NOFAIL);
if (!new_transaction) { if (!new_transaction) {
ret = -ENOMEM; congestion_wait(BLK_RW_ASYNC, HZ/50);
goto out; goto alloc_transaction;
} }
} }
...@@ -696,7 +696,6 @@ do_get_write_access(handle_t *handle, struct journal_head *jh, ...@@ -696,7 +696,6 @@ do_get_write_access(handle_t *handle, struct journal_head *jh,
if (!jh->b_transaction) { if (!jh->b_transaction) {
JBUFFER_TRACE(jh, "no transaction"); JBUFFER_TRACE(jh, "no transaction");
J_ASSERT_JH(jh, !jh->b_next_transaction); J_ASSERT_JH(jh, !jh->b_next_transaction);
jh->b_transaction = transaction;
JBUFFER_TRACE(jh, "file as BJ_Reserved"); JBUFFER_TRACE(jh, "file as BJ_Reserved");
spin_lock(&journal->j_list_lock); spin_lock(&journal->j_list_lock);
__journal_file_buffer(jh, transaction, BJ_Reserved); __journal_file_buffer(jh, transaction, BJ_Reserved);
...@@ -818,7 +817,6 @@ int journal_get_create_access(handle_t *handle, struct buffer_head *bh) ...@@ -818,7 +817,6 @@ int journal_get_create_access(handle_t *handle, struct buffer_head *bh)
* committed and so it's safe to clear the dirty bit. * committed and so it's safe to clear the dirty bit.
*/ */
clear_buffer_dirty(jh2bh(jh)); clear_buffer_dirty(jh2bh(jh));
jh->b_transaction = transaction;
/* first access by this transaction */ /* first access by this transaction */
jh->b_modified = 0; jh->b_modified = 0;
...@@ -844,8 +842,8 @@ int journal_get_create_access(handle_t *handle, struct buffer_head *bh) ...@@ -844,8 +842,8 @@ int journal_get_create_access(handle_t *handle, struct buffer_head *bh)
*/ */
JBUFFER_TRACE(jh, "cancelling revoke"); JBUFFER_TRACE(jh, "cancelling revoke");
journal_cancel_revoke(handle, jh); journal_cancel_revoke(handle, jh);
journal_put_journal_head(jh);
out: out:
journal_put_journal_head(jh);
return err; return err;
} }
...@@ -1069,8 +1067,9 @@ int journal_dirty_data(handle_t *handle, struct buffer_head *bh) ...@@ -1069,8 +1067,9 @@ int journal_dirty_data(handle_t *handle, struct buffer_head *bh)
ret = -EIO; ret = -EIO;
goto no_journal; goto no_journal;
} }
/* We might have slept so buffer could be refiled now */
if (jh->b_transaction != NULL) { if (jh->b_transaction != NULL &&
jh->b_transaction != handle->h_transaction) {
JBUFFER_TRACE(jh, "unfile from commit"); JBUFFER_TRACE(jh, "unfile from commit");
__journal_temp_unlink_buffer(jh); __journal_temp_unlink_buffer(jh);
/* It still points to the committing /* It still points to the committing
...@@ -1091,8 +1090,6 @@ int journal_dirty_data(handle_t *handle, struct buffer_head *bh) ...@@ -1091,8 +1090,6 @@ int journal_dirty_data(handle_t *handle, struct buffer_head *bh)
if (jh->b_jlist != BJ_SyncData && jh->b_jlist != BJ_Locked) { if (jh->b_jlist != BJ_SyncData && jh->b_jlist != BJ_Locked) {
JBUFFER_TRACE(jh, "not on correct data list: unfile"); JBUFFER_TRACE(jh, "not on correct data list: unfile");
J_ASSERT_JH(jh, jh->b_jlist != BJ_Shadow); J_ASSERT_JH(jh, jh->b_jlist != BJ_Shadow);
__journal_temp_unlink_buffer(jh);
jh->b_transaction = handle->h_transaction;
JBUFFER_TRACE(jh, "file as data"); JBUFFER_TRACE(jh, "file as data");
__journal_file_buffer(jh, handle->h_transaction, __journal_file_buffer(jh, handle->h_transaction,
BJ_SyncData); BJ_SyncData);
...@@ -1300,8 +1297,6 @@ int journal_forget (handle_t *handle, struct buffer_head *bh) ...@@ -1300,8 +1297,6 @@ int journal_forget (handle_t *handle, struct buffer_head *bh)
__journal_file_buffer(jh, transaction, BJ_Forget); __journal_file_buffer(jh, transaction, BJ_Forget);
} else { } else {
__journal_unfile_buffer(jh); __journal_unfile_buffer(jh);
journal_remove_journal_head(bh);
__brelse(bh);
if (!buffer_jbd(bh)) { if (!buffer_jbd(bh)) {
spin_unlock(&journal->j_list_lock); spin_unlock(&journal->j_list_lock);
jbd_unlock_bh_state(bh); jbd_unlock_bh_state(bh);
...@@ -1622,19 +1617,32 @@ static void __journal_temp_unlink_buffer(struct journal_head *jh) ...@@ -1622,19 +1617,32 @@ static void __journal_temp_unlink_buffer(struct journal_head *jh)
mark_buffer_dirty(bh); /* Expose it to the VM */ mark_buffer_dirty(bh); /* Expose it to the VM */
} }
/*
* Remove buffer from all transactions.
*
* Called with bh_state lock and j_list_lock
*
* jh and bh may be already freed when this function returns.
*/
void __journal_unfile_buffer(struct journal_head *jh) void __journal_unfile_buffer(struct journal_head *jh)
{ {
__journal_temp_unlink_buffer(jh); __journal_temp_unlink_buffer(jh);
jh->b_transaction = NULL; jh->b_transaction = NULL;
journal_put_journal_head(jh);
} }
void journal_unfile_buffer(journal_t *journal, struct journal_head *jh) void journal_unfile_buffer(journal_t *journal, struct journal_head *jh)
{ {
jbd_lock_bh_state(jh2bh(jh)); struct buffer_head *bh = jh2bh(jh);
/* Get reference so that buffer cannot be freed before we unlock it */
get_bh(bh);
jbd_lock_bh_state(bh);
spin_lock(&journal->j_list_lock); spin_lock(&journal->j_list_lock);
__journal_unfile_buffer(jh); __journal_unfile_buffer(jh);
spin_unlock(&journal->j_list_lock); spin_unlock(&journal->j_list_lock);
jbd_unlock_bh_state(jh2bh(jh)); jbd_unlock_bh_state(bh);
__brelse(bh);
} }
/* /*
...@@ -1661,16 +1669,12 @@ __journal_try_to_free_buffer(journal_t *journal, struct buffer_head *bh) ...@@ -1661,16 +1669,12 @@ __journal_try_to_free_buffer(journal_t *journal, struct buffer_head *bh)
/* A written-back ordered data buffer */ /* A written-back ordered data buffer */
JBUFFER_TRACE(jh, "release data"); JBUFFER_TRACE(jh, "release data");
__journal_unfile_buffer(jh); __journal_unfile_buffer(jh);
journal_remove_journal_head(bh);
__brelse(bh);
} }
} else if (jh->b_cp_transaction != NULL && jh->b_transaction == NULL) { } else if (jh->b_cp_transaction != NULL && jh->b_transaction == NULL) {
/* written-back checkpointed metadata buffer */ /* written-back checkpointed metadata buffer */
if (jh->b_jlist == BJ_None) { if (jh->b_jlist == BJ_None) {
JBUFFER_TRACE(jh, "remove from checkpoint list"); JBUFFER_TRACE(jh, "remove from checkpoint list");
__journal_remove_checkpoint(jh); __journal_remove_checkpoint(jh);
journal_remove_journal_head(bh);
__brelse(bh);
} }
} }
spin_unlock(&journal->j_list_lock); spin_unlock(&journal->j_list_lock);
...@@ -1733,7 +1737,7 @@ int journal_try_to_free_buffers(journal_t *journal, ...@@ -1733,7 +1737,7 @@ int journal_try_to_free_buffers(journal_t *journal,
/* /*
* We take our own ref against the journal_head here to avoid * We take our own ref against the journal_head here to avoid
* having to add tons of locking around each instance of * having to add tons of locking around each instance of
* journal_remove_journal_head() and journal_put_journal_head(). * journal_put_journal_head().
*/ */
jh = journal_grab_journal_head(bh); jh = journal_grab_journal_head(bh);
if (!jh) if (!jh)
...@@ -1770,10 +1774,9 @@ static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction) ...@@ -1770,10 +1774,9 @@ static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction)
int may_free = 1; int may_free = 1;
struct buffer_head *bh = jh2bh(jh); struct buffer_head *bh = jh2bh(jh);
__journal_unfile_buffer(jh);
if (jh->b_cp_transaction) { if (jh->b_cp_transaction) {
JBUFFER_TRACE(jh, "on running+cp transaction"); JBUFFER_TRACE(jh, "on running+cp transaction");
__journal_temp_unlink_buffer(jh);
/* /*
* We don't want to write the buffer anymore, clear the * We don't want to write the buffer anymore, clear the
* bit so that we don't confuse checks in * bit so that we don't confuse checks in
...@@ -1784,8 +1787,7 @@ static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction) ...@@ -1784,8 +1787,7 @@ static int __dispose_buffer(struct journal_head *jh, transaction_t *transaction)
may_free = 0; may_free = 0;
} else { } else {
JBUFFER_TRACE(jh, "on running transaction"); JBUFFER_TRACE(jh, "on running transaction");
journal_remove_journal_head(bh); __journal_unfile_buffer(jh);
__brelse(bh);
} }
return may_free; return may_free;
} }
...@@ -2070,6 +2072,8 @@ void __journal_file_buffer(struct journal_head *jh, ...@@ -2070,6 +2072,8 @@ void __journal_file_buffer(struct journal_head *jh,
if (jh->b_transaction) if (jh->b_transaction)
__journal_temp_unlink_buffer(jh); __journal_temp_unlink_buffer(jh);
else
journal_grab_journal_head(bh);
jh->b_transaction = transaction; jh->b_transaction = transaction;
switch (jlist) { switch (jlist) {
...@@ -2127,9 +2131,10 @@ void journal_file_buffer(struct journal_head *jh, ...@@ -2127,9 +2131,10 @@ void journal_file_buffer(struct journal_head *jh,
* already started to be used by a subsequent transaction, refile the * already started to be used by a subsequent transaction, refile the
* buffer on that transaction's metadata list. * buffer on that transaction's metadata list.
* *
* Called under journal->j_list_lock * Called under j_list_lock
*
* Called under jbd_lock_bh_state(jh2bh(jh)) * Called under jbd_lock_bh_state(jh2bh(jh))
*
* jh and bh may be already free when this function returns
*/ */
void __journal_refile_buffer(struct journal_head *jh) void __journal_refile_buffer(struct journal_head *jh)
{ {
...@@ -2153,6 +2158,11 @@ void __journal_refile_buffer(struct journal_head *jh) ...@@ -2153,6 +2158,11 @@ void __journal_refile_buffer(struct journal_head *jh)
was_dirty = test_clear_buffer_jbddirty(bh); was_dirty = test_clear_buffer_jbddirty(bh);
__journal_temp_unlink_buffer(jh); __journal_temp_unlink_buffer(jh);
/*
* We set b_transaction here because b_next_transaction will inherit
* our jh reference and thus __journal_file_buffer() must not take a
* new one.
*/
jh->b_transaction = jh->b_next_transaction; jh->b_transaction = jh->b_next_transaction;
jh->b_next_transaction = NULL; jh->b_next_transaction = NULL;
if (buffer_freed(bh)) if (buffer_freed(bh))
...@@ -2169,30 +2179,21 @@ void __journal_refile_buffer(struct journal_head *jh) ...@@ -2169,30 +2179,21 @@ void __journal_refile_buffer(struct journal_head *jh)
} }
/* /*
* For the unlocked version of this call, also make sure that any * __journal_refile_buffer() with necessary locking added. We take our bh
* hanging journal_head is cleaned up if necessary. * reference so that we can safely unlock bh.
* *
* __journal_refile_buffer is usually called as part of a single locked * The jh and bh may be freed by this call.
* operation on a buffer_head, in which the caller is probably going to
* be hooking the journal_head onto other lists. In that case it is up
* to the caller to remove the journal_head if necessary. For the
* unlocked journal_refile_buffer call, the caller isn't going to be
* doing anything else to the buffer so we need to do the cleanup
* ourselves to avoid a jh leak.
*
* *** The journal_head may be freed by this call! ***
*/ */
void journal_refile_buffer(journal_t *journal, struct journal_head *jh) void journal_refile_buffer(journal_t *journal, struct journal_head *jh)
{ {
struct buffer_head *bh = jh2bh(jh); struct buffer_head *bh = jh2bh(jh);
/* Get reference so that buffer cannot be freed before we unlock it */
get_bh(bh);
jbd_lock_bh_state(bh); jbd_lock_bh_state(bh);
spin_lock(&journal->j_list_lock); spin_lock(&journal->j_list_lock);
__journal_refile_buffer(jh); __journal_refile_buffer(jh);
jbd_unlock_bh_state(bh); jbd_unlock_bh_state(bh);
journal_remove_journal_head(bh);
spin_unlock(&journal->j_list_lock); spin_unlock(&journal->j_list_lock);
__brelse(bh); __brelse(bh);
} }
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/magic.h> #include <linux/magic.h>
#include <linux/fs.h>
/* /*
* The second extended filesystem constants/structures * The second extended filesystem constants/structures
......
...@@ -418,12 +418,11 @@ struct ext3_inode { ...@@ -418,12 +418,11 @@ struct ext3_inode {
#define EXT2_MOUNT_DATA_FLAGS EXT3_MOUNT_DATA_FLAGS #define EXT2_MOUNT_DATA_FLAGS EXT3_MOUNT_DATA_FLAGS
#endif #endif
#define ext3_set_bit __test_and_set_bit_le #define ext3_set_bit __set_bit_le
#define ext3_set_bit_atomic ext2_set_bit_atomic #define ext3_set_bit_atomic ext2_set_bit_atomic
#define ext3_clear_bit __test_and_clear_bit_le #define ext3_clear_bit __clear_bit_le
#define ext3_clear_bit_atomic ext2_clear_bit_atomic #define ext3_clear_bit_atomic ext2_clear_bit_atomic
#define ext3_test_bit test_bit_le #define ext3_test_bit test_bit_le
#define ext3_find_first_zero_bit find_first_zero_bit_le
#define ext3_find_next_zero_bit find_next_zero_bit_le #define ext3_find_next_zero_bit find_next_zero_bit_le
/* /*
...@@ -913,7 +912,7 @@ extern void ext3_dirty_inode(struct inode *, int); ...@@ -913,7 +912,7 @@ extern void ext3_dirty_inode(struct inode *, int);
extern int ext3_change_inode_journal_flag(struct inode *, int); extern int ext3_change_inode_journal_flag(struct inode *, int);
extern int ext3_get_inode_loc(struct inode *, struct ext3_iloc *); extern int ext3_get_inode_loc(struct inode *, struct ext3_iloc *);
extern int ext3_can_truncate(struct inode *inode); extern int ext3_can_truncate(struct inode *inode);
extern void ext3_truncate (struct inode *); extern void ext3_truncate(struct inode *inode);
extern void ext3_set_inode_flags(struct inode *); extern void ext3_set_inode_flags(struct inode *);
extern void ext3_get_inode_flags(struct ext3_inode_info *); extern void ext3_get_inode_flags(struct ext3_inode_info *);
extern void ext3_set_aops(struct inode *inode); extern void ext3_set_aops(struct inode *inode);
......
...@@ -940,7 +940,6 @@ extern int journal_force_commit(journal_t *); ...@@ -940,7 +940,6 @@ extern int journal_force_commit(journal_t *);
*/ */
struct journal_head *journal_add_journal_head(struct buffer_head *bh); struct journal_head *journal_add_journal_head(struct buffer_head *bh);
struct journal_head *journal_grab_journal_head(struct buffer_head *bh); struct journal_head *journal_grab_journal_head(struct buffer_head *bh);
void journal_remove_journal_head(struct buffer_head *bh);
void journal_put_journal_head(struct journal_head *jh); void journal_put_journal_head(struct journal_head *jh);
/* /*
......
...@@ -45,7 +45,7 @@ struct journal_head { ...@@ -45,7 +45,7 @@ struct journal_head {
* has been cowed * has been cowed
* [jbd_lock_bh_state()] * [jbd_lock_bh_state()]
*/ */
unsigned b_cow_tid; tid_t b_cow_tid;
/* /*
* Copy of the buffer data frozen for writing to the log. * Copy of the buffer data frozen for writing to the log.
......
...@@ -415,13 +415,5 @@ struct quota_module_name { ...@@ -415,13 +415,5 @@ struct quota_module_name {
{QFMT_VFS_V0, "quota_v2"},\ {QFMT_VFS_V0, "quota_v2"},\
{0, NULL}} {0, NULL}}
#else
# /* nodep */ include <sys/cdefs.h>
__BEGIN_DECLS
long quotactl __P ((unsigned int, const char *, int, caddr_t));
__END_DECLS
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* _QUOTA_ */ #endif /* _QUOTA_ */
This diff is collapsed.
#undef TRACE_SYSTEM
#define TRACE_SYSTEM jbd
#if !defined(_TRACE_JBD_H) || defined(TRACE_HEADER_MULTI_READ)
#define _TRACE_JBD_H
#include <linux/jbd.h>
#include <linux/tracepoint.h>
TRACE_EVENT(jbd_checkpoint,
TP_PROTO(journal_t *journal, int result),
TP_ARGS(journal, result),
TP_STRUCT__entry(
__field( dev_t, dev )
__field( int, result )
),
TP_fast_assign(
__entry->dev = journal->j_fs_dev->bd_dev;
__entry->result = result;
),
TP_printk("dev %d,%d result %d",
MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->result)
);
DECLARE_EVENT_CLASS(jbd_commit,
TP_PROTO(journal_t *journal, transaction_t *commit_transaction),
TP_ARGS(journal, commit_transaction),
TP_STRUCT__entry(
__field( dev_t, dev )
__field( char, sync_commit )
__field( int, transaction )
),
TP_fast_assign(
__entry->dev = journal->j_fs_dev->bd_dev;
__entry->sync_commit = commit_transaction->t_synchronous_commit;
__entry->transaction = commit_transaction->t_tid;
),
TP_printk("dev %d,%d transaction %d sync %d",
MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->transaction, __entry->sync_commit)
);
DEFINE_EVENT(jbd_commit, jbd_start_commit,
TP_PROTO(journal_t *journal, transaction_t *commit_transaction),
TP_ARGS(journal, commit_transaction)
);
DEFINE_EVENT(jbd_commit, jbd_commit_locking,
TP_PROTO(journal_t *journal, transaction_t *commit_transaction),
TP_ARGS(journal, commit_transaction)
);
DEFINE_EVENT(jbd_commit, jbd_commit_flushing,
TP_PROTO(journal_t *journal, transaction_t *commit_transaction),
TP_ARGS(journal, commit_transaction)
);
DEFINE_EVENT(jbd_commit, jbd_commit_logging,
TP_PROTO(journal_t *journal, transaction_t *commit_transaction),
TP_ARGS(journal, commit_transaction)
);
TRACE_EVENT(jbd_drop_transaction,
TP_PROTO(journal_t *journal, transaction_t *commit_transaction),
TP_ARGS(journal, commit_transaction),
TP_STRUCT__entry(
__field( dev_t, dev )
__field( char, sync_commit )
__field( int, transaction )
),
TP_fast_assign(
__entry->dev = journal->j_fs_dev->bd_dev;
__entry->sync_commit = commit_transaction->t_synchronous_commit;
__entry->transaction = commit_transaction->t_tid;
),
TP_printk("dev %d,%d transaction %d sync %d",
MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->transaction, __entry->sync_commit)
);
TRACE_EVENT(jbd_end_commit,
TP_PROTO(journal_t *journal, transaction_t *commit_transaction),
TP_ARGS(journal, commit_transaction),
TP_STRUCT__entry(
__field( dev_t, dev )
__field( char, sync_commit )
__field( int, transaction )
__field( int, head )
),
TP_fast_assign(
__entry->dev = journal->j_fs_dev->bd_dev;
__entry->sync_commit = commit_transaction->t_synchronous_commit;
__entry->transaction = commit_transaction->t_tid;
__entry->head = journal->j_tail_sequence;
),
TP_printk("dev %d,%d transaction %d sync %d head %d",
MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->transaction, __entry->sync_commit, __entry->head)
);
TRACE_EVENT(jbd_do_submit_data,
TP_PROTO(journal_t *journal, transaction_t *commit_transaction),
TP_ARGS(journal, commit_transaction),
TP_STRUCT__entry(
__field( dev_t, dev )
__field( char, sync_commit )
__field( int, transaction )
),
TP_fast_assign(
__entry->dev = journal->j_fs_dev->bd_dev;
__entry->sync_commit = commit_transaction->t_synchronous_commit;
__entry->transaction = commit_transaction->t_tid;
),
TP_printk("dev %d,%d transaction %d sync %d",
MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->transaction, __entry->sync_commit)
);
TRACE_EVENT(jbd_cleanup_journal_tail,
TP_PROTO(journal_t *journal, tid_t first_tid,
unsigned long block_nr, unsigned long freed),
TP_ARGS(journal, first_tid, block_nr, freed),
TP_STRUCT__entry(
__field( dev_t, dev )
__field( tid_t, tail_sequence )
__field( tid_t, first_tid )
__field(unsigned long, block_nr )
__field(unsigned long, freed )
),
TP_fast_assign(
__entry->dev = journal->j_fs_dev->bd_dev;
__entry->tail_sequence = journal->j_tail_sequence;
__entry->first_tid = first_tid;
__entry->block_nr = block_nr;
__entry->freed = freed;
),
TP_printk("dev %d,%d from %u to %u offset %lu freed %lu",
MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->tail_sequence, __entry->first_tid,
__entry->block_nr, __entry->freed)
);
TRACE_EVENT(jbd_update_superblock_end,
TP_PROTO(journal_t *journal, int wait),
TP_ARGS(journal, wait),
TP_STRUCT__entry(
__field( dev_t, dev )
__field( int, wait )
),
TP_fast_assign(
__entry->dev = journal->j_fs_dev->bd_dev;
__entry->wait = wait;
),
TP_printk("dev %d,%d wait %d",
MAJOR(__entry->dev), MINOR(__entry->dev),
__entry->wait)
);
#endif /* _TRACE_JBD_H */
/* This part must be outside protection */
#include <trace/define_trace.h>
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