1. 20 7月, 2018 6 次提交
  2. 18 7月, 2018 5 次提交
    • M
      ovl: add ovl_fiemap() · 9e142c41
      Miklos Szeredi 提交于
      Implement stacked fiemap().
      
      Need to split inode operations for regular file (which has fiemap) and
      special file (which doesn't have fiemap).
      Signed-off-by: NMiklos Szeredi <mszeredi@redhat.com>
      9e142c41
    • M
      ovl: stack file ops · d1d04ef8
      Miklos Szeredi 提交于
      Implement file operations on a regular overlay file.  The underlying file
      is opened separately and cached in ->private_data.
      
      It might be worth making an exception for such files when accounting in
      nr_file to confirm to userspace expectations.  We are only adding a small
      overhead (248bytes for the struct file) since the real inode and dentry are
      pinned by overlayfs anyway.
      
      This patch doesn't have any effect, since the vfs will use d_real() to find
      the real underlying file to open.  The patch at the end of the series will
      actually enable this functionality.
      
      AV: make it use open_with_fake_path(), don't mess with override_creds
      
      SzM: still need to mess with override_creds() until no fs uses
      current_cred() in their open method.
      Signed-off-by: NMiklos Szeredi <mszeredi@redhat.com>
      Signed-off-by: NAl Viro <viro@zeniv.linux.org.uk>
      d1d04ef8
    • M
      ovl: copy up file size as well · 46e5d0a3
      Miklos Szeredi 提交于
      Copy i_size of the underlying inode to the overlay inode in ovl_copyattr().
      
      This is in preparation for stacking I/O operations on overlay files.
      
      This patch shouldn't have any observable effect.
      
      Remove stale comment from ovl_setattr() [spotted by Vivek Goyal].
      Signed-off-by: NMiklos Szeredi <mszeredi@redhat.com>
      46e5d0a3
    • M
      Revert "Revert "ovl: get_write_access() in truncate"" · 5812160e
      Miklos Szeredi 提交于
      This reverts commit 31c3a706.
      
      Re-add functionality dealing with i_writecount on truncate to overlayfs.
      This patch shouldn't have any observable effects, since we just re-assert
      the writecout that vfs_truncate() already got for us.
      
      This is in preparation for moving overlay functionality out of the VFS.
      Signed-off-by: NMiklos Szeredi <mszeredi@redhat.com>
      5812160e
    • M
      ovl: copy up times · d9854c87
      Miklos Szeredi 提交于
      Copy up mtime and ctime to overlay inode after times in real object are
      modified.  Be careful not to dirty cachelines when not necessary.
      
      This is in preparation for moving overlay functionality out of the VFS.
      
      This patch shouldn't have any observable effect.
      Signed-off-by: NMiklos Szeredi <mszeredi@redhat.com>
      d9854c87
  3. 06 6月, 2018 1 次提交
    • D
      vfs: change inode times to use struct timespec64 · 95582b00
      Deepa Dinamani 提交于
      struct timespec is not y2038 safe. Transition vfs to use
      y2038 safe struct timespec64 instead.
      
      The change was made with the help of the following cocinelle
      script. This catches about 80% of the changes.
      All the header file and logic changes are included in the
      first 5 rules. The rest are trivial substitutions.
      I avoid changing any of the function signatures or any other
      filesystem specific data structures to keep the patch simple
      for review.
      
      The script can be a little shorter by combining different cases.
      But, this version was sufficient for my usecase.
      
      virtual patch
      
      @ depends on patch @
      identifier now;
      @@
      - struct timespec
      + struct timespec64
        current_time ( ... )
        {
      - struct timespec now = current_kernel_time();
      + struct timespec64 now = current_kernel_time64();
        ...
      - return timespec_trunc(
      + return timespec64_trunc(
        ... );
        }
      
      @ depends on patch @
      identifier xtime;
      @@
       struct \( iattr \| inode \| kstat \) {
       ...
      -       struct timespec xtime;
      +       struct timespec64 xtime;
       ...
       }
      
      @ depends on patch @
      identifier t;
      @@
       struct inode_operations {
       ...
      int (*update_time) (...,
      -       struct timespec t,
      +       struct timespec64 t,
      ...);
       ...
       }
      
      @ depends on patch @
      identifier t;
      identifier fn_update_time =~ "update_time$";
      @@
       fn_update_time (...,
      - struct timespec *t,
      + struct timespec64 *t,
       ...) { ... }
      
      @ depends on patch @
      identifier t;
      @@
      lease_get_mtime( ... ,
      - struct timespec *t
      + struct timespec64 *t
        ) { ... }
      
      @te depends on patch forall@
      identifier ts;
      local idexpression struct inode *inode_node;
      identifier i_xtime =~ "^i_[acm]time$";
      identifier ia_xtime =~ "^ia_[acm]time$";
      identifier fn_update_time =~ "update_time$";
      identifier fn;
      expression e, E3;
      local idexpression struct inode *node1;
      local idexpression struct inode *node2;
      local idexpression struct iattr *attr1;
      local idexpression struct iattr *attr2;
      local idexpression struct iattr attr;
      identifier i_xtime1 =~ "^i_[acm]time$";
      identifier i_xtime2 =~ "^i_[acm]time$";
      identifier ia_xtime1 =~ "^ia_[acm]time$";
      identifier ia_xtime2 =~ "^ia_[acm]time$";
      @@
      (
      (
      - struct timespec ts;
      + struct timespec64 ts;
      |
      - struct timespec ts = current_time(inode_node);
      + struct timespec64 ts = current_time(inode_node);
      )
      
      <+... when != ts
      (
      - timespec_equal(&inode_node->i_xtime, &ts)
      + timespec64_equal(&inode_node->i_xtime, &ts)
      |
      - timespec_equal(&ts, &inode_node->i_xtime)
      + timespec64_equal(&ts, &inode_node->i_xtime)
      |
      - timespec_compare(&inode_node->i_xtime, &ts)
      + timespec64_compare(&inode_node->i_xtime, &ts)
      |
      - timespec_compare(&ts, &inode_node->i_xtime)
      + timespec64_compare(&ts, &inode_node->i_xtime)
      |
      ts = current_time(e)
      |
      fn_update_time(..., &ts,...)
      |
      inode_node->i_xtime = ts
      |
      node1->i_xtime = ts
      |
      ts = inode_node->i_xtime
      |
      <+... attr1->ia_xtime ...+> = ts
      |
      ts = attr1->ia_xtime
      |
      ts.tv_sec
      |
      ts.tv_nsec
      |
      btrfs_set_stack_timespec_sec(..., ts.tv_sec)
      |
      btrfs_set_stack_timespec_nsec(..., ts.tv_nsec)
      |
      - ts = timespec64_to_timespec(
      + ts =
      ...
      -)
      |
      - ts = ktime_to_timespec(
      + ts = ktime_to_timespec64(
      ...)
      |
      - ts = E3
      + ts = timespec_to_timespec64(E3)
      |
      - ktime_get_real_ts(&ts)
      + ktime_get_real_ts64(&ts)
      |
      fn(...,
      - ts
      + timespec64_to_timespec(ts)
      ,...)
      )
      ...+>
      (
      <... when != ts
      - return ts;
      + return timespec64_to_timespec(ts);
      ...>
      )
      |
      - timespec_equal(&node1->i_xtime1, &node2->i_xtime2)
      + timespec64_equal(&node1->i_xtime2, &node2->i_xtime2)
      |
      - timespec_equal(&node1->i_xtime1, &attr2->ia_xtime2)
      + timespec64_equal(&node1->i_xtime2, &attr2->ia_xtime2)
      |
      - timespec_compare(&node1->i_xtime1, &node2->i_xtime2)
      + timespec64_compare(&node1->i_xtime1, &node2->i_xtime2)
      |
      node1->i_xtime1 =
      - timespec_trunc(attr1->ia_xtime1,
      + timespec64_trunc(attr1->ia_xtime1,
      ...)
      |
      - attr1->ia_xtime1 = timespec_trunc(attr2->ia_xtime2,
      + attr1->ia_xtime1 =  timespec64_trunc(attr2->ia_xtime2,
      ...)
      |
      - ktime_get_real_ts(&attr1->ia_xtime1)
      + ktime_get_real_ts64(&attr1->ia_xtime1)
      |
      - ktime_get_real_ts(&attr.ia_xtime1)
      + ktime_get_real_ts64(&attr.ia_xtime1)
      )
      
      @ depends on patch @
      struct inode *node;
      struct iattr *attr;
      identifier fn;
      identifier i_xtime =~ "^i_[acm]time$";
      identifier ia_xtime =~ "^ia_[acm]time$";
      expression e;
      @@
      (
      - fn(node->i_xtime);
      + fn(timespec64_to_timespec(node->i_xtime));
      |
       fn(...,
      - node->i_xtime);
      + timespec64_to_timespec(node->i_xtime));
      |
      - e = fn(attr->ia_xtime);
      + e = fn(timespec64_to_timespec(attr->ia_xtime));
      )
      
      @ depends on patch forall @
      struct inode *node;
      struct iattr *attr;
      identifier i_xtime =~ "^i_[acm]time$";
      identifier ia_xtime =~ "^ia_[acm]time$";
      identifier fn;
      @@
      {
      + struct timespec ts;
      <+...
      (
      + ts = timespec64_to_timespec(node->i_xtime);
      fn (...,
      - &node->i_xtime,
      + &ts,
      ...);
      |
      + ts = timespec64_to_timespec(attr->ia_xtime);
      fn (...,
      - &attr->ia_xtime,
      + &ts,
      ...);
      )
      ...+>
      }
      
      @ depends on patch forall @
      struct inode *node;
      struct iattr *attr;
      struct kstat *stat;
      identifier ia_xtime =~ "^ia_[acm]time$";
      identifier i_xtime =~ "^i_[acm]time$";
      identifier xtime =~ "^[acm]time$";
      identifier fn, ret;
      @@
      {
      + struct timespec ts;
      <+...
      (
      + ts = timespec64_to_timespec(node->i_xtime);
      ret = fn (...,
      - &node->i_xtime,
      + &ts,
      ...);
      |
      + ts = timespec64_to_timespec(node->i_xtime);
      ret = fn (...,
      - &node->i_xtime);
      + &ts);
      |
      + ts = timespec64_to_timespec(attr->ia_xtime);
      ret = fn (...,
      - &attr->ia_xtime,
      + &ts,
      ...);
      |
      + ts = timespec64_to_timespec(attr->ia_xtime);
      ret = fn (...,
      - &attr->ia_xtime);
      + &ts);
      |
      + ts = timespec64_to_timespec(stat->xtime);
      ret = fn (...,
      - &stat->xtime);
      + &ts);
      )
      ...+>
      }
      
      @ depends on patch @
      struct inode *node;
      struct inode *node2;
      identifier i_xtime1 =~ "^i_[acm]time$";
      identifier i_xtime2 =~ "^i_[acm]time$";
      identifier i_xtime3 =~ "^i_[acm]time$";
      struct iattr *attrp;
      struct iattr *attrp2;
      struct iattr attr ;
      identifier ia_xtime1 =~ "^ia_[acm]time$";
      identifier ia_xtime2 =~ "^ia_[acm]time$";
      struct kstat *stat;
      struct kstat stat1;
      struct timespec64 ts;
      identifier xtime =~ "^[acmb]time$";
      expression e;
      @@
      (
      ( node->i_xtime2 \| attrp->ia_xtime2 \| attr.ia_xtime2 \) = node->i_xtime1  ;
      |
       node->i_xtime2 = \( node2->i_xtime1 \| timespec64_trunc(...) \);
      |
       node->i_xtime2 = node->i_xtime1 = node->i_xtime3 = \(ts \| current_time(...) \);
      |
       node->i_xtime1 = node->i_xtime3 = \(ts \| current_time(...) \);
      |
       stat->xtime = node2->i_xtime1;
      |
       stat1.xtime = node2->i_xtime1;
      |
      ( node->i_xtime2 \| attrp->ia_xtime2 \) = attrp->ia_xtime1  ;
      |
      ( attrp->ia_xtime1 \| attr.ia_xtime1 \) = attrp2->ia_xtime2;
      |
      - e = node->i_xtime1;
      + e = timespec64_to_timespec( node->i_xtime1 );
      |
      - e = attrp->ia_xtime1;
      + e = timespec64_to_timespec( attrp->ia_xtime1 );
      |
      node->i_xtime1 = current_time(...);
      |
       node->i_xtime2 = node->i_xtime1 = node->i_xtime3 =
      - e;
      + timespec_to_timespec64(e);
      |
       node->i_xtime1 = node->i_xtime3 =
      - e;
      + timespec_to_timespec64(e);
      |
      - node->i_xtime1 = e;
      + node->i_xtime1 = timespec_to_timespec64(e);
      )
      Signed-off-by: NDeepa Dinamani <deepa.kernel@gmail.com>
      Cc: <anton@tuxera.com>
      Cc: <balbi@kernel.org>
      Cc: <bfields@fieldses.org>
      Cc: <darrick.wong@oracle.com>
      Cc: <dhowells@redhat.com>
      Cc: <dsterba@suse.com>
      Cc: <dwmw2@infradead.org>
      Cc: <hch@lst.de>
      Cc: <hirofumi@mail.parknet.co.jp>
      Cc: <hubcap@omnibond.com>
      Cc: <jack@suse.com>
      Cc: <jaegeuk@kernel.org>
      Cc: <jaharkes@cs.cmu.edu>
      Cc: <jslaby@suse.com>
      Cc: <keescook@chromium.org>
      Cc: <mark@fasheh.com>
      Cc: <miklos@szeredi.hu>
      Cc: <nico@linaro.org>
      Cc: <reiserfs-devel@vger.kernel.org>
      Cc: <richard@nod.at>
      Cc: <sage@redhat.com>
      Cc: <sfrench@samba.org>
      Cc: <swhiteho@redhat.com>
      Cc: <tj@kernel.org>
      Cc: <trond.myklebust@primarydata.com>
      Cc: <tytso@mit.edu>
      Cc: <viro@zeniv.linux.org.uk>
      95582b00
  4. 31 5月, 2018 2 次提交
    • A
      ovl: use inode_insert5() to hash a newly created inode · 01b39dcc
      Amir Goldstein 提交于
      Currently, there is a small window where ovl_obtain_alias() can
      race with ovl_instantiate() and create two different overlay inodes
      with the same underlying real non-dir non-hardlink inode.
      
      The race requires an adversary to guess the file handle of the
      yet to be created upper inode and decode the guessed file handle
      after ovl_creat_real(), but before ovl_instantiate().
      This race does not affect overlay directory inodes, because those
      are decoded via ovl_lookup_real() and not with ovl_obtain_alias().
      
      This patch fixes the race, by using inode_insert5() to add a newly
      created inode to cache.
      
      If the newly created inode apears to already exist in cache (hashed
      by the same real upper inode), we instantiate the dentry with the old
      inode and drop the new inode, instead of silently not hashing the new
      inode.
      Signed-off-by: NAmir Goldstein <amir73il@gmail.com>
      Signed-off-by: NMiklos Szeredi <mszeredi@redhat.com>
      01b39dcc
    • V
      ovl: Pass argument to ovl_get_inode() in a structure · ac6a52eb
      Vivek Goyal 提交于
      ovl_get_inode() right now has 5 parameters. Soon this patch series will
      add 2 more and suddenly argument list starts looking too long.
      
      Hence pass arguments to ovl_get_inode() in a structure and it looks
      little cleaner.
      Signed-off-by: NVivek Goyal <vgoyal@redhat.com>
      Signed-off-by: NAmir Goldstein <amir73il@gmail.com>
      Signed-off-by: NMiklos Szeredi <mszeredi@redhat.com>
      ac6a52eb
  5. 12 4月, 2018 8 次提交
  6. 16 2月, 2018 1 次提交
    • A
      ovl: hash non-dir by lower inode for fsnotify · 764baba8
      Amir Goldstein 提交于
      Commit 31747eda ("ovl: hash directory inodes for fsnotify")
      fixed an issue of inotify watch on directory that stops getting
      events after dropping dentry caches.
      
      A similar issue exists for non-dir non-upper files, for example:
      
      $ mkdir -p lower upper work merged
      $ touch lower/foo
      $ mount -t overlay -o
      lowerdir=lower,workdir=work,upperdir=upper none merged
      $ inotifywait merged/foo &
      $ echo 2 > /proc/sys/vm/drop_caches
      $ cat merged/foo
      
      inotifywait doesn't get the OPEN event, because ovl_lookup() called
      from 'cat' allocates a new overlay inode and does not reuse the
      watched inode.
      
      Fix this by hashing non-dir overlay inodes by lower real inode in
      the following cases that were not hashed before this change:
       - A non-upper overlay mount
       - A lower non-hardlink when index=off
      
      A helper ovl_hash_bylower() was added to put all the logic and
      documentation about which real inode an overlay inode is hashed by
      into one place.
      
      The issue dates back to initial version of overlayfs, but this
      patch depends on ovl_inode code that was introduced in kernel v4.13.
      
      Cc: <stable@vger.kernel.org> #v4.13
      Signed-off-by: NAmir Goldstein <amir73il@gmail.com>
      Signed-off-by: NMiklos Szeredi <mszeredi@redhat.com>
      764baba8
  7. 24 1月, 2018 6 次提交
  8. 19 1月, 2018 1 次提交
    • A
      ovl: hash directory inodes for fsnotify · 31747eda
      Amir Goldstein 提交于
      fsnotify pins a watched directory inode in cache, but if directory dentry
      is released, new lookup will allocate a new dentry and a new inode.
      Directory events will be notified on the new inode, while fsnotify listener
      is watching the old pinned inode.
      
      Hash all directory inodes to reuse the pinned inode on lookup. Pure upper
      dirs are hashes by real upper inode, merge and lower dirs are hashed by
      real lower inode.
      
      The reference to lower inode was being held by the lower dentry object
      in the overlay dentry (oe->lowerstack[0]). Releasing the overlay dentry
      may drop lower inode refcount to zero. Add a refcount on behalf of the
      overlay inode to prevent that.
      
      As a by-product, hashing directory inodes also detects multiple
      redirected dirs to the same lower dir and uncovered redirected dir
      target on and returns -ESTALE on lookup.
      
      The reported issue dates back to initial version of overlayfs, but this
      patch depends on ovl_inode code that was introduced in kernel v4.13.
      
      Cc: <stable@vger.kernel.org> #v4.13
      Reported-by: NNiklas Cassel <niklas.cassel@axis.com>
      Signed-off-by: NAmir Goldstein <amir73il@gmail.com>
      Signed-off-by: NMiklos Szeredi <mszeredi@redhat.com>
      Tested-by: NNiklas Cassel <niklas.cassel@axis.com>
      31747eda
  9. 09 11月, 2017 5 次提交
  10. 24 10月, 2017 1 次提交
    • A
      ovl: fix EIO from lookup of non-indexed upper · 6eaf0111
      Amir Goldstein 提交于
      Commit fbaf94ee ("ovl: don't set origin on broken lower hardlink")
      attempt to avoid the condition of non-indexed upper inode with lower
      hardlink as origin. If this condition is found, lookup returns EIO.
      
      The protection of commit mentioned above does not cover the case of lower
      that is not a hardlink when it is copied up (with either index=off/on)
      and then lower is hardlinked while overlay is offline.
      
      Changes to lower layer while overlayfs is offline should not result in
      unexpected behavior, so a permanent EIO error after creating a link in
      lower layer should not be considered as correct behavior.
      
      This fix replaces EIO error with success in cases where upper has origin
      but no index is found, or index is found that does not match upper
      inode. In those cases, lookup will not fail and the returned overlay inode
      will be hashed by upper inode instead of by lower origin inode.
      
      Fixes: 359f392c ("ovl: lookup index entry for copy up origin")
      Cc: <stable@vger.kernel.org> # v4.13
      Signed-off-by: NAmir Goldstein <amir73il@gmail.com>
      Signed-off-by: NMiklos Szeredi <mszeredi@redhat.com>
      6eaf0111
  11. 12 9月, 2017 1 次提交
    • A
      ovl: fix false positive ESTALE on lookup · 939ae4ef
      Amir Goldstein 提交于
      Commit b9ac5c27 ("ovl: hash overlay non-dir inodes by copy up origin")
      verifies that the origin lower inode stored in the overlayfs inode matched
      the inode of a copy up origin dentry found by lookup.
      
      There is a false positive result in that check when lower fs does not
      support file handles and copy up origin cannot be followed by file handle
      at lookup time.
      
      The false negative happens when finding an overlay inode in cache on a
      copied up overlay dentry lookup. The overlay inode still 'remembers' the
      copy up origin inode, but the copy up origin dentry is not available for
      verification.
      
      Relax the check in case copy up origin dentry is not available.
      
      Fixes: b9ac5c27 ("ovl: hash overlay non-dir inodes by copy up...")
      Cc: <stable@vger.kernel.org> # v4.13
      Reported-by: NJordi Pujol <jordipujolp@gmail.com>
      Signed-off-by: NAmir Goldstein <amir73il@gmail.com>
      Signed-off-by: NMiklos Szeredi <mszeredi@redhat.com>
      939ae4ef
  12. 28 7月, 2017 1 次提交
  13. 20 7月, 2017 1 次提交
  14. 05 7月, 2017 1 次提交
    • A
      ovl: cleanup orphan index entries · caf70cb2
      Amir Goldstein 提交于
      index entry should live only as long as there are upper or lower
      hardlinks.
      
      Cleanup orphan index entries on mount and when dropping the last
      overlay inode nlink.
      
      When about to cleanup or link up to orphan index and the index inode
      nlink > 1, admit that something went wrong and adjust overlay nlink
      to index inode nlink - 1 to prevent it from dropping below zero.
      This could happen when adding lower hardlinks underneath a mounted
      overlay and then trying to unlink them.
      Signed-off-by: NAmir Goldstein <amir73il@gmail.com>
      Signed-off-by: NMiklos Szeredi <mszeredi@redhat.com>
      caf70cb2