Skip to content

Commit

Permalink
ovl: factor out ovl_map_dev_ino() helper
Browse files Browse the repository at this point in the history
A helper for ovl_getattr() to map the values of st_dev and st_ino
according to constant st_ino rules.

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
  • Loading branch information
Amir Goldstein authored and Miklos Szeredi committed Apr 12, 2018
1 parent 8f35cf5 commit da309e8
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 39 deletions.
88 changes: 49 additions & 39 deletions fs/overlayfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,6 @@
#include "overlayfs.h"


static dev_t ovl_get_pseudo_dev(struct dentry *dentry)
{
struct ovl_entry *oe = dentry->d_fsdata;

return oe->lowerstack[0].layer->pseudo_dev;
}

int ovl_setattr(struct dentry *dentry, struct iattr *attr)
{
int err;
Expand Down Expand Up @@ -66,6 +59,43 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr)
return err;
}

static int ovl_map_dev_ino(struct dentry *dentry, struct kstat *stat,
struct ovl_layer *lower_layer)
{
bool samefs = ovl_same_sb(dentry->d_sb);

if (samefs) {
/*
* When all layers are on the same fs, all real inode
* number are unique, so we use the overlay st_dev,
* which is friendly to du -x.
*/
stat->dev = dentry->d_sb->s_dev;
} else if (S_ISDIR(dentry->d_inode->i_mode)) {
/*
* Always use the overlay st_dev for directories, so 'find
* -xdev' will scan the entire overlay mount and won't cross the
* overlay mount boundaries.
*
* If not all layers are on the same fs the pair {real st_ino;
* overlay st_dev} is not unique, so use the non persistent
* overlay st_ino for directories.
*/
stat->dev = dentry->d_sb->s_dev;
stat->ino = dentry->d_inode->i_ino;
} else if (lower_layer) {
/*
* For non-samefs setup, if we cannot map all layers st_ino
* to a unified address space, we need to make sure that st_dev
* is unique per layer. Upper layer uses real st_dev and lower
* layers use the unique anonymous bdev.
*/
stat->dev = lower_layer->pseudo_dev;
}

return 0;
}

int ovl_getattr(const struct path *path, struct kstat *stat,
u32 request_mask, unsigned int flags)
{
Expand All @@ -75,6 +105,7 @@ int ovl_getattr(const struct path *path, struct kstat *stat,
const struct cred *old_cred;
bool is_dir = S_ISDIR(dentry->d_inode->i_mode);
bool samefs = ovl_same_sb(dentry->d_sb);
struct ovl_layer *lower_layer = NULL;
int err;

type = ovl_path_real(dentry, &realpath);
Expand All @@ -84,14 +115,16 @@ int ovl_getattr(const struct path *path, struct kstat *stat,
goto out;

/*
* For non-dir or same fs, we use st_ino of the copy up origin, if we
* know it. This guaranties constant st_dev/st_ino across copy up.
* For non-dir or same fs, we use st_ino of the copy up origin.
* This guaranties constant st_dev/st_ino across copy up.
*
* If filesystem supports NFS export ops, this also guaranties
* If lower filesystem supports NFS file handles, this also guaranties
* persistent st_ino across mount cycle.
*/
if (!is_dir || samefs) {
if (OVL_TYPE_ORIGIN(type)) {
if (!OVL_TYPE_UPPER(type)) {
lower_layer = ovl_layer_lower(dentry);
} else if (OVL_TYPE_ORIGIN(type)) {
struct kstat lowerstat;
u32 lowermask = STATX_INO | (!is_dir ? STATX_NLINK : 0);

Expand Down Expand Up @@ -120,38 +153,15 @@ int ovl_getattr(const struct path *path, struct kstat *stat,
(!ovl_verify_lower(dentry->d_sb) &&
(is_dir || lowerstat.nlink == 1))) {
stat->ino = lowerstat.ino;
stat->dev = ovl_get_pseudo_dev(dentry);
lower_layer = ovl_layer_lower(dentry);
}
}
if (samefs) {
/*
* When all layers are on the same fs, all real inode
* number are unique, so we use the overlay st_dev,
* which is friendly to du -x.
*/
stat->dev = dentry->d_sb->s_dev;
} else if (!OVL_TYPE_UPPER(type)) {
/*
* For non-samefs setup, to make sure that st_dev/st_ino
* pair is unique across the system, we use a unique
* anonymous st_dev for lower layer inode.
*/
stat->dev = ovl_get_pseudo_dev(dentry);
}
} else {
/*
* Always use the overlay st_dev for directories, so 'find
* -xdev' will scan the entire overlay mount and won't cross the
* overlay mount boundaries.
*
* If not all layers are on the same fs the pair {real st_ino;
* overlay st_dev} is not unique, so use the non persistent
* overlay st_ino for directories.
*/
stat->dev = dentry->d_sb->s_dev;
stat->ino = dentry->d_inode->i_ino;
}

err = ovl_map_dev_ino(dentry, stat, lower_layer);
if (err)
goto out;

/*
* It's probably not worth it to count subdirs to get the
* correct link count. nlink=1 seems to pacify 'find' and
Expand Down
1 change: 1 addition & 0 deletions fs/overlayfs/overlayfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ void ovl_path_lower(struct dentry *dentry, struct path *path);
enum ovl_path_type ovl_path_real(struct dentry *dentry, struct path *path);
struct dentry *ovl_dentry_upper(struct dentry *dentry);
struct dentry *ovl_dentry_lower(struct dentry *dentry);
struct ovl_layer *ovl_layer_lower(struct dentry *dentry);
struct dentry *ovl_dentry_real(struct dentry *dentry);
struct dentry *ovl_i_dentry_upper(struct inode *inode);
struct inode *ovl_inode_upper(struct inode *inode);
Expand Down
7 changes: 7 additions & 0 deletions fs/overlayfs/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,13 @@ struct dentry *ovl_dentry_lower(struct dentry *dentry)
return oe->numlower ? oe->lowerstack[0].dentry : NULL;
}

struct ovl_layer *ovl_layer_lower(struct dentry *dentry)
{
struct ovl_entry *oe = dentry->d_fsdata;

return oe->numlower ? oe->lowerstack[0].layer : NULL;
}

struct dentry *ovl_dentry_real(struct dentry *dentry)
{
return ovl_dentry_upper(dentry) ?: ovl_dentry_lower(dentry);
Expand Down

0 comments on commit da309e8

Please sign in to comment.