* Re: [PATCH 03/10] mm: Add support for a filesystem to control swap files
From: Christoph Hellwig @ 2011-09-09 13:36 UTC (permalink / raw)
To: Mel Gorman
Cc: Christoph Hellwig, Linux-MM, Linux-Netdev, Linux-NFS, LKML,
Andrew Morton, David Miller, Trond Myklebust, Neil Brown,
Peter Zijlstra
In-Reply-To: <20110909131550.GV14369@suse.de>
On Fri, Sep 09, 2011 at 02:15:50PM +0100, Mel Gorman wrote:
>
> I confess I haven't investigated this direction at
> all yet. Is it correct that your previous objection was
> http://linux.derkeiler.com/Mailing-Lists/Kernel/2009-10/msg00455.html
> and the direct-IO patchset you were thinking of was
> http://copilotco.com/mail-archives/linux-kernel.2009/msg87176.html ?
Yes.
> If so, are you suggesting that instead of swap_readpage and
> swap_writepage I look into what is required for swap to use ->readpage
> method and ->direct_IO aops?
The equivalent of ->direct_IO should be used for both reads and writes.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [PATCH 2/2] GRETH: avoid overwrite IP-stack's IP-frags checksum
From: Eric Dumazet @ 2011-09-09 13:29 UTC (permalink / raw)
To: Daniel Hellstrom; +Cc: davem, netdev, kristoffer
In-Reply-To: <1315487676-16733-2-git-send-email-daniel@gaisler.com>
Le jeudi 08 septembre 2011 à 15:14 +0200, Daniel Hellstrom a écrit :
> The GRETH GBIT core does not do checksum offloading for IP
> segmentation. This patch adds a check in the xmit function to
> determine if the stack has calculated the checksum for us.
>
> Signed-off-by: Daniel Hellstrom <daniel@gaisler.com>
> ---
> drivers/net/greth.c | 7 +++++--
> 1 files changed, 5 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/greth.c b/drivers/net/greth.c
> index 9d39fb9..27ba855 100644
> --- a/drivers/net/greth.c
> +++ b/drivers/net/greth.c
> @@ -489,7 +489,8 @@ greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev)
> if (nr_frags != 0)
> status = GRETH_TXBD_MORE;
>
> - status |= GRETH_TXBD_CSALL;
> + if (skb->ip_summed == CHECKSUM_PARTIAL)
> + status |= GRETH_TXBD_CSALL;
> status |= skb_headlen(skb) & GRETH_BD_LEN;
> if (greth->tx_next == GRETH_TXBD_NUM_MASK)
> status |= GRETH_BD_WR;
> @@ -512,7 +513,9 @@ greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev)
> greth->tx_skbuff[curr_tx] = NULL;
> bdp = greth->tx_bd_base + curr_tx;
>
> - status = GRETH_TXBD_CSALL | GRETH_BD_EN;
> + status = GRETH_BD_EN;
> + if (skb->ip_summed == CHECKSUM_PARTIAL)
> + status | GRETH_TXBD_CSALL;
typo here ?
> status |= frag->size & GRETH_BD_LEN;
>
> /* Wrap around descriptor ring */
^ permalink raw reply
* Octeon crash in virt_to_page(&core0_stack_variable)
From: Cosmin Ratiu @ 2011-09-09 13:23 UTC (permalink / raw)
To: linux-mips; +Cc: netdev
[-- Attachment #1: Type: text/plain, Size: 1649 bytes --]
Hello,
I've been investigating a strange crash and I wanted to ask for your help.
The crash happens when virt_to_page is called with an address from the softirq
stack of core 0 on Cavium Octeon. It may happen on other MIPS processors as
well, but I'm not sure.
I've attached a simple kernel module to demonstrate the problem and the output
of dmesg + the crash. Two seconds after inserting the module, the kernel
should crash.
From what I've dug up in the kernel sources, it seems the stack for the first
idle task resides in the data segment (mapped in kseg2) while the rest are
allocated with kmalloc in __cpu_up() and reside in a different area (CAC_BASE
upwards).
It seems virt_to_phys produces bogus results for kseg2 and after that,
virt_to_page crashes trying to access invalid memory.
This problem was discovered when doing BGP traffic with the TCP MD5 option
activated, where the following call chain caused a crash:
* tcp_v4_rcv
* tcp_v4_timewait_ack
* tcp_v4_send_ack -> follow stack variable rep.th
* tcp_v4_md5_hash_hdr
* tcp_md5_hash_header
* sg_init_one
* sg_set_buf
* virt_to_page
I noticed that tcp_v4_send_reset uses a similar stack variable and also calls
tcp_v4_md5_hash_hdr, so it has the same problem.
I don't fully understand octeon mm details, so I wanted to bring up this issue
in order to find a proper fix.
To avoid the problem, I've implemented a quick hack to declare those variables
percpu instead of on the stack, so they would also reside in CAC_BASE upwards.
I've attached a patch against 2.6.32 for reference.
Cosmin.
[-- Attachment #2: dmesg.log --]
[-- Type: text/x-log, Size: 20013 bytes --]
[ 0.000/0] Linux version 2.6.32 (IxOS linux_2.6.32/main/6.20.0.298) (ixsdk@ixca-cm-vmbld72) (gcc version 4.3.3 (Cavium Networks Version: 2_0_0 build 95) ) #1 SMP Wed Aug 24 09:26:59 PDT 2011
[ 0.000/0] boot_desc_ptr 800000000fde4300 bootinfo 800000000fde5c00 phy_mem_desc_addr 24108
[ 0.000/0] Ixia kernel instance 0, cores_per_instance 12, port_type 161
[ 0.000/0] CVMSEG size: 2 cache lines (256 bytes)
[ 0.000/0] ixia_uart: configured at 800000000ffa9000
[ 0.000/0] bootconsole [early0] enabled
[ 0.000/0] CPU revision is: 000d0409 (Cavium Octeon+)
[ 0.000/0] Checking for the multiply/shift bug... no.
[ 0.000/0] Checking for the daddiu bug... no.
[ 0.000/0] Found named block linmem0.0 @ 0x3000000, size= 0xb000000
[ 0.000/0] Found named block linmem0.1 @ 0x410000000, size= 0x10000000
[ 0.000/0] Found named block linmem0.2 @ 0x20000000, size= 0x20000000
[ 0.000/0] Found named block linmem0.3 @ 0x40000000, size= 0xc0000000
[ 0.000/0] Scan_named_regions complete
[ 0.000/0] Determined physical RAM map:
[ 0.000/0] memory: 00000000008dd000 @ 00000000013f3000 (usable after init)
[ 0.000/0] memory: 000000000b000000 @ 0000000003000000 (usable)
[ 0.000/0] memory: 0000000010000000 @ 0000000410000000 (usable)
[ 0.000/0] memory: 00000000e0000000 @ 0000000020000000 (usable)
[ 0.000/0] Wasting 285992 bytes for tracking 5107 unused pages
[ 0.000/0] Initrd not found or empty - disabling initrd
[ 0.000/0] Zone PFN ranges:
[ 0.000/0] Normal 0x000013f3 -> 0x00420000
[ 0.000/0] Movable zone start PFN for each node
[ 0.000/0] early_node_map[4] active PFN ranges
[ 0.000/0] 0: 0x000013f3 -> 0x00001cd0
[ 0.000/0] 0: 0x00003000 -> 0x0000e000
[ 0.000/0] 0: 0x00020000 -> 0x00100000
[ 0.000/0] 0: 0x00410000 -> 0x00420000
[ 0.000/0] On node 0 totalpages: 1030365
[ 0.000/0] Normal zone: 59067 pages used for memmap
[ 0.000/0] Normal zone: 0 pages reserved
[ 0.000/0] Normal zone: 971298 pages, LIFO batch:31
[ 0.000/0] Failed to allocate memory for Hotplug memory block
[ 0.000/0] PERCPU: Embedded 10 pages/cpu @a8000000068a0000 s10624 r8192 d22144 u65536
[ 0.000/0] pcpu-alloc: s10624 r8192 d22144 u65536 alloc=16*4096
[ 0.000/0] pcpu-alloc: [0] 00 [0] 01 [0] 02 [0] 03 [0] 04 [0] 05 [0] 06 [0] 07
[ 0.000/0] pcpu-alloc: [0] 08 [0] 09 [0] 10 [0] 11
[ 0.000/0] Built 1 zonelists in Zone order, mobility grouping on. Total pages: 971298
[ 0.000/0] Kernel command line: console=ttyS0,115200
[ 0.000/0] PID hash table entries: 4096 (order: 3, 32768 bytes)
[ 0.000/0] Dentry cache hash table entries: 524288 (order: 10, 4194304 bytes)
[ 0.000/0] Inode-cache hash table entries: 262144 (order: 9, 2097152 bytes)
[ 0.000/0] Primary instruction cache 32kB, virtually tagged, 4 way, 64 sets, linesize 128 bytes.
[ 0.000/0] Primary data cache 16kB, 64-way, 2 sets, linesize 128 bytes.
[ 0.000/0] Memory: 4047476k/4121460k available (2975k kernel code, 73196k reserved, 1067k data, 9076k init, 0k highmem)
[ 0.000/0] Hierarchical RCU implementation.
[ 0.000/0] NR_IRQS:408
[ 0.000/0] console [ttyS0] enabled, bootconsole disabled
[ 1951.025/0] Calibrating delay loop (skipped) preset value.. 1200.00 BogoMIPS (lpj=600000)
[ 1951.026/0] Mount-cache hash table entries: 256
[ 1951.026/0] Checking for the daddi bug... no.
[ 1951.027/0] SMP: Booting CPU01 (CoreId 1)...
[ 1951.027/1] CPU revision is: 000d0409 (Cavium Octeon+)
[ 1951.027/0] SMP: Booting CPU02 (CoreId 2)...
[ 1951.027/2] CPU revision is: 000d0409 (Cavium Octeon+)
[ 1951.028/0] SMP: Booting CPU03 (CoreId 3)...
[ 1951.028/3] CPU revision is: 000d0409 (Cavium Octeon+)
[ 1951.028/0] SMP: Booting CPU04 (CoreId 4)...
[ 1951.028/4] CPU revision is: 000d0409 (Cavium Octeon+)
[ 1951.029/0] SMP: Booting CPU05 (CoreId 5)...
[ 1951.029/5] CPU revision is: 000d0409 (Cavium Octeon+)
[ 1951.030/0] SMP: Booting CPU06 (CoreId 6)...
[ 1951.030/6] CPU revision is: 000d0409 (Cavium Octeon+)
[ 1951.030/0] SMP: Booting CPU07 (CoreId 7)...
[ 1951.030/7] CPU revision is: 000d0409 (Cavium Octeon+)
[ 1951.031/0] SMP: Booting CPU08 (CoreId 8)...
[ 1951.031/8] CPU revision is: 000d0409 (Cavium Octeon+)
[ 1951.031/0] SMP: Booting CPU09 (CoreId 9)...
[ 1951.031/9] CPU revision is: 000d0409 (Cavium Octeon+)
[ 1951.032/0] SMP: Booting CPU10 (CoreId 10)...
[ 1951.032/a] CPU revision is: 000d0409 (Cavium Octeon+)
[ 1951.033/0] SMP: Booting CPU11 (CoreId 11)...
[ 1951.033/b] CPU revision is: 000d0409 (Cavium Octeon+)
[ 1951.033/0] Brought up 12 CPUs
[ 1951.033/0] CPU0 attaching sched-domain:
[ 1951.033/0] domain 0: span 0-11 level CPU
[ 1951.033/0] groups: 0 1 2 3 4 5 6 7 8 9 10 11
[ 1951.033/0] CPU1 attaching sched-domain:
[ 1951.033/0] domain 0: span 0-11 level CPU
[ 1951.033/0] groups: 1 2 3 4 5 6 7 8 9 10 11 0
[ 1951.033/0] CPU2 attaching sched-domain:
[ 1951.033/0] domain 0: span 0-11 level CPU
[ 1951.033/0] groups: 2 3 4 5 6 7 8 9 10 11 0 1
[ 1951.033/0] CPU3 attaching sched-domain:
[ 1951.033/0] domain 0: span 0-11 level CPU
[ 1951.033/0] groups: 3 4 5 6 7 8 9 10 11 0 1 2
[ 1951.033/0] CPU4 attaching sched-domain:
[ 1951.033/0] domain 0: span 0-11 level CPU
[ 1951.033/0] groups: 4 5 6 7 8 9 10 11 0 1 2 3
[ 1951.033/0] CPU5 attaching sched-domain:
[ 1951.033/0] domain 0: span 0-11 level CPU
[ 1951.033/0] groups: 5 6 7 8 9 10 11 0 1 2 3 4
[ 1951.033/0] CPU6 attaching sched-domain:
[ 1951.033/0] domain 0: span 0-11 level CPU
[ 1951.033/0] groups: 6 7 8 9 10 11 0 1 2 3 4 5
[ 1951.033/0] CPU7 attaching sched-domain:
[ 1951.033/0] domain 0: span 0-11 level CPU
[ 1951.033/0] groups: 7 8 9 10 11 0 1 2 3 4 5 6
[ 1951.034/0] CPU8 attaching sched-domain:
[ 1951.034/0] domain 0: span 0-11 level CPU
[ 1951.034/0] groups: 8 9 10 11 0 1 2 3 4 5 6 7
[ 1951.034/0] CPU9 attaching sched-domain:
[ 1951.034/0] domain 0: span 0-11 level CPU
[ 1951.034/0] groups: 9 10 11 0 1 2 3 4 5 6 7 8
[ 1951.034/0] CPU10 attaching sched-domain:
[ 1951.034/0] domain 0: span 0-11 level CPU
[ 1951.034/0] groups: 10 11 0 1 2 3 4 5 6 7 8 9
[ 1951.034/0] CPU11 attaching sched-domain:
[ 1951.034/0] domain 0: span 0-11 level CPU
[ 1951.034/0] groups: 11 0 1 2 3 4 5 6 7 8 9 10
[ 1951.039/0] NET: Registered protocol family 16
[ 1951.039/0] bio: create slab <bio-0> at 0
[ 1951.041/0] SCSI subsystem initialized
[ 1951.041/0] Switching to clocksource OCTEON_CVMCOUNT
[ 1951.043/8] [multinic] Initializing ...
[ 1951.043/8] NET: Registered protocol family 2
[ 1951.044/8] IP route cache hash table entries: 131072 (order: 8, 1048576 bytes)
[ 1951.045/8] TCP established hash table entries: 262144 (order: 10, 4194304 bytes)
[ 1951.051/8] TCP bind hash table entries: 65536 (order: 8, 1048576 bytes)
[ 1951.052/8] TCP portaddr_bind hash table entries: 65536 (order: 8, 1048576 bytes)
[ 1951.053/8] TCP listening hash table entries: 65536 (order: 8, 1048576 bytes)
[ 1951.055/8] TCP: Hash tables configured (established 262144 bind 65536 listening 65536)
[ 1951.055/8] TCP reno registered
[ 1951.056/8] NET: Registered protocol family 1
[ 1951.057/8] RPC: Registered udp transport module.
[ 1951.057/8] RPC: Registered tcp transport module.
[ 1951.058/8] RPC: Registered tcp NFSv4.1 backchannel transport module.
[ 1952.710/8] /proc/octeon_perf: Octeon performace counter interface loaded
[ 1952.713/8] msgmni has been set to 7906
[ 1952.715/1] alg: No test for stdrng (krng)
[ 1952.715/8] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 254)
[ 1952.715/8] io scheduler noop registered
[ 1952.715/8] io scheduler anticipatory registered
[ 1952.715/8] io scheduler deadline registered
[ 1952.716/8] io scheduler cfq registered (default)
[ 1952.720/8] Ixia Backplane UART version 0.01
[ 1952.720/8] Fixed MDIO Bus: probed
[ 1952.720/8] oprofile: using mips/octeon performance monitoring.
[ 1952.720/8] NET: Registered protocol family 26
[ 1952.722/8] [ixroute] Initialized.
[ 1952.722/8] TCP cubic registered
[ 1952.723/8] NET: Registered protocol family 10
[ 1952.742/8] [ixroute6] Initialized.
[ 1952.742/8] IPv6 over IPv4 tunneling driver
[ 1952.742/8] NET: Registered protocol family 17
[ 1952.743/8] L2 lock: TLB refill 256 bytes
[ 1952.743/8] L2 lock: General exception 128 bytes
[ 1952.743/8] L2 lock: low-level interrupt 128 bytes
[ 1952.743/8] L2 lock: interrupt 640 bytes
[ 1952.743/8] L2 lock: memcpy 1152 bytes
[ 1952.749/8] Freeing unused kernel memory: 9076k freed
[ 1953.050/8] ixsysctl: module license 'Copyright 2002, Ixia Communications; all rights reserved' taints kernel.
[ 1953.050/8] Disabling lock debugging due to kernel taint
[ 1953.051/8] ixsysctl: ixsysctl_init: Ixia System Control Utility Module Aug 25 2011 19:38:20
[ 1953.090/a] ixllm: init_module: Ixia Link Layer Manager Aug 25 2011 19:37:57
[ 1953.126/7] pcie: TX FPGA Version 0x1107
[ 1953.126/7] pcie: RX FPGA Version 0x10e5
[ 1953.132/8] octeon_msi_irq_dispatcher_init, kernel instance 0
[ 1953.132/8] ixia_irq_msi_dispatcher_init
[ 1953.195/2] cavium-ethernet: Cavium Networks Octeon SDK version 2.0.0-p4, build 373
[ 1953.195/2] Driver compiled with: USE_NAMEDBLOCK_FOR_FPA
[ 1953.195/2] cavium-ethernet: Using dev: ixint0 as Ixia root dev
[ 1953.195/2] everest_hw_init: kernel instance 0, cores_per_os: 12
[ 1953.195/2] octeon_ethernet.ko: Enable TX 1588
[ 1953.195/2] octeon_ethernet.ko: Enable RX 1588
[ 1953.196/2] nb name: ixia-platform-control-block size: 0x10000 addr: 0xfe15000
[ 1953.196/2] >> Core 2 coremask: fff
[ 1953.196/2] cvm_eth_instance_count_add Instance count: 1
[ 1953.196/2] >> Instance 0 mac_offset: 1 fau_offset: 2044 group: 0
[ 1953.196/2] Reclaimed 0 WQE and 0 FPA entries from POW
[ 1953.196/2] fpa 0: que-available: 1fb0
[ 1953.196/2] fpa 1: que-available: 1fc0
[ 1953.196/2] fpa 2: que-available: 53
[ 1953.196/2] cvm_oct_configure_common_hw: group 0
[ 1953.196/2] cvm_eth_get_interfaces_of_interest Adding interface 0 of type 5
[ 1953.196/2] Interface 0 has 1 ports (XAUI)
[ 1953.196/2] Interface 1 has 1 ports (XAUI)
[ 1953.196/2] cvmx_helper_interface_probe_mi: Not probing Interface type 8
[ 1953.196/2] cvmx_helper_interface_probe_mi: Not probing Interface type 9
[ 1953.196/2] Checking port 0, max_port: 0 num_ports: 1
[ 1953.196/2] ixia_probe_hw
[ 1953.196/2] Bringing up device ixint0 (i/f: 0 port: 0)
[ 1953.196/2] priv->tx_port 0 priv->tx_queue 0
[ 1953.196/2] cvm_oct_init_module dev->mtu: 14000
[ 1953.196/2] cvm_oct_rx_initialize: max_rx_cpus=12
[ 1953.196/2] IRQ request for 24 succeeded
[ 1953.196/2] MSI Enable for msi_num 4 is location 0x80011f000000bc50 value 0x10
[ 1953.282/3] Basic DMA tests passed
[ 1953.301/4] IXHOST mcb->dwBootRamBase = 0x800000000ffe9000
[ 1953.301/4] CPU Frequency: 600 MHz
[ 1953.302/4] ADVERTISED FLAG = 0x0000000000008f8f
[ 1953.302/4] dma_xmit_open: dma_idx: 0, tx_fifo_base: 0x8000c00000000000
[ 1953.302/4] MSI Enable for msi_num 0 is location 0x80011f000000bc50 value 0x11
[ 1953.302/4] CIU_INT0_EN0 = 0x10300000001
[ 1953.302/4] ixhostm: MessageQueueInit success
[ 1953.302/4] Virtual queue base = 0x800000000fb20000
[ 1953.302/4] Base physical = 0xfb20000
[ 1953.302/4] OS instance = 0
[ 1953.302/4] Virtual chassis card map base = 0x800000000fbb0000
[ 1953.302/4] Virtual P2P rx_que_base = 0x800000000fb20000
[ 1953.302/4] [2 s. 276082 us] p2p_message_queue_init success
[ 1953.302/4] IXHOST ver 3.0.0
[ 1953.322/7] hwstate: timestamp test passed
[ 1953.617/2] [multinic] operation: +
[ 1953.617/2] [multinic] device: ixint0
[ 1953.617/2] [multinic] id: 0
[ 1996.813/0] [1315571465 s. 798972 us] Refreshing topology Chassis X2 ...
[ 1996.813/0] ---- Slot= 1 PortType=161 PortMap=0x0000ffff
[ 1996.814/0] ---- Slot= 2 PortType= 83 PortMap=0x000000ff
[ 2038.300/0] vcrash initializing
[ 2040.299/8] core 8: &x a80000041f98fbd0 virt_to_phys(&x) 41f98fbd0
[ 2040.299/b] core 11: &x a80000041fa0bbd0 virt_to_phys(&x) 41fa0bbd0
[ 2040.299/a] core 10: &x a80000041f9cbbd0 virt_to_phys(&x) 41f9cbbd0
[ 2040.299/1] core 1: &x a80000041f87bbd0 virt_to_phys(&x) 41f87bbd0
[ 2040.299/2] core 2: &x a80000041f8bbbd0 virt_to_phys(&x) 41f8bbbd0
[ 2040.299/3] core 3: &x a80000041f8d7bd0 virt_to_phys(&x) 41f8d7bd0
[ 2040.299/5] core 5: &x a80000041f917bd0 virt_to_phys(&x) 41f917bd0
[ 2040.299/4] core 4: &x a80000041f8f7bd0 virt_to_phys(&x) 41f8f7bd0
[ 2040.299/0] core 0: &x ffffffffc03a3b70 virt_to_phys(&x) 57ffffffc03a3b70
[ 2040.299/b] core 11: virt_to_page(&x) a800000006870268
[ 2040.299/6] core 6: &x a80000041f953bd0 virt_to_phys(&x) 41f953bd0
[ 2040.299/9] core 9: &x a80000041f9afbd0 virt_to_phys(&x) 41f9afbd0
[ 2040.299/7] core 7: &x a80000041f96fbd0 virt_to_phys(&x) 41f96fbd0
[ 2040.299/a] core 10: virt_to_page(&x) a80000000686f468
[ 2040.299/1] core 1: virt_to_page(&x) a80000000686aae8
[ 2040.299/2] core 2: virt_to_page(&x) a80000000686b8e8
[ 2040.299/3] core 3: virt_to_page(&x) a80000000686bf08
[ 2040.299/5] core 5: virt_to_page(&x) a80000000686cd08
[ 2040.299/4] core 4: virt_to_page(&x) a80000000686c608
[ 2040.299/0] CPU 0 Unable to handle kernel paging request at virtual address 00000057c0d14640, epc == ffffffffc123a054, ra == ffffffffc123a030
[ 2040.299/6] core 6: virt_to_page(&x) a80000000686da28
[ 2040.299/9] core 9: virt_to_page(&x) a80000000686ee48
[ 2040.299/7] core 7: virt_to_page(&x) a80000000686e048
[ 2040.299/0] die: oom_log() temporarily disabled on this architecture
[ 2040.299/0] Oops[#1]:
[ 2040.299/0] Cpu 0
[ 2040.299/0] $ 0 : 0000000000000000 0000000000000000 00000057c0d14640 00000057ffffffc0
[ 2040.299/0] $ 4 : ffffffffc1240000 ffffffffc0ce0000 0000000000000000 0000000000020000
[ 2040.299/0] $ 8 : ffffffffc0ce0000 ffffffffffffffff fffffffffffffffb 0000000000000010
[ 2040.299/0] $12 : 0000000000000020 00000000000186a0 0000000000000009 0000000000000000
[ 2040.300/0] $16 : 0133ffffff20cba8 0000000000000100 ffffffffc123a000 ffffffffc0d0a220
[ 2040.300/0] $20 : ffffffffc0d09e20 ffffffffc0d09a20 ffffffffc0d09620 0000000000200200
[ 2040.300/0] $24 : 0000000000000002 ffffffffc000baa4
[ 2040.300/0] $28 : ffffffffc03a0000 ffffffffc03a3b70 ffffffffc03a0000 ffffffffc123a030
[ 2040.300/0] Hi : 00000000000b6854
[ 2040.300/0] Lo : 000000000000012b
[ 2040.300/0] epc : ffffffffc123a054 vcrash+0x54/0x80 [vcrash]
[ 2040.300/0] Tainted: P
[ 2040.300/0] ra : ffffffffc123a030 vcrash+0x30/0x80 [vcrash]
[ 2040.300/0] Status: 1000cce3 KX SX UX KERNEL EXL IE
[ 2040.300/0] Cause : 00800008
[ 2040.300/0] BadVA : 00000057c0d14640
[ 2040.300/0] PrId : 000d0409 (Cavium Octeon+)
[ 2040.300/0] Modules linked in: vcrash ixvaluelist(P) ixgremod(P) ixunc(P) kseusrmgr(P) evfmanager(P) filtermanager hwstate ixhostm octeon_dma octeon_ethernet octeon_mdiobus ixnam_binstats(P) octeon_msi pcie ixllm ixsysctl(P) nlproc_driver
[ 2040.300/0] Process swapper (pid: 0, threadinfo=ffffffffc03a0000, task=ffffffffc03be580, tls=0000000000000000)
[ 2040.300/0] Stack : ffffffffc03a0000 ffffffffc03a4788 ffffffffc0d08600 ffffffffc0065f28
[ 2040.300/0] ffffffffc03a3b90 ffffffffc03a3b90 0000000000000100 0000000000000001
[ 2040.300/0] ffffffffc03a4788 0000000000000101 0000000000000008 ffffffffc0cc31b0
[ 2040.300/0] 000000000000000a 0000000000000000 ffffffffc0d07b80 ffffffffc00609e0
[ 2040.300/0] 0000000000000000 8001070000000000 8001070000000218 8001070000000200
[ 2040.300/0] 8001070000000108 ffffffffc0ce0000 0000000000010000 000000000fde4300
[ 2040.300/0] ffffffffc03a0000 ffffffffc0060adc 0000000000000000 ffffffffc0060cb0
[ 2040.300/0] 0000000000000000 ffffffffc000ba7c a8000000068a0058 0000000000000000
[ 2040.300/0] 0000000000000001 ffffffffc0ce0000 ffffffffc0ce0000 000000000fdd0000
[ 2040.300/0] 0000000000000000 ffffffffc0000888 0000000000000000 0000000000000000
[ 2040.300/0] ...
[ 2040.300/0] Call Trace:
[ 2040.300/0] [<ffffffffc123a054>] vcrash+0x54/0x80 [vcrash]
[ 2040.300/0] [<ffffffffc0065f28>] run_timer_softirq+0x198/0x23c
[ 2040.300/0] [<ffffffffc00609e0>] __do_softirq+0xd8/0x188
[ 2040.300/0] [<ffffffffc0060adc>] do_softirq+0x4c/0x6c
[ 2040.300/0] [<ffffffffc0060cb0>] irq_exit+0x48/0x8c
[ 2040.300/0] [<ffffffffc000ba7c>] plat_irq_dispatch+0x128/0x150
[ 2040.300/0] [<ffffffffc0000888>] ret_from_irq+0x0/0x4
[ 2040.300/0] [<ffffffffc0000a80>] r4k_wait+0x20/0x40
[ 2040.300/0] [<ffffffffc0033fe0>] cpu_idle+0x60/0x9c
[ 2040.300/0] [<ffffffffc03f3a9c>] start_kernel+0x3e8/0x404
[ 2040.300/0]
[ 2040.300/0]
[ 2040.300/0] Code: 64424680 0043102d 3c04c124 <dc460000> 2402fffc 8f850020 6484a2d8 00c23024 0c001c23
[ 2040.300/0] Kernel panic - not syncing: Fatal exception in interrupt
[ 2040.300/0] Call Trace:
[ 2040.300/0] [<ffffffffc0006ef8>] dump_stack+0x8/0x34
[ 2040.300/0] [<ffffffffc0006fa0>] panic+0x7c/0x168
[ 2040.300/0] [<ffffffffc0036bd8>] die+0x114/0x11c
[ 2040.300/0] [<ffffffffc0041468>] do_page_fault+0x314/0x39c
[ 2040.300/0] [<ffffffffc0000880>] ret_from_exception+0x0/0x8
[ 2040.300/0] [<ffffffffc123a054>] vcrash+0x54/0x80 [vcrash]
[ 2040.300/0] [<ffffffffc0065f28>] run_timer_softirq+0x198/0x23c
[ 2040.300/0] [<ffffffffc00609e0>] __do_softirq+0xd8/0x188
[ 2040.300/0] [<ffffffffc0060adc>] do_softirq+0x4c/0x6c
[ 2040.300/0] [<ffffffffc0060cb0>] irq_exit+0x48/0x8c
[ 2040.300/0] [<ffffffffc000ba7c>] plat_irq_dispatch+0x128/0x150
[ 2040.300/0] [<ffffffffc0000888>] ret_from_irq+0x0/0x4
[ 2040.300/0] [<ffffffffc0000a80>] r4k_wait+0x20/0x40
[ 2040.300/0] [<ffffffffc0033fe0>] cpu_idle+0x60/0x9c
[ 2040.300/0] [<ffffffffc03f3a9c>] start_kernel+0x3e8/0x404
[ 2040.300/0]
[ 2040.300/0] ixhost: ENABLE Tx message checksum
[ 2040.300/0] ixhost: DISABLE Rx message checksum
[ 2040.300/0] ixhost: ENABLE SGC Communication mode
[ 2040.300/0] ixhost: ENABLE Lcpu Interrupt Host
[ 2040.300/0] ixhost: ENABLE Host Interrupt Lcpu
[ 2040.300/0] ixhost: ENABLE 32-bit Pointer mode
[ 2040.300/0] ixhost: Advertised BCAST=0x0000
[ 2040.300/0] TxFrameCount= 1097 TxByteCount= 129484
[ 2040.300/0] H/W TxFifoBase=0xa80000041e4dc000 TxFifoEnd=0xa80000041e4dfff0 TxFifoSize=0x3ff0
[ 2040.300/0] RRN=0xa80000041e4dfff0 RRB=0xa80000041e4dfff8 TW=0xa80000041e4dfff4
[ 2040.301/0]
[ 2040.301/0] H/W RxFifoBase=0x800000000ff29000 RxFifoEnd=0x800000000ff38ff8 RxFifoSize=0xfff8
[ 2040.301/0] RW=0x800000000ff38ff8 TR=0x800000000ff38ffc
[ 2040.301/0] RxWrite=0x800000000ff38ff8 RxRead=0xa80000041e4dfff0 TxWrite=0xa80000041e4dfff4 TxRead=0x800000000ff38ffc
[ 2040.301/0] ImagTransmitBase=0xa80000041e4dc000 WritePos=0x3a3c ReadPos=0x3a3c00000000 PrevWrite=0xa80000041e4dfa00
[ 2040.301/0] Receive[normal]
[ 2040.301/0] WritePtr : 0x800096ac0ff2ca3c
[ 2040.301/0] ReadPtr : 0x800000000ff326ac
[ 2040.301/0] Advertised Read Ptr : 0x000096ac
[ 2040.301/0] PrevRead : 0x800000000ff32674
[ 2040.301/0] Receive[broadcast]
[ 2040.301/0] WritePtr : 0x800000000ff39000
[ 2040.301/0] ReadPtr : 0x800000000ff39000
[ 2040.301/0] Advertised Read Ptr : 0x00000000
[ 2040.301/0] PrevRead : 0x800000000ff39000
[ 2040.301/0] Octeon board_info
[ 2040.301/0] ----- head=19 tail=16 buffer:
[ 2040.301/0] pData = 0xa8000000018ca800 len = 64
[ 2040.301/0] (0xa8000000018ca800) 0x0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[ 2040.301/0] (0xa8000000018ca810) 0x0010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[ 2040.301/0] (0xa8000000018ca820) 0x0020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[ 2040.301/0] (0xa8000000018ca830) 0x0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
[ 2040.301/0]
[ 2040.301/0] p2h_fifo_len: 0000 p2p_fifo_len: 0000
[ 2040.301/0] p2h_count: 25524, p2p_count: 0
[ 2040.301/0] fpa 0: que-available: 1fb0
[ 2040.301/0] fpa 1: que-available: 1fc0
[ 2040.301/0] fpa 2: que-available: 53
[ 2040.301/0] ixhost::panic_handler: setting kProcessorHalted bit
[ 2040.301/0] ixhost::panic_handler: done
[ 2041.634/0] Reclaimed 0 WQE and 0 FPA entries from POW
[-- Attachment #3: vcrash.c --]
[-- Type: text/x-csrc, Size: 1001 bytes --]
/*
* A module that should crash the kernel on mips master core by using virt_to_page on a
* softirq stack address.
*
* Cosmin Ratiu <cratiu@ixiacom.com>
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/cpu.h>
#include <linux/timer.h>
#include <linux/mm.h>
struct timer_list t[NR_CPUS];
void vcrash(unsigned long data)
{
int x;
printk("core %i: &x %p virt_to_phys(&x) %lx\n", smp_processor_id(), &x, virt_to_phys(&x));
printk("core %i: virt_to_page(&x) %p\n", smp_processor_id(), virt_to_page(&x));
}
int vcrash_init(void)
{
int cpu;
printk("vcrash initializing\n");
for_each_online_cpu(cpu) {
init_timer(t + cpu);
t[cpu].expires = jiffies + 2 * HZ;
t[cpu].function = vcrash;
add_timer_on(t + cpu, cpu);
}
return 0;
}
void vcrash_exit(void)
{
int cpu;
for_each_online_cpu(cpu) {
del_timer_sync(t + cpu);
}
printk("vcrash exiting\n");
}
module_init(vcrash_init);
module_exit(vcrash_exit);
MODULE_AUTHOR("Cosmin Ratiu");
MODULE_LICENSE("GPL");
[-- Attachment #4: tcp-md5-crash.diff --]
[-- Type: text/x-patch, Size: 4762 bytes --]
Change 3360379 by cratiu@cratiu on 2011/09/02 09:44:48 *pending*
TCP/md5: Switch from a stack var to a percpu var to avoid a crash.
tcp_v4_send_ack uses a stack variable to construct the TCP header for
the response packet.
When using TCP MD5 signatures on mips architecture a crash happens
sometimes when the current core is the master core using the initial
stack allocated in vmlinux.
The reason for this is that the initial stack is mapped in kseg2
so it can't be directly translated to a physical address by
virt_to_phys as expected by sg_set_buf from the following call chain:
> (optimized: sg_set_buf)
> sg_init_one+0x58/0xa4
> tcp_md5_hash_header+0x30/0x64
> tcp_v4_md5_hash_hdr+0xb4/0x134
> tcp_v4_send_ack+0x16c/0x25c
> (optimized: tcp_v4_timewait_ack)
> tcp_v4_rcv+0x1b3c/0x1e58
As a temporary fix that should not affect performance, the stack
variable is converted in a percpu variable allocated at boot time.
Affected files ...
... //packages/linux_2.6.32/main/src/include/net/tcp.h#6 edit
... //packages/linux_2.6.32/main/src/net/ipv4/tcp.c#11 edit
... //packages/linux_2.6.32/main/src/net/ipv4/tcp_ipv4.c#15 edit
include/net/tcp.h | 10 +++++++++
net/ipv4/tcp.c | 5 ++++
net/ipv4/tcp_ipv4.c | 53 ++++++++++++++++++++++++----------------------------
3 files changed, 40 insertions(+), 28 deletions(-)
Signed-off-by: Cosmin Ratiu <cratiu@ixiacom.com>
--- src/include/net/tcp.h~
+++ src/include/net/tcp.h
@@ -1570,5 +1570,15 @@
return skc->skc_net_params->tcp.rmem;
}
+struct tcp_reply_hdr {
+ struct tcphdr th;
+ __be32 opt[(TCPOLEN_TSTAMP_ALIGNED >> 2)
+#ifdef CONFIG_TCP_MD5SIG
+ + (TCPOLEN_MD5SIG_ALIGNED >> 2)
+#endif
+ ];
+};
+
+extern struct tcp_reply_hdr *tcp_rep_percpu;
#endif /* _TCP_H */
--- src/net/ipv4/tcp.c~
+++ src/net/ipv4/tcp.c
@@ -3150,6 +3150,11 @@
tcp_hashinfo.lhash_size);
tcp_register_congestion_control(&tcp_reno);
+
+ /* Hack alert: a proper fix should be implemented for the md5 crash */
+ tcp_rep_percpu = alloc_percpu(struct tcp_reply_hdr);
+ if (!tcp_rep_percpu)
+ panic("Cannot allocate per cpu tcp reply hdr\n");
}
EXPORT_SYMBOL(tcp_close);
--- src/net/ipv4/tcp_ipv4.c~
+++ src/net/ipv4/tcp_ipv4.c
@@ -680,6 +680,8 @@
SOCK_STAT_INC(groupptr, TcpRstSent, skb_get_portid(skb));
}
+struct tcp_reply_hdr *tcp_rep_percpu;
+
/* The code following below sending ACKs in SYN-RECV and TIME-WAIT states
outside socket context is ugly, certainly. What can I do?
*/
@@ -691,53 +693,48 @@
int reply_flags, u32 vlanprio)
{
struct tcphdr *th = tcp_hdr(skb);
- struct {
- struct tcphdr th;
- __be32 opt[(TCPOLEN_TSTAMP_ALIGNED >> 2)
-#ifdef CONFIG_TCP_MD5SIG
- + (TCPOLEN_MD5SIG_ALIGNED >> 2)
-#endif
- ];
- } rep;
+ struct tcp_reply_hdr *rep;
struct ip_reply_arg arg;
- memset(&rep.th, 0, sizeof(struct tcphdr));
+ rep = per_cpu_ptr(tcp_rep_percpu, get_cpu());
+
+ memset(&rep->th, 0, sizeof(struct tcphdr));
memset(&arg, 0, sizeof(arg));
- arg.iov[0].iov_base = (unsigned char *)&rep;
- arg.iov[0].iov_len = sizeof(rep.th);
+ arg.iov[0].iov_base = (unsigned char *)rep;
+ arg.iov[0].iov_len = sizeof(rep->th);
if (ts) {
- rep.opt[0] = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
+ rep->opt[0] = htonl((TCPOPT_NOP << 24) | (TCPOPT_NOP << 16) |
(TCPOPT_TIMESTAMP << 8) |
TCPOLEN_TIMESTAMP);
- rep.opt[1] = htonl(tcp_time_stamp);
- rep.opt[2] = htonl(ts);
+ rep->opt[1] = htonl(tcp_time_stamp);
+ rep->opt[2] = htonl(ts);
arg.iov[0].iov_len += TCPOLEN_TSTAMP_ALIGNED;
}
/* Swap the send and the receive. */
- rep.th.dest = th->source;
- rep.th.source = th->dest;
- rep.th.doff = arg.iov[0].iov_len / 4;
- rep.th.seq = htonl(seq);
- rep.th.ack_seq = htonl(ack);
- rep.th.ack = 1;
- rep.th.window = htons(win);
+ rep->th.dest = th->source;
+ rep->th.source = th->dest;
+ rep->th.doff = arg.iov[0].iov_len / 4;
+ rep->th.seq = htonl(seq);
+ rep->th.ack_seq = htonl(ack);
+ rep->th.ack = 1;
+ rep->th.window = htons(win);
#ifdef CONFIG_TCP_MD5SIG
if (key) {
int offset = (ts) ? 3 : 0;
- rep.opt[offset++] = htonl((TCPOPT_NOP << 24) |
- (TCPOPT_NOP << 16) |
- (TCPOPT_MD5SIG << 8) |
- TCPOLEN_MD5SIG);
+ rep->opt[offset++] = htonl((TCPOPT_NOP << 24) |
+ (TCPOPT_NOP << 16) |
+ (TCPOPT_MD5SIG << 8) |
+ TCPOLEN_MD5SIG);
arg.iov[0].iov_len += TCPOLEN_MD5SIG_ALIGNED;
- rep.th.doff = arg.iov[0].iov_len/4;
+ rep->th.doff = arg.iov[0].iov_len/4;
- tcp_v4_md5_hash_hdr((__u8 *) &rep.opt[offset],
+ tcp_v4_md5_hash_hdr((__u8 *) &rep->opt[offset],
key, ip_hdr(skb)->saddr,
- ip_hdr(skb)->daddr, &rep.th);
+ ip_hdr(skb)->daddr, &rep->th);
}
#endif
arg.flags = reply_flags;
^ permalink raw reply
* Re: [PATCH 03/10] mm: Add support for a filesystem to control swap files
From: Mel Gorman @ 2011-09-09 13:15 UTC (permalink / raw)
To: Christoph Hellwig
Cc: Linux-MM, Linux-Netdev, Linux-NFS, LKML, Andrew Morton,
David Miller, Trond Myklebust, Neil Brown, Peter Zijlstra
In-Reply-To: <20110909130007.GA11810@infradead.org>
On Fri, Sep 09, 2011 at 09:00:08AM -0400, Christoph Hellwig wrote:
> On Fri, Sep 09, 2011 at 12:00:47PM +0100, Mel Gorman wrote:
> > Currently swapfiles are managed entirely by the core VM by using
> > ->bmap to allocate space and write to the blocks directly. This
> > patch adds address_space_operations methods that allow a filesystem
> > to optionally control the swapfile.
> >
> > int swap_activate(struct file *);
> > int swap_deactivate(struct file *);
> > int swap_writepage(struct file *, struct page *, struct writeback_control *);
> > int swap_readpage(struct file *, struct page *);
>
> Just as the last two dozen times this came up:
>
> NAK
>
> The right fix is to add a filesystem method to support direct-I/O on
> arbitrary kernel pages, instead of letting the wap abstraction leak into
> the filesystem.
Ok.
I confess I haven't investigated this direction at
all yet. Is it correct that your previous objection was
http://linux.derkeiler.com/Mailing-Lists/Kernel/2009-10/msg00455.html
and the direct-IO patchset you were thinking of was
http://copilotco.com/mail-archives/linux-kernel.2009/msg87176.html ?
If so, are you suggesting that instead of swap_readpage and
swap_writepage I look into what is required for swap to use ->readpage
method and ->direct_IO aops?
--
Mel Gorman
SUSE Labs
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [PATCH 01/15] add Documentation/namespaces/user_namespace.txt (v3)
From: Serge E. Hallyn @ 2011-09-09 13:10 UTC (permalink / raw)
To: Andrew Morton
Cc: Serge Hallyn, segooon, linux-kernel, netdev, containers, dhowells,
ebiederm, rdunlap
In-Reply-To: <20110907155024.42e3fe27.akpm@linux-foundation.org>
Quoting Andrew Morton (akpm@linux-foundation.org):
> On Fri, 2 Sep 2011 19:56:26 +0000
> Serge Hallyn <serge@hallyn.com> wrote:
>
> > +Note that this userid mapping for the VFS is not yet implemented, though the
> > +lkml and containers mailing list archives will show several previous
> > +prototypes. In the end, those got hung up waiting on the concept of targeted
> > +capabilities to be developed, which, thanks to the insight of Eric Biederman,
> > +they finally did.
>
> not-yet-implemented things worry me. When can we expect this to
> happen, and how big and ugly will it be?
Hi Andrew,
We did a proof of concept of the simplest version of this in early August
(see git://git.kernel.org/pub/scm/linux/kernel/git/ebiederm/linux-userns-devel.git)
which actually was very un-scary. So technically we could push it at the
same time as this set, but I thought that might just be too much for
review in one cycle. That set (Eric's) is the very simplest approach
which tags an entire filesystem with a user namespace.
We would also want to pursue the more baroque approach, where filesystems
themselves are user-namespace aware. I did an approach like that in
2008, see
https://lists.linux-foundation.org/pipermail/containers/2008-August/012679.html
It again is very do-able without being ugly, but, importantly, user
namespaces are usable for containers without that. For starters, we only
need /proc and /sys to be user namespace aware (since they must allow
access from multiple namespaces), and that is simple as they are not
persistent.
So I believe that this is the last scary patchset, and that user
namespaces could actually be usable by the end of the year!
> I'm not seeing many (any) reviewed-by's on these patches. I could get
> down and stare at them myself, but that wouldn't be very useful. This
> work goes pretty deep and is quite security-affecting. And network-afecting.
> Can you round up some suitable people and get the reviewing and testing happening
> please?
Will try. Unfortunately I missed my chance to beg and bribe people in
person at plumbers :(
thanks,
-serge
^ permalink raw reply
* Re: [PATCH 10/10] Avoid dereferencing bd_disk during swap_entry_free for network storage
From: Christoph Hellwig @ 2011-09-09 13:02 UTC (permalink / raw)
To: Mel Gorman
Cc: Linux-MM, Linux-Netdev, Linux-NFS, LKML, Andrew Morton,
David Miller, Trond Myklebust, Neil Brown, Peter Zijlstra
In-Reply-To: <1315566054-17209-11-git-send-email-mgorman@suse.de>
On Fri, Sep 09, 2011 at 12:00:54PM +0100, Mel Gorman wrote:
> Commit [b3a27d: swap: Add swap slot free callback to
> block_device_operations] dereferences p->bdev->bd_disk but this is a
> NULL dereference if using swap-over-NFS. This patch checks SWP_BLKDEV
> on the swap_info_struct before dereferencing.
Please just remove the callback entirely. It has no user outside the
staging tree and was added clearly against the rules for that staging
tree.
(and it's butt ugly)
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [PATCH 03/10] mm: Add support for a filesystem to control swap files
From: Christoph Hellwig @ 2011-09-09 13:00 UTC (permalink / raw)
To: Mel Gorman
Cc: Linux-MM, Linux-Netdev, Linux-NFS, LKML, Andrew Morton,
David Miller, Trond Myklebust, Neil Brown, Peter Zijlstra
In-Reply-To: <1315566054-17209-4-git-send-email-mgorman-l3A5Bk7waGM@public.gmane.org>
On Fri, Sep 09, 2011 at 12:00:47PM +0100, Mel Gorman wrote:
> Currently swapfiles are managed entirely by the core VM by using
> ->bmap to allocate space and write to the blocks directly. This
> patch adds address_space_operations methods that allow a filesystem
> to optionally control the swapfile.
>
> int swap_activate(struct file *);
> int swap_deactivate(struct file *);
> int swap_writepage(struct file *, struct page *, struct writeback_control *);
> int swap_readpage(struct file *, struct page *);
Just as the last two dozen times this came up:
NAK
The right fix is to add a filesystem method to support direct-I/O on
arbitrary kernel pages, instead of letting the wap abstraction leak into
the filesystem.
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH v3] net/smsc911x: add device tree probe support
From: Shawn Guo @ 2011-09-09 12:59 UTC (permalink / raw)
To: Dave Martin
Cc: Grant Likely, Shawn Guo, netdev, patches, devicetree-discuss,
Steve Glendinning, David S. Miller, linux-arm-kernel
In-Reply-To: <20110909085030.GA3069@arm.com>
On Fri, Sep 09, 2011 at 09:50:30AM +0100, Dave Martin wrote:
> On Thu, Sep 08, 2011 at 11:29:20AM -0700, Grant Likely wrote:
> > On Thu, Sep 08, 2011 at 03:59:46PM +0100, Dave Martin wrote:
> > > Hi Shawn,
> > >
> > > On Sun, Jul 31, 2011 at 02:26:00AM +0800, Shawn Guo wrote:
> > > > It adds device tree probe support for smsc911x driver.
> > > >
> > > > Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> > > > Cc: Grant Likely <grant.likely@secretlab.ca>
> > > > Cc: Steve Glendinning <steve.glendinning@smsc.com>
> > > > Cc: David S. Miller <davem@davemloft.net>
> > > > Reviewed-by: Grant Likely <grant.likely@secretlab.ca>
> > > > ---
> > > > Changes since v2:
> > > > * Fix a typo in smsc911x.txt
> > > >
> > > > Changes since v1:
> > > > * Instead of getting irq line from gpio number, it use irq domain
> > > > to keep platform_get_resource(IORESOURCE_IRQ) works for dt too.
> > > > * Use 'lan9115' the first model that smsc911x supports in the match
> > > > table
> > > > * Use reg-shift and reg-io-width which already used in of_serial for
> > > > shift and access size binding
> > >
> > > When using this patch with vexpress, I found that 16-bit register access
> > > mode doesn't seem to be getting set correctly.
> > >
> > > Can you take a look at this additional patch and let me know if it looks
> > > correct?
> > >
> > > Cheers
> > > ---Dave
> > >
> > > From: Dave Martin <dave.martin@linaro.org>
> > > Date: Wed, 7 Sep 2011 17:26:31 +0100
> > > Subject: [PATCH] net/smsc911x: Correctly configure 16-bit register access from DT
> > >
> > > The SMSC911X_USE_16BIT needs to be set when using 16-bit register
> > > access. However, currently no flag is set if the DT doesn't specify
> > > 32-bit access.
> > >
> > > This patch should set the SMSC911X_USE_16BIT flag in a manner consistent
> > > with the documented DT bindings.
> > >
> > > Signed-off-by: Dave Martin <dave.martin@linaro.org>
> > > ---
> > > drivers/net/smsc911x.c | 2 ++
> > > 1 files changed, 2 insertions(+), 0 deletions(-)
> > >
> > > diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c
> > > index 75c08a5..1a35c25 100644
> > > --- a/drivers/net/smsc911x.c
> > > +++ b/drivers/net/smsc911x.c
> > > @@ -2121,6 +2121,8 @@ static int __devinit smsc911x_probe_config_dt(
> > > of_property_read_u32(np, "reg-io-width", &width);
> > > if (width == 4)
> > > config->flags |= SMSC911X_USE_32BIT;
> > > + else
> > > + config->flags |= SMSC911X_USE_16BIT;
> >
> > Would it be better to do "else if (width == 2)"? (completely
> > uninformed comment. I've not looked at what the non-DT probe path
> > does on this driver.)
>
> I wouldn't have a problem with that. But currently the binding
> documentation says that any value other than 4, or a missing property,
> implies 16-bit register access.
>
> So the binding documentation would need to change too in that case.
>
> Personally I think this would be better, but it's just an opinion.
>
Yes. SMSC911X_USE_32BIT and SMSC911X_USE_16BIT are the only two cases
supported by the driver.
--
Regards,
Shawn
^ permalink raw reply
* [PATCH v2 5/5] SUNRPC: remove rpcbind clients destruction on module cleanup
From: Stanislav Kinsbursky @ 2011-09-09 12:09 UTC (permalink / raw)
To: Trond.Myklebust
Cc: linux-nfs, xemul, neilb, netdev, linux-kernel, bfields, davem
In-Reply-To: <20110909115146.13697.71682.stgit@localhost6.localdomain6>
Rpcbind clients destruction during SUNRPC module removing is obsolete since now
those clients are destroying during last RPC service shutdown.
Signed-off-by: Stanislav Kinsbursky <skinsbursky@parallels.com>
---
net/sunrpc/rpcb_clnt.c | 12 ------------
net/sunrpc/sunrpc_syms.c | 3 ---
2 files changed, 0 insertions(+), 15 deletions(-)
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
index f363efe..94a310d 100644
--- a/net/sunrpc/rpcb_clnt.c
+++ b/net/sunrpc/rpcb_clnt.c
@@ -1098,15 +1098,3 @@ static struct rpc_program rpcb_program = {
.version = rpcb_version,
.stats = &rpcb_stats,
};
-
-/**
- * cleanup_rpcb_clnt - remove xprtsock's sysctls, unregister
- *
- */
-void cleanup_rpcb_clnt(void)
-{
- if (rpcb_local_clnt4)
- rpc_shutdown_client(rpcb_local_clnt4);
- if (rpcb_local_clnt)
- rpc_shutdown_client(rpcb_local_clnt);
-}
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index 9d08091..8ec9778 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -61,8 +61,6 @@ static struct pernet_operations sunrpc_net_ops = {
extern struct cache_detail unix_gid_cache;
-extern void cleanup_rpcb_clnt(void);
-
static int __init
init_sunrpc(void)
{
@@ -102,7 +100,6 @@ out:
static void __exit
cleanup_sunrpc(void)
{
- cleanup_rpcb_clnt();
rpcauth_remove_module();
cleanup_socket_xprt();
svc_cleanup_xprt_sock();
^ permalink raw reply related
* [PATCH v2 4/5] SUNRPC: remove rpcbind clients creation during service registering
From: Stanislav Kinsbursky @ 2011-09-09 12:08 UTC (permalink / raw)
To: Trond.Myklebust
Cc: linux-nfs, xemul, neilb, netdev, linux-kernel, bfields, davem
In-Reply-To: <20110909115146.13697.71682.stgit@localhost6.localdomain6>
We don't need this code since rpcbind clients are creating during RPC service
creation.
Signed-off-by: Stanislav Kinsbursky <skinsbursky@parallels.com>
---
net/sunrpc/rpcb_clnt.c | 9 ---------
1 files changed, 0 insertions(+), 9 deletions(-)
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
index 437ec60..f363efe 100644
--- a/net/sunrpc/rpcb_clnt.c
+++ b/net/sunrpc/rpcb_clnt.c
@@ -429,11 +429,6 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port)
struct rpc_message msg = {
.rpc_argp = &map,
};
- int error;
-
- error = rpcb_create_local();
- if (error)
- return error;
dprintk("RPC: %sregistering (%u, %u, %d, %u) with local "
"rpcbind\n", (port ? "" : "un"),
@@ -569,11 +564,7 @@ int rpcb_v4_register(const u32 program, const u32 version,
struct rpc_message msg = {
.rpc_argp = &map,
};
- int error;
- error = rpcb_create_local();
- if (error)
- return error;
if (rpcb_local_clnt4 == NULL)
return -EPROTONOSUPPORT;
^ permalink raw reply related
* [PATCH v2 3/5] SUNRPC: make RPC service dependable on rpcbind clients creation
From: Stanislav Kinsbursky @ 2011-09-09 12:08 UTC (permalink / raw)
To: Trond.Myklebust
Cc: linux-nfs, xemul, neilb, netdev, linux-kernel, bfields, davem
In-Reply-To: <20110909115146.13697.71682.stgit@localhost6.localdomain6>
Create rcbind clients or increase rpcbind users counter during RPC service
creation and decrease this counter (and possibly destroy those clients) on RPC
service destruction.
Signed-off-by: Stanislav Kinsbursky <skinsbursky@parallels.com>
---
include/linux/sunrpc/clnt.h | 2 ++
net/sunrpc/rpcb_clnt.c | 2 +-
net/sunrpc/svc.c | 13 +++++++++++--
3 files changed, 14 insertions(+), 3 deletions(-)
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index db7bcaf..65a8115 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -135,10 +135,12 @@ void rpc_shutdown_client(struct rpc_clnt *);
void rpc_release_client(struct rpc_clnt *);
void rpc_task_release_client(struct rpc_task *);
+int rpcb_create_local(void);
int rpcb_register(u32, u32, int, unsigned short);
int rpcb_v4_register(const u32 program, const u32 version,
const struct sockaddr *address,
const char *netid);
+void rpcb_put_local(void);
void rpcb_getport_async(struct rpc_task *);
void rpc_call_start(struct rpc_task *);
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
index b4cc0f1..437ec60 100644
--- a/net/sunrpc/rpcb_clnt.c
+++ b/net/sunrpc/rpcb_clnt.c
@@ -318,7 +318,7 @@ out:
* Returns zero on success, otherwise a negative errno value
* is returned.
*/
-static int rpcb_create_local(void)
+int rpcb_create_local(void)
{
static DEFINE_MUTEX(rpcb_create_local_mutex);
int result = 0;
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 6a69a11..9095c0e 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -367,8 +367,11 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
unsigned int xdrsize;
unsigned int i;
- if (!(serv = kzalloc(sizeof(*serv), GFP_KERNEL)))
+ if (rpcb_create_local() < 0)
return NULL;
+
+ if (!(serv = kzalloc(sizeof(*serv), GFP_KERNEL)))
+ goto out_err;
serv->sv_name = prog->pg_name;
serv->sv_program = prog;
serv->sv_nrthreads = 1;
@@ -403,7 +406,7 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
GFP_KERNEL);
if (!serv->sv_pools) {
kfree(serv);
- return NULL;
+ goto out_err;
}
for (i = 0; i < serv->sv_nrpools; i++) {
@@ -423,6 +426,10 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
svc_unregister(serv);
return serv;
+
+out_err:
+ rpcb_put_local();
+ return NULL;
}
struct svc_serv *
@@ -491,6 +498,8 @@ svc_destroy(struct svc_serv *serv)
svc_unregister(serv);
kfree(serv->sv_pools);
kfree(serv);
+
+ rpcb_put_local();
}
EXPORT_SYMBOL_GPL(svc_destroy);
^ permalink raw reply related
* [PATCH v2 2/5] SUNRPC: use rpcbind reference counting helpers
From: Stanislav Kinsbursky @ 2011-09-09 12:08 UTC (permalink / raw)
To: Trond.Myklebust
Cc: linux-nfs, xemul, neilb, netdev, linux-kernel, bfields, davem
In-Reply-To: <20110909115146.13697.71682.stgit@localhost6.localdomain6>
All is simple: we just increase users counter if rpcbind clients has been
created already. Otherwise we create them and set users counter to 1.
Signed-off-by: Stanislav Kinsbursky <skinsbursky@parallels.com>
---
net/sunrpc/rpcb_clnt.c | 12 ++++--------
1 files changed, 4 insertions(+), 8 deletions(-)
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
index c84e6a3..b4cc0f1 100644
--- a/net/sunrpc/rpcb_clnt.c
+++ b/net/sunrpc/rpcb_clnt.c
@@ -256,9 +256,7 @@ static int rpcb_create_local_unix(void)
clnt4 = NULL;
}
- /* Protected by rpcb_create_local_mutex */
- rpcb_local_clnt = clnt;
- rpcb_local_clnt4 = clnt4;
+ rpcb_set_local(clnt, clnt4);
out:
return result;
@@ -310,9 +308,7 @@ static int rpcb_create_local_net(void)
clnt4 = NULL;
}
- /* Protected by rpcb_create_local_mutex */
- rpcb_local_clnt = clnt;
- rpcb_local_clnt4 = clnt4;
+ rpcb_set_local(clnt, clnt4);
out:
return result;
@@ -327,11 +323,11 @@ static int rpcb_create_local(void)
static DEFINE_MUTEX(rpcb_create_local_mutex);
int result = 0;
- if (rpcb_local_clnt)
+ if (rpcb_get_local())
return result;
mutex_lock(&rpcb_create_local_mutex);
- if (rpcb_local_clnt)
+ if (rpcb_get_local())
goto out;
if (rpcb_create_local_unix() != 0)
^ permalink raw reply related
* [PATCH v2 1/5] SUNRPC: introduce helpers for reference counted rpcbind clients
From: Stanislav Kinsbursky @ 2011-09-09 12:08 UTC (permalink / raw)
To: Trond.Myklebust
Cc: linux-nfs, xemul, neilb, netdev, linux-kernel, bfields, davem
In-Reply-To: <20110909115146.13697.71682.stgit@localhost6.localdomain6>
This helpers will be used for dynamical creation and destruction of rpcbind
clients.
Variable rpcb_users is actually a counter of lauched RPC services. If rpcbind
clients has been created already, then we just increase rpcb_users.
Signed-off-by: Stanislav Kinsbursky <skinsbursky@parallels.com>
---
net/sunrpc/rpcb_clnt.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 51 insertions(+), 0 deletions(-)
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
index e45d2fb..c84e6a3 100644
--- a/net/sunrpc/rpcb_clnt.c
+++ b/net/sunrpc/rpcb_clnt.c
@@ -114,6 +114,9 @@ static struct rpc_program rpcb_program;
static struct rpc_clnt * rpcb_local_clnt;
static struct rpc_clnt * rpcb_local_clnt4;
+DEFINE_SPINLOCK(rpcb_clnt_lock);
+unsigned int rpcb_users;
+
struct rpcbind_args {
struct rpc_xprt * r_xprt;
@@ -161,6 +164,54 @@ static void rpcb_map_release(void *data)
kfree(map);
}
+static int rpcb_get_local(void)
+{
+ spin_lock(&rpcb_clnt_lock);
+ if (rpcb_users)
+ rpcb_users++;
+ spin_unlock(&rpcb_clnt_lock);
+
+ return rpcb_users;
+}
+
+void rpcb_put_local(void)
+{
+ struct rpc_clnt *clnt = rpcb_local_clnt;
+ struct rpc_clnt *clnt4 = rpcb_local_clnt4;
+ int shutdown;
+
+ spin_lock(&rpcb_clnt_lock);
+ if (--rpcb_users == 0) {
+ rpcb_local_clnt = NULL;
+ rpcb_local_clnt4 = NULL;
+ }
+ shutdown = !rpcb_users;
+ spin_unlock(&rpcb_clnt_lock);
+
+ if (shutdown) {
+ /*
+ * cleanup_rpcb_clnt - remove xprtsock's sysctls, unregister
+ */
+ if (clnt4)
+ rpc_shutdown_client(clnt4);
+ if (clnt)
+ rpc_shutdown_client(clnt);
+ }
+ return;
+}
+
+static void rpcb_set_local(struct rpc_clnt *clnt, struct rpc_clnt *clnt4)
+{
+ /* Protected by rpcb_create_local_mutex */
+ rpcb_local_clnt = clnt;
+ rpcb_local_clnt4 = clnt4;
+ rpcb_users++;
+ dprintk("RPC: created new rpcb local clients (rpcb_local_clnt: "
+ "0x%p, rpcb_local_clnt4: 0x%p)\n", rpcb_local_clnt,
+ rpcb_local_clnt4);
+
+}
+
/*
* Returns zero on success, otherwise a negative errno value
* is returned.
^ permalink raw reply related
* [PATCH v2 0/5] SUNRPC: make rpcbind clients allocated and destroyed dynamically
From: Stanislav Kinsbursky @ 2011-09-09 12:08 UTC (permalink / raw)
To: Trond.Myklebust
Cc: linux-nfs, xemul, neilb, netdev, linux-kernel, bfields, davem
v2:
1) rebased to v3.1-rc4 (against branch
git://git.linux-nfs.org/projects/trondmy/nfs-2.6.git)
2) Patch 3/5 (SUNRPC: make RPC service dependable on rpcbind clients creation)
fixed: added rpcb_put_local() call in case of svc_serv creation failure.
This patch is required for further RPC layer virtualization, because rpcbind
clients have to be per network namespace.
To achive this, we have to untie network namespace from rpcbind clients sockets.
The idea of this patch set is to make rpcbind clients non-static. I.e. rpcbind
clients will be created during first RPC service creation, and destroyed when
last RPC service is stopped.
With this patch set rpcbind clients can be virtualized easely.
The following series consists of:
---
Stanislav Kinsbursky (5):
SUNRPC: introduce helpers for reference counted rpcbind clients
SUNRPC: use rpcbind reference counting helpers
SUNRPC: make RPC service dependable on rpcbind clients creation
SUNRPC: remove rpcbind clients creation during service registering
SUNRPC: remove rpcbind clients destruction on module cleanup
include/linux/sunrpc/clnt.h | 2 +
net/sunrpc/rpcb_clnt.c | 86 ++++++++++++++++++++++++++++---------------
net/sunrpc/sunrpc_syms.c | 3 --
net/sunrpc/svc.c | 13 ++++++-
4 files changed, 69 insertions(+), 35 deletions(-)
--
Signature
^ permalink raw reply
* Re: [PATCH v2 6/9] per-cgroup tcp buffers control
From: Glauber Costa @ 2011-09-09 12:01 UTC (permalink / raw)
To: KAMEZAWA Hiroyuki
Cc: linux-kernel, linux-mm, containers, netdev, xemul,
David S. Miller, Eric W. Biederman
In-Reply-To: <20110909121206.e1d628d1.kamezawa.hiroyu@jp.fujitsu.com>
On 09/09/2011 12:12 AM, KAMEZAWA Hiroyuki wrote:
> On Wed, 7 Sep 2011 01:23:16 -0300
> Glauber Costa<glommer@parallels.com> wrote:
>
>> With all the infrastructure in place, this patch implements
>> per-cgroup control for tcp memory pressure handling.
>>
>> Signed-off-by: Glauber Costa<glommer@parallels.com>
>> CC: David S. Miller<davem@davemloft.net>
>> CC: Hiroyouki Kamezawa<kamezawa.hiroyu@jp.fujitsu.com>
>> CC: Eric W. Biederman<ebiederm@xmission.com>
>
> Hmm, then, kmem_cgroup.c is just a caller of plugins implemented
> by other components ?
Kame,
Refer to my discussion with Greg. How would you feel about it being
accounted to a single "kernel memory" limit in memcg?
Thanks!
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [PATCH v3] net/smsc911x: add device tree probe support
From: Shawn Guo @ 2011-09-09 11:48 UTC (permalink / raw)
To: Dave Martin
Cc: Shawn Guo, netdev, patches, devicetree-discuss, Grant Likely,
Steve Glendinning, David S. Miller, linux-arm-kernel
In-Reply-To: <20110908145946.GE2070@arm.com>
On Thu, Sep 08, 2011 at 03:59:46PM +0100, Dave Martin wrote:
> Hi Shawn,
>
> On Sun, Jul 31, 2011 at 02:26:00AM +0800, Shawn Guo wrote:
> > It adds device tree probe support for smsc911x driver.
> >
> > Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
> > Cc: Grant Likely <grant.likely@secretlab.ca>
> > Cc: Steve Glendinning <steve.glendinning@smsc.com>
> > Cc: David S. Miller <davem@davemloft.net>
> > Reviewed-by: Grant Likely <grant.likely@secretlab.ca>
> > ---
> > Changes since v2:
> > * Fix a typo in smsc911x.txt
> >
> > Changes since v1:
> > * Instead of getting irq line from gpio number, it use irq domain
> > to keep platform_get_resource(IORESOURCE_IRQ) works for dt too.
> > * Use 'lan9115' the first model that smsc911x supports in the match
> > table
> > * Use reg-shift and reg-io-width which already used in of_serial for
> > shift and access size binding
>
> When using this patch with vexpress, I found that 16-bit register access
> mode doesn't seem to be getting set correctly.
>
> Can you take a look at this additional patch and let me know if it looks
> correct?
>
> Cheers
> ---Dave
>
> From: Dave Martin <dave.martin@linaro.org>
> Date: Wed, 7 Sep 2011 17:26:31 +0100
> Subject: [PATCH] net/smsc911x: Correctly configure 16-bit register access from DT
>
> The SMSC911X_USE_16BIT needs to be set when using 16-bit register
> access. However, currently no flag is set if the DT doesn't specify
> 32-bit access.
>
> This patch should set the SMSC911X_USE_16BIT flag in a manner consistent
> with the documented DT bindings.
>
> Signed-off-by: Dave Martin <dave.martin@linaro.org>
> ---
Acked-by: Shawn Guo <shawn.guo@linaro.org>
> drivers/net/smsc911x.c | 2 ++
> 1 files changed, 2 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c
> index 75c08a5..1a35c25 100644
> --- a/drivers/net/smsc911x.c
> +++ b/drivers/net/smsc911x.c
> @@ -2121,6 +2121,8 @@ static int __devinit smsc911x_probe_config_dt(
> of_property_read_u32(np, "reg-io-width", &width);
> if (width == 4)
> config->flags |= SMSC911X_USE_32BIT;
> + else
> + config->flags |= SMSC911X_USE_16BIT;
>
> if (of_get_property(np, "smsc,irq-active-high", NULL))
> config->irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH;
> --
> 1.7.4.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
^ permalink raw reply
* [PATCH net-next] af_unix: allow bigger skbs in unix_stream_sendmsg
From: Eric Dumazet @ 2011-09-09 11:32 UTC (permalink / raw)
To: David Miller; +Cc: netdev, Tim Chen, Andi Kleen
unix_stream_sendmsg() currently builds basic skbs, of up to 16192 bytes
(order-2 allocations) per skb.
We switch to pure order-0 allocations, with up to 16 fragments per skbs,
to lower number of context switches and lower memory pressure on high
order pages and LOWMEM (frags pages can be allocated from HIGHMEM).
We can send 64Kb in one round.
I get a 50% speedup on a AF_UNIX benchmark using 16Kb buffers.
No impact on small writes.
Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
benchmark is hackbench, slightly modified.
include/net/af_unix.h | 1 +
net/unix/af_unix.c | 40 ++++++++++++++++------------------------
2 files changed, 17 insertions(+), 24 deletions(-)
diff --git a/include/net/af_unix.h b/include/net/af_unix.h
index 91ab5b0..9a57b4b 100644
--- a/include/net/af_unix.h
+++ b/include/net/af_unix.h
@@ -30,6 +30,7 @@ struct unix_skb_parms {
#ifdef CONFIG_SECURITY_NETWORK
u32 secid; /* Security ID */
#endif
+ int offset;
};
#define UNIXCB(skb) (*(struct unix_skb_parms *)&((skb)->cb))
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 1bd4ecf..4736af4 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -1575,7 +1575,7 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
struct sock_iocb *siocb = kiocb_to_siocb(kiocb);
struct sock *sk = sock->sk;
struct sock *other = NULL;
- int err, size;
+ int err, size, header_len;
struct sk_buff *skb = NULL;
int sent = 0;
struct scm_cookie tmp_scm;
@@ -1616,31 +1616,22 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
size = len-sent;
/* Keep two messages in the pipe so it schedules better */
- if (size > ((sk->sk_sndbuf >> 1) - 64))
- size = (sk->sk_sndbuf >> 1) - 64;
+ size = min_t(int, size, (sk->sk_sndbuf >> 1) - 64);
- if (size > SKB_MAX_ALLOC)
- size = SKB_MAX_ALLOC;
+ /* size of a full skb, using order-0 allocations */
+ size = min_t(int, size, SKB_MAX_ORDER(0,0) + MAX_SKB_FRAGS * PAGE_SIZE);
- /*
- * Grab a buffer
- */
+ header_len = min_t(int, size, SKB_MAX_ORDER(0,0));
- skb = sock_alloc_send_skb(sk, size, msg->msg_flags&MSG_DONTWAIT,
- &err);
+ skb = sock_alloc_send_pskb(sk, header_len, size - header_len,
+ msg->msg_flags & MSG_DONTWAIT, &err);
if (skb == NULL)
goto out_err;
- /*
- * If you pass two values to the sock_alloc_send_skb
- * it tries to grab the large buffer with GFP_NOFS
- * (which can fail easily), and if it fails grab the
- * fallback size buffer which is under a page and will
- * succeed. [Alan]
- */
- size = min_t(int, size, skb_tailroom(skb));
-
+ skb_put(skb, header_len);
+ skb->data_len = size - header_len;
+ skb->len = size;
/* Only send the fds in first buffer
* Last buffer can steal our references to pid/cred
@@ -1654,7 +1645,7 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
max_level = err + 1;
fds_sent = true;
- err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
+ err = skb_copy_datagram_from_iovec(skb, 0, msg->msg_iov, 0, size);
if (err) {
kfree_skb(skb);
goto out_err;
@@ -1965,8 +1956,9 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
sunaddr = NULL;
}
- chunk = min_t(unsigned int, skb->len, size);
- if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) {
+ chunk = min_t(unsigned int, skb->len - UNIXCB(skb).offset, size);
+ if (skb_copy_datagram_iovec(skb, UNIXCB(skb).offset,
+ msg->msg_iov, chunk)) {
skb_queue_head(&sk->sk_receive_queue, skb);
skb = NULL;
if (copied == 0)
@@ -1978,13 +1970,13 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
/* Mark read part of skb as used */
if (!(flags & MSG_PEEK)) {
- skb_pull(skb, chunk);
+ UNIXCB(skb).offset += chunk;
if (UNIXCB(skb).fp)
unix_detach_fds(siocb->scm, skb);
/* put the skb back if we didn't use it up.. */
- if (skb->len) {
+ if (UNIXCB(skb).offset < skb->len) {
skb_queue_head(&sk->sk_receive_queue, skb);
skb = NULL;
break;
^ permalink raw reply related
* [PATCH 10/10] Avoid dereferencing bd_disk during swap_entry_free for network storage
From: Mel Gorman @ 2011-09-09 11:00 UTC (permalink / raw)
To: Linux-MM
Cc: Linux-Netdev, Linux-NFS, LKML, Andrew Morton, David Miller,
Trond Myklebust, Neil Brown, Peter Zijlstra, Mel Gorman
In-Reply-To: <1315566054-17209-1-git-send-email-mgorman@suse.de>
Commit [b3a27d: swap: Add swap slot free callback to
block_device_operations] dereferences p->bdev->bd_disk but this is a
NULL dereference if using swap-over-NFS. This patch checks SWP_BLKDEV
on the swap_info_struct before dereferencing.
Signed-off-by: Xiaotian Feng <dfeng@redhat.com>
Signed-off-by: Mel Gorman <mgorman@suse.de>
---
mm/swapfile.c | 9 +++++----
1 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 806b994..8b85a88 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -547,7 +547,6 @@ static unsigned char swap_entry_free(struct swap_info_struct *p,
/* free if no reference */
if (!usage) {
- struct gendisk *disk = p->bdev->bd_disk;
if (offset < p->lowest_bit)
p->lowest_bit = offset;
if (offset > p->highest_bit)
@@ -557,9 +556,11 @@ static unsigned char swap_entry_free(struct swap_info_struct *p,
swap_list.next = p->type;
nr_swap_pages++;
p->inuse_pages--;
- if ((p->flags & SWP_BLKDEV) &&
- disk->fops->swap_slot_free_notify)
- disk->fops->swap_slot_free_notify(p->bdev, offset);
+ if (p->flags & SWP_BLKDEV) {
+ struct gendisk *disk = p->bdev->bd_disk;
+ if (disk->fops->swap_slot_free_notify)
+ disk->fops->swap_slot_free_notify(p->bdev, offset);
+ }
}
return usage;
--
1.7.3.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related
* [PATCH 09/10] nfs: Prevent page allocator recursions with swap over NFS.
From: Mel Gorman @ 2011-09-09 11:00 UTC (permalink / raw)
To: Linux-MM
Cc: Linux-Netdev, Linux-NFS, LKML, Andrew Morton, David Miller,
Trond Myklebust, Neil Brown, Peter Zijlstra, Mel Gorman
In-Reply-To: <1315566054-17209-1-git-send-email-mgorman@suse.de>
GFP_NOFS is _more_ permissive than GFP_NOIO in that it will initiate
IO, just not of any filesystem data.
The problem is that previously NOFS was correct because that avoids
recursion into the NFS code. With swap-over-NFS, it is no longer
correct as swap IO can lead to this recursion.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Signed-off-by: Mel Gorman <mgorman@suse.de>
---
fs/nfs/pagelist.c | 2 +-
fs/nfs/write.c | 7 ++++---
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index 1fcc294..5eb527d 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -27,7 +27,7 @@ static struct kmem_cache *nfs_page_cachep;
static inline struct nfs_page *
nfs_page_alloc(void)
{
- struct nfs_page *p = kmem_cache_zalloc(nfs_page_cachep, GFP_KERNEL);
+ struct nfs_page *p = kmem_cache_zalloc(nfs_page_cachep, GFP_NOIO);
if (p)
INIT_LIST_HEAD(&p->wb_list);
return p;
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 475e1f2..78e4ce6 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -51,7 +51,7 @@ static mempool_t *nfs_commit_mempool;
struct nfs_write_data *nfs_commitdata_alloc(void)
{
- struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, GFP_NOFS);
+ struct nfs_write_data *p = mempool_alloc(nfs_commit_mempool, GFP_NOIO);
if (p) {
memset(p, 0, sizeof(*p));
@@ -71,7 +71,7 @@ EXPORT_SYMBOL_GPL(nfs_commit_free);
struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount)
{
- struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, GFP_NOFS);
+ struct nfs_write_data *p = mempool_alloc(nfs_wdata_mempool, GFP_NOIO);
if (p) {
memset(p, 0, sizeof(*p));
@@ -80,7 +80,8 @@ struct nfs_write_data *nfs_writedata_alloc(unsigned int pagecount)
if (pagecount <= ARRAY_SIZE(p->page_array))
p->pagevec = p->page_array;
else {
- p->pagevec = kcalloc(pagecount, sizeof(struct page *), GFP_NOFS);
+ p->pagevec = kcalloc(pagecount, sizeof(struct page *),
+ GFP_NOIO);
if (!p->pagevec) {
mempool_free(p, nfs_wdata_mempool);
p = NULL;
--
1.7.3.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related
* [PATCH 08/10] nfs: enable swap on NFS
From: Mel Gorman @ 2011-09-09 11:00 UTC (permalink / raw)
To: Linux-MM
Cc: Linux-Netdev, Linux-NFS, LKML, Andrew Morton, David Miller,
Trond Myklebust, Neil Brown, Peter Zijlstra, Mel Gorman
In-Reply-To: <1315566054-17209-1-git-send-email-mgorman@suse.de>
Implement all the new swapfile a_ops for NFS. This will set the NFS
socket to SOCK_MEMALLOC and run socket reconnect under PF_MEMALLOC as
well as reset SOCK_MEMALLOC before engaging the protocol ->connect()
method.
PF_MEMALLOC should allow the allocation of struct socket and related
objects and the early (re)setting of SOCK_MEMALLOC should allow us
to receive the packets required for the TCP connection buildup.
[dfeng@redhat.com: Fix handling of multiple swap files]
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Signed-off-by: Mel Gorman <mgorman@suse.de>
---
fs/nfs/Kconfig | 8 ++++++
fs/nfs/file.c | 20 +++++++++++++++
fs/nfs/write.c | 33 ++++++++++++++++++++++++-
include/linux/nfs_fs.h | 2 +
include/linux/sunrpc/xprt.h | 3 ++
net/sunrpc/Kconfig | 5 ++++
net/sunrpc/clnt.c | 2 +
net/sunrpc/sched.c | 7 ++++-
net/sunrpc/xprtsock.c | 57 +++++++++++++++++++++++++++++++++++++++++++
9 files changed, 134 insertions(+), 3 deletions(-)
diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig
index dbcd821..7c3b921 100644
--- a/fs/nfs/Kconfig
+++ b/fs/nfs/Kconfig
@@ -74,6 +74,14 @@ config NFS_V4
If unsure, say Y.
+config NFS_SWAP
+ bool "Provide swap over NFS support"
+ default n
+ depends on NFS_FS
+ select SUNRPC_SWAP
+ help
+ This option enables swapon to work on files located on NFS mounts.
+
config NFS_V4_1
bool "NFS client support for NFSv4.1 (EXPERIMENTAL)"
depends on NFS_FS && NFS_V4 && EXPERIMENTAL
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 38c7cf4..2fdb1bd 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -536,6 +536,20 @@ static int nfs_launder_page(struct page *page)
return nfs_wb_page(inode, page);
}
+#ifdef CONFIG_NFS_SWAP
+static int nfs_swap_activate(struct swap_info_struct *sis, struct file *file,
+ sector_t *span)
+{
+ *span = sis->pages;
+ return xs_swapper(NFS_CLIENT(file->f_mapping->host)->cl_xprt, 1);
+}
+
+static void nfs_swap_deactivate(struct file *file)
+{
+ xs_swapper(NFS_CLIENT(file->f_mapping->host)->cl_xprt, 0);
+}
+#endif
+
const struct address_space_operations nfs_file_aops = {
.readpage = nfs_readpage,
.readpages = nfs_readpages,
@@ -550,6 +564,12 @@ const struct address_space_operations nfs_file_aops = {
.migratepage = nfs_migrate_page,
.launder_page = nfs_launder_page,
.error_remove_page = generic_error_remove_page,
+#ifdef CONFIG_NFS_SWAP
+ .swap_activate = nfs_swap_activate,
+ .swap_deactivate = nfs_swap_deactivate,
+ .swap_writepage = nfs_swap_writepage,
+ .swap_readpage = nfs_readpage,
+#endif
};
/*
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index 15e3b7a..475e1f2 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -369,6 +369,28 @@ int nfs_writepage(struct page *page, struct writeback_control *wbc)
return ret;
}
+static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page,
+ unsigned int offset, unsigned int count);
+
+int nfs_swap_writepage(struct file *file, struct page *page,
+ struct writeback_control *wbc)
+{
+ struct nfs_open_context *ctx = nfs_file_open_context(file);
+ int status;
+
+ status = nfs_writepage_setup(ctx, page, 0, nfs_page_length(page));
+ if (status < 0) {
+ nfs_set_pageerror(page);
+ goto out;
+ }
+
+ status = nfs_writepage_locked(page, wbc);
+
+out:
+ unlock_page(page);
+ return status;
+}
+
static int nfs_writepages_callback(struct page *page, struct writeback_control *wbc, void *data)
{
int ret;
@@ -734,7 +756,16 @@ static int nfs_writepage_setup(struct nfs_open_context *ctx, struct page *page,
/* Update file length */
nfs_grow_file(page, offset, count);
nfs_mark_uptodate(page, req->wb_pgbase, req->wb_bytes);
- nfs_mark_request_dirty(req);
+
+ /*
+ * There is no need to mark swapfile requests as dirty like normal
+ * writepage requests as page dirtying and cleaning is managed
+ * from the mm. If a PageSwapCache page is marked dirty like this,
+ * it will still be dirty after kswapd calls writepage and may
+ * never be released
+ */
+ if (!PageSwapCache(page))
+ nfs_mark_request_dirty(req);
nfs_clear_page_tag_locked(req);
return 0;
}
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index eaac770..c7a1e01 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -513,6 +513,8 @@ extern int nfs_writepages(struct address_space *, struct writeback_control *);
extern int nfs_flush_incompatible(struct file *file, struct page *page);
extern int nfs_updatepage(struct file *, struct page *, unsigned int, unsigned int);
extern void nfs_writeback_done(struct rpc_task *, struct nfs_write_data *);
+extern int nfs_swap_writepage(struct file *file, struct page *page,
+ struct writeback_control *wbc);
/*
* Try to write back everything synchronously (but check the
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index 15518a1..bc2fd1e 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -174,6 +174,8 @@ struct rpc_xprt {
unsigned long state; /* transport state */
unsigned char shutdown : 1, /* being shut down */
resvport : 1; /* use a reserved port */
+ unsigned int swapper; /* we're swapping over this
+ transport */
unsigned int bind_index; /* bind function index */
/*
@@ -311,6 +313,7 @@ void xprt_release_rqst_cong(struct rpc_task *task);
void xprt_disconnect_done(struct rpc_xprt *xprt);
void xprt_force_disconnect(struct rpc_xprt *xprt);
void xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie);
+int xs_swapper(struct rpc_xprt *xprt, int enable);
/*
* Reserved bit positions in xprt->state
diff --git a/net/sunrpc/Kconfig b/net/sunrpc/Kconfig
index ffd243d..0e9d340 100644
--- a/net/sunrpc/Kconfig
+++ b/net/sunrpc/Kconfig
@@ -21,6 +21,11 @@ config SUNRPC_XPRT_RDMA
If unsure, say N.
+config SUNRPC_SWAP
+ bool
+ depends on SUNRPC
+ select NETVM
+
config RPCSEC_GSS_KRB5
tristate "Secure RPC: Kerberos V mechanism"
depends on SUNRPC && CRYPTO
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index c5347d2..63547e0 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -594,6 +594,8 @@ void rpc_task_set_client(struct rpc_task *task, struct rpc_clnt *clnt)
atomic_inc(&clnt->cl_count);
if (clnt->cl_softrtry)
task->tk_flags |= RPC_TASK_SOFT;
+ if (task->tk_client->cl_xprt->swapper)
+ task->tk_flags |= RPC_TASK_SWAPPER;
/* Add to the client's list of all tasks */
spin_lock(&clnt->cl_lock);
list_add_tail(&task->tk_task, &clnt->cl_tasks);
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index d12ffa5..e116ab2 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -748,7 +748,10 @@ static void rpc_async_schedule(struct work_struct *work)
void *rpc_malloc(struct rpc_task *task, size_t size)
{
struct rpc_buffer *buf;
- gfp_t gfp = RPC_IS_SWAPPER(task) ? GFP_ATOMIC : GFP_NOWAIT;
+ gfp_t gfp = GFP_NOWAIT;
+
+ if (RPC_IS_SWAPPER(task))
+ gfp |= __GFP_MEMALLOC;
size += sizeof(struct rpc_buffer);
if (size <= RPC_BUFFER_MAXSIZE)
@@ -828,7 +831,7 @@ static void rpc_init_task(struct rpc_task *task, const struct rpc_task_setup *ta
static struct rpc_task *
rpc_alloc_task(void)
{
- return (struct rpc_task *)mempool_alloc(rpc_task_mempool, GFP_NOFS);
+ return (struct rpc_task *)mempool_alloc(rpc_task_mempool, GFP_NOIO);
}
/*
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index d7f97ef..6448abe 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -1931,6 +1931,49 @@ out:
xprt_wake_pending_tasks(xprt, status);
}
+#ifdef CONFIG_SUNRPC_SWAP
+static void xs_set_memalloc(struct rpc_xprt *xprt)
+{
+ struct sock_xprt *transport = container_of(xprt, struct sock_xprt,
+ xprt);
+
+ if (xprt->swapper)
+ sk_set_memalloc(transport->inet);
+}
+
+#define RPC_BUF_RESERVE_PAGES \
+ kmalloc_estimate_objs(sizeof(struct rpc_rqst), GFP_KERNEL, RPC_MAX_SLOT_TABLE)
+#define RPC_RESERVE_PAGES (RPC_BUF_RESERVE_PAGES + TX_RESERVE_PAGES)
+
+/**
+ * xs_swapper - Tag this transport as being used for swap.
+ * @xprt: transport to tag
+ * @enable: enable/disable
+ *
+ */
+int xs_swapper(struct rpc_xprt *xprt, int enable)
+{
+ struct sock_xprt *transport = container_of(xprt, struct sock_xprt,
+ xprt);
+ int err = 0;
+
+ if (enable) {
+ xprt->swapper++;
+ xs_set_memalloc(xprt);
+ } else if (xprt->swapper) {
+ xprt->swapper--;
+ sk_clear_memalloc(transport->inet);
+ }
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(xs_swapper);
+#else
+static void xs_set_memalloc(struct rpc_xprt *xprt)
+{
+}
+#endif
+
static void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
{
struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
@@ -1955,6 +1998,8 @@ static void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
transport->sock = sock;
transport->inet = sk;
+ xs_set_memalloc(xprt);
+
write_unlock_bh(&sk->sk_callback_lock);
}
xs_udp_do_set_buffer_size(xprt);
@@ -1966,11 +2011,15 @@ static void xs_udp_setup_socket(struct work_struct *work)
container_of(work, struct sock_xprt, connect_worker.work);
struct rpc_xprt *xprt = &transport->xprt;
struct socket *sock = transport->sock;
+ unsigned long pflags = current->flags;
int status = -EIO;
if (xprt->shutdown)
goto out;
+ if (xprt->swapper)
+ current->flags |= PF_MEMALLOC;
+
/* Start by resetting any existing state */
xs_reset_transport(transport);
sock = xs_create_sock(xprt, transport,
@@ -1989,6 +2038,7 @@ static void xs_udp_setup_socket(struct work_struct *work)
out:
xprt_clear_connecting(xprt);
xprt_wake_pending_tasks(xprt, status);
+ tsk_restore_flags(current, pflags, PF_MEMALLOC);
}
/*
@@ -2079,6 +2129,8 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
if (!xprt_bound(xprt))
goto out;
+ xs_set_memalloc(xprt);
+
/* Tell the socket layer to start connecting... */
xprt->stat.connect_count++;
xprt->stat.connect_start = jiffies;
@@ -2109,11 +2161,15 @@ static void xs_tcp_setup_socket(struct work_struct *work)
container_of(work, struct sock_xprt, connect_worker.work);
struct socket *sock = transport->sock;
struct rpc_xprt *xprt = &transport->xprt;
+ unsigned long pflags = current->flags;
int status = -EIO;
if (xprt->shutdown)
goto out;
+ if (xprt->swapper)
+ current->flags |= PF_MEMALLOC;
+
if (!sock) {
clear_bit(XPRT_CONNECTION_ABORT, &xprt->state);
sock = xs_create_sock(xprt, transport,
@@ -2175,6 +2231,7 @@ out_eagain:
out:
xprt_clear_connecting(xprt);
xprt_wake_pending_tasks(xprt, status);
+ tsk_restore_flags(current, pflags, PF_MEMALLOC);
}
/**
--
1.7.3.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related
* [PATCH 07/10] nfs: disable data cache revalidation for swapfiles
From: Mel Gorman @ 2011-09-09 11:00 UTC (permalink / raw)
To: Linux-MM
Cc: Linux-Netdev, Linux-NFS, LKML, Andrew Morton, David Miller,
Trond Myklebust, Neil Brown, Peter Zijlstra, Mel Gorman
In-Reply-To: <1315566054-17209-1-git-send-email-mgorman@suse.de>
The VM does not like PG_private set on PG_swapcache pages. As suggested
by Trond in http://lkml.org/lkml/2006/8/25/348, this patch disables
NFS data cache revalidation on swap files. as it does not make
sense to have other clients change the file while it is being used as
swap. This avoids setting PG_private on swap pages, since there ought
to be no further races with invalidate_inode_pages2() to deal with.
Since we cannot set PG_private we cannot use page->private which
is already used by PG_swapcache pages to store the nfs_page. Thus
augment the new nfs_page_find_request logic.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Signed-off-by: Mel Gorman <mgorman@suse.de>
---
fs/nfs/inode.c | 6 ++++
fs/nfs/write.c | 77 +++++++++++++++++++++++++++++++++++++++++++++-----------
2 files changed, 68 insertions(+), 15 deletions(-)
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index fe12037..fa25e2c 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -877,6 +877,12 @@ int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
struct nfs_inode *nfsi = NFS_I(inode);
int ret = 0;
+ /*
+ * swapfiles are not supposed to be shared.
+ */
+ if (IS_SWAPFILE(inode))
+ goto out;
+
if ((nfsi->cache_validity & NFS_INO_REVAL_PAGECACHE)
|| nfs_attribute_cache_expired(inode)
|| NFS_STALE(inode)) {
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index ffd95d1..15e3b7a 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -111,25 +111,64 @@ static void nfs_context_set_write_error(struct nfs_open_context *ctx, int error)
set_bit(NFS_CONTEXT_ERROR_WRITE, &ctx->flags);
}
-static struct nfs_page *nfs_page_find_request_locked(struct page *page)
+static struct nfs_page *
+__nfs_page_find_request_locked(struct nfs_inode *nfsi, struct page *page,
+ int get)
{
struct nfs_page *req = NULL;
- if (PagePrivate(page)) {
+ if (PagePrivate(page))
req = (struct nfs_page *)page_private(page);
- if (req != NULL)
- kref_get(&req->wb_kref);
- }
+ else if (unlikely(PageSwapCache(page)))
+ req = radix_tree_lookup(&nfsi->nfs_page_tree,
+ page_file_index(page));
+
+ if (get && req)
+ kref_get(&req->wb_kref);
+
return req;
}
+static inline struct nfs_page *
+nfs_page_find_request_locked(struct nfs_inode *nfsi, struct page *page)
+{
+ return __nfs_page_find_request_locked(nfsi, page, 1);
+}
+
+static int __nfs_page_has_request(struct page *page)
+{
+ struct inode *inode = page_file_mapping(page)->host;
+ struct nfs_page *req = NULL;
+
+ spin_lock(&inode->i_lock);
+ req = __nfs_page_find_request_locked(NFS_I(inode), page, 0);
+ spin_unlock(&inode->i_lock);
+
+ /*
+ * hole here plugged by the caller holding onto PG_locked
+ */
+
+ return req != NULL;
+}
+
+static inline int nfs_page_has_request(struct page *page)
+{
+ if (PagePrivate(page))
+ return 1;
+
+ if (unlikely(PageSwapCache(page)))
+ return __nfs_page_has_request(page);
+
+ return 0;
+}
+
static struct nfs_page *nfs_page_find_request(struct page *page)
{
struct inode *inode = page_file_mapping(page)->host;
struct nfs_page *req = NULL;
spin_lock(&inode->i_lock);
- req = nfs_page_find_request_locked(page);
+ req = nfs_page_find_request_locked(NFS_I(inode), page);
spin_unlock(&inode->i_lock);
return req;
}
@@ -232,7 +271,7 @@ static struct nfs_page *nfs_find_and_lock_request(struct page *page, bool nonblo
spin_lock(&inode->i_lock);
for (;;) {
- req = nfs_page_find_request_locked(page);
+ req = nfs_page_find_request_locked(NFS_I(inode), page);
if (req == NULL)
break;
if (nfs_set_page_tag_locked(req))
@@ -392,9 +431,15 @@ static int nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
BUG_ON(error);
if (!nfsi->npages && nfs_have_delegation(inode, FMODE_WRITE))
nfsi->change_attr++;
- set_bit(PG_MAPPED, &req->wb_flags);
- SetPagePrivate(req->wb_page);
- set_page_private(req->wb_page, (unsigned long)req);
+ /*
+ * Swap-space should not get truncated. Hence no need to plug the race
+ * with invalidate/truncate.
+ */
+ if (likely(!PageSwapCache(req->wb_page))) {
+ set_bit(PG_MAPPED, &req->wb_flags);
+ SetPagePrivate(req->wb_page);
+ set_page_private(req->wb_page, (unsigned long)req);
+ }
nfsi->npages++;
kref_get(&req->wb_kref);
radix_tree_tag_set(&nfsi->nfs_page_tree, req->wb_index,
@@ -416,9 +461,11 @@ static void nfs_inode_remove_request(struct nfs_page *req)
BUG_ON (!NFS_WBACK_BUSY(req));
spin_lock(&inode->i_lock);
- set_page_private(req->wb_page, 0);
- ClearPagePrivate(req->wb_page);
- clear_bit(PG_MAPPED, &req->wb_flags);
+ if (likely(!PageSwapCache(req->wb_page))) {
+ set_page_private(req->wb_page, 0);
+ ClearPagePrivate(req->wb_page);
+ clear_bit(PG_MAPPED, &req->wb_flags);
+ }
radix_tree_delete(&nfsi->nfs_page_tree, req->wb_index);
nfsi->npages--;
spin_unlock(&inode->i_lock);
@@ -593,7 +640,7 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode,
spin_lock(&inode->i_lock);
for (;;) {
- req = nfs_page_find_request_locked(page);
+ req = nfs_page_find_request_locked(NFS_I(inode), page);
if (req == NULL)
goto out_unlock;
@@ -1657,7 +1704,7 @@ int nfs_wb_page_cancel(struct inode *inode, struct page *page)
*/
int nfs_wb_page(struct inode *inode, struct page *page)
{
- loff_t range_start = page_offset(page);
+ loff_t range_start = page_file_offset(page);
loff_t range_end = range_start + (loff_t)(PAGE_CACHE_SIZE - 1);
struct writeback_control wbc = {
.sync_mode = WB_SYNC_ALL,
--
1.7.3.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related
* [PATCH 06/10] nfs: teach the NFS client how to treat PG_swapcache pages
From: Mel Gorman @ 2011-09-09 11:00 UTC (permalink / raw)
To: Linux-MM
Cc: Linux-Netdev, Linux-NFS, LKML, Andrew Morton, David Miller,
Trond Myklebust, Neil Brown, Peter Zijlstra, Mel Gorman
In-Reply-To: <1315566054-17209-1-git-send-email-mgorman@suse.de>
Replace all relevant occurences of page->index and page->mapping in
the NFS client with the new page_file_index() and page_file_mapping()
functions.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Signed-off-by: Mel Gorman <mgorman@suse.de>
---
fs/nfs/file.c | 6 +++---
fs/nfs/internal.h | 7 ++++---
fs/nfs/pagelist.c | 6 +++---
fs/nfs/read.c | 6 +++---
fs/nfs/write.c | 46 +++++++++++++++++++++++++---------------------
5 files changed, 38 insertions(+), 33 deletions(-)
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index 28b8c3f..38c7cf4 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -484,7 +484,7 @@ static void nfs_invalidate_page(struct page *page, unsigned long offset)
if (offset != 0)
return;
/* Cancel any unstarted writes on this page */
- nfs_wb_page_cancel(page->mapping->host, page);
+ nfs_wb_page_cancel(page_file_mapping(page)->host, page);
nfs_fscache_invalidate_page(page, page->mapping->host);
}
@@ -526,7 +526,7 @@ static int nfs_release_page(struct page *page, gfp_t gfp)
*/
static int nfs_launder_page(struct page *page)
{
- struct inode *inode = page->mapping->host;
+ struct inode *inode = page_file_mapping(page)->host;
struct nfs_inode *nfsi = NFS_I(inode);
dfprintk(PAGECACHE, "NFS: launder_page(%ld, %llu)\n",
@@ -575,7 +575,7 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
nfs_fscache_wait_on_page_write(NFS_I(dentry->d_inode), page);
lock_page(page);
- mapping = page->mapping;
+ mapping = page_file_mapping(page);
if (mapping != dentry->d_inode->i_mapping)
goto out_unlock;
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index ab12913..1085e02 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -425,13 +425,14 @@ void nfs_super_set_maxbytes(struct super_block *sb, __u64 maxfilesize)
static inline
unsigned int nfs_page_length(struct page *page)
{
- loff_t i_size = i_size_read(page->mapping->host);
+ loff_t i_size = i_size_read(page_file_mapping(page)->host);
if (i_size > 0) {
+ pgoff_t page_index = page_file_index(page);
pgoff_t end_index = (i_size - 1) >> PAGE_CACHE_SHIFT;
- if (page->index < end_index)
+ if (page_index < end_index)
return PAGE_CACHE_SIZE;
- if (page->index == end_index)
+ if (page_index == end_index)
return ((i_size - 1) & ~PAGE_CACHE_MASK) + 1;
}
return 0;
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index b60970c..1fcc294 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -75,11 +75,11 @@ nfs_create_request(struct nfs_open_context *ctx, struct inode *inode,
* update_nfs_request below if the region is not locked. */
req->wb_page = page;
atomic_set(&req->wb_complete, 0);
- req->wb_index = page->index;
+ req->wb_index = page_file_index(page);
page_cache_get(page);
BUG_ON(PagePrivate(page));
BUG_ON(!PageLocked(page));
- BUG_ON(page->mapping->host != inode);
+ BUG_ON(page_file_mapping(page)->host != inode);
req->wb_offset = offset;
req->wb_pgbase = offset;
req->wb_bytes = count;
@@ -429,7 +429,7 @@ void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *desc, pgoff_t index)
* nfs_scan_list - Scan a list for matching requests
* @nfsi: NFS inode
* @dst: Destination list
- * @idx_start: lower bound of page->index to scan
+ * @idx_start: lower bound of page_file_index(page) to scan
* @npages: idx_start + npages sets the upper bound to scan.
* @tag: tag to scan for
*
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index 2171c04..3352782 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -568,11 +568,11 @@ static const struct rpc_call_ops nfs_read_full_ops = {
int nfs_readpage(struct file *file, struct page *page)
{
struct nfs_open_context *ctx;
- struct inode *inode = page->mapping->host;
+ struct inode *inode = page_file_mapping(page)->host;
int error;
dprintk("NFS: nfs_readpage (%p %ld@%lu)\n",
- page, PAGE_CACHE_SIZE, page->index);
+ page, PAGE_CACHE_SIZE, page_file_index(page));
nfs_inc_stats(inode, NFSIOS_VFSREADPAGE);
nfs_add_stats(inode, NFSIOS_READPAGES, 1);
@@ -626,7 +626,7 @@ static int
readpage_async_filler(void *data, struct page *page)
{
struct nfs_readdesc *desc = (struct nfs_readdesc *)data;
- struct inode *inode = page->mapping->host;
+ struct inode *inode = page_file_mapping(page)->host;
struct nfs_page *new;
unsigned int len;
int error;
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index b39b37f..ffd95d1 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -125,7 +125,7 @@ static struct nfs_page *nfs_page_find_request_locked(struct page *page)
static struct nfs_page *nfs_page_find_request(struct page *page)
{
- struct inode *inode = page->mapping->host;
+ struct inode *inode = page_file_mapping(page)->host;
struct nfs_page *req = NULL;
spin_lock(&inode->i_lock);
@@ -137,16 +137,16 @@ static struct nfs_page *nfs_page_find_request(struct page *page)
/* Adjust the file length if we're writing beyond the end */
static void nfs_grow_file(struct page *page, unsigned int offset, unsigned int count)
{
- struct inode *inode = page->mapping->host;
+ struct inode *inode = page_file_mapping(page)->host;
loff_t end, i_size;
pgoff_t end_index;
spin_lock(&inode->i_lock);
i_size = i_size_read(inode);
end_index = (i_size - 1) >> PAGE_CACHE_SHIFT;
- if (i_size > 0 && page->index < end_index)
+ if (i_size > 0 && page_file_index(page) < end_index)
goto out;
- end = ((loff_t)page->index << PAGE_CACHE_SHIFT) + ((loff_t)offset+count);
+ end = page_file_offset(page) + ((loff_t)offset+count);
if (i_size >= end)
goto out;
i_size_write(inode, end);
@@ -159,7 +159,7 @@ out:
static void nfs_set_pageerror(struct page *page)
{
SetPageError(page);
- nfs_zap_mapping(page->mapping->host, page->mapping);
+ nfs_zap_mapping(page_file_mapping(page)->host, page_file_mapping(page));
}
/* We can set the PG_uptodate flag if we see that a write request
@@ -200,7 +200,7 @@ static int nfs_set_page_writeback(struct page *page)
int ret = test_set_page_writeback(page);
if (!ret) {
- struct inode *inode = page->mapping->host;
+ struct inode *inode = page_file_mapping(page)->host;
struct nfs_server *nfss = NFS_SERVER(inode);
page_cache_get(page);
@@ -215,7 +215,7 @@ static int nfs_set_page_writeback(struct page *page)
static void nfs_end_page_writeback(struct page *page)
{
- struct inode *inode = page->mapping->host;
+ struct inode *inode = page_file_mapping(page)->host;
struct nfs_server *nfss = NFS_SERVER(inode);
end_page_writeback(page);
@@ -226,7 +226,7 @@ static void nfs_end_page_writeback(struct page *page)
static struct nfs_page *nfs_find_and_lock_request(struct page *page, bool nonblock)
{
- struct inode *inode = page->mapping->host;
+ struct inode *inode = page_file_mapping(page)->host;
struct nfs_page *req;
int ret;
@@ -287,13 +287,13 @@ out:
static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, struct nfs_pageio_descriptor *pgio)
{
- struct inode *inode = page->mapping->host;
+ struct inode *inode = page_file_mapping(page)->host;
int ret;
nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE);
nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1);
- nfs_pageio_cond_complete(pgio, page->index);
+ nfs_pageio_cond_complete(pgio, page_file_index(page));
ret = nfs_page_async_flush(pgio, page, wbc->sync_mode == WB_SYNC_NONE);
if (ret == -EAGAIN) {
redirty_page_for_writepage(wbc, page);
@@ -310,7 +310,8 @@ static int nfs_writepage_locked(struct page *page, struct writeback_control *wbc
struct nfs_pageio_descriptor pgio;
int err;
- nfs_pageio_init_write(&pgio, page->mapping->host, wb_priority(wbc));
+ nfs_pageio_init_write(&pgio, page_file_mapping(page)->host,
+ wb_priority(wbc));
err = nfs_do_writepage(page, wbc, &pgio);
nfs_pageio_complete(&pgio);
if (err < 0)
@@ -428,7 +429,8 @@ static void
nfs_mark_request_dirty(struct nfs_page *req)
{
__set_page_dirty_nobuffers(req->wb_page);
- __mark_inode_dirty(req->wb_page->mapping->host, I_DIRTY_DATASYNC);
+ __mark_inode_dirty(page_file_mapping(req->wb_page)->host,
+ I_DIRTY_DATASYNC);
}
#if defined(CONFIG_NFS_V3) || defined(CONFIG_NFS_V4)
@@ -450,7 +452,8 @@ nfs_mark_request_commit(struct nfs_page *req, struct pnfs_layout_segment *lseg)
spin_unlock(&inode->i_lock);
pnfs_mark_request_commit(req, lseg);
inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
- inc_bdi_stat(req->wb_page->mapping->backing_dev_info, BDI_RECLAIMABLE);
+ inc_bdi_stat(page_file_mapping(req->wb_page)->backing_dev_info,
+ BDI_RECLAIMABLE);
__mark_inode_dirty(inode, I_DIRTY_DATASYNC);
}
@@ -461,7 +464,8 @@ nfs_clear_request_commit(struct nfs_page *req)
if (test_and_clear_bit(PG_CLEAN, &(req)->wb_flags)) {
dec_zone_page_state(page, NR_UNSTABLE_NFS);
- dec_bdi_stat(page->mapping->backing_dev_info, BDI_RECLAIMABLE);
+ dec_bdi_stat(page_file_mapping(page)->backing_dev_info,
+ BDI_RECLAIMABLE);
return 1;
}
return 0;
@@ -527,7 +531,7 @@ nfs_need_commit(struct nfs_inode *nfsi)
* nfs_scan_commit - Scan an inode for commit requests
* @inode: NFS inode to scan
* @dst: destination list
- * @idx_start: lower bound of page->index to scan.
+ * @idx_start: lower bound of page_file_index(page) to scan.
* @npages: idx_start + npages sets the upper bound to scan.
*
* Moves requests from the inode's 'commit' request list.
@@ -653,7 +657,7 @@ out_err:
static struct nfs_page * nfs_setup_write_request(struct nfs_open_context* ctx,
struct page *page, unsigned int offset, unsigned int bytes)
{
- struct inode *inode = page->mapping->host;
+ struct inode *inode = page_file_mapping(page)->host;
struct nfs_page *req;
int error;
@@ -711,7 +715,7 @@ int nfs_flush_incompatible(struct file *file, struct page *page)
nfs_release_request(req);
if (!do_flush)
return 0;
- status = nfs_wb_page(page->mapping->host, page);
+ status = nfs_wb_page(page_file_mapping(page)->host, page);
} while (status == 0);
return status;
}
@@ -737,7 +741,7 @@ int nfs_updatepage(struct file *file, struct page *page,
unsigned int offset, unsigned int count)
{
struct nfs_open_context *ctx = nfs_file_open_context(file);
- struct inode *inode = page->mapping->host;
+ struct inode *inode = page_file_mapping(page)->host;
int status = 0;
nfs_inc_stats(inode, NFSIOS_VFSUPDATEPAGE);
@@ -745,7 +749,7 @@ int nfs_updatepage(struct file *file, struct page *page,
dprintk("NFS: nfs_updatepage(%s/%s %d@%lld)\n",
file->f_path.dentry->d_parent->d_name.name,
file->f_path.dentry->d_name.name, count,
- (long long)(page_offset(page) + offset));
+ (long long)(page_file_offset(page) + offset));
/* If we're not using byte range locks, and we know the page
* is up to date, it may be more efficient to extend the write
@@ -1104,7 +1108,7 @@ static void nfs_writeback_release_partial(void *calldata)
}
if (nfs_write_need_commit(data)) {
- struct inode *inode = page->mapping->host;
+ struct inode *inode = page_file_mapping(page)->host;
spin_lock(&inode->i_lock);
if (test_bit(PG_NEED_RESCHED, &req->wb_flags)) {
@@ -1409,7 +1413,7 @@ void nfs_retry_commit(struct list_head *page_list,
nfs_list_remove_request(req);
nfs_mark_request_commit(req, lseg);
dec_zone_page_state(req->wb_page, NR_UNSTABLE_NFS);
- dec_bdi_stat(req->wb_page->mapping->backing_dev_info,
+ dec_bdi_stat(page_file_mapping(req->wb_page)->backing_dev_info,
BDI_RECLAIMABLE);
nfs_clear_page_tag_locked(req);
}
--
1.7.3.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related
* [PATCH 05/10] mm: Methods for teaching filesystems about PG_swapcache pages
From: Mel Gorman @ 2011-09-09 11:00 UTC (permalink / raw)
To: Linux-MM
Cc: Linux-Netdev, Linux-NFS, LKML, Andrew Morton, David Miller,
Trond Myklebust, Neil Brown, Peter Zijlstra, Mel Gorman
In-Reply-To: <1315566054-17209-1-git-send-email-mgorman@suse.de>
In order to teach filesystems to handle swap cache pages, three new
page functions are introduced:
pgoff_t page_file_index(struct page *);
loff_t page_file_offset(struct page *);
struct address_space *page_file_mapping(struct page *);
page_file_index() - gives the offset of this page in the file in
PAGE_CACHE_SIZE blocks. Like page->index is for mapped pages, this
function also gives the correct index for PG_swapcache pages.
page_file_offset() - uses page_file_index(), so that it will give
the expected result, even for PG_swapcache pages.
page_file_mapping() - gives the mapping backing the actual page;
that is for swap cache pages it will give swap_file->f_mapping.
Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl>
Signed-off-by: Mel Gorman <mgorman@suse.de>
---
include/linux/mm.h | 25 +++++++++++++++++++++++++
include/linux/pagemap.h | 5 +++++
mm/swapfile.c | 19 +++++++++++++++++++
3 files changed, 49 insertions(+), 0 deletions(-)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 7438071..45442a8 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -787,6 +787,17 @@ static inline void *page_rmapping(struct page *page)
return (void *)((unsigned long)page->mapping & ~PAGE_MAPPING_FLAGS);
}
+extern struct address_space *__page_file_mapping(struct page *);
+
+static inline
+struct address_space *page_file_mapping(struct page *page)
+{
+ if (unlikely(PageSwapCache(page)))
+ return __page_file_mapping(page);
+
+ return page->mapping;
+}
+
static inline int PageAnon(struct page *page)
{
return ((unsigned long)page->mapping & PAGE_MAPPING_ANON) != 0;
@@ -803,6 +814,20 @@ static inline pgoff_t page_index(struct page *page)
return page->index;
}
+extern pgoff_t __page_file_index(struct page *page);
+
+/*
+ * Return the file index of the page. Regular pagecache pages use ->index
+ * whereas swapcache pages use swp_offset(->private)
+ */
+static inline pgoff_t page_file_index(struct page *page)
+{
+ if (unlikely(PageSwapCache(page)))
+ return __page_file_index(page);
+
+ return page->index;
+}
+
/*
* The atomic page->_mapcount, like _count, starts from -1:
* so that transitions both from it and to it can be tracked,
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index cfaaa69..d4d4bda 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -286,6 +286,11 @@ static inline loff_t page_offset(struct page *page)
return ((loff_t)page->index) << PAGE_CACHE_SHIFT;
}
+static inline loff_t page_file_offset(struct page *page)
+{
+ return ((loff_t)page_file_index(page)) << PAGE_CACHE_SHIFT;
+}
+
extern pgoff_t linear_hugepage_index(struct vm_area_struct *vma,
unsigned long address);
diff --git a/mm/swapfile.c b/mm/swapfile.c
index c49cb33..806b994 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -2232,6 +2232,25 @@ struct swap_info_struct *page_swap_info(struct page *page)
}
/*
+ * out-of-line __page_file_ methods to avoid include hell.
+ */
+
+struct address_space *__page_file_mapping(struct page *page)
+{
+ VM_BUG_ON(!PageSwapCache(page));
+ return page_swap_info(page)->swap_file->f_mapping;
+}
+EXPORT_SYMBOL_GPL(__page_file_mapping);
+
+pgoff_t __page_file_index(struct page *page)
+{
+ swp_entry_t swap = { .val = page_private(page) };
+ VM_BUG_ON(!PageSwapCache(page));
+ return swp_offset(swap);
+}
+EXPORT_SYMBOL_GPL(__page_file_index);
+
+/*
* swap_lock prevents swap_map being freed. Don't grab an extra
* reference on the swaphandle, it doesn't matter if it becomes unused.
*/
--
1.7.3.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related
* [PATCH 04/10] mm: swap: Implement generic handlers for swap-related address ops
From: Mel Gorman @ 2011-09-09 11:00 UTC (permalink / raw)
To: Linux-MM
Cc: Linux-Netdev, Linux-NFS, LKML, Andrew Morton, David Miller,
Trond Myklebust, Neil Brown, Peter Zijlstra, Mel Gorman
In-Reply-To: <1315566054-17209-1-git-send-email-mgorman@suse.de>
With the introduction of swap_activate, swap_writepage and
swap_readpage, there is a number of SWP_FILE checks that call a_ops and
fallback to generic handlers. This patch clarifies things by creating
generic versions of these functions and passing in all the information
required to implement a generic handler so the same information is
available to filesystems. This removes the need for SWP_FILE and
cleans up the flow slightly. There are no functional changes.
Signed-off-by: Mel Gorman <mgorman@suse.de>
---
include/linux/fs.h | 7 ++-
include/linux/swap.h | 6 ++-
mm/page_io.c | 184 +++++++++++++++++++++++++++++++++++++++-----------
mm/swapfile.c | 102 +++-------------------------
4 files changed, 162 insertions(+), 137 deletions(-)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 387b767..dd93bb1 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -581,6 +581,8 @@ typedef struct {
typedef int (*read_actor_t)(read_descriptor_t *, struct page *,
unsigned long, unsigned long);
+struct swap_info_struct;
+
struct address_space_operations {
int (*writepage)(struct page *page, struct writeback_control *wbc);
int (*readpage)(struct file *, struct page *);
@@ -619,8 +621,9 @@ struct address_space_operations {
int (*error_remove_page)(struct address_space *, struct page *);
/* swapfile support */
- int (*swap_activate)(struct file *file);
- int (*swap_deactivate)(struct file *file);
+ int (*swap_activate)(struct swap_info_struct *sis, struct file *file,
+ sector_t *span);
+ void (*swap_deactivate)(struct file *file);
int (*swap_writepage)(struct file *file, struct page *page,
struct writeback_control *wbc);
int (*swap_readpage)(struct file *file, struct page *page);
diff --git a/include/linux/swap.h b/include/linux/swap.h
index a044198..195ae15 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -148,7 +148,6 @@ enum {
SWP_SOLIDSTATE = (1 << 4), /* blkdev seeks are cheap */
SWP_CONTINUED = (1 << 5), /* swap_map has count continuation */
SWP_BLKDEV = (1 << 6), /* its a block device */
- SWP_FILE = (1 << 7), /* set after swap_activate success */
/* add others here before... */
SWP_SCANNING = (1 << 8), /* refcount in scan_swap_map */
};
@@ -307,6 +306,11 @@ extern int swap_writepage(struct page *page, struct writeback_control *wbc);
extern int swap_set_page_dirty(struct page *page);
extern void end_swap_bio_read(struct bio *bio, int err);
+int add_swap_extent(struct swap_info_struct *, unsigned long start_pfn,
+ unsigned long nr_pages, sector_t);
+int generic_swapfile_activate(struct swap_info_struct *, struct file *,
+ sector_t *);
+
/* linux/mm/swap_state.c */
extern struct address_space swapper_space;
#define total_swapcache_pages swapper_space.nrpages
diff --git a/mm/page_io.c b/mm/page_io.c
index 5ed5710..6ea49d3 100644
--- a/mm/page_io.c
+++ b/mm/page_io.c
@@ -86,87 +86,189 @@ void end_swap_bio_read(struct bio *bio, int err)
bio_put(bio);
}
+int generic_swap_writepage(struct page *page, struct writeback_control *wbc)
+{
+ struct bio *bio;
+ int rw = WRITE;
+
+ bio = get_swap_bio(GFP_NOIO, page, end_swap_bio_write);
+ if (bio == NULL) {
+ set_page_dirty(page);
+ unlock_page(page);
+ return -ENOMEM;
+ }
+ if (wbc->sync_mode == WB_SYNC_ALL)
+ rw |= REQ_SYNC;
+ count_vm_event(PSWPOUT);
+ set_page_writeback(page);
+ unlock_page(page);
+ submit_bio(rw, bio);
+
+ return 0;
+}
+
+int generic_swap_readpage(struct page *page)
+{
+ struct bio *bio;
+ bio = get_swap_bio(GFP_KERNEL, page, end_swap_bio_read);
+ if (bio == NULL) {
+ unlock_page(page);
+ return -ENOMEM;
+ }
+ count_vm_event(PSWPIN);
+ submit_bio(READ, bio);
+
+ return 0;
+}
+
+int generic_swapfile_activate(struct swap_info_struct *sis,
+ struct file *swap_file,
+ sector_t *span)
+{
+ struct address_space *mapping = swap_file->f_mapping;
+ struct inode *inode = mapping->host;
+ unsigned blocks_per_page;
+ unsigned long page_no;
+ unsigned blkbits;
+ sector_t probe_block;
+ sector_t last_block;
+ sector_t lowest_block = -1;
+ sector_t highest_block = 0;
+ int nr_extents = 0;
+ int ret;
+
+ blkbits = inode->i_blkbits;
+ blocks_per_page = PAGE_SIZE >> blkbits;
+
+ /*
+ * Map all the blocks into the extent list. This code doesn't try
+ * to be very smart.
+ */
+ probe_block = 0;
+ page_no = 0;
+ last_block = i_size_read(inode) >> blkbits;
+ while ((probe_block + blocks_per_page) <= last_block &&
+ page_no < sis->max) {
+ unsigned block_in_page;
+ sector_t first_block;
+
+ first_block = bmap(inode, probe_block);
+ if (first_block == 0)
+ goto bad_bmap;
+
+ /*
+ * It must be PAGE_SIZE aligned on-disk
+ */
+ if (first_block & (blocks_per_page - 1)) {
+ probe_block++;
+ goto reprobe;
+ }
+
+ for (block_in_page = 1; block_in_page < blocks_per_page;
+ block_in_page++) {
+ sector_t block;
+
+ block = bmap(inode, probe_block + block_in_page);
+ if (block == 0)
+ goto bad_bmap;
+ if (block != first_block + block_in_page) {
+ /* Discontiguity */
+ probe_block++;
+ goto reprobe;
+ }
+ }
+
+ first_block >>= (PAGE_SHIFT - blkbits);
+ if (page_no) { /* exclude the header page */
+ if (first_block < lowest_block)
+ lowest_block = first_block;
+ if (first_block > highest_block)
+ highest_block = first_block;
+ }
+
+ /*
+ * We found a PAGE_SIZE-length, PAGE_SIZE-aligned run of blocks
+ */
+ ret = add_swap_extent(sis, page_no, 1, first_block);
+ if (ret < 0)
+ goto out;
+ nr_extents += ret;
+ page_no++;
+ probe_block += blocks_per_page;
+reprobe:
+ continue;
+ }
+ ret = nr_extents;
+ *span = 1 + highest_block - lowest_block;
+ if (page_no == 0)
+ page_no = 1; /* force Empty message */
+ sis->max = page_no;
+ sis->pages = page_no - 1;
+ sis->highest_bit = page_no - 1;
+out:
+ return ret;
+bad_bmap:
+ printk(KERN_ERR "swapon: swapfile has holes\n");
+ ret = -EINVAL;
+ goto out;
+}
/*
* We may have stale swap cache pages in memory: notice
* them here and get rid of the unnecessary final write.
*/
int swap_writepage(struct page *page, struct writeback_control *wbc)
{
- struct bio *bio;
- int ret = 0, rw = WRITE;
+ int ret = 0;
struct swap_info_struct *sis = page_swap_info(page);
+ struct file *swap_file;
+ struct address_space *mapping;
if (try_to_free_swap(page)) {
unlock_page(page);
- goto out;
+ return ret;
}
- if (sis->flags & SWP_FILE) {
- struct file *swap_file = sis->swap_file;
- struct address_space *mapping = swap_file->f_mapping;
-
+ swap_file = sis->swap_file;
+ mapping = swap_file->f_mapping;
+ if (mapping->a_ops->swap_writepage) {
ret = mapping->a_ops->swap_writepage(swap_file, page, wbc);
if (!ret)
count_vm_event(PSWPOUT);
return ret;
}
- bio = get_swap_bio(GFP_NOIO, page, end_swap_bio_write);
- if (bio == NULL) {
- set_page_dirty(page);
- unlock_page(page);
- ret = -ENOMEM;
- goto out;
- }
- if (wbc->sync_mode == WB_SYNC_ALL)
- rw |= REQ_SYNC;
- count_vm_event(PSWPOUT);
- set_page_writeback(page);
- unlock_page(page);
- submit_bio(rw, bio);
-out:
- return ret;
+ return generic_swap_writepage(page, wbc);
}
int swap_readpage(struct page *page)
{
- struct bio *bio;
int ret = 0;
struct swap_info_struct *sis = page_swap_info(page);
+ struct file *swap_file;
+ struct address_space *mapping;
VM_BUG_ON(!PageLocked(page));
VM_BUG_ON(PageUptodate(page));
- if (sis->flags & SWP_FILE) {
- struct file *swap_file = sis->swap_file;
- struct address_space *mapping = swap_file->f_mapping;
-
+ swap_file = sis->swap_file;
+ mapping = swap_file->f_mapping;
+ if (mapping->a_ops->swap_readpage) {
ret = mapping->a_ops->swap_readpage(swap_file, page);
if (!ret)
count_vm_event(PSWPIN);
return ret;
}
- bio = get_swap_bio(GFP_KERNEL, page, end_swap_bio_read);
- if (bio == NULL) {
- unlock_page(page);
- ret = -ENOMEM;
- goto out;
- }
- count_vm_event(PSWPIN);
- submit_bio(READ, bio);
-out:
- return ret;
+ return generic_swap_readpage(page);
}
int swap_set_page_dirty(struct page *page)
{
struct swap_info_struct *sis = page_swap_info(page);
+ struct address_space *mapping = sis->swap_file->f_mapping;
- if (sis->flags & SWP_FILE) {
- struct address_space *mapping = sis->swap_file->f_mapping;
+ if (mapping->a_ops->set_page_dirty)
return mapping->a_ops->set_page_dirty(page);
- } else {
+ else
return __set_page_dirty_nobuffers(page);
- }
}
diff --git a/mm/swapfile.c b/mm/swapfile.c
index f181884..c49cb33 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -1335,6 +1335,9 @@ sector_t map_swap_page(struct page *page, struct block_device **bdev)
*/
static void destroy_swap_extents(struct swap_info_struct *sis)
{
+ struct file *swap_file = sis->swap_file;
+ struct address_space *mapping = swap_file->f_mapping;
+
while (!list_empty(&sis->first_swap_extent.list)) {
struct swap_extent *se;
@@ -1344,13 +1347,8 @@ static void destroy_swap_extents(struct swap_info_struct *sis)
kfree(se);
}
- if (sis->flags & SWP_FILE) {
- struct file *swap_file = sis->swap_file;
- struct address_space *mapping = swap_file->f_mapping;
-
- sis->flags &= ~SWP_FILE;
+ if (mapping->a_ops->swap_deactivate)
mapping->a_ops->swap_deactivate(swap_file);
- }
}
/*
@@ -1359,7 +1357,7 @@ static void destroy_swap_extents(struct swap_info_struct *sis)
*
* This function rather assumes that it is called in ascending page order.
*/
-static int
+int
add_swap_extent(struct swap_info_struct *sis, unsigned long start_page,
unsigned long nr_pages, sector_t start_block)
{
@@ -1435,106 +1433,24 @@ static int setup_swap_extents(struct swap_info_struct *sis, sector_t *span)
struct file *swap_file = sis->swap_file;
struct address_space *mapping = swap_file->f_mapping;
struct inode *inode = mapping->host;
- unsigned blocks_per_page;
- unsigned long page_no;
- unsigned blkbits;
- sector_t probe_block;
- sector_t last_block;
- sector_t lowest_block = -1;
- sector_t highest_block = 0;
- int nr_extents = 0;
int ret;
if (S_ISBLK(inode->i_mode)) {
ret = add_swap_extent(sis, 0, sis->max, 0);
*span = sis->pages;
- goto out;
+ return ret;
}
if (mapping->a_ops->swap_activate) {
- ret = mapping->a_ops->swap_activate(swap_file);
+ ret = mapping->a_ops->swap_activate(sis, swap_file, span);
if (!ret) {
- sis->flags |= SWP_FILE;
ret = add_swap_extent(sis, 0, sis->max, 0);
*span = sis->pages;
}
- goto out;
+ return ret;
}
- blkbits = inode->i_blkbits;
- blocks_per_page = PAGE_SIZE >> blkbits;
-
- /*
- * Map all the blocks into the extent list. This code doesn't try
- * to be very smart.
- */
- probe_block = 0;
- page_no = 0;
- last_block = i_size_read(inode) >> blkbits;
- while ((probe_block + blocks_per_page) <= last_block &&
- page_no < sis->max) {
- unsigned block_in_page;
- sector_t first_block;
-
- first_block = bmap(inode, probe_block);
- if (first_block == 0)
- goto bad_bmap;
-
- /*
- * It must be PAGE_SIZE aligned on-disk
- */
- if (first_block & (blocks_per_page - 1)) {
- probe_block++;
- goto reprobe;
- }
-
- for (block_in_page = 1; block_in_page < blocks_per_page;
- block_in_page++) {
- sector_t block;
-
- block = bmap(inode, probe_block + block_in_page);
- if (block == 0)
- goto bad_bmap;
- if (block != first_block + block_in_page) {
- /* Discontiguity */
- probe_block++;
- goto reprobe;
- }
- }
-
- first_block >>= (PAGE_SHIFT - blkbits);
- if (page_no) { /* exclude the header page */
- if (first_block < lowest_block)
- lowest_block = first_block;
- if (first_block > highest_block)
- highest_block = first_block;
- }
-
- /*
- * We found a PAGE_SIZE-length, PAGE_SIZE-aligned run of blocks
- */
- ret = add_swap_extent(sis, page_no, 1, first_block);
- if (ret < 0)
- goto out;
- nr_extents += ret;
- page_no++;
- probe_block += blocks_per_page;
-reprobe:
- continue;
- }
- ret = nr_extents;
- *span = 1 + highest_block - lowest_block;
- if (page_no == 0)
- page_no = 1; /* force Empty message */
- sis->max = page_no;
- sis->pages = page_no - 1;
- sis->highest_bit = page_no - 1;
-out:
- return ret;
-bad_bmap:
- printk(KERN_ERR "swapon: swapfile has holes\n");
- ret = -EINVAL;
- goto out;
+ return generic_swapfile_activate(sis, swap_file, span);
}
static void enable_swap_info(struct swap_info_struct *p, int prio,
--
1.7.3.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related
* [PATCH 03/10] mm: Add support for a filesystem to control swap files
From: Mel Gorman @ 2011-09-09 11:00 UTC (permalink / raw)
To: Linux-MM
Cc: Linux-Netdev, Linux-NFS, LKML, Andrew Morton, David Miller,
Trond Myklebust, Neil Brown, Peter Zijlstra, Mel Gorman
In-Reply-To: <1315566054-17209-1-git-send-email-mgorman@suse.de>
Currently swapfiles are managed entirely by the core VM by using
->bmap to allocate space and write to the blocks directly. This
patch adds address_space_operations methods that allow a filesystem
to optionally control the swapfile.
int swap_activate(struct file *);
int swap_deactivate(struct file *);
int swap_writepage(struct file *, struct page *, struct writeback_control *);
int swap_readpage(struct file *, struct page *);
The ->swap_activate() method is used to communicate to the file
that the VM relies on it, and the address_space should take adequate
measures such as reserving space in the underlying device, reserving
memory for mempools etc. The ->swap_deactivate() method is called on
sys_swapoff() if ->swap_activate() returned success.
After a successful swapfile ->swap_activate, the swapfile
is marked SWP_FILE and swapper_space.a_ops will proxy to
sis->swap_file->f_mappings->a_ops using ->swap_readpage and
->swap_writepage tp read/write swapcache pages.
The primary user of this interface is expected to be NFS for supporting
swap-over-NFS which is why the existing readpage/writepage interface
is not used. For writing a swap page on NFS, the struct file * is
needed for a credential context that is not passed into writepage.
[a.p.zijlstra@chello.nl: Original patch]
Signed-off-by: Mel Gorman <mgorman@suse.de>
---
Documentation/filesystems/Locking | 23 +++++++++++++++++++++++
Documentation/filesystems/vfs.txt | 21 +++++++++++++++++++++
include/linux/fs.h | 7 +++++++
include/linux/swap.h | 3 +++
mm/page_io.c | 37 +++++++++++++++++++++++++++++++++++++
mm/swap_state.c | 2 +-
mm/swapfile.c | 30 ++++++++++++++++++++++++++++--
7 files changed, 120 insertions(+), 3 deletions(-)
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking
index 6533807..7f534f4 100644
--- a/Documentation/filesystems/Locking
+++ b/Documentation/filesystems/Locking
@@ -201,6 +201,10 @@ prototypes:
int (*launder_page)(struct page *);
int (*is_partially_uptodate)(struct page *, read_descriptor_t *, unsigned long);
int (*error_remove_page)(struct address_space *, struct page *);
+ int (*swap_activate)(struct file *);
+ int (*swap_deactivate)(struct file *);
+ int (*swap_out)(struct file *, struct page *, struct writeback_control *);
+ int (*swap_in)(struct file *, struct page *);
locking rules:
All except set_page_dirty and freepage may block
@@ -224,6 +228,10 @@ migratepage: yes (both)
launder_page: yes
is_partially_uptodate: yes
error_remove_page: yes
+swap_activate: no
+swap_deactivate: no
+swap_out no yes, unlocks
+swap_in no yes, unlocks
->write_begin(), ->write_end(), ->sync_page() and ->readpage()
may be called from the request handler (/dev/loop).
@@ -325,6 +333,21 @@ cleaned, or an error value if not. Note that in order to prevent the page
getting mapped back in and redirtied, it needs to be kept locked
across the entire operation.
+ ->swap_activate will be called with a non-zero argument on
+files backing (non block device backed) swapfiles. A return value
+of zero indicates success, in which case this file can be used for
+backing swapspace. The swapspace operations will be proxied to the
+address space operations.
+
+ ->swap_deactivate() will be called in the sys_swapoff()
+path after ->swap_activate() returned success.
+
+ ->swap_writepage() is usable after swap_activate() returned
+success. This method is used to write a swap page.
+
+ ->swap_readpage() is usable after swap_activate() returned
+success, this method is used to read a swap page.
+
----------------------- file_lock_operations ------------------------------
prototypes:
void (*fl_copy_lock)(struct file_lock *, struct file_lock *);
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index 52d8fb8..8378eaa 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -581,6 +581,11 @@ struct address_space_operations {
int (*migratepage) (struct page *, struct page *);
int (*launder_page) (struct page *);
int (*error_remove_page) (struct mapping *mapping, struct page *page);
+ int (*swap_activate)(struct file *);
+ int (*swap_deactivate)(struct file *);
+ int (*swap_out)(struct file *, struct page *,
+ struct writeback_control *);
+ int (*swap_in)(struct file *, struct page *);
};
writepage: called by the VM to write a dirty page to backing store.
@@ -749,6 +754,22 @@ struct address_space_operations {
Setting this implies you deal with pages going away under you,
unless you have them locked or reference counts increased.
+ swap_activate: Called when swapon is used on a file to allocating
+ space if necessary and perform any other necessary
+ housekeeping. A return value of zero indicates success,
+ in which case this file can be used to back swapspace. The
+ swapspace operations will be proxied to this address space's
+ ->swap_{out,in} methods.
+
+ swap_deactivate: Called during swapoff on files where swap_activate
+ was successful.
+
+ swap_writepage: Called to write a swapcache page to a backing store,
+ similar to writepage.
+
+ swap_readpage: Called to read a swapcache page from a backing store,
+ similar to readpage.
+
The File Object
===============
diff --git a/include/linux/fs.h b/include/linux/fs.h
index c2bd68f..387b767 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -617,6 +617,13 @@ struct address_space_operations {
int (*is_partially_uptodate) (struct page *, read_descriptor_t *,
unsigned long);
int (*error_remove_page)(struct address_space *, struct page *);
+
+ /* swapfile support */
+ int (*swap_activate)(struct file *file);
+ int (*swap_deactivate)(struct file *file);
+ int (*swap_writepage)(struct file *file, struct page *page,
+ struct writeback_control *wbc);
+ int (*swap_readpage)(struct file *file, struct page *page);
};
extern const struct address_space_operations empty_aops;
diff --git a/include/linux/swap.h b/include/linux/swap.h
index 14d6249..a044198 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -148,6 +148,7 @@ enum {
SWP_SOLIDSTATE = (1 << 4), /* blkdev seeks are cheap */
SWP_CONTINUED = (1 << 5), /* swap_map has count continuation */
SWP_BLKDEV = (1 << 6), /* its a block device */
+ SWP_FILE = (1 << 7), /* set after swap_activate success */
/* add others here before... */
SWP_SCANNING = (1 << 8), /* refcount in scan_swap_map */
};
@@ -303,6 +304,7 @@ static inline int mem_cgroup_swappiness(struct mem_cgroup *mem)
/* linux/mm/page_io.c */
extern int swap_readpage(struct page *);
extern int swap_writepage(struct page *page, struct writeback_control *wbc);
+extern int swap_set_page_dirty(struct page *page);
extern void end_swap_bio_read(struct bio *bio, int err);
/* linux/mm/swap_state.c */
@@ -339,6 +341,7 @@ extern int swap_type_of(dev_t, sector_t, struct block_device **);
extern unsigned int count_swap_pages(int, int);
extern sector_t map_swap_page(struct page *, struct block_device **);
extern sector_t swapdev_block(int, pgoff_t);
+extern struct swap_info_struct *page_swap_info(struct page *);
extern int reuse_swap_page(struct page *);
extern int try_to_free_swap(struct page *);
struct backing_dev_info;
diff --git a/mm/page_io.c b/mm/page_io.c
index dc76b4d..5ed5710 100644
--- a/mm/page_io.c
+++ b/mm/page_io.c
@@ -17,6 +17,7 @@
#include <linux/swap.h>
#include <linux/bio.h>
#include <linux/swapops.h>
+#include <linux/buffer_head.h>
#include <linux/writeback.h>
#include <asm/pgtable.h>
@@ -93,11 +94,23 @@ int swap_writepage(struct page *page, struct writeback_control *wbc)
{
struct bio *bio;
int ret = 0, rw = WRITE;
+ struct swap_info_struct *sis = page_swap_info(page);
if (try_to_free_swap(page)) {
unlock_page(page);
goto out;
}
+
+ if (sis->flags & SWP_FILE) {
+ struct file *swap_file = sis->swap_file;
+ struct address_space *mapping = swap_file->f_mapping;
+
+ ret = mapping->a_ops->swap_writepage(swap_file, page, wbc);
+ if (!ret)
+ count_vm_event(PSWPOUT);
+ return ret;
+ }
+
bio = get_swap_bio(GFP_NOIO, page, end_swap_bio_write);
if (bio == NULL) {
set_page_dirty(page);
@@ -119,9 +132,21 @@ int swap_readpage(struct page *page)
{
struct bio *bio;
int ret = 0;
+ struct swap_info_struct *sis = page_swap_info(page);
VM_BUG_ON(!PageLocked(page));
VM_BUG_ON(PageUptodate(page));
+
+ if (sis->flags & SWP_FILE) {
+ struct file *swap_file = sis->swap_file;
+ struct address_space *mapping = swap_file->f_mapping;
+
+ ret = mapping->a_ops->swap_readpage(swap_file, page);
+ if (!ret)
+ count_vm_event(PSWPIN);
+ return ret;
+ }
+
bio = get_swap_bio(GFP_KERNEL, page, end_swap_bio_read);
if (bio == NULL) {
unlock_page(page);
@@ -133,3 +158,15 @@ int swap_readpage(struct page *page)
out:
return ret;
}
+
+int swap_set_page_dirty(struct page *page)
+{
+ struct swap_info_struct *sis = page_swap_info(page);
+
+ if (sis->flags & SWP_FILE) {
+ struct address_space *mapping = sis->swap_file->f_mapping;
+ return mapping->a_ops->set_page_dirty(page);
+ } else {
+ return __set_page_dirty_nobuffers(page);
+ }
+}
diff --git a/mm/swap_state.c b/mm/swap_state.c
index 4668046..787ca54 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -28,7 +28,7 @@
*/
static const struct address_space_operations swap_aops = {
.writepage = swap_writepage,
- .set_page_dirty = __set_page_dirty_nobuffers,
+ .set_page_dirty = swap_set_page_dirty,
.migratepage = migrate_page,
};
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 17bc224..f181884 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -1343,6 +1343,14 @@ static void destroy_swap_extents(struct swap_info_struct *sis)
list_del(&se->list);
kfree(se);
}
+
+ if (sis->flags & SWP_FILE) {
+ struct file *swap_file = sis->swap_file;
+ struct address_space *mapping = swap_file->f_mapping;
+
+ sis->flags &= ~SWP_FILE;
+ mapping->a_ops->swap_deactivate(swap_file);
+ }
}
/*
@@ -1424,7 +1432,9 @@ add_swap_extent(struct swap_info_struct *sis, unsigned long start_page,
*/
static int setup_swap_extents(struct swap_info_struct *sis, sector_t *span)
{
- struct inode *inode;
+ struct file *swap_file = sis->swap_file;
+ struct address_space *mapping = swap_file->f_mapping;
+ struct inode *inode = mapping->host;
unsigned blocks_per_page;
unsigned long page_no;
unsigned blkbits;
@@ -1435,13 +1445,22 @@ static int setup_swap_extents(struct swap_info_struct *sis, sector_t *span)
int nr_extents = 0;
int ret;
- inode = sis->swap_file->f_mapping->host;
if (S_ISBLK(inode->i_mode)) {
ret = add_swap_extent(sis, 0, sis->max, 0);
*span = sis->pages;
goto out;
}
+ if (mapping->a_ops->swap_activate) {
+ ret = mapping->a_ops->swap_activate(swap_file);
+ if (!ret) {
+ sis->flags |= SWP_FILE;
+ ret = add_swap_extent(sis, 0, sis->max, 0);
+ *span = sis->pages;
+ }
+ goto out;
+ }
+
blkbits = inode->i_blkbits;
blocks_per_page = PAGE_SIZE >> blkbits;
@@ -2289,6 +2308,13 @@ int swapcache_prepare(swp_entry_t entry)
return __swap_duplicate(entry, SWAP_HAS_CACHE);
}
+struct swap_info_struct *page_swap_info(struct page *page)
+{
+ swp_entry_t swap = { .val = page_private(page) };
+ BUG_ON(!PageSwapCache(page));
+ return swap_info[swp_type(swap)];
+}
+
/*
* swap_lock prevents swap_map being freed. Don't grab an extra
* reference on the swaphandle, it doesn't matter if it becomes unused.
--
1.7.3.4
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox