- Merge SLE11-SP3 rpm-3.0.76-0.11-167-g92d1972
- Fix LOCK_STAT build bug while here.
- patches.rt/0349-fs-dentry-use-seqlock.patch
suse-commit: 82ddc307ddc3fad0d5612522a290b606788ce5d1
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index b7edde3..608fc2e 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -904,11 +904,11 @@
return NULL;
if (pt->misc & DRM_EDID_PT_STEREO) {
- printk(KERN_WARNING "stereo mode not supported\n");
+ DRM_DEBUG_KMS("stereo mode not supported\n");
return NULL;
}
if (!(pt->misc & DRM_EDID_PT_SEPARATE_SYNC)) {
- printk(KERN_WARNING "composite sync not supported\n");
+ DRM_DEBUG_KMS("composite sync not supported\n");
}
/* it is incorrect if hsync/vsync width is zero */
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index 18d80cc..42cccce 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -16994,10 +16994,13 @@
tg3_full_unlock(tp);
done:
- if (state == pci_channel_io_perm_failure)
+ if (state == pci_channel_io_perm_failure) {
+ tg3_napi_enable(tp);
+ dev_close(netdev);
err = PCI_ERS_RESULT_DISCONNECT;
- else
+ } else {
pci_disable_device(pdev);
+ }
rtnl_unlock();
@@ -17043,6 +17046,10 @@
rc = PCI_ERS_RESULT_RECOVERED;
done:
+ if (rc != PCI_ERS_RESULT_RECOVERED && netif_running(netdev)) {
+ tg3_napi_enable(tp);
+ dev_close(netdev);
+ }
rtnl_unlock();
return rc;
diff --git a/drivers/pci/hotplug/pciehp_core.c b/drivers/pci/hotplug/pciehp_core.c
index 23e7503..84d3a6b 100644
--- a/drivers/pci/hotplug/pciehp_core.c
+++ b/drivers/pci/hotplug/pciehp_core.c
@@ -356,14 +356,14 @@
/* HP Probook 445 */
.ident = "HP ProBook 445",
.matches = {
- DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook 445 G1 Notebook PC"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook 445 G1"),
},
},
{
/* HP Probook 455 */
.ident = "HP ProBook 455",
.matches = {
- DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook 455 G1 Notebook PC"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook 455 G1"),
},
},
{} /* terminating entry */
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index acf4eac..dbfc0e1 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -876,6 +876,8 @@
return SCSI_DH_RETRY;
}
switch (pg->state) {
+ case TPGS_STATE_OPTIMIZED:
+ return SCSI_DH_OK;
case TPGS_STATE_NONOPTIMIZED:
if ((pg->flags & ALUA_OPTIMIZE_STPG) &&
(!pg->pref) &&
@@ -890,10 +892,11 @@
break;
case TPGS_STATE_TRANSITIONING:
return SCSI_DH_RETRY;
- break;
default:
+ sdev_printk(KERN_INFO, sdev,
+ "%s: stpg failed, unhandled TPGS state %d",
+ ALUA_DH_NAME, pg->state);
return SCSI_DH_NOSYS;
- break;
}
retval = submit_stpg(sdev, pg->group_id, sense);
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index e33741a..74ef935 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -571,6 +571,20 @@
},
.driver_data = (void *)64,
},
+ {
+ /* HP EliteBook 8580 */
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook 8580w"),
+ },
+ .driver_data = (void *)64,
+ },
+ {
+ /* HP EliteBook 8780 */
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "HP EliteBook 8780w"),
+ },
+ .driver_data = (void *)64,
+ },
{ }
};
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
index c9d9421..e38f37e 100644
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -85,25 +85,21 @@
{
struct autofs_sb_info *sbi = autofs4_sbi(root->d_sb);
struct list_head *next;
- struct dentry *p, *q;
+ struct dentry *q;
spin_lock(&sbi->lookup_lock);
+ seq_spin_lock(&root->d_lock);
- if (prev == NULL) {
- seq_spin_lock(&root->d_lock);
+ if (prev)
+ next = prev->d_u.d_child.next;
+ else {
prev = dget_dlock(root);
next = prev->d_subdirs.next;
- p = prev;
- goto start;
}
- p = prev;
- seq_spin_lock(&p->d_lock);
-again:
- next = p->d_u.d_child.next;
-start:
+cont:
if (next == &root->d_subdirs) {
- seq_spin_unlock(&p->d_lock);
+ seq_spin_unlock(&root->d_lock);
spin_unlock(&sbi->lookup_lock);
dput(prev);
return NULL;
@@ -112,16 +108,15 @@
q = list_entry(next, struct dentry, d_u.d_child);
seq_spin_lock_nested(&q->d_lock, DENTRY_D_LOCK_NESTED);
- /* Negative dentry - try next */
- if (!simple_positive(q)) {
- seq_spin_unlock(&p->d_lock);
- lock_set_subclass(&q->d_lock.dep_map, 0, _RET_IP_);
- p = q;
- goto again;
+ /* Already gone or negative dentry (under construction) - try next */
+ if (q->d_count == 0 || !simple_positive(q)) {
+ seq_spin_unlock(&q->d_lock);
+ next = q->d_u.d_child.next;
+ goto cont;
}
dget_dlock(q);
seq_spin_unlock(&q->d_lock);
- seq_spin_unlock(&p->d_lock);
+ seq_spin_unlock(&root->d_lock);
spin_unlock(&sbi->lookup_lock);
dput(prev);
@@ -178,7 +173,7 @@
/* Negative dentry - try next */
if (!simple_positive(ret)) {
seq_spin_unlock(&p->d_lock);
- lock_set_subclass(&ret->d_lock.dep_map, 0, _RET_IP_);
+ lock_set_subclass(&ret->d_lock.lock.dep_map, 0, _RET_IP_);
p = ret;
goto again;
}
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 2ee75c7..918048e 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1441,7 +1441,6 @@
int do_barriers;
int closing;
int log_root_recovering;
- int enospc_unlink;
int trans_no_join;
u64 total_pinned;
@@ -3090,6 +3089,9 @@
int btrfs_block_rsv_migrate(struct btrfs_block_rsv *src_rsv,
struct btrfs_block_rsv *dst_rsv,
u64 num_bytes);
+int btrfs_cond_migrate_bytes(struct btrfs_fs_info *fs_info,
+ struct btrfs_block_rsv *dest, u64 num_bytes,
+ int min_factor);
void btrfs_block_rsv_release(struct btrfs_root *root,
struct btrfs_block_rsv *block_rsv,
u64 num_bytes);
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index c55ef57..c6efd22 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -4234,6 +4234,31 @@
spin_unlock(&block_rsv->lock);
}
+int btrfs_cond_migrate_bytes(struct btrfs_fs_info *fs_info,
+ struct btrfs_block_rsv *dest, u64 num_bytes,
+ int min_factor)
+{
+ struct btrfs_block_rsv *global_rsv = &fs_info->global_block_rsv;
+ u64 min_bytes;
+
+ if (global_rsv->space_info != dest->space_info)
+ return -ENOSPC;
+
+ spin_lock(&global_rsv->lock);
+ min_bytes = div_factor(global_rsv->size, min_factor);
+ if (global_rsv->reserved < min_bytes + num_bytes) {
+ spin_unlock(&global_rsv->lock);
+ return -ENOSPC;
+ }
+ global_rsv->reserved -= num_bytes;
+ if (global_rsv->reserved < global_rsv->size)
+ global_rsv->full = 0;
+ spin_unlock(&global_rsv->lock);
+
+ block_rsv_add_bytes(dest, num_bytes, 1);
+ return 0;
+}
+
static void block_rsv_release_bytes(struct btrfs_fs_info *fs_info,
struct btrfs_block_rsv *block_rsv,
struct btrfs_block_rsv *dest, u64 num_bytes)
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index ded94b2..5d9357b 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -3642,53 +3642,20 @@
}
return ret;
}
-
-
-/* helper to check if there is any shared block in the path */
-static int check_path_shared(struct btrfs_root *root,
- struct btrfs_path *path)
-{
- struct extent_buffer *eb;
- int level;
- u64 refs = 1;
-
- for (level = 0; level < BTRFS_MAX_LEVEL; level++) {
- int ret;
-
- if (!path->nodes[level])
- break;
- eb = path->nodes[level];
- if (!btrfs_block_can_be_shared(root, eb))
- continue;
- ret = btrfs_lookup_extent_info(NULL, root, eb->start, eb->len,
- &refs, NULL);
- if (refs > 1)
- return 1;
- }
- return 0;
-}
/*
* helper to start transaction for unlink and rmdir.
*
- * unlink and rmdir are special in btrfs, they do not always free space.
- * so in enospc case, we should make sure they will free space before
- * allowing them to use the global metadata reservation.
+ * unlink and rmdir are special in btrfs, they do not always free space, so
+ * if we cannot make our reservations the normal way try and see if there is
+ * plenty of slack room in the global reserve to migrate, otherwise we cannot
+ * allow the unlink to occur.
*/
-static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir,
- struct dentry *dentry)
+static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir)
{
struct btrfs_trans_handle *trans;
struct btrfs_root *root = BTRFS_I(dir)->root;
- struct btrfs_path *path;
- struct btrfs_dir_item *di;
- struct inode *inode = dentry->d_inode;
- u64 index;
- int check_link = 1;
- int err = -ENOSPC;
int ret;
- u64 ino = btrfs_ino(inode);
- u64 dir_ino = btrfs_ino(dir);
/*
* 1 for the possible orphan item
@@ -3701,158 +3668,23 @@
if (!IS_ERR(trans) || PTR_ERR(trans) != -ENOSPC)
return trans;
- if (ino == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)
- return ERR_PTR(-ENOSPC);
+ if (PTR_ERR(trans) == -ENOSPC) {
+ u64 num_bytes = btrfs_calc_trans_metadata_size(root, 5);
- /* check if there is someone else holds reference */
- if (S_ISDIR(inode->i_mode) && atomic_read(&inode->i_count) > 1)
- return ERR_PTR(-ENOSPC);
-
- if (atomic_read(&inode->i_count) > 2)
- return ERR_PTR(-ENOSPC);
-
- if (xchg(&root->fs_info->enospc_unlink, 1))
- return ERR_PTR(-ENOSPC);
-
- path = btrfs_alloc_path();
- if (!path) {
- root->fs_info->enospc_unlink = 0;
- return ERR_PTR(-ENOMEM);
- }
-
- /* 1 for the orphan item */
- trans = btrfs_start_transaction(root, 1);
- if (IS_ERR(trans)) {
- btrfs_free_path(path);
- root->fs_info->enospc_unlink = 0;
- return trans;
- }
-
- path->skip_locking = 1;
- path->search_commit_root = 1;
-
- ret = btrfs_lookup_inode(trans, root, path,
- &BTRFS_I(dir)->location, 0);
- if (ret < 0) {
- err = ret;
- goto out;
- }
- if (ret == 0) {
- if (check_path_shared(root, path))
- goto out;
- } else {
- check_link = 0;
- }
- btrfs_release_path(path);
-
- ret = btrfs_lookup_inode(trans, root, path,
- &BTRFS_I(inode)->location, 0);
- if (ret < 0) {
- err = ret;
- goto out;
- }
- if (ret == 0) {
- if (check_path_shared(root, path))
- goto out;
- } else {
- check_link = 0;
- }
- btrfs_release_path(path);
-
- if (ret == 0 && S_ISREG(inode->i_mode)) {
- ret = btrfs_lookup_file_extent(trans, root, path,
- ino, (u64)-1, 0);
- if (ret < 0) {
- err = ret;
- goto out;
+ trans = btrfs_start_transaction(root, 0);
+ if (IS_ERR(trans))
+ return trans;
+ ret = btrfs_cond_migrate_bytes(root->fs_info,
+ &root->fs_info->trans_block_rsv,
+ num_bytes, 5);
+ if (ret) {
+ btrfs_end_transaction(trans, root);
+ return ERR_PTR(ret);
}
- BUG_ON(ret == 0); /* Corruption */
- if (check_path_shared(root, path))
- goto out;
- btrfs_release_path(path);
- }
-
- if (!check_link) {
- err = 0;
- goto out;
- }
-
- di = btrfs_lookup_dir_item(trans, root, path, dir_ino,
- dentry->d_name.name, dentry->d_name.len, 0);
- if (IS_ERR(di)) {
- err = PTR_ERR(di);
- goto out;
- }
- if (di) {
- if (check_path_shared(root, path))
- goto out;
- } else {
- err = 0;
- goto out;
- }
- btrfs_release_path(path);
-
- ret = btrfs_get_inode_ref_index(trans, root, path, dentry->d_name.name,
- dentry->d_name.len, ino, dir_ino, 0,
- &index);
- if (ret) {
- err = ret;
- goto out;
- }
-
- if (check_path_shared(root, path))
- goto out;
-
- btrfs_release_path(path);
-
- /*
- * This is a commit root search, if we can lookup inode item and other
- * relative items in the commit root, it means the transaction of
- * dir/file creation has been committed, and the dir index item that we
- * delay to insert has also been inserted into the commit root. So
- * we needn't worry about the delayed insertion of the dir index item
- * here.
- */
- di = btrfs_lookup_dir_index_item(trans, root, path, dir_ino, index,
- dentry->d_name.name, dentry->d_name.len, 0);
- if (IS_ERR(di)) {
- err = PTR_ERR(di);
- goto out;
- }
- BUG_ON(ret == -ENOENT);
- if (check_path_shared(root, path))
- goto out;
-
- err = 0;
-out:
- btrfs_free_path(path);
- /* Migrate the orphan reservation over */
- if (!err)
- err = btrfs_block_rsv_migrate(trans->block_rsv,
- &root->fs_info->global_block_rsv,
- trans->bytes_reserved);
-
- if (err) {
- btrfs_end_transaction(trans, root);
- root->fs_info->enospc_unlink = 0;
- return ERR_PTR(err);
- }
-
- trans->block_rsv = &root->fs_info->global_block_rsv;
- return trans;
-}
-
-static void __unlink_end_trans(struct btrfs_trans_handle *trans,
- struct btrfs_root *root)
-{
- if (trans->block_rsv->type == BTRFS_BLOCK_RSV_GLOBAL) {
- btrfs_block_rsv_release(root, trans->block_rsv,
- trans->bytes_reserved);
trans->block_rsv = &root->fs_info->trans_block_rsv;
- BUG_ON(!root->fs_info->enospc_unlink);
- root->fs_info->enospc_unlink = 0;
+ trans->bytes_reserved = num_bytes;
}
- btrfs_end_transaction(trans, root);
+ return trans;
}
static int btrfs_unlink(struct inode *dir, struct dentry *dentry)
@@ -3862,7 +3694,7 @@
struct inode *inode = dentry->d_inode;
int ret;
- trans = __unlink_start_trans(dir, dentry);
+ trans = __unlink_start_trans(dir);
if (IS_ERR(trans))
return PTR_ERR(trans);
@@ -3880,7 +3712,7 @@
}
out:
- __unlink_end_trans(trans, root);
+ btrfs_end_transaction(trans, root);
btrfs_btree_balance_dirty(root);
return ret;
}
@@ -3977,7 +3809,7 @@
if (btrfs_ino(inode) == BTRFS_FIRST_FREE_OBJECTID)
return -EPERM;
- trans = __unlink_start_trans(dir, dentry);
+ trans = __unlink_start_trans(dir);
if (IS_ERR(trans))
return PTR_ERR(trans);
@@ -3999,7 +3831,7 @@
if (!err)
btrfs_i_size_write(inode, 0);
out:
- __unlink_end_trans(trans, root);
+ btrfs_end_transaction(trans, root);
btrfs_btree_balance_dirty(root);
return err;
diff --git a/fs/exec.c b/fs/exec.c
index a215e7a..e60a029 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -56,6 +56,8 @@
#include <linux/oom.h>
#include <linux/compat.h>
+#include <trace/events/fs-open.h>
+
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
#include <asm/tlb.h>
@@ -140,6 +142,8 @@
fsnotify_open(file);
+ trace_uselib(file);
+
error = -ENOEXEC;
if(file->f_op) {
struct linux_binfmt * fmt;
@@ -789,6 +793,8 @@
fsnotify_open(file);
+ trace_open_exec(file);
+
if (file->f_op && file->f_op->open_exec) {
err = file->f_op->open_exec(file->f_path.dentry->d_inode);
if (err)
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 72a226f..15e9afd 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -245,6 +245,8 @@
return ret;
}
+extern struct super_block *blockdev_superblock;
+
/*
* Move expired dirty inodes from @delaying_queue to @dispatch_queue.
*/
@@ -263,10 +265,12 @@
if (older_than_this &&
inode_dirtied_after(inode, *older_than_this))
break;
+ list_move(&inode->i_wb_list, &tmp);
+ if (inode->i_sb == blockdev_superblock)
+ continue;
if (sb && sb != inode->i_sb)
do_sb_sort = 1;
sb = inode->i_sb;
- list_move(&inode->i_wb_list, &tmp);
}
/* just one sb in list, splice to dispatch_queue and we're done */
@@ -301,7 +305,14 @@
{
assert_spin_locked(&wb->list_lock);
list_splice_init(&wb->b_more_io, &wb->b_io);
- move_expired_inodes(&wb->b_dirty, &wb->b_io, older_than_this);
+ /*
+ * If we want all inodes and we don't have to sort superblocks, just
+ * splice the list
+ */
+ if (!older_than_this && !test_bit(BDI_multiple_sb, &wb->bdi->state))
+ list_splice_init(&wb->b_dirty, &wb->b_io);
+ else
+ move_expired_inodes(&wb->b_dirty, &wb->b_io, older_than_this);
}
static int write_inode(struct inode *inode, struct writeback_control *wbc)
@@ -517,6 +528,15 @@
struct inode *inode = wb_inode(wb->b_io.prev);
if (inode->i_sb != sb) {
+ /*
+ * Really two different filesystem superblocks? Mark
+ * the bdi as such so that we sort inodes by sb from
+ * now on.
+ */
+ if (inode->i_sb != blockdev_superblock &&
+ sb != blockdev_superblock &&
+ !test_bit(BDI_multiple_sb, &wb->bdi->state))
+ set_bit(BDI_multiple_sb, &wb->bdi->state);
if (only_this_sb) {
/*
* We only want to write back data for this
diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h
index a3385b6..7d927cd 100644
--- a/fs/ocfs2/journal.h
+++ b/fs/ocfs2/journal.h
@@ -538,7 +538,7 @@
extent_blocks = 1 + 1 + le16_to_cpu(root_el->l_tree_depth);
return bitmap_blocks + sysfile_bitmap_blocks + extent_blocks +
- ocfs2_quota_trans_credits(sb);
+ ocfs2_quota_trans_credits(sb) + bits_wanted;
}
static inline int ocfs2_calc_symlink_credits(struct super_block *sb)
diff --git a/fs/open.c b/fs/open.c
index bf00a86..9c72cfa 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -33,6 +33,9 @@
#include "internal.h"
+#define CREATE_TRACE_POINTS
+#include <trace/events/fs-open.h>
+
int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
struct file *filp)
{
@@ -1006,6 +1009,7 @@
} else {
fsnotify_open(f);
fd_install(fd, f);
+ trace_do_sys_open(f, flags, mode);
}
}
putname(tmp);
diff --git a/include/linux/backing-dev.h b/include/linux/backing-dev.h
index 304af69..c1f07a8 100644
--- a/include/linux/backing-dev.h
+++ b/include/linux/backing-dev.h
@@ -32,6 +32,7 @@
BDI_sync_congested, /* The sync queue is getting full */
BDI_registered, /* bdi_register() was done */
BDI_writeback_running, /* Writeback is in progress */
+ BDI_multiple_sb, /* Multiple superblocks belong to this bdi */
BDI_unused, /* Available bits start here */
};
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h
index 94cd46c..e60c821 100644
--- a/include/linux/ftrace_event.h
+++ b/include/linux/ftrace_event.h
@@ -256,6 +256,10 @@
int trace_set_clr_event(const char *system, const char *event, int set);
+/* file pointer helpers */
+extern int ftrace_file_name_len (const struct file *f);
+extern void ftrace_assign_file (char *dest, int dest_len, const struct file *f);
+
/*
* The double __builtin_constant_p is because gcc will give us an error
* if we try to allocate the static variable to fmt if it is not a
diff --git a/include/trace/events/fs-open.h b/include/trace/events/fs-open.h
new file mode 100644
index 0000000..32633e5
--- /dev/null
+++ b/include/trace/events/fs-open.h
@@ -0,0 +1,66 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM fs-open
+
+#if !defined(_TRACE_FS_OPEN_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_FS_OPEN_H
+
+#include <linux/fs.h>
+#include <linux/tracepoint.h>
+
+/*
+ * Here we have a problem; the __string macro uses __dynamic_array,
+ * which requires the ability to know it's own length before we
+ * allocate the buffer - in the get_offsets_ call - which does not
+ * know the length of the resulting path we create in TP_fast_assign.
+ * So - give up and use a fixed length.
+ */
+TRACE_EVENT(do_sys_open,
+
+ TP_PROTO(struct file *filp, int flags, int mode),
+
+ TP_ARGS(filp, flags, mode),
+
+ TP_STRUCT__entry(
+ __file_p( filename, filp )
+ __field( int, flags )
+ __field( int, mode )
+ ),
+
+ TP_fast_assign(
+ __assign_file_p(filename, filp);
+ __entry->flags = flags;
+ __entry->mode = mode;
+ ),
+
+ TP_printk("\"%s\" %x %o", __get_str(filename),
+ __entry->flags, __entry->mode)
+);
+
+TRACE_EVENT(uselib,
+ TP_PROTO(struct file *filp),
+ TP_ARGS(filp),
+ TP_STRUCT__entry(
+ __file_p(filename, filp)
+ ),
+ TP_fast_assign(
+ __assign_file_p(filename, filp);
+ ),
+ TP_printk("\"%s\"", __get_str(filename))
+);
+
+TRACE_EVENT(open_exec,
+ TP_PROTO(struct file *filp),
+ TP_ARGS(filp),
+ TP_STRUCT__entry(
+ __file_p(filename, filp)
+ ),
+ TP_fast_assign(
+ __assign_file_p(filename, filp);
+ ),
+ TP_printk("\"%s\"", __get_str(filename))
+);
+
+#endif /* _TRACE_FS_OPEN_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h
index db14daf..bd38f7d 100644
--- a/include/trace/ftrace.h
+++ b/include/trace/ftrace.h
@@ -53,6 +53,9 @@
#undef __string
#define __string(item, src) __dynamic_array(char, item, -1)
+#undef __file_p
+#define __file_p(item, src) __dynamic_array(char, item, -1)
+
#undef TP_STRUCT__entry
#define TP_STRUCT__entry(args...) args
@@ -120,6 +123,10 @@
#undef __string
#define __string(item, src) __dynamic_array(char, item, -1)
+#undef __file_p
+#define __file_p(item, src) int item; \
+ int item##__size;
+
#undef DECLARE_EVENT_CLASS
#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
struct ftrace_data_offsets_##call { \
@@ -333,6 +340,9 @@
#undef __string
#define __string(item, src) __dynamic_array(char, item, -1)
+#undef __file_p
+#define __file_p(item, src) __dynamic_array(char, item, -1)
+
#undef DECLARE_EVENT_CLASS
#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, func, print) \
static int notrace \
@@ -381,6 +391,13 @@
#undef __string
#define __string(item, src) __dynamic_array(char, item, strlen(src) + 1)
+#undef __file_p
+#define __file_p(item, src) \
+ __data_offsets->item = __data_size + \
+ offsetof(typeof(*entry), __data); \
+ __data_offsets->item##__size = ftrace_file_name_len(src); \
+ __data_size += __data_offsets->item##__size;
+
#undef DECLARE_EVENT_CLASS
#define DECLARE_EVENT_CLASS(call, proto, args, tstruct, assign, print) \
static inline notrace int ftrace_get_offsets_##call( \
@@ -502,10 +519,17 @@
#undef __string
#define __string(item, src) __dynamic_array(char, item, -1) \
+#undef __file_p
+#define __file_p(item, src) __dynamic_array(char, item, -1) \
+
#undef __assign_str
#define __assign_str(dst, src) \
strcpy(__get_str(dst), src);
+#undef __assign_file_p
+#define __assign_file_p(dst, src) \
+ ftrace_assign_file(__get_str (dst), __data_offsets.dst##__size, src);
+
#undef TP_fast_assign
#define TP_fast_assign(args...) args
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 87b1996..66071dc 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -1313,6 +1313,38 @@
(unsigned long)event < (unsigned long)end; \
event++)
+/* file pointer helpers */
+int ftrace_file_name_len (const struct file *f)
+{
+ /* This performs pretty terribly - obviously */
+ int len = 1;
+ char *buf, *fname;
+
+ if (!(buf = kzalloc(PAGE_SIZE, GFP_KERNEL)))
+ return len;
+ fname = d_path(&f->f_path, buf, PAGE_SIZE);
+ if (!IS_ERR (fname))
+ len += strlen (fname);
+ kfree(buf);
+ return len;
+}
+
+void ftrace_assign_file (char *dest, int dest_len, const struct file *f)
+{
+ char *buf, *fname;
+
+ dest[0] = '\0';
+ if (!(buf = kzalloc(PAGE_SIZE, GFP_KERNEL)))
+ return;
+
+ /* it would be nicer to write this directly into the
+ * allocated buffer, but d_path doesn't like that */
+ fname = d_path(&f->f_path, buf, PAGE_SIZE);
+ if (!IS_ERR (fname))
+ strncpy (dest, fname, dest_len);
+ kfree(buf);
+}
+
#ifdef CONFIG_MODULES
static LIST_HEAD(ftrace_module_file_list);
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index a15de5c..89813a3 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -299,11 +299,17 @@
*
* Note: If the task is ASYNC, this must be called with
* the spinlock held to protect the wait queue operation.
+ * Note the ordering of rpc_test_and_set_running() and rpc_clear_queued(),
+ * which is needed to ensure that __rpc_execute() doesn't loop (due to the
+ * lockless RPC_IS_QUEUED() test) before we've had a chance to test
+ * the RPC_TASK_RUNNING flag.
*/
static void rpc_make_runnable(struct rpc_task *task)
{
+ bool need_wakeup = !rpc_test_and_set_running(task);
+
rpc_clear_queued(task);
- if (rpc_test_and_set_running(task))
+ if (!need_wakeup)
return;
if (RPC_IS_ASYNC(task)) {
INIT_WORK(&task->u.tk_work, rpc_async_schedule);
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 72125fe..3cff132 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -855,10 +855,19 @@
hdmi_non_intrinsic_event(codec, res);
}
-static void haswell_verify_pin_D0(struct hda_codec *codec, hda_nid_t nid)
+static void haswell_verify_pin_D0(struct hda_codec *codec,
+ hda_nid_t cvt_nid, hda_nid_t nid)
{
int pwr, lamp, ramp;
+ /* For Haswell, the converter 1/2 may keep in D3 state after bootup,
+ * thus pins could only choose converter 0 for use. Make sure the
+ * converters are in correct power state */
+ pwr = snd_hda_codec_read(codec, cvt_nid, 0, AC_VERB_GET_POWER_STATE, 0);
+ pwr = (pwr & AC_PWRST_ACTUAL) >> AC_PWRST_ACTUAL_SHIFT;
+ if (pwr != AC_PWRST_D0)
+ snd_hda_codec_write(codec, cvt_nid, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D0);
+
pwr = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0);
pwr = (pwr & AC_PWRST_ACTUAL) >> AC_PWRST_ACTUAL_SHIFT;
if (pwr != AC_PWRST_D0) {
@@ -905,7 +914,7 @@
int new_pinctl = 0;
if (codec->vendor_id == 0x80862807)
- haswell_verify_pin_D0(codec, pin_nid);
+ haswell_verify_pin_D0(codec, cvt_nid, pin_nid);
if (snd_hda_query_pin_caps(codec, pin_nid) & AC_PINCAP_HBR) {
pinctl = snd_hda_codec_read(codec, pin_nid, 0,
@@ -938,26 +947,15 @@
return 0;
}
-/*
- * HDA PCM callbacks
- */
-static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
- struct hda_codec *codec,
- struct snd_pcm_substream *substream)
+static int hdmi_choose_cvt(struct hda_codec *codec,
+ int pin_idx, int *cvt_id, int *mux_id)
{
struct hdmi_spec *spec = codec->spec;
- struct snd_pcm_runtime *runtime = substream->runtime;
- int pin_idx, cvt_idx, mux_idx = 0;
struct hdmi_spec_per_pin *per_pin;
- struct hdmi_eld *eld;
struct hdmi_spec_per_cvt *per_cvt = NULL;
+ int cvt_idx, mux_idx = 0;
- /* Validate hinfo */
- pin_idx = hinfo_to_pin_index(spec, hinfo);
- if (snd_BUG_ON(pin_idx < 0))
- return -EINVAL;
per_pin = &spec->pins[pin_idx];
- eld = &per_pin->sink_eld;
/* Dynamically assign converter to stream */
for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) {
@@ -975,17 +973,89 @@
continue;
break;
}
+
/* No free converters */
if (cvt_idx == spec->num_cvts)
return -ENODEV;
+ if (cvt_id)
+ *cvt_id = cvt_idx;
+ if (mux_id)
+ *mux_id = mux_idx;
+
+ return 0;
+}
+
+static void haswell_config_cvts(struct hda_codec *codec,
+ int pin_id, int mux_id)
+{
+ struct hdmi_spec *spec = codec->spec;
+ struct hdmi_spec_per_pin *per_pin;
+ int pin_idx, mux_idx;
+ int curr;
+ int err;
+
+ for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) {
+ per_pin = &spec->pins[pin_idx];
+
+ if (pin_idx == pin_id)
+ continue;
+
+ curr = snd_hda_codec_read(codec, per_pin->pin_nid, 0,
+ AC_VERB_GET_CONNECT_SEL, 0);
+
+ /* Choose another unused converter */
+ if (curr == mux_id) {
+ err = hdmi_choose_cvt(codec, pin_idx, NULL, &mux_idx);
+ if (err < 0)
+ return;
+ snd_printdd("HDMI: choose converter %d for pin %d\n", mux_idx, pin_idx);
+ snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
+ AC_VERB_SET_CONNECT_SEL,
+ mux_idx);
+ }
+ }
+}
+
+/*
+ * HDA PCM callbacks
+ */
+static int hdmi_pcm_open(struct hda_pcm_stream *hinfo,
+ struct hda_codec *codec,
+ struct snd_pcm_substream *substream)
+{
+ struct hdmi_spec *spec = codec->spec;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int pin_idx, cvt_idx, mux_idx = 0;
+ struct hdmi_spec_per_pin *per_pin;
+ struct hdmi_eld *eld;
+ struct hdmi_spec_per_cvt *per_cvt = NULL;
+ int err;
+
+ /* Validate hinfo */
+ pin_idx = hinfo_to_pin_index(spec, hinfo);
+ if (snd_BUG_ON(pin_idx < 0))
+ return -EINVAL;
+ per_pin = &spec->pins[pin_idx];
+ eld = &per_pin->sink_eld;
+
+ err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx, &mux_idx);
+ if (err < 0)
+ return err;
+
+ per_cvt = &spec->cvts[cvt_idx];
/* Claim converter */
per_cvt->assigned = 1;
hinfo->nid = per_cvt->cvt_nid;
- snd_hda_codec_write(codec, per_pin->pin_nid, 0,
+ snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0,
AC_VERB_SET_CONNECT_SEL,
mux_idx);
+
+ /* configure unused pins to choose other converters */
+ if (codec->vendor_id == 0x80862807)
+ haswell_config_cvts(codec, pin_idx, mux_idx);
+
snd_hda_spdif_ctls_assign(codec, pin_idx, per_cvt->cvt_nid);
/* Initially set the converter's capabilities */
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c
index 6bfef26..72d4caf 100644
--- a/sound/pci/hda/patch_via.c
+++ b/sound/pci/hda/patch_via.c
@@ -217,6 +217,7 @@
int hp_work_active;
int vt1708_jack_detect;
int vt1708_hp_present;
+ bool mute_via_amp;
void (*set_widgets_power_state)(struct hda_codec *codec);
@@ -1643,7 +1644,7 @@
}
/* mute/unmute outputs */
-static void toggle_output_mutes(struct hda_codec *codec, int num_pins,
+static void toggle_output_mutes_via_pin(struct hda_codec *codec, int num_pins,
hda_nid_t *pins, bool mute)
{
int i;
@@ -1660,6 +1661,30 @@
}
}
+static void toggle_output_mutes_via_amp(struct hda_codec *codec, int num_pins,
+ hda_nid_t *pins, bool mute)
+{
+ int i, ch;
+ for (i = 0; i < num_pins; i++) {
+ for (ch = 0; ch < 2; ch++) {
+ snd_hda_codec_amp_update(codec, pins[i], ch,
+ HDA_OUTPUT, 0, 0x80,
+ mute ? 0x80 : 0x00);
+ }
+ }
+}
+
+static void toggle_output_mutes(struct hda_codec *codec, int num_pins,
+ hda_nid_t *pins, bool mute)
+{
+ struct via_spec *spec = codec->spec;
+
+ if (spec->mute_via_amp)
+ toggle_output_mutes_via_amp(codec, num_pins, pins, mute);
+ else
+ toggle_output_mutes_via_pin(codec, num_pins, pins, mute);
+}
+
/* mute internal speaker if line-out is plugged */
static void via_line_automute(struct hda_codec *codec, int present)
{
@@ -1860,7 +1885,8 @@
}
static int create_ch_ctls(struct hda_codec *codec, const char *pfx,
- int chs, bool check_dac, struct nid_path *path)
+ int chs, bool check_dac, struct nid_path *path,
+ bool check_mute_via_amp)
{
struct via_spec *spec = codec->spec;
char name[32];
@@ -1888,6 +1914,9 @@
path->vol_ctl = nid;
}
+ if (check_mute_via_amp && spec->mute_via_amp)
+ return 0; /* no mute */
+
if (dac && check_amp_caps(codec, dac, HDA_OUTPUT, AC_AMPCAP_MUTE))
nid = dac;
else if (check_amp_caps(codec, pin, HDA_OUTPUT, AC_AMPCAP_MUTE))
@@ -1985,10 +2014,10 @@
continue;
path = spec->out_path + i;
if (i == HDA_CLFE) {
- err = create_ch_ctls(codec, "Center", 1, true, path);
+ err = create_ch_ctls(codec, "Center", 1, true, path, true);
if (err < 0)
return err;
- err = create_ch_ctls(codec, "LFE", 2, true, path);
+ err = create_ch_ctls(codec, "LFE", 2, true, path, true);
if (err < 0)
return err;
} else {
@@ -1996,7 +2025,7 @@
if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT &&
cfg->line_outs == 1)
pfx = "Speaker";
- err = create_ch_ctls(codec, pfx, 3, true, path);
+ err = create_ch_ctls(codec, pfx, 3, true, path, true);
if (err < 0)
return err;
}
@@ -2075,7 +2104,7 @@
path = &spec->hp_mix_path;
check_dac = false;
}
- err = create_ch_ctls(codec, "Headphone", 3, check_dac, path);
+ err = create_ch_ctls(codec, "Headphone", 3, check_dac, path, false);
if (err < 0)
return err;
if (check_dac)
@@ -2126,7 +2155,7 @@
path = &spec->speaker_mix_path;
check_dac = false;
}
- err = create_ch_ctls(codec, "Speaker", 3, check_dac, path);
+ err = create_ch_ctls(codec, "Speaker", 3, check_dac, path, true);
if (err < 0)
return err;
if (check_dac)
@@ -2844,6 +2873,7 @@
codec->jackpoll = 1;
spec->vt1708_jack_detect = 1;
+ spec->mute_via_amp = 1;
/* Add HP and CD pin config connect bit re-config action */
vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID);