Merge "Merge remote-tracking branch 'quic/tmp-d8ff506' into LA.BR.1.3.3 HEAD"
This commit is contained in:
commit
8a02c8bfaf
|
@ -0,0 +1,16 @@
|
|||
What: /sys/kernel/wakeup_reasons/last_resume_reason
|
||||
Date: February 2014
|
||||
Contact: Ruchi Kandoi <kandoiruchi@google.com>
|
||||
Description:
|
||||
The /sys/kernel/wakeup_reasons/last_resume_reason is
|
||||
used to report wakeup reasons after system exited suspend.
|
||||
|
||||
What: /sys/kernel/wakeup_reasons/last_suspend_time
|
||||
Date: March 2015
|
||||
Contact: jinqian <jinqian@google.com>
|
||||
Description:
|
||||
The /sys/kernel/wakeup_reasons/last_suspend_time is
|
||||
used to report time spent in last suspend cycle. It contains
|
||||
two numbers (in seconds) separated by space. First number is
|
||||
the time spent in suspend and resume processes. Second number
|
||||
is the time spent in sleep state.
|
|
@ -10,7 +10,7 @@ Construction Parameters
|
|||
<version> <dev> <hash_dev>
|
||||
<data_block_size> <hash_block_size>
|
||||
<num_data_blocks> <hash_start_block>
|
||||
<algorithm> <digest> <salt>
|
||||
<algorithm> <digest> <salt> <mode>
|
||||
|
||||
<version>
|
||||
This is the type of the on-disk hash format.
|
||||
|
@ -62,6 +62,16 @@ Construction Parameters
|
|||
<salt>
|
||||
The hexadecimal encoding of the salt value.
|
||||
|
||||
<mode>
|
||||
Optional. The mode of operation.
|
||||
|
||||
0 is the normal mode of operation where a corrupted block will result in an
|
||||
I/O error.
|
||||
|
||||
1 is logging mode where corrupted blocks are logged and a uevent is sent to
|
||||
notify user space.
|
||||
|
||||
|
||||
Theory of operation
|
||||
===================
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ Optional properties:
|
|||
- cap-mmc-highspeed: MMC high-speed timing is supported
|
||||
- cap-power-off-card: powering off the card is safe
|
||||
- cap-sdio-irq: enable SDIO IRQ signalling on this interface
|
||||
- full-pwr-cycle: full power cycle of the card is supported
|
||||
|
||||
*NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line
|
||||
polarity properties, we have to fix the meaning of the "normal" and "inverted"
|
||||
|
|
|
@ -445,3 +445,6 @@ object doesn't exist. It's remote/distributed ones that might care...
|
|||
[mandatory]
|
||||
FS_REVAL_DOT is gone; if you used to have it, add ->d_weak_revalidate()
|
||||
in your dentry operations instead.
|
||||
--
|
||||
[mandatory]
|
||||
vfs_readdir() is gone; switch to iterate_dir() instead
|
||||
|
|
|
@ -491,6 +491,10 @@ To clear the bits for the file mapped pages associated with the process
|
|||
> echo 3 > /proc/PID/clear_refs
|
||||
Any other value written to /proc/PID/clear_refs will have no effect.
|
||||
|
||||
To reset the peak resident set size ("high water mark") to the process's
|
||||
current value:
|
||||
> echo 5 > /proc/PID/clear_refs
|
||||
|
||||
The file /proc/PID/reclaim is used to reclaim pages in this process.
|
||||
To reclaim file-backed pages,
|
||||
> echo file > /proc/PID/reclaim
|
||||
|
@ -525,50 +529,50 @@ files are there, and which are missing.
|
|||
|
||||
Table 1-5: Kernel info in /proc
|
||||
..............................................................................
|
||||
File Content
|
||||
apm Advanced power management info
|
||||
File Content
|
||||
apm Advanced power management info
|
||||
buddyinfo Kernel memory allocator information (see text) (2.5)
|
||||
bus Directory containing bus specific information
|
||||
cmdline Kernel command line
|
||||
cpuinfo Info about the CPU
|
||||
devices Available devices (block and character)
|
||||
dma Used DMS channels
|
||||
filesystems Supported filesystems
|
||||
bus Directory containing bus specific information
|
||||
cmdline Kernel command line
|
||||
cpuinfo Info about the CPU
|
||||
devices Available devices (block and character)
|
||||
dma Used DMS channels
|
||||
filesystems Supported filesystems
|
||||
driver Various drivers grouped here, currently rtc (2.4)
|
||||
execdomains Execdomains, related to security (2.4)
|
||||
fb Frame Buffer devices (2.4)
|
||||
fs File system parameters, currently nfs/exports (2.4)
|
||||
ide Directory containing info about the IDE subsystem
|
||||
interrupts Interrupt usage
|
||||
ide Directory containing info about the IDE subsystem
|
||||
interrupts Interrupt usage
|
||||
iomem Memory map (2.4)
|
||||
ioports I/O port usage
|
||||
ioports I/O port usage
|
||||
irq Masks for irq to cpu affinity (2.4)(smp?)
|
||||
isapnp ISA PnP (Plug&Play) Info (2.4)
|
||||
kcore Kernel core image (can be ELF or A.OUT(deprecated in 2.4))
|
||||
kmsg Kernel messages
|
||||
ksyms Kernel symbol table
|
||||
loadavg Load average of last 1, 5 & 15 minutes
|
||||
locks Kernel locks
|
||||
meminfo Memory info
|
||||
misc Miscellaneous
|
||||
modules List of loaded modules
|
||||
mounts Mounted filesystems
|
||||
net Networking info (see text)
|
||||
kcore Kernel core image (can be ELF or A.OUT(deprecated in 2.4))
|
||||
kmsg Kernel messages
|
||||
ksyms Kernel symbol table
|
||||
loadavg Load average of last 1, 5 & 15 minutes
|
||||
locks Kernel locks
|
||||
meminfo Memory info
|
||||
misc Miscellaneous
|
||||
modules List of loaded modules
|
||||
mounts Mounted filesystems
|
||||
net Networking info (see text)
|
||||
pagetypeinfo Additional page allocator information (see text) (2.5)
|
||||
partitions Table of partitions known to the system
|
||||
partitions Table of partitions known to the system
|
||||
pci Deprecated info of PCI bus (new way -> /proc/bus/pci/,
|
||||
decoupled by lspci (2.4)
|
||||
rtc Real time clock
|
||||
scsi SCSI info (see text)
|
||||
slabinfo Slab pool info
|
||||
rtc Real time clock
|
||||
scsi SCSI info (see text)
|
||||
slabinfo Slab pool info
|
||||
softirqs softirq usage
|
||||
stat Overall statistics
|
||||
swaps Swap space utilization
|
||||
sys See chapter 2
|
||||
stat Overall statistics
|
||||
swaps Swap space utilization
|
||||
sys See chapter 2
|
||||
sysvipc Info of SysVIPC Resources (msg, sem, shm) (2.4)
|
||||
tty Info of tty drivers
|
||||
uptime System uptime
|
||||
version Kernel version
|
||||
uptime System uptime
|
||||
version Kernel version
|
||||
video bttv info of video resources (2.4)
|
||||
vmallocinfo Show vmalloced areas
|
||||
..............................................................................
|
||||
|
@ -576,28 +580,28 @@ Table 1-5: Kernel info in /proc
|
|||
You can, for example, check which interrupts are currently in use and what
|
||||
they are used for by looking in the file /proc/interrupts:
|
||||
|
||||
> cat /proc/interrupts
|
||||
CPU0
|
||||
0: 8728810 XT-PIC timer
|
||||
1: 895 XT-PIC keyboard
|
||||
2: 0 XT-PIC cascade
|
||||
3: 531695 XT-PIC aha152x
|
||||
4: 2014133 XT-PIC serial
|
||||
5: 44401 XT-PIC pcnet_cs
|
||||
8: 2 XT-PIC rtc
|
||||
11: 8 XT-PIC i82365
|
||||
12: 182918 XT-PIC PS/2 Mouse
|
||||
13: 1 XT-PIC fpu
|
||||
14: 1232265 XT-PIC ide0
|
||||
15: 7 XT-PIC ide1
|
||||
NMI: 0
|
||||
> cat /proc/interrupts
|
||||
CPU0
|
||||
0: 8728810 XT-PIC timer
|
||||
1: 895 XT-PIC keyboard
|
||||
2: 0 XT-PIC cascade
|
||||
3: 531695 XT-PIC aha152x
|
||||
4: 2014133 XT-PIC serial
|
||||
5: 44401 XT-PIC pcnet_cs
|
||||
8: 2 XT-PIC rtc
|
||||
11: 8 XT-PIC i82365
|
||||
12: 182918 XT-PIC PS/2 Mouse
|
||||
13: 1 XT-PIC fpu
|
||||
14: 1232265 XT-PIC ide0
|
||||
15: 7 XT-PIC ide1
|
||||
NMI: 0
|
||||
|
||||
In 2.4.* a couple of lines where added to this file LOC & ERR (this time is the
|
||||
output of a SMP machine):
|
||||
|
||||
> cat /proc/interrupts
|
||||
> cat /proc/interrupts
|
||||
|
||||
CPU0 CPU1
|
||||
CPU0 CPU1
|
||||
0: 1243498 1214548 IO-APIC-edge timer
|
||||
1: 8949 8958 IO-APIC-edge keyboard
|
||||
2: 0 0 XT-PIC cascade
|
||||
|
@ -610,8 +614,8 @@ output of a SMP machine):
|
|||
15: 2183 2415 IO-APIC-edge ide1
|
||||
17: 30564 30414 IO-APIC-level eth0
|
||||
18: 177 164 IO-APIC-level bttv
|
||||
NMI: 2457961 2457959
|
||||
LOC: 2457882 2457881
|
||||
NMI: 2457961 2457959
|
||||
LOC: 2457882 2457881
|
||||
ERR: 2155
|
||||
|
||||
NMI is incremented in this case because every timer interrupt generates a NMI
|
||||
|
@ -658,7 +662,7 @@ IRQ to only one CPU, or to exclude a CPU of handling IRQs. The contents of the
|
|||
irq subdir is one subdir for each IRQ, and two files; default_smp_affinity and
|
||||
prof_cpu_mask.
|
||||
|
||||
For example
|
||||
For example
|
||||
> ls /proc/irq/
|
||||
0 10 12 14 16 18 2 4 6 8 prof_cpu_mask
|
||||
1 11 13 15 17 19 3 5 7 9 default_smp_affinity
|
||||
|
@ -721,14 +725,14 @@ Node 0, zone Normal 1 0 0 1 101 8 ...
|
|||
Node 0, zone HighMem 2 0 0 1 1 0 ...
|
||||
|
||||
External fragmentation is a problem under some workloads, and buddyinfo is a
|
||||
useful tool for helping diagnose these problems. Buddyinfo will give you a
|
||||
useful tool for helping diagnose these problems. Buddyinfo will give you a
|
||||
clue as to how big an area you can safely allocate, or why a previous
|
||||
allocation failed.
|
||||
|
||||
Each column represents the number of pages of a certain order which are
|
||||
available. In this case, there are 0 chunks of 2^0*PAGE_SIZE available in
|
||||
ZONE_DMA, 4 chunks of 2^1*PAGE_SIZE in ZONE_DMA, 101 chunks of 2^4*PAGE_SIZE
|
||||
available in ZONE_NORMAL, etc...
|
||||
Each column represents the number of pages of a certain order which are
|
||||
available. In this case, there are 0 chunks of 2^0*PAGE_SIZE available in
|
||||
ZONE_DMA, 4 chunks of 2^1*PAGE_SIZE in ZONE_DMA, 101 chunks of 2^4*PAGE_SIZE
|
||||
available in ZONE_NORMAL, etc...
|
||||
|
||||
More information relevant to external fragmentation can be found in
|
||||
pagetypeinfo.
|
||||
|
@ -974,11 +978,11 @@ directories contains the files shown in table 1-6.
|
|||
|
||||
Table 1-6: IDE controller info in /proc/ide/ide?
|
||||
..............................................................................
|
||||
File Content
|
||||
channel IDE channel (0 or 1)
|
||||
config Configuration (only for PCI/IDE bridge)
|
||||
mate Mate name
|
||||
model Type/Chipset of IDE controller
|
||||
File Content
|
||||
channel IDE channel (0 or 1)
|
||||
config Configuration (only for PCI/IDE bridge)
|
||||
mate Mate name
|
||||
model Type/Chipset of IDE controller
|
||||
..............................................................................
|
||||
|
||||
Each device connected to a controller has a separate subdirectory in the
|
||||
|
@ -988,41 +992,41 @@ directories.
|
|||
|
||||
Table 1-7: IDE device information
|
||||
..............................................................................
|
||||
File Content
|
||||
cache The cache
|
||||
capacity Capacity of the medium (in 512Byte blocks)
|
||||
driver driver and version
|
||||
geometry physical and logical geometry
|
||||
identify device identify block
|
||||
media media type
|
||||
model device identifier
|
||||
settings device setup
|
||||
smart_thresholds IDE disk management thresholds
|
||||
smart_values IDE disk management values
|
||||
File Content
|
||||
cache The cache
|
||||
capacity Capacity of the medium (in 512Byte blocks)
|
||||
driver driver and version
|
||||
geometry physical and logical geometry
|
||||
identify device identify block
|
||||
media media type
|
||||
model device identifier
|
||||
settings device setup
|
||||
smart_thresholds IDE disk management thresholds
|
||||
smart_values IDE disk management values
|
||||
..............................................................................
|
||||
|
||||
The most interesting file is settings. This file contains a nice overview of
|
||||
the drive parameters:
|
||||
|
||||
# cat /proc/ide/ide0/hda/settings
|
||||
name value min max mode
|
||||
---- ----- --- --- ----
|
||||
bios_cyl 526 0 65535 rw
|
||||
bios_head 255 0 255 rw
|
||||
bios_sect 63 0 63 rw
|
||||
breada_readahead 4 0 127 rw
|
||||
bswap 0 0 1 r
|
||||
file_readahead 72 0 2097151 rw
|
||||
io_32bit 0 0 3 rw
|
||||
keepsettings 0 0 1 rw
|
||||
max_kb_per_request 122 1 127 rw
|
||||
multcount 0 0 8 rw
|
||||
nice1 1 0 1 rw
|
||||
nowerr 0 0 1 rw
|
||||
pio_mode write-only 0 255 w
|
||||
slow 0 0 1 rw
|
||||
unmaskirq 0 0 1 rw
|
||||
using_dma 0 0 1 rw
|
||||
# cat /proc/ide/ide0/hda/settings
|
||||
name value min max mode
|
||||
---- ----- --- --- ----
|
||||
bios_cyl 526 0 65535 rw
|
||||
bios_head 255 0 255 rw
|
||||
bios_sect 63 0 63 rw
|
||||
breada_readahead 4 0 127 rw
|
||||
bswap 0 0 1 r
|
||||
file_readahead 72 0 2097151 rw
|
||||
io_32bit 0 0 3 rw
|
||||
keepsettings 0 0 1 rw
|
||||
max_kb_per_request 122 1 127 rw
|
||||
multcount 0 0 8 rw
|
||||
nice1 1 0 1 rw
|
||||
nowerr 0 0 1 rw
|
||||
pio_mode write-only 0 255 w
|
||||
slow 0 0 1 rw
|
||||
unmaskirq 0 0 1 rw
|
||||
using_dma 0 0 1 rw
|
||||
|
||||
|
||||
1.4 Networking info in /proc/net
|
||||
|
@ -1035,65 +1039,65 @@ support this. Table 1-9 lists the files and their meaning.
|
|||
|
||||
Table 1-8: IPv6 info in /proc/net
|
||||
..............................................................................
|
||||
File Content
|
||||
udp6 UDP sockets (IPv6)
|
||||
tcp6 TCP sockets (IPv6)
|
||||
raw6 Raw device statistics (IPv6)
|
||||
igmp6 IP multicast addresses, which this host joined (IPv6)
|
||||
if_inet6 List of IPv6 interface addresses
|
||||
ipv6_route Kernel routing table for IPv6
|
||||
rt6_stats Global IPv6 routing tables statistics
|
||||
sockstat6 Socket statistics (IPv6)
|
||||
snmp6 Snmp data (IPv6)
|
||||
File Content
|
||||
udp6 UDP sockets (IPv6)
|
||||
tcp6 TCP sockets (IPv6)
|
||||
raw6 Raw device statistics (IPv6)
|
||||
igmp6 IP multicast addresses, which this host joined (IPv6)
|
||||
if_inet6 List of IPv6 interface addresses
|
||||
ipv6_route Kernel routing table for IPv6
|
||||
rt6_stats Global IPv6 routing tables statistics
|
||||
sockstat6 Socket statistics (IPv6)
|
||||
snmp6 Snmp data (IPv6)
|
||||
..............................................................................
|
||||
|
||||
|
||||
Table 1-9: Network info in /proc/net
|
||||
..............................................................................
|
||||
File Content
|
||||
arp Kernel ARP table
|
||||
dev network devices with statistics
|
||||
File Content
|
||||
arp Kernel ARP table
|
||||
dev network devices with statistics
|
||||
dev_mcast the Layer2 multicast groups a device is listening too
|
||||
(interface index, label, number of references, number of bound
|
||||
addresses).
|
||||
dev_stat network device status
|
||||
ip_fwchains Firewall chain linkage
|
||||
ip_fwnames Firewall chain names
|
||||
ip_masq Directory containing the masquerading tables
|
||||
ip_masquerade Major masquerading table
|
||||
netstat Network statistics
|
||||
raw raw device statistics
|
||||
route Kernel routing table
|
||||
rpc Directory containing rpc info
|
||||
rt_cache Routing cache
|
||||
snmp SNMP data
|
||||
sockstat Socket statistics
|
||||
tcp TCP sockets
|
||||
udp UDP sockets
|
||||
unix UNIX domain sockets
|
||||
wireless Wireless interface data (Wavelan etc)
|
||||
igmp IP multicast addresses, which this host joined
|
||||
psched Global packet scheduler parameters.
|
||||
netlink List of PF_NETLINK sockets
|
||||
ip_mr_vifs List of multicast virtual interfaces
|
||||
ip_mr_cache List of multicast routing cache
|
||||
addresses).
|
||||
dev_stat network device status
|
||||
ip_fwchains Firewall chain linkage
|
||||
ip_fwnames Firewall chain names
|
||||
ip_masq Directory containing the masquerading tables
|
||||
ip_masquerade Major masquerading table
|
||||
netstat Network statistics
|
||||
raw raw device statistics
|
||||
route Kernel routing table
|
||||
rpc Directory containing rpc info
|
||||
rt_cache Routing cache
|
||||
snmp SNMP data
|
||||
sockstat Socket statistics
|
||||
tcp TCP sockets
|
||||
udp UDP sockets
|
||||
unix UNIX domain sockets
|
||||
wireless Wireless interface data (Wavelan etc)
|
||||
igmp IP multicast addresses, which this host joined
|
||||
psched Global packet scheduler parameters.
|
||||
netlink List of PF_NETLINK sockets
|
||||
ip_mr_vifs List of multicast virtual interfaces
|
||||
ip_mr_cache List of multicast routing cache
|
||||
..............................................................................
|
||||
|
||||
You can use this information to see which network devices are available in
|
||||
your system and how much traffic was routed over those devices:
|
||||
|
||||
> cat /proc/net/dev
|
||||
Inter-|Receive |[...
|
||||
face |bytes packets errs drop fifo frame compressed multicast|[...
|
||||
lo: 908188 5596 0 0 0 0 0 0 [...
|
||||
ppp0:15475140 20721 410 0 0 410 0 0 [...
|
||||
eth0: 614530 7085 0 0 0 0 0 1 [...
|
||||
|
||||
...] Transmit
|
||||
...] bytes packets errs drop fifo colls carrier compressed
|
||||
...] 908188 5596 0 0 0 0 0 0
|
||||
...] 1375103 17405 0 0 0 0 0 0
|
||||
...] 1703981 5535 0 0 0 3 0 0
|
||||
> cat /proc/net/dev
|
||||
Inter-|Receive |[...
|
||||
face |bytes packets errs drop fifo frame compressed multicast|[...
|
||||
lo: 908188 5596 0 0 0 0 0 0 [...
|
||||
ppp0:15475140 20721 410 0 0 410 0 0 [...
|
||||
eth0: 614530 7085 0 0 0 0 0 1 [...
|
||||
|
||||
...] Transmit
|
||||
...] bytes packets errs drop fifo colls carrier compressed
|
||||
...] 908188 5596 0 0 0 0 0 0
|
||||
...] 1375103 17405 0 0 0 0 0 0
|
||||
...] 1703981 5535 0 0 0 3 0 0
|
||||
|
||||
In addition, each Channel Bond interface has its own directory. For
|
||||
example, the bond0 device will have a directory called /proc/net/bond0/.
|
||||
|
@ -1108,14 +1112,14 @@ If you have a SCSI host adapter in your system, you'll find a subdirectory
|
|||
named after the driver for this adapter in /proc/scsi. You'll also see a list
|
||||
of all recognized SCSI devices in /proc/scsi:
|
||||
|
||||
>cat /proc/scsi/scsi
|
||||
Attached devices:
|
||||
Host: scsi0 Channel: 00 Id: 00 Lun: 00
|
||||
Vendor: IBM Model: DGHS09U Rev: 03E0
|
||||
Type: Direct-Access ANSI SCSI revision: 03
|
||||
Host: scsi0 Channel: 00 Id: 06 Lun: 00
|
||||
Vendor: PIONEER Model: CD-ROM DR-U06S Rev: 1.04
|
||||
Type: CD-ROM ANSI SCSI revision: 02
|
||||
>cat /proc/scsi/scsi
|
||||
Attached devices:
|
||||
Host: scsi0 Channel: 00 Id: 00 Lun: 00
|
||||
Vendor: IBM Model: DGHS09U Rev: 03E0
|
||||
Type: Direct-Access ANSI SCSI revision: 03
|
||||
Host: scsi0 Channel: 00 Id: 06 Lun: 00
|
||||
Vendor: PIONEER Model: CD-ROM DR-U06S Rev: 1.04
|
||||
Type: CD-ROM ANSI SCSI revision: 02
|
||||
|
||||
|
||||
The directory named after the driver has one file for each adapter found in
|
||||
|
@ -1124,44 +1128,44 @@ the used IRQ and the IO address range. The amount of information shown is
|
|||
dependent on the adapter you use. The example shows the output for an Adaptec
|
||||
AHA-2940 SCSI adapter:
|
||||
|
||||
> cat /proc/scsi/aic7xxx/0
|
||||
|
||||
Adaptec AIC7xxx driver version: 5.1.19/3.2.4
|
||||
Compile Options:
|
||||
TCQ Enabled By Default : Disabled
|
||||
AIC7XXX_PROC_STATS : Disabled
|
||||
AIC7XXX_RESET_DELAY : 5
|
||||
Adapter Configuration:
|
||||
SCSI Adapter: Adaptec AHA-294X Ultra SCSI host adapter
|
||||
Ultra Wide Controller
|
||||
PCI MMAPed I/O Base: 0xeb001000
|
||||
Adapter SEEPROM Config: SEEPROM found and used.
|
||||
Adaptec SCSI BIOS: Enabled
|
||||
IRQ: 10
|
||||
SCBs: Active 0, Max Active 2,
|
||||
Allocated 15, HW 16, Page 255
|
||||
Interrupts: 160328
|
||||
BIOS Control Word: 0x18b6
|
||||
Adapter Control Word: 0x005b
|
||||
Extended Translation: Enabled
|
||||
Disconnect Enable Flags: 0xffff
|
||||
Ultra Enable Flags: 0x0001
|
||||
Tag Queue Enable Flags: 0x0000
|
||||
Ordered Queue Tag Flags: 0x0000
|
||||
Default Tag Queue Depth: 8
|
||||
Tagged Queue By Device array for aic7xxx host instance 0:
|
||||
{255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255}
|
||||
Actual queue depth per device for aic7xxx host instance 0:
|
||||
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}
|
||||
Statistics:
|
||||
(scsi0:0:0:0)
|
||||
Device using Wide/Sync transfers at 40.0 MByte/sec, offset 8
|
||||
Transinfo settings: current(12/8/1/0), goal(12/8/1/0), user(12/15/1/0)
|
||||
Total transfers 160151 (74577 reads and 85574 writes)
|
||||
(scsi0:0:6:0)
|
||||
Device using Narrow/Sync transfers at 5.0 MByte/sec, offset 15
|
||||
Transinfo settings: current(50/15/0/0), goal(50/15/0/0), user(50/15/0/0)
|
||||
Total transfers 0 (0 reads and 0 writes)
|
||||
> cat /proc/scsi/aic7xxx/0
|
||||
|
||||
Adaptec AIC7xxx driver version: 5.1.19/3.2.4
|
||||
Compile Options:
|
||||
TCQ Enabled By Default : Disabled
|
||||
AIC7XXX_PROC_STATS : Disabled
|
||||
AIC7XXX_RESET_DELAY : 5
|
||||
Adapter Configuration:
|
||||
SCSI Adapter: Adaptec AHA-294X Ultra SCSI host adapter
|
||||
Ultra Wide Controller
|
||||
PCI MMAPed I/O Base: 0xeb001000
|
||||
Adapter SEEPROM Config: SEEPROM found and used.
|
||||
Adaptec SCSI BIOS: Enabled
|
||||
IRQ: 10
|
||||
SCBs: Active 0, Max Active 2,
|
||||
Allocated 15, HW 16, Page 255
|
||||
Interrupts: 160328
|
||||
BIOS Control Word: 0x18b6
|
||||
Adapter Control Word: 0x005b
|
||||
Extended Translation: Enabled
|
||||
Disconnect Enable Flags: 0xffff
|
||||
Ultra Enable Flags: 0x0001
|
||||
Tag Queue Enable Flags: 0x0000
|
||||
Ordered Queue Tag Flags: 0x0000
|
||||
Default Tag Queue Depth: 8
|
||||
Tagged Queue By Device array for aic7xxx host instance 0:
|
||||
{255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255}
|
||||
Actual queue depth per device for aic7xxx host instance 0:
|
||||
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}
|
||||
Statistics:
|
||||
(scsi0:0:0:0)
|
||||
Device using Wide/Sync transfers at 40.0 MByte/sec, offset 8
|
||||
Transinfo settings: current(12/8/1/0), goal(12/8/1/0), user(12/15/1/0)
|
||||
Total transfers 160151 (74577 reads and 85574 writes)
|
||||
(scsi0:0:6:0)
|
||||
Device using Narrow/Sync transfers at 5.0 MByte/sec, offset 15
|
||||
Transinfo settings: current(50/15/0/0), goal(50/15/0/0), user(50/15/0/0)
|
||||
Total transfers 0 (0 reads and 0 writes)
|
||||
|
||||
|
||||
1.6 Parallel port info in /proc/parport
|
||||
|
@ -1176,15 +1180,15 @@ These directories contain the four files shown in Table 1-10.
|
|||
|
||||
Table 1-10: Files in /proc/parport
|
||||
..............................................................................
|
||||
File Content
|
||||
autoprobe Any IEEE-1284 device ID information that has been acquired.
|
||||
File Content
|
||||
autoprobe Any IEEE-1284 device ID information that has been acquired.
|
||||
devices list of the device drivers using that port. A + will appear by the
|
||||
name of the device currently using the port (it might not appear
|
||||
against any).
|
||||
hardware Parallel port's base address, IRQ line and DMA channel.
|
||||
against any).
|
||||
hardware Parallel port's base address, IRQ line and DMA channel.
|
||||
irq IRQ that parport is using for that port. This is in a separate
|
||||
file to allow you to alter it by writing a new value in (IRQ
|
||||
number or none).
|
||||
number or none).
|
||||
..............................................................................
|
||||
|
||||
1.7 TTY info in /proc/tty
|
||||
|
@ -1197,27 +1201,27 @@ this directory, as shown in Table 1-11.
|
|||
|
||||
Table 1-11: Files in /proc/tty
|
||||
..............................................................................
|
||||
File Content
|
||||
drivers list of drivers and their usage
|
||||
ldiscs registered line disciplines
|
||||
driver/serial usage statistic and status of single tty lines
|
||||
File Content
|
||||
drivers list of drivers and their usage
|
||||
ldiscs registered line disciplines
|
||||
driver/serial usage statistic and status of single tty lines
|
||||
..............................................................................
|
||||
|
||||
To see which tty's are currently in use, you can simply look into the file
|
||||
/proc/tty/drivers:
|
||||
|
||||
> cat /proc/tty/drivers
|
||||
pty_slave /dev/pts 136 0-255 pty:slave
|
||||
pty_master /dev/ptm 128 0-255 pty:master
|
||||
pty_slave /dev/ttyp 3 0-255 pty:slave
|
||||
pty_master /dev/pty 2 0-255 pty:master
|
||||
serial /dev/cua 5 64-67 serial:callout
|
||||
serial /dev/ttyS 4 64-67 serial
|
||||
/dev/tty0 /dev/tty0 4 0 system:vtmaster
|
||||
/dev/ptmx /dev/ptmx 5 2 system
|
||||
/dev/console /dev/console 5 1 system:console
|
||||
/dev/tty /dev/tty 5 0 system:/dev/tty
|
||||
unknown /dev/tty 4 1-63 console
|
||||
> cat /proc/tty/drivers
|
||||
pty_slave /dev/pts 136 0-255 pty:slave
|
||||
pty_master /dev/ptm 128 0-255 pty:master
|
||||
pty_slave /dev/ttyp 3 0-255 pty:slave
|
||||
pty_master /dev/pty 2 0-255 pty:master
|
||||
serial /dev/cua 5 64-67 serial:callout
|
||||
serial /dev/ttyS 4 64-67 serial
|
||||
/dev/tty0 /dev/tty0 4 0 system:vtmaster
|
||||
/dev/ptmx /dev/ptmx 5 2 system
|
||||
/dev/console /dev/console 5 1 system:console
|
||||
/dev/tty /dev/tty 5 0 system:/dev/tty
|
||||
unknown /dev/tty 4 1-63 console
|
||||
|
||||
|
||||
1.8 Miscellaneous kernel statistics in /proc/stat
|
||||
|
@ -1292,7 +1296,7 @@ in Table 1-12, below.
|
|||
|
||||
Table 1-12: Files in /proc/fs/ext4/<devname>
|
||||
..............................................................................
|
||||
File Content
|
||||
File Content
|
||||
mb_groups details of multiblock allocator buddy cache of free blocks
|
||||
..............................................................................
|
||||
|
||||
|
|
|
@ -2,10 +2,10 @@ SQUASHFS 4.0 FILESYSTEM
|
|||
=======================
|
||||
|
||||
Squashfs is a compressed read-only filesystem for Linux.
|
||||
It uses zlib/lzo/xz compression to compress files, inodes and directories.
|
||||
Inodes in the system are very small and all blocks are packed to minimise
|
||||
data overhead. Block sizes greater than 4K are supported up to a maximum
|
||||
of 1Mbytes (default block size 128K).
|
||||
It uses zlib, lz4, lzo, or xz compression to compress files, inodes and
|
||||
directories. Inodes in the system are very small and all blocks are packed to
|
||||
minimise data overhead. Block sizes greater than 4K are supported up to a
|
||||
maximum of 1Mbytes (default block size 128K).
|
||||
|
||||
Squashfs is intended for general read-only filesystem use, for archival
|
||||
use (i.e. in cases where a .tar.gz file may be used), and in constrained
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
# CONFIG_OABI_COMPAT is not set
|
||||
CONFIG_ANDROID=y
|
||||
CONFIG_ANDROID_BINDER_IPC=y
|
||||
CONFIG_ANDROID_INTF_ALARM_DEV=y
|
||||
CONFIG_ANDROID_LOW_MEMORY_KILLER=y
|
||||
CONFIG_ARMV7_COMPAT=y
|
||||
CONFIG_ASHMEM=y
|
||||
CONFIG_AUDIT=y
|
||||
CONFIG_BLK_DEV_DM=y
|
||||
CONFIG_BLK_DEV_INITRD=y
|
||||
CONFIG_CGROUPS=y
|
||||
|
@ -50,6 +50,7 @@ CONFIG_IP_NF_MATCH_AH=y
|
|||
CONFIG_IP_NF_MATCH_ECN=y
|
||||
CONFIG_IP_NF_MATCH_TTL=y
|
||||
CONFIG_IP_NF_RAW=y
|
||||
CONFIG_IP_NF_SECURITY=y
|
||||
CONFIG_IP_NF_TARGET_MASQUERADE=y
|
||||
CONFIG_IP_NF_TARGET_NETMAP=y
|
||||
CONFIG_IP_NF_TARGET_REDIRECT=y
|
||||
|
@ -84,10 +85,12 @@ CONFIG_NETFILTER_XT_MATCH_TIME=y
|
|||
CONFIG_NETFILTER_XT_MATCH_U32=y
|
||||
CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
|
||||
CONFIG_NETFILTER_XT_TARGET_CONNMARK=y
|
||||
CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y
|
||||
CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y
|
||||
CONFIG_NETFILTER_XT_TARGET_MARK=y
|
||||
CONFIG_NETFILTER_XT_TARGET_NFLOG=y
|
||||
CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y
|
||||
CONFIG_NETFILTER_XT_TARGET_SECMARK=y
|
||||
CONFIG_NETFILTER_XT_TARGET_TCPMSS=y
|
||||
CONFIG_NETFILTER_XT_TARGET_TPROXY=y
|
||||
CONFIG_NETFILTER_XT_TARGET_TRACE=y
|
||||
|
@ -109,6 +112,7 @@ CONFIG_NF_CONNTRACK_IRC=y
|
|||
CONFIG_NF_CONNTRACK_NETBIOS_NS=y
|
||||
CONFIG_NF_CONNTRACK_PPTP=y
|
||||
CONFIG_NF_CONNTRACK_SANE=y
|
||||
CONFIG_NF_CONNTRACK_SECMARK=y
|
||||
CONFIG_NF_CONNTRACK_TFTP=y
|
||||
CONFIG_NF_CT_NETLINK=y
|
||||
CONFIG_NF_CT_PROTO_DCCP=y
|
||||
|
@ -129,6 +133,11 @@ CONFIG_PREEMPT=y
|
|||
CONFIG_RESOURCE_COUNTERS=y
|
||||
CONFIG_RTC_CLASS=y
|
||||
CONFIG_RT_GROUP_SCHED=y
|
||||
CONFIG_SECURITY=y
|
||||
CONFIG_SECURITY_NETWORK=y
|
||||
CONFIG_SECURITY_SELINUX=y
|
||||
CONFIG_SND=y
|
||||
CONFIG_SOUND=y
|
||||
CONFIG_STAGING=y
|
||||
CONFIG_SWITCH=y
|
||||
CONFIG_SYNC=y
|
||||
|
|
|
@ -96,6 +96,7 @@ struct osf_dirent {
|
|||
};
|
||||
|
||||
struct osf_dirent_callback {
|
||||
struct dir_context ctx;
|
||||
struct osf_dirent __user *dirent;
|
||||
long __user *basep;
|
||||
unsigned int count;
|
||||
|
@ -146,17 +147,17 @@ SYSCALL_DEFINE4(osf_getdirentries, unsigned int, fd,
|
|||
{
|
||||
int error;
|
||||
struct fd arg = fdget(fd);
|
||||
struct osf_dirent_callback buf;
|
||||
struct osf_dirent_callback buf = {
|
||||
.ctx.actor = osf_filldir,
|
||||
.dirent = dirent,
|
||||
.basep = basep,
|
||||
.count = count
|
||||
};
|
||||
|
||||
if (!arg.file)
|
||||
return -EBADF;
|
||||
|
||||
buf.dirent = dirent;
|
||||
buf.basep = basep;
|
||||
buf.count = count;
|
||||
buf.error = 0;
|
||||
|
||||
error = vfs_readdir(arg.file, osf_filldir, &buf);
|
||||
error = iterate_dir(arg.file, &buf.ctx);
|
||||
if (error >= 0)
|
||||
error = buf.error;
|
||||
if (count != buf.count)
|
||||
|
|
|
@ -6,12 +6,15 @@ obj-$(CONFIG_CRYPTO_AES_ARM) += aes-arm.o
|
|||
obj-$(CONFIG_CRYPTO_AES_ARM_BS) += aes-arm-bs.o
|
||||
obj-$(CONFIG_CRYPTO_SHA1_ARM) += sha1-arm.o
|
||||
obj-$(CONFIG_CRYPTO_SHA1_ARM_NEON) += sha1-arm-neon.o
|
||||
obj-$(CONFIG_CRYPTO_SHA256_ARM) += sha256-arm.o
|
||||
obj-$(CONFIG_CRYPTO_SHA512_ARM_NEON) += sha512-arm-neon.o
|
||||
|
||||
aes-arm-y := aes-armv4.o aes_glue.o
|
||||
aes-arm-bs-y := aesbs-core.o aesbs-glue.o
|
||||
sha1-arm-y := sha1-armv4-large.o sha1_glue.o
|
||||
sha1-arm-neon-y := sha1-armv7-neon.o sha1_neon_glue.o
|
||||
sha256-arm-neon-$(CONFIG_KERNEL_MODE_NEON) := sha256_neon_glue.o
|
||||
sha256-arm-y := sha256-core.o sha256_glue.o $(sha256-arm-neon-y)
|
||||
sha512-arm-neon-y := sha512-armv7-neon.o sha512_neon_glue.o
|
||||
|
||||
quiet_cmd_perl = PERL $@
|
||||
|
@ -20,4 +23,7 @@ quiet_cmd_perl = PERL $@
|
|||
$(src)/aesbs-core.S_shipped: $(src)/bsaes-armv7.pl
|
||||
$(call cmd,perl)
|
||||
|
||||
.PRECIOUS: $(obj)/aesbs-core.S
|
||||
$(src)/sha256-core.S_shipped: $(src)/sha256-armv4.pl
|
||||
$(call cmd,perl)
|
||||
|
||||
.PRECIOUS: $(obj)/aesbs-core.S $(obj)/sha256-core.S
|
||||
|
|
|
@ -0,0 +1,716 @@
|
|||
#!/usr/bin/env perl
|
||||
|
||||
# ====================================================================
|
||||
# Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
|
||||
# project. The module is, however, dual licensed under OpenSSL and
|
||||
# CRYPTOGAMS licenses depending on where you obtain it. For further
|
||||
# details see http://www.openssl.org/~appro/cryptogams/.
|
||||
#
|
||||
# Permission to use under GPL terms is granted.
|
||||
# ====================================================================
|
||||
|
||||
# SHA256 block procedure for ARMv4. May 2007.
|
||||
|
||||
# Performance is ~2x better than gcc 3.4 generated code and in "abso-
|
||||
# lute" terms is ~2250 cycles per 64-byte block or ~35 cycles per
|
||||
# byte [on single-issue Xscale PXA250 core].
|
||||
|
||||
# July 2010.
|
||||
#
|
||||
# Rescheduling for dual-issue pipeline resulted in 22% improvement on
|
||||
# Cortex A8 core and ~20 cycles per processed byte.
|
||||
|
||||
# February 2011.
|
||||
#
|
||||
# Profiler-assisted and platform-specific optimization resulted in 16%
|
||||
# improvement on Cortex A8 core and ~15.4 cycles per processed byte.
|
||||
|
||||
# September 2013.
|
||||
#
|
||||
# Add NEON implementation. On Cortex A8 it was measured to process one
|
||||
# byte in 12.5 cycles or 23% faster than integer-only code. Snapdragon
|
||||
# S4 does it in 12.5 cycles too, but it's 50% faster than integer-only
|
||||
# code (meaning that latter performs sub-optimally, nothing was done
|
||||
# about it).
|
||||
|
||||
# May 2014.
|
||||
#
|
||||
# Add ARMv8 code path performing at 2.0 cpb on Apple A7.
|
||||
|
||||
while (($output=shift) && ($output!~/^\w[\w\-]*\.\w+$/)) {}
|
||||
open STDOUT,">$output";
|
||||
|
||||
$ctx="r0"; $t0="r0";
|
||||
$inp="r1"; $t4="r1";
|
||||
$len="r2"; $t1="r2";
|
||||
$T1="r3"; $t3="r3";
|
||||
$A="r4";
|
||||
$B="r5";
|
||||
$C="r6";
|
||||
$D="r7";
|
||||
$E="r8";
|
||||
$F="r9";
|
||||
$G="r10";
|
||||
$H="r11";
|
||||
@V=($A,$B,$C,$D,$E,$F,$G,$H);
|
||||
$t2="r12";
|
||||
$Ktbl="r14";
|
||||
|
||||
@Sigma0=( 2,13,22);
|
||||
@Sigma1=( 6,11,25);
|
||||
@sigma0=( 7,18, 3);
|
||||
@sigma1=(17,19,10);
|
||||
|
||||
sub BODY_00_15 {
|
||||
my ($i,$a,$b,$c,$d,$e,$f,$g,$h) = @_;
|
||||
|
||||
$code.=<<___ if ($i<16);
|
||||
#if __ARM_ARCH__>=7
|
||||
@ ldr $t1,[$inp],#4 @ $i
|
||||
# if $i==15
|
||||
str $inp,[sp,#17*4] @ make room for $t4
|
||||
# endif
|
||||
eor $t0,$e,$e,ror#`$Sigma1[1]-$Sigma1[0]`
|
||||
add $a,$a,$t2 @ h+=Maj(a,b,c) from the past
|
||||
eor $t0,$t0,$e,ror#`$Sigma1[2]-$Sigma1[0]` @ Sigma1(e)
|
||||
# ifndef __ARMEB__
|
||||
rev $t1,$t1
|
||||
# endif
|
||||
#else
|
||||
@ ldrb $t1,[$inp,#3] @ $i
|
||||
add $a,$a,$t2 @ h+=Maj(a,b,c) from the past
|
||||
ldrb $t2,[$inp,#2]
|
||||
ldrb $t0,[$inp,#1]
|
||||
orr $t1,$t1,$t2,lsl#8
|
||||
ldrb $t2,[$inp],#4
|
||||
orr $t1,$t1,$t0,lsl#16
|
||||
# if $i==15
|
||||
str $inp,[sp,#17*4] @ make room for $t4
|
||||
# endif
|
||||
eor $t0,$e,$e,ror#`$Sigma1[1]-$Sigma1[0]`
|
||||
orr $t1,$t1,$t2,lsl#24
|
||||
eor $t0,$t0,$e,ror#`$Sigma1[2]-$Sigma1[0]` @ Sigma1(e)
|
||||
#endif
|
||||
___
|
||||
$code.=<<___;
|
||||
ldr $t2,[$Ktbl],#4 @ *K256++
|
||||
add $h,$h,$t1 @ h+=X[i]
|
||||
str $t1,[sp,#`$i%16`*4]
|
||||
eor $t1,$f,$g
|
||||
add $h,$h,$t0,ror#$Sigma1[0] @ h+=Sigma1(e)
|
||||
and $t1,$t1,$e
|
||||
add $h,$h,$t2 @ h+=K256[i]
|
||||
eor $t1,$t1,$g @ Ch(e,f,g)
|
||||
eor $t0,$a,$a,ror#`$Sigma0[1]-$Sigma0[0]`
|
||||
add $h,$h,$t1 @ h+=Ch(e,f,g)
|
||||
#if $i==31
|
||||
and $t2,$t2,#0xff
|
||||
cmp $t2,#0xf2 @ done?
|
||||
#endif
|
||||
#if $i<15
|
||||
# if __ARM_ARCH__>=7
|
||||
ldr $t1,[$inp],#4 @ prefetch
|
||||
# else
|
||||
ldrb $t1,[$inp,#3]
|
||||
# endif
|
||||
eor $t2,$a,$b @ a^b, b^c in next round
|
||||
#else
|
||||
ldr $t1,[sp,#`($i+2)%16`*4] @ from future BODY_16_xx
|
||||
eor $t2,$a,$b @ a^b, b^c in next round
|
||||
ldr $t4,[sp,#`($i+15)%16`*4] @ from future BODY_16_xx
|
||||
#endif
|
||||
eor $t0,$t0,$a,ror#`$Sigma0[2]-$Sigma0[0]` @ Sigma0(a)
|
||||
and $t3,$t3,$t2 @ (b^c)&=(a^b)
|
||||
add $d,$d,$h @ d+=h
|
||||
eor $t3,$t3,$b @ Maj(a,b,c)
|
||||
add $h,$h,$t0,ror#$Sigma0[0] @ h+=Sigma0(a)
|
||||
@ add $h,$h,$t3 @ h+=Maj(a,b,c)
|
||||
___
|
||||
($t2,$t3)=($t3,$t2);
|
||||
}
|
||||
|
||||
sub BODY_16_XX {
|
||||
my ($i,$a,$b,$c,$d,$e,$f,$g,$h) = @_;
|
||||
|
||||
$code.=<<___;
|
||||
@ ldr $t1,[sp,#`($i+1)%16`*4] @ $i
|
||||
@ ldr $t4,[sp,#`($i+14)%16`*4]
|
||||
mov $t0,$t1,ror#$sigma0[0]
|
||||
add $a,$a,$t2 @ h+=Maj(a,b,c) from the past
|
||||
mov $t2,$t4,ror#$sigma1[0]
|
||||
eor $t0,$t0,$t1,ror#$sigma0[1]
|
||||
eor $t2,$t2,$t4,ror#$sigma1[1]
|
||||
eor $t0,$t0,$t1,lsr#$sigma0[2] @ sigma0(X[i+1])
|
||||
ldr $t1,[sp,#`($i+0)%16`*4]
|
||||
eor $t2,$t2,$t4,lsr#$sigma1[2] @ sigma1(X[i+14])
|
||||
ldr $t4,[sp,#`($i+9)%16`*4]
|
||||
|
||||
add $t2,$t2,$t0
|
||||
eor $t0,$e,$e,ror#`$Sigma1[1]-$Sigma1[0]` @ from BODY_00_15
|
||||
add $t1,$t1,$t2
|
||||
eor $t0,$t0,$e,ror#`$Sigma1[2]-$Sigma1[0]` @ Sigma1(e)
|
||||
add $t1,$t1,$t4 @ X[i]
|
||||
___
|
||||
&BODY_00_15(@_);
|
||||
}
|
||||
|
||||
$code=<<___;
|
||||
#ifndef __KERNEL__
|
||||
# include "arm_arch.h"
|
||||
#else
|
||||
# define __ARM_ARCH__ __LINUX_ARM_ARCH__
|
||||
# define __ARM_MAX_ARCH__ 7
|
||||
#endif
|
||||
|
||||
.text
|
||||
#if __ARM_ARCH__<7
|
||||
.code 32
|
||||
#else
|
||||
.syntax unified
|
||||
# ifdef __thumb2__
|
||||
# define adrl adr
|
||||
.thumb
|
||||
# else
|
||||
.code 32
|
||||
# endif
|
||||
#endif
|
||||
|
||||
.type K256,%object
|
||||
.align 5
|
||||
K256:
|
||||
.word 0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5
|
||||
.word 0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5
|
||||
.word 0xd807aa98,0x12835b01,0x243185be,0x550c7dc3
|
||||
.word 0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174
|
||||
.word 0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc
|
||||
.word 0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da
|
||||
.word 0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7
|
||||
.word 0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967
|
||||
.word 0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13
|
||||
.word 0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85
|
||||
.word 0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3
|
||||
.word 0xd192e819,0xd6990624,0xf40e3585,0x106aa070
|
||||
.word 0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5
|
||||
.word 0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3
|
||||
.word 0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208
|
||||
.word 0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
|
||||
.size K256,.-K256
|
||||
.word 0 @ terminator
|
||||
#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
|
||||
.LOPENSSL_armcap:
|
||||
.word OPENSSL_armcap_P-sha256_block_data_order
|
||||
#endif
|
||||
.align 5
|
||||
|
||||
.global sha256_block_data_order
|
||||
.type sha256_block_data_order,%function
|
||||
sha256_block_data_order:
|
||||
#if __ARM_ARCH__<7
|
||||
sub r3,pc,#8 @ sha256_block_data_order
|
||||
#else
|
||||
adr r3,sha256_block_data_order
|
||||
#endif
|
||||
#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
|
||||
ldr r12,.LOPENSSL_armcap
|
||||
ldr r12,[r3,r12] @ OPENSSL_armcap_P
|
||||
tst r12,#ARMV8_SHA256
|
||||
bne .LARMv8
|
||||
tst r12,#ARMV7_NEON
|
||||
bne .LNEON
|
||||
#endif
|
||||
add $len,$inp,$len,lsl#6 @ len to point at the end of inp
|
||||
stmdb sp!,{$ctx,$inp,$len,r4-r11,lr}
|
||||
ldmia $ctx,{$A,$B,$C,$D,$E,$F,$G,$H}
|
||||
sub $Ktbl,r3,#256+32 @ K256
|
||||
sub sp,sp,#16*4 @ alloca(X[16])
|
||||
.Loop:
|
||||
# if __ARM_ARCH__>=7
|
||||
ldr $t1,[$inp],#4
|
||||
# else
|
||||
ldrb $t1,[$inp,#3]
|
||||
# endif
|
||||
eor $t3,$B,$C @ magic
|
||||
eor $t2,$t2,$t2
|
||||
___
|
||||
for($i=0;$i<16;$i++) { &BODY_00_15($i,@V); unshift(@V,pop(@V)); }
|
||||
$code.=".Lrounds_16_xx:\n";
|
||||
for (;$i<32;$i++) { &BODY_16_XX($i,@V); unshift(@V,pop(@V)); }
|
||||
$code.=<<___;
|
||||
#if __ARM_ARCH__>=7
|
||||
ite eq @ Thumb2 thing, sanity check in ARM
|
||||
#endif
|
||||
ldreq $t3,[sp,#16*4] @ pull ctx
|
||||
bne .Lrounds_16_xx
|
||||
|
||||
add $A,$A,$t2 @ h+=Maj(a,b,c) from the past
|
||||
ldr $t0,[$t3,#0]
|
||||
ldr $t1,[$t3,#4]
|
||||
ldr $t2,[$t3,#8]
|
||||
add $A,$A,$t0
|
||||
ldr $t0,[$t3,#12]
|
||||
add $B,$B,$t1
|
||||
ldr $t1,[$t3,#16]
|
||||
add $C,$C,$t2
|
||||
ldr $t2,[$t3,#20]
|
||||
add $D,$D,$t0
|
||||
ldr $t0,[$t3,#24]
|
||||
add $E,$E,$t1
|
||||
ldr $t1,[$t3,#28]
|
||||
add $F,$F,$t2
|
||||
ldr $inp,[sp,#17*4] @ pull inp
|
||||
ldr $t2,[sp,#18*4] @ pull inp+len
|
||||
add $G,$G,$t0
|
||||
add $H,$H,$t1
|
||||
stmia $t3,{$A,$B,$C,$D,$E,$F,$G,$H}
|
||||
cmp $inp,$t2
|
||||
sub $Ktbl,$Ktbl,#256 @ rewind Ktbl
|
||||
bne .Loop
|
||||
|
||||
add sp,sp,#`16+3`*4 @ destroy frame
|
||||
#if __ARM_ARCH__>=5
|
||||
ldmia sp!,{r4-r11,pc}
|
||||
#else
|
||||
ldmia sp!,{r4-r11,lr}
|
||||
tst lr,#1
|
||||
moveq pc,lr @ be binary compatible with V4, yet
|
||||
bx lr @ interoperable with Thumb ISA:-)
|
||||
#endif
|
||||
.size sha256_block_data_order,.-sha256_block_data_order
|
||||
___
|
||||
######################################################################
|
||||
# NEON stuff
|
||||
#
|
||||
{{{
|
||||
my @X=map("q$_",(0..3));
|
||||
my ($T0,$T1,$T2,$T3,$T4,$T5)=("q8","q9","q10","q11","d24","d25");
|
||||
my $Xfer=$t4;
|
||||
my $j=0;
|
||||
|
||||
sub Dlo() { shift=~m|q([1]?[0-9])|?"d".($1*2):""; }
|
||||
sub Dhi() { shift=~m|q([1]?[0-9])|?"d".($1*2+1):""; }
|
||||
|
||||
sub AUTOLOAD() # thunk [simplified] x86-style perlasm
|
||||
{ my $opcode = $AUTOLOAD; $opcode =~ s/.*:://; $opcode =~ s/_/\./;
|
||||
my $arg = pop;
|
||||
$arg = "#$arg" if ($arg*1 eq $arg);
|
||||
$code .= "\t$opcode\t".join(',',@_,$arg)."\n";
|
||||
}
|
||||
|
||||
sub Xupdate()
|
||||
{ use integer;
|
||||
my $body = shift;
|
||||
my @insns = (&$body,&$body,&$body,&$body);
|
||||
my ($a,$b,$c,$d,$e,$f,$g,$h);
|
||||
|
||||
&vext_8 ($T0,@X[0],@X[1],4); # X[1..4]
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
&vext_8 ($T1,@X[2],@X[3],4); # X[9..12]
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
&vshr_u32 ($T2,$T0,$sigma0[0]);
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
&vadd_i32 (@X[0],@X[0],$T1); # X[0..3] += X[9..12]
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
&vshr_u32 ($T1,$T0,$sigma0[2]);
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
&vsli_32 ($T2,$T0,32-$sigma0[0]);
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
&vshr_u32 ($T3,$T0,$sigma0[1]);
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
&veor ($T1,$T1,$T2);
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
&vsli_32 ($T3,$T0,32-$sigma0[1]);
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
&vshr_u32 ($T4,&Dhi(@X[3]),$sigma1[0]);
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
&veor ($T1,$T1,$T3); # sigma0(X[1..4])
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
&vsli_32 ($T4,&Dhi(@X[3]),32-$sigma1[0]);
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
&vshr_u32 ($T5,&Dhi(@X[3]),$sigma1[2]);
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
&vadd_i32 (@X[0],@X[0],$T1); # X[0..3] += sigma0(X[1..4])
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
&veor ($T5,$T5,$T4);
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
&vshr_u32 ($T4,&Dhi(@X[3]),$sigma1[1]);
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
&vsli_32 ($T4,&Dhi(@X[3]),32-$sigma1[1]);
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
&veor ($T5,$T5,$T4); # sigma1(X[14..15])
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
&vadd_i32 (&Dlo(@X[0]),&Dlo(@X[0]),$T5);# X[0..1] += sigma1(X[14..15])
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
&vshr_u32 ($T4,&Dlo(@X[0]),$sigma1[0]);
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
&vsli_32 ($T4,&Dlo(@X[0]),32-$sigma1[0]);
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
&vshr_u32 ($T5,&Dlo(@X[0]),$sigma1[2]);
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
&veor ($T5,$T5,$T4);
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
&vshr_u32 ($T4,&Dlo(@X[0]),$sigma1[1]);
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
&vld1_32 ("{$T0}","[$Ktbl,:128]!");
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
&vsli_32 ($T4,&Dlo(@X[0]),32-$sigma1[1]);
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
&veor ($T5,$T5,$T4); # sigma1(X[16..17])
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
&vadd_i32 (&Dhi(@X[0]),&Dhi(@X[0]),$T5);# X[2..3] += sigma1(X[16..17])
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
&vadd_i32 ($T0,$T0,@X[0]);
|
||||
while($#insns>=2) { eval(shift(@insns)); }
|
||||
&vst1_32 ("{$T0}","[$Xfer,:128]!");
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
|
||||
push(@X,shift(@X)); # "rotate" X[]
|
||||
}
|
||||
|
||||
sub Xpreload()
|
||||
{ use integer;
|
||||
my $body = shift;
|
||||
my @insns = (&$body,&$body,&$body,&$body);
|
||||
my ($a,$b,$c,$d,$e,$f,$g,$h);
|
||||
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
&vld1_32 ("{$T0}","[$Ktbl,:128]!");
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
&vrev32_8 (@X[0],@X[0]);
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
eval(shift(@insns));
|
||||
&vadd_i32 ($T0,$T0,@X[0]);
|
||||
foreach (@insns) { eval; } # remaining instructions
|
||||
&vst1_32 ("{$T0}","[$Xfer,:128]!");
|
||||
|
||||
push(@X,shift(@X)); # "rotate" X[]
|
||||
}
|
||||
|
||||
sub body_00_15 () {
|
||||
(
|
||||
'($a,$b,$c,$d,$e,$f,$g,$h)=@V;'.
|
||||
'&add ($h,$h,$t1)', # h+=X[i]+K[i]
|
||||
'&eor ($t1,$f,$g)',
|
||||
'&eor ($t0,$e,$e,"ror#".($Sigma1[1]-$Sigma1[0]))',
|
||||
'&add ($a,$a,$t2)', # h+=Maj(a,b,c) from the past
|
||||
'&and ($t1,$t1,$e)',
|
||||
'&eor ($t2,$t0,$e,"ror#".($Sigma1[2]-$Sigma1[0]))', # Sigma1(e)
|
||||
'&eor ($t0,$a,$a,"ror#".($Sigma0[1]-$Sigma0[0]))',
|
||||
'&eor ($t1,$t1,$g)', # Ch(e,f,g)
|
||||
'&add ($h,$h,$t2,"ror#$Sigma1[0]")', # h+=Sigma1(e)
|
||||
'&eor ($t2,$a,$b)', # a^b, b^c in next round
|
||||
'&eor ($t0,$t0,$a,"ror#".($Sigma0[2]-$Sigma0[0]))', # Sigma0(a)
|
||||
'&add ($h,$h,$t1)', # h+=Ch(e,f,g)
|
||||
'&ldr ($t1,sprintf "[sp,#%d]",4*(($j+1)&15)) if (($j&15)!=15);'.
|
||||
'&ldr ($t1,"[$Ktbl]") if ($j==15);'.
|
||||
'&ldr ($t1,"[sp,#64]") if ($j==31)',
|
||||
'&and ($t3,$t3,$t2)', # (b^c)&=(a^b)
|
||||
'&add ($d,$d,$h)', # d+=h
|
||||
'&add ($h,$h,$t0,"ror#$Sigma0[0]");'. # h+=Sigma0(a)
|
||||
'&eor ($t3,$t3,$b)', # Maj(a,b,c)
|
||||
'$j++; unshift(@V,pop(@V)); ($t2,$t3)=($t3,$t2);'
|
||||
)
|
||||
}
|
||||
|
||||
$code.=<<___;
|
||||
#if __ARM_MAX_ARCH__>=7
|
||||
.arch armv7-a
|
||||
.fpu neon
|
||||
|
||||
.global sha256_block_data_order_neon
|
||||
.type sha256_block_data_order_neon,%function
|
||||
.align 4
|
||||
sha256_block_data_order_neon:
|
||||
.LNEON:
|
||||
stmdb sp!,{r4-r12,lr}
|
||||
|
||||
sub $H,sp,#16*4+16
|
||||
adrl $Ktbl,K256
|
||||
bic $H,$H,#15 @ align for 128-bit stores
|
||||
mov $t2,sp
|
||||
mov sp,$H @ alloca
|
||||
add $len,$inp,$len,lsl#6 @ len to point at the end of inp
|
||||
|
||||
vld1.8 {@X[0]},[$inp]!
|
||||
vld1.8 {@X[1]},[$inp]!
|
||||
vld1.8 {@X[2]},[$inp]!
|
||||
vld1.8 {@X[3]},[$inp]!
|
||||
vld1.32 {$T0},[$Ktbl,:128]!
|
||||
vld1.32 {$T1},[$Ktbl,:128]!
|
||||
vld1.32 {$T2},[$Ktbl,:128]!
|
||||
vld1.32 {$T3},[$Ktbl,:128]!
|
||||
vrev32.8 @X[0],@X[0] @ yes, even on
|
||||
str $ctx,[sp,#64]
|
||||
vrev32.8 @X[1],@X[1] @ big-endian
|
||||
str $inp,[sp,#68]
|
||||
mov $Xfer,sp
|
||||
vrev32.8 @X[2],@X[2]
|
||||
str $len,[sp,#72]
|
||||
vrev32.8 @X[3],@X[3]
|
||||
str $t2,[sp,#76] @ save original sp
|
||||
vadd.i32 $T0,$T0,@X[0]
|
||||
vadd.i32 $T1,$T1,@X[1]
|
||||
vst1.32 {$T0},[$Xfer,:128]!
|
||||
vadd.i32 $T2,$T2,@X[2]
|
||||
vst1.32 {$T1},[$Xfer,:128]!
|
||||
vadd.i32 $T3,$T3,@X[3]
|
||||
vst1.32 {$T2},[$Xfer,:128]!
|
||||
vst1.32 {$T3},[$Xfer,:128]!
|
||||
|
||||
ldmia $ctx,{$A-$H}
|
||||
sub $Xfer,$Xfer,#64
|
||||
ldr $t1,[sp,#0]
|
||||
eor $t2,$t2,$t2
|
||||
eor $t3,$B,$C
|
||||
b .L_00_48
|
||||
|
||||
.align 4
|
||||
.L_00_48:
|
||||
___
|
||||
&Xupdate(\&body_00_15);
|
||||
&Xupdate(\&body_00_15);
|
||||
&Xupdate(\&body_00_15);
|
||||
&Xupdate(\&body_00_15);
|
||||
$code.=<<___;
|
||||
teq $t1,#0 @ check for K256 terminator
|
||||
ldr $t1,[sp,#0]
|
||||
sub $Xfer,$Xfer,#64
|
||||
bne .L_00_48
|
||||
|
||||
ldr $inp,[sp,#68]
|
||||
ldr $t0,[sp,#72]
|
||||
sub $Ktbl,$Ktbl,#256 @ rewind $Ktbl
|
||||
teq $inp,$t0
|
||||
it eq
|
||||
subeq $inp,$inp,#64 @ avoid SEGV
|
||||
vld1.8 {@X[0]},[$inp]! @ load next input block
|
||||
vld1.8 {@X[1]},[$inp]!
|
||||
vld1.8 {@X[2]},[$inp]!
|
||||
vld1.8 {@X[3]},[$inp]!
|
||||
it ne
|
||||
strne $inp,[sp,#68]
|
||||
mov $Xfer,sp
|
||||
___
|
||||
&Xpreload(\&body_00_15);
|
||||
&Xpreload(\&body_00_15);
|
||||
&Xpreload(\&body_00_15);
|
||||
&Xpreload(\&body_00_15);
|
||||
$code.=<<___;
|
||||
ldr $t0,[$t1,#0]
|
||||
add $A,$A,$t2 @ h+=Maj(a,b,c) from the past
|
||||
ldr $t2,[$t1,#4]
|
||||
ldr $t3,[$t1,#8]
|
||||
ldr $t4,[$t1,#12]
|
||||
add $A,$A,$t0 @ accumulate
|
||||
ldr $t0,[$t1,#16]
|
||||
add $B,$B,$t2
|
||||
ldr $t2,[$t1,#20]
|
||||
add $C,$C,$t3
|
||||
ldr $t3,[$t1,#24]
|
||||
add $D,$D,$t4
|
||||
ldr $t4,[$t1,#28]
|
||||
add $E,$E,$t0
|
||||
str $A,[$t1],#4
|
||||
add $F,$F,$t2
|
||||
str $B,[$t1],#4
|
||||
add $G,$G,$t3
|
||||
str $C,[$t1],#4
|
||||
add $H,$H,$t4
|
||||
str $D,[$t1],#4
|
||||
stmia $t1,{$E-$H}
|
||||
|
||||
ittte ne
|
||||
movne $Xfer,sp
|
||||
ldrne $t1,[sp,#0]
|
||||
eorne $t2,$t2,$t2
|
||||
ldreq sp,[sp,#76] @ restore original sp
|
||||
itt ne
|
||||
eorne $t3,$B,$C
|
||||
bne .L_00_48
|
||||
|
||||
ldmia sp!,{r4-r12,pc}
|
||||
.size sha256_block_data_order_neon,.-sha256_block_data_order_neon
|
||||
#endif
|
||||
___
|
||||
}}}
|
||||
######################################################################
|
||||
# ARMv8 stuff
|
||||
#
|
||||
{{{
|
||||
my ($ABCD,$EFGH,$abcd)=map("q$_",(0..2));
|
||||
my @MSG=map("q$_",(8..11));
|
||||
my ($W0,$W1,$ABCD_SAVE,$EFGH_SAVE)=map("q$_",(12..15));
|
||||
my $Ktbl="r3";
|
||||
|
||||
$code.=<<___;
|
||||
#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
|
||||
|
||||
# ifdef __thumb2__
|
||||
# define INST(a,b,c,d) .byte c,d|0xc,a,b
|
||||
# else
|
||||
# define INST(a,b,c,d) .byte a,b,c,d
|
||||
# endif
|
||||
|
||||
.type sha256_block_data_order_armv8,%function
|
||||
.align 5
|
||||
sha256_block_data_order_armv8:
|
||||
.LARMv8:
|
||||
vld1.32 {$ABCD,$EFGH},[$ctx]
|
||||
# ifdef __thumb2__
|
||||
adr $Ktbl,.LARMv8
|
||||
sub $Ktbl,$Ktbl,#.LARMv8-K256
|
||||
# else
|
||||
adrl $Ktbl,K256
|
||||
# endif
|
||||
add $len,$inp,$len,lsl#6 @ len to point at the end of inp
|
||||
|
||||
.Loop_v8:
|
||||
vld1.8 {@MSG[0]-@MSG[1]},[$inp]!
|
||||
vld1.8 {@MSG[2]-@MSG[3]},[$inp]!
|
||||
vld1.32 {$W0},[$Ktbl]!
|
||||
vrev32.8 @MSG[0],@MSG[0]
|
||||
vrev32.8 @MSG[1],@MSG[1]
|
||||
vrev32.8 @MSG[2],@MSG[2]
|
||||
vrev32.8 @MSG[3],@MSG[3]
|
||||
vmov $ABCD_SAVE,$ABCD @ offload
|
||||
vmov $EFGH_SAVE,$EFGH
|
||||
teq $inp,$len
|
||||
___
|
||||
for($i=0;$i<12;$i++) {
|
||||
$code.=<<___;
|
||||
vld1.32 {$W1},[$Ktbl]!
|
||||
vadd.i32 $W0,$W0,@MSG[0]
|
||||
sha256su0 @MSG[0],@MSG[1]
|
||||
vmov $abcd,$ABCD
|
||||
sha256h $ABCD,$EFGH,$W0
|
||||
sha256h2 $EFGH,$abcd,$W0
|
||||
sha256su1 @MSG[0],@MSG[2],@MSG[3]
|
||||
___
|
||||
($W0,$W1)=($W1,$W0); push(@MSG,shift(@MSG));
|
||||
}
|
||||
$code.=<<___;
|
||||
vld1.32 {$W1},[$Ktbl]!
|
||||
vadd.i32 $W0,$W0,@MSG[0]
|
||||
vmov $abcd,$ABCD
|
||||
sha256h $ABCD,$EFGH,$W0
|
||||
sha256h2 $EFGH,$abcd,$W0
|
||||
|
||||
vld1.32 {$W0},[$Ktbl]!
|
||||
vadd.i32 $W1,$W1,@MSG[1]
|
||||
vmov $abcd,$ABCD
|
||||
sha256h $ABCD,$EFGH,$W1
|
||||
sha256h2 $EFGH,$abcd,$W1
|
||||
|
||||
vld1.32 {$W1},[$Ktbl]
|
||||
vadd.i32 $W0,$W0,@MSG[2]
|
||||
sub $Ktbl,$Ktbl,#256-16 @ rewind
|
||||
vmov $abcd,$ABCD
|
||||
sha256h $ABCD,$EFGH,$W0
|
||||
sha256h2 $EFGH,$abcd,$W0
|
||||
|
||||
vadd.i32 $W1,$W1,@MSG[3]
|
||||
vmov $abcd,$ABCD
|
||||
sha256h $ABCD,$EFGH,$W1
|
||||
sha256h2 $EFGH,$abcd,$W1
|
||||
|
||||
vadd.i32 $ABCD,$ABCD,$ABCD_SAVE
|
||||
vadd.i32 $EFGH,$EFGH,$EFGH_SAVE
|
||||
it ne
|
||||
bne .Loop_v8
|
||||
|
||||
vst1.32 {$ABCD,$EFGH},[$ctx]
|
||||
|
||||
ret @ bx lr
|
||||
.size sha256_block_data_order_armv8,.-sha256_block_data_order_armv8
|
||||
#endif
|
||||
___
|
||||
}}}
|
||||
$code.=<<___;
|
||||
.asciz "SHA256 block transform for ARMv4/NEON/ARMv8, CRYPTOGAMS by <appro\@openssl.org>"
|
||||
.align 2
|
||||
#if __ARM_MAX_ARCH__>=7 && !defined(__KERNEL__)
|
||||
.comm OPENSSL_armcap_P,4,4
|
||||
#endif
|
||||
___
|
||||
|
||||
open SELF,$0;
|
||||
while(<SELF>) {
|
||||
next if (/^#!/);
|
||||
last if (!s/^#/@/ and !/^$/);
|
||||
print;
|
||||
}
|
||||
close SELF;
|
||||
|
||||
{ my %opcode = (
|
||||
"sha256h" => 0xf3000c40, "sha256h2" => 0xf3100c40,
|
||||
"sha256su0" => 0xf3ba03c0, "sha256su1" => 0xf3200c40 );
|
||||
|
||||
sub unsha256 {
|
||||
my ($mnemonic,$arg)=@_;
|
||||
|
||||
if ($arg =~ m/q([0-9]+)(?:,\s*q([0-9]+))?,\s*q([0-9]+)/o) {
|
||||
my $word = $opcode{$mnemonic}|(($1&7)<<13)|(($1&8)<<19)
|
||||
|(($2&7)<<17)|(($2&8)<<4)
|
||||
|(($3&7)<<1) |(($3&8)<<2);
|
||||
# since ARMv7 instructions are always encoded little-endian.
|
||||
# correct solution is to use .inst directive, but older
|
||||
# assemblers don't implement it:-(
|
||||
sprintf "INST(0x%02x,0x%02x,0x%02x,0x%02x)\t@ %s %s",
|
||||
$word&0xff,($word>>8)&0xff,
|
||||
($word>>16)&0xff,($word>>24)&0xff,
|
||||
$mnemonic,$arg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (split($/,$code)) {
|
||||
|
||||
s/\`([^\`]*)\`/eval $1/geo;
|
||||
|
||||
s/\b(sha256\w+)\s+(q.*)/unsha256($1,$2)/geo;
|
||||
|
||||
s/\bret\b/bx lr/go or
|
||||
s/\bbx\s+lr\b/.word\t0xe12fff1e/go; # make it possible to compile with -march=armv4
|
||||
|
||||
print $_,"\n";
|
||||
}
|
||||
|
||||
close STDOUT; # enforce flush
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
* Glue code for the SHA256 Secure Hash Algorithm assembly implementation
|
||||
* using optimized ARM assembler and NEON instructions.
|
||||
*
|
||||
* Copyright © 2015 Google Inc.
|
||||
*
|
||||
* This file is based on sha256_ssse3_glue.c:
|
||||
* Copyright (C) 2013 Intel Corporation
|
||||
* Author: Tim Chen <tim.c.chen@linux.intel.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <crypto/internal/hash.h>
|
||||
#include <linux/crypto.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/cryptohash.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/string.h>
|
||||
#include <crypto/sha.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <asm/simd.h>
|
||||
#include <asm/neon.h>
|
||||
#include "sha256_glue.h"
|
||||
|
||||
asmlinkage void sha256_block_data_order(u32 *digest, const void *data,
|
||||
unsigned int num_blks);
|
||||
|
||||
|
||||
int sha256_init(struct shash_desc *desc)
|
||||
{
|
||||
struct sha256_state *sctx = shash_desc_ctx(desc);
|
||||
|
||||
sctx->state[0] = SHA256_H0;
|
||||
sctx->state[1] = SHA256_H1;
|
||||
sctx->state[2] = SHA256_H2;
|
||||
sctx->state[3] = SHA256_H3;
|
||||
sctx->state[4] = SHA256_H4;
|
||||
sctx->state[5] = SHA256_H5;
|
||||
sctx->state[6] = SHA256_H6;
|
||||
sctx->state[7] = SHA256_H7;
|
||||
sctx->count = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sha224_init(struct shash_desc *desc)
|
||||
{
|
||||
struct sha256_state *sctx = shash_desc_ctx(desc);
|
||||
|
||||
sctx->state[0] = SHA224_H0;
|
||||
sctx->state[1] = SHA224_H1;
|
||||
sctx->state[2] = SHA224_H2;
|
||||
sctx->state[3] = SHA224_H3;
|
||||
sctx->state[4] = SHA224_H4;
|
||||
sctx->state[5] = SHA224_H5;
|
||||
sctx->state[6] = SHA224_H6;
|
||||
sctx->state[7] = SHA224_H7;
|
||||
sctx->count = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __sha256_update(struct shash_desc *desc, const u8 *data, unsigned int len,
|
||||
unsigned int partial)
|
||||
{
|
||||
struct sha256_state *sctx = shash_desc_ctx(desc);
|
||||
unsigned int done = 0;
|
||||
|
||||
sctx->count += len;
|
||||
|
||||
if (partial) {
|
||||
done = SHA256_BLOCK_SIZE - partial;
|
||||
memcpy(sctx->buf + partial, data, done);
|
||||
sha256_block_data_order(sctx->state, sctx->buf, 1);
|
||||
}
|
||||
|
||||
if (len - done >= SHA256_BLOCK_SIZE) {
|
||||
const unsigned int rounds = (len - done) / SHA256_BLOCK_SIZE;
|
||||
|
||||
sha256_block_data_order(sctx->state, data + done, rounds);
|
||||
done += rounds * SHA256_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
memcpy(sctx->buf, data + done, len - done);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sha256_update(struct shash_desc *desc, const u8 *data, unsigned int len)
|
||||
{
|
||||
struct sha256_state *sctx = shash_desc_ctx(desc);
|
||||
unsigned int partial = sctx->count % SHA256_BLOCK_SIZE;
|
||||
|
||||
/* Handle the fast case right here */
|
||||
if (partial + len < SHA256_BLOCK_SIZE) {
|
||||
sctx->count += len;
|
||||
memcpy(sctx->buf + partial, data, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
return __sha256_update(desc, data, len, partial);
|
||||
}
|
||||
|
||||
/* Add padding and return the message digest. */
|
||||
static int sha256_final(struct shash_desc *desc, u8 *out)
|
||||
{
|
||||
struct sha256_state *sctx = shash_desc_ctx(desc);
|
||||
unsigned int i, index, padlen;
|
||||
__be32 *dst = (__be32 *)out;
|
||||
__be64 bits;
|
||||
static const u8 padding[SHA256_BLOCK_SIZE] = { 0x80, };
|
||||
|
||||
/* save number of bits */
|
||||
bits = cpu_to_be64(sctx->count << 3);
|
||||
|
||||
/* Pad out to 56 mod 64 and append length */
|
||||
index = sctx->count % SHA256_BLOCK_SIZE;
|
||||
padlen = (index < 56) ? (56 - index) : ((SHA256_BLOCK_SIZE+56)-index);
|
||||
|
||||
/* We need to fill a whole block for __sha256_update */
|
||||
if (padlen <= 56) {
|
||||
sctx->count += padlen;
|
||||
memcpy(sctx->buf + index, padding, padlen);
|
||||
} else {
|
||||
__sha256_update(desc, padding, padlen, index);
|
||||
}
|
||||
__sha256_update(desc, (const u8 *)&bits, sizeof(bits), 56);
|
||||
|
||||
/* Store state in digest */
|
||||
for (i = 0; i < 8; i++)
|
||||
dst[i] = cpu_to_be32(sctx->state[i]);
|
||||
|
||||
/* Wipe context */
|
||||
memset(sctx, 0, sizeof(*sctx));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sha224_final(struct shash_desc *desc, u8 *out)
|
||||
{
|
||||
u8 D[SHA256_DIGEST_SIZE];
|
||||
|
||||
sha256_final(desc, D);
|
||||
|
||||
memcpy(out, D, SHA224_DIGEST_SIZE);
|
||||
memset(D, 0, SHA256_DIGEST_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sha256_export(struct shash_desc *desc, void *out)
|
||||
{
|
||||
struct sha256_state *sctx = shash_desc_ctx(desc);
|
||||
|
||||
memcpy(out, sctx, sizeof(*sctx));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sha256_import(struct shash_desc *desc, const void *in)
|
||||
{
|
||||
struct sha256_state *sctx = shash_desc_ctx(desc);
|
||||
|
||||
memcpy(sctx, in, sizeof(*sctx));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct shash_alg algs[] = { {
|
||||
.digestsize = SHA256_DIGEST_SIZE,
|
||||
.init = sha256_init,
|
||||
.update = sha256_update,
|
||||
.final = sha256_final,
|
||||
.export = sha256_export,
|
||||
.import = sha256_import,
|
||||
.descsize = sizeof(struct sha256_state),
|
||||
.statesize = sizeof(struct sha256_state),
|
||||
.base = {
|
||||
.cra_name = "sha256",
|
||||
.cra_driver_name = "sha256-asm",
|
||||
.cra_priority = 150,
|
||||
.cra_flags = CRYPTO_ALG_TYPE_SHASH,
|
||||
.cra_blocksize = SHA256_BLOCK_SIZE,
|
||||
.cra_module = THIS_MODULE,
|
||||
}
|
||||
}, {
|
||||
.digestsize = SHA224_DIGEST_SIZE,
|
||||
.init = sha224_init,
|
||||
.update = sha256_update,
|
||||
.final = sha224_final,
|
||||
.export = sha256_export,
|
||||
.import = sha256_import,
|
||||
.descsize = sizeof(struct sha256_state),
|
||||
.statesize = sizeof(struct sha256_state),
|
||||
.base = {
|
||||
.cra_name = "sha224",
|
||||
.cra_driver_name = "sha224-asm",
|
||||
.cra_priority = 150,
|
||||
.cra_flags = CRYPTO_ALG_TYPE_SHASH,
|
||||
.cra_blocksize = SHA224_BLOCK_SIZE,
|
||||
.cra_module = THIS_MODULE,
|
||||
}
|
||||
} };
|
||||
|
||||
static int __init sha256_mod_init(void)
|
||||
{
|
||||
int res = crypto_register_shashes(algs, ARRAY_SIZE(algs));
|
||||
|
||||
if (res < 0)
|
||||
return res;
|
||||
|
||||
if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) && cpu_has_neon()) {
|
||||
res = crypto_register_shashes(sha256_neon_algs,
|
||||
ARRAY_SIZE(sha256_neon_algs));
|
||||
|
||||
if (res < 0)
|
||||
crypto_unregister_shashes(algs, ARRAY_SIZE(algs));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void __exit sha256_mod_fini(void)
|
||||
{
|
||||
crypto_unregister_shashes(algs, ARRAY_SIZE(algs));
|
||||
|
||||
if (IS_ENABLED(CONFIG_KERNEL_MODE_NEON) && cpu_has_neon())
|
||||
crypto_unregister_shashes(sha256_neon_algs,
|
||||
ARRAY_SIZE(sha256_neon_algs));
|
||||
}
|
||||
|
||||
module_init(sha256_mod_init);
|
||||
module_exit(sha256_mod_fini);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_DESCRIPTION("SHA256 Secure Hash Algorithm (ARM), including NEON");
|
||||
|
||||
MODULE_ALIAS("sha256");
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef _CRYPTO_SHA256_GLUE_H
|
||||
#define _CRYPTO_SHA256_GLUE_H
|
||||
|
||||
#include <linux/crypto.h>
|
||||
#include <crypto/sha.h>
|
||||
|
||||
extern struct shash_alg sha256_neon_algs[2];
|
||||
|
||||
extern int sha256_init(struct shash_desc *desc);
|
||||
|
||||
extern int sha224_init(struct shash_desc *desc);
|
||||
|
||||
extern int __sha256_update(struct shash_desc *desc, const u8 *data,
|
||||
unsigned int len, unsigned int partial);
|
||||
|
||||
extern int sha256_update(struct shash_desc *desc, const u8 *data,
|
||||
unsigned int len);
|
||||
|
||||
extern int sha256_export(struct shash_desc *desc, void *out);
|
||||
|
||||
extern int sha256_import(struct shash_desc *desc, const void *in);
|
||||
|
||||
#endif /* _CRYPTO_SHA256_GLUE_H */
|
|
@ -0,0 +1,172 @@
|
|||
/*
|
||||
* Glue code for the SHA256 Secure Hash Algorithm assembly implementation
|
||||
* using NEON instructions.
|
||||
*
|
||||
* Copyright © 2015 Google Inc.
|
||||
*
|
||||
* This file is based on sha512_neon_glue.c:
|
||||
* Copyright © 2014 Jussi Kivilinna <jussi.kivilinna@iki.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <crypto/internal/hash.h>
|
||||
#include <linux/cryptohash.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/string.h>
|
||||
#include <crypto/sha.h>
|
||||
#include <asm/byteorder.h>
|
||||
#include <asm/simd.h>
|
||||
#include <asm/neon.h>
|
||||
#include "sha256_glue.h"
|
||||
|
||||
asmlinkage void sha256_block_data_order_neon(u32 *digest, const void *data,
|
||||
unsigned int num_blks);
|
||||
|
||||
|
||||
static int __sha256_neon_update(struct shash_desc *desc, const u8 *data,
|
||||
unsigned int len, unsigned int partial)
|
||||
{
|
||||
struct sha256_state *sctx = shash_desc_ctx(desc);
|
||||
unsigned int done = 0;
|
||||
|
||||
sctx->count += len;
|
||||
|
||||
if (partial) {
|
||||
done = SHA256_BLOCK_SIZE - partial;
|
||||
memcpy(sctx->buf + partial, data, done);
|
||||
sha256_block_data_order_neon(sctx->state, sctx->buf, 1);
|
||||
}
|
||||
|
||||
if (len - done >= SHA256_BLOCK_SIZE) {
|
||||
const unsigned int rounds = (len - done) / SHA256_BLOCK_SIZE;
|
||||
|
||||
sha256_block_data_order_neon(sctx->state, data + done, rounds);
|
||||
done += rounds * SHA256_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
memcpy(sctx->buf, data + done, len - done);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sha256_neon_update(struct shash_desc *desc, const u8 *data,
|
||||
unsigned int len)
|
||||
{
|
||||
struct sha256_state *sctx = shash_desc_ctx(desc);
|
||||
unsigned int partial = sctx->count % SHA256_BLOCK_SIZE;
|
||||
int res;
|
||||
|
||||
/* Handle the fast case right here */
|
||||
if (partial + len < SHA256_BLOCK_SIZE) {
|
||||
sctx->count += len;
|
||||
memcpy(sctx->buf + partial, data, len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!may_use_simd()) {
|
||||
res = __sha256_update(desc, data, len, partial);
|
||||
} else {
|
||||
kernel_neon_begin();
|
||||
res = __sha256_neon_update(desc, data, len, partial);
|
||||
kernel_neon_end();
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Add padding and return the message digest. */
|
||||
static int sha256_neon_final(struct shash_desc *desc, u8 *out)
|
||||
{
|
||||
struct sha256_state *sctx = shash_desc_ctx(desc);
|
||||
unsigned int i, index, padlen;
|
||||
__be32 *dst = (__be32 *)out;
|
||||
__be64 bits;
|
||||
static const u8 padding[SHA256_BLOCK_SIZE] = { 0x80, };
|
||||
|
||||
/* save number of bits */
|
||||
bits = cpu_to_be64(sctx->count << 3);
|
||||
|
||||
/* Pad out to 56 mod 64 and append length */
|
||||
index = sctx->count % SHA256_BLOCK_SIZE;
|
||||
padlen = (index < 56) ? (56 - index) : ((SHA256_BLOCK_SIZE+56)-index);
|
||||
|
||||
if (!may_use_simd()) {
|
||||
sha256_update(desc, padding, padlen);
|
||||
sha256_update(desc, (const u8 *)&bits, sizeof(bits));
|
||||
} else {
|
||||
kernel_neon_begin();
|
||||
/* We need to fill a whole block for __sha256_neon_update() */
|
||||
if (padlen <= 56) {
|
||||
sctx->count += padlen;
|
||||
memcpy(sctx->buf + index, padding, padlen);
|
||||
} else {
|
||||
__sha256_neon_update(desc, padding, padlen, index);
|
||||
}
|
||||
__sha256_neon_update(desc, (const u8 *)&bits,
|
||||
sizeof(bits), 56);
|
||||
kernel_neon_end();
|
||||
}
|
||||
|
||||
/* Store state in digest */
|
||||
for (i = 0; i < 8; i++)
|
||||
dst[i] = cpu_to_be32(sctx->state[i]);
|
||||
|
||||
/* Wipe context */
|
||||
memset(sctx, 0, sizeof(*sctx));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sha224_neon_final(struct shash_desc *desc, u8 *out)
|
||||
{
|
||||
u8 D[SHA256_DIGEST_SIZE];
|
||||
|
||||
sha256_neon_final(desc, D);
|
||||
|
||||
memcpy(out, D, SHA224_DIGEST_SIZE);
|
||||
memset(D, 0, SHA256_DIGEST_SIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct shash_alg sha256_neon_algs[] = { {
|
||||
.digestsize = SHA256_DIGEST_SIZE,
|
||||
.init = sha256_init,
|
||||
.update = sha256_neon_update,
|
||||
.final = sha256_neon_final,
|
||||
.export = sha256_export,
|
||||
.import = sha256_import,
|
||||
.descsize = sizeof(struct sha256_state),
|
||||
.statesize = sizeof(struct sha256_state),
|
||||
.base = {
|
||||
.cra_name = "sha256",
|
||||
.cra_driver_name = "sha256-neon",
|
||||
.cra_priority = 250,
|
||||
.cra_flags = CRYPTO_ALG_TYPE_SHASH,
|
||||
.cra_blocksize = SHA256_BLOCK_SIZE,
|
||||
.cra_module = THIS_MODULE,
|
||||
}
|
||||
}, {
|
||||
.digestsize = SHA224_DIGEST_SIZE,
|
||||
.init = sha224_init,
|
||||
.update = sha256_neon_update,
|
||||
.final = sha224_neon_final,
|
||||
.export = sha256_export,
|
||||
.import = sha256_import,
|
||||
.descsize = sizeof(struct sha256_state),
|
||||
.statesize = sizeof(struct sha256_state),
|
||||
.base = {
|
||||
.cra_name = "sha224",
|
||||
.cra_driver_name = "sha224-neon",
|
||||
.cra_priority = 250,
|
||||
.cra_flags = CRYPTO_ALG_TYPE_SHASH,
|
||||
.cra_blocksize = SHA224_BLOCK_SIZE,
|
||||
.cra_module = THIS_MODULE,
|
||||
}
|
||||
} };
|
|
@ -60,6 +60,7 @@ struct hpux_dirent {
|
|||
};
|
||||
|
||||
struct getdents_callback {
|
||||
struct dir_context ctx;
|
||||
struct hpux_dirent __user *current_dir;
|
||||
struct hpux_dirent __user *previous;
|
||||
int count;
|
||||
|
@ -110,24 +111,23 @@ int hpux_getdents(unsigned int fd, struct hpux_dirent __user *dirent, unsigned i
|
|||
{
|
||||
struct fd arg;
|
||||
struct hpux_dirent __user * lastdirent;
|
||||
struct getdents_callback buf;
|
||||
struct getdents_callback buf = {
|
||||
.ctx.actor = filldir,
|
||||
.current_dir = dirent,
|
||||
.count = count
|
||||
};
|
||||
int error;
|
||||
|
||||
arg = fdget(fd);
|
||||
if (!arg.file)
|
||||
return -EBADF;
|
||||
|
||||
buf.current_dir = dirent;
|
||||
buf.previous = NULL;
|
||||
buf.count = count;
|
||||
buf.error = 0;
|
||||
|
||||
error = vfs_readdir(arg.file, filldir, &buf);
|
||||
error = iterate_dir(arg.file, &buf.ctx);
|
||||
if (error >= 0)
|
||||
error = buf.error;
|
||||
lastdirent = buf.previous;
|
||||
if (lastdirent) {
|
||||
if (put_user(arg.file->f_pos, &lastdirent->d_off))
|
||||
if (put_user(buf.ctx.pos, &lastdirent->d_off))
|
||||
error = -EFAULT;
|
||||
else
|
||||
error = count - buf.count;
|
||||
|
|
|
@ -6,13 +6,13 @@
|
|||
#ifndef __FRAME_KERN_H_
|
||||
#define __FRAME_KERN_H_
|
||||
|
||||
extern int setup_signal_stack_sc(unsigned long stack_top, int sig,
|
||||
extern int setup_signal_stack_sc(unsigned long stack_top, int sig,
|
||||
struct k_sigaction *ka,
|
||||
struct pt_regs *regs,
|
||||
struct pt_regs *regs,
|
||||
sigset_t *mask);
|
||||
extern int setup_signal_stack_si(unsigned long stack_top, int sig,
|
||||
extern int setup_signal_stack_si(unsigned long stack_top, int sig,
|
||||
struct k_sigaction *ka,
|
||||
struct pt_regs *regs, siginfo_t *info,
|
||||
struct pt_regs *regs, struct siginfo *info,
|
||||
sigset_t *mask);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -19,7 +19,7 @@ EXPORT_SYMBOL(unblock_signals);
|
|||
* OK, we're invoking a handler
|
||||
*/
|
||||
static void handle_signal(struct pt_regs *regs, unsigned long signr,
|
||||
struct k_sigaction *ka, siginfo_t *info)
|
||||
struct k_sigaction *ka, struct siginfo *info)
|
||||
{
|
||||
sigset_t *oldset = sigmask_to_save();
|
||||
int singlestep = 0;
|
||||
|
@ -71,7 +71,7 @@ static void handle_signal(struct pt_regs *regs, unsigned long signr,
|
|||
static int kern_do_signal(struct pt_regs *regs)
|
||||
{
|
||||
struct k_sigaction ka_copy;
|
||||
siginfo_t info;
|
||||
struct siginfo info;
|
||||
int sig, handled_sig = 0;
|
||||
|
||||
while ((sig = get_signal_to_deliver(&info, &ka_copy, regs, NULL)) > 0) {
|
||||
|
|
|
@ -25,7 +25,7 @@ void (*sig_info[NSIG])(int, struct siginfo *, struct uml_pt_regs *) = {
|
|||
[SIGIO] = sigio_handler,
|
||||
[SIGVTALRM] = timer_handler };
|
||||
|
||||
static void sig_handler_common(int sig, siginfo_t *si, mcontext_t *mc)
|
||||
static void sig_handler_common(int sig, struct siginfo *si, mcontext_t *mc)
|
||||
{
|
||||
struct uml_pt_regs r;
|
||||
int save_errno = errno;
|
||||
|
@ -61,7 +61,7 @@ static void sig_handler_common(int sig, siginfo_t *si, mcontext_t *mc)
|
|||
static int signals_enabled;
|
||||
static unsigned int signals_pending;
|
||||
|
||||
void sig_handler(int sig, siginfo_t *si, mcontext_t *mc)
|
||||
void sig_handler(int sig, struct siginfo *si, mcontext_t *mc)
|
||||
{
|
||||
int enabled;
|
||||
|
||||
|
@ -120,7 +120,7 @@ void set_sigstack(void *sig_stack, int size)
|
|||
panic("enabling signal stack failed, errno = %d\n", errno);
|
||||
}
|
||||
|
||||
static void (*handlers[_NSIG])(int sig, siginfo_t *si, mcontext_t *mc) = {
|
||||
static void (*handlers[_NSIG])(int sig, struct siginfo *si, mcontext_t *mc) = {
|
||||
[SIGSEGV] = sig_handler,
|
||||
[SIGBUS] = sig_handler,
|
||||
[SIGILL] = sig_handler,
|
||||
|
@ -162,7 +162,7 @@ static void hard_handler(int sig, siginfo_t *si, void *p)
|
|||
while ((sig = ffs(pending)) != 0){
|
||||
sig--;
|
||||
pending &= ~(1 << sig);
|
||||
(*handlers[sig])(sig, si, mc);
|
||||
(*handlers[sig])(sig, (struct siginfo *)si, mc);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -409,7 +409,7 @@ void userspace(struct uml_pt_regs *regs)
|
|||
if (WIFSTOPPED(status)) {
|
||||
int sig = WSTOPSIG(status);
|
||||
|
||||
ptrace(PTRACE_GETSIGINFO, pid, 0, &si);
|
||||
ptrace(PTRACE_GETSIGINFO, pid, 0, (struct siginfo *)&si);
|
||||
|
||||
switch (sig) {
|
||||
case SIGSEGV:
|
||||
|
@ -417,7 +417,7 @@ void userspace(struct uml_pt_regs *regs)
|
|||
!ptrace_faultinfo) {
|
||||
get_skas_faultinfo(pid,
|
||||
®s->faultinfo);
|
||||
(*sig_info[SIGSEGV])(SIGSEGV, &si,
|
||||
(*sig_info[SIGSEGV])(SIGSEGV, (struct siginfo *)&si,
|
||||
regs);
|
||||
}
|
||||
else handle_segv(pid, regs);
|
||||
|
@ -426,14 +426,14 @@ void userspace(struct uml_pt_regs *regs)
|
|||
handle_trap(pid, regs, local_using_sysemu);
|
||||
break;
|
||||
case SIGTRAP:
|
||||
relay_signal(SIGTRAP, &si, regs);
|
||||
relay_signal(SIGTRAP, (struct siginfo *)&si, regs);
|
||||
break;
|
||||
case SIGVTALRM:
|
||||
now = os_nsecs();
|
||||
if (now < nsecs)
|
||||
break;
|
||||
block_signals();
|
||||
(*sig_info[sig])(sig, &si, regs);
|
||||
(*sig_info[sig])(sig, (struct siginfo *)&si, regs);
|
||||
unblock_signals();
|
||||
nsecs = timer.it_value.tv_sec *
|
||||
UM_NSEC_PER_SEC +
|
||||
|
@ -447,7 +447,7 @@ void userspace(struct uml_pt_regs *regs)
|
|||
case SIGFPE:
|
||||
case SIGWINCH:
|
||||
block_signals();
|
||||
(*sig_info[sig])(sig, &si, regs);
|
||||
(*sig_info[sig])(sig, (struct siginfo *)&si, regs);
|
||||
unblock_signals();
|
||||
break;
|
||||
default:
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -660,6 +660,10 @@ static inline void cpu_relax(void)
|
|||
rep_nop();
|
||||
}
|
||||
|
||||
#ifndef cpu_read_relax
|
||||
#define cpu_read_relax() cpu_relax()
|
||||
#endif
|
||||
|
||||
/* Stop speculative execution and prefetching of modified code. */
|
||||
static inline void sync_core(void)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* x86/include/asm/relaxed.h
|
||||
*
|
||||
* (copied from arm/include/asm/relaxed.h)
|
||||
*
|
||||
* Copyright (c) 2014 NVIDIA Corporation. All rights reserved.
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _ASM_RELAXED_H_
|
||||
#define _ASM_RELAXED_H_
|
||||
|
||||
#include <asm-generic/relaxed.h>
|
||||
|
||||
#endif /*_ASM_RELAXED_H_*/
|
|
@ -508,7 +508,6 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
|
|||
{
|
||||
struct rt_sigframe __user *frame;
|
||||
int err = 0;
|
||||
struct task_struct *me = current;
|
||||
|
||||
frame = (struct rt_sigframe __user *)
|
||||
round_down(stack_top - sizeof(struct rt_sigframe), 16);
|
||||
|
|
|
@ -556,6 +556,13 @@ config CRYPTO_SHA256
|
|||
This code also includes SHA-224, a 224 bit hash with 112 bits
|
||||
of security against collision attacks.
|
||||
|
||||
config CRYPTO_SHA256_ARM
|
||||
tristate "SHA-224/256 digest algorithm (ARM-asm and NEON)"
|
||||
select CRYPTO_HASH
|
||||
help
|
||||
SHA-256 secure hash standard (DFIPS 180-2) implemented
|
||||
using optimized ARM assembler and NEON, when available.
|
||||
|
||||
config CRYPTO_SHA256_SPARC64
|
||||
tristate "SHA224 and SHA256 digest algorithm (SPARC64)"
|
||||
depends on SPARC64
|
||||
|
|
|
@ -3585,13 +3585,24 @@ static int binder_transactions_show(struct seq_file *m, void *unused)
|
|||
|
||||
static int binder_proc_show(struct seq_file *m, void *unused)
|
||||
{
|
||||
struct binder_proc *itr;
|
||||
struct binder_proc *proc = m->private;
|
||||
int do_lock = !binder_debug_no_lock;
|
||||
bool valid_proc = false;
|
||||
|
||||
if (do_lock)
|
||||
binder_lock(__func__);
|
||||
seq_puts(m, "binder proc state:\n");
|
||||
print_binder_proc(m, proc, 1);
|
||||
|
||||
hlist_for_each_entry(itr, &binder_procs, proc_node) {
|
||||
if (itr == proc) {
|
||||
valid_proc = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (valid_proc) {
|
||||
seq_puts(m, "binder proc state:\n");
|
||||
print_binder_proc(m, proc, 1);
|
||||
}
|
||||
if (do_lock)
|
||||
binder_unlock(__func__);
|
||||
return 0;
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#if !defined(__i386__) && !defined(__amd64__)
|
||||
/*
|
||||
* Coherent per-device memory handling.
|
||||
* Borrowed from i386
|
||||
|
@ -218,3 +219,228 @@ int dma_mmap_from_coherent(struct device *dev, struct vm_area_struct *vma,
|
|||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dma_mmap_from_coherent);
|
||||
#else
|
||||
/* CMA is a wretched hive of scum and villany --- and also doesn't
|
||||
* compile on x86 */
|
||||
|
||||
/*
|
||||
* Coherent per-device memory handling.
|
||||
* Borrowed from i386
|
||||
*/
|
||||
#include <linux/slab.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
|
||||
struct dma_coherent_mem {
|
||||
void *virt_base;
|
||||
dma_addr_t device_base;
|
||||
phys_addr_t pfn_base;
|
||||
int size;
|
||||
int flags;
|
||||
unsigned long *bitmap;
|
||||
};
|
||||
|
||||
int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
|
||||
dma_addr_t device_addr, size_t size, int flags)
|
||||
{
|
||||
void __iomem *mem_base = NULL;
|
||||
int pages = size >> PAGE_SHIFT;
|
||||
int bitmap_size = BITS_TO_LONGS(pages) * sizeof(long);
|
||||
|
||||
if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0)
|
||||
goto out;
|
||||
if (!size)
|
||||
goto out;
|
||||
if (dev->dma_mem)
|
||||
goto out;
|
||||
|
||||
/* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */
|
||||
|
||||
mem_base = ioremap(bus_addr, size);
|
||||
if (!mem_base)
|
||||
goto out;
|
||||
|
||||
dev->dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL);
|
||||
if (!dev->dma_mem)
|
||||
goto out;
|
||||
dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
|
||||
if (!dev->dma_mem->bitmap)
|
||||
goto free1_out;
|
||||
|
||||
dev->dma_mem->virt_base = mem_base;
|
||||
dev->dma_mem->device_base = device_addr;
|
||||
dev->dma_mem->pfn_base = PFN_DOWN(bus_addr);
|
||||
dev->dma_mem->size = pages;
|
||||
dev->dma_mem->flags = flags;
|
||||
|
||||
if (flags & DMA_MEMORY_MAP)
|
||||
return DMA_MEMORY_MAP;
|
||||
|
||||
return DMA_MEMORY_IO;
|
||||
|
||||
free1_out:
|
||||
kfree(dev->dma_mem);
|
||||
out:
|
||||
if (mem_base)
|
||||
iounmap(mem_base);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dma_declare_coherent_memory);
|
||||
|
||||
void dma_release_declared_memory(struct device *dev)
|
||||
{
|
||||
struct dma_coherent_mem *mem = dev->dma_mem;
|
||||
|
||||
if (!mem)
|
||||
return;
|
||||
dev->dma_mem = NULL;
|
||||
iounmap(mem->virt_base);
|
||||
kfree(mem->bitmap);
|
||||
kfree(mem);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_release_declared_memory);
|
||||
|
||||
void *dma_mark_declared_memory_occupied(struct device *dev,
|
||||
dma_addr_t device_addr, size_t size)
|
||||
{
|
||||
struct dma_coherent_mem *mem = dev->dma_mem;
|
||||
int pos, err;
|
||||
|
||||
size += device_addr & ~PAGE_MASK;
|
||||
|
||||
if (!mem)
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
pos = (device_addr - mem->device_base) >> PAGE_SHIFT;
|
||||
err = bitmap_allocate_region(mem->bitmap, pos, get_order(size));
|
||||
if (err != 0)
|
||||
return ERR_PTR(err);
|
||||
return mem->virt_base + (pos << PAGE_SHIFT);
|
||||
}
|
||||
EXPORT_SYMBOL(dma_mark_declared_memory_occupied);
|
||||
|
||||
/**
|
||||
* dma_alloc_from_coherent() - try to allocate memory from the per-device coherent area
|
||||
*
|
||||
* @dev: device from which we allocate memory
|
||||
* @size: size of requested memory area
|
||||
* @dma_handle: This will be filled with the correct dma handle
|
||||
* @ret: This pointer will be filled with the virtual address
|
||||
* to allocated area.
|
||||
*
|
||||
* This function should be only called from per-arch dma_alloc_coherent()
|
||||
* to support allocation from per-device coherent memory pools.
|
||||
*
|
||||
* Returns 0 if dma_alloc_coherent should continue with allocating from
|
||||
* generic memory areas, or !0 if dma_alloc_coherent should return @ret.
|
||||
*/
|
||||
int dma_alloc_from_coherent(struct device *dev, ssize_t size,
|
||||
dma_addr_t *dma_handle, void **ret)
|
||||
{
|
||||
struct dma_coherent_mem *mem;
|
||||
int order = get_order(size);
|
||||
int pageno;
|
||||
|
||||
if (!dev)
|
||||
return 0;
|
||||
mem = dev->dma_mem;
|
||||
if (!mem)
|
||||
return 0;
|
||||
|
||||
*ret = NULL;
|
||||
|
||||
if (unlikely(size > (mem->size << PAGE_SHIFT)))
|
||||
goto err;
|
||||
|
||||
pageno = bitmap_find_free_region(mem->bitmap, mem->size, order);
|
||||
if (unlikely(pageno < 0))
|
||||
goto err;
|
||||
|
||||
/*
|
||||
* Memory was found in the per-device area.
|
||||
*/
|
||||
*dma_handle = mem->device_base + (pageno << PAGE_SHIFT);
|
||||
*ret = mem->virt_base + (pageno << PAGE_SHIFT);
|
||||
memset(*ret, 0, size);
|
||||
|
||||
return 1;
|
||||
|
||||
err:
|
||||
/*
|
||||
* In the case where the allocation can not be satisfied from the
|
||||
* per-device area, try to fall back to generic memory if the
|
||||
* constraints allow it.
|
||||
*/
|
||||
return mem->flags & DMA_MEMORY_EXCLUSIVE;
|
||||
}
|
||||
EXPORT_SYMBOL(dma_alloc_from_coherent);
|
||||
|
||||
/**
|
||||
* dma_release_from_coherent() - try to free the memory allocated from per-device coherent memory pool
|
||||
* @dev: device from which the memory was allocated
|
||||
* @order: the order of pages allocated
|
||||
* @vaddr: virtual address of allocated pages
|
||||
*
|
||||
* This checks whether the memory was allocated from the per-device
|
||||
* coherent memory pool and if so, releases that memory.
|
||||
*
|
||||
* Returns 1 if we correctly released the memory, or 0 if
|
||||
* dma_release_coherent() should proceed with releasing memory from
|
||||
* generic pools.
|
||||
*/
|
||||
int dma_release_from_coherent(struct device *dev, int order, void *vaddr)
|
||||
{
|
||||
struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
|
||||
|
||||
if (mem && vaddr >= mem->virt_base && vaddr <
|
||||
(mem->virt_base + (mem->size << PAGE_SHIFT))) {
|
||||
int page = (vaddr - mem->virt_base) >> PAGE_SHIFT;
|
||||
|
||||
bitmap_release_region(mem->bitmap, page, order);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dma_release_from_coherent);
|
||||
|
||||
/**
|
||||
* dma_mmap_from_coherent() - try to mmap the memory allocated from
|
||||
* per-device coherent memory pool to userspace
|
||||
* @dev: device from which the memory was allocated
|
||||
* @vma: vm_area for the userspace memory
|
||||
* @vaddr: cpu address returned by dma_alloc_from_coherent
|
||||
* @size: size of the memory buffer allocated by dma_alloc_from_coherent
|
||||
* @ret: result from remap_pfn_range()
|
||||
*
|
||||
* This checks whether the memory was allocated from the per-device
|
||||
* coherent memory pool and if so, maps that memory to the provided vma.
|
||||
*
|
||||
* Returns 1 if we correctly mapped the memory, or 0 if the caller should
|
||||
* proceed with mapping memory from generic pools.
|
||||
*/
|
||||
int dma_mmap_from_coherent(struct device *dev, struct vm_area_struct *vma,
|
||||
void *vaddr, size_t size, int *ret)
|
||||
{
|
||||
struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
|
||||
|
||||
if (mem && vaddr >= mem->virt_base && vaddr + size <=
|
||||
(mem->virt_base + (mem->size << PAGE_SHIFT))) {
|
||||
unsigned long off = vma->vm_pgoff;
|
||||
int start = (vaddr - mem->virt_base) >> PAGE_SHIFT;
|
||||
int user_count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
|
||||
int count = size >> PAGE_SHIFT;
|
||||
|
||||
*ret = -ENXIO;
|
||||
if (off < count && user_count <= count - off) {
|
||||
unsigned pfn = mem->pfn_base + start + off;
|
||||
*ret = remap_pfn_range(vma, vma->vm_start, pfn,
|
||||
user_count << PAGE_SHIFT,
|
||||
vma->vm_page_prot);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dma_mmap_from_coherent);
|
||||
#endif
|
||||
|
|
|
@ -54,6 +54,8 @@ static LIST_HEAD(wakeup_sources);
|
|||
|
||||
static DECLARE_WAIT_QUEUE_HEAD(wakeup_count_wait_queue);
|
||||
|
||||
static ktime_t last_read_time;
|
||||
|
||||
/**
|
||||
* wakeup_source_prepare - Prepare a new wakeup source for initialization.
|
||||
* @ws: Wakeup source to prepare.
|
||||
|
@ -372,6 +374,20 @@ int device_set_wakeup_enable(struct device *dev, bool enable)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(device_set_wakeup_enable);
|
||||
|
||||
/**
|
||||
* wakeup_source_not_registered - validate the given wakeup source.
|
||||
* @ws: Wakeup source to be validated.
|
||||
*/
|
||||
static bool wakeup_source_not_registered(struct wakeup_source *ws)
|
||||
{
|
||||
/*
|
||||
* Use timer struct to check if the given source is initialized
|
||||
* by wakeup_source_add.
|
||||
*/
|
||||
return ws->timer.function != pm_wakeup_timer_fn ||
|
||||
ws->timer.data != (unsigned long)ws;
|
||||
}
|
||||
|
||||
/*
|
||||
* The functions below use the observation that each wakeup event starts a
|
||||
* period in which the system should not be suspended. The moment this period
|
||||
|
@ -412,6 +428,10 @@ static void wakeup_source_activate(struct wakeup_source *ws)
|
|||
{
|
||||
unsigned int cec;
|
||||
|
||||
if (WARN(wakeup_source_not_registered(ws),
|
||||
"unregistered wakeup source\n"))
|
||||
return;
|
||||
|
||||
/*
|
||||
* active wakeup source should bring the system
|
||||
* out of PM_SUSPEND_FREEZE state
|
||||
|
@ -789,10 +809,15 @@ bool pm_wakeup_pending(void)
|
|||
bool pm_get_wakeup_count(unsigned int *count, bool block)
|
||||
{
|
||||
unsigned int cnt, inpr;
|
||||
unsigned long flags;
|
||||
|
||||
if (block) {
|
||||
DEFINE_WAIT(wait);
|
||||
|
||||
spin_lock_irqsave(&events_lock, flags);
|
||||
last_read_time = ktime_get();
|
||||
spin_unlock_irqrestore(&events_lock, flags);
|
||||
|
||||
for (;;) {
|
||||
prepare_to_wait(&wakeup_count_wait_queue, &wait,
|
||||
TASK_INTERRUPTIBLE);
|
||||
|
@ -824,6 +849,7 @@ bool pm_save_wakeup_count(unsigned int count)
|
|||
{
|
||||
unsigned int cnt, inpr;
|
||||
unsigned long flags;
|
||||
struct wakeup_source *ws;
|
||||
|
||||
events_check_enabled = false;
|
||||
spin_lock_irqsave(&events_lock, flags);
|
||||
|
@ -831,6 +857,15 @@ bool pm_save_wakeup_count(unsigned int count)
|
|||
if (cnt == count && inpr == 0) {
|
||||
saved_count = count;
|
||||
events_check_enabled = true;
|
||||
} else {
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
|
||||
if (ws->active ||
|
||||
ktime_compare(ws->last_time, last_read_time) > 0) {
|
||||
ws->wakeup_count++;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
spin_unlock_irqrestore(&events_lock, flags);
|
||||
return events_check_enabled;
|
||||
|
|
|
@ -18,20 +18,36 @@
|
|||
|
||||
#include <linux/module.h>
|
||||
#include <linux/device-mapper.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <crypto/hash.h>
|
||||
|
||||
#define DM_MSG_PREFIX "verity"
|
||||
|
||||
#define DM_VERITY_ENV_LENGTH 42
|
||||
#define DM_VERITY_ENV_VAR_NAME "VERITY_ERR_BLOCK_NR"
|
||||
|
||||
#define DM_VERITY_IO_VEC_INLINE 16
|
||||
#define DM_VERITY_MEMPOOL_SIZE 4
|
||||
#define DM_VERITY_DEFAULT_PREFETCH_SIZE 262144
|
||||
|
||||
#define DM_VERITY_MAX_LEVELS 63
|
||||
#define DM_VERITY_MAX_CORRUPTED_ERRS 100
|
||||
|
||||
static unsigned dm_verity_prefetch_cluster = DM_VERITY_DEFAULT_PREFETCH_SIZE;
|
||||
|
||||
module_param_named(prefetch_cluster, dm_verity_prefetch_cluster, uint, S_IRUGO | S_IWUSR);
|
||||
|
||||
enum verity_mode {
|
||||
DM_VERITY_MODE_EIO = 0,
|
||||
DM_VERITY_MODE_LOGGING = 1,
|
||||
DM_VERITY_MODE_RESTART = 2
|
||||
};
|
||||
|
||||
enum verity_block_type {
|
||||
DM_VERITY_BLOCK_TYPE_DATA,
|
||||
DM_VERITY_BLOCK_TYPE_METADATA
|
||||
};
|
||||
|
||||
struct dm_verity {
|
||||
struct dm_dev *data_dev;
|
||||
struct dm_dev *hash_dev;
|
||||
|
@ -54,6 +70,8 @@ struct dm_verity {
|
|||
unsigned digest_size; /* digest size for the current hash algorithm */
|
||||
unsigned shash_descsize;/* the size of temporary space for crypto */
|
||||
int hash_failed; /* set to 1 if hash of any block failed */
|
||||
enum verity_mode mode; /* mode for handling verification errors */
|
||||
unsigned corrupted_errs;/* Number of errors for corrupted blocks */
|
||||
|
||||
mempool_t *vec_mempool; /* mempool of bio vector */
|
||||
|
||||
|
@ -179,6 +197,54 @@ static void verity_hash_at_level(struct dm_verity *v, sector_t block, int level,
|
|||
*offset = idx << (v->hash_dev_block_bits - v->hash_per_block_bits);
|
||||
}
|
||||
|
||||
/*
|
||||
* Handle verification errors.
|
||||
*/
|
||||
static int verity_handle_err(struct dm_verity *v, enum verity_block_type type,
|
||||
unsigned long long block)
|
||||
{
|
||||
char verity_env[DM_VERITY_ENV_LENGTH];
|
||||
char *envp[] = { verity_env, NULL };
|
||||
const char *type_str = "";
|
||||
struct mapped_device *md = dm_table_get_md(v->ti->table);
|
||||
|
||||
if (v->corrupted_errs >= DM_VERITY_MAX_CORRUPTED_ERRS)
|
||||
goto out;
|
||||
|
||||
++v->corrupted_errs;
|
||||
|
||||
switch (type) {
|
||||
case DM_VERITY_BLOCK_TYPE_DATA:
|
||||
type_str = "data";
|
||||
break;
|
||||
case DM_VERITY_BLOCK_TYPE_METADATA:
|
||||
type_str = "metadata";
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
|
||||
DMERR_LIMIT("%s: %s block %llu is corrupted", v->data_dev->name,
|
||||
type_str, block);
|
||||
|
||||
if (v->corrupted_errs == DM_VERITY_MAX_CORRUPTED_ERRS)
|
||||
DMERR("%s: reached maximum errors", v->data_dev->name);
|
||||
|
||||
snprintf(verity_env, DM_VERITY_ENV_LENGTH, "%s=%d,%llu",
|
||||
DM_VERITY_ENV_VAR_NAME, type, block);
|
||||
|
||||
kobject_uevent_env(&disk_to_dev(dm_disk(md))->kobj, KOBJ_CHANGE, envp);
|
||||
|
||||
out:
|
||||
if (v->mode == DM_VERITY_MODE_LOGGING)
|
||||
return 0;
|
||||
|
||||
if (v->mode == DM_VERITY_MODE_RESTART)
|
||||
kernel_restart("dm-verity device corrupted");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify hash of a metadata block pertaining to the specified data block
|
||||
* ("block" argument) at a specified level ("level" argument).
|
||||
|
@ -256,11 +322,13 @@ static int verity_verify_level(struct dm_verity_io *io, sector_t block,
|
|||
goto release_ret_r;
|
||||
}
|
||||
if (unlikely(memcmp(result, io_want_digest(v, io), v->digest_size))) {
|
||||
DMERR_LIMIT("metadata block %llu is corrupted",
|
||||
(unsigned long long)hash_block);
|
||||
v->hash_failed = 1;
|
||||
r = -EIO;
|
||||
goto release_ret_r;
|
||||
|
||||
if (verity_handle_err(v, DM_VERITY_BLOCK_TYPE_METADATA,
|
||||
hash_block)) {
|
||||
r = -EIO;
|
||||
goto release_ret_r;
|
||||
}
|
||||
} else
|
||||
aux->hash_verified = 1;
|
||||
}
|
||||
|
@ -377,10 +445,11 @@ test_block_hash:
|
|||
return r;
|
||||
}
|
||||
if (unlikely(memcmp(result, io_want_digest(v, io), v->digest_size))) {
|
||||
DMERR_LIMIT("data block %llu is corrupted",
|
||||
(unsigned long long)(io->block + b));
|
||||
v->hash_failed = 1;
|
||||
return -EIO;
|
||||
|
||||
if (verity_handle_err(v, DM_VERITY_BLOCK_TYPE_DATA,
|
||||
io->block + b))
|
||||
return -EIO;
|
||||
}
|
||||
}
|
||||
BUG_ON(vector != io->io_vec_size);
|
||||
|
@ -689,8 +758,8 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
|
|||
goto bad;
|
||||
}
|
||||
|
||||
if (argc != 10) {
|
||||
ti->error = "Invalid argument count: exactly 10 arguments required";
|
||||
if (argc < 10 || argc > 11) {
|
||||
ti->error = "Invalid argument count: 10-11 arguments required";
|
||||
r = -EINVAL;
|
||||
goto bad;
|
||||
}
|
||||
|
@ -811,6 +880,17 @@ static int verity_ctr(struct dm_target *ti, unsigned argc, char **argv)
|
|||
}
|
||||
}
|
||||
|
||||
if (argc > 10) {
|
||||
if (sscanf(argv[10], "%d%c", &num, &dummy) != 1 ||
|
||||
num < DM_VERITY_MODE_EIO ||
|
||||
num > DM_VERITY_MODE_RESTART) {
|
||||
ti->error = "Invalid mode";
|
||||
r = -EINVAL;
|
||||
goto bad;
|
||||
}
|
||||
v->mode = num;
|
||||
}
|
||||
|
||||
v->hash_per_block_bits =
|
||||
fls((1 << v->hash_dev_block_bits) / v->digest_size) - 1;
|
||||
|
||||
|
|
|
@ -4089,42 +4089,7 @@ static void mmc_blk_remove(struct mmc_card *card)
|
|||
#endif
|
||||
}
|
||||
|
||||
static void mmc_blk_shutdown(struct mmc_card *card)
|
||||
{
|
||||
struct mmc_blk_data *part_md;
|
||||
struct mmc_blk_data *md = mmc_get_drvdata(card);
|
||||
int rc;
|
||||
|
||||
/* Silent the block layer */
|
||||
if (md) {
|
||||
rc = mmc_queue_suspend(&md->queue, 1);
|
||||
if (rc)
|
||||
goto suspend_error;
|
||||
list_for_each_entry(part_md, &md->part, part) {
|
||||
rc = mmc_queue_suspend(&part_md->queue, 1);
|
||||
if (rc)
|
||||
goto suspend_error;
|
||||
}
|
||||
}
|
||||
|
||||
/* send power off notification */
|
||||
if (mmc_card_mmc(card)) {
|
||||
mmc_rpm_hold(card->host, &card->dev);
|
||||
mmc_claim_host(card->host);
|
||||
mmc_stop_bkops(card);
|
||||
mmc_release_host(card->host);
|
||||
mmc_send_pon(card);
|
||||
mmc_rpm_release(card->host, &card->dev);
|
||||
}
|
||||
return;
|
||||
|
||||
suspend_error:
|
||||
pr_err("%s: mmc_queue_suspend returned error = %d",
|
||||
mmc_hostname(card->host), rc);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int mmc_blk_suspend(struct mmc_card *card)
|
||||
static int _mmc_blk_suspend(struct mmc_card *card)
|
||||
{
|
||||
struct mmc_blk_data *part_md;
|
||||
struct mmc_blk_data *md = mmc_get_drvdata(card);
|
||||
|
@ -4151,6 +4116,17 @@ static int mmc_blk_suspend(struct mmc_card *card)
|
|||
return rc;
|
||||
}
|
||||
|
||||
static void mmc_blk_shutdown(struct mmc_card *card)
|
||||
{
|
||||
_mmc_blk_suspend(card);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int mmc_blk_suspend(struct mmc_card *card)
|
||||
{
|
||||
return _mmc_blk_suspend(card);
|
||||
}
|
||||
|
||||
static int mmc_blk_resume(struct mmc_card *card)
|
||||
{
|
||||
struct mmc_blk_data *part_md;
|
||||
|
|
|
@ -3028,12 +3028,17 @@ static void mmc_test_remove(struct mmc_card *card)
|
|||
mmc_test_free_dbgfs_file(card);
|
||||
}
|
||||
|
||||
static void mmc_test_shutdown(struct mmc_card *card)
|
||||
{
|
||||
}
|
||||
|
||||
static struct mmc_driver mmc_driver = {
|
||||
.drv = {
|
||||
.name = "mmc_test",
|
||||
},
|
||||
.probe = mmc_test_probe,
|
||||
.remove = mmc_test_remove,
|
||||
.shutdown = mmc_test_shutdown,
|
||||
};
|
||||
|
||||
static int __init mmc_test_init(void)
|
||||
|
|
|
@ -127,19 +127,18 @@ static void mmc_bus_shutdown(struct device *dev)
|
|||
{
|
||||
struct mmc_driver *drv = to_mmc_driver(dev->driver);
|
||||
struct mmc_card *card = mmc_dev_to_card(dev);
|
||||
struct mmc_host *host = card->host;
|
||||
int ret;
|
||||
|
||||
if (!drv) {
|
||||
pr_debug("%s: %s: drv is NULL\n", dev_name(dev), __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!card) {
|
||||
pr_debug("%s: %s: card is NULL\n", dev_name(dev), __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (drv->shutdown)
|
||||
if (dev->driver && drv->shutdown)
|
||||
drv->shutdown(card);
|
||||
|
||||
if (host->bus_ops->shutdown) {
|
||||
ret = host->bus_ops->shutdown(host);
|
||||
if (ret)
|
||||
pr_warn("%s: error %d during shutdown\n",
|
||||
mmc_hostname(host), ret);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
@ -267,7 +266,7 @@ static struct bus_type mmc_bus_type = {
|
|||
.uevent = mmc_bus_uevent,
|
||||
.probe = mmc_bus_probe,
|
||||
.remove = mmc_bus_remove,
|
||||
.shutdown = mmc_bus_shutdown,
|
||||
.shutdown = mmc_bus_shutdown,
|
||||
.pm = &mmc_bus_pm_ops,
|
||||
};
|
||||
|
||||
|
|
|
@ -4014,60 +4014,6 @@ int mmc_flush_cache(struct mmc_card *card)
|
|||
}
|
||||
EXPORT_SYMBOL(mmc_flush_cache);
|
||||
|
||||
/*
|
||||
* Turn the cache ON/OFF.
|
||||
* Turning the cache OFF shall trigger flushing of the data
|
||||
* to the non-volatile storage.
|
||||
* This function should be called with host claimed
|
||||
*/
|
||||
int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
|
||||
{
|
||||
struct mmc_card *card = host->card;
|
||||
unsigned int timeout;
|
||||
int err = 0, rc;
|
||||
|
||||
BUG_ON(!card);
|
||||
timeout = card->ext_csd.generic_cmd6_time;
|
||||
|
||||
if (!(host->caps2 & MMC_CAP2_CACHE_CTRL) ||
|
||||
mmc_card_is_removable(host) ||
|
||||
(card->quirks & MMC_QUIRK_CACHE_DISABLE))
|
||||
return err;
|
||||
|
||||
if (card && mmc_card_mmc(card) &&
|
||||
(card->ext_csd.cache_size > 0)) {
|
||||
enable = !!enable;
|
||||
|
||||
if (card->ext_csd.cache_ctrl ^ enable) {
|
||||
if (!enable)
|
||||
timeout = MMC_FLUSH_REQ_TIMEOUT_MS;
|
||||
|
||||
err = mmc_switch_ignore_timeout(card,
|
||||
EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_CACHE_CTRL, enable, timeout);
|
||||
|
||||
if (err == -ETIMEDOUT && !enable) {
|
||||
pr_err("%s:cache disable operation timeout\n",
|
||||
mmc_hostname(card->host));
|
||||
rc = mmc_interrupt_hpi(card);
|
||||
if (rc)
|
||||
pr_err("%s: mmc_interrupt_hpi() failed (%d)\n",
|
||||
mmc_hostname(host), rc);
|
||||
} else if (err) {
|
||||
pr_err("%s: cache %s error %d\n",
|
||||
mmc_hostname(card->host),
|
||||
enable ? "on" : "off",
|
||||
err);
|
||||
} else {
|
||||
card->ext_csd.cache_ctrl = enable;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_cache_ctrl);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
/**
|
||||
|
|
|
@ -26,6 +26,7 @@ struct mmc_bus_ops {
|
|||
int (*power_restore)(struct mmc_host *);
|
||||
int (*alive)(struct mmc_host *);
|
||||
int (*change_bus_speed)(struct mmc_host *, unsigned long *);
|
||||
int (*shutdown)(struct mmc_host *);
|
||||
};
|
||||
|
||||
void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
|
||||
|
|
|
@ -630,6 +630,8 @@ void mmc_of_parse(struct mmc_host *host)
|
|||
host->caps |= MMC_CAP_POWER_OFF_CARD;
|
||||
if (of_find_property(np, "cap-sdio-irq", &len))
|
||||
host->caps |= MMC_CAP_SDIO_IRQ;
|
||||
if (of_find_property(np, "full-pwr-cycle", &len))
|
||||
host->caps2 |= MMC_CAP2_FULL_PWR_CYCLE;
|
||||
if (of_find_property(np, "keep-power-in-suspend", &len))
|
||||
host->pm_caps |= MMC_PM_KEEP_POWER;
|
||||
if (of_find_property(np, "enable-sdio-wakeup", &len))
|
||||
|
|
|
@ -1627,11 +1627,9 @@ reinit:
|
|||
}
|
||||
|
||||
/*
|
||||
* If the host supports the power_off_notify capability then
|
||||
* set the notification byte in the ext_csd register of device
|
||||
* Enable power_off_notification byte in the ext_csd register
|
||||
*/
|
||||
if ((host->caps2 & MMC_CAP2_POWEROFF_NOTIFY) &&
|
||||
(card->ext_csd.rev >= 6)) {
|
||||
if (card->ext_csd.rev >= 6) {
|
||||
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_POWER_OFF_NOTIFICATION,
|
||||
EXT_CSD_POWER_ON,
|
||||
|
@ -1911,12 +1909,11 @@ static void mmc_detect(struct mmc_host *host)
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Suspend callback from host.
|
||||
*/
|
||||
static int mmc_suspend(struct mmc_host *host)
|
||||
static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
|
||||
{
|
||||
int err = 0;
|
||||
unsigned int notify_type = is_suspend ? EXT_CSD_POWER_OFF_SHORT :
|
||||
EXT_CSD_POWER_OFF_LONG;
|
||||
|
||||
BUG_ON(!host);
|
||||
BUG_ON(!host->card);
|
||||
|
@ -1930,11 +1927,14 @@ static int mmc_suspend(struct mmc_host *host)
|
|||
*/
|
||||
mmc_disable_clk_scaling(host);
|
||||
|
||||
err = mmc_cache_ctrl(host, 0);
|
||||
err = mmc_flush_cache(host->card);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (mmc_card_can_sleep(host))
|
||||
if (mmc_can_poweroff_notify(host->card) &&
|
||||
((host->caps2 & MMC_CAP2_FULL_PWR_CYCLE) || !is_suspend))
|
||||
err = mmc_poweroff_notify(host->card, notify_type);
|
||||
else if (mmc_card_can_sleep(host))
|
||||
err = mmc_card_sleep(host);
|
||||
else if (!mmc_host_is_spi(host))
|
||||
err = mmc_deselect_cards(host);
|
||||
|
@ -1945,6 +1945,22 @@ out:
|
|||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Suspend callback from host.
|
||||
*/
|
||||
static int mmc_suspend(struct mmc_host *host)
|
||||
{
|
||||
return _mmc_suspend(host, true);
|
||||
}
|
||||
|
||||
/*
|
||||
* Shutdown callback
|
||||
*/
|
||||
static int mmc_shutdown(struct mmc_host *host)
|
||||
{
|
||||
return _mmc_suspend(host, false);
|
||||
}
|
||||
|
||||
/*
|
||||
* Resume callback from host.
|
||||
*
|
||||
|
@ -2070,6 +2086,7 @@ static const struct mmc_bus_ops mmc_ops = {
|
|||
.power_restore = mmc_power_restore,
|
||||
.alive = mmc_alive,
|
||||
.change_bus_speed = mmc_change_bus_speed,
|
||||
.shutdown = mmc_shutdown,
|
||||
};
|
||||
|
||||
static const struct mmc_bus_ops mmc_ops_unsafe = {
|
||||
|
@ -2082,6 +2099,7 @@ static const struct mmc_bus_ops mmc_ops_unsafe = {
|
|||
.power_restore = mmc_power_restore,
|
||||
.alive = mmc_alive,
|
||||
.change_bus_speed = mmc_change_bus_speed,
|
||||
.shutdown = mmc_shutdown,
|
||||
};
|
||||
|
||||
static void mmc_attach_bus_ops(struct mmc_host *host)
|
||||
|
|
|
@ -930,7 +930,7 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
|
|||
if (!err) {
|
||||
if (retries > 1) {
|
||||
printk(KERN_WARNING
|
||||
"%s: recovered\n",
|
||||
"%s: recovered\n",
|
||||
mmc_hostname(host));
|
||||
}
|
||||
break;
|
||||
|
@ -1302,6 +1302,7 @@ static const struct mmc_bus_ops mmc_sd_ops = {
|
|||
.power_restore = mmc_sd_power_restore,
|
||||
.alive = mmc_sd_alive,
|
||||
.change_bus_speed = mmc_sd_change_bus_speed,
|
||||
.shutdown = mmc_sd_suspend,
|
||||
};
|
||||
|
||||
static const struct mmc_bus_ops mmc_sd_ops_unsafe = {
|
||||
|
@ -1312,6 +1313,7 @@ static const struct mmc_bus_ops mmc_sd_ops_unsafe = {
|
|||
.power_restore = mmc_sd_power_restore,
|
||||
.alive = mmc_sd_alive,
|
||||
.change_bus_speed = mmc_sd_change_bus_speed,
|
||||
.shutdown = mmc_sd_suspend,
|
||||
};
|
||||
|
||||
static void mmc_sd_attach_bus_ops(struct mmc_host *host)
|
||||
|
|
|
@ -3714,7 +3714,7 @@ static int sdhci_msm_probe(struct platform_device *pdev)
|
|||
msm_host->mmc->caps2 |= (MMC_CAP2_BOOTPART_NOACC |
|
||||
MMC_CAP2_DETECT_ON_ERR);
|
||||
msm_host->mmc->caps2 |= MMC_CAP2_CACHE_CTRL;
|
||||
msm_host->mmc->caps2 |= MMC_CAP2_POWEROFF_NOTIFY;
|
||||
msm_host->mmc->caps2 |= MMC_CAP2_FULL_PWR_CYCLE;
|
||||
msm_host->mmc->caps2 |= MMC_CAP2_CLK_SCALE;
|
||||
msm_host->mmc->caps2 |= MMC_CAP2_STOP_REQUEST;
|
||||
msm_host->mmc->caps2 |= MMC_CAP2_ASYNC_SDIO_IRQ_4BIT_MODE;
|
||||
|
|
|
@ -20,31 +20,6 @@ config ASHMEM
|
|||
It is, in theory, a good memory allocator for low-memory devices,
|
||||
because it can discard shared memory units when under memory pressure.
|
||||
|
||||
config ANDROID_LOGGER
|
||||
tristate "Android log driver"
|
||||
default n
|
||||
---help---
|
||||
This adds support for system-wide logging using four log buffers.
|
||||
|
||||
These are:
|
||||
|
||||
1: main
|
||||
2: events
|
||||
3: radio
|
||||
4: system
|
||||
|
||||
Log reading and writing is performed via normal Linux reads and
|
||||
optimized writes. This optimization avoids logging having too
|
||||
much overhead in the system.
|
||||
|
||||
config LOGCAT_SIZE
|
||||
int "Adjust android log buffer sizes"
|
||||
default 256
|
||||
depends on ANDROID_LOGGER
|
||||
help
|
||||
Set logger buffer size. Enter a number greater than zero.
|
||||
Any value less than 256 is recommended. Reduce value to save kernel static memory size.
|
||||
|
||||
config ANDROID_TIMED_OUTPUT
|
||||
bool "Timed output class driver"
|
||||
default y
|
||||
|
@ -69,15 +44,6 @@ config ANDROID_LOW_MEMORY_KILLER_AUTODETECT_OOM_ADJ_VALUES
|
|||
/sys/module/lowmemorykiller/parameters/adj and convert them
|
||||
to oom_score_adj values.
|
||||
|
||||
config ANDROID_INTF_ALARM_DEV
|
||||
bool "Android alarm driver"
|
||||
depends on RTC_CLASS
|
||||
default n
|
||||
---help---
|
||||
Provides non-wakeup and rtc backed wakeup alarms based on rtc or
|
||||
elapsed realtime, and a non-wakeup alarm on the monotonic clock.
|
||||
Also exports the alarm interface to user-space.
|
||||
|
||||
config SYNC
|
||||
bool "Synchronization framework"
|
||||
default n
|
||||
|
|
|
@ -4,11 +4,9 @@ obj-y += ion/
|
|||
obj-$(CONFIG_FIQ_DEBUGGER) += fiq_debugger/
|
||||
|
||||
obj-$(CONFIG_ASHMEM) += ashmem.o
|
||||
obj-$(CONFIG_ANDROID_LOGGER) += logger.o
|
||||
obj-$(CONFIG_ANDROID_TIMED_OUTPUT) += timed_output.o
|
||||
obj-$(CONFIG_ANDROID_TIMED_GPIO) += timed_gpio.o
|
||||
obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER) += lowmemorykiller.o
|
||||
obj-$(CONFIG_ANDROID_INTF_ALARM_DEV) += alarm-dev.o
|
||||
obj-$(CONFIG_SYNC) += sync.o
|
||||
obj-$(CONFIG_SW_SYNC) += sw_sync.o
|
||||
obj-$(CONFIG_ONESHOT_SYNC) += oneshot_sync.o
|
||||
|
|
|
@ -1,462 +0,0 @@
|
|||
/* drivers/rtc/alarm-dev.c
|
||||
*
|
||||
* Copyright (C) 2007-2009 Google, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/time.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/alarmtimer.h>
|
||||
#include "android_alarm.h"
|
||||
|
||||
#define ANDROID_ALARM_PRINT_INFO (1U << 0)
|
||||
#define ANDROID_ALARM_PRINT_IO (1U << 1)
|
||||
#define ANDROID_ALARM_PRINT_INT (1U << 2)
|
||||
|
||||
static int debug_mask = ANDROID_ALARM_PRINT_INFO;
|
||||
module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
|
||||
|
||||
#define alarm_dbg(debug_level_mask, fmt, ...) \
|
||||
do { \
|
||||
if (debug_mask & ANDROID_ALARM_PRINT_##debug_level_mask) \
|
||||
pr_info(fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define ANDROID_ALARM_WAKEUP_MASK ( \
|
||||
ANDROID_ALARM_RTC_WAKEUP_MASK | \
|
||||
ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK | \
|
||||
ANDROID_ALARM_RTC_POWEROFF_WAKEUP_MASK)
|
||||
|
||||
static int alarm_opened;
|
||||
static DEFINE_SPINLOCK(alarm_slock);
|
||||
static DEFINE_MUTEX(alarm_mutex);
|
||||
static struct wakeup_source alarm_wake_lock;
|
||||
static DECLARE_WAIT_QUEUE_HEAD(alarm_wait_queue);
|
||||
static uint32_t alarm_pending;
|
||||
static uint32_t alarm_enabled;
|
||||
static uint32_t wait_pending;
|
||||
|
||||
struct devalarm {
|
||||
union {
|
||||
struct hrtimer hrt;
|
||||
struct alarm alrm;
|
||||
} u;
|
||||
enum android_alarm_type type;
|
||||
};
|
||||
|
||||
static struct devalarm alarms[ANDROID_ALARM_TYPE_COUNT];
|
||||
|
||||
|
||||
static int is_wakeup(enum android_alarm_type type)
|
||||
{
|
||||
return (type == ANDROID_ALARM_RTC_WAKEUP ||
|
||||
type == ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP ||
|
||||
type == ANDROID_ALARM_RTC_POWEROFF_WAKEUP);
|
||||
}
|
||||
|
||||
|
||||
static void devalarm_start(struct devalarm *alrm, ktime_t exp)
|
||||
{
|
||||
if (is_wakeup(alrm->type))
|
||||
alarm_start(&alrm->u.alrm, exp);
|
||||
else
|
||||
hrtimer_start(&alrm->u.hrt, exp, HRTIMER_MODE_ABS);
|
||||
}
|
||||
|
||||
|
||||
static int devalarm_try_to_cancel(struct devalarm *alrm)
|
||||
{
|
||||
if (is_wakeup(alrm->type))
|
||||
return alarm_try_to_cancel(&alrm->u.alrm);
|
||||
return hrtimer_try_to_cancel(&alrm->u.hrt);
|
||||
}
|
||||
|
||||
static void devalarm_cancel(struct devalarm *alrm)
|
||||
{
|
||||
if (is_wakeup(alrm->type))
|
||||
alarm_cancel(&alrm->u.alrm);
|
||||
else
|
||||
hrtimer_cancel(&alrm->u.hrt);
|
||||
}
|
||||
|
||||
static void alarm_clear(enum android_alarm_type alarm_type, struct timespec *ts)
|
||||
{
|
||||
uint32_t alarm_type_mask = 1U << alarm_type;
|
||||
unsigned long flags;
|
||||
|
||||
mutex_lock(&alarm_mutex);
|
||||
spin_lock_irqsave(&alarm_slock, flags);
|
||||
alarm_dbg(IO, "alarm %d clear\n", alarm_type);
|
||||
devalarm_try_to_cancel(&alarms[alarm_type]);
|
||||
if (alarm_pending) {
|
||||
alarm_pending &= ~alarm_type_mask;
|
||||
if (!alarm_pending && !wait_pending)
|
||||
__pm_relax(&alarm_wake_lock);
|
||||
}
|
||||
alarm_enabled &= ~alarm_type_mask;
|
||||
spin_unlock_irqrestore(&alarm_slock, flags);
|
||||
|
||||
if (alarm_type == ANDROID_ALARM_RTC_POWEROFF_WAKEUP)
|
||||
set_power_on_alarm(ts->tv_sec, 0);
|
||||
mutex_unlock(&alarm_mutex);
|
||||
}
|
||||
|
||||
static void alarm_set(enum android_alarm_type alarm_type,
|
||||
struct timespec *ts)
|
||||
{
|
||||
uint32_t alarm_type_mask = 1U << alarm_type;
|
||||
unsigned long flags;
|
||||
|
||||
mutex_lock(&alarm_mutex);
|
||||
spin_lock_irqsave(&alarm_slock, flags);
|
||||
alarm_dbg(IO, "alarm %d set %ld.%09ld\n",
|
||||
alarm_type, ts->tv_sec, ts->tv_nsec);
|
||||
alarm_enabled |= alarm_type_mask;
|
||||
devalarm_start(&alarms[alarm_type], timespec_to_ktime(*ts));
|
||||
spin_unlock_irqrestore(&alarm_slock, flags);
|
||||
|
||||
if (alarm_type == ANDROID_ALARM_RTC_POWEROFF_WAKEUP)
|
||||
set_power_on_alarm(ts->tv_sec, 1);
|
||||
mutex_unlock(&alarm_mutex);
|
||||
}
|
||||
|
||||
static int alarm_wait(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
int rv = 0;
|
||||
|
||||
spin_lock_irqsave(&alarm_slock, flags);
|
||||
alarm_dbg(IO, "alarm wait\n");
|
||||
if (!alarm_pending && wait_pending) {
|
||||
__pm_relax(&alarm_wake_lock);
|
||||
wait_pending = 0;
|
||||
}
|
||||
spin_unlock_irqrestore(&alarm_slock, flags);
|
||||
|
||||
rv = wait_event_interruptible(alarm_wait_queue, alarm_pending);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
spin_lock_irqsave(&alarm_slock, flags);
|
||||
rv = alarm_pending;
|
||||
wait_pending = 1;
|
||||
alarm_pending = 0;
|
||||
spin_unlock_irqrestore(&alarm_slock, flags);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int alarm_set_rtc(struct timespec *ts)
|
||||
{
|
||||
struct rtc_time new_rtc_tm;
|
||||
struct rtc_device *rtc_dev;
|
||||
unsigned long flags;
|
||||
int rv = 0;
|
||||
|
||||
rtc_time_to_tm(ts->tv_sec, &new_rtc_tm);
|
||||
rtc_dev = alarmtimer_get_rtcdev();
|
||||
rv = do_settimeofday(ts);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
if (rtc_dev)
|
||||
rv = rtc_set_time(rtc_dev, &new_rtc_tm);
|
||||
|
||||
spin_lock_irqsave(&alarm_slock, flags);
|
||||
alarm_pending |= ANDROID_ALARM_TIME_CHANGE_MASK;
|
||||
wake_up(&alarm_wait_queue);
|
||||
spin_unlock_irqrestore(&alarm_slock, flags);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int alarm_get_time(enum android_alarm_type alarm_type,
|
||||
struct timespec *ts)
|
||||
{
|
||||
int rv = 0;
|
||||
|
||||
switch (alarm_type) {
|
||||
case ANDROID_ALARM_RTC_WAKEUP:
|
||||
case ANDROID_ALARM_RTC:
|
||||
case ANDROID_ALARM_RTC_POWEROFF_WAKEUP:
|
||||
getnstimeofday(ts);
|
||||
break;
|
||||
case ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP:
|
||||
case ANDROID_ALARM_ELAPSED_REALTIME:
|
||||
get_monotonic_boottime(ts);
|
||||
break;
|
||||
case ANDROID_ALARM_SYSTEMTIME:
|
||||
ktime_get_ts(ts);
|
||||
break;
|
||||
default:
|
||||
rv = -EINVAL;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static long alarm_do_ioctl(struct file *file, unsigned int cmd,
|
||||
struct timespec *ts)
|
||||
{
|
||||
int rv = 0;
|
||||
unsigned long flags;
|
||||
enum android_alarm_type alarm_type = ANDROID_ALARM_IOCTL_TO_TYPE(cmd);
|
||||
|
||||
if (alarm_type >= ANDROID_ALARM_TYPE_COUNT)
|
||||
return -EINVAL;
|
||||
|
||||
if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_GET_TIME(0)) {
|
||||
if ((file->f_flags & O_ACCMODE) == O_RDONLY)
|
||||
return -EPERM;
|
||||
if (file->private_data == NULL &&
|
||||
cmd != ANDROID_ALARM_SET_RTC) {
|
||||
spin_lock_irqsave(&alarm_slock, flags);
|
||||
if (alarm_opened) {
|
||||
spin_unlock_irqrestore(&alarm_slock, flags);
|
||||
return -EBUSY;
|
||||
}
|
||||
alarm_opened = 1;
|
||||
file->private_data = (void *)1;
|
||||
spin_unlock_irqrestore(&alarm_slock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
switch (ANDROID_ALARM_BASE_CMD(cmd)) {
|
||||
case ANDROID_ALARM_CLEAR(0):
|
||||
alarm_clear(alarm_type, ts);
|
||||
break;
|
||||
case ANDROID_ALARM_SET(0):
|
||||
alarm_set(alarm_type, ts);
|
||||
break;
|
||||
case ANDROID_ALARM_SET_AND_WAIT(0):
|
||||
alarm_set(alarm_type, ts);
|
||||
/* fall though */
|
||||
case ANDROID_ALARM_WAIT:
|
||||
rv = alarm_wait();
|
||||
break;
|
||||
case ANDROID_ALARM_SET_RTC:
|
||||
rv = alarm_set_rtc(ts);
|
||||
break;
|
||||
case ANDROID_ALARM_GET_TIME(0):
|
||||
rv = alarm_get_time(alarm_type, ts);
|
||||
break;
|
||||
|
||||
default:
|
||||
rv = -EINVAL;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
|
||||
struct timespec ts;
|
||||
int rv;
|
||||
|
||||
switch (ANDROID_ALARM_BASE_CMD(cmd)) {
|
||||
case ANDROID_ALARM_SET_AND_WAIT(0):
|
||||
case ANDROID_ALARM_SET(0):
|
||||
case ANDROID_ALARM_SET_RTC:
|
||||
case ANDROID_ALARM_CLEAR(0):
|
||||
if (copy_from_user(&ts, (void __user *)arg, sizeof(ts)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
rv = alarm_do_ioctl(file, cmd, &ts);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
switch (ANDROID_ALARM_BASE_CMD(cmd)) {
|
||||
case ANDROID_ALARM_GET_TIME(0):
|
||||
if (copy_to_user((void __user *)arg, &ts, sizeof(ts)))
|
||||
return -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#ifdef CONFIG_COMPAT
|
||||
static long alarm_compat_ioctl(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
|
||||
struct timespec ts;
|
||||
int rv;
|
||||
|
||||
switch (ANDROID_ALARM_BASE_CMD(cmd)) {
|
||||
case ANDROID_ALARM_SET_AND_WAIT_COMPAT(0):
|
||||
case ANDROID_ALARM_SET_COMPAT(0):
|
||||
case ANDROID_ALARM_SET_RTC_COMPAT:
|
||||
if (compat_get_timespec(&ts, (void __user *)arg))
|
||||
return -EFAULT;
|
||||
/* fall through */
|
||||
case ANDROID_ALARM_GET_TIME_COMPAT(0):
|
||||
cmd = ANDROID_ALARM_COMPAT_TO_NORM(cmd);
|
||||
break;
|
||||
}
|
||||
|
||||
rv = alarm_do_ioctl(file, cmd, &ts);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
switch (ANDROID_ALARM_BASE_CMD(cmd)) {
|
||||
case ANDROID_ALARM_GET_TIME(0): /* NOTE: we modified cmd above */
|
||||
if (compat_put_timespec(&ts, (void __user *)arg))
|
||||
return -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int alarm_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
file->private_data = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int alarm_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
int i;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&alarm_slock, flags);
|
||||
if (file->private_data) {
|
||||
for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++) {
|
||||
uint32_t alarm_type_mask = 1U << i;
|
||||
|
||||
if (alarm_enabled & alarm_type_mask) {
|
||||
alarm_dbg(INFO,
|
||||
"%s: clear alarm, pending %d\n",
|
||||
__func__,
|
||||
!!(alarm_pending & alarm_type_mask));
|
||||
alarm_enabled &= ~alarm_type_mask;
|
||||
}
|
||||
spin_unlock_irqrestore(&alarm_slock, flags);
|
||||
devalarm_cancel(&alarms[i]);
|
||||
spin_lock_irqsave(&alarm_slock, flags);
|
||||
}
|
||||
if (alarm_pending | wait_pending) {
|
||||
if (alarm_pending)
|
||||
alarm_dbg(INFO, "%s: clear pending alarms %x\n",
|
||||
__func__, alarm_pending);
|
||||
__pm_relax(&alarm_wake_lock);
|
||||
wait_pending = 0;
|
||||
alarm_pending = 0;
|
||||
}
|
||||
alarm_opened = 0;
|
||||
}
|
||||
spin_unlock_irqrestore(&alarm_slock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void devalarm_triggered(struct devalarm *alarm)
|
||||
{
|
||||
unsigned long flags;
|
||||
uint32_t alarm_type_mask = 1U << alarm->type;
|
||||
|
||||
alarm_dbg(INT, "%s: type %d\n", __func__, alarm->type);
|
||||
spin_lock_irqsave(&alarm_slock, flags);
|
||||
if (alarm_enabled & alarm_type_mask) {
|
||||
__pm_wakeup_event(&alarm_wake_lock, 5000); /* 5secs */
|
||||
alarm_enabled &= ~alarm_type_mask;
|
||||
alarm_pending |= alarm_type_mask;
|
||||
wake_up(&alarm_wait_queue);
|
||||
}
|
||||
spin_unlock_irqrestore(&alarm_slock, flags);
|
||||
}
|
||||
|
||||
|
||||
static enum hrtimer_restart devalarm_hrthandler(struct hrtimer *hrt)
|
||||
{
|
||||
struct devalarm *devalrm = container_of(hrt, struct devalarm, u.hrt);
|
||||
|
||||
devalarm_triggered(devalrm);
|
||||
return HRTIMER_NORESTART;
|
||||
}
|
||||
|
||||
static enum alarmtimer_restart devalarm_alarmhandler(struct alarm *alrm,
|
||||
ktime_t now)
|
||||
{
|
||||
struct devalarm *devalrm = container_of(alrm, struct devalarm, u.alrm);
|
||||
|
||||
devalarm_triggered(devalrm);
|
||||
return ALARMTIMER_NORESTART;
|
||||
}
|
||||
|
||||
|
||||
static const struct file_operations alarm_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.unlocked_ioctl = alarm_ioctl,
|
||||
.open = alarm_open,
|
||||
.release = alarm_release,
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compat_ioctl = alarm_compat_ioctl,
|
||||
#endif
|
||||
};
|
||||
|
||||
static struct miscdevice alarm_device = {
|
||||
.minor = MISC_DYNAMIC_MINOR,
|
||||
.name = "alarm",
|
||||
.fops = &alarm_fops,
|
||||
};
|
||||
|
||||
static int __init alarm_dev_init(void)
|
||||
{
|
||||
int err;
|
||||
int i;
|
||||
|
||||
err = misc_register(&alarm_device);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
alarm_init(&alarms[ANDROID_ALARM_RTC_WAKEUP].u.alrm,
|
||||
ALARM_REALTIME, devalarm_alarmhandler);
|
||||
hrtimer_init(&alarms[ANDROID_ALARM_RTC].u.hrt,
|
||||
CLOCK_REALTIME, HRTIMER_MODE_ABS);
|
||||
alarm_init(&alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].u.alrm,
|
||||
ALARM_BOOTTIME, devalarm_alarmhandler);
|
||||
hrtimer_init(&alarms[ANDROID_ALARM_ELAPSED_REALTIME].u.hrt,
|
||||
CLOCK_BOOTTIME, HRTIMER_MODE_ABS);
|
||||
hrtimer_init(&alarms[ANDROID_ALARM_SYSTEMTIME].u.hrt,
|
||||
CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
|
||||
alarm_init(&alarms[ANDROID_ALARM_RTC_POWEROFF_WAKEUP].u.alrm,
|
||||
ALARM_REALTIME, devalarm_alarmhandler);
|
||||
|
||||
for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++) {
|
||||
alarms[i].type = i;
|
||||
if (!is_wakeup(i))
|
||||
alarms[i].u.hrt.function = devalarm_hrthandler;
|
||||
}
|
||||
|
||||
wakeup_source_init(&alarm_wake_lock, "alarm");
|
||||
|
||||
power_on_alarm_init();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit alarm_dev_exit(void)
|
||||
{
|
||||
misc_deregister(&alarm_device);
|
||||
wakeup_source_trash(&alarm_wake_lock);
|
||||
}
|
||||
|
||||
module_init(alarm_dev_init);
|
||||
module_exit(alarm_dev_exit);
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
/* include/linux/android_alarm.h
|
||||
*
|
||||
* Copyright (C) 2006-2007 Google, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_ANDROID_ALARM_H
|
||||
#define _LINUX_ANDROID_ALARM_H
|
||||
|
||||
#include <linux/compat.h>
|
||||
#include <linux/ioctl.h>
|
||||
|
||||
#include "uapi/android_alarm.h"
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
#define ANDROID_ALARM_SET_COMPAT(type) ALARM_IOW(2, type, \
|
||||
struct compat_timespec)
|
||||
#define ANDROID_ALARM_SET_AND_WAIT_COMPAT(type) ALARM_IOW(3, type, \
|
||||
struct compat_timespec)
|
||||
#define ANDROID_ALARM_GET_TIME_COMPAT(type) ALARM_IOW(4, type, \
|
||||
struct compat_timespec)
|
||||
#define ANDROID_ALARM_SET_RTC_COMPAT _IOW('a', 5, \
|
||||
struct compat_timespec)
|
||||
#define ANDROID_ALARM_IOCTL_NR(cmd) (_IOC_NR(cmd) & ((1<<4)-1))
|
||||
#define ANDROID_ALARM_COMPAT_TO_NORM(cmd) \
|
||||
ALARM_IOW(ANDROID_ALARM_IOCTL_NR(cmd), \
|
||||
ANDROID_ALARM_IOCTL_TO_TYPE(cmd), \
|
||||
struct timespec)
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -376,7 +376,7 @@ static int ashmem_shrink(struct shrinker *s, struct shrink_control *sc)
|
|||
loff_t start = range->pgstart * PAGE_SIZE;
|
||||
loff_t end = (range->pgend + 1) * PAGE_SIZE;
|
||||
|
||||
do_fallocate(range->asma->file,
|
||||
range->asma->file->f_op->fallocate(range->asma->file,
|
||||
FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
|
||||
start, end - start);
|
||||
range->purged = ASHMEM_WAS_PURGED;
|
||||
|
|
|
@ -429,7 +429,8 @@ static void fiq_debugger_help(struct fiq_debugger_state *state)
|
|||
" pc PC status\n"
|
||||
" regs Register dump\n"
|
||||
" allregs Extended Register dump\n"
|
||||
" bt Stack trace\n"
|
||||
" bt Stack trace\n");
|
||||
fiq_debugger_printf(&state->output,
|
||||
" reboot [<c>] Reboot with command <c>\n"
|
||||
" reset [<c>] Hard reset with command <c>\n"
|
||||
" irqs Interupt status\n"
|
||||
|
|
|
@ -1,858 +0,0 @@
|
|||
/*
|
||||
* drivers/misc/logger.c
|
||||
*
|
||||
* A Logging Subsystem
|
||||
*
|
||||
* Copyright (C) 2007-2008 Google, Inc.
|
||||
*
|
||||
* Robert Love <rlove@google.com>
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "logger: " fmt
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/aio.h>
|
||||
#include "logger.h"
|
||||
|
||||
#include <asm/ioctls.h>
|
||||
|
||||
#ifndef CONFIG_LOGCAT_SIZE
|
||||
#define CONFIG_LOGCAT_SIZE 256
|
||||
#endif
|
||||
|
||||
/**
|
||||
* struct logger_log - represents a specific log, such as 'main' or 'radio'
|
||||
* @buffer: The actual ring buffer
|
||||
* @misc: The "misc" device representing the log
|
||||
* @wq: The wait queue for @readers
|
||||
* @readers: This log's readers
|
||||
* @mutex: The mutex that protects the @buffer
|
||||
* @w_off: The current write head offset
|
||||
* @head: The head, or location that readers start reading at.
|
||||
* @size: The size of the log
|
||||
* @logs: The list of log channels
|
||||
*
|
||||
* This structure lives from module insertion until module removal, so it does
|
||||
* not need additional reference counting. The structure is protected by the
|
||||
* mutex 'mutex'.
|
||||
*/
|
||||
struct logger_log {
|
||||
unsigned char *buffer;
|
||||
struct miscdevice misc;
|
||||
wait_queue_head_t wq;
|
||||
struct list_head readers;
|
||||
struct mutex mutex;
|
||||
size_t w_off;
|
||||
size_t head;
|
||||
size_t size;
|
||||
struct list_head logs;
|
||||
};
|
||||
|
||||
static LIST_HEAD(log_list);
|
||||
|
||||
|
||||
/**
|
||||
* struct logger_reader - a logging device open for reading
|
||||
* @log: The associated log
|
||||
* @list: The associated entry in @logger_log's list
|
||||
* @r_off: The current read head offset.
|
||||
* @r_all: Reader can read all entries
|
||||
* @r_ver: Reader ABI version
|
||||
*
|
||||
* This object lives from open to release, so we don't need additional
|
||||
* reference counting. The structure is protected by log->mutex.
|
||||
*/
|
||||
struct logger_reader {
|
||||
struct logger_log *log;
|
||||
struct list_head list;
|
||||
size_t r_off;
|
||||
bool r_all;
|
||||
int r_ver;
|
||||
};
|
||||
|
||||
/* logger_offset - returns index 'n' into the log via (optimized) modulus */
|
||||
static size_t logger_offset(struct logger_log *log, size_t n)
|
||||
{
|
||||
return n & (log->size - 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* file_get_log - Given a file structure, return the associated log
|
||||
*
|
||||
* This isn't aesthetic. We have several goals:
|
||||
*
|
||||
* 1) Need to quickly obtain the associated log during an I/O operation
|
||||
* 2) Readers need to maintain state (logger_reader)
|
||||
* 3) Writers need to be very fast (open() should be a near no-op)
|
||||
*
|
||||
* In the reader case, we can trivially go file->logger_reader->logger_log.
|
||||
* For a writer, we don't want to maintain a logger_reader, so we just go
|
||||
* file->logger_log. Thus what file->private_data points at depends on whether
|
||||
* or not the file was opened for reading. This function hides that dirtiness.
|
||||
*/
|
||||
static inline struct logger_log *file_get_log(struct file *file)
|
||||
{
|
||||
if (file->f_mode & FMODE_READ) {
|
||||
struct logger_reader *reader = file->private_data;
|
||||
|
||||
return reader->log;
|
||||
} else
|
||||
return file->private_data;
|
||||
}
|
||||
|
||||
/*
|
||||
* get_entry_header - returns a pointer to the logger_entry header within
|
||||
* 'log' starting at offset 'off'. A temporary logger_entry 'scratch' must
|
||||
* be provided. Typically the return value will be a pointer within
|
||||
* 'logger->buf'. However, a pointer to 'scratch' may be returned if
|
||||
* the log entry spans the end and beginning of the circular buffer.
|
||||
*/
|
||||
static struct logger_entry *get_entry_header(struct logger_log *log,
|
||||
size_t off, struct logger_entry *scratch)
|
||||
{
|
||||
size_t len = min(sizeof(struct logger_entry), log->size - off);
|
||||
|
||||
if (len != sizeof(struct logger_entry)) {
|
||||
memcpy(((void *) scratch), log->buffer + off, len);
|
||||
memcpy(((void *) scratch) + len, log->buffer,
|
||||
sizeof(struct logger_entry) - len);
|
||||
return scratch;
|
||||
}
|
||||
|
||||
return (struct logger_entry *) (log->buffer + off);
|
||||
}
|
||||
|
||||
/*
|
||||
* get_entry_msg_len - Grabs the length of the message of the entry
|
||||
* starting from from 'off'.
|
||||
*
|
||||
* An entry length is 2 bytes (16 bits) in host endian order.
|
||||
* In the log, the length does not include the size of the log entry structure.
|
||||
* This function returns the size including the log entry structure.
|
||||
*
|
||||
* Caller needs to hold log->mutex.
|
||||
*/
|
||||
static __u32 get_entry_msg_len(struct logger_log *log, size_t off)
|
||||
{
|
||||
struct logger_entry scratch;
|
||||
struct logger_entry *entry;
|
||||
|
||||
entry = get_entry_header(log, off, &scratch);
|
||||
return entry->len;
|
||||
}
|
||||
|
||||
static size_t get_user_hdr_len(int ver)
|
||||
{
|
||||
if (ver < 2)
|
||||
return sizeof(struct user_logger_entry_compat);
|
||||
else
|
||||
return sizeof(struct logger_entry);
|
||||
}
|
||||
|
||||
static ssize_t copy_header_to_user(int ver, struct logger_entry *entry,
|
||||
char __user *buf)
|
||||
{
|
||||
void *hdr;
|
||||
size_t hdr_len;
|
||||
struct user_logger_entry_compat v1;
|
||||
|
||||
if (ver < 2) {
|
||||
v1.len = entry->len;
|
||||
v1.__pad = 0;
|
||||
v1.pid = entry->pid;
|
||||
v1.tid = entry->tid;
|
||||
v1.sec = entry->sec;
|
||||
v1.nsec = entry->nsec;
|
||||
hdr = &v1;
|
||||
hdr_len = sizeof(struct user_logger_entry_compat);
|
||||
} else {
|
||||
hdr = entry;
|
||||
hdr_len = sizeof(struct logger_entry);
|
||||
}
|
||||
|
||||
return copy_to_user(buf, hdr, hdr_len);
|
||||
}
|
||||
|
||||
/*
|
||||
* do_read_log_to_user - reads exactly 'count' bytes from 'log' into the
|
||||
* user-space buffer 'buf'. Returns 'count' on success.
|
||||
*
|
||||
* Caller must hold log->mutex.
|
||||
*/
|
||||
static ssize_t do_read_log_to_user(struct logger_log *log,
|
||||
struct logger_reader *reader,
|
||||
char __user *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct logger_entry scratch;
|
||||
struct logger_entry *entry;
|
||||
size_t len;
|
||||
size_t msg_start;
|
||||
|
||||
/*
|
||||
* First, copy the header to userspace, using the version of
|
||||
* the header requested
|
||||
*/
|
||||
entry = get_entry_header(log, reader->r_off, &scratch);
|
||||
if (copy_header_to_user(reader->r_ver, entry, buf))
|
||||
return -EFAULT;
|
||||
|
||||
count -= get_user_hdr_len(reader->r_ver);
|
||||
buf += get_user_hdr_len(reader->r_ver);
|
||||
msg_start = logger_offset(log,
|
||||
reader->r_off + sizeof(struct logger_entry));
|
||||
|
||||
/*
|
||||
* We read from the msg in two disjoint operations. First, we read from
|
||||
* the current msg head offset up to 'count' bytes or to the end of
|
||||
* the log, whichever comes first.
|
||||
*/
|
||||
len = min(count, log->size - msg_start);
|
||||
if (copy_to_user(buf, log->buffer + msg_start, len))
|
||||
return -EFAULT;
|
||||
|
||||
/*
|
||||
* Second, we read any remaining bytes, starting back at the head of
|
||||
* the log.
|
||||
*/
|
||||
if (count != len)
|
||||
if (copy_to_user(buf + len, log->buffer, count - len))
|
||||
return -EFAULT;
|
||||
|
||||
reader->r_off = logger_offset(log, reader->r_off +
|
||||
sizeof(struct logger_entry) + count);
|
||||
|
||||
return count + get_user_hdr_len(reader->r_ver);
|
||||
}
|
||||
|
||||
/*
|
||||
* get_next_entry_by_uid - Starting at 'off', returns an offset into
|
||||
* 'log->buffer' which contains the first entry readable by 'euid'
|
||||
*/
|
||||
static size_t get_next_entry_by_uid(struct logger_log *log,
|
||||
size_t off, kuid_t euid)
|
||||
{
|
||||
while (off != log->w_off) {
|
||||
struct logger_entry *entry;
|
||||
struct logger_entry scratch;
|
||||
size_t next_len;
|
||||
|
||||
entry = get_entry_header(log, off, &scratch);
|
||||
|
||||
if (uid_eq(entry->euid, euid))
|
||||
return off;
|
||||
|
||||
next_len = sizeof(struct logger_entry) + entry->len;
|
||||
off = logger_offset(log, off + next_len);
|
||||
}
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
/*
|
||||
* logger_read - our log's read() method
|
||||
*
|
||||
* Behavior:
|
||||
*
|
||||
* - O_NONBLOCK works
|
||||
* - If there are no log entries to read, blocks until log is written to
|
||||
* - Atomically reads exactly one log entry
|
||||
*
|
||||
* Will set errno to EINVAL if read
|
||||
* buffer is insufficient to hold next entry.
|
||||
*/
|
||||
static ssize_t logger_read(struct file *file, char __user *buf,
|
||||
size_t count, loff_t *pos)
|
||||
{
|
||||
struct logger_reader *reader = file->private_data;
|
||||
struct logger_log *log = reader->log;
|
||||
ssize_t ret;
|
||||
DEFINE_WAIT(wait);
|
||||
|
||||
start:
|
||||
while (1) {
|
||||
mutex_lock(&log->mutex);
|
||||
|
||||
prepare_to_wait(&log->wq, &wait, TASK_INTERRUPTIBLE);
|
||||
|
||||
ret = (log->w_off == reader->r_off);
|
||||
mutex_unlock(&log->mutex);
|
||||
if (!ret)
|
||||
break;
|
||||
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
ret = -EAGAIN;
|
||||
break;
|
||||
}
|
||||
|
||||
if (signal_pending(current)) {
|
||||
ret = -EINTR;
|
||||
break;
|
||||
}
|
||||
|
||||
schedule();
|
||||
}
|
||||
|
||||
finish_wait(&log->wq, &wait);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&log->mutex);
|
||||
|
||||
if (!reader->r_all)
|
||||
reader->r_off = get_next_entry_by_uid(log,
|
||||
reader->r_off, current_euid());
|
||||
|
||||
/* is there still something to read or did we race? */
|
||||
if (unlikely(log->w_off == reader->r_off)) {
|
||||
mutex_unlock(&log->mutex);
|
||||
goto start;
|
||||
}
|
||||
|
||||
/* get the size of the next entry */
|
||||
ret = get_user_hdr_len(reader->r_ver) +
|
||||
get_entry_msg_len(log, reader->r_off);
|
||||
if (count < ret) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* get exactly one entry from the log */
|
||||
ret = do_read_log_to_user(log, reader, buf, ret);
|
||||
|
||||
out:
|
||||
mutex_unlock(&log->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* get_next_entry - return the offset of the first valid entry at least 'len'
|
||||
* bytes after 'off'.
|
||||
*
|
||||
* Caller must hold log->mutex.
|
||||
*/
|
||||
static size_t get_next_entry(struct logger_log *log, size_t off, size_t len)
|
||||
{
|
||||
size_t count = 0;
|
||||
|
||||
do {
|
||||
size_t nr = sizeof(struct logger_entry) +
|
||||
get_entry_msg_len(log, off);
|
||||
off = logger_offset(log, off + nr);
|
||||
count += nr;
|
||||
} while (count < len);
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
/*
|
||||
* is_between - is a < c < b, accounting for wrapping of a, b, and c
|
||||
* positions in the buffer
|
||||
*
|
||||
* That is, if a<b, check for c between a and b
|
||||
* and if a>b, check for c outside (not between) a and b
|
||||
*
|
||||
* |------- a xxxxxxxx b --------|
|
||||
* c^
|
||||
*
|
||||
* |xxxxx b --------- a xxxxxxxxx|
|
||||
* c^
|
||||
* or c^
|
||||
*/
|
||||
static inline int is_between(size_t a, size_t b, size_t c)
|
||||
{
|
||||
if (a < b) {
|
||||
/* is c between a and b? */
|
||||
if (a < c && c <= b)
|
||||
return 1;
|
||||
} else {
|
||||
/* is c outside of b through a? */
|
||||
if (c <= b || a < c)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* fix_up_readers - walk the list of all readers and "fix up" any who were
|
||||
* lapped by the writer; also do the same for the default "start head".
|
||||
* We do this by "pulling forward" the readers and start head to the first
|
||||
* entry after the new write head.
|
||||
*
|
||||
* The caller needs to hold log->mutex.
|
||||
*/
|
||||
static void fix_up_readers(struct logger_log *log, size_t len)
|
||||
{
|
||||
size_t old = log->w_off;
|
||||
size_t new = logger_offset(log, old + len);
|
||||
struct logger_reader *reader;
|
||||
|
||||
if (is_between(old, new, log->head))
|
||||
log->head = get_next_entry(log, log->head, len);
|
||||
|
||||
list_for_each_entry(reader, &log->readers, list)
|
||||
if (is_between(old, new, reader->r_off))
|
||||
reader->r_off = get_next_entry(log, reader->r_off, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* do_write_log - writes 'len' bytes from 'buf' to 'log'
|
||||
*
|
||||
* The caller needs to hold log->mutex.
|
||||
*/
|
||||
static void do_write_log(struct logger_log *log, const void *buf, size_t count)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
len = min(count, log->size - log->w_off);
|
||||
memcpy(log->buffer + log->w_off, buf, len);
|
||||
|
||||
if (count != len)
|
||||
memcpy(log->buffer, buf + len, count - len);
|
||||
|
||||
log->w_off = logger_offset(log, log->w_off + count);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* do_write_log_user - writes 'len' bytes from the user-space buffer 'buf' to
|
||||
* the log 'log'
|
||||
*
|
||||
* The caller needs to hold log->mutex.
|
||||
*
|
||||
* Returns 'count' on success, negative error code on failure.
|
||||
*/
|
||||
static ssize_t do_write_log_from_user(struct logger_log *log,
|
||||
const void __user *buf, size_t count)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
len = min(count, log->size - log->w_off);
|
||||
if (len && copy_from_user(log->buffer + log->w_off, buf, len))
|
||||
return -EFAULT;
|
||||
|
||||
if (count != len)
|
||||
if (copy_from_user(log->buffer, buf + len, count - len))
|
||||
/*
|
||||
* Note that by not updating w_off, this abandons the
|
||||
* portion of the new entry that *was* successfully
|
||||
* copied, just above. This is intentional to avoid
|
||||
* message corruption from missing fragments.
|
||||
*/
|
||||
return -EFAULT;
|
||||
|
||||
log->w_off = logger_offset(log, log->w_off + count);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/*
|
||||
* logger_aio_write - our write method, implementing support for write(),
|
||||
* writev(), and aio_write(). Writes are our fast path, and we try to optimize
|
||||
* them above all else.
|
||||
*/
|
||||
static ssize_t logger_aio_write(struct kiocb *iocb, const struct iovec *iov,
|
||||
unsigned long nr_segs, loff_t ppos)
|
||||
{
|
||||
struct logger_log *log = file_get_log(iocb->ki_filp);
|
||||
size_t orig;
|
||||
struct logger_entry header;
|
||||
struct timespec now;
|
||||
ssize_t ret = 0;
|
||||
|
||||
now = current_kernel_time();
|
||||
|
||||
header.pid = current->tgid;
|
||||
header.tid = current->pid;
|
||||
header.sec = now.tv_sec;
|
||||
header.nsec = now.tv_nsec;
|
||||
header.euid = current_euid();
|
||||
header.len = min_t(size_t, iocb->ki_left, LOGGER_ENTRY_MAX_PAYLOAD);
|
||||
header.hdr_size = sizeof(struct logger_entry);
|
||||
|
||||
/* null writes succeed, return zero */
|
||||
if (unlikely(!header.len))
|
||||
return 0;
|
||||
|
||||
mutex_lock(&log->mutex);
|
||||
|
||||
orig = log->w_off;
|
||||
|
||||
/*
|
||||
* Fix up any readers, pulling them forward to the first readable
|
||||
* entry after (what will be) the new write offset. We do this now
|
||||
* because if we partially fail, we can end up with clobbered log
|
||||
* entries that encroach on readable buffer.
|
||||
*/
|
||||
fix_up_readers(log, sizeof(struct logger_entry) + header.len);
|
||||
|
||||
do_write_log(log, &header, sizeof(struct logger_entry));
|
||||
|
||||
while (nr_segs-- > 0) {
|
||||
size_t len;
|
||||
ssize_t nr;
|
||||
|
||||
/* figure out how much of this vector we can keep */
|
||||
len = min_t(size_t, iov->iov_len, header.len - ret);
|
||||
|
||||
/* write out this segment's payload */
|
||||
nr = do_write_log_from_user(log, iov->iov_base, len);
|
||||
if (unlikely(nr < 0)) {
|
||||
log->w_off = orig;
|
||||
mutex_unlock(&log->mutex);
|
||||
return nr;
|
||||
}
|
||||
|
||||
iov++;
|
||||
ret += nr;
|
||||
}
|
||||
|
||||
mutex_unlock(&log->mutex);
|
||||
|
||||
/* wake up any blocked readers */
|
||||
wake_up_interruptible(&log->wq);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct logger_log *get_log_from_minor(int minor)
|
||||
{
|
||||
struct logger_log *log;
|
||||
|
||||
list_for_each_entry(log, &log_list, logs)
|
||||
if (log->misc.minor == minor)
|
||||
return log;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* logger_open - the log's open() file operation
|
||||
*
|
||||
* Note how near a no-op this is in the write-only case. Keep it that way!
|
||||
*/
|
||||
static int logger_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct logger_log *log;
|
||||
int ret;
|
||||
|
||||
ret = nonseekable_open(inode, file);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
log = get_log_from_minor(MINOR(inode->i_rdev));
|
||||
if (!log)
|
||||
return -ENODEV;
|
||||
|
||||
if (file->f_mode & FMODE_READ) {
|
||||
struct logger_reader *reader;
|
||||
|
||||
reader = kmalloc(sizeof(struct logger_reader), GFP_KERNEL);
|
||||
if (!reader)
|
||||
return -ENOMEM;
|
||||
|
||||
reader->log = log;
|
||||
reader->r_ver = 1;
|
||||
reader->r_all = in_egroup_p(inode->i_gid) ||
|
||||
capable(CAP_SYSLOG);
|
||||
|
||||
INIT_LIST_HEAD(&reader->list);
|
||||
|
||||
mutex_lock(&log->mutex);
|
||||
reader->r_off = log->head;
|
||||
list_add_tail(&reader->list, &log->readers);
|
||||
mutex_unlock(&log->mutex);
|
||||
|
||||
file->private_data = reader;
|
||||
} else
|
||||
file->private_data = log;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* logger_release - the log's release file operation
|
||||
*
|
||||
* Note this is a total no-op in the write-only case. Keep it that way!
|
||||
*/
|
||||
static int logger_release(struct inode *ignored, struct file *file)
|
||||
{
|
||||
if (file->f_mode & FMODE_READ) {
|
||||
struct logger_reader *reader = file->private_data;
|
||||
struct logger_log *log = reader->log;
|
||||
|
||||
mutex_lock(&log->mutex);
|
||||
list_del(&reader->list);
|
||||
mutex_unlock(&log->mutex);
|
||||
|
||||
kfree(reader);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* logger_poll - the log's poll file operation, for poll/select/epoll
|
||||
*
|
||||
* Note we always return POLLOUT, because you can always write() to the log.
|
||||
* Note also that, strictly speaking, a return value of POLLIN does not
|
||||
* guarantee that the log is readable without blocking, as there is a small
|
||||
* chance that the writer can lap the reader in the interim between poll()
|
||||
* returning and the read() request.
|
||||
*/
|
||||
static unsigned int logger_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
struct logger_reader *reader;
|
||||
struct logger_log *log;
|
||||
unsigned int ret = POLLOUT | POLLWRNORM;
|
||||
|
||||
if (!(file->f_mode & FMODE_READ))
|
||||
return ret;
|
||||
|
||||
reader = file->private_data;
|
||||
log = reader->log;
|
||||
|
||||
poll_wait(file, &log->wq, wait);
|
||||
|
||||
mutex_lock(&log->mutex);
|
||||
if (!reader->r_all)
|
||||
reader->r_off = get_next_entry_by_uid(log,
|
||||
reader->r_off, current_euid());
|
||||
|
||||
if (log->w_off != reader->r_off)
|
||||
ret |= POLLIN | POLLRDNORM;
|
||||
mutex_unlock(&log->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static long logger_set_version(struct logger_reader *reader, void __user *arg)
|
||||
{
|
||||
int version;
|
||||
|
||||
if (copy_from_user(&version, arg, sizeof(int)))
|
||||
return -EFAULT;
|
||||
|
||||
if ((version < 1) || (version > 2))
|
||||
return -EINVAL;
|
||||
|
||||
reader->r_ver = version;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static long logger_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct logger_log *log = file_get_log(file);
|
||||
struct logger_reader *reader;
|
||||
long ret = -EINVAL;
|
||||
void __user *argp = (void __user *) arg;
|
||||
|
||||
mutex_lock(&log->mutex);
|
||||
|
||||
switch (cmd) {
|
||||
case LOGGER_GET_LOG_BUF_SIZE:
|
||||
ret = log->size;
|
||||
break;
|
||||
case LOGGER_GET_LOG_LEN:
|
||||
if (!(file->f_mode & FMODE_READ)) {
|
||||
ret = -EBADF;
|
||||
break;
|
||||
}
|
||||
reader = file->private_data;
|
||||
if (log->w_off >= reader->r_off)
|
||||
ret = log->w_off - reader->r_off;
|
||||
else
|
||||
ret = (log->size - reader->r_off) + log->w_off;
|
||||
break;
|
||||
case LOGGER_GET_NEXT_ENTRY_LEN:
|
||||
if (!(file->f_mode & FMODE_READ)) {
|
||||
ret = -EBADF;
|
||||
break;
|
||||
}
|
||||
reader = file->private_data;
|
||||
|
||||
if (!reader->r_all)
|
||||
reader->r_off = get_next_entry_by_uid(log,
|
||||
reader->r_off, current_euid());
|
||||
|
||||
if (log->w_off != reader->r_off)
|
||||
ret = get_user_hdr_len(reader->r_ver) +
|
||||
get_entry_msg_len(log, reader->r_off);
|
||||
else
|
||||
ret = 0;
|
||||
break;
|
||||
case LOGGER_FLUSH_LOG:
|
||||
if (!(file->f_mode & FMODE_WRITE)) {
|
||||
ret = -EBADF;
|
||||
break;
|
||||
}
|
||||
if (!(in_egroup_p(file->f_dentry->d_inode->i_gid) ||
|
||||
capable(CAP_SYSLOG))) {
|
||||
ret = -EPERM;
|
||||
break;
|
||||
}
|
||||
list_for_each_entry(reader, &log->readers, list)
|
||||
reader->r_off = log->w_off;
|
||||
log->head = log->w_off;
|
||||
ret = 0;
|
||||
break;
|
||||
case LOGGER_GET_VERSION:
|
||||
if (!(file->f_mode & FMODE_READ)) {
|
||||
ret = -EBADF;
|
||||
break;
|
||||
}
|
||||
reader = file->private_data;
|
||||
ret = reader->r_ver;
|
||||
break;
|
||||
case LOGGER_SET_VERSION:
|
||||
if (!(file->f_mode & FMODE_READ)) {
|
||||
ret = -EBADF;
|
||||
break;
|
||||
}
|
||||
reader = file->private_data;
|
||||
ret = logger_set_version(reader, argp);
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&log->mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct file_operations logger_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = logger_read,
|
||||
.aio_write = logger_aio_write,
|
||||
.poll = logger_poll,
|
||||
.unlocked_ioctl = logger_ioctl,
|
||||
.compat_ioctl = logger_ioctl,
|
||||
.open = logger_open,
|
||||
.release = logger_release,
|
||||
};
|
||||
|
||||
/*
|
||||
* Log size must must be a power of two, and greater than
|
||||
* (LOGGER_ENTRY_MAX_PAYLOAD + sizeof(struct logger_entry)).
|
||||
*/
|
||||
static int __init create_log(char *log_name, int size)
|
||||
{
|
||||
int ret = 0;
|
||||
struct logger_log *log;
|
||||
unsigned char *buffer;
|
||||
|
||||
buffer = vmalloc(size);
|
||||
if (buffer == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
log = kzalloc(sizeof(struct logger_log), GFP_KERNEL);
|
||||
if (log == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto out_free_buffer;
|
||||
}
|
||||
log->buffer = buffer;
|
||||
|
||||
log->misc.minor = MISC_DYNAMIC_MINOR;
|
||||
log->misc.name = kstrdup(log_name, GFP_KERNEL);
|
||||
if (log->misc.name == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto out_free_log;
|
||||
}
|
||||
|
||||
log->misc.fops = &logger_fops;
|
||||
log->misc.parent = NULL;
|
||||
|
||||
init_waitqueue_head(&log->wq);
|
||||
INIT_LIST_HEAD(&log->readers);
|
||||
mutex_init(&log->mutex);
|
||||
log->w_off = 0;
|
||||
log->head = 0;
|
||||
log->size = size;
|
||||
|
||||
INIT_LIST_HEAD(&log->logs);
|
||||
list_add_tail(&log->logs, &log_list);
|
||||
|
||||
/* finally, initialize the misc device for this log */
|
||||
ret = misc_register(&log->misc);
|
||||
if (unlikely(ret)) {
|
||||
pr_err("failed to register misc device for log '%s'!\n",
|
||||
log->misc.name);
|
||||
goto out_free_log;
|
||||
}
|
||||
|
||||
pr_info("created %luK log '%s'\n",
|
||||
(unsigned long) log->size >> 10, log->misc.name);
|
||||
|
||||
return 0;
|
||||
|
||||
out_free_log:
|
||||
kfree(log);
|
||||
|
||||
out_free_buffer:
|
||||
vfree(buffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __init logger_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = create_log(LOGGER_LOG_MAIN, CONFIG_LOGCAT_SIZE*1024);
|
||||
if (unlikely(ret))
|
||||
goto out;
|
||||
|
||||
ret = create_log(LOGGER_LOG_EVENTS, CONFIG_LOGCAT_SIZE*1024);
|
||||
if (unlikely(ret))
|
||||
goto out;
|
||||
|
||||
ret = create_log(LOGGER_LOG_RADIO, CONFIG_LOGCAT_SIZE*1024);
|
||||
if (unlikely(ret))
|
||||
goto out;
|
||||
|
||||
ret = create_log(LOGGER_LOG_SYSTEM, CONFIG_LOGCAT_SIZE*1024);
|
||||
if (unlikely(ret))
|
||||
goto out;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit logger_exit(void)
|
||||
{
|
||||
struct logger_log *current_log, *next_log;
|
||||
|
||||
list_for_each_entry_safe(current_log, next_log, &log_list, logs) {
|
||||
/* we have to delete all the entry inside log_list */
|
||||
misc_deregister(¤t_log->misc);
|
||||
vfree(current_log->buffer);
|
||||
kfree(current_log->misc.name);
|
||||
list_del(¤t_log->logs);
|
||||
kfree(current_log);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
device_initcall(logger_init);
|
||||
module_exit(logger_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Robert Love, <rlove@google.com>");
|
||||
MODULE_DESCRIPTION("Android Logger");
|
|
@ -1,89 +0,0 @@
|
|||
/* include/linux/logger.h
|
||||
*
|
||||
* Copyright (C) 2007-2008 Google, Inc.
|
||||
* Author: Robert Love <rlove@android.com>
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_LOGGER_H
|
||||
#define _LINUX_LOGGER_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/ioctl.h>
|
||||
|
||||
/**
|
||||
* struct user_logger_entry_compat - defines a single entry that is given to a logger
|
||||
* @len: The length of the payload
|
||||
* @__pad: Two bytes of padding that appear to be required
|
||||
* @pid: The generating process' process ID
|
||||
* @tid: The generating process' thread ID
|
||||
* @sec: The number of seconds that have elapsed since the Epoch
|
||||
* @nsec: The number of nanoseconds that have elapsed since @sec
|
||||
* @msg: The message that is to be logged
|
||||
*
|
||||
* The userspace structure for version 1 of the logger_entry ABI.
|
||||
* This structure is returned to userspace unless the caller requests
|
||||
* an upgrade to a newer ABI version.
|
||||
*/
|
||||
struct user_logger_entry_compat {
|
||||
__u16 len;
|
||||
__u16 __pad;
|
||||
__s32 pid;
|
||||
__s32 tid;
|
||||
__s32 sec;
|
||||
__s32 nsec;
|
||||
char msg[0];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct logger_entry - defines a single entry that is given to a logger
|
||||
* @len: The length of the payload
|
||||
* @hdr_size: sizeof(struct logger_entry_v2)
|
||||
* @pid: The generating process' process ID
|
||||
* @tid: The generating process' thread ID
|
||||
* @sec: The number of seconds that have elapsed since the Epoch
|
||||
* @nsec: The number of nanoseconds that have elapsed since @sec
|
||||
* @euid: Effective UID of logger
|
||||
* @msg: The message that is to be logged
|
||||
*
|
||||
* The structure for version 2 of the logger_entry ABI.
|
||||
* This structure is returned to userspace if ioctl(LOGGER_SET_VERSION)
|
||||
* is called with version >= 2
|
||||
*/
|
||||
struct logger_entry {
|
||||
__u16 len;
|
||||
__u16 hdr_size;
|
||||
__s32 pid;
|
||||
__s32 tid;
|
||||
__s32 sec;
|
||||
__s32 nsec;
|
||||
kuid_t euid;
|
||||
char msg[0];
|
||||
};
|
||||
|
||||
#define LOGGER_LOG_RADIO "log_radio" /* radio-related messages */
|
||||
#define LOGGER_LOG_EVENTS "log_events" /* system/hardware events */
|
||||
#define LOGGER_LOG_SYSTEM "log_system" /* system/framework messages */
|
||||
#define LOGGER_LOG_MAIN "log_main" /* everything else */
|
||||
|
||||
#define LOGGER_ENTRY_MAX_PAYLOAD 4076
|
||||
|
||||
#define __LOGGERIO 0xAE
|
||||
|
||||
#define LOGGER_GET_LOG_BUF_SIZE _IO(__LOGGERIO, 1) /* size of log */
|
||||
#define LOGGER_GET_LOG_LEN _IO(__LOGGERIO, 2) /* used log len */
|
||||
#define LOGGER_GET_NEXT_ENTRY_LEN _IO(__LOGGERIO, 3) /* next entry len */
|
||||
#define LOGGER_FLUSH_LOG _IO(__LOGGERIO, 4) /* flush log */
|
||||
#define LOGGER_GET_VERSION _IO(__LOGGERIO, 5) /* abi version */
|
||||
#define LOGGER_SET_VERSION _IO(__LOGGERIO, 6) /* abi version */
|
||||
|
||||
#endif /* _LINUX_LOGGER_H */
|
|
@ -1,65 +0,0 @@
|
|||
/* drivers/staging/android/uapi/android_alarm.h
|
||||
*
|
||||
* Copyright (C) 2006-2007 Google, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _UAPI_LINUX_ANDROID_ALARM_H
|
||||
#define _UAPI_LINUX_ANDROID_ALARM_H
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/time.h>
|
||||
|
||||
enum android_alarm_type {
|
||||
/* return code bit numbers or set alarm arg */
|
||||
ANDROID_ALARM_RTC_WAKEUP,
|
||||
ANDROID_ALARM_RTC,
|
||||
ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
|
||||
ANDROID_ALARM_ELAPSED_REALTIME,
|
||||
ANDROID_ALARM_RTC_POWEROFF_WAKEUP,
|
||||
ANDROID_ALARM_SYSTEMTIME,
|
||||
|
||||
ANDROID_ALARM_TYPE_COUNT,
|
||||
|
||||
/* return code bit numbers */
|
||||
/* ANDROID_ALARM_TIME_CHANGE = 16 */
|
||||
};
|
||||
|
||||
enum android_alarm_return_flags {
|
||||
ANDROID_ALARM_RTC_WAKEUP_MASK = 1U << ANDROID_ALARM_RTC_WAKEUP,
|
||||
ANDROID_ALARM_RTC_MASK = 1U << ANDROID_ALARM_RTC,
|
||||
ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK =
|
||||
1U << ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
|
||||
ANDROID_ALARM_ELAPSED_REALTIME_MASK =
|
||||
1U << ANDROID_ALARM_ELAPSED_REALTIME,
|
||||
ANDROID_ALARM_RTC_POWEROFF_WAKEUP_MASK =
|
||||
1U << ANDROID_ALARM_RTC_POWEROFF_WAKEUP,
|
||||
ANDROID_ALARM_SYSTEMTIME_MASK = 1U << ANDROID_ALARM_SYSTEMTIME,
|
||||
ANDROID_ALARM_TIME_CHANGE_MASK = 1U << 16
|
||||
};
|
||||
|
||||
/* Disable alarm */
|
||||
#define ANDROID_ALARM_CLEAR(type) _IO('a', 0 | ((type) << 4))
|
||||
|
||||
/* Ack last alarm and wait for next */
|
||||
#define ANDROID_ALARM_WAIT _IO('a', 1)
|
||||
|
||||
#define ALARM_IOW(c, type, size) _IOW('a', (c) | ((type) << 4), size)
|
||||
/* Set alarm */
|
||||
#define ANDROID_ALARM_SET(type) ALARM_IOW(2, type, struct timespec)
|
||||
#define ANDROID_ALARM_SET_AND_WAIT(type) ALARM_IOW(3, type, struct timespec)
|
||||
#define ANDROID_ALARM_GET_TIME(type) ALARM_IOW(4, type, struct timespec)
|
||||
#define ANDROID_ALARM_SET_RTC _IOW('a', 5, struct timespec)
|
||||
#define ANDROID_ALARM_BASE_CMD(cmd) (cmd & ~(_IOC(0, 0, 0xf0, 0)))
|
||||
#define ANDROID_ALARM_IOCTL_TO_TYPE(cmd) (_IOC_NR(cmd) >> 4)
|
||||
|
||||
#endif
|
|
@ -873,6 +873,9 @@ config USB_G_PRINTER
|
|||
|
||||
config USB_G_ANDROID
|
||||
boolean "Android Composite Gadget"
|
||||
depends on SND
|
||||
select SND_PCM
|
||||
select SND_RAWMIDI
|
||||
select USB_F_ACM
|
||||
select USB_F_SERIAL
|
||||
select USB_LIBCOMPOSITE
|
||||
|
|
|
@ -191,7 +191,7 @@ static struct usb_gadget_strings *midi_strings[] = {
|
|||
NULL,
|
||||
};
|
||||
|
||||
static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length)
|
||||
static struct usb_request *midi_alloc_ep_req(struct usb_ep *ep, unsigned length)
|
||||
{
|
||||
struct usb_request *req;
|
||||
|
||||
|
@ -207,7 +207,7 @@ static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length)
|
|||
return req;
|
||||
}
|
||||
|
||||
static void free_ep_req(struct usb_ep *ep, struct usb_request *req)
|
||||
static void midi_free_ep_req(struct usb_ep *ep, struct usb_request *req)
|
||||
{
|
||||
kfree(req->buf);
|
||||
usb_ep_free_request(ep, req);
|
||||
|
@ -278,7 +278,7 @@ f_midi_complete(struct usb_ep *ep, struct usb_request *req)
|
|||
if (ep == midi->out_ep)
|
||||
f_midi_handle_out_data(ep, req);
|
||||
|
||||
free_ep_req(ep, req);
|
||||
midi_free_ep_req(ep, req);
|
||||
return;
|
||||
|
||||
case -EOVERFLOW: /* buffer overrun on read means that
|
||||
|
@ -365,7 +365,7 @@ static int f_midi_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
|
|||
/* allocate a bunch of read buffers and queue them all at once. */
|
||||
for (i = 0; i < midi->qlen && err == 0; i++) {
|
||||
struct usb_request *req =
|
||||
alloc_ep_req(midi->out_ep, midi->buflen);
|
||||
midi_alloc_ep_req(midi->out_ep, midi->buflen);
|
||||
if (req == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -409,7 +409,7 @@ static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f)
|
|||
card = midi->card;
|
||||
midi->card = NULL;
|
||||
if (card)
|
||||
snd_card_free(card);
|
||||
snd_card_free_when_closed(card);
|
||||
|
||||
kfree(midi->id);
|
||||
midi->id = NULL;
|
||||
|
@ -546,10 +546,10 @@ static void f_midi_transmit(struct f_midi *midi, struct usb_request *req)
|
|||
return;
|
||||
|
||||
if (!req)
|
||||
req = alloc_ep_req(ep, midi->buflen);
|
||||
req = midi_alloc_ep_req(ep, midi->buflen);
|
||||
|
||||
if (!req) {
|
||||
ERROR(midi, "gmidi_transmit: alloc_ep_request failed\n");
|
||||
ERROR(midi, "gmidi_transmit: midi_alloc_ep_request failed\n");
|
||||
return;
|
||||
}
|
||||
req->length = 0;
|
||||
|
@ -575,7 +575,7 @@ static void f_midi_transmit(struct f_midi *midi, struct usb_request *req)
|
|||
if (req->length > 0)
|
||||
usb_ep_queue(ep, req, GFP_ATOMIC);
|
||||
else
|
||||
free_ep_req(ep, req);
|
||||
midi_free_ep_req(ep, req);
|
||||
}
|
||||
|
||||
static void f_midi_in_tasklet(unsigned long data)
|
||||
|
|
|
@ -213,6 +213,7 @@ static int parse_options(struct super_block *sb, char *options)
|
|||
|
||||
static int adfs_remount(struct super_block *sb, int *flags, char *data)
|
||||
{
|
||||
sync_filesystem(sb);
|
||||
*flags |= MS_NODIRATIME;
|
||||
return parse_options(sb, data);
|
||||
}
|
||||
|
|
|
@ -549,6 +549,7 @@ affs_remount(struct super_block *sb, int *flags, char *data)
|
|||
|
||||
pr_debug("AFFS: remount(flags=0x%x,opts=\"%s\")\n",*flags,data);
|
||||
|
||||
sync_filesystem(sb);
|
||||
*flags |= MS_NODIRATIME;
|
||||
|
||||
memcpy(volume, sbi->s_volume, 32);
|
||||
|
|
|
@ -908,6 +908,7 @@ befs_fill_super(struct super_block *sb, void *data, int silent)
|
|||
static int
|
||||
befs_remount(struct super_block *sb, int *flags, char *data)
|
||||
{
|
||||
sync_filesystem(sb);
|
||||
if (!(*flags & MS_RDONLY))
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
|
|
|
@ -1239,6 +1239,7 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
|
|||
unsigned int old_metadata_ratio = fs_info->metadata_ratio;
|
||||
int ret;
|
||||
|
||||
sync_filesystem(sb);
|
||||
btrfs_remount_prepare(fs_info);
|
||||
|
||||
ret = btrfs_parse_options(root, data);
|
||||
|
|
|
@ -521,6 +521,7 @@ static int cifs_show_stats(struct seq_file *s, struct dentry *root)
|
|||
|
||||
static int cifs_remount(struct super_block *sb, int *flags, char *data)
|
||||
{
|
||||
sync_filesystem(sb);
|
||||
*flags |= MS_NODIRATIME;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -391,8 +391,7 @@ static int coda_readdir(struct file *coda_file, void *buf, filldir_t filldir)
|
|||
if (!host_file->f_op)
|
||||
return -ENOTDIR;
|
||||
|
||||
if (host_file->f_op->readdir)
|
||||
{
|
||||
if (host_file->f_op->readdir) {
|
||||
/* potemkin case: we were handed a directory inode.
|
||||
* We can't use vfs_readdir because we have to keep the file
|
||||
* position in sync between the coda_file and the host_file.
|
||||
|
@ -410,8 +409,20 @@ static int coda_readdir(struct file *coda_file, void *buf, filldir_t filldir)
|
|||
|
||||
coda_file->f_pos = host_file->f_pos;
|
||||
mutex_unlock(&host_inode->i_mutex);
|
||||
}
|
||||
else /* Venus: we must read Venus dirents from a file */
|
||||
} else if (host_file->f_op->iterate) {
|
||||
struct inode *host_inode = file_inode(host_file);
|
||||
struct dir_context *ctx = buf;
|
||||
|
||||
mutex_lock(&host_inode->i_mutex);
|
||||
ret = -ENOENT;
|
||||
if (!IS_DEADDIR(host_inode)) {
|
||||
ret = host_file->f_op->iterate(host_file, ctx);
|
||||
file_accessed(host_file);
|
||||
}
|
||||
mutex_unlock(&host_inode->i_mutex);
|
||||
|
||||
coda_file->f_pos = ctx->pos;
|
||||
} else /* Venus: we must read Venus dirents from a file */
|
||||
ret = coda_venus_readdir(coda_file, buf, filldir);
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -96,6 +96,7 @@ void coda_destroy_inodecache(void)
|
|||
|
||||
static int coda_remount(struct super_block *sb, int *flags, char *data)
|
||||
{
|
||||
sync_filesystem(sb);
|
||||
*flags |= MS_NOATIME;
|
||||
return 0;
|
||||
}
|
||||
|
|
43
fs/compat.c
43
fs/compat.c
|
@ -832,6 +832,7 @@ struct compat_old_linux_dirent {
|
|||
};
|
||||
|
||||
struct compat_readdir_callback {
|
||||
struct dir_context ctx;
|
||||
struct compat_old_linux_dirent __user *dirent;
|
||||
int result;
|
||||
};
|
||||
|
@ -873,15 +874,15 @@ asmlinkage long compat_sys_old_readdir(unsigned int fd,
|
|||
{
|
||||
int error;
|
||||
struct fd f = fdget(fd);
|
||||
struct compat_readdir_callback buf;
|
||||
struct compat_readdir_callback buf = {
|
||||
.ctx.actor = compat_fillonedir,
|
||||
.dirent = dirent
|
||||
};
|
||||
|
||||
if (!f.file)
|
||||
return -EBADF;
|
||||
|
||||
buf.result = 0;
|
||||
buf.dirent = dirent;
|
||||
|
||||
error = vfs_readdir(f.file, compat_fillonedir, &buf);
|
||||
error = iterate_dir(f.file, &buf.ctx);
|
||||
if (buf.result)
|
||||
error = buf.result;
|
||||
|
||||
|
@ -897,6 +898,7 @@ struct compat_linux_dirent {
|
|||
};
|
||||
|
||||
struct compat_getdents_callback {
|
||||
struct dir_context ctx;
|
||||
struct compat_linux_dirent __user *current_dir;
|
||||
struct compat_linux_dirent __user *previous;
|
||||
int count;
|
||||
|
@ -951,7 +953,11 @@ asmlinkage long compat_sys_getdents(unsigned int fd,
|
|||
{
|
||||
struct fd f;
|
||||
struct compat_linux_dirent __user * lastdirent;
|
||||
struct compat_getdents_callback buf;
|
||||
struct compat_getdents_callback buf = {
|
||||
.ctx.actor = compat_filldir,
|
||||
.current_dir = dirent,
|
||||
.count = count
|
||||
};
|
||||
int error;
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, dirent, count))
|
||||
|
@ -961,17 +967,12 @@ asmlinkage long compat_sys_getdents(unsigned int fd,
|
|||
if (!f.file)
|
||||
return -EBADF;
|
||||
|
||||
buf.current_dir = dirent;
|
||||
buf.previous = NULL;
|
||||
buf.count = count;
|
||||
buf.error = 0;
|
||||
|
||||
error = vfs_readdir(f.file, compat_filldir, &buf);
|
||||
error = iterate_dir(f.file, &buf.ctx);
|
||||
if (error >= 0)
|
||||
error = buf.error;
|
||||
lastdirent = buf.previous;
|
||||
if (lastdirent) {
|
||||
if (put_user(f.file->f_pos, &lastdirent->d_off))
|
||||
if (put_user(buf.ctx.pos, &lastdirent->d_off))
|
||||
error = -EFAULT;
|
||||
else
|
||||
error = count - buf.count;
|
||||
|
@ -983,6 +984,7 @@ asmlinkage long compat_sys_getdents(unsigned int fd,
|
|||
#ifdef __ARCH_WANT_COMPAT_SYS_GETDENTS64
|
||||
|
||||
struct compat_getdents_callback64 {
|
||||
struct dir_context ctx;
|
||||
struct linux_dirent64 __user *current_dir;
|
||||
struct linux_dirent64 __user *previous;
|
||||
int count;
|
||||
|
@ -1036,7 +1038,11 @@ asmlinkage long compat_sys_getdents64(unsigned int fd,
|
|||
{
|
||||
struct fd f;
|
||||
struct linux_dirent64 __user * lastdirent;
|
||||
struct compat_getdents_callback64 buf;
|
||||
struct compat_getdents_callback64 buf = {
|
||||
.ctx.actor = compat_filldir64,
|
||||
.current_dir = dirent,
|
||||
.count = count
|
||||
};
|
||||
int error;
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, dirent, count))
|
||||
|
@ -1046,17 +1052,12 @@ asmlinkage long compat_sys_getdents64(unsigned int fd,
|
|||
if (!f.file)
|
||||
return -EBADF;
|
||||
|
||||
buf.current_dir = dirent;
|
||||
buf.previous = NULL;
|
||||
buf.count = count;
|
||||
buf.error = 0;
|
||||
|
||||
error = vfs_readdir(f.file, compat_filldir64, &buf);
|
||||
error = iterate_dir(f.file, &buf.ctx);
|
||||
if (error >= 0)
|
||||
error = buf.error;
|
||||
lastdirent = buf.previous;
|
||||
if (lastdirent) {
|
||||
typeof(lastdirent->d_off) d_off = f.file->f_pos;
|
||||
typeof(lastdirent->d_off) d_off = buf.ctx.pos;
|
||||
if (__put_user_unaligned(d_off, &lastdirent->d_off))
|
||||
error = -EFAULT;
|
||||
else
|
||||
|
|
|
@ -227,6 +227,7 @@ static void cramfs_put_super(struct super_block *sb)
|
|||
|
||||
static int cramfs_remount(struct super_block *sb, int *flags, char *data)
|
||||
{
|
||||
sync_filesystem(sb);
|
||||
*flags |= MS_RDONLY;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -218,6 +218,7 @@ static int debugfs_remount(struct super_block *sb, int *flags, char *data)
|
|||
int err;
|
||||
struct debugfs_fs_info *fsi = sb->s_fs_info;
|
||||
|
||||
sync_filesystem(sb);
|
||||
err = debugfs_parse_options(data, &fsi->mount_opts);
|
||||
if (err)
|
||||
goto fail;
|
||||
|
|
|
@ -313,6 +313,7 @@ static int devpts_remount(struct super_block *sb, int *flags, char *data)
|
|||
struct pts_fs_info *fsi = DEVPTS_SB(sb);
|
||||
struct pts_mount_opts *opts = &fsi->mount_opts;
|
||||
|
||||
sync_filesystem(sb);
|
||||
err = parse_mount_options(data, PARSE_REMOUNT, opts);
|
||||
|
||||
/*
|
||||
|
|
|
@ -68,6 +68,7 @@ static ssize_t ecryptfs_read_update_atime(struct kiocb *iocb,
|
|||
}
|
||||
|
||||
struct ecryptfs_getdents_callback {
|
||||
struct dir_context ctx;
|
||||
void *dirent;
|
||||
struct dentry *dentry;
|
||||
filldir_t filldir;
|
||||
|
@ -115,18 +116,19 @@ static int ecryptfs_readdir(struct file *file, void *dirent, filldir_t filldir)
|
|||
int rc;
|
||||
struct file *lower_file;
|
||||
struct inode *inode;
|
||||
struct ecryptfs_getdents_callback buf;
|
||||
struct ecryptfs_getdents_callback buf = {
|
||||
.dirent = dirent,
|
||||
.dentry = file->f_path.dentry,
|
||||
.filldir = filldir,
|
||||
.filldir_called = 0,
|
||||
.entries_written = 0,
|
||||
.ctx.actor = ecryptfs_filldir
|
||||
};
|
||||
|
||||
lower_file = ecryptfs_file_to_lower(file);
|
||||
lower_file->f_pos = file->f_pos;
|
||||
inode = file_inode(file);
|
||||
memset(&buf, 0, sizeof(buf));
|
||||
buf.dirent = dirent;
|
||||
buf.dentry = file->f_path.dentry;
|
||||
buf.filldir = filldir;
|
||||
buf.filldir_called = 0;
|
||||
buf.entries_written = 0;
|
||||
rc = vfs_readdir(lower_file, ecryptfs_filldir, (void *)&buf);
|
||||
rc = iterate_dir(lower_file, &buf.ctx);
|
||||
file->f_pos = lower_file->f_pos;
|
||||
if (rc < 0)
|
||||
goto out;
|
||||
|
|
|
@ -113,6 +113,7 @@ static void efs_put_super(struct super_block *s)
|
|||
|
||||
static int efs_remount(struct super_block *sb, int *flags, char *data)
|
||||
{
|
||||
sync_filesystem(sb);
|
||||
*flags |= MS_RDONLY;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -212,6 +212,7 @@ reconnect_path(struct vfsmount *mnt, struct dentry *target_dir, char *nbuf)
|
|||
}
|
||||
|
||||
struct getdents_callback {
|
||||
struct dir_context ctx;
|
||||
char *name; /* name that was found. It already points to a
|
||||
buffer NAME_MAX+1 is size */
|
||||
unsigned long ino; /* the inum we are looking for */
|
||||
|
@ -254,7 +255,11 @@ static int get_name(const struct path *path, char *name, struct dentry *child)
|
|||
struct inode *dir = path->dentry->d_inode;
|
||||
int error;
|
||||
struct file *file;
|
||||
struct getdents_callback buffer;
|
||||
struct getdents_callback buffer = {
|
||||
.ctx.actor = filldir_one,
|
||||
.name = name,
|
||||
.ino = child->d_inode->i_ino
|
||||
};
|
||||
|
||||
error = -ENOTDIR;
|
||||
if (!dir || !S_ISDIR(dir->i_mode))
|
||||
|
@ -271,17 +276,14 @@ static int get_name(const struct path *path, char *name, struct dentry *child)
|
|||
goto out;
|
||||
|
||||
error = -EINVAL;
|
||||
if (!file->f_op->readdir)
|
||||
if (!file->f_op->readdir && !file->f_op->iterate)
|
||||
goto out_close;
|
||||
|
||||
buffer.name = name;
|
||||
buffer.ino = child->d_inode->i_ino;
|
||||
buffer.found = 0;
|
||||
buffer.sequence = 0;
|
||||
while (1) {
|
||||
int old_seq = buffer.sequence;
|
||||
|
||||
error = vfs_readdir(file, filldir_one, &buffer);
|
||||
error = iterate_dir(file, &buffer.ctx);
|
||||
if (buffer.found) {
|
||||
error = 0;
|
||||
break;
|
||||
|
|
|
@ -1254,6 +1254,7 @@ static int ext2_remount (struct super_block * sb, int * flags, char * data)
|
|||
unsigned long old_sb_flags;
|
||||
int err;
|
||||
|
||||
sync_filesystem(sb);
|
||||
spin_lock(&sbi->s_lock);
|
||||
|
||||
/* Store the old options */
|
||||
|
|
|
@ -2588,6 +2588,8 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data)
|
|||
int i;
|
||||
#endif
|
||||
|
||||
sync_filesystem(sb);
|
||||
|
||||
/* Store the original options */
|
||||
old_sb_flags = sb->s_flags;
|
||||
old_opts.s_mount_opt = sbi->s_mount_opt;
|
||||
|
|
|
@ -4624,6 +4624,8 @@ static int ext4_remount(struct super_block *sb, int *flags, char *data)
|
|||
#endif
|
||||
char *orig_data = kstrdup(data, GFP_KERNEL);
|
||||
|
||||
sync_filesystem(sb);
|
||||
|
||||
/* Store the original options */
|
||||
old_sb_flags = sb->s_flags;
|
||||
old_opts.s_mount_opt = sbi->s_mount_opt;
|
||||
|
|
|
@ -239,7 +239,6 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
|
|||
if (test_opt(sbi, DISABLE_EXT_IDENTIFY))
|
||||
seq_puts(seq, ",disable_ext_identify");
|
||||
|
||||
seq_printf(seq, ",active_logs=%u", sbi->active_logs);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -632,6 +632,8 @@ static int fat_remount(struct super_block *sb, int *flags, char *data)
|
|||
struct msdos_sb_info *sbi = MSDOS_SB(sb);
|
||||
*flags |= MS_NODIRATIME | (sbi->options.isvfat ? 0 : MS_NOATIME);
|
||||
|
||||
sync_filesystem(sb);
|
||||
|
||||
/* make sure we update state on remount. */
|
||||
new_rdonly = *flags & MS_RDONLY;
|
||||
if (new_rdonly != (sb->s_flags & MS_RDONLY)) {
|
||||
|
|
|
@ -124,6 +124,7 @@ vxfs_statfs(struct dentry *dentry, struct kstatfs *bufp)
|
|||
|
||||
static int vxfs_remount(struct super_block *sb, int *flags, char *data)
|
||||
{
|
||||
sync_filesystem(sb);
|
||||
*flags |= MS_RDONLY;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@ struct wb_writeback_work {
|
|||
unsigned int for_kupdate:1;
|
||||
unsigned int range_cyclic:1;
|
||||
unsigned int for_background:1;
|
||||
unsigned int for_sync:1; /* sync(2) WB_SYNC_ALL writeback */
|
||||
enum wb_reason reason; /* why was writeback initiated? */
|
||||
|
||||
struct list_head list; /* pending work list */
|
||||
|
@ -456,9 +457,11 @@ __writeback_single_inode(struct inode *inode, struct writeback_control *wbc)
|
|||
/*
|
||||
* Make sure to wait on the data before writing out the metadata.
|
||||
* This is important for filesystems that modify metadata on data
|
||||
* I/O completion.
|
||||
* I/O completion. We don't do it for sync(2) writeback because it has a
|
||||
* separate, external IO completion path and ->sync_fs for guaranteeing
|
||||
* inode metadata is written back correctly.
|
||||
*/
|
||||
if (wbc->sync_mode == WB_SYNC_ALL) {
|
||||
if (wbc->sync_mode == WB_SYNC_ALL && !wbc->for_sync) {
|
||||
int err = filemap_fdatawait(mapping);
|
||||
if (ret == 0)
|
||||
ret = err;
|
||||
|
@ -610,6 +613,7 @@ static long writeback_sb_inodes(struct super_block *sb,
|
|||
.tagged_writepages = work->tagged_writepages,
|
||||
.for_kupdate = work->for_kupdate,
|
||||
.for_background = work->for_background,
|
||||
.for_sync = work->for_sync,
|
||||
.range_cyclic = work->range_cyclic,
|
||||
.range_start = 0,
|
||||
.range_end = LLONG_MAX,
|
||||
|
@ -1393,6 +1397,7 @@ void sync_inodes_sb(struct super_block *sb)
|
|||
.range_cyclic = 0,
|
||||
.done = &done,
|
||||
.reason = WB_REASON_SYNC,
|
||||
.for_sync = 1,
|
||||
};
|
||||
|
||||
/* Nothing to do? */
|
||||
|
|
|
@ -135,6 +135,7 @@ static void fuse_evict_inode(struct inode *inode)
|
|||
|
||||
static int fuse_remount_fs(struct super_block *sb, int *flags, char *data)
|
||||
{
|
||||
sync_filesystem(sb);
|
||||
if (*flags & MS_MANDLOCK)
|
||||
return -EINVAL;
|
||||
|
||||
|
|
|
@ -88,7 +88,10 @@ static int gfs2_get_name(struct dentry *parent, char *name,
|
|||
struct inode *dir = parent->d_inode;
|
||||
struct inode *inode = child->d_inode;
|
||||
struct gfs2_inode *dip, *ip;
|
||||
struct get_name_filldir gnfd;
|
||||
struct get_name_filldir gnfd = {
|
||||
.ctx.actor = get_name_filldir,
|
||||
.name = name
|
||||
};
|
||||
struct gfs2_holder gh;
|
||||
u64 offset = 0;
|
||||
int error;
|
||||
|
@ -106,7 +109,6 @@ static int gfs2_get_name(struct dentry *parent, char *name,
|
|||
*name = 0;
|
||||
gnfd.inum.no_addr = ip->i_no_addr;
|
||||
gnfd.inum.no_formal_ino = ip->i_no_formal_ino;
|
||||
gnfd.name = name;
|
||||
|
||||
error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &gh);
|
||||
if (error)
|
||||
|
|
|
@ -1142,6 +1142,8 @@ static int gfs2_remount_fs(struct super_block *sb, int *flags, char *data)
|
|||
struct gfs2_tune *gt = &sdp->sd_tune;
|
||||
int error;
|
||||
|
||||
sync_filesystem(sb);
|
||||
|
||||
spin_lock(>->gt_spin);
|
||||
args.ar_commit = gt->gt_logd_secs;
|
||||
args.ar_quota_quantum = gt->gt_quota_quantum;
|
||||
|
|
|
@ -112,6 +112,7 @@ static int hfs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
|
||||
static int hfs_remount(struct super_block *sb, int *flags, char *data)
|
||||
{
|
||||
sync_filesystem(sb);
|
||||
*flags |= MS_NODIRATIME;
|
||||
if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
|
||||
return 0;
|
||||
|
|
|
@ -323,6 +323,7 @@ static int hfsplus_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
|
||||
static int hfsplus_remount(struct super_block *sb, int *flags, char *data)
|
||||
{
|
||||
sync_filesystem(sb);
|
||||
if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
|
||||
return 0;
|
||||
if (!(*flags & MS_RDONLY)) {
|
||||
|
|
|
@ -395,6 +395,8 @@ static int hpfs_remount_fs(struct super_block *s, int *flags, char *data)
|
|||
struct hpfs_sb_info *sbi = hpfs_sb(s);
|
||||
char *new_opts = kstrdup(data, GFP_KERNEL);
|
||||
|
||||
sync_filesystem(s);
|
||||
|
||||
*flags |= MS_NOATIME;
|
||||
|
||||
hpfs_lock(s);
|
||||
|
|
35
fs/inode.c
35
fs/inode.c
|
@ -979,6 +979,41 @@ void unlock_new_inode(struct inode *inode)
|
|||
}
|
||||
EXPORT_SYMBOL(unlock_new_inode);
|
||||
|
||||
/**
|
||||
* lock_two_nondirectories - take two i_mutexes on non-directory objects
|
||||
*
|
||||
* Lock any non-NULL argument that is not a directory.
|
||||
* Zero, one or two objects may be locked by this function.
|
||||
*
|
||||
* @inode1: first inode to lock
|
||||
* @inode2: second inode to lock
|
||||
*/
|
||||
void lock_two_nondirectories(struct inode *inode1, struct inode *inode2)
|
||||
{
|
||||
if (inode1 > inode2)
|
||||
swap(inode1, inode2);
|
||||
|
||||
if (inode1 && !S_ISDIR(inode1->i_mode))
|
||||
mutex_lock(&inode1->i_mutex);
|
||||
if (inode2 && !S_ISDIR(inode2->i_mode) && inode2 != inode1)
|
||||
mutex_lock_nested(&inode2->i_mutex, I_MUTEX_NONDIR2);
|
||||
}
|
||||
EXPORT_SYMBOL(lock_two_nondirectories);
|
||||
|
||||
/**
|
||||
* unlock_two_nondirectories - release locks from lock_two_nondirectories()
|
||||
* @inode1: first inode to unlock
|
||||
* @inode2: second inode to unlock
|
||||
*/
|
||||
void unlock_two_nondirectories(struct inode *inode1, struct inode *inode2)
|
||||
{
|
||||
if (inode1 && !S_ISDIR(inode1->i_mode))
|
||||
mutex_unlock(&inode1->i_mutex);
|
||||
if (inode2 && !S_ISDIR(inode2->i_mode) && inode2 != inode1)
|
||||
mutex_unlock(&inode2->i_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(unlock_two_nondirectories);
|
||||
|
||||
/**
|
||||
* iget5_locked - obtain an inode from a mounted file system
|
||||
* @sb: super block of file system
|
||||
|
|
|
@ -243,6 +243,7 @@ static int jffs2_remount_fs(struct super_block *sb, int *flags, char *data)
|
|||
struct jffs2_sb_info *c = JFFS2_SB_INFO(sb);
|
||||
int err;
|
||||
|
||||
sync_filesystem(sb);
|
||||
err = jffs2_parse_options(c, data);
|
||||
if (err)
|
||||
return -EINVAL;
|
||||
|
|
|
@ -413,6 +413,7 @@ static int jfs_remount(struct super_block *sb, int *flags, char *data)
|
|||
int flag = JFS_SBI(sb)->flag;
|
||||
int ret;
|
||||
|
||||
sync_filesystem(sb);
|
||||
if (!parse_options(data, sb, &newLVSize, &flag)) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
@ -123,6 +123,7 @@ static int minix_remount (struct super_block * sb, int * flags, char * data)
|
|||
struct minix_sb_info * sbi = minix_sb(sb);
|
||||
struct minix_super_block * ms;
|
||||
|
||||
sync_filesystem(sb);
|
||||
ms = sbi->s_ms;
|
||||
if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
|
||||
return 0;
|
||||
|
|
|
@ -99,6 +99,7 @@ static void destroy_inodecache(void)
|
|||
|
||||
static int ncp_remount(struct super_block *sb, int *flags, char* data)
|
||||
{
|
||||
sync_filesystem(sb);
|
||||
*flags |= MS_NODIRATIME;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -2133,6 +2133,8 @@ nfs_remount(struct super_block *sb, int *flags, char *raw_data)
|
|||
struct nfs4_mount_data *options4 = (struct nfs4_mount_data *)raw_data;
|
||||
u32 nfsvers = nfss->nfs_client->rpc_ops->version;
|
||||
|
||||
sync_filesystem(sb);
|
||||
|
||||
/*
|
||||
* Userspace mount programs that send binary options generally send
|
||||
* them populated with default values. We have no way to know which
|
||||
|
|
|
@ -240,11 +240,16 @@ struct name_list {
|
|||
struct list_head list;
|
||||
};
|
||||
|
||||
struct nfs4_dir_ctx {
|
||||
struct dir_context ctx;
|
||||
struct list_head names;
|
||||
};
|
||||
|
||||
static int
|
||||
nfsd4_build_namelist(void *arg, const char *name, int namlen,
|
||||
loff_t offset, u64 ino, unsigned int d_type)
|
||||
{
|
||||
struct list_head *names = arg;
|
||||
struct nfs4_dir_ctx *ctx = arg;
|
||||
struct name_list *entry;
|
||||
|
||||
if (namlen != HEXDIR_LEN - 1)
|
||||
|
@ -254,7 +259,7 @@ nfsd4_build_namelist(void *arg, const char *name, int namlen,
|
|||
return -ENOMEM;
|
||||
memcpy(entry->name, name, HEXDIR_LEN - 1);
|
||||
entry->name[HEXDIR_LEN - 1] = '\0';
|
||||
list_add(&entry->list, names);
|
||||
list_add(&entry->list, &ctx->names);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -263,7 +268,10 @@ nfsd4_list_rec_dir(recdir_func *f, struct nfsd_net *nn)
|
|||
{
|
||||
const struct cred *original_cred;
|
||||
struct dentry *dir = nn->rec_file->f_path.dentry;
|
||||
LIST_HEAD(names);
|
||||
struct nfs4_dir_ctx ctx = {
|
||||
.ctx.actor = nfsd4_build_namelist,
|
||||
.names = LIST_HEAD_INIT(ctx.names)
|
||||
};
|
||||
int status;
|
||||
|
||||
status = nfs4_save_creds(&original_cred);
|
||||
|
@ -276,11 +284,11 @@ nfsd4_list_rec_dir(recdir_func *f, struct nfsd_net *nn)
|
|||
return status;
|
||||
}
|
||||
|
||||
status = vfs_readdir(nn->rec_file, nfsd4_build_namelist, &names);
|
||||
status = iterate_dir(nn->rec_file, &ctx.ctx);
|
||||
mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
|
||||
while (!list_empty(&names)) {
|
||||
while (!list_empty(&ctx.names)) {
|
||||
struct name_list *entry;
|
||||
entry = list_entry(names.next, struct name_list, list);
|
||||
entry = list_entry(ctx.names.next, struct name_list, list);
|
||||
if (!status) {
|
||||
struct dentry *dentry;
|
||||
dentry = lookup_one_len(entry->name, dir, HEXDIR_LEN-1);
|
||||
|
|
|
@ -1950,6 +1950,7 @@ struct buffered_dirent {
|
|||
};
|
||||
|
||||
struct readdir_data {
|
||||
struct dir_context ctx;
|
||||
char *dirent;
|
||||
size_t used;
|
||||
int full;
|
||||
|
@ -1981,13 +1982,15 @@ static int nfsd_buffered_filldir(void *__buf, const char *name, int namlen,
|
|||
static __be32 nfsd_buffered_readdir(struct file *file, filldir_t func,
|
||||
struct readdir_cd *cdp, loff_t *offsetp)
|
||||
{
|
||||
struct readdir_data buf;
|
||||
struct buffered_dirent *de;
|
||||
int host_err;
|
||||
int size;
|
||||
loff_t offset;
|
||||
struct readdir_data buf = {
|
||||
.ctx.actor = nfsd_buffered_filldir,
|
||||
.dirent = (void *)__get_free_page(GFP_KERNEL)
|
||||
};
|
||||
|
||||
buf.dirent = (void *)__get_free_page(GFP_KERNEL);
|
||||
if (!buf.dirent)
|
||||
return nfserrno(-ENOMEM);
|
||||
|
||||
|
@ -2001,7 +2004,7 @@ static __be32 nfsd_buffered_readdir(struct file *file, filldir_t func,
|
|||
buf.used = 0;
|
||||
buf.full = 0;
|
||||
|
||||
host_err = vfs_readdir(file, nfsd_buffered_filldir, &buf);
|
||||
host_err = iterate_dir(file, &buf.ctx);
|
||||
if (buf.full)
|
||||
host_err = 0;
|
||||
|
||||
|
|
|
@ -1114,6 +1114,7 @@ static int nilfs_remount(struct super_block *sb, int *flags, char *data)
|
|||
unsigned long old_mount_opt;
|
||||
int err;
|
||||
|
||||
sync_filesystem(sb);
|
||||
old_sb_flags = sb->s_flags;
|
||||
old_mount_opt = nilfs->ns_mount_opt;
|
||||
|
||||
|
|
|
@ -468,6 +468,8 @@ static int ntfs_remount(struct super_block *sb, int *flags, char *opt)
|
|||
|
||||
ntfs_debug("Entering with remount options string: %s", opt);
|
||||
|
||||
sync_filesystem(sb);
|
||||
|
||||
#ifndef NTFS_RW
|
||||
/* For read-only compiled driver, enforce read-only flag. */
|
||||
*flags |= MS_RDONLY;
|
||||
|
|
|
@ -632,6 +632,8 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
|
|||
struct ocfs2_super *osb = OCFS2_SB(sb);
|
||||
u32 tmp;
|
||||
|
||||
sync_filesystem(sb);
|
||||
|
||||
if (!ocfs2_parse_options(sb, data, &parsed_options, 1) ||
|
||||
!ocfs2_check_set_options(sb, &parsed_options)) {
|
||||
ret = -EINVAL;
|
||||
|
|
|
@ -375,6 +375,7 @@ static struct inode *openprom_iget(struct super_block *sb, ino_t ino)
|
|||
|
||||
static int openprom_remount(struct super_block *sb, int *flags, char *data)
|
||||
{
|
||||
sync_filesystem(sb);
|
||||
*flags |= MS_NOATIME;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -140,12 +140,6 @@ struct pid_entry {
|
|||
NULL, &proc_single_file_operations, \
|
||||
{ .proc_show = show } )
|
||||
|
||||
/* ANDROID is for special files in /proc. */
|
||||
#define ANDROID(NAME, MODE, OTYPE) \
|
||||
NOD(NAME, (S_IFREG|(MODE)), \
|
||||
&proc_##OTYPE##_inode_operations, \
|
||||
&proc_##OTYPE##_operations, {})
|
||||
|
||||
/*
|
||||
* Count the number of hardlinks for the pid_entry table, excluding the .
|
||||
* and .. links.
|
||||
|
@ -1015,35 +1009,6 @@ out:
|
|||
return err < 0 ? err : count;
|
||||
}
|
||||
|
||||
static int oom_adjust_permission(struct inode *inode, int mask)
|
||||
{
|
||||
uid_t uid;
|
||||
struct task_struct *p;
|
||||
|
||||
p = get_proc_task(inode);
|
||||
if(p) {
|
||||
uid = task_uid(p);
|
||||
put_task_struct(p);
|
||||
}
|
||||
|
||||
/*
|
||||
* System Server (uid == 1000) is granted access to oom_adj of all
|
||||
* android applications (uid > 10000) as and services (uid >= 1000)
|
||||
*/
|
||||
if (p && (current_fsuid() == 1000) && (uid >= 1000)) {
|
||||
if (inode->i_mode >> 6 & mask) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fall back to default. */
|
||||
return generic_permission(inode, mask);
|
||||
}
|
||||
|
||||
static const struct inode_operations proc_oom_adj_inode_operations = {
|
||||
.permission = oom_adjust_permission,
|
||||
};
|
||||
|
||||
static const struct file_operations proc_oom_adj_operations = {
|
||||
.read = oom_adj_read,
|
||||
.write = oom_adj_write,
|
||||
|
@ -2941,8 +2906,8 @@ static const struct pid_entry tgid_base_stuff[] = {
|
|||
REG("cgroup", S_IRUGO, proc_cgroup_operations),
|
||||
#endif
|
||||
INF("oom_score", S_IRUGO, proc_oom_score),
|
||||
ANDROID("oom_adj", S_IRUGO|S_IWUSR, oom_adj),
|
||||
REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations),
|
||||
REG("oom_adj", S_IRUSR, proc_oom_adj_operations),
|
||||
REG("oom_score_adj", S_IRUSR, proc_oom_score_adj_operations),
|
||||
#ifdef CONFIG_AUDITSYSCALL
|
||||
REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations),
|
||||
REG("sessionid", S_IRUGO, proc_sessionid_operations),
|
||||
|
@ -3298,8 +3263,8 @@ static const struct pid_entry tid_base_stuff[] = {
|
|||
REG("cgroup", S_IRUGO, proc_cgroup_operations),
|
||||
#endif
|
||||
INF("oom_score", S_IRUGO, proc_oom_score),
|
||||
REG("oom_adj", S_IRUGO|S_IWUSR, proc_oom_adj_operations),
|
||||
REG("oom_score_adj", S_IRUGO|S_IWUSR, proc_oom_score_adj_operations),
|
||||
REG("oom_adj", S_IRUSR, proc_oom_adj_operations),
|
||||
REG("oom_score_adj", S_IRUSR, proc_oom_score_adj_operations),
|
||||
#ifdef CONFIG_AUDITSYSCALL
|
||||
REG("loginuid", S_IWUSR|S_IRUGO, proc_loginuid_operations),
|
||||
REG("sessionid", S_IRUGO, proc_sessionid_operations),
|
||||
|
|
|
@ -92,6 +92,8 @@ static int proc_parse_options(char *options, struct pid_namespace *pid)
|
|||
int proc_remount(struct super_block *sb, int *flags, char *data)
|
||||
{
|
||||
struct pid_namespace *pid = sb->s_fs_info;
|
||||
|
||||
sync_filesystem(sb);
|
||||
return !proc_parse_options(data, pid);
|
||||
}
|
||||
|
||||
|
|
|
@ -778,6 +778,7 @@ static int clear_refs_pte_range(pmd_t *pmd, unsigned long addr,
|
|||
#define CLEAR_REFS_ALL 1
|
||||
#define CLEAR_REFS_ANON 2
|
||||
#define CLEAR_REFS_MAPPED 3
|
||||
#define CLEAR_REFS_MM_HIWATER_RSS 5
|
||||
|
||||
static ssize_t clear_refs_write(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
|
@ -797,7 +798,8 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf,
|
|||
rv = kstrtoint(strstrip(buffer), 10, &type);
|
||||
if (rv < 0)
|
||||
return rv;
|
||||
if (type < CLEAR_REFS_ALL || type > CLEAR_REFS_MAPPED)
|
||||
if ((type < CLEAR_REFS_ALL || type > CLEAR_REFS_MAPPED) &&
|
||||
type != CLEAR_REFS_MM_HIWATER_RSS)
|
||||
return -EINVAL;
|
||||
task = get_proc_task(file_inode(file));
|
||||
if (!task)
|
||||
|
@ -808,6 +810,18 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf,
|
|||
.pmd_entry = clear_refs_pte_range,
|
||||
.mm = mm,
|
||||
};
|
||||
|
||||
if (type == CLEAR_REFS_MM_HIWATER_RSS) {
|
||||
/*
|
||||
* Writing 5 to /proc/pid/clear_refs resets the peak
|
||||
* resident set size to this mm's current rss value.
|
||||
*/
|
||||
down_write(&mm->mmap_sem);
|
||||
reset_mm_hiwater_rss(mm);
|
||||
up_write(&mm->mmap_sem);
|
||||
goto out_mm;
|
||||
}
|
||||
|
||||
down_read(&mm->mmap_sem);
|
||||
for (vma = mm->mmap; vma; vma = vma->vm_next) {
|
||||
clear_refs_walk.private = vma;
|
||||
|
@ -831,6 +845,7 @@ static ssize_t clear_refs_write(struct file *file, const char __user *buf,
|
|||
}
|
||||
flush_tlb_mm(mm);
|
||||
up_read(&mm->mmap_sem);
|
||||
out_mm:
|
||||
mmput(mm);
|
||||
}
|
||||
put_task_struct(task);
|
||||
|
|
|
@ -249,6 +249,7 @@ static void parse_options(char *options)
|
|||
|
||||
static int pstore_remount(struct super_block *sb, int *flags, char *data)
|
||||
{
|
||||
sync_filesystem(sb);
|
||||
parse_options(data);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -46,6 +46,7 @@ static int qnx4_remount(struct super_block *sb, int *flags, char *data)
|
|||
{
|
||||
struct qnx4_sb_info *qs;
|
||||
|
||||
sync_filesystem(sb);
|
||||
qs = qnx4_sb(sb);
|
||||
qs->Version = QNX4_VERSION;
|
||||
*flags |= MS_RDONLY;
|
||||
|
|
|
@ -55,6 +55,7 @@ static int qnx6_show_options(struct seq_file *seq, struct dentry *root)
|
|||
|
||||
static int qnx6_remount(struct super_block *sb, int *flags, char *data)
|
||||
{
|
||||
sync_filesystem(sb);
|
||||
*flags |= MS_RDONLY;
|
||||
return 0;
|
||||
}
|
||||
|
|
61
fs/readdir.c
61
fs/readdir.c
|
@ -20,11 +20,11 @@
|
|||
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
int vfs_readdir(struct file *file, filldir_t filler, void *buf)
|
||||
int iterate_dir(struct file *file, struct dir_context *ctx)
|
||||
{
|
||||
struct inode *inode = file_inode(file);
|
||||
int res = -ENOTDIR;
|
||||
if (!file->f_op || !file->f_op->readdir)
|
||||
if (!file->f_op || (!file->f_op->readdir && !file->f_op->iterate))
|
||||
goto out;
|
||||
|
||||
res = security_file_permission(file, MAY_READ);
|
||||
|
@ -37,15 +37,21 @@ int vfs_readdir(struct file *file, filldir_t filler, void *buf)
|
|||
|
||||
res = -ENOENT;
|
||||
if (!IS_DEADDIR(inode)) {
|
||||
res = file->f_op->readdir(file, buf, filler);
|
||||
if (file->f_op->iterate) {
|
||||
ctx->pos = file->f_pos;
|
||||
res = file->f_op->iterate(file, ctx);
|
||||
file->f_pos = ctx->pos;
|
||||
} else {
|
||||
res = file->f_op->readdir(file, ctx, ctx->actor);
|
||||
ctx->pos = file->f_pos;
|
||||
}
|
||||
file_accessed(file);
|
||||
}
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
out:
|
||||
return res;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(vfs_readdir);
|
||||
EXPORT_SYMBOL(iterate_dir);
|
||||
|
||||
/*
|
||||
* Traditional linux readdir() handling..
|
||||
|
@ -66,6 +72,7 @@ struct old_linux_dirent {
|
|||
};
|
||||
|
||||
struct readdir_callback {
|
||||
struct dir_context ctx;
|
||||
struct old_linux_dirent __user * dirent;
|
||||
int result;
|
||||
};
|
||||
|
@ -73,7 +80,7 @@ struct readdir_callback {
|
|||
static int fillonedir(void * __buf, const char * name, int namlen, loff_t offset,
|
||||
u64 ino, unsigned int d_type)
|
||||
{
|
||||
struct readdir_callback * buf = (struct readdir_callback *) __buf;
|
||||
struct readdir_callback *buf = (struct readdir_callback *) __buf;
|
||||
struct old_linux_dirent __user * dirent;
|
||||
unsigned long d_ino;
|
||||
|
||||
|
@ -107,15 +114,15 @@ SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
|
|||
{
|
||||
int error;
|
||||
struct fd f = fdget(fd);
|
||||
struct readdir_callback buf;
|
||||
struct readdir_callback buf = {
|
||||
.ctx.actor = fillonedir,
|
||||
.dirent = dirent
|
||||
};
|
||||
|
||||
if (!f.file)
|
||||
return -EBADF;
|
||||
|
||||
buf.result = 0;
|
||||
buf.dirent = dirent;
|
||||
|
||||
error = vfs_readdir(f.file, fillonedir, &buf);
|
||||
error = iterate_dir(f.file, &buf.ctx);
|
||||
if (buf.result)
|
||||
error = buf.result;
|
||||
|
||||
|
@ -137,6 +144,7 @@ struct linux_dirent {
|
|||
};
|
||||
|
||||
struct getdents_callback {
|
||||
struct dir_context ctx;
|
||||
struct linux_dirent __user * current_dir;
|
||||
struct linux_dirent __user * previous;
|
||||
int count;
|
||||
|
@ -191,7 +199,11 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd,
|
|||
{
|
||||
struct fd f;
|
||||
struct linux_dirent __user * lastdirent;
|
||||
struct getdents_callback buf;
|
||||
struct getdents_callback buf = {
|
||||
.ctx.actor = filldir,
|
||||
.count = count,
|
||||
.current_dir = dirent
|
||||
};
|
||||
int error;
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, dirent, count))
|
||||
|
@ -201,17 +213,12 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd,
|
|||
if (!f.file)
|
||||
return -EBADF;
|
||||
|
||||
buf.current_dir = dirent;
|
||||
buf.previous = NULL;
|
||||
buf.count = count;
|
||||
buf.error = 0;
|
||||
|
||||
error = vfs_readdir(f.file, filldir, &buf);
|
||||
error = iterate_dir(f.file, &buf.ctx);
|
||||
if (error >= 0)
|
||||
error = buf.error;
|
||||
lastdirent = buf.previous;
|
||||
if (lastdirent) {
|
||||
if (put_user(f.file->f_pos, &lastdirent->d_off))
|
||||
if (put_user(buf.ctx.pos, &lastdirent->d_off))
|
||||
error = -EFAULT;
|
||||
else
|
||||
error = count - buf.count;
|
||||
|
@ -221,6 +228,7 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd,
|
|||
}
|
||||
|
||||
struct getdents_callback64 {
|
||||
struct dir_context ctx;
|
||||
struct linux_dirent64 __user * current_dir;
|
||||
struct linux_dirent64 __user * previous;
|
||||
int count;
|
||||
|
@ -271,7 +279,11 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd,
|
|||
{
|
||||
struct fd f;
|
||||
struct linux_dirent64 __user * lastdirent;
|
||||
struct getdents_callback64 buf;
|
||||
struct getdents_callback64 buf = {
|
||||
.ctx.actor = filldir64,
|
||||
.count = count,
|
||||
.current_dir = dirent
|
||||
};
|
||||
int error;
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, dirent, count))
|
||||
|
@ -281,17 +293,12 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd,
|
|||
if (!f.file)
|
||||
return -EBADF;
|
||||
|
||||
buf.current_dir = dirent;
|
||||
buf.previous = NULL;
|
||||
buf.count = count;
|
||||
buf.error = 0;
|
||||
|
||||
error = vfs_readdir(f.file, filldir64, &buf);
|
||||
error = iterate_dir(f.file, &buf.ctx);
|
||||
if (error >= 0)
|
||||
error = buf.error;
|
||||
lastdirent = buf.previous;
|
||||
if (lastdirent) {
|
||||
typeof(lastdirent->d_off) d_off = f.file->f_pos;
|
||||
typeof(lastdirent->d_off) d_off = buf.ctx.pos;
|
||||
if (__put_user(d_off, &lastdirent->d_off))
|
||||
error = -EFAULT;
|
||||
else
|
||||
|
|
|
@ -1317,6 +1317,7 @@ static int reiserfs_remount(struct super_block *s, int *mount_flags, char *arg)
|
|||
int i;
|
||||
#endif
|
||||
|
||||
sync_filesystem(s);
|
||||
reiserfs_write_lock(s);
|
||||
|
||||
#ifdef CONFIG_QUOTA
|
||||
|
|
|
@ -435,6 +435,7 @@ static int romfs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
|||
*/
|
||||
static int romfs_remount(struct super_block *sb, int *flags, char *data)
|
||||
{
|
||||
sync_filesystem(sb);
|
||||
*flags |= MS_RDONLY;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,78 @@ config SQUASHFS
|
|||
|
||||
If unsure, say N.
|
||||
|
||||
choice
|
||||
prompt "File decompression options"
|
||||
depends on SQUASHFS
|
||||
help
|
||||
Squashfs now supports two options for decompressing file
|
||||
data. Traditionally Squashfs has decompressed into an
|
||||
intermediate buffer and then memcopied it into the page cache.
|
||||
Squashfs now supports the ability to decompress directly into
|
||||
the page cache.
|
||||
|
||||
If unsure, select "Decompress file data into an intermediate buffer"
|
||||
|
||||
config SQUASHFS_FILE_CACHE
|
||||
bool "Decompress file data into an intermediate buffer"
|
||||
help
|
||||
Decompress file data into an intermediate buffer and then
|
||||
memcopy it into the page cache.
|
||||
|
||||
config SQUASHFS_FILE_DIRECT
|
||||
bool "Decompress files directly into the page cache"
|
||||
help
|
||||
Directly decompress file data into the page cache.
|
||||
Doing so can significantly improve performance because
|
||||
it eliminates a memcpy and it also removes the lock contention
|
||||
on the single buffer.
|
||||
|
||||
endchoice
|
||||
|
||||
choice
|
||||
prompt "Decompressor parallelisation options"
|
||||
depends on SQUASHFS
|
||||
help
|
||||
Squashfs now supports three parallelisation options for
|
||||
decompression. Each one exhibits various trade-offs between
|
||||
decompression performance and CPU and memory usage.
|
||||
|
||||
If in doubt, select "Single threaded compression"
|
||||
|
||||
config SQUASHFS_DECOMP_SINGLE
|
||||
bool "Single threaded compression"
|
||||
help
|
||||
Traditionally Squashfs has used single-threaded decompression.
|
||||
Only one block (data or metadata) can be decompressed at any
|
||||
one time. This limits CPU and memory usage to a minimum.
|
||||
|
||||
config SQUASHFS_DECOMP_MULTI
|
||||
bool "Use multiple decompressors for parallel I/O"
|
||||
help
|
||||
By default Squashfs uses a single decompressor but it gives
|
||||
poor performance on parallel I/O workloads when using multiple CPU
|
||||
machines due to waiting on decompressor availability.
|
||||
|
||||
If you have a parallel I/O workload and your system has enough memory,
|
||||
using this option may improve overall I/O performance.
|
||||
|
||||
This decompressor implementation uses up to two parallel
|
||||
decompressors per core. It dynamically allocates decompressors
|
||||
on a demand basis.
|
||||
|
||||
config SQUASHFS_DECOMP_MULTI_PERCPU
|
||||
bool "Use percpu multiple decompressors for parallel I/O"
|
||||
help
|
||||
By default Squashfs uses a single decompressor but it gives
|
||||
poor performance on parallel I/O workloads when using multiple CPU
|
||||
machines due to waiting on decompressor availability.
|
||||
|
||||
This decompressor implementation uses a maximum of one
|
||||
decompressor per core. It uses percpu variables to ensure
|
||||
decompression is load-balanced across the cores.
|
||||
|
||||
endchoice
|
||||
|
||||
config SQUASHFS_XATTR
|
||||
bool "Squashfs XATTR support"
|
||||
depends on SQUASHFS
|
||||
|
@ -48,6 +120,21 @@ config SQUASHFS_ZLIB
|
|||
|
||||
If unsure, say Y.
|
||||
|
||||
config SQUASHFS_LZ4
|
||||
bool "Include support for LZ4 compressed file systems"
|
||||
depends on SQUASHFS
|
||||
select LZ4_DECOMPRESS
|
||||
help
|
||||
Saying Y here includes support for reading Squashfs file systems
|
||||
compressed with LZ4 compression. LZ4 compression is mainly
|
||||
aimed at embedded systems with slower CPUs where the overheads
|
||||
of zlib are too high.
|
||||
|
||||
LZ4 is not the standard compression used in Squashfs and so most
|
||||
file systems will be readable without selecting this option.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config SQUASHFS_LZO
|
||||
bool "Include support for LZO compressed file systems"
|
||||
depends on SQUASHFS
|
||||
|
|
|
@ -5,7 +5,13 @@
|
|||
obj-$(CONFIG_SQUASHFS) += squashfs.o
|
||||
squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o
|
||||
squashfs-y += namei.o super.o symlink.o decompressor.o
|
||||
squashfs-$(CONFIG_SQUASHFS_FILE_CACHE) += file_cache.o
|
||||
squashfs-$(CONFIG_SQUASHFS_FILE_DIRECT) += file_direct.o page_actor.o
|
||||
squashfs-$(CONFIG_SQUASHFS_DECOMP_SINGLE) += decompressor_single.o
|
||||
squashfs-$(CONFIG_SQUASHFS_DECOMP_MULTI) += decompressor_multi.o
|
||||
squashfs-$(CONFIG_SQUASHFS_DECOMP_MULTI_PERCPU) += decompressor_multi_percpu.o
|
||||
squashfs-$(CONFIG_SQUASHFS_XATTR) += xattr.o xattr_id.o
|
||||
squashfs-$(CONFIG_SQUASHFS_LZ4) += lz4_wrapper.o
|
||||
squashfs-$(CONFIG_SQUASHFS_LZO) += lzo_wrapper.o
|
||||
squashfs-$(CONFIG_SQUASHFS_XZ) += xz_wrapper.o
|
||||
squashfs-$(CONFIG_SQUASHFS_ZLIB) += zlib_wrapper.o
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "squashfs_fs_sb.h"
|
||||
#include "squashfs.h"
|
||||
#include "decompressor.h"
|
||||
#include "page_actor.h"
|
||||
|
||||
/*
|
||||
* Read the metadata block length, this is stored in the first two
|
||||
|
@ -86,16 +87,16 @@ static struct buffer_head *get_block_length(struct super_block *sb,
|
|||
* generated a larger block - this does occasionally happen with compression
|
||||
* algorithms).
|
||||
*/
|
||||
int squashfs_read_data(struct super_block *sb, void **buffer, u64 index,
|
||||
int length, u64 *next_index, int srclength, int pages)
|
||||
int squashfs_read_data(struct super_block *sb, u64 index, int length,
|
||||
u64 *next_index, struct squashfs_page_actor *output)
|
||||
{
|
||||
struct squashfs_sb_info *msblk = sb->s_fs_info;
|
||||
struct buffer_head **bh;
|
||||
int offset = index & ((1 << msblk->devblksize_log2) - 1);
|
||||
u64 cur_index = index >> msblk->devblksize_log2;
|
||||
int bytes, compressed, b = 0, k = 0, page = 0, avail;
|
||||
int bytes, compressed, b = 0, k = 0, avail, i;
|
||||
|
||||
bh = kcalloc(((srclength + msblk->devblksize - 1)
|
||||
bh = kcalloc(((output->length + msblk->devblksize - 1)
|
||||
>> msblk->devblksize_log2) + 1, sizeof(*bh), GFP_KERNEL);
|
||||
if (bh == NULL)
|
||||
return -ENOMEM;
|
||||
|
@ -111,9 +112,9 @@ int squashfs_read_data(struct super_block *sb, void **buffer, u64 index,
|
|||
*next_index = index + length;
|
||||
|
||||
TRACE("Block @ 0x%llx, %scompressed size %d, src size %d\n",
|
||||
index, compressed ? "" : "un", length, srclength);
|
||||
index, compressed ? "" : "un", length, output->length);
|
||||
|
||||
if (length < 0 || length > srclength ||
|
||||
if (length < 0 || length > output->length ||
|
||||
(index + length) > msblk->bytes_used)
|
||||
goto read_failure;
|
||||
|
||||
|
@ -145,7 +146,7 @@ int squashfs_read_data(struct super_block *sb, void **buffer, u64 index,
|
|||
TRACE("Block @ 0x%llx, %scompressed size %d\n", index,
|
||||
compressed ? "" : "un", length);
|
||||
|
||||
if (length < 0 || length > srclength ||
|
||||
if (length < 0 || length > output->length ||
|
||||
(index + length) > msblk->bytes_used)
|
||||
goto block_release;
|
||||
|
||||
|
@ -158,35 +159,36 @@ int squashfs_read_data(struct super_block *sb, void **buffer, u64 index,
|
|||
ll_rw_block(READ, b - 1, bh + 1);
|
||||
}
|
||||
|
||||
for (i = 0; i < b; i++) {
|
||||
wait_on_buffer(bh[i]);
|
||||
if (!buffer_uptodate(bh[i]))
|
||||
goto block_release;
|
||||
}
|
||||
|
||||
if (compressed) {
|
||||
length = squashfs_decompress(msblk, buffer, bh, b, offset,
|
||||
length, srclength, pages);
|
||||
length = squashfs_decompress(msblk, bh, b, offset, length,
|
||||
output);
|
||||
if (length < 0)
|
||||
goto read_failure;
|
||||
} else {
|
||||
/*
|
||||
* Block is uncompressed.
|
||||
*/
|
||||
int i, in, pg_offset = 0;
|
||||
|
||||
for (i = 0; i < b; i++) {
|
||||
wait_on_buffer(bh[i]);
|
||||
if (!buffer_uptodate(bh[i]))
|
||||
goto block_release;
|
||||
}
|
||||
int in, pg_offset = 0;
|
||||
void *data = squashfs_first_page(output);
|
||||
|
||||
for (bytes = length; k < b; k++) {
|
||||
in = min(bytes, msblk->devblksize - offset);
|
||||
bytes -= in;
|
||||
while (in) {
|
||||
if (pg_offset == PAGE_CACHE_SIZE) {
|
||||
page++;
|
||||
data = squashfs_next_page(output);
|
||||
pg_offset = 0;
|
||||
}
|
||||
avail = min_t(int, in, PAGE_CACHE_SIZE -
|
||||
pg_offset);
|
||||
memcpy(buffer[page] + pg_offset,
|
||||
bh[k]->b_data + offset, avail);
|
||||
memcpy(data + pg_offset, bh[k]->b_data + offset,
|
||||
avail);
|
||||
in -= avail;
|
||||
pg_offset += avail;
|
||||
offset += avail;
|
||||
|
@ -194,6 +196,7 @@ int squashfs_read_data(struct super_block *sb, void **buffer, u64 index,
|
|||
offset = 0;
|
||||
put_bh(bh[k]);
|
||||
}
|
||||
squashfs_finish_page(output);
|
||||
}
|
||||
|
||||
kfree(bh);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue