]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.1-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 30 Jul 2015 19:41:39 +0000 (12:41 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 30 Jul 2015 19:41:39 +0000 (12:41 -0700)
added patches:
tpm-fix-initialization-of-the-cdev.patch
tpm-tpm_crb-fail-when-tpm2-acpi-table-contents-look-corrupted.patch
tpm-tpm_crb-fix-le64_to_cpu-conversions-in-crb_acpi_add.patch
vtpm-set-virtual-device-before-passing-to-ibmvtpm_reset_crq.patch
w1_therm-reference-count-family-data.patch
xfs-don-t-truncate-attribute-extents-if-no-extents-exist.patch
xfs-fix-remote-symlinks-on-v5-crc-filesystems.patch

queue-4.1/series
queue-4.1/tpm-fix-initialization-of-the-cdev.patch [new file with mode: 0644]
queue-4.1/tpm-tpm_crb-fail-when-tpm2-acpi-table-contents-look-corrupted.patch [new file with mode: 0644]
queue-4.1/tpm-tpm_crb-fix-le64_to_cpu-conversions-in-crb_acpi_add.patch [new file with mode: 0644]
queue-4.1/vtpm-set-virtual-device-before-passing-to-ibmvtpm_reset_crq.patch [new file with mode: 0644]
queue-4.1/w1_therm-reference-count-family-data.patch [new file with mode: 0644]
queue-4.1/xfs-don-t-truncate-attribute-extents-if-no-extents-exist.patch [new file with mode: 0644]
queue-4.1/xfs-fix-remote-symlinks-on-v5-crc-filesystems.patch [new file with mode: 0644]

index c851bfbe4fb0637fa79bbd607a6d157b01867984..dc8bffa20bf013fce0fca33fbfea4766affe0c9b 100644 (file)
@@ -162,3 +162,10 @@ drm-add-a-check-for-x-y-in-drm_mode_setcrtc.patch
 drm-provide-compat-ioctl-for-addfb2.1.patch
 drm-stop-resetting-connector-state-to-unknown.patch
 libata-fix-regression-when-the-ncq-send-and-receive-log-page-is-absent.patch
+xfs-fix-remote-symlinks-on-v5-crc-filesystems.patch
+xfs-don-t-truncate-attribute-extents-if-no-extents-exist.patch
+w1_therm-reference-count-family-data.patch
+tpm-tpm_crb-fix-le64_to_cpu-conversions-in-crb_acpi_add.patch
+vtpm-set-virtual-device-before-passing-to-ibmvtpm_reset_crq.patch
+tpm-fix-initialization-of-the-cdev.patch
+tpm-tpm_crb-fail-when-tpm2-acpi-table-contents-look-corrupted.patch
diff --git a/queue-4.1/tpm-fix-initialization-of-the-cdev.patch b/queue-4.1/tpm-fix-initialization-of-the-cdev.patch
new file mode 100644 (file)
index 0000000..43b84fa
--- /dev/null
@@ -0,0 +1,41 @@
+From ba0ef85479c46a2ab354c2220bdb6152f7f4baf3 Mon Sep 17 00:00:00 2001
+From: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
+Date: Tue, 30 Jun 2015 13:15:31 -0600
+Subject: tpm: Fix initialization of the cdev
+
+From: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
+
+commit ba0ef85479c46a2ab354c2220bdb6152f7f4baf3 upstream.
+
+When a cdev is contained in a dynamic structure the cdev parent kobj
+should be set to the kobj that controls the lifetime of the enclosing
+structure. In TPM's case this is the embedded struct device.
+
+Also, cdev_init 0's the whole structure, so all sets must be after,
+not before. This fixes module ref counting and cdev.
+
+Fixes: 313d21eeab92 ("tpm: device class for tpm")
+Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
+Reviewed-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
+Reviewed-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+Tested-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+Signed-off-by: Peter Huewe <peterhuewe@gmx.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/char/tpm/tpm-chip.c |    3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/char/tpm/tpm-chip.c
++++ b/drivers/char/tpm/tpm-chip.c
+@@ -129,8 +129,9 @@ struct tpm_chip *tpmm_chip_alloc(struct
+       device_initialize(&chip->dev);
+-      chip->cdev.owner = chip->pdev->driver->owner;
+       cdev_init(&chip->cdev, &tpm_fops);
++      chip->cdev.owner = chip->pdev->driver->owner;
++      chip->cdev.kobj.parent = &chip->dev.kobj;
+       return chip;
+ }
diff --git a/queue-4.1/tpm-tpm_crb-fail-when-tpm2-acpi-table-contents-look-corrupted.patch b/queue-4.1/tpm-tpm_crb-fail-when-tpm2-acpi-table-contents-look-corrupted.patch
new file mode 100644 (file)
index 0000000..d1020f0
--- /dev/null
@@ -0,0 +1,42 @@
+From b371616b8537d6450ebca0819defbf53452bebf3 Mon Sep 17 00:00:00 2001
+From: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+Date: Wed, 24 Jun 2015 17:14:55 +0300
+Subject: tpm, tpm_crb: fail when TPM2 ACPI table contents look corrupted
+
+From: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+
+commit b371616b8537d6450ebca0819defbf53452bebf3 upstream.
+
+At least some versions of AMI BIOS have corrupted contents in the TPM2
+ACPI table and namely the physical address of the control area is set to
+zero.
+
+This patch changes the driver to fail gracefully  when we observe a zero
+address instead of continuing to ioremap.
+
+Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+Reviewed-by: Peter Huewe <peterhuewe@gmx.de>
+Signed-off-by: Peter Huewe <peterhuewe@gmx.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/char/tpm/tpm_crb.c |    8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/drivers/char/tpm/tpm_crb.c
++++ b/drivers/char/tpm/tpm_crb.c
+@@ -233,6 +233,14 @@ static int crb_acpi_add(struct acpi_devi
+               return -ENODEV;
+       }
++      /* At least some versions of AMI BIOS have a bug that TPM2 table has
++       * zero address for the control area and therefore we must fail.
++      */
++      if (!buf->control_area_pa) {
++              dev_err(dev, "TPM2 ACPI table has a zero address for the control area\n");
++              return -EINVAL;
++      }
++
+       if (buf->hdr.length < sizeof(struct acpi_tpm2)) {
+               dev_err(dev, "TPM2 ACPI table has wrong size");
+               return -EINVAL;
diff --git a/queue-4.1/tpm-tpm_crb-fix-le64_to_cpu-conversions-in-crb_acpi_add.patch b/queue-4.1/tpm-tpm_crb-fix-le64_to_cpu-conversions-in-crb_acpi_add.patch
new file mode 100644 (file)
index 0000000..56d2846
--- /dev/null
@@ -0,0 +1,44 @@
+From 49afd7289bd937401c5f7faa193054bc3c41dad6 Mon Sep 17 00:00:00 2001
+From: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+Date: Tue, 9 Jun 2015 15:07:59 +0300
+Subject: tpm, tpm_crb: fix le64_to_cpu conversions in crb_acpi_add()
+
+From: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+
+commit 49afd7289bd937401c5f7faa193054bc3c41dad6 upstream.
+
+le64_to_cpu() was applied twice to the physical addresses read from the
+control area. This hasn't shown any visible regressions because CRB
+driver has been tested only on the little endian platofrms so far.
+
+Reported-by: Matt Fleming <matt.fleming@intel.com>
+Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+Reviewed-By: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
+Fixes: 30fc8d138e91 ("tpm: TPM 2.0 CRB Interface")
+Signed-off-by: Peter Huewe <peterhuewe@gmx.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/char/tpm/tpm_crb.c |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/char/tpm/tpm_crb.c
++++ b/drivers/char/tpm/tpm_crb.c
+@@ -267,7 +267,7 @@ static int crb_acpi_add(struct acpi_devi
+       memcpy_fromio(&pa, &priv->cca->cmd_pa, 8);
+       pa = le64_to_cpu(pa);
+-      priv->cmd = devm_ioremap_nocache(dev, le64_to_cpu(pa),
++      priv->cmd = devm_ioremap_nocache(dev, pa,
+                                        ioread32(&priv->cca->cmd_size));
+       if (!priv->cmd) {
+               dev_err(dev, "ioremap of the command buffer failed\n");
+@@ -276,7 +276,7 @@ static int crb_acpi_add(struct acpi_devi
+       memcpy_fromio(&pa, &priv->cca->rsp_pa, 8);
+       pa = le64_to_cpu(pa);
+-      priv->rsp = devm_ioremap_nocache(dev, le64_to_cpu(pa),
++      priv->rsp = devm_ioremap_nocache(dev, pa,
+                                        ioread32(&priv->cca->rsp_size));
+       if (!priv->rsp) {
+               dev_err(dev, "ioremap of the response buffer failed\n");
diff --git a/queue-4.1/vtpm-set-virtual-device-before-passing-to-ibmvtpm_reset_crq.patch b/queue-4.1/vtpm-set-virtual-device-before-passing-to-ibmvtpm_reset_crq.patch
new file mode 100644 (file)
index 0000000..5207c5a
--- /dev/null
@@ -0,0 +1,45 @@
+From 9d75f08946e8485109458ccf16f714697c207f41 Mon Sep 17 00:00:00 2001
+From: "Hon Ching \\(Vicky\\) Lo" <honclo@linux.vnet.ibm.com>
+Date: Fri, 22 May 2015 13:23:02 -0400
+Subject: vTPM: set virtual device before passing to ibmvtpm_reset_crq
+
+From: "Hon Ching \\(Vicky\\) Lo" <honclo@linux.vnet.ibm.com>
+
+commit 9d75f08946e8485109458ccf16f714697c207f41 upstream.
+
+tpm_ibmvtpm_probe() calls ibmvtpm_reset_crq(ibmvtpm) without having yet
+set the virtual device in the ibmvtpm structure. So in ibmvtpm_reset_crq,
+the phype call contains empty unit addresses, ibmvtpm->vdev->unit_address.
+
+Signed-off-by: Hon Ching(Vicky) Lo <honclo@linux.vnet.ibm.com>
+Signed-off-by: Joy Latten <jmlatten@linux.vnet.ibm.com>
+Reviewed-by: Ashley Lai <ashley@ahsleylai.com>
+Fixes: 132f76294744 ("drivers/char/tpm: Add new device driver to support IBM vTPM")
+Signed-off-by: Peter Huewe <peterhuewe@gmx.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/char/tpm/tpm_ibmvtpm.c |    5 +++--
+ 1 file changed, 3 insertions(+), 2 deletions(-)
+
+--- a/drivers/char/tpm/tpm_ibmvtpm.c
++++ b/drivers/char/tpm/tpm_ibmvtpm.c
+@@ -578,6 +578,9 @@ static int tpm_ibmvtpm_probe(struct vio_
+               goto cleanup;
+       }
++      ibmvtpm->dev = dev;
++      ibmvtpm->vdev = vio_dev;
++
+       crq_q = &ibmvtpm->crq_queue;
+       crq_q->crq_addr = (struct ibmvtpm_crq *)get_zeroed_page(GFP_KERNEL);
+       if (!crq_q->crq_addr) {
+@@ -622,8 +625,6 @@ static int tpm_ibmvtpm_probe(struct vio_
+       crq_q->index = 0;
+-      ibmvtpm->dev = dev;
+-      ibmvtpm->vdev = vio_dev;
+       TPM_VPRIV(chip) = (void *)ibmvtpm;
+       spin_lock_init(&ibmvtpm->rtce_lock);
diff --git a/queue-4.1/w1_therm-reference-count-family-data.patch b/queue-4.1/w1_therm-reference-count-family-data.patch
new file mode 100644 (file)
index 0000000..b088e24
--- /dev/null
@@ -0,0 +1,144 @@
+From f7134eea05b2fb4a2c0935f8a540539fff01f3eb Mon Sep 17 00:00:00 2001
+From: David Fries <David@Fries.net>
+Date: Fri, 8 May 2015 19:51:50 -0500
+Subject: w1_therm reference count family data
+
+From: David Fries <David@Fries.net>
+
+commit f7134eea05b2fb4a2c0935f8a540539fff01f3eb upstream.
+
+A temperature conversion can take 750 ms and when possible the
+w1_therm slave driver drops the bus_mutex to allow other bus
+operations, but that includes operations such as a periodic slave
+search, which can remove this slave when it is no longer detected.
+If that happens the sl->family_data will be freed and set to NULL
+causing w1_slave_show to crash when it wakes up.
+
+Signed-off-by: David Fries <David@Fries.net>
+Reported-By: Thorsten Bschorr <thorsten@bschorr.de>
+Tested-by: Thorsten Bschorr <thorsten@bschorr.de>
+Acked-by: Evgeniy Polyakov <zbr@ioremap.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/w1/slaves/w1_therm.c |   62 ++++++++++++++++++++++++++++++++-----------
+ 1 file changed, 47 insertions(+), 15 deletions(-)
+
+--- a/drivers/w1/slaves/w1_therm.c
++++ b/drivers/w1/slaves/w1_therm.c
+@@ -59,16 +59,32 @@ MODULE_ALIAS("w1-family-" __stringify(W1
+ static int w1_strong_pullup = 1;
+ module_param_named(strong_pullup, w1_strong_pullup, int, 0);
++struct w1_therm_family_data {
++      uint8_t rom[9];
++      atomic_t refcnt;
++};
++
++/* return the address of the refcnt in the family data */
++#define THERM_REFCNT(family_data) \
++      (&((struct w1_therm_family_data*)family_data)->refcnt)
++
+ static int w1_therm_add_slave(struct w1_slave *sl)
+ {
+-      sl->family_data = kzalloc(9, GFP_KERNEL);
++      sl->family_data = kzalloc(sizeof(struct w1_therm_family_data),
++              GFP_KERNEL);
+       if (!sl->family_data)
+               return -ENOMEM;
++      atomic_set(THERM_REFCNT(sl->family_data), 1);
+       return 0;
+ }
+ static void w1_therm_remove_slave(struct w1_slave *sl)
+ {
++      int refcnt = atomic_sub_return(1, THERM_REFCNT(sl->family_data));
++      while(refcnt) {
++              msleep(1000);
++              refcnt = atomic_read(THERM_REFCNT(sl->family_data));
++      }
+       kfree(sl->family_data);
+       sl->family_data = NULL;
+ }
+@@ -194,13 +210,22 @@ static ssize_t w1_slave_show(struct devi
+       struct w1_slave *sl = dev_to_w1_slave(device);
+       struct w1_master *dev = sl->master;
+       u8 rom[9], crc, verdict, external_power;
+-      int i, max_trying = 10;
++      int i, ret, max_trying = 10;
+       ssize_t c = PAGE_SIZE;
++      u8 *family_data = sl->family_data;
++
++      ret = mutex_lock_interruptible(&dev->bus_mutex);
++      if (ret != 0)
++              goto post_unlock;
+-      i = mutex_lock_interruptible(&dev->bus_mutex);
+-      if (i != 0)
+-              return i;
++      if(!sl->family_data)
++      {
++              ret = -ENODEV;
++              goto pre_unlock;
++      }
++      /* prevent the slave from going away in sleep */
++      atomic_inc(THERM_REFCNT(family_data));
+       memset(rom, 0, sizeof(rom));
+       while (max_trying--) {
+@@ -230,17 +255,19 @@ static ssize_t w1_slave_show(struct devi
+                               mutex_unlock(&dev->bus_mutex);
+                               sleep_rem = msleep_interruptible(tm);
+-                              if (sleep_rem != 0)
+-                                      return -EINTR;
++                              if (sleep_rem != 0) {
++                                      ret = -EINTR;
++                                      goto post_unlock;
++                              }
+-                              i = mutex_lock_interruptible(&dev->bus_mutex);
+-                              if (i != 0)
+-                                      return i;
++                              ret = mutex_lock_interruptible(&dev->bus_mutex);
++                              if (ret != 0)
++                                      goto post_unlock;
+                       } else if (!w1_strong_pullup) {
+                               sleep_rem = msleep_interruptible(tm);
+                               if (sleep_rem != 0) {
+-                                      mutex_unlock(&dev->bus_mutex);
+-                                      return -EINTR;
++                                      ret = -EINTR;
++                                      goto pre_unlock;
+                               }
+                       }
+@@ -269,19 +296,24 @@ static ssize_t w1_slave_show(struct devi
+       c -= snprintf(buf + PAGE_SIZE - c, c, ": crc=%02x %s\n",
+                          crc, (verdict) ? "YES" : "NO");
+       if (verdict)
+-              memcpy(sl->family_data, rom, sizeof(rom));
++              memcpy(family_data, rom, sizeof(rom));
+       else
+               dev_warn(device, "Read failed CRC check\n");
+       for (i = 0; i < 9; ++i)
+               c -= snprintf(buf + PAGE_SIZE - c, c, "%02x ",
+-                            ((u8 *)sl->family_data)[i]);
++                            ((u8 *)family_data)[i]);
+       c -= snprintf(buf + PAGE_SIZE - c, c, "t=%d\n",
+               w1_convert_temp(rom, sl->family->fid));
++      ret = PAGE_SIZE - c;
++
++pre_unlock:
+       mutex_unlock(&dev->bus_mutex);
+-      return PAGE_SIZE - c;
++post_unlock:
++      atomic_dec(THERM_REFCNT(family_data));
++      return ret;
+ }
+ static int __init w1_therm_init(void)
diff --git a/queue-4.1/xfs-don-t-truncate-attribute-extents-if-no-extents-exist.patch b/queue-4.1/xfs-don-t-truncate-attribute-extents-if-no-extents-exist.patch
new file mode 100644 (file)
index 0000000..4aa130a
--- /dev/null
@@ -0,0 +1,63 @@
+From f66bf042693b620133d39af8d2f13615f03eadfc Mon Sep 17 00:00:00 2001
+From: Brian Foster <bfoster@redhat.com>
+Date: Tue, 23 Jun 2015 08:47:20 +1000
+Subject: xfs: don't truncate attribute extents if no extents exist
+
+From: Brian Foster <bfoster@redhat.com>
+
+commit f66bf042693b620133d39af8d2f13615f03eadfc upstream.
+
+The xfs_attr3_root_inactive() call from xfs_attr_inactive() assumes that
+attribute blocks exist to invalidate. It is possible to have an
+attribute fork without extents, however. Consider the case where the
+attribute fork is created towards the beginning of xfs_attr_set() but
+some part of the subsequent attribute set fails.
+
+If an inode in such a state hits xfs_attr_inactive(), it eventually
+calls xfs_dabuf_map() and possibly xfs_bmapi_read(). The former emits a
+filesystem corruption warning, returns an error that bubbles back up to
+xfs_attr_inactive(), and leads to destruction of the in-core attribute
+fork without an on-disk reset. If the inode happens to make it back
+through xfs_inactive() in this state (e.g., via a concurrent bulkstat
+that cycles the inode from the reclaim state and releases it), i_afp
+might not exist when xfs_bmapi_read() is called and causes a NULL
+dereference panic.
+
+A '-p 2' fsstress run to ENOSPC on a relatively small fs (1GB)
+reproduces these problems. The behavior is a regression caused by:
+
+6dfe5a0 xfs: xfs_attr_inactive leaves inconsistent attr fork state behind
+
+... which removed logic that avoided the attribute extent truncate when
+no extents exist. Restore this logic to ensure the attribute fork is
+destroyed and reset correctly if it exists without any allocated
+extents.
+
+Signed-off-by: Brian Foster <bfoster@redhat.com>
+Reviewed-by: Dave Chinner <dchinner@redhat.com>
+Signed-off-by: Dave Chinner <david@fromorbit.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/xfs/xfs_attr_inactive.c |   10 ++++++++--
+ 1 file changed, 8 insertions(+), 2 deletions(-)
+
+--- a/fs/xfs/xfs_attr_inactive.c
++++ b/fs/xfs/xfs_attr_inactive.c
+@@ -435,8 +435,14 @@ xfs_attr_inactive(
+        */
+       xfs_trans_ijoin(trans, dp, 0);
+-      /* invalidate and truncate the attribute fork extents */
+-      if (dp->i_d.di_aformat != XFS_DINODE_FMT_LOCAL) {
++      /*
++       * Invalidate and truncate the attribute fork extents. Make sure the
++       * fork actually has attributes as otherwise the invalidation has no
++       * blocks to read and returns an error. In this case, just do the fork
++       * removal below.
++       */
++      if (xfs_inode_hasattr(dp) &&
++          dp->i_d.di_aformat != XFS_DINODE_FMT_LOCAL) {
+               error = xfs_attr3_root_inactive(&trans, dp);
+               if (error)
+                       goto out_cancel;
diff --git a/queue-4.1/xfs-fix-remote-symlinks-on-v5-crc-filesystems.patch b/queue-4.1/xfs-fix-remote-symlinks-on-v5-crc-filesystems.patch
new file mode 100644 (file)
index 0000000..10aba64
--- /dev/null
@@ -0,0 +1,49 @@
+From 2ac56d3d4bd625450a54d4c3f9292d58f6b88232 Mon Sep 17 00:00:00 2001
+From: Eric Sandeen <sandeen@redhat.com>
+Date: Mon, 22 Jun 2015 09:42:48 +1000
+Subject: xfs: fix remote symlinks on V5/CRC filesystems
+
+From: Eric Sandeen <sandeen@redhat.com>
+
+commit 2ac56d3d4bd625450a54d4c3f9292d58f6b88232 upstream.
+
+If we create a CRC filesystem, mount it, and create a symlink with
+a path long enough that it can't live in the inode, we get a very
+strange result upon remount:
+
+# ls -l mnt
+total 4
+lrwxrwxrwx. 1 root root 929 Jun 15 16:58 link -> XSLM
+
+XSLM is the V5 symlink block header magic (which happens to be
+followed by a NUL, so the string looks terminated).
+
+xfs_readlink_bmap() advanced cur_chunk by the size of the header
+for CRC filesystems, but never actually used that pointer; it
+kept reading from bp->b_addr, which is the start of the block,
+rather than the start of the symlink data after the header.
+
+Looks like this problem goes back to v3.10.
+
+Fixing this gets us reading the proper link target, again.
+
+Signed-off-by: Eric Sandeen <sandeen@redhat.com>
+Reviewed-by: Dave Chinner <dchinner@redhat.com>
+Signed-off-by: Dave Chinner <david@fromorbit.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/xfs/xfs_symlink.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/fs/xfs/xfs_symlink.c
++++ b/fs/xfs/xfs_symlink.c
+@@ -104,7 +104,7 @@ xfs_readlink_bmap(
+                       cur_chunk += sizeof(struct xfs_dsymlink_hdr);
+               }
+-              memcpy(link + offset, bp->b_addr, byte_cnt);
++              memcpy(link + offset, cur_chunk, byte_cnt);
+               pathlen -= byte_cnt;
+               offset += byte_cnt;