From: Greg Kroah-Hartman Date: Wed, 21 Apr 2010 19:21:25 +0000 (-0700) Subject: .33 patches X-Git-Tag: v2.6.32.12~20 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=640657f9093664cb67c6b7de64b3f1b7e2ec2e0c;p=thirdparty%2Fkernel%2Fstable-queue.git .33 patches --- diff --git a/queue-2.6.33/acpi-ec-allow-multibyte-access-to-ec.patch b/queue-2.6.33/acpi-ec-allow-multibyte-access-to-ec.patch new file mode 100644 index 00000000000..24521d23ef6 --- /dev/null +++ b/queue-2.6.33/acpi-ec-allow-multibyte-access-to-ec.patch @@ -0,0 +1,105 @@ +From ben@decadent.org.uk Wed Apr 21 12:11:57 2010 +From: Alexey Starikovskiy +Date: Sat, 10 Apr 2010 02:18:35 +0100 +Subject: ACPI: EC: Allow multibyte access to EC +To: stable@kernel.org +Cc: Len Brown , 563313@bugs.debian.org, Alexey Starikovskiy +Message-ID: <1270862315.2176.69.camel@localhost> + + +From: Alexey Starikovskiy + +commit dadf28a10c3eb29421837a2e413ab869ebd upstream + +http://bugzilla.kernel.org/show_bug.cgi?id=14667 + +[bwh: Backport to 2.6.32; same applies to 2.6.33] + +Signed-off-by: Alexey Starikovskiy +Signed-off-by: Len Brown +Cc: Ben Hutchings +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/acpi/acpica/exprep.c | 12 ++++++++++++ + drivers/acpi/ec.c | 35 +++++++++-------------------------- + 2 files changed, 21 insertions(+), 26 deletions(-) + +--- a/drivers/acpi/acpica/exprep.c ++++ b/drivers/acpi/acpica/exprep.c +@@ -468,6 +468,18 @@ acpi_status acpi_ex_prep_field_value(str + + acpi_ut_add_reference(obj_desc->field.region_obj); + ++ /* allow full data read from EC address space */ ++ if (obj_desc->field.region_obj->region.space_id == ++ ACPI_ADR_SPACE_EC) { ++ if (obj_desc->common_field.bit_length > 8) ++ obj_desc->common_field.access_bit_width = ++ ACPI_ROUND_UP(obj_desc->common_field. ++ bit_length, 8); ++ obj_desc->common_field.access_byte_width = ++ ACPI_DIV_8(obj_desc->common_field. ++ access_bit_width); ++ } ++ + ACPI_DEBUG_PRINT((ACPI_DB_BFIELD, + "RegionField: BitOff %X, Off %X, Gran %X, Region %p\n", + obj_desc->field.start_field_bit_offset, +--- a/drivers/acpi/ec.c ++++ b/drivers/acpi/ec.c +@@ -589,12 +589,12 @@ static u32 acpi_ec_gpe_handler(void *dat + + static acpi_status + acpi_ec_space_handler(u32 function, acpi_physical_address address, +- u32 bits, acpi_integer *value, ++ u32 bits, acpi_integer *value64, + void *handler_context, void *region_context) + { + struct acpi_ec *ec = handler_context; +- int result = 0, i; +- u8 temp = 0; ++ int result = 0, i, bytes = bits / 8; ++ u8 *value = (u8 *)value64; + + if ((address > 0xFF) || !value || !handler_context) + return AE_BAD_PARAMETER; +@@ -602,32 +602,15 @@ acpi_ec_space_handler(u32 function, acpi + if (function != ACPI_READ && function != ACPI_WRITE) + return AE_BAD_PARAMETER; + +- if (bits != 8 && acpi_strict) +- return AE_BAD_PARAMETER; +- +- if (EC_FLAGS_MSI) ++ if (EC_FLAGS_MSI || bits > 8) + acpi_ec_burst_enable(ec); + +- if (function == ACPI_READ) { +- result = acpi_ec_read(ec, address, &temp); +- *value = temp; +- } else { +- temp = 0xff & (*value); +- result = acpi_ec_write(ec, address, temp); +- } +- +- for (i = 8; unlikely(bits - i > 0); i += 8) { +- ++address; +- if (function == ACPI_READ) { +- result = acpi_ec_read(ec, address, &temp); +- (*value) |= ((acpi_integer)temp) << i; +- } else { +- temp = 0xff & ((*value) >> i); +- result = acpi_ec_write(ec, address, temp); +- } +- } ++ for (i = 0; i < bytes; ++i, ++address, ++value) ++ result = (function == ACPI_READ) ? ++ acpi_ec_read(ec, address, value) : ++ acpi_ec_write(ec, address, *value); + +- if (EC_FLAGS_MSI) ++ if (EC_FLAGS_MSI || bits > 8) + acpi_ec_burst_disable(ec); + + switch (result) { diff --git a/queue-2.6.33/e1000e-stop-cleaning-when-we-reach-tx_ring-next_to_use.patch b/queue-2.6.33/e1000e-stop-cleaning-when-we-reach-tx_ring-next_to_use.patch new file mode 100644 index 00000000000..29d096dfb71 --- /dev/null +++ b/queue-2.6.33/e1000e-stop-cleaning-when-we-reach-tx_ring-next_to_use.patch @@ -0,0 +1,35 @@ +From dac876193cd79ced36d0462749ea47c05844fb49 Mon Sep 17 00:00:00 2001 +From: Terry Loftin +Date: Fri, 9 Apr 2010 10:29:49 +0000 +Subject: e1000e: stop cleaning when we reach tx_ring->next_to_use + +From: Terry Loftin + +commit dac876193cd79ced36d0462749ea47c05844fb49 upstream. + +Tx ring buffers after tx_ring->next_to_use are volatile and could +change, possibly causing a crash. Stop cleaning when we hit +tx_ring->next_to_use. + +Signed-off-by: Terry Loftin +Acked-by: Bruce Allan +Signed-off-by: Jeff Kirsher +Signed-off-by: David S. Miller +Cc: Matthew Burgess +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/e1000e/netdev.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/net/e1000e/netdev.c ++++ b/drivers/net/e1000e/netdev.c +@@ -660,6 +660,8 @@ static bool e1000_clean_tx_irq(struct e1 + i = 0; + } + ++ if (i == tx_ring->next_to_use) ++ break; + eop = tx_ring->buffer_info[i].next_to_watch; + eop_desc = E1000_TX_DESC(*tx_ring, eop); + } diff --git a/queue-2.6.33/ecryptfs-decrypt-symlink-target-for-stat-size.patch b/queue-2.6.33/ecryptfs-decrypt-symlink-target-for-stat-size.patch new file mode 100644 index 00000000000..62b8bf8e745 --- /dev/null +++ b/queue-2.6.33/ecryptfs-decrypt-symlink-target-for-stat-size.patch @@ -0,0 +1,166 @@ +From 3a60a1686f0d51c99bd0df8ac93050fb6dfce647 Mon Sep 17 00:00:00 2001 +From: Tyler Hicks +Date: Mon, 22 Mar 2010 00:41:35 -0500 +Subject: eCryptfs: Decrypt symlink target for stat size +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Tyler Hicks + +commit 3a60a1686f0d51c99bd0df8ac93050fb6dfce647 upstream. + +Create a getattr handler for eCryptfs symlinks that is capable of +reading the lower target and decrypting its path. Prior to this patch, +a stat's st_size field would represent the strlen of the encrypted path, +while readlink() would return the strlen of the decrypted path. This +could lead to confusion in some userspace applications, since the two +values should be equal. + +https://bugs.launchpad.net/bugs/524919 + +Reported-by: Loïc Minier +Signed-off-by: Tyler Hicks +Signed-off-by: Greg Kroah-Hartman + +--- + fs/ecryptfs/inode.c | 100 +++++++++++++++++++++++++++------------------------- + 1 file changed, 52 insertions(+), 48 deletions(-) + +--- a/fs/ecryptfs/inode.c ++++ b/fs/ecryptfs/inode.c +@@ -647,38 +647,17 @@ out_lock: + return rc; + } + +-static int +-ecryptfs_readlink(struct dentry *dentry, char __user *buf, int bufsiz) ++static int ecryptfs_readlink_lower(struct dentry *dentry, char **buf, ++ size_t *bufsiz) + { ++ struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry); + char *lower_buf; +- size_t lower_bufsiz; +- struct dentry *lower_dentry; +- struct ecryptfs_mount_crypt_stat *mount_crypt_stat; +- char *plaintext_name; +- size_t plaintext_name_size; ++ size_t lower_bufsiz = PATH_MAX; + mm_segment_t old_fs; + int rc; + +- lower_dentry = ecryptfs_dentry_to_lower(dentry); +- if (!lower_dentry->d_inode->i_op->readlink) { +- rc = -EINVAL; +- goto out; +- } +- mount_crypt_stat = &ecryptfs_superblock_to_private( +- dentry->d_sb)->mount_crypt_stat; +- /* +- * If the lower filename is encrypted, it will result in a significantly +- * longer name. If needed, truncate the name after decode and decrypt. +- */ +- if (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES) +- lower_bufsiz = PATH_MAX; +- else +- lower_bufsiz = bufsiz; +- /* Released in this function */ + lower_buf = kmalloc(lower_bufsiz, GFP_KERNEL); +- if (lower_buf == NULL) { +- printk(KERN_ERR "%s: Out of memory whilst attempting to " +- "kmalloc [%zd] bytes\n", __func__, lower_bufsiz); ++ if (!lower_buf) { + rc = -ENOMEM; + goto out; + } +@@ -688,29 +667,31 @@ ecryptfs_readlink(struct dentry *dentry, + (char __user *)lower_buf, + lower_bufsiz); + set_fs(old_fs); +- if (rc >= 0) { +- rc = ecryptfs_decode_and_decrypt_filename(&plaintext_name, +- &plaintext_name_size, +- dentry, lower_buf, +- rc); +- if (rc) { +- printk(KERN_ERR "%s: Error attempting to decode and " +- "decrypt filename; rc = [%d]\n", __func__, +- rc); +- goto out_free_lower_buf; +- } +- /* Check for bufsiz <= 0 done in sys_readlinkat() */ +- rc = copy_to_user(buf, plaintext_name, +- min((size_t) bufsiz, plaintext_name_size)); +- if (rc) +- rc = -EFAULT; +- else +- rc = plaintext_name_size; +- kfree(plaintext_name); +- fsstack_copy_attr_atime(dentry->d_inode, lower_dentry->d_inode); +- } +-out_free_lower_buf: ++ if (rc < 0) ++ goto out; ++ lower_bufsiz = rc; ++ rc = ecryptfs_decode_and_decrypt_filename(buf, bufsiz, dentry, ++ lower_buf, lower_bufsiz); ++out: + kfree(lower_buf); ++ return rc; ++} ++ ++static int ++ecryptfs_readlink(struct dentry *dentry, char __user *buf, int bufsiz) ++{ ++ char *kbuf; ++ size_t kbufsiz, copied; ++ int rc; ++ ++ rc = ecryptfs_readlink_lower(dentry, &kbuf, &kbufsiz); ++ if (rc) ++ goto out; ++ copied = min_t(size_t, bufsiz, kbufsiz); ++ rc = copy_to_user(buf, kbuf, copied) ? -EFAULT : copied; ++ kfree(kbuf); ++ fsstack_copy_attr_atime(dentry->d_inode, ++ ecryptfs_dentry_to_lower(dentry)->d_inode); + out: + return rc; + } +@@ -1015,6 +996,28 @@ out: + return rc; + } + ++int ecryptfs_getattr_link(struct vfsmount *mnt, struct dentry *dentry, ++ struct kstat *stat) ++{ ++ struct ecryptfs_mount_crypt_stat *mount_crypt_stat; ++ int rc = 0; ++ ++ mount_crypt_stat = &ecryptfs_superblock_to_private( ++ dentry->d_sb)->mount_crypt_stat; ++ generic_fillattr(dentry->d_inode, stat); ++ if (mount_crypt_stat->flags & ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES) { ++ char *target; ++ size_t targetsiz; ++ ++ rc = ecryptfs_readlink_lower(dentry, &target, &targetsiz); ++ if (!rc) { ++ kfree(target); ++ stat->size = targetsiz; ++ } ++ } ++ return rc; ++} ++ + int ecryptfs_getattr(struct vfsmount *mnt, struct dentry *dentry, + struct kstat *stat) + { +@@ -1132,6 +1135,7 @@ const struct inode_operations ecryptfs_s + .put_link = ecryptfs_put_link, + .permission = ecryptfs_permission, + .setattr = ecryptfs_setattr, ++ .getattr = ecryptfs_getattr_link, + .setxattr = ecryptfs_setxattr, + .getxattr = ecryptfs_getxattr, + .listxattr = ecryptfs_listxattr, diff --git a/queue-2.6.33/ecryptfs-fix-error-code-for-missing-xattrs-in-lower-fs.patch b/queue-2.6.33/ecryptfs-fix-error-code-for-missing-xattrs-in-lower-fs.patch new file mode 100644 index 00000000000..59c28e29391 --- /dev/null +++ b/queue-2.6.33/ecryptfs-fix-error-code-for-missing-xattrs-in-lower-fs.patch @@ -0,0 +1,61 @@ +From cfce08c6bdfb20ade979284e55001ca1f100ed51 Mon Sep 17 00:00:00 2001 +From: Christian Pulvermacher +Date: Tue, 23 Mar 2010 11:51:38 -0500 +Subject: ecryptfs: fix error code for missing xattrs in lower fs + +From: Christian Pulvermacher + +commit cfce08c6bdfb20ade979284e55001ca1f100ed51 upstream. + +If the lower file system driver has extended attributes disabled, +ecryptfs' own access functions return -ENOSYS instead of -EOPNOTSUPP. +This breaks execution of programs in the ecryptfs mount, since the +kernel expects the latter error when checking for security +capabilities in xattrs. + +Signed-off-by: Christian Pulvermacher +Signed-off-by: Tyler Hicks +Signed-off-by: Greg Kroah-Hartman + +--- + fs/ecryptfs/inode.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +--- a/fs/ecryptfs/inode.c ++++ b/fs/ecryptfs/inode.c +@@ -1042,7 +1042,7 @@ ecryptfs_setxattr(struct dentry *dentry, + + lower_dentry = ecryptfs_dentry_to_lower(dentry); + if (!lower_dentry->d_inode->i_op->setxattr) { +- rc = -ENOSYS; ++ rc = -EOPNOTSUPP; + goto out; + } + mutex_lock(&lower_dentry->d_inode->i_mutex); +@@ -1060,7 +1060,7 @@ ecryptfs_getxattr_lower(struct dentry *l + int rc = 0; + + if (!lower_dentry->d_inode->i_op->getxattr) { +- rc = -ENOSYS; ++ rc = -EOPNOTSUPP; + goto out; + } + mutex_lock(&lower_dentry->d_inode->i_mutex); +@@ -1087,7 +1087,7 @@ ecryptfs_listxattr(struct dentry *dentry + + lower_dentry = ecryptfs_dentry_to_lower(dentry); + if (!lower_dentry->d_inode->i_op->listxattr) { +- rc = -ENOSYS; ++ rc = -EOPNOTSUPP; + goto out; + } + mutex_lock(&lower_dentry->d_inode->i_mutex); +@@ -1104,7 +1104,7 @@ static int ecryptfs_removexattr(struct d + + lower_dentry = ecryptfs_dentry_to_lower(dentry); + if (!lower_dentry->d_inode->i_op->removexattr) { +- rc = -ENOSYS; ++ rc = -EOPNOTSUPP; + goto out; + } + mutex_lock(&lower_dentry->d_inode->i_mutex); diff --git a/queue-2.6.33/ecryptfs-fix-use-with-tmpfs-by-removing-d_drop-from-ecryptfs_destroy_inode.patch b/queue-2.6.33/ecryptfs-fix-use-with-tmpfs-by-removing-d_drop-from-ecryptfs_destroy_inode.patch new file mode 100644 index 00000000000..d9cf3613cdc --- /dev/null +++ b/queue-2.6.33/ecryptfs-fix-use-with-tmpfs-by-removing-d_drop-from-ecryptfs_destroy_inode.patch @@ -0,0 +1,59 @@ +From 133b8f9d632cc23715c6d72d1c5ac449e054a12a Mon Sep 17 00:00:00 2001 +From: Jeff Mahoney +Date: Fri, 19 Mar 2010 15:35:46 -0400 +Subject: ecryptfs: fix use with tmpfs by removing d_drop from ecryptfs_destroy_inode + +From: Jeff Mahoney + +commit 133b8f9d632cc23715c6d72d1c5ac449e054a12a upstream. + +Since tmpfs has no persistent storage, it pins all its dentries in memory +so they have d_count=1 when other file systems would have d_count=0. +->lookup is only used to create new dentries. If the caller doesn't +instantiate it, it's freed immediately at dput(). ->readdir reads +directly from the dcache and depends on the dentries being hashed. + +When an ecryptfs mount is mounted, it associates the lower file and dentry +with the ecryptfs files as they're accessed. When it's umounted and +destroys all the in-memory ecryptfs inodes, it fput's the lower_files and +d_drop's the lower_dentries. Commit 4981e081 added this and a d_delete in +2008 and several months later commit caeeeecf removed the d_delete. I +believe the d_drop() needs to be removed as well. + +The d_drop effectively hides any file that has been accessed via ecryptfs +from the underlying tmpfs since it depends on it being hashed for it to +be accessible. I've removed the d_drop on my development node and see no +ill effects with basic testing on both tmpfs and persistent storage. + +As a side effect, after ecryptfs d_drops the dentries on tmpfs, tmpfs +BUGs on umount. This is due to the dentries being unhashed. +tmpfs->kill_sb is kill_litter_super which calls d_genocide to drop +the reference pinning the dentry. It skips unhashed and negative dentries, +but shrink_dcache_for_umount_subtree doesn't. Since those dentries +still have an elevated d_count, we get a BUG(). + +This patch removes the d_drop call and fixes both issues. + +This issue was reported at: +https://bugzilla.novell.com/show_bug.cgi?id=567887 + +Reported-by: Árpád Bíró +Signed-off-by: Jeff Mahoney +Cc: Dustin Kirkland +Signed-off-by: Tyler Hicks +Signed-off-by: Greg Kroah-Hartman + +--- + fs/ecryptfs/super.c | 1 - + 1 file changed, 1 deletion(-) + +--- a/fs/ecryptfs/super.c ++++ b/fs/ecryptfs/super.c +@@ -85,7 +85,6 @@ static void ecryptfs_destroy_inode(struc + if (lower_dentry->d_inode) { + fput(inode_info->lower_file); + inode_info->lower_file = NULL; +- d_drop(lower_dentry); + } + } + ecryptfs_destroy_crypt_stat(&inode_info->crypt_stat); diff --git a/queue-2.6.33/iwlwifi-clear-all-tx-queues-when-firmware-ready.patch b/queue-2.6.33/iwlwifi-clear-all-tx-queues-when-firmware-ready.patch new file mode 100644 index 00000000000..64e22bc6459 --- /dev/null +++ b/queue-2.6.33/iwlwifi-clear-all-tx-queues-when-firmware-ready.patch @@ -0,0 +1,44 @@ +From dff010ac8e57e43669518a14c0e945dfeb80c2a7 Mon Sep 17 00:00:00 2001 +From: Wey-Yi Guy +Date: Tue, 2 Feb 2010 16:58:34 -0800 +Subject: iwlwifi: clear all tx queues when firmware ready + +From: Wey-Yi Guy + +commit dff010ac8e57e43669518a14c0e945dfeb80c2a7 upstream. + +Reset and clear all the tx queues when finished downloading runtime +uCode and ready to go into operation mode. + +Signed-off-by: Wey-Yi Guy +Signed-off-by: Reinette Chatre +Cc: maximilian attems +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/iwlwifi/iwl-4965.c | 2 ++ + drivers/net/wireless/iwlwifi/iwl-5000.c | 2 ++ + 2 files changed, 4 insertions(+) + +--- a/drivers/net/wireless/iwlwifi/iwl-4965.c ++++ b/drivers/net/wireless/iwlwifi/iwl-4965.c +@@ -581,6 +581,8 @@ static int iwl4965_alive_notify(struct i + + iwl4965_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0); + ++ /* reset to 0 to enable all the queue first */ ++ priv->txq_ctx_active_msk = 0; + /* Map each Tx/cmd queue to its corresponding fifo */ + for (i = 0; i < ARRAY_SIZE(default_queue_to_tx_fifo); i++) { + int ac = default_queue_to_tx_fifo[i]; +--- a/drivers/net/wireless/iwlwifi/iwl-5000.c ++++ b/drivers/net/wireless/iwlwifi/iwl-5000.c +@@ -657,6 +657,8 @@ int iwl5000_alive_notify(struct iwl_priv + + iwl5000_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0); + ++ /* reset to 0 to enable all the queue first */ ++ priv->txq_ctx_active_msk = 0; + /* map qos queues to fifos one-to-one */ + for (i = 0; i < ARRAY_SIZE(iwl5000_default_queue_to_tx_fifo); i++) { + int ac = iwl5000_default_queue_to_tx_fifo[i]; diff --git a/queue-2.6.33/iwlwifi-fix-scan-race.patch b/queue-2.6.33/iwlwifi-fix-scan-race.patch new file mode 100644 index 00000000000..37a37ab7942 --- /dev/null +++ b/queue-2.6.33/iwlwifi-fix-scan-race.patch @@ -0,0 +1,74 @@ +From bbcbb9ef9735c67da303d30bd6beb9e699f0f508 Mon Sep 17 00:00:00 2001 +From: Reinette Chatre +Date: Tue, 2 Feb 2010 10:57:12 -0800 +Subject: iwlwifi: fix scan race + +From: Reinette Chatre + +commit bbcbb9ef9735c67da303d30bd6beb9e699f0f508 upstream. + +There is a problem if an "internal short scan" is in progress when a +mac80211 requested scan arrives. If this new scan request arrives within +the "next_scan_jiffies" period then driver will immediately return success +and complete the scan. The problem here is that the scan has not been +fully initialized at this time (is_internal_short_scan is still set to true +because of the currently running scan), which results in the scan +completion never to be sent to mac80211. At this time also, evan though the +internal short scan is still running the state (is_internal_short_scan) +will be set to false, so when the internal scan does complete then mac80211 +will receive a scan completion. + +Fix this by checking right away if a scan is in progress when a scan +request arrives from mac80211. + +Signed-off-by: Reinette Chatre +Cc: maximilian attems +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/wireless/iwlwifi/iwl-scan.c | 27 ++++++++++++--------------- + 1 file changed, 12 insertions(+), 15 deletions(-) + +--- a/drivers/net/wireless/iwlwifi/iwl-scan.c ++++ b/drivers/net/wireless/iwlwifi/iwl-scan.c +@@ -404,21 +404,6 @@ EXPORT_SYMBOL(iwl_init_scan_params); + + static int iwl_scan_initiate(struct iwl_priv *priv) + { +- if (!iwl_is_ready_rf(priv)) { +- IWL_DEBUG_SCAN(priv, "Aborting scan due to not ready.\n"); +- return -EIO; +- } +- +- if (test_bit(STATUS_SCANNING, &priv->status)) { +- IWL_DEBUG_SCAN(priv, "Scan already in progress.\n"); +- return -EAGAIN; +- } +- +- if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { +- IWL_DEBUG_SCAN(priv, "Scan request while abort pending\n"); +- return -EAGAIN; +- } +- + IWL_DEBUG_INFO(priv, "Starting scan...\n"); + set_bit(STATUS_SCANNING, &priv->status); + priv->scan_start = jiffies; +@@ -449,6 +434,18 @@ int iwl_mac_hw_scan(struct ieee80211_hw + goto out_unlock; + } + ++ if (test_bit(STATUS_SCANNING, &priv->status)) { ++ IWL_DEBUG_SCAN(priv, "Scan already in progress.\n"); ++ ret = -EAGAIN; ++ goto out_unlock; ++ } ++ ++ if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) { ++ IWL_DEBUG_SCAN(priv, "Scan request while abort pending\n"); ++ ret = -EAGAIN; ++ goto out_unlock; ++ } ++ + /* We don't schedule scan within next_scan_jiffies period. + * Avoid scanning during possible EAPOL exchange, return + * success immediately. diff --git a/queue-2.6.33/perf_events-x86-implement-intel-westmere-nehalem-ex-support.patch b/queue-2.6.33/perf_events-x86-implement-intel-westmere-nehalem-ex-support.patch new file mode 100644 index 00000000000..dd4aa9391d5 --- /dev/null +++ b/queue-2.6.33/perf_events-x86-implement-intel-westmere-nehalem-ex-support.patch @@ -0,0 +1,189 @@ +From youquan.song@linux.intel.com Wed Apr 21 11:57:31 2010 +From: Peter Zijlstra +Date: Fri, 16 Apr 2010 05:14:41 -0400 +Subject: perf_events, x86: Implement Intel Westmere/Nehalem-EX support +To: Vince Weaver , gregkh@novell.com +Cc: youquan.song@intel.com, a.p.zijlstra@chello.nl, gregkh@novell.com, "Youquan, Song" , trenn@novell.com, stable@kernel.org +Message-ID: <20100416091441.GA14199@youquan-linux.bj.intel.com> +Content-Disposition: inline + +From: Peter Zijlstra + +original patch commit ids: 452a339a976e7f782c786eb3f73080401e2fa3a6 and +134fbadf028a5977a1b06b0253d3ee33e6f0c642 + +perf_events, x86: Implement Intel Westmere support + +The new Intel documentation includes Westmere arch specific +event maps that are significantly different from the Nehalem +ones. Add support for this generation. + +Found the CPUID model numbers on wikipedia. + +Also ammend some Nehalem constraints, spotted those when looking +for the differences between Nehalem and Westmere. + +Signed-off-by: Peter Zijlstra +Cc: Arjan van de Ven +Cc: "H. Peter Anvin" +Cc: Stephane Eranian +LKML-Reference: <20100127221122.151865645@chello.nl> +Signed-off-by: Ingo Molnar + +perf, x86: Enable Nehalem-EX support + +According to Intel Software Devel Manual Volume 3B, the +Nehalem-EX PMU is just like regular Nehalem (except for the +uncore support, which is completely different). + +Signed-off-by: Vince Weaver +Cc: Peter Zijlstra +Cc: Paul Mackerras +Cc: Arnaldo Carvalho de Melo +Cc: "H. Peter Anvin" +Cc: Arjan van de Ven +Cc: Lin Ming +LKML-Reference: +Signed-off-by: Ingo Molnar +Cc: Youquan Song +--- + + +--- + arch/x86/kernel/cpu/perf_event.c | 104 ++++++++++++++++++++++++++++++++++++++- + 1 file changed, 103 insertions(+), 1 deletion(-) + +--- a/arch/x86/kernel/cpu/perf_event.c ++++ b/arch/x86/kernel/cpu/perf_event.c +@@ -245,6 +245,97 @@ static u64 __read_mostly hw_cache_event_ + [PERF_COUNT_HW_CACHE_OP_MAX] + [PERF_COUNT_HW_CACHE_RESULT_MAX]; + ++static const u64 westmere_hw_cache_event_ids ++ [PERF_COUNT_HW_CACHE_MAX] ++ [PERF_COUNT_HW_CACHE_OP_MAX] ++ [PERF_COUNT_HW_CACHE_RESULT_MAX] = ++{ ++ [ C(L1D) ] = { ++ [ C(OP_READ) ] = { ++ [ C(RESULT_ACCESS) ] = 0x010b, /* MEM_INST_RETIRED.LOADS */ ++ [ C(RESULT_MISS) ] = 0x0151, /* L1D.REPL */ ++ }, ++ [ C(OP_WRITE) ] = { ++ [ C(RESULT_ACCESS) ] = 0x020b, /* MEM_INST_RETURED.STORES */ ++ [ C(RESULT_MISS) ] = 0x0251, /* L1D.M_REPL */ ++ }, ++ [ C(OP_PREFETCH) ] = { ++ [ C(RESULT_ACCESS) ] = 0x014e, /* L1D_PREFETCH.REQUESTS */ ++ [ C(RESULT_MISS) ] = 0x024e, /* L1D_PREFETCH.MISS */ ++ }, ++ }, ++ [ C(L1I ) ] = { ++ [ C(OP_READ) ] = { ++ [ C(RESULT_ACCESS) ] = 0x0380, /* L1I.READS */ ++ [ C(RESULT_MISS) ] = 0x0280, /* L1I.MISSES */ ++ }, ++ [ C(OP_WRITE) ] = { ++ [ C(RESULT_ACCESS) ] = -1, ++ [ C(RESULT_MISS) ] = -1, ++ }, ++ [ C(OP_PREFETCH) ] = { ++ [ C(RESULT_ACCESS) ] = 0x0, ++ [ C(RESULT_MISS) ] = 0x0, ++ }, ++ }, ++ [ C(LL ) ] = { ++ [ C(OP_READ) ] = { ++ [ C(RESULT_ACCESS) ] = 0x0324, /* L2_RQSTS.LOADS */ ++ [ C(RESULT_MISS) ] = 0x0224, /* L2_RQSTS.LD_MISS */ ++ }, ++ [ C(OP_WRITE) ] = { ++ [ C(RESULT_ACCESS) ] = 0x0c24, /* L2_RQSTS.RFOS */ ++ [ C(RESULT_MISS) ] = 0x0824, /* L2_RQSTS.RFO_MISS */ ++ }, ++ [ C(OP_PREFETCH) ] = { ++ [ C(RESULT_ACCESS) ] = 0x4f2e, /* LLC Reference */ ++ [ C(RESULT_MISS) ] = 0x412e, /* LLC Misses */ ++ }, ++ }, ++ [ C(DTLB) ] = { ++ [ C(OP_READ) ] = { ++ [ C(RESULT_ACCESS) ] = 0x010b, /* MEM_INST_RETIRED.LOADS */ ++ [ C(RESULT_MISS) ] = 0x0108, /* DTLB_LOAD_MISSES.ANY */ ++ }, ++ [ C(OP_WRITE) ] = { ++ [ C(RESULT_ACCESS) ] = 0x020b, /* MEM_INST_RETURED.STORES */ ++ [ C(RESULT_MISS) ] = 0x010c, /* MEM_STORE_RETIRED.DTLB_MISS */ ++ }, ++ [ C(OP_PREFETCH) ] = { ++ [ C(RESULT_ACCESS) ] = 0x0, ++ [ C(RESULT_MISS) ] = 0x0, ++ }, ++ }, ++ [ C(ITLB) ] = { ++ [ C(OP_READ) ] = { ++ [ C(RESULT_ACCESS) ] = 0x01c0, /* INST_RETIRED.ANY_P */ ++ [ C(RESULT_MISS) ] = 0x0185, /* ITLB_MISSES.ANY */ ++ }, ++ [ C(OP_WRITE) ] = { ++ [ C(RESULT_ACCESS) ] = -1, ++ [ C(RESULT_MISS) ] = -1, ++ }, ++ [ C(OP_PREFETCH) ] = { ++ [ C(RESULT_ACCESS) ] = -1, ++ [ C(RESULT_MISS) ] = -1, ++ }, ++ }, ++ [ C(BPU ) ] = { ++ [ C(OP_READ) ] = { ++ [ C(RESULT_ACCESS) ] = 0x00c4, /* BR_INST_RETIRED.ALL_BRANCHES */ ++ [ C(RESULT_MISS) ] = 0x03e8, /* BPU_CLEARS.ANY */ ++ }, ++ [ C(OP_WRITE) ] = { ++ [ C(RESULT_ACCESS) ] = -1, ++ [ C(RESULT_MISS) ] = -1, ++ }, ++ [ C(OP_PREFETCH) ] = { ++ [ C(RESULT_ACCESS) ] = -1, ++ [ C(RESULT_MISS) ] = -1, ++ }, ++ }, ++}; ++ + static __initconst u64 nehalem_hw_cache_event_ids + [PERF_COUNT_HW_CACHE_MAX] + [PERF_COUNT_HW_CACHE_OP_MAX] +@@ -2118,6 +2209,7 @@ static __init int intel_pmu_init(void) + * Install the hw-cache-events table: + */ + switch (boot_cpu_data.x86_model) { ++ + case 15: /* original 65 nm celeron/pentium/core2/xeon, "Merom"/"Conroe" */ + case 22: /* single-core 65 nm celeron/core2solo "Merom-L"/"Conroe-L" */ + case 23: /* current 45 nm celeron/core2/xeon "Penryn"/"Wolfdale" */ +@@ -2129,7 +2221,9 @@ static __init int intel_pmu_init(void) + event_constraints = intel_core_event_constraints; + break; + default: +- case 26: ++ case 26: /* 45 nm nehalem, "Bloomfield" */ ++ case 30: /* 45 nm nehalem, "Lynnfield" */ ++ case 46: /* 45 nm nehalem-ex, "Beckton" */ + memcpy(hw_cache_event_ids, nehalem_hw_cache_event_ids, + sizeof(hw_cache_event_ids)); + +@@ -2142,6 +2236,14 @@ static __init int intel_pmu_init(void) + + pr_cont("Atom events, "); + break; ++ ++ case 37: /* 32 nm nehalem, "Clarkdale" */ ++ case 44: /* 32 nm nehalem, "Gulftown" */ ++ memcpy(hw_cache_event_ids, westmere_hw_cache_event_ids, ++ sizeof(hw_cache_event_ids)); ++ ++ pr_cont("Westmere events, "); ++ break; + } + return 0; + } diff --git a/queue-2.6.33/series b/queue-2.6.33/series index 60935512054..1cccc6eea52 100644 --- a/queue-2.6.33/series +++ b/queue-2.6.33/series @@ -104,3 +104,16 @@ i2c-i801-add-intel-cougar-point-device-ids.patch b43-allow-pio-mode-to-be-selected-at-module-load.patch b43-fall-back-gracefully-to-pio-mode-after-fatal-dma-errors.patch alsa-hda-add-position_fix-quirk-for-biostar-mobo.patch +ecryptfs-fix-use-with-tmpfs-by-removing-d_drop-from-ecryptfs_destroy_inode.patch +ecryptfs-decrypt-symlink-target-for-stat-size.patch +ecryptfs-fix-error-code-for-missing-xattrs-in-lower-fs.patch +usb-cdc-acm-update-to-new-autopm-api.patch +usb-cdc-acm-fix-stupid-null-pointer-in-resume.patch +iwlwifi-clear-all-tx-queues-when-firmware-ready.patch +iwlwifi-fix-scan-race.patch +e1000e-stop-cleaning-when-we-reach-tx_ring-next_to_use.patch +perf_events-x86-implement-intel-westmere-nehalem-ex-support.patch +xfs-non-blocking-inode-locking-in-io-completion.patch +xfs-fix-locking-for-inode-cache-radix-tree-tag-updates.patch +xfs-check-for-more-work-before-sleeping-in-xfssyncd.patch +acpi-ec-allow-multibyte-access-to-ec.patch diff --git a/queue-2.6.33/usb-cdc-acm-fix-stupid-null-pointer-in-resume.patch b/queue-2.6.33/usb-cdc-acm-fix-stupid-null-pointer-in-resume.patch new file mode 100644 index 00000000000..6ef94da3bbf --- /dev/null +++ b/queue-2.6.33/usb-cdc-acm-fix-stupid-null-pointer-in-resume.patch @@ -0,0 +1,30 @@ +From f0730924e9e32bb8935c60040a26d94179355088 Mon Sep 17 00:00:00 2001 +From: Oliver Neukum +Date: Wed, 3 Mar 2010 00:37:56 +0100 +Subject: USB: cdc-acm: Fix stupid NULL pointer in resume() + +From: Oliver Neukum + +commit f0730924e9e32bb8935c60040a26d94179355088 upstream. + +Stupid logic bug passing a just nulled pointer + +Signed-off-by: Oliver Neukum +Signed-off-by: Greg Kroah-Hartman +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/class/cdc-acm.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/usb/class/cdc-acm.c ++++ b/drivers/usb/class/cdc-acm.c +@@ -1441,7 +1441,7 @@ static int acm_resume(struct usb_interfa + wb = acm->delayed_wb; + acm->delayed_wb = NULL; + spin_unlock_irq(&acm->write_lock); +- acm_start_wb(acm, acm->delayed_wb); ++ acm_start_wb(acm, wb); + } else { + spin_unlock_irq(&acm->write_lock); + } diff --git a/queue-2.6.33/usb-cdc-acm-update-to-new-autopm-api.patch b/queue-2.6.33/usb-cdc-acm-update-to-new-autopm-api.patch new file mode 100644 index 00000000000..0f0992e45b0 --- /dev/null +++ b/queue-2.6.33/usb-cdc-acm-update-to-new-autopm-api.patch @@ -0,0 +1,126 @@ +From 97d35f95552c9a0ee4777a7f04431a9fd1260478 Mon Sep 17 00:00:00 2001 +From: Oliver Neukum +Date: Wed, 16 Dec 2009 17:05:57 +0100 +Subject: USB: cdc-acm: Update to new autopm API + +From: Oliver Neukum + +commit 97d35f95552c9a0ee4777a7f04431a9fd1260478 upstream. + +Update cdc-acm to the async methods eliminating the workqueue + +[This fixes a reported lockup for the cdc-acm driver - gregkh] + +Signed-off-by: Oliver Neukum +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/usb/class/cdc-acm.c | 43 ++++++++++++++++++++++--------------------- + drivers/usb/class/cdc-acm.h | 1 - + 2 files changed, 22 insertions(+), 22 deletions(-) + +--- a/drivers/usb/class/cdc-acm.c ++++ b/drivers/usb/class/cdc-acm.c +@@ -170,6 +170,7 @@ static void acm_write_done(struct acm *a + { + wb->use = 0; + acm->transmitting--; ++ usb_autopm_put_interface_async(acm->control); + } + + /* +@@ -211,9 +212,12 @@ static int acm_write_start(struct acm *a + } + + dbg("%s susp_count: %d", __func__, acm->susp_count); ++ usb_autopm_get_interface_async(acm->control); + if (acm->susp_count) { +- acm->delayed_wb = wb; +- schedule_work(&acm->waker); ++ if (!acm->delayed_wb) ++ acm->delayed_wb = wb; ++ else ++ usb_autopm_put_interface_async(acm->control); + spin_unlock_irqrestore(&acm->write_lock, flags); + return 0; /* A white lie */ + } +@@ -534,23 +538,6 @@ static void acm_softint(struct work_stru + tty_kref_put(tty); + } + +-static void acm_waker(struct work_struct *waker) +-{ +- struct acm *acm = container_of(waker, struct acm, waker); +- int rv; +- +- rv = usb_autopm_get_interface(acm->control); +- if (rv < 0) { +- dev_err(&acm->dev->dev, "Autopm failure in %s\n", __func__); +- return; +- } +- if (acm->delayed_wb) { +- acm_start_wb(acm, acm->delayed_wb); +- acm->delayed_wb = NULL; +- } +- usb_autopm_put_interface(acm->control); +-} +- + /* + * TTY handlers + */ +@@ -1178,7 +1165,6 @@ made_compressed_probe: + acm->urb_task.func = acm_rx_tasklet; + acm->urb_task.data = (unsigned long) acm; + INIT_WORK(&acm->work, acm_softint); +- INIT_WORK(&acm->waker, acm_waker); + init_waitqueue_head(&acm->drain_wait); + spin_lock_init(&acm->throttle_lock); + spin_lock_init(&acm->write_lock); +@@ -1343,7 +1329,6 @@ static void stop_data_traffic(struct acm + tasklet_enable(&acm->urb_task); + + cancel_work_sync(&acm->work); +- cancel_work_sync(&acm->waker); + } + + static void acm_disconnect(struct usb_interface *intf) +@@ -1435,6 +1420,7 @@ static int acm_suspend(struct usb_interf + static int acm_resume(struct usb_interface *intf) + { + struct acm *acm = usb_get_intfdata(intf); ++ struct acm_wb *wb; + int rv = 0; + int cnt; + +@@ -1449,6 +1435,21 @@ static int acm_resume(struct usb_interfa + mutex_lock(&acm->mutex); + if (acm->port.count) { + rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO); ++ ++ spin_lock_irq(&acm->write_lock); ++ if (acm->delayed_wb) { ++ wb = acm->delayed_wb; ++ acm->delayed_wb = NULL; ++ spin_unlock_irq(&acm->write_lock); ++ acm_start_wb(acm, acm->delayed_wb); ++ } else { ++ spin_unlock_irq(&acm->write_lock); ++ } ++ ++ /* ++ * delayed error checking because we must ++ * do the write path at all cost ++ */ + if (rv < 0) + goto err_out; + +--- a/drivers/usb/class/cdc-acm.h ++++ b/drivers/usb/class/cdc-acm.h +@@ -112,7 +112,6 @@ struct acm { + struct mutex mutex; + struct usb_cdc_line_coding line; /* bits, stop, parity */ + struct work_struct work; /* work queue entry for line discipline waking up */ +- struct work_struct waker; + wait_queue_head_t drain_wait; /* close processing */ + struct tasklet_struct urb_task; /* rx processing */ + spinlock_t throttle_lock; /* synchronize throtteling and read callback */ diff --git a/queue-2.6.33/xfs-check-for-more-work-before-sleeping-in-xfssyncd.patch b/queue-2.6.33/xfs-check-for-more-work-before-sleeping-in-xfssyncd.patch new file mode 100644 index 00000000000..39973bacf60 --- /dev/null +++ b/queue-2.6.33/xfs-check-for-more-work-before-sleeping-in-xfssyncd.patch @@ -0,0 +1,49 @@ +From 20f6b2c785cf187445f126321638ab8ba7aa7494 Mon Sep 17 00:00:00 2001 +From: Dave Chinner +Date: Thu, 4 Mar 2010 01:46:23 +0000 +Subject: xfs: check for more work before sleeping in xfssyncd + +From: Dave Chinner + +commit 20f6b2c785cf187445f126321638ab8ba7aa7494 upstream. + +xfssyncd processes a queue of work by detaching the queue and +then iterating over all the work items. It then sleeps for a +time period or until new work comes in. If new work is queued +while xfssyncd is actively processing the detached work queue, +it will not process that new work until after a sleep timeout +or the next work event queued wakes it. + +Fix this by checking the work queue again before going to sleep. + +Signed-off-by: Dave Chinner +Signed-off-by: Christoph Hellwig +Signed-off-by: Alex Elder +Signed-off-by: Greg Kroah-Hartman + +--- + fs/xfs/linux-2.6/xfs_sync.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +--- a/fs/xfs/linux-2.6/xfs_sync.c ++++ b/fs/xfs/linux-2.6/xfs_sync.c +@@ -613,7 +613,8 @@ xfssyncd( + set_freezable(); + timeleft = xfs_syncd_centisecs * msecs_to_jiffies(10); + for (;;) { +- timeleft = schedule_timeout_interruptible(timeleft); ++ if (list_empty(&mp->m_sync_list)) ++ timeleft = schedule_timeout_interruptible(timeleft); + /* swsusp */ + try_to_freeze(); + if (kthread_should_stop() && list_empty(&mp->m_sync_list)) +@@ -633,8 +634,7 @@ xfssyncd( + list_add_tail(&mp->m_sync_work.w_list, + &mp->m_sync_list); + } +- list_for_each_entry_safe(work, n, &mp->m_sync_list, w_list) +- list_move(&work->w_list, &tmp); ++ list_splice_init(&mp->m_sync_list, &tmp); + spin_unlock(&mp->m_sync_lock); + + list_for_each_entry_safe(work, n, &tmp, w_list) { diff --git a/queue-2.6.33/xfs-fix-locking-for-inode-cache-radix-tree-tag-updates.patch b/queue-2.6.33/xfs-fix-locking-for-inode-cache-radix-tree-tag-updates.patch new file mode 100644 index 00000000000..b984326aaf4 --- /dev/null +++ b/queue-2.6.33/xfs-fix-locking-for-inode-cache-radix-tree-tag-updates.patch @@ -0,0 +1,82 @@ +From f1f724e4b523d444c5a598d74505aefa3d6844d2 Mon Sep 17 00:00:00 2001 +From: Christoph Hellwig +Date: Mon, 1 Mar 2010 11:30:31 +0000 +Subject: xfs: fix locking for inode cache radix tree tag updates + +From: Christoph Hellwig + +commit f1f724e4b523d444c5a598d74505aefa3d6844d2 upstream. + +The radix-tree code requires it's users to serialize tag updates +against other updates to the tree. While XFS protects tag updates +against each other it does not serialize them against updates of the +tree contents, which can lead to tag corruption. Fix the inode +cache to always take pag_ici_lock in exclusive mode when updating +radix tree tags. + +Signed-off-by: Christoph Hellwig +Reported-by: Patrick Schreurs +Tested-by: Patrick Schreurs +Signed-off-by: Alex Elder +Cc: Dave Chinner +Signed-off-by: Greg Kroah-Hartman + +--- + fs/xfs/linux-2.6/xfs_sync.c | 4 ++-- + fs/xfs/xfs_iget.c | 19 +++++++++++++------ + 2 files changed, 15 insertions(+), 8 deletions(-) + +--- a/fs/xfs/linux-2.6/xfs_sync.c ++++ b/fs/xfs/linux-2.6/xfs_sync.c +@@ -693,12 +693,12 @@ xfs_inode_set_reclaim_tag( + xfs_mount_t *mp = ip->i_mount; + xfs_perag_t *pag = xfs_get_perag(mp, ip->i_ino); + +- read_lock(&pag->pag_ici_lock); ++ write_lock(&pag->pag_ici_lock); + spin_lock(&ip->i_flags_lock); + __xfs_inode_set_reclaim_tag(pag, ip); + __xfs_iflags_set(ip, XFS_IRECLAIMABLE); + spin_unlock(&ip->i_flags_lock); +- read_unlock(&pag->pag_ici_lock); ++ write_unlock(&pag->pag_ici_lock); + xfs_put_perag(mp, pag); + } + +--- a/fs/xfs/xfs_iget.c ++++ b/fs/xfs/xfs_iget.c +@@ -190,13 +190,12 @@ xfs_iget_cache_hit( + trace_xfs_iget_reclaim(ip); + + /* +- * We need to set XFS_INEW atomically with clearing the +- * reclaimable tag so that we do have an indicator of the +- * inode still being initialized. ++ * We need to set XFS_IRECLAIM to prevent xfs_reclaim_inode ++ * from stomping over us while we recycle the inode. We can't ++ * clear the radix tree reclaimable tag yet as it requires ++ * pag_ici_lock to be held exclusive. + */ +- ip->i_flags |= XFS_INEW; +- ip->i_flags &= ~XFS_IRECLAIMABLE; +- __xfs_inode_clear_reclaim_tag(mp, pag, ip); ++ ip->i_flags |= XFS_IRECLAIM; + + spin_unlock(&ip->i_flags_lock); + read_unlock(&pag->pag_ici_lock); +@@ -216,7 +215,15 @@ xfs_iget_cache_hit( + trace_xfs_iget_reclaim(ip); + goto out_error; + } ++ ++ write_lock(&pag->pag_ici_lock); ++ spin_lock(&ip->i_flags_lock); ++ ip->i_flags &= ~(XFS_IRECLAIMABLE | XFS_IRECLAIM); ++ ip->i_flags |= XFS_INEW; ++ __xfs_inode_clear_reclaim_tag(mp, pag, ip); + inode->i_state = I_NEW; ++ spin_unlock(&ip->i_flags_lock); ++ write_unlock(&pag->pag_ici_lock); + } else { + /* If the VFS inode is being torn down, pause and try again. */ + if (!igrab(inode)) { diff --git a/queue-2.6.33/xfs-non-blocking-inode-locking-in-io-completion.patch b/queue-2.6.33/xfs-non-blocking-inode-locking-in-io-completion.patch new file mode 100644 index 00000000000..65961b0f0d0 --- /dev/null +++ b/queue-2.6.33/xfs-non-blocking-inode-locking-in-io-completion.patch @@ -0,0 +1,183 @@ +From 77d7a0c2eeb285c9069e15396703d0cb9690ac50 Mon Sep 17 00:00:00 2001 +From: Dave Chinner +Date: Wed, 17 Feb 2010 05:36:29 +0000 +Subject: xfs: Non-blocking inode locking in IO completion + +From: Dave Chinner + +commit 77d7a0c2eeb285c9069e15396703d0cb9690ac50 upstream. + +The introduction of barriers to loop devices has created a new IO +order completion dependency that XFS does not handle. The loop +device implements barriers using fsync and so turns a log IO in the +XFS filesystem on the loop device into a data IO in the backing +filesystem. That is, the completion of log IOs in the loop +filesystem are now dependent on completion of data IO in the backing +filesystem. + +This can cause deadlocks when a flush daemon issues a log force with +an inode locked because the IO completion of IO on the inode is +blocked by the inode lock. This in turn prevents further data IO +completion from occuring on all XFS filesystems on that CPU (due to +the shared nature of the completion queues). This then prevents the +log IO from completing because the log is waiting for data IO +completion as well. + +The fix for this new completion order dependency issue is to make +the IO completion inode locking non-blocking. If the inode lock +can't be grabbed, simply requeue the IO completion back to the work +queue so that it can be processed later. This prevents the +completion queue from being blocked and allows data IO completion on +other inodes to proceed, hence avoiding completion order dependent +deadlocks. + +Signed-off-by: Dave Chinner +Reviewed-by: Christoph Hellwig +Signed-off-by: Alex Elder +Signed-off-by: Greg Kroah-Hartman + +--- + fs/xfs/linux-2.6/xfs_aops.c | 93 ++++++++++++++++++++++++++------------------ + 1 file changed, 56 insertions(+), 37 deletions(-) + +--- a/fs/xfs/linux-2.6/xfs_aops.c ++++ b/fs/xfs/linux-2.6/xfs_aops.c +@@ -163,14 +163,17 @@ xfs_ioend_new_eof( + } + + /* +- * Update on-disk file size now that data has been written to disk. +- * The current in-memory file size is i_size. If a write is beyond +- * eof i_new_size will be the intended file size until i_size is +- * updated. If this write does not extend all the way to the valid +- * file size then restrict this update to the end of the write. ++ * Update on-disk file size now that data has been written to disk. The ++ * current in-memory file size is i_size. If a write is beyond eof i_new_size ++ * will be the intended file size until i_size is updated. If this write does ++ * not extend all the way to the valid file size then restrict this update to ++ * the end of the write. ++ * ++ * This function does not block as blocking on the inode lock in IO completion ++ * can lead to IO completion order dependency deadlocks.. If it can't get the ++ * inode ilock it will return EAGAIN. Callers must handle this. + */ +- +-STATIC void ++STATIC int + xfs_setfilesize( + xfs_ioend_t *ioend) + { +@@ -181,9 +184,11 @@ xfs_setfilesize( + ASSERT(ioend->io_type != IOMAP_READ); + + if (unlikely(ioend->io_error)) +- return; ++ return 0; ++ ++ if (!xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) ++ return EAGAIN; + +- xfs_ilock(ip, XFS_ILOCK_EXCL); + isize = xfs_ioend_new_eof(ioend); + if (isize) { + ip->i_d.di_size = isize; +@@ -191,6 +196,28 @@ xfs_setfilesize( + } + + xfs_iunlock(ip, XFS_ILOCK_EXCL); ++ return 0; ++} ++ ++/* ++ * Schedule IO completion handling on a xfsdatad if this was ++ * the final hold on this ioend. If we are asked to wait, ++ * flush the workqueue. ++ */ ++STATIC void ++xfs_finish_ioend( ++ xfs_ioend_t *ioend, ++ int wait) ++{ ++ if (atomic_dec_and_test(&ioend->io_remaining)) { ++ struct workqueue_struct *wq; ++ ++ wq = (ioend->io_type == IOMAP_UNWRITTEN) ? ++ xfsconvertd_workqueue : xfsdatad_workqueue; ++ queue_work(wq, &ioend->io_work); ++ if (wait) ++ flush_workqueue(wq); ++ } + } + + /* +@@ -198,11 +225,11 @@ xfs_setfilesize( + */ + STATIC void + xfs_end_io( +- struct work_struct *work) ++ struct work_struct *work) + { +- xfs_ioend_t *ioend = +- container_of(work, xfs_ioend_t, io_work); +- struct xfs_inode *ip = XFS_I(ioend->io_inode); ++ xfs_ioend_t *ioend = container_of(work, xfs_ioend_t, io_work); ++ struct xfs_inode *ip = XFS_I(ioend->io_inode); ++ int error; + + /* + * For unwritten extents we need to issue transactions to convert a +@@ -210,7 +237,6 @@ xfs_end_io( + */ + if (ioend->io_type == IOMAP_UNWRITTEN && + likely(!ioend->io_error && !XFS_FORCED_SHUTDOWN(ip->i_mount))) { +- int error; + + error = xfs_iomap_write_unwritten(ip, ioend->io_offset, + ioend->io_size); +@@ -222,30 +248,23 @@ xfs_end_io( + * We might have to update the on-disk file size after extending + * writes. + */ +- if (ioend->io_type != IOMAP_READ) +- xfs_setfilesize(ioend); +- xfs_destroy_ioend(ioend); +-} +- +-/* +- * Schedule IO completion handling on a xfsdatad if this was +- * the final hold on this ioend. If we are asked to wait, +- * flush the workqueue. +- */ +-STATIC void +-xfs_finish_ioend( +- xfs_ioend_t *ioend, +- int wait) +-{ +- if (atomic_dec_and_test(&ioend->io_remaining)) { +- struct workqueue_struct *wq; +- +- wq = (ioend->io_type == IOMAP_UNWRITTEN) ? +- xfsconvertd_workqueue : xfsdatad_workqueue; +- queue_work(wq, &ioend->io_work); +- if (wait) +- flush_workqueue(wq); ++ if (ioend->io_type != IOMAP_READ) { ++ error = xfs_setfilesize(ioend); ++ ASSERT(!error || error == EAGAIN); + } ++ ++ /* ++ * If we didn't complete processing of the ioend, requeue it to the ++ * tail of the workqueue for another attempt later. Otherwise destroy ++ * it. ++ */ ++ if (error == EAGAIN) { ++ atomic_inc(&ioend->io_remaining); ++ xfs_finish_ioend(ioend, 0); ++ /* ensure we don't spin on blocked ioends */ ++ delay(1); ++ } else ++ xfs_destroy_ioend(ioend); + } + + /*