diff options
author | Avik Sil <avik.sil@linaro.org> | 2011-03-31 11:06:38 +0000 |
---|---|---|
committer | Avik Sil <avik.sil@linaro.org> | 2011-03-31 11:06:38 +0000 |
commit | ebb688e3183bd5891312bdb8f4e2f520d70b36b6 (patch) | |
tree | c30d1abefaccc8cd1baa4944aae3348668e13bde /fs | |
parent | 8061f3a885ec3538bf405ff3957c205b1ab2aae4 (diff) | |
parent | b2afcd30fff4c24290a63a2497de301864d9726d (diff) |
Merge remote branch 'lttng/2.6.38-lttng-0.247'
Conflicts:
arch/arm/kernel/traps.c
arch/arm/mach-omap2/clock34xx.c
arch/arm/mach-omap2/pm34xx.c
Diffstat (limited to 'fs')
-rw-r--r-- | fs/buffer.c | 6 | ||||
-rw-r--r-- | fs/compat.c | 2 | ||||
-rw-r--r-- | fs/exec.c | 7 | ||||
-rw-r--r-- | fs/ioctl.c | 5 | ||||
-rw-r--r-- | fs/open.c | 6 | ||||
-rw-r--r-- | fs/read_write.c | 28 | ||||
-rw-r--r-- | fs/select.c | 47 | ||||
-rw-r--r-- | fs/seq_file.c | 44 | ||||
-rw-r--r-- | fs/splice.c | 1 |
9 files changed, 141 insertions, 5 deletions
diff --git a/fs/buffer.c b/fs/buffer.c index 2219a76e2ca..5d0c2c6045c 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -41,11 +41,15 @@ #include <linux/bitops.h> #include <linux/mpage.h> #include <linux/bit_spinlock.h> +#include <trace/fs.h> static int fsync_buffers_list(spinlock_t *lock, struct list_head *list); #define BH_ENTRY(list) list_entry((list), struct buffer_head, b_assoc_buffers) +DEFINE_TRACE(fs_buffer_wait_start); +DEFINE_TRACE(fs_buffer_wait_end); + inline void init_buffer(struct buffer_head *bh, bh_end_io_t *handler, void *private) { @@ -90,7 +94,9 @@ EXPORT_SYMBOL(unlock_buffer); */ void __wait_on_buffer(struct buffer_head * bh) { + trace_fs_buffer_wait_start(bh); wait_on_bit(&bh->b_state, BH_Lock, sync_buffer, TASK_UNINTERRUPTIBLE); + trace_fs_buffer_wait_end(bh); } EXPORT_SYMBOL(__wait_on_buffer); diff --git a/fs/compat.c b/fs/compat.c index 691c3fd8ce1..933042d14e6 100644 --- a/fs/compat.c +++ b/fs/compat.c @@ -50,6 +50,7 @@ #include <linux/fs_struct.h> #include <linux/slab.h> #include <linux/pagemap.h> +#include <trace/fs.h> #include <asm/uaccess.h> #include <asm/mmu_context.h> @@ -1533,6 +1534,7 @@ int compat_do_execve(char * filename, if (retval < 0) goto out; + trace_fs_exec(filename); /* execve succeeded */ current->fs->in_exec = 0; current->in_execve = 0; diff --git a/fs/exec.c b/fs/exec.c index 52a447d9b6a..9a92bbe142d 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -55,6 +55,7 @@ #include <linux/fs_struct.h> #include <linux/pipe_fs_i.h> #include <linux/oom.h> +#include <trace/fs.h> #include <asm/uaccess.h> #include <asm/mmu_context.h> @@ -77,6 +78,11 @@ static atomic_t call_count = ATOMIC_INIT(1); static LIST_HEAD(formats); static DEFINE_RWLOCK(binfmt_lock); +/* + * Also used in compat.c. + */ +DEFINE_TRACE(fs_exec); + int __register_binfmt(struct linux_binfmt * fmt, int insert) { if (!fmt) @@ -1447,6 +1453,7 @@ int do_execve(const char * filename, if (retval < 0) goto out; + trace_fs_exec(filename); /* execve succeeded */ current->fs->in_exec = 0; current->in_execve = 0; diff --git a/fs/ioctl.c b/fs/ioctl.c index 1eebeb72b20..a1fecf33b11 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c @@ -15,9 +15,12 @@ #include <linux/writeback.h> #include <linux/buffer_head.h> #include <linux/falloc.h> +#include <trace/fs.h> #include <asm/ioctls.h> +DEFINE_TRACE(fs_ioctl); + /* So that the fiemap access checks can't overflow on 32 bit machines. */ #define FIEMAP_MAX_EXTENTS (UINT_MAX / sizeof(struct fiemap_extent)) @@ -616,6 +619,8 @@ SYSCALL_DEFINE3(ioctl, unsigned int, fd, unsigned int, cmd, unsigned long, arg) if (!filp) goto out; + trace_fs_ioctl(fd, cmd, arg); + error = security_file_ioctl(filp, cmd, arg); if (error) goto out_fput; diff --git a/fs/open.c b/fs/open.c index b47aab39c05..575c92f3b81 100644 --- a/fs/open.c +++ b/fs/open.c @@ -30,9 +30,13 @@ #include <linux/fs_struct.h> #include <linux/ima.h> #include <linux/dnotify.h> +#include <trace/fs.h> #include "internal.h" +DEFINE_TRACE(fs_open); +DEFINE_TRACE(fs_close); + int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs, struct file *filp) { @@ -906,6 +910,7 @@ long do_sys_open(int dfd, const char __user *filename, int flags, int mode) fsnotify_open(f); fd_install(fd, f); } + trace_fs_open(fd, tmp); } putname(tmp); } @@ -995,6 +1000,7 @@ SYSCALL_DEFINE1(close, unsigned int, fd) filp = fdt->fd[fd]; if (!filp) goto out_unlock; + trace_fs_close(fd); rcu_assign_pointer(fdt->fd[fd], NULL); FD_CLR(fd, fdt->close_on_exec); __put_unused_fd(files, fd); diff --git a/fs/read_write.c b/fs/read_write.c index 5520f8ad550..6a3f7f9c9db 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -15,6 +15,7 @@ #include <linux/syscalls.h> #include <linux/pagemap.h> #include <linux/splice.h> +#include <trace/fs.h> #include "read_write.h" #include <asm/uaccess.h> @@ -30,6 +31,15 @@ const struct file_operations generic_ro_fops = { EXPORT_SYMBOL(generic_ro_fops); +DEFINE_TRACE(fs_lseek); +DEFINE_TRACE(fs_llseek); +DEFINE_TRACE(fs_read); +DEFINE_TRACE(fs_write); +DEFINE_TRACE(fs_pread64); +DEFINE_TRACE(fs_pwrite64); +DEFINE_TRACE(fs_readv); +DEFINE_TRACE(fs_writev); + static inline int unsigned_offsets(struct file *file) { return file->f_mode & FMODE_UNSIGNED_OFFSET; @@ -187,6 +197,9 @@ SYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, origin) if (res != (loff_t)retval) retval = -EOVERFLOW; /* LFS: should only happen on 32 bit platforms */ } + + trace_fs_lseek(fd, offset, origin); + fput_light(file, fput_needed); bad: return retval; @@ -214,6 +227,8 @@ SYSCALL_DEFINE5(llseek, unsigned int, fd, unsigned long, offset_high, offset = vfs_llseek(file, ((loff_t) offset_high << 32) | offset_low, origin); + trace_fs_llseek(fd, offset, origin); + retval = (int)offset; if (offset >= 0) { retval = -EFAULT; @@ -409,6 +424,7 @@ SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count) if (file) { loff_t pos = file_pos_read(file); ret = vfs_read(file, buf, count, &pos); + trace_fs_read(fd, buf, count, ret); file_pos_write(file, pos); fput_light(file, fput_needed); } @@ -427,6 +443,7 @@ SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf, if (file) { loff_t pos = file_pos_read(file); ret = vfs_write(file, buf, count, &pos); + trace_fs_write(fd, buf, count, ret); file_pos_write(file, pos); fput_light(file, fput_needed); } @@ -447,8 +464,11 @@ SYSCALL_DEFINE(pread64)(unsigned int fd, char __user *buf, file = fget_light(fd, &fput_needed); if (file) { ret = -ESPIPE; - if (file->f_mode & FMODE_PREAD) + if (file->f_mode & FMODE_PREAD) { ret = vfs_read(file, buf, count, &pos); + trace_fs_pread64(fd, buf, count, pos, ret); + } + fput_light(file, fput_needed); } @@ -476,8 +496,10 @@ SYSCALL_DEFINE(pwrite64)(unsigned int fd, const char __user *buf, file = fget_light(fd, &fput_needed); if (file) { ret = -ESPIPE; - if (file->f_mode & FMODE_PWRITE) + if (file->f_mode & FMODE_PWRITE) { ret = vfs_write(file, buf, count, &pos); + trace_fs_pwrite64(fd, buf, count, pos, ret); + } fput_light(file, fput_needed); } @@ -736,6 +758,7 @@ SYSCALL_DEFINE3(readv, unsigned long, fd, const struct iovec __user *, vec, if (file) { loff_t pos = file_pos_read(file); ret = vfs_readv(file, vec, vlen, &pos); + trace_fs_readv(fd, vec, vlen, ret); file_pos_write(file, pos); fput_light(file, fput_needed); } @@ -757,6 +780,7 @@ SYSCALL_DEFINE3(writev, unsigned long, fd, const struct iovec __user *, vec, if (file) { loff_t pos = file_pos_read(file); ret = vfs_writev(file, vec, vlen, &pos); + trace_fs_writev(fd, vec, vlen, ret); file_pos_write(file, pos); fput_light(file, fput_needed); } diff --git a/fs/select.c b/fs/select.c index e56560d2b08..64c2404f2cc 100644 --- a/fs/select.c +++ b/fs/select.c @@ -26,6 +26,7 @@ #include <linux/fs.h> #include <linux/rcupdate.h> #include <linux/hrtimer.h> +#include <trace/fs.h> #include <asm/uaccess.h> @@ -98,6 +99,9 @@ struct poll_table_page { #define POLL_TABLE_FULL(table) \ ((unsigned long)((table)->entry+1) > PAGE_SIZE + (unsigned long)(table)) +DEFINE_TRACE(fs_select); +DEFINE_TRACE(fs_poll); + /* * Ok, Peter made a complicated, but straightforward multiple_wait() function. * I have rewritten this, taking some shortcuts: This code may not be easy to @@ -112,6 +116,9 @@ struct poll_table_page { */ static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p); +static void __pollwait_exclusive(struct file *filp, + wait_queue_head_t *wait_address, + poll_table *p); void poll_initwait(struct poll_wqueues *pwq) { @@ -152,6 +159,20 @@ void poll_freewait(struct poll_wqueues *pwq) } EXPORT_SYMBOL(poll_freewait); +/** + * poll_wait_set_exclusive - set poll wait queue to exclusive + * + * Sets up a poll wait queue to use exclusive wakeups. This is useful to + * wake up only one waiter at each wakeup. Used to work-around "thundering herd" + * problem. + */ +void poll_wait_set_exclusive(poll_table *p) +{ + if (p) + init_poll_funcptr(p, __pollwait_exclusive); +} +EXPORT_SYMBOL(poll_wait_set_exclusive); + static struct poll_table_entry *poll_get_entry(struct poll_wqueues *p) { struct poll_table_page *table = p->table; @@ -213,8 +234,10 @@ static int pollwake(wait_queue_t *wait, unsigned mode, int sync, void *key) } /* Add a new entry */ -static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, - poll_table *p) +static void __pollwait_common(struct file *filp, + wait_queue_head_t *wait_address, + poll_table *p, + int exclusive) { struct poll_wqueues *pwq = container_of(p, struct poll_wqueues, pt); struct poll_table_entry *entry = poll_get_entry(pwq); @@ -226,7 +249,23 @@ static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, entry->key = p->key; init_waitqueue_func_entry(&entry->wait, pollwake); entry->wait.private = pwq; - add_wait_queue(wait_address, &entry->wait); + if (!exclusive) + add_wait_queue(wait_address, &entry->wait); + else + add_wait_queue_exclusive(wait_address, &entry->wait); +} + +static void __pollwait(struct file *filp, wait_queue_head_t *wait_address, + poll_table *p) +{ + __pollwait_common(filp, wait_address, p, 0); +} + +static void __pollwait_exclusive(struct file *filp, + wait_queue_head_t *wait_address, + poll_table *p) +{ + __pollwait_common(filp, wait_address, p, 1); } int poll_schedule_timeout(struct poll_wqueues *pwq, int state, @@ -450,6 +489,7 @@ int do_select(int n, fd_set_bits *fds, struct timespec *end_time) file = fget_light(i, &fput_needed); if (file) { f_op = file->f_op; + trace_fs_select(i, end_time); mask = DEFAULT_POLLMASK; if (f_op && f_op->poll) { wait_key_set(wait, in, out, bit); @@ -739,6 +779,7 @@ static inline unsigned int do_pollfd(struct pollfd *pollfd, poll_table *pwait) file = fget_light(fd, &fput_needed); mask = POLLNVAL; if (file != NULL) { + trace_fs_poll(fd); mask = DEFAULT_POLLMASK; if (file->f_op && file->f_op->poll) { if (pwait) diff --git a/fs/seq_file.c b/fs/seq_file.c index 05d6b0e78c9..691c84baf4f 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c @@ -819,3 +819,47 @@ struct hlist_node *seq_hlist_next_rcu(void *v, return rcu_dereference(node->next); } EXPORT_SYMBOL(seq_hlist_next_rcu); + +struct list_head *seq_sorted_list_start(struct list_head *head, loff_t *ppos) +{ + struct list_head *lh; + + list_for_each(lh, head) + if ((unsigned long)lh >= *ppos) { + *ppos = (unsigned long)lh; + return lh; + } + return NULL; +} +EXPORT_SYMBOL(seq_sorted_list_start); + +struct list_head *seq_sorted_list_start_head(struct list_head *head, + loff_t *ppos) +{ + struct list_head *lh; + + if (!*ppos) { + *ppos = (unsigned long)head; + return head; + } + list_for_each(lh, head) + if ((unsigned long)lh >= *ppos) { + *ppos = (long)lh->prev; + return lh->prev; + } + return NULL; +} +EXPORT_SYMBOL(seq_sorted_list_start_head); + +struct list_head *seq_sorted_list_next(void *p, struct list_head *head, + loff_t *ppos) +{ + struct list_head *lh; + void *next; + + lh = ((struct list_head *)p)->next; + next = (lh == head) ? NULL : lh; + *ppos = next ? ((unsigned long)next) : (-1UL); + return next; +} +EXPORT_SYMBOL(seq_sorted_list_next); diff --git a/fs/splice.c b/fs/splice.c index 50a5d978da1..e76aac5c993 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -259,6 +259,7 @@ ssize_t splice_to_pipe(struct pipe_inode_info *pipe, return ret; } +EXPORT_SYMBOL_GPL(splice_to_pipe); static void spd_release_page(struct splice_pipe_desc *spd, unsigned int i) { |