1. 11 5月, 2015 1 次提交
  2. 23 4月, 2015 1 次提交
  3. 28 3月, 2015 1 次提交
    • M
      spi: spidev: Warn loudly if instantiated from DT as "spidev" · 956b200a
      Mark Brown 提交于
      Since spidev is a detail of how Linux controls a device rather than a
      description of the hardware in the system we should never have a node
      described as "spidev" in DT, any SPI device could be a spidev so this
      is just not a useful description.
      
      In order to help prevent users from writing such device trees generate a
      warning if spidev is instantiated as a DT node without an ID in the match
      table.
      Signed-off-by: NMark Brown <broonie@kernel.org>
      956b200a
  4. 24 3月, 2015 1 次提交
    • I
      spi: spidev: fix possible arithmetic overflow for multi-transfer message · f20fbaad
      Ian Abbott 提交于
      `spidev_message()` sums the lengths of the individual SPI transfers to
      determine the overall SPI message length.  It restricts the total
      length, returning an error if too long, but it does not check for
      arithmetic overflow.  For example, if the SPI message consisted of two
      transfers and the first has a length of 10 and the second has a length
      of (__u32)(-1), the total length would be seen as 9, even though the
      second transfer is actually very long.  If the second transfer specifies
      a null `rx_buf` and a non-null `tx_buf`, the `copy_from_user()` could
      overrun the spidev's pre-allocated tx buffer before it reaches an
      invalid user memory address.  Fix it by checking that neither the total
      nor the individual transfer lengths exceed the maximum allowed value.
      
      Thanks to Dan Carpenter for reporting the potential integer overflow.
      Signed-off-by: NIan Abbott <abbotti@mev.co.uk>
      Signed-off-by: NMark Brown <broonie@kernel.org>
      f20fbaad
  5. 24 2月, 2015 1 次提交
    • I
      spi: spidev: only use up TX/RX bounce buffer space when needed · 9a12bff7
      Ian Abbott 提交于
      This patch changes the way space is reserved in spidev's pre-allocated
      TX and RX bounce buffers to avoid wasting space in the buffers for an
      SPI message consisting of multiple, half-duplex transfers in different
      directions.
      
      Background:
      
      spidev data structures have separate, pre-allocated TX and RX bounce
      buffers (`spidev->tx_buffer` and `spidev->rx_buffer`) of fixed size
      (`bufsiz`).  The `SPI_IOC_MESSAGE(N)` ioctl processing uses a kernel
      copy of the N `struct spi_ioc_transfer` elements copied from the
      userspace ioctl arg pointer.  In these elements: `.len` is the length of
      transfer in bytes; `.rx_buf` is either a userspace pointer to a buffer
      to copy the RX data to or is set to 0 to discard the data; and `.tx_buf`
      is either a userspace pointer to TX data supplied by the user or is set
      to 0 to transmit zeros for this transfer.
      
      `spidev_message()` uses the array of N `struct spi_ioc_transfer`
      elements to construct a kernel SPI message consisting of a `struct
      spi_message` containing a linked list (allocated as an array) of N
      `struct spi_transfer` elements.  This involves iterating through the
      `struct spi_ioc_transfer` and `struct spi_transfer` elements (variables
      `u_tmp` and `k_tmp` respectively).  Before the first iteration,
      variables `tx_buf` and `rx_buf` point to the start of the TX and RX
      bounce buffers `spidev->tx_buffer` and `spidev->rx_buffer` and variable
      `total` is set to 0.  These variables keep track of the next available
      space in the bounce buffers and the total length of the SPI message.
      Each iteration checks that there is enough room left in the buffers for
      the transfer.  If `u_tmp->rx_buf` is non-zero, `k_tmp->rx_buf` is set to
      `rx_buf`, otherwise it remains set to NULL.  If `u_tmp->tx_buf` is
      non-zero, `k_tmp->tx_buf` is set to `tx_buf` and the userspace TX data
      copied there, otherwise it remains set to NULL.  The variables `total`,
      `rx_buf` and `tx_buf` are advanced by the length of the transfer.
      
      The "problem":
      
      While iterating through the transfers, the local bounce buffer "free
      space" pointer variables `tx_buf` and `rx_buf` are always advanced by
      the length of the transfer.  If `u_tmp->rx_buf` is 0 (so `k_tmp->rx_buf`
      is NULL), then `rx_buf` is advanced unnecessarily and that part of
      `spidev->rx_buffer` is wasted.  Similarly, if `u_tmp->tx_buf` is 0 (so
      `k_tmp->tx_buf` is NULL), part of `spidev->tx_buffer` is wasted.
      
      What this patch does:
      
      To avoid wasting space unnecessarily in the RX bounce buffer, only
      advance `rx_buf` by the transfer length if `u_tmp->rx_buf` is non-zero.
      Similarly, to avoid wasting space unnecessarily in the TX bounce buffer,
      only advance `tx_buf` if `u_tmp->tx_buf is non-zero.  To avoid pointer
      subtraction, use new variables `rx_total` and `tx_total` to keep track
      of the amount of space allocated in each of the bounce buffers.  If
      these exceed the available space, a `-EMSGSIZE` error will be returned.
      
      Limit the total length of the transfers (tracked by variable `total`) to
      `INT_MAX` instead of `bufsiz`, returning an `-EMSGSIZE` error if
      exceeded.  The total length is returned by `spidev_message()` on success
      and we want that to be non-negative.  The message size limits for the
      `SPI_IOC_MESSAGE(N)` ioctl are now as follows:
      
      (a) total length of transfers is <= INTMAX;
      (b) total length of transfers with non-NULL rx_buf is <= bufsiz;
      (c) total length of transfers with non-NULL tx_buf is <= bufsiz.
      
      Some transfers may have NULL rx_buf and NULL tx_buf.
      
      If the transfer is completed successfully by the SPI core,
      `spidev_message()` iterates through the transfers to copy any RX data
      from the bounce buffer back to userspace on those transfers where
      `u_tmp->rx_buf` is non-zero.  The variable `rx_buf` is again used to
      keep track of the corresponding positions in the bounce buffer.  Now it
      is only advanced for those transfers that use the RX bounce buffer.
      Signed-off-by: NIan Abbott <abbotti@mev.co.uk>
      Signed-off-by: NMark Brown <broonie@kernel.org>
      9a12bff7
  6. 03 2月, 2015 1 次提交
    • I
      spi: spidev: Convert buf pointers for 32-bit compat SPI_IOC_MESSAGE(n) · 7782a1a9
      Ian Abbott 提交于
      The SPI_IOC_MESSAGE(n) ioctl commands' argument points to an array of n
      struct spi_ioc_transfer elements.  The spidev's compat_ioctl handler
      just converts this pointer and passes it on to the unlocked_ioctl
      handler to process it.
      
      The tx_buf and rx_buf members of struct spi_ioc_transfer are of type
      __u64 and hold pointer values.  A 32-bit userspace application running
      in a 64-bit kernel might not have widened the 32-bit pointers correctly
      for the kernel.  The application might have sign-extended the pointer to
      when the kernel expects it to be zero-extended, or vice versa, leading
      to an -EFAULT being returned by spidev_message() if the widened pointer
      is invalid.
      
      Handle the SPI_IOC_MESSAGE(n) ioctl commands specially in the
      compat_ioctl handler, calling new function spidev_compat_ioctl_message()
      to handle them.  This processes them in the same way as the
      unlocked_ioctl handler except that it uses compat_ptr() to convert the
      tx_buf and rx_buf members of each struct spi_ioc_transfer element.
      
      To save code, factor out part of the unlocked_ioctl handler into a new
      function spidev_get_ioc_message().  This checks the ioctl command code
      is a valid SPI_IOC_MESSAGE(n), determines n and copies the array of n
      struct spi_ioc_transfer elements from userspace into dynamically
      allocated memory, returning either a pointer to the memory, an
      ERR_PTR(-err) value, or NULL (for SPI_IOC_MESSAGE(0)).
      Signed-off-by: NIan Abbott <abbotti@mev.co.uk>
      Signed-off-by: NMark Brown <broonie@kernel.org>
      7782a1a9
  7. 22 12月, 2014 1 次提交
  8. 12 11月, 2014 1 次提交
    • M
      spi: spidev: Don't mangle max_speed_hz in underlying spi device · 91690516
      Mark Brown 提交于
      Currently spidev allows callers to set the default speed by overriding the
      max_speed_hz in the underlying device. This achieves the immediate goal but
      is not what devices expect and can easily lead to userspace trying to set
      unsupported speeds and succeeding, apart from anything else drivers can't
      set a limit on the speed using max_speed_hz as they'd expect and any other
      devices on the bus will be affected.
      
      Instead store the default speed in the spidev struct and fill this in on
      each transfer.
      Signed-off-by: NMark Brown <broonie@kernel.org>
      91690516
  9. 13 10月, 2014 1 次提交
  10. 27 2月, 2014 2 次提交
  11. 15 10月, 2013 1 次提交
  12. 17 9月, 2013 1 次提交
  13. 15 7月, 2013 1 次提交
  14. 01 4月, 2013 1 次提交
  15. 08 12月, 2012 1 次提交
  16. 01 11月, 2012 2 次提交
  17. 06 6月, 2011 1 次提交
  18. 04 2月, 2011 1 次提交
  19. 02 11月, 2010 1 次提交
  20. 15 10月, 2010 1 次提交
    • A
      llseek: automatically add .llseek fop · 6038f373
      Arnd Bergmann 提交于
      All file_operations should get a .llseek operation so we can make
      nonseekable_open the default for future file operations without a
      .llseek pointer.
      
      The three cases that we can automatically detect are no_llseek, seq_lseek
      and default_llseek. For cases where we can we can automatically prove that
      the file offset is always ignored, we use noop_llseek, which maintains
      the current behavior of not returning an error from a seek.
      
      New drivers should normally not use noop_llseek but instead use no_llseek
      and call nonseekable_open at open time.  Existing drivers can be converted
      to do the same when the maintainer knows for certain that no user code
      relies on calling seek on the device file.
      
      The generated code is often incorrectly indented and right now contains
      comments that clarify for each added line why a specific variant was
      chosen. In the version that gets submitted upstream, the comments will
      be gone and I will manually fix the indentation, because there does not
      seem to be a way to do that using coccinelle.
      
      Some amount of new code is currently sitting in linux-next that should get
      the same modifications, which I will do at the end of the merge window.
      
      Many thanks to Julia Lawall for helping me learn to write a semantic
      patch that does all this.
      
      ===== begin semantic patch =====
      // This adds an llseek= method to all file operations,
      // as a preparation for making no_llseek the default.
      //
      // The rules are
      // - use no_llseek explicitly if we do nonseekable_open
      // - use seq_lseek for sequential files
      // - use default_llseek if we know we access f_pos
      // - use noop_llseek if we know we don't access f_pos,
      //   but we still want to allow users to call lseek
      //
      @ open1 exists @
      identifier nested_open;
      @@
      nested_open(...)
      {
      <+...
      nonseekable_open(...)
      ...+>
      }
      
      @ open exists@
      identifier open_f;
      identifier i, f;
      identifier open1.nested_open;
      @@
      int open_f(struct inode *i, struct file *f)
      {
      <+...
      (
      nonseekable_open(...)
      |
      nested_open(...)
      )
      ...+>
      }
      
      @ read disable optional_qualifier exists @
      identifier read_f;
      identifier f, p, s, off;
      type ssize_t, size_t, loff_t;
      expression E;
      identifier func;
      @@
      ssize_t read_f(struct file *f, char *p, size_t s, loff_t *off)
      {
      <+...
      (
         *off = E
      |
         *off += E
      |
         func(..., off, ...)
      |
         E = *off
      )
      ...+>
      }
      
      @ read_no_fpos disable optional_qualifier exists @
      identifier read_f;
      identifier f, p, s, off;
      type ssize_t, size_t, loff_t;
      @@
      ssize_t read_f(struct file *f, char *p, size_t s, loff_t *off)
      {
      ... when != off
      }
      
      @ write @
      identifier write_f;
      identifier f, p, s, off;
      type ssize_t, size_t, loff_t;
      expression E;
      identifier func;
      @@
      ssize_t write_f(struct file *f, const char *p, size_t s, loff_t *off)
      {
      <+...
      (
        *off = E
      |
        *off += E
      |
        func(..., off, ...)
      |
        E = *off
      )
      ...+>
      }
      
      @ write_no_fpos @
      identifier write_f;
      identifier f, p, s, off;
      type ssize_t, size_t, loff_t;
      @@
      ssize_t write_f(struct file *f, const char *p, size_t s, loff_t *off)
      {
      ... when != off
      }
      
      @ fops0 @
      identifier fops;
      @@
      struct file_operations fops = {
       ...
      };
      
      @ has_llseek depends on fops0 @
      identifier fops0.fops;
      identifier llseek_f;
      @@
      struct file_operations fops = {
      ...
       .llseek = llseek_f,
      ...
      };
      
      @ has_read depends on fops0 @
      identifier fops0.fops;
      identifier read_f;
      @@
      struct file_operations fops = {
      ...
       .read = read_f,
      ...
      };
      
      @ has_write depends on fops0 @
      identifier fops0.fops;
      identifier write_f;
      @@
      struct file_operations fops = {
      ...
       .write = write_f,
      ...
      };
      
      @ has_open depends on fops0 @
      identifier fops0.fops;
      identifier open_f;
      @@
      struct file_operations fops = {
      ...
       .open = open_f,
      ...
      };
      
      // use no_llseek if we call nonseekable_open
      ////////////////////////////////////////////
      @ nonseekable1 depends on !has_llseek && has_open @
      identifier fops0.fops;
      identifier nso ~= "nonseekable_open";
      @@
      struct file_operations fops = {
      ...  .open = nso, ...
      +.llseek = no_llseek, /* nonseekable */
      };
      
      @ nonseekable2 depends on !has_llseek @
      identifier fops0.fops;
      identifier open.open_f;
      @@
      struct file_operations fops = {
      ...  .open = open_f, ...
      +.llseek = no_llseek, /* open uses nonseekable */
      };
      
      // use seq_lseek for sequential files
      /////////////////////////////////////
      @ seq depends on !has_llseek @
      identifier fops0.fops;
      identifier sr ~= "seq_read";
      @@
      struct file_operations fops = {
      ...  .read = sr, ...
      +.llseek = seq_lseek, /* we have seq_read */
      };
      
      // use default_llseek if there is a readdir
      ///////////////////////////////////////////
      @ fops1 depends on !has_llseek && !nonseekable1 && !nonseekable2 && !seq @
      identifier fops0.fops;
      identifier readdir_e;
      @@
      // any other fop is used that changes pos
      struct file_operations fops = {
      ... .readdir = readdir_e, ...
      +.llseek = default_llseek, /* readdir is present */
      };
      
      // use default_llseek if at least one of read/write touches f_pos
      /////////////////////////////////////////////////////////////////
      @ fops2 depends on !fops1 && !has_llseek && !nonseekable1 && !nonseekable2 && !seq @
      identifier fops0.fops;
      identifier read.read_f;
      @@
      // read fops use offset
      struct file_operations fops = {
      ... .read = read_f, ...
      +.llseek = default_llseek, /* read accesses f_pos */
      };
      
      @ fops3 depends on !fops1 && !fops2 && !has_llseek && !nonseekable1 && !nonseekable2 && !seq @
      identifier fops0.fops;
      identifier write.write_f;
      @@
      // write fops use offset
      struct file_operations fops = {
      ... .write = write_f, ...
      +	.llseek = default_llseek, /* write accesses f_pos */
      };
      
      // Use noop_llseek if neither read nor write accesses f_pos
      ///////////////////////////////////////////////////////////
      
      @ fops4 depends on !fops1 && !fops2 && !fops3 && !has_llseek && !nonseekable1 && !nonseekable2 && !seq @
      identifier fops0.fops;
      identifier read_no_fpos.read_f;
      identifier write_no_fpos.write_f;
      @@
      // write fops use offset
      struct file_operations fops = {
      ...
       .write = write_f,
       .read = read_f,
      ...
      +.llseek = noop_llseek, /* read and write both use no f_pos */
      };
      
      @ depends on has_write && !has_read && !fops1 && !fops2 && !has_llseek && !nonseekable1 && !nonseekable2 && !seq @
      identifier fops0.fops;
      identifier write_no_fpos.write_f;
      @@
      struct file_operations fops = {
      ... .write = write_f, ...
      +.llseek = noop_llseek, /* write uses no f_pos */
      };
      
      @ depends on has_read && !has_write && !fops1 && !fops2 && !has_llseek && !nonseekable1 && !nonseekable2 && !seq @
      identifier fops0.fops;
      identifier read_no_fpos.read_f;
      @@
      struct file_operations fops = {
      ... .read = read_f, ...
      +.llseek = noop_llseek, /* read uses no f_pos */
      };
      
      @ depends on !has_read && !has_write && !fops1 && !fops2 && !has_llseek && !nonseekable1 && !nonseekable2 && !seq @
      identifier fops0.fops;
      @@
      struct file_operations fops = {
      ...
      +.llseek = noop_llseek, /* no read or write fn */
      };
      ===== End semantic patch =====
      Signed-off-by: NArnd Bergmann <arnd@arndb.de>
      Cc: Julia Lawall <julia@diku.dk>
      Cc: Christoph Hellwig <hch@infradead.org>
      6038f373
  21. 17 12月, 2009 2 次提交
  22. 09 12月, 2009 1 次提交
    • F
      spi: fix spidev compilation failure when VERBOSE is defined · 41df70d9
      Florian Fainelli 提交于
      When VERBOSE is defined in the spidev module, the compilation
      will throw an error on 'spi' not being defined:
      
      CC [M]  drivers/spi/spidev.o
      drivers/spi/spidev.c: In function 'spidev_message':
      drivers/spi/spidev.c:266: error: 'spi' undeclared (first use in this function)
      drivers/spi/spidev.c:266: error: (Each undeclared identifier is reported only once
      drivers/spi/spidev.c:266: error: for each function it appears in.)
      
      instead of using spi-> we should actually use spidev->spi.
      This patch fixes the build failure.
      Signed-off-by: NFlorian Fainelli <ffainelli@freebox.fr>
      Signed-off-by: NGrant Likely <grant.likely@secretlab.ca>
      41df70d9
  23. 04 12月, 2009 1 次提交
  24. 14 10月, 2009 1 次提交
  25. 02 10月, 2009 1 次提交
  26. 23 9月, 2009 1 次提交
  27. 01 7月, 2009 1 次提交
    • D
      spi: new spi->mode bits · b55f627f
      David Brownell 提交于
      Add two new spi_device.mode bits to accomodate more protocol options, and
      pass them through to usermode drivers:
      
       * SPI_NO_CS ... a second 3-wire variant, where the chipselect
         line is removed instead of a data line; transfers are still
         full duplex.
      
         This obviously has STRONG protocol implications since the
         chipselect transitions can't be used to synchronize state
         transitions with the SPI master.
      
       * SPI_READY ... defines open drain signal that's pulled low
         to pause the clock.  This defines a 5-wire variant (normal
         4-wire SPI plus READY) and two 4-wire variants (READY plus
         each of the 3-wire flavors).
      
         Such hardware flow control can be a big win.  There are ADC
         converters and flash chips that expose READY signals, but not
         many host controllers support it today.
      
      The spi_bitbang code should be changed to use SPI_NO_CS instead of its
      current nonportable hack.  That's a mode most hardware can easily support
      (unlike SPI_READY).
      Signed-off-by: NDavid Brownell <dbrownell@users.sourceforge.net>
      Cc: "Paulraj, Sandeep" <s-paulraj@ti.com>
      Signed-off-by: NAndrew Morton <akpm@linux-foundation.org>
      Signed-off-by: NLinus Torvalds <torvalds@linux-foundation.org>
      b55f627f
  28. 02 12月, 2008 1 次提交
    • W
      spi: avoid spidev crash when device is removed · aaacf4bb
      Wolfgang Ocker 提交于
      I saw a kernel oops in spidev_remove() when a spidev device was registered
      and I unloaded the SPI master driver:
      
      Unable to handle kernel paging request for data at address 0x00000004
      Faulting instruction address: 0xc01c0c50
      Oops: Kernel access of bad area, sig: 11 [#1]
      CDSPR
      Modules linked in: spi_ppc4xx(-)
      NIP: c01c0c50 LR: c01bf9e4 CTR: c01c0c34
      REGS: cec89c30 TRAP: 0300   Not tainted  (2.6.27.3izt)
      MSR: 00021000 <ME>  CR: 24000228  XER: 20000007
      DEAR: 00000004, ESR: 00800000
      TASK = cf889040[2070] 'rmmod' THREAD: cec88000
      GPR00: 00000000 cec89ce0 cf889040 cec8e000 00000004 cec8e000 ffffffff 00000000
      GPR08: 0000001c c0336380 00000000 c01c0c34 00000001 1001a338 100e0000 100df49c
      GPR16: 100b54c0 100df49c 100ddd20 100f05a8 100b5340 100efd68 00000000 00000000
      GPR24: 100ec008 100f0428 c0327788 c0327794 cec8e0ac cec8e000 c0336380 00000000
      NIP [c01c0c50] spidev_remove+0x1c/0xe4
      LR [c01bf9e4] spi_drv_remove+0x2c/0x3c
      Call Trace:
      [cec89d00] [c01bf9e4] spi_drv_remove+0x2c/0x3c
      [cec89d10] [c01859a0] __device_release_driver+0x78/0xb4
      [cec89d20] [c0185ab0] device_release_driver+0x28/0x44
      [cec89d40] [c0184be8] bus_remove_device+0xac/0xd8
      [cec89d60] [c0183094] device_del+0x100/0x194
      [cec89d80] [c0183140] device_unregister+0x18/0x30
      [cec89da0] [c01bf30c] __unregister+0x20/0x34
      [cec89db0] [c0182778] device_for_each_child+0x38/0x74
      [cec89de0] [c01bf2d0] spi_unregister_master+0x28/0x44
      [cec89e00] [c01bfeac] spi_bitbang_stop+0x1c/0x58
      [cec89e20] [d908a5e0] spi_ppc4xx_of_remove+0x24/0x7c [spi_ppc4xx]
      [...]
      
      IMHO a call to spi_set_drvdata() is missing in spidev_probe(). The patch
      below helped.
      Signed-off-by: NWolfgang Ocker <weo@reccoware.de>
      Signed-off-by: NDavid Brownell <dbrownell@users.sourceforge.net>
      Signed-off-by: NAndrew Morton <akpm@linux-foundation.org>
      Signed-off-by: NLinus Torvalds <torvalds@linux-foundation.org>
      aaacf4bb
  29. 17 10月, 2008 1 次提交
  30. 25 7月, 2008 1 次提交
  31. 22 7月, 2008 1 次提交
  32. 05 7月, 2008 1 次提交
    • S
      spi: fix the read path in spidev · 4b1295b0
      Sebastian Siewior 提交于
      This got broken by the recent "fix rmmod $spi_driver while spidev-user is
      active".  I tested the rmmod & write path but didn't check the read path.
      I am sorry.  The read logic changed and spidev_sync_read() +
      spidev_sync_write() do not return zero on success anymore but the number
      of bytes that has been transfered over the bus.  This patch changes the
      logic and copy_to_user() gets called again.
      
      The write path returns the number of bytes which are written to the
      underlying device what may be less than the requested size.  This patch
      makes the same change to the read path or else we request a read of 20
      bytes, get 10, don't call copy to user and report to the user that we read
      10 bytes.
      
      [akpm@linux-foundation.org: remove test of known-to-be-zero local]
      Signed-off-by: NSebastian Siewior <bigeasy@linutronix.de>
      Acked-by: NDavid Brownell <dbrownell@users.sourceforge.net>
      Signed-off-by: NAndrew Morton <akpm@linux-foundation.org>
      Signed-off-by: NLinus Torvalds <torvalds@linux-foundation.org>
      4b1295b0
  33. 21 6月, 2008 1 次提交
  34. 07 6月, 2008 1 次提交
  35. 25 5月, 2008 1 次提交
  36. 29 10月, 2007 1 次提交
    • A
      fix abuses of ptrdiff_t · 142956af
      Al Viro 提交于
      Use of ptrdiff_t in places like
      
      -                       if (!access_ok(VERIFY_WRITE, u_tmp->rx_buf, u_tmp->len))
      +                       if (!access_ok(VERIFY_WRITE, (u8 __user *)
      +                                               (ptrdiff_t) u_tmp->rx_buf,
      +                                               u_tmp->len))
      
      is wrong; for one thing, it's a bad C (it's what uintptr_t is for; in general
      we are not even promised that ptrdiff_t is large enough to hold a pointer,
      just enough to hold a difference between two pointers within the same object).
      For another, it confuses the fsck out of sparse.
      
      Use unsigned long or uintptr_t instead.  There are several places misusing
      ptrdiff_t; fixed.
      Signed-off-by: NAl Viro <viro@zeniv.linux.org.uk>
      Signed-off-by: NLinus Torvalds <torvalds@linux-foundation.org>
      142956af
  37. 12 8月, 2007 1 次提交