1. 15 6月, 2016 1 次提交
    • N
      debugfs: full_proxy_open(): free proxy on ->open() failure · b10e3e90
      Nicolai Stange 提交于
      Debugfs' full_proxy_open(), the ->open() installed at all inodes created
      through debugfs_create_file(),
      - grabs a reference to the original struct file_operations instance passed
        to debugfs_create_file(),
      - dynamically allocates a proxy struct file_operations instance wrapping
        the original
      - and installs this at the file's ->f_op.
      
      Afterwards, it calls the original ->open() and passes its return value back
      to the VFS layer.
      
      Now, if that return value indicates failure, the VFS layer won't ever call
      ->release() and thus, neither the reference to the original file_operations
      nor the memory for the proxy file_operations will get released, i.e. both
      are leaked.
      
      Upon failure of the original fops' ->open(), undo the proxy installation.
      That is:
      - Set the struct file ->f_op to what it had been when full_proxy_open()
        was entered.
      - Drop the reference to the original file_operations.
      - Free the memory holding the proxy file_operations.
      
      Fixes: 49d200de ("debugfs: prevent access to removed files' private
                            data")
      Signed-off-by: NNicolai Stange <nicstange@gmail.com>
      Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
      b10e3e90
  2. 13 4月, 2016 7 次提交
    • N
      debugfs: unproxify files created through debugfs_create_u32_array() · c4a74f63
      Nicolai Stange 提交于
      The struct file_operations u32_array_fops associated with files created
      through debugfs_create_u32_array() has been lifetime aware already:
      everything needed for subsequent operation is copied to a ->f_private
      buffer at file opening time in u32_array_open(). Now, ->open() is always
      protected against file removal issues by the debugfs core.
      
      There is no need for the debugfs core to wrap the u32_array_fops
      with a file lifetime managing proxy.
      
      Make debugfs_create_u32_array() create its files in non-proxying operation
      mode by means of debugfs_create_file_unsafe().
      Signed-off-by: NNicolai Stange <nicstange@gmail.com>
      Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
      c4a74f63
    • N
      debugfs: unproxify files created through debugfs_create_blob() · 83b711cb
      Nicolai Stange 提交于
      Currently, the struct file_operations fops_blob associated with files
      created through the debugfs_create_blob() helpers are not file
      lifetime aware.
      
      Thus, a lifetime managing proxy is created around fops_blob each time such
      a file is opened which is an unnecessary waste of resources.
      
      Implement file lifetime management for the fops_bool file_operations.
      Namely, make read_file_blob() safe gainst file removals by means of
      debugfs_use_file_start() and debugfs_use_file_finish().
      
      Make debugfs_create_blob() create its files in non-proxying operation mode
      by means of debugfs_create_file_unsafe().
      Signed-off-by: NNicolai Stange <nicstange@gmail.com>
      Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
      83b711cb
    • N
      debugfs: unproxify files created through debugfs_create_bool() · 4d45f797
      Nicolai Stange 提交于
      Currently, the struct file_operations fops_bool associated with files
      created through the debugfs_create_bool() helpers are not file
      lifetime aware.
      
      Thus, a lifetime managing proxy is created around fops_bool each time such
      a file is opened which is an unnecessary waste of resources.
      
      Implement file lifetime management for the fops_bool file_operations.
      Namely, make debugfs_read_file_bool() and debugfs_write_file_bool() safe
      against file removals by means of debugfs_use_file_start() and
      debugfs_use_file_finish().
      
      Make debugfs_create_bool() create its files in non-proxying operation mode
      through debugfs_create_mode_unsafe().
      
      Finally, purge debugfs_create_mode() as debugfs_create_bool() had been its
      last user.
      Signed-off-by: NNicolai Stange <nicstange@gmail.com>
      Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
      4d45f797
    • N
      debugfs: unproxify integer attribute files · 4909f168
      Nicolai Stange 提交于
      Currently, the struct file_operations associated with the integer attribute
      style files created through the debugfs_create_*() helpers are not file
      lifetime aware as they are defined by means of DEFINE_SIMPLE_ATTRIBUTE().
      
      Thus, a lifetime managing proxy is created around the original fops each
      time such a file is opened which is an unnecessary waste of resources.
      
      Migrate all usages of DEFINE_SIMPLE_ATTRIBUTE() within debugfs itself
      to DEFINE_DEBUGFS_ATTRIBUTE() in order to implement file lifetime managing
      within the struct file_operations thus defined.
      
      Introduce the debugfs_create_mode_unsafe() helper, analogous to
      debugfs_create_mode(), but distinct in that it creates the files in
      non-proxying operation mode through debugfs_create_file_unsafe().
      
      Feed all struct file_operations migrated to DEFINE_DEBUGFS_ATTRIBUTE()
      into debugfs_create_mode_unsafe() instead of former debugfs_create_mode().
      Signed-off-by: NNicolai Stange <nicstange@gmail.com>
      Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
      4909f168
    • N
      debugfs: add support for self-protecting attribute file fops · c6468808
      Nicolai Stange 提交于
      In order to protect them against file removal issues, debugfs_create_file()
      creates a lifetime managing proxy around each struct file_operations
      handed in.
      
      In cases where this struct file_operations is able to manage file lifetime
      by itself already, the proxy created by debugfs is a waste of resources.
      
      The most common class of struct file_operations given to debugfs are those
      defined by means of the DEFINE_SIMPLE_ATTRIBUTE() macro.
      
      Introduce a DEFINE_DEBUGFS_ATTRIBUTE() macro to allow any
      struct file_operations of this class to be easily made file lifetime aware
      and thus, to be operated unproxied.
      
      Specifically, introduce debugfs_attr_read() and debugfs_attr_write()
      which wrap simple_attr_read() and simple_attr_write() under the protection
      of a debugfs_use_file_start()/debugfs_use_file_finish() pair.
      
      Make DEFINE_DEBUGFS_ATTRIBUTE() set the defined struct file_operations'
      ->read() and ->write() members to these wrappers.
      
      Export debugfs_create_file_unsafe() in order to allow debugfs users to
      create their files in non-proxying operation mode.
      Signed-off-by: NNicolai Stange <nicstange@gmail.com>
      Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
      c6468808
    • N
      debugfs: prevent access to removed files' private data · 49d200de
      Nicolai Stange 提交于
      Upon return of debugfs_remove()/debugfs_remove_recursive(), it might
      still be attempted to access associated private file data through
      previously opened struct file objects. If that data has been freed by
      the caller of debugfs_remove*() in the meanwhile, the reading/writing
      process would either encounter a fault or, if the memory address in
      question has been reassigned again, unrelated data structures could get
      overwritten.
      
      However, since debugfs files are seldomly removed, usually from module
      exit handlers only, the impact is very low.
      
      Currently, there are ~1000 call sites of debugfs_create_file() spread
      throughout the whole tree and touching all of those struct file_operations
      in order to make them file removal aware by means of checking the result of
      debugfs_use_file_start() from within their methods is unfeasible.
      
      Instead, wrap the struct file_operations by a lifetime managing proxy at
      file open:
      - In debugfs_create_file(), the original fops handed in has got stashed
        away in ->d_fsdata already.
      - In debugfs_create_file(), install a proxy file_operations factory,
        debugfs_full_proxy_file_operations, at ->i_fop.
      
      This proxy factory has got an ->open() method only. It carries out some
      lifetime checks and if successful, dynamically allocates and sets up a new
      struct file_operations proxy at ->f_op. Afterwards, it forwards to the
      ->open() of the original struct file_operations in ->d_fsdata, if any.
      
      The dynamically set up proxy at ->f_op has got a lifetime managing wrapper
      set for each of the methods defined in the original struct file_operations
      in ->d_fsdata.
      
      Its ->release()er frees the proxy again and forwards to the original
      ->release(), if any.
      
      In order not to mislead the VFS layer, it is strictly necessary to leave
      those fields blank in the proxy that have been NULL in the original
      struct file_operations also, i.e. aren't supported. This is why there is a
      need for dynamically allocated proxies. The choice made not to allocate a
      proxy instance for every dentry at file creation, but for every
      struct file object instantiated thereof is justified by the expected usage
      pattern of debugfs, namely that in general very few files get opened more
      than once at a time.
      
      The wrapper methods set in the struct file_operations implement lifetime
      managing by means of the SRCU protection facilities already in place for
      debugfs:
      They set up a SRCU read side critical section and check whether the dentry
      is still alive by means of debugfs_use_file_start(). If so, they forward
      the call to the original struct file_operation stored in ->d_fsdata, still
      under the protection of the SRCU read side critical section.
      This SRCU read side critical section prevents any pending debugfs_remove()
      and friends to return to their callers. Since a file's private data must
      only be freed after the return of debugfs_remove(), the ongoing proxied
      call is guarded against any file removal race.
      
      If, on the other hand, the initial call to debugfs_use_file_start() detects
      that the dentry is dead, the wrapper simply returns -EIO and does not
      forward the call. Note that the ->poll() wrapper is special in that its
      signature does not allow for the return of arbitrary -EXXX values and thus,
      POLLHUP is returned here.
      
      In order not to pollute debugfs with wrapper definitions that aren't ever
      needed, I chose not to define a wrapper for every struct file_operations
      method possible. Instead, a wrapper is defined only for the subset of
      methods which are actually set by any debugfs users.
      Currently, these are:
      
        ->llseek()
        ->read()
        ->write()
        ->unlocked_ioctl()
        ->poll()
      
      The ->release() wrapper is special in that it does not protect the original
      ->release() in any way from dead files in order not to leak resources.
      Thus, any ->release() handed to debugfs must implement file lifetime
      management manually, if needed.
      For only 33 out of a total of 434 releasers handed in to debugfs, it could
      not be verified immediately whether they access data structures that might
      have been freed upon a debugfs_remove() return in the meanwhile.
      
      Export debugfs_use_file_start() and debugfs_use_file_finish() in order to
      allow any ->release() to manually implement file lifetime management.
      
      For a set of common cases of struct file_operations implemented by the
      debugfs_core itself, future patches will incorporate file lifetime
      management directly within those in order to allow for their unproxied
      operation. Rename the original, non-proxying "debugfs_create_file()" to
      "debugfs_create_file_unsafe()" and keep it for future internal use by
      debugfs itself. Factor out code common to both into the new
      __debugfs_create_file().
      Signed-off-by: NNicolai Stange <nicstange@gmail.com>
      Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
      49d200de
    • N
      debugfs: prevent access to possibly dead file_operations at file open · 9fd4dcec
      Nicolai Stange 提交于
      Nothing prevents a dentry found by path lookup before a return of
      __debugfs_remove() to actually get opened after that return. Now, after
      the return of __debugfs_remove(), there are no guarantees whatsoever
      regarding the memory the corresponding inode's file_operations object
      had been kept in.
      
      Since __debugfs_remove() is seldomly invoked, usually from module exit
      handlers only, the race is hard to trigger and the impact is very low.
      
      A discussion of the problem outlined above as well as a suggested
      solution can be found in the (sub-)thread rooted at
      
        http://lkml.kernel.org/g/20130401203445.GA20862@ZenIV.linux.org.uk
        ("Yet another pipe related oops.")
      
      Basically, Greg KH suggests to introduce an intermediate fops and
      Al Viro points out that a pointer to the original ones may be stored in
      ->d_fsdata.
      
      Follow this line of reasoning:
      - Add SRCU as a reverse dependency of DEBUG_FS.
      - Introduce a srcu_struct object for the debugfs subsystem.
      - In debugfs_create_file(), store a pointer to the original
        file_operations object in ->d_fsdata.
      - Make debugfs_remove() and debugfs_remove_recursive() wait for a
        SRCU grace period after the dentry has been delete()'d and before they
        return to their callers.
      - Introduce an intermediate file_operations object named
        "debugfs_open_proxy_file_operations". It's ->open() functions checks,
        under the protection of a SRCU read lock, whether the dentry is still
        alive, i.e. has not been d_delete()'d and if so, tries to acquire a
        reference on the owning module.
        On success, it sets the file object's ->f_op to the original
        file_operations and forwards the ongoing open() call to the original
        ->open().
      - For clarity, rename the former debugfs_file_operations to
        debugfs_noop_file_operations -- they are in no way canonical.
      
      The choice of SRCU over "normal" RCU is justified by the fact, that the
      former may also be used to protect ->i_private data from going away
      during the execution of a file's readers and writers which may (and do)
      sleep.
      
      Finally, introduce the fs/debugfs/internal.h header containing some
      declarations internal to the debugfs implementation.
      Signed-off-by: NNicolai Stange <nicstange@gmail.com>
      Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
      9fd4dcec
  3. 19 10月, 2015 1 次提交
  4. 18 10月, 2015 4 次提交
  5. 04 10月, 2015 1 次提交
  6. 21 7月, 2015 1 次提交
  7. 11 5月, 2015 1 次提交
  8. 16 4月, 2015 1 次提交
  9. 27 11月, 2014 1 次提交
  10. 06 11月, 2014 1 次提交
  11. 10 7月, 2014 1 次提交
  12. 04 6月, 2013 2 次提交
  13. 22 9月, 2012 2 次提交
    • L
      debugfs: fix u32_array race in format_array_alloc · e05e279e
      Linus Torvalds 提交于
      The format_array_alloc() function is fundamentally racy, in that it
      prints the array twice: once to figure out how much space to allocate
      for the buffer, and the second time to actually print out the data.
      
      If any of the array contents changes in between, the allocation size may
      be wrong, and the end result may be truncated in odd ways.
      
      Just don't do it.  Allocate a maximum-sized array up-front, and just
      format the array contents once.  The only user of the u32_array
      interfaces is the Xen spinlock statistics code, and it has 31 entries in
      the arrays, so the maximum size really isn't that big, and the end
      result is much simpler code without the bug.
      Signed-off-by: NLinus Torvalds <torvalds@linux-foundation.org>
      e05e279e
    • D
      debugfs: fix race in u32_array_read and allocate array at open · 36048853
      David Rientjes 提交于
      u32_array_open() is racy when multiple threads read from a file with a
      seek position of zero, i.e. when two or more simultaneous reads are
      occurring after the non-seekable files are created.  It is possible that
      file->private_data is double-freed because the threads races between
      
      	kfree(file->private-data);
      
      and
      
      	file->private_data = NULL;
      
      The fix is to only do format_array_alloc() when the file is opened and
      free it when it is closed.
      
      Note that because the file has always been non-seekable, you can't open
      it and read it multiple times anyway, so the data has always been
      generated just once.  The difference is that now it is generated at open
      time rather than at the time of the first read, and that avoids the
      race.
      Reported-by: NDave Jones <davej@redhat.com>
      Acked-by: NKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>
      Tested-by: NRaghavendra <raghavendra.kt@linux.vnet.ibm.com>
      Signed-off-by: NDavid Rientjes <rientjes@google.com>
      Signed-off-by: NLinus Torvalds <torvalds@linux-foundation.org>
      36048853
  14. 17 4月, 2012 1 次提交
  15. 06 4月, 2012 1 次提交
    • S
      simple_open: automatically convert to simple_open() · 234e3405
      Stephen Boyd 提交于
      Many users of debugfs copy the implementation of default_open() when
      they want to support a custom read/write function op.  This leads to a
      proliferation of the default_open() implementation across the entire
      tree.
      
      Now that the common implementation has been consolidated into libfs we
      can replace all the users of this function with simple_open().
      
      This replacement was done with the following semantic patch:
      
      <smpl>
      @ open @
      identifier open_f != simple_open;
      identifier i, f;
      @@
      -int open_f(struct inode *i, struct file *f)
      -{
      (
      -if (i->i_private)
      -f->private_data = i->i_private;
      |
      -f->private_data = i->i_private;
      )
      -return 0;
      -}
      
      @ has_open depends on open @
      identifier fops;
      identifier open.open_f;
      @@
      struct file_operations fops = {
      ...
      -.open = open_f,
      +.open = simple_open,
      ...
      };
      </smpl>
      
      [akpm@linux-foundation.org: checkpatch fixes]
      Signed-off-by: NStephen Boyd <sboyd@codeaurora.org>
      Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
      Cc: Al Viro <viro@zeniv.linux.org.uk>
      Cc: Julia Lawall <Julia.Lawall@lip6.fr>
      Acked-by: NIngo Molnar <mingo@elte.hu>
      Signed-off-by: NAndrew Morton <akpm@linux-foundation.org>
      Signed-off-by: NLinus Torvalds <torvalds@linux-foundation.org>
      234e3405
  16. 21 3月, 2012 1 次提交
  17. 25 1月, 2012 1 次提交
  18. 24 1月, 2012 1 次提交
  19. 04 1月, 2012 2 次提交
  20. 27 11月, 2011 1 次提交
  21. 23 11月, 2011 1 次提交
  22. 19 11月, 2011 2 次提交
  23. 19 5月, 2011 1 次提交
  24. 14 5月, 2011 1 次提交
    • S
      debugfs: Silence DEBUG_STRICT_USER_COPY_CHECKS=y warning · c42d2237
      Stephen Boyd 提交于
      Enabling DEBUG_STRICT_USER_COPY_CHECKS causes the following
      warning:
      
      In file included from arch/x86/include/asm/uaccess.h:573,
                       from include/linux/uaccess.h:5,
                       from include/linux/highmem.h:7,
                       from include/linux/pagemap.h:10,
                       from fs/debugfs/file.c:18:
      In function 'copy_from_user',
          inlined from 'write_file_bool' at fs/debugfs/file.c:435:
      arch/x86/include/asm/uaccess_64.h:65: warning: call to
      'copy_from_user_overflow' declared with attribute warning:
      copy_from_user() buffer size is not provably correct
      
      presumably due to buf_size being signed causing GCC to fail to
      see that buf_size can't become negative.
      Signed-off-by: NStephen Boyd <sboyd@codeaurora.org>
      Signed-off-by: NGreg Kroah-Hartman <gregkh@suse.de>
      c42d2237
  25. 26 4月, 2011 1 次提交
  26. 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
  27. 20 5月, 2010 1 次提交