This is the 4.9.157 stable release
-----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEZH8oZUiU471FcZm+ONu9yGCSaT4FAlxmZTwACgkQONu9yGCS aT5RRRAApBBKX80D/RVr7Ff0mSdK6cthcpvuRt1XK0BOxem1j3AcGz+TtWyas/A3 Dn4kLCvOdIJTVP6Pk9Uk4DeEGcoO7cfP71J3EK5pk6UQt2eR0gVhm1F6nctlR5dk mtDyeWIHbmkowYfhq0Jr8XyUt/jPpNQZocBGX5aAvj0okJt5fmuq0gw2XFfoCS8n +3oI5s2TzxVmv//yi0pNQs1nsvsjCRBeM8O6NnzsOVbJhAzi58tDZKhODyw4UD3J 9cfn3ryHq20/p7HZ82xcV08jGlu/cIIudRkLLBjJn4bVP5rByzF5nLVpaW/WvkRi nuXfby7DjlVdJ+i27MVJkNcwI5bGm03GcBywp1Bff+Heud33XSIY16+Q7LkidH1T v+LkHsxQ6oMBph6yEhrzlarbFuUUxz0yV9f25/1JmvUETyQgrKbmkZF3CqlGhZrY Oi40GcIETGvK6/9SS0buezEZGCXyUgD4Ro+kPFxygb0MyquB92GM0/O+zsqxKTKK 96hkEyxvosFNjFqhzPNtnnzAslvzEgv811OWKWCZMk3EJhMW7HLdbec/7TgMbG9Y onzX2v0/Myu95XzXjRVUP/s8A3HmuSoBLSi1onS3s22oFY+XuofUpdz/3G98zMJq 18SiCiOdtC8abYISJmiC5msQjjC6L4fc802pjhSDqNxiysdNZxc= =OIEO -----END PGP SIGNATURE----- Merge 4.9.157 into android-4.9 Changes in 4.9.157 mtd: rawnand: gpmi: fix MX28 bus master lockup problem iio: chemical: atlas-ph-sensor: correct IIO_TEMP values to millicelsius signal: Always notice exiting tasks signal: Better detection of synchronous signals misc: vexpress: Off by one in vexpress_syscfg_exec() samples: mei: use /dev/mei0 instead of /dev/mei debugfs: fix debugfs_rename parameter checking mips: cm: reprime error cause MIPS: OCTEON: don't set octeon_dma_bar_type if PCI is disabled MIPS: VDSO: Include $(ccflags-vdso) in o32,n32 .lds builds ARM: iop32x/n2100: fix PCI IRQ mapping ARM: tango: Improve ARCH_MULTIPLATFORM compatibility mac80211: ensure that mgmt tx skbs have tailroom for encryption drm/modes: Prevent division by zero htotal drm/vmwgfx: Fix setting of dma masks drm/vmwgfx: Return error code from vmw_execbuf_copy_fence_user nfsd4: fix cached replies to solo SEQUENCE compounds nfsd4: catch some false session retries HID: debug: fix the ring buffer implementation Revert "cifs: In Kconfig CONFIG_CIFS_POSIX needs depends on legacy (insecure cifs)" libceph: avoid KEEPALIVE_PENDING races in ceph_con_keepalive() xfrm: refine validation of template and selector families batman-adv: Avoid WARN on net_device without parent in netns batman-adv: Force mac header to start of data on xmit Linux 4.9.157 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
commit
78c4814db7
28 changed files with 248 additions and 134 deletions
2
Makefile
2
Makefile
|
|
@ -1,6 +1,6 @@
|
|||
VERSION = 4
|
||||
PATCHLEVEL = 9
|
||||
SUBLEVEL = 156
|
||||
SUBLEVEL = 157
|
||||
EXTRAVERSION =
|
||||
NAME = Roaring Lionus
|
||||
|
||||
|
|
|
|||
|
|
@ -75,8 +75,7 @@ void __init n2100_map_io(void)
|
|||
/*
|
||||
* N2100 PCI.
|
||||
*/
|
||||
static int __init
|
||||
n2100_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
||||
static int n2100_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
|
||||
{
|
||||
int irq;
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#include <linux/suspend.h>
|
||||
#include <asm/suspend.h>
|
||||
#include "smc.h"
|
||||
#include "pm.h"
|
||||
|
||||
static int tango_pm_powerdown(unsigned long arg)
|
||||
{
|
||||
|
|
@ -23,10 +24,7 @@ static const struct platform_suspend_ops tango_pm_ops = {
|
|||
.valid = suspend_valid_only_mem,
|
||||
};
|
||||
|
||||
static int __init tango_pm_init(void)
|
||||
void __init tango_pm_init(void)
|
||||
{
|
||||
suspend_set_ops(&tango_pm_ops);
|
||||
return 0;
|
||||
}
|
||||
|
||||
late_initcall(tango_pm_init);
|
||||
|
|
|
|||
7
arch/arm/mach-tango/pm.h
Normal file
7
arch/arm/mach-tango/pm.h
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#ifdef CONFIG_SUSPEND
|
||||
void __init tango_pm_init(void);
|
||||
#else
|
||||
#define tango_pm_init NULL
|
||||
#endif
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
#include <asm/mach/arch.h>
|
||||
#include <asm/hardware/cache-l2x0.h>
|
||||
#include "smc.h"
|
||||
#include "pm.h"
|
||||
|
||||
static void tango_l2c_write(unsigned long val, unsigned int reg)
|
||||
{
|
||||
|
|
@ -14,4 +15,5 @@ DT_MACHINE_START(TANGO_DT, "Sigma Tango DT")
|
|||
.dt_compat = tango_dt_compat,
|
||||
.l2c_aux_mask = ~0,
|
||||
.l2c_write_sec = tango_l2c_write,
|
||||
.init_late = tango_pm_init,
|
||||
MACHINE_END
|
||||
|
|
|
|||
|
|
@ -424,5 +424,5 @@ void mips_cm_error_report(void)
|
|||
}
|
||||
|
||||
/* reprime cause register */
|
||||
write_gcr_error_cause(0);
|
||||
write_gcr_error_cause(cm_error);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -573,6 +573,11 @@ static int __init octeon_pci_setup(void)
|
|||
if (octeon_has_feature(OCTEON_FEATURE_PCIE))
|
||||
return 0;
|
||||
|
||||
if (!octeon_is_pci_host()) {
|
||||
pr_notice("Not in host mode, PCI Controller not initialized\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Point pcibios_map_irq() to the PCI version of it */
|
||||
octeon_pcibios_map_irq = octeon_pci_pcibios_map_irq;
|
||||
|
||||
|
|
@ -584,11 +589,6 @@ static int __init octeon_pci_setup(void)
|
|||
else
|
||||
octeon_dma_bar_type = OCTEON_DMA_BAR_TYPE_BIG;
|
||||
|
||||
if (!octeon_is_pci_host()) {
|
||||
pr_notice("Not in host mode, PCI Controller not initialized\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* PCI I/O and PCI MEM values */
|
||||
set_io_port_base(OCTEON_PCI_IOSPACE_BASE);
|
||||
ioport_resource.start = 0;
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ $(obj)/%-o32.o: $(src)/%.c FORCE
|
|||
$(call cmd,force_checksrc)
|
||||
$(call if_changed_rule,cc_o_c)
|
||||
|
||||
$(obj)/vdso-o32.lds: KBUILD_CPPFLAGS := -mabi=32
|
||||
$(obj)/vdso-o32.lds: KBUILD_CPPFLAGS := $(ccflags-vdso) -mabi=32
|
||||
$(obj)/vdso-o32.lds: $(src)/vdso.lds.S FORCE
|
||||
$(call if_changed_dep,cpp_lds_S)
|
||||
|
||||
|
|
@ -156,7 +156,7 @@ $(obj)/%-n32.o: $(src)/%.c FORCE
|
|||
$(call cmd,force_checksrc)
|
||||
$(call if_changed_rule,cc_o_c)
|
||||
|
||||
$(obj)/vdso-n32.lds: KBUILD_CPPFLAGS := -mabi=n32
|
||||
$(obj)/vdso-n32.lds: KBUILD_CPPFLAGS := $(ccflags-vdso) -mabi=n32
|
||||
$(obj)/vdso-n32.lds: $(src)/vdso.lds.S FORCE
|
||||
$(call if_changed_dep,cpp_lds_S)
|
||||
|
||||
|
|
|
|||
|
|
@ -753,7 +753,7 @@ int drm_mode_hsync(const struct drm_display_mode *mode)
|
|||
if (mode->hsync)
|
||||
return mode->hsync;
|
||||
|
||||
if (mode->htotal < 0)
|
||||
if (mode->htotal <= 0)
|
||||
return 0;
|
||||
|
||||
calc_val = (mode->clock * 1000) / mode->htotal; /* hsync in Hz */
|
||||
|
|
|
|||
|
|
@ -605,13 +605,16 @@ out_fixup:
|
|||
static int vmw_dma_masks(struct vmw_private *dev_priv)
|
||||
{
|
||||
struct drm_device *dev = dev_priv->dev;
|
||||
int ret = 0;
|
||||
|
||||
if (intel_iommu_enabled &&
|
||||
ret = dma_set_mask_and_coherent(dev->dev, DMA_BIT_MASK(64));
|
||||
if (dev_priv->map_mode != vmw_dma_phys &&
|
||||
(sizeof(unsigned long) == 4 || vmw_restrict_dma_mask)) {
|
||||
DRM_INFO("Restricting DMA addresses to 44 bits.\n");
|
||||
return dma_set_mask(dev->dev, DMA_BIT_MASK(44));
|
||||
return dma_set_mask_and_coherent(dev->dev, DMA_BIT_MASK(44));
|
||||
}
|
||||
return 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
static int vmw_dma_masks(struct vmw_private *dev_priv)
|
||||
|
|
|
|||
|
|
@ -3769,7 +3769,7 @@ int vmw_execbuf_fence_commands(struct drm_file *file_priv,
|
|||
*p_fence = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/kfifo.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/slab.h>
|
||||
|
|
@ -455,7 +456,7 @@ static char *resolv_usage_page(unsigned page, struct seq_file *f) {
|
|||
char *buf = NULL;
|
||||
|
||||
if (!f) {
|
||||
buf = kzalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC);
|
||||
buf = kzalloc(HID_DEBUG_BUFSIZE, GFP_ATOMIC);
|
||||
if (!buf)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
|
@ -659,17 +660,12 @@ EXPORT_SYMBOL_GPL(hid_dump_device);
|
|||
/* enqueue string to 'events' ring buffer */
|
||||
void hid_debug_event(struct hid_device *hdev, char *buf)
|
||||
{
|
||||
unsigned i;
|
||||
struct hid_debug_list *list;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&hdev->debug_list_lock, flags);
|
||||
list_for_each_entry(list, &hdev->debug_list, node) {
|
||||
for (i = 0; buf[i]; i++)
|
||||
list->hid_debug_buf[(list->tail + i) % HID_DEBUG_BUFSIZE] =
|
||||
buf[i];
|
||||
list->tail = (list->tail + i) % HID_DEBUG_BUFSIZE;
|
||||
}
|
||||
list_for_each_entry(list, &hdev->debug_list, node)
|
||||
kfifo_in(&list->hid_debug_fifo, buf, strlen(buf));
|
||||
spin_unlock_irqrestore(&hdev->debug_list_lock, flags);
|
||||
|
||||
wake_up_interruptible(&hdev->debug_wait);
|
||||
|
|
@ -720,8 +716,7 @@ void hid_dump_input(struct hid_device *hdev, struct hid_usage *usage, __s32 valu
|
|||
hid_debug_event(hdev, buf);
|
||||
|
||||
kfree(buf);
|
||||
wake_up_interruptible(&hdev->debug_wait);
|
||||
|
||||
wake_up_interruptible(&hdev->debug_wait);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(hid_dump_input);
|
||||
|
||||
|
|
@ -1086,8 +1081,8 @@ static int hid_debug_events_open(struct inode *inode, struct file *file)
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (!(list->hid_debug_buf = kzalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_KERNEL))) {
|
||||
err = -ENOMEM;
|
||||
err = kfifo_alloc(&list->hid_debug_fifo, HID_DEBUG_FIFOSIZE, GFP_KERNEL);
|
||||
if (err) {
|
||||
kfree(list);
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -1107,77 +1102,57 @@ static ssize_t hid_debug_events_read(struct file *file, char __user *buffer,
|
|||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct hid_debug_list *list = file->private_data;
|
||||
int ret = 0, len;
|
||||
int ret = 0, copied;
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
|
||||
mutex_lock(&list->read_mutex);
|
||||
while (ret == 0) {
|
||||
if (list->head == list->tail) {
|
||||
add_wait_queue(&list->hdev->debug_wait, &wait);
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
if (kfifo_is_empty(&list->hid_debug_fifo)) {
|
||||
add_wait_queue(&list->hdev->debug_wait, &wait);
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
|
||||
while (list->head == list->tail) {
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
ret = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
if (signal_pending(current)) {
|
||||
ret = -ERESTARTSYS;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!list->hdev || !list->hdev->debug) {
|
||||
ret = -EIO;
|
||||
set_current_state(TASK_RUNNING);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* allow O_NONBLOCK from other threads */
|
||||
mutex_unlock(&list->read_mutex);
|
||||
schedule();
|
||||
mutex_lock(&list->read_mutex);
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
while (kfifo_is_empty(&list->hid_debug_fifo)) {
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
ret = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
|
||||
set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&list->hdev->debug_wait, &wait);
|
||||
if (signal_pending(current)) {
|
||||
ret = -ERESTARTSYS;
|
||||
break;
|
||||
}
|
||||
|
||||
/* if list->hdev is NULL we cannot remove_wait_queue().
|
||||
* if list->hdev->debug is 0 then hid_debug_unregister()
|
||||
* was already called and list->hdev is being destroyed.
|
||||
* if we add remove_wait_queue() here we can hit a race.
|
||||
*/
|
||||
if (!list->hdev || !list->hdev->debug) {
|
||||
ret = -EIO;
|
||||
set_current_state(TASK_RUNNING);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* allow O_NONBLOCK from other threads */
|
||||
mutex_unlock(&list->read_mutex);
|
||||
schedule();
|
||||
mutex_lock(&list->read_mutex);
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
}
|
||||
|
||||
__set_current_state(TASK_RUNNING);
|
||||
remove_wait_queue(&list->hdev->debug_wait, &wait);
|
||||
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
/* pass the ringbuffer contents to userspace */
|
||||
copy_rest:
|
||||
if (list->tail == list->head)
|
||||
goto out;
|
||||
if (list->tail > list->head) {
|
||||
len = list->tail - list->head;
|
||||
if (len > count)
|
||||
len = count;
|
||||
|
||||
if (copy_to_user(buffer + ret, &list->hid_debug_buf[list->head], len)) {
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
ret += len;
|
||||
list->head += len;
|
||||
} else {
|
||||
len = HID_DEBUG_BUFSIZE - list->head;
|
||||
if (len > count)
|
||||
len = count;
|
||||
|
||||
if (copy_to_user(buffer, &list->hid_debug_buf[list->head], len)) {
|
||||
ret = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
list->head = 0;
|
||||
ret += len;
|
||||
count -= len;
|
||||
if (count > 0)
|
||||
goto copy_rest;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* pass the fifo content to userspace, locking is not needed with only
|
||||
* one concurrent reader and one concurrent writer
|
||||
*/
|
||||
ret = kfifo_to_user(&list->hid_debug_fifo, buffer, count, &copied);
|
||||
if (ret)
|
||||
goto out;
|
||||
ret = copied;
|
||||
out:
|
||||
mutex_unlock(&list->read_mutex);
|
||||
return ret;
|
||||
|
|
@ -1188,7 +1163,7 @@ static unsigned int hid_debug_events_poll(struct file *file, poll_table *wait)
|
|||
struct hid_debug_list *list = file->private_data;
|
||||
|
||||
poll_wait(file, &list->hdev->debug_wait, wait);
|
||||
if (list->head != list->tail)
|
||||
if (!kfifo_is_empty(&list->hid_debug_fifo))
|
||||
return POLLIN | POLLRDNORM;
|
||||
if (!list->hdev->debug)
|
||||
return POLLERR | POLLHUP;
|
||||
|
|
@ -1203,7 +1178,7 @@ static int hid_debug_events_release(struct inode *inode, struct file *file)
|
|||
spin_lock_irqsave(&list->hdev->debug_list_lock, flags);
|
||||
list_del(&list->node);
|
||||
spin_unlock_irqrestore(&list->hdev->debug_list_lock, flags);
|
||||
kfree(list->hid_debug_buf);
|
||||
kfifo_free(&list->hid_debug_fifo);
|
||||
kfree(list);
|
||||
|
||||
return 0;
|
||||
|
|
@ -1254,4 +1229,3 @@ void hid_debug_exit(void)
|
|||
{
|
||||
debugfs_remove_recursive(hid_debug_root);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -453,9 +453,8 @@ static int atlas_read_raw(struct iio_dev *indio_dev,
|
|||
case IIO_CHAN_INFO_SCALE:
|
||||
switch (chan->type) {
|
||||
case IIO_TEMP:
|
||||
*val = 1; /* 0.01 */
|
||||
*val2 = 100;
|
||||
break;
|
||||
*val = 10;
|
||||
return IIO_VAL_INT;
|
||||
case IIO_PH:
|
||||
*val = 1; /* 0.001 */
|
||||
*val2 = 1000;
|
||||
|
|
@ -486,7 +485,7 @@ static int atlas_write_raw(struct iio_dev *indio_dev,
|
|||
int val, int val2, long mask)
|
||||
{
|
||||
struct atlas_data *data = iio_priv(indio_dev);
|
||||
__be32 reg = cpu_to_be32(val);
|
||||
__be32 reg = cpu_to_be32(val / 10);
|
||||
|
||||
if (val2 != 0 || val < 0 || val > 20000)
|
||||
return -EINVAL;
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ static int vexpress_syscfg_exec(struct vexpress_syscfg_func *func,
|
|||
int tries;
|
||||
long timeout;
|
||||
|
||||
if (WARN_ON(index > func->num_templates))
|
||||
if (WARN_ON(index >= func->num_templates))
|
||||
return -EINVAL;
|
||||
|
||||
command = readl(syscfg->base + SYS_CFGCTRL);
|
||||
|
|
|
|||
|
|
@ -168,9 +168,10 @@ int gpmi_init(struct gpmi_nand_data *this)
|
|||
|
||||
/*
|
||||
* Reset BCH here, too. We got failures otherwise :(
|
||||
* See later BCH reset for explanation of MX23 handling
|
||||
* See later BCH reset for explanation of MX23 and MX28 handling
|
||||
*/
|
||||
ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MX23(this));
|
||||
ret = gpmi_reset_block(r->bch_regs,
|
||||
GPMI_IS_MX23(this) || GPMI_IS_MX28(this));
|
||||
if (ret)
|
||||
goto err_out;
|
||||
|
||||
|
|
@ -275,13 +276,11 @@ int bch_set_geometry(struct gpmi_nand_data *this)
|
|||
|
||||
/*
|
||||
* Due to erratum #2847 of the MX23, the BCH cannot be soft reset on this
|
||||
* chip, otherwise it will lock up. So we skip resetting BCH on the MX23.
|
||||
* On the other hand, the MX28 needs the reset, because one case has been
|
||||
* seen where the BCH produced ECC errors constantly after 10000
|
||||
* consecutive reboots. The latter case has not been seen on the MX23
|
||||
* yet, still we don't know if it could happen there as well.
|
||||
* chip, otherwise it will lock up. So we skip resetting BCH on the MX23
|
||||
* and MX28.
|
||||
*/
|
||||
ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MX23(this));
|
||||
ret = gpmi_reset_block(r->bch_regs,
|
||||
GPMI_IS_MX23(this) || GPMI_IS_MX28(this));
|
||||
if (ret)
|
||||
goto err_out;
|
||||
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ config CIFS_XATTR
|
|||
|
||||
config CIFS_POSIX
|
||||
bool "CIFS POSIX Extensions"
|
||||
depends on CIFS && CIFS_ALLOW_INSECURE_LEGACY && CIFS_XATTR
|
||||
depends on CIFS_XATTR
|
||||
help
|
||||
Enabling this option will cause the cifs client to attempt to
|
||||
negotiate a newer dialect with servers, such as Samba 3.0.5
|
||||
|
|
|
|||
|
|
@ -732,6 +732,13 @@ struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry,
|
|||
struct dentry *dentry = NULL, *trap;
|
||||
struct name_snapshot old_name;
|
||||
|
||||
if (IS_ERR(old_dir))
|
||||
return old_dir;
|
||||
if (IS_ERR(new_dir))
|
||||
return new_dir;
|
||||
if (IS_ERR_OR_NULL(old_dentry))
|
||||
return old_dentry;
|
||||
|
||||
trap = lock_rename(new_dir, old_dir);
|
||||
/* Source or destination directories don't exist? */
|
||||
if (d_really_is_negative(old_dir) || d_really_is_negative(new_dir))
|
||||
|
|
|
|||
|
|
@ -1472,8 +1472,10 @@ free_session_slots(struct nfsd4_session *ses)
|
|||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ses->se_fchannel.maxreqs; i++)
|
||||
for (i = 0; i < ses->se_fchannel.maxreqs; i++) {
|
||||
free_svc_cred(&ses->se_slots[i]->sl_cred);
|
||||
kfree(ses->se_slots[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -2344,14 +2346,18 @@ nfsd4_store_cache_entry(struct nfsd4_compoundres *resp)
|
|||
|
||||
dprintk("--> %s slot %p\n", __func__, slot);
|
||||
|
||||
slot->sl_flags |= NFSD4_SLOT_INITIALIZED;
|
||||
slot->sl_opcnt = resp->opcnt;
|
||||
slot->sl_status = resp->cstate.status;
|
||||
free_svc_cred(&slot->sl_cred);
|
||||
copy_cred(&slot->sl_cred, &resp->rqstp->rq_cred);
|
||||
|
||||
slot->sl_flags |= NFSD4_SLOT_INITIALIZED;
|
||||
if (nfsd4_not_cached(resp)) {
|
||||
slot->sl_datalen = 0;
|
||||
if (!nfsd4_cache_this(resp)) {
|
||||
slot->sl_flags &= ~NFSD4_SLOT_CACHED;
|
||||
return;
|
||||
}
|
||||
slot->sl_flags |= NFSD4_SLOT_CACHED;
|
||||
|
||||
base = resp->cstate.data_offset;
|
||||
slot->sl_datalen = buf->len - base;
|
||||
if (read_bytes_from_xdr_buf(buf, base, slot->sl_data, slot->sl_datalen))
|
||||
|
|
@ -2378,8 +2384,16 @@ nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args,
|
|||
op = &args->ops[resp->opcnt - 1];
|
||||
nfsd4_encode_operation(resp, op);
|
||||
|
||||
/* Return nfserr_retry_uncached_rep in next operation. */
|
||||
if (args->opcnt > 1 && !(slot->sl_flags & NFSD4_SLOT_CACHETHIS)) {
|
||||
if (slot->sl_flags & NFSD4_SLOT_CACHED)
|
||||
return op->status;
|
||||
if (args->opcnt == 1) {
|
||||
/*
|
||||
* The original operation wasn't a solo sequence--we
|
||||
* always cache those--so this retry must not match the
|
||||
* original:
|
||||
*/
|
||||
op->status = nfserr_seq_false_retry;
|
||||
} else {
|
||||
op = &args->ops[resp->opcnt++];
|
||||
op->status = nfserr_retry_uncached_rep;
|
||||
nfsd4_encode_operation(resp, op);
|
||||
|
|
@ -3039,6 +3053,34 @@ static bool nfsd4_request_too_big(struct svc_rqst *rqstp,
|
|||
return xb->len > session->se_fchannel.maxreq_sz;
|
||||
}
|
||||
|
||||
static bool replay_matches_cache(struct svc_rqst *rqstp,
|
||||
struct nfsd4_sequence *seq, struct nfsd4_slot *slot)
|
||||
{
|
||||
struct nfsd4_compoundargs *argp = rqstp->rq_argp;
|
||||
|
||||
if ((bool)(slot->sl_flags & NFSD4_SLOT_CACHETHIS) !=
|
||||
(bool)seq->cachethis)
|
||||
return false;
|
||||
/*
|
||||
* If there's an error than the reply can have fewer ops than
|
||||
* the call. But if we cached a reply with *more* ops than the
|
||||
* call you're sending us now, then this new call is clearly not
|
||||
* really a replay of the old one:
|
||||
*/
|
||||
if (slot->sl_opcnt < argp->opcnt)
|
||||
return false;
|
||||
/* This is the only check explicitly called by spec: */
|
||||
if (!same_creds(&rqstp->rq_cred, &slot->sl_cred))
|
||||
return false;
|
||||
/*
|
||||
* There may be more comparisons we could actually do, but the
|
||||
* spec doesn't require us to catch every case where the calls
|
||||
* don't match (that would require caching the call as well as
|
||||
* the reply), so we don't bother.
|
||||
*/
|
||||
return true;
|
||||
}
|
||||
|
||||
__be32
|
||||
nfsd4_sequence(struct svc_rqst *rqstp,
|
||||
struct nfsd4_compound_state *cstate,
|
||||
|
|
@ -3098,6 +3140,9 @@ nfsd4_sequence(struct svc_rqst *rqstp,
|
|||
status = nfserr_seq_misordered;
|
||||
if (!(slot->sl_flags & NFSD4_SLOT_INITIALIZED))
|
||||
goto out_put_session;
|
||||
status = nfserr_seq_false_retry;
|
||||
if (!replay_matches_cache(rqstp, seq, slot))
|
||||
goto out_put_session;
|
||||
cstate->slot = slot;
|
||||
cstate->session = session;
|
||||
cstate->clp = clp;
|
||||
|
|
|
|||
|
|
@ -169,11 +169,13 @@ static inline struct nfs4_delegation *delegstateid(struct nfs4_stid *s)
|
|||
struct nfsd4_slot {
|
||||
u32 sl_seqid;
|
||||
__be32 sl_status;
|
||||
struct svc_cred sl_cred;
|
||||
u32 sl_datalen;
|
||||
u16 sl_opcnt;
|
||||
#define NFSD4_SLOT_INUSE (1 << 0)
|
||||
#define NFSD4_SLOT_CACHETHIS (1 << 1)
|
||||
#define NFSD4_SLOT_INITIALIZED (1 << 2)
|
||||
#define NFSD4_SLOT_CACHED (1 << 3)
|
||||
u8 sl_flags;
|
||||
char sl_data[];
|
||||
};
|
||||
|
|
|
|||
|
|
@ -645,9 +645,18 @@ static inline bool nfsd4_is_solo_sequence(struct nfsd4_compoundres *resp)
|
|||
return resp->opcnt == 1 && args->ops[0].opnum == OP_SEQUENCE;
|
||||
}
|
||||
|
||||
static inline bool nfsd4_not_cached(struct nfsd4_compoundres *resp)
|
||||
/*
|
||||
* The session reply cache only needs to cache replies that the client
|
||||
* actually asked us to. But it's almost free for us to cache compounds
|
||||
* consisting of only a SEQUENCE op, so we may as well cache those too.
|
||||
* Also, the protocol doesn't give us a convenient response in the case
|
||||
* of a replay of a solo SEQUENCE op that wasn't cached
|
||||
* (RETRY_UNCACHED_REP can only be returned in the second op of a
|
||||
* compound).
|
||||
*/
|
||||
static inline bool nfsd4_cache_this(struct nfsd4_compoundres *resp)
|
||||
{
|
||||
return !(resp->cstate.slot->sl_flags & NFSD4_SLOT_CACHETHIS)
|
||||
return (resp->cstate.slot->sl_flags & NFSD4_SLOT_CACHETHIS)
|
||||
|| nfsd4_is_solo_sequence(resp);
|
||||
}
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue