Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/viro/vfs

Pull vfs fixes from Al Viro:
 "Assorted fixes, most in overlayfs land"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  ovl: ovl_dir_fsync() cleanup
  ovl: update MAINTAINERS
  ovl: pass dentry into ovl_dir_read_merged()
  ovl: use lockless_dereference() for upperdentry
  ovl: allow filenames with comma
  ovl: fix race in private xattr checks
  ovl: fix remove/copy-up race
  ovl: rename filesystem type to "overlay"
  isofs: avoid unused function warning
  vfs: fix reference leak in d_prune_aliases()
  • Loading branch information
Linus Torvalds committed Nov 22, 2014
2 parents 8a84e01 + 3035b67 commit ecde006
Show file tree
Hide file tree
Showing 11 changed files with 133 additions and 85 deletions.
2 changes: 1 addition & 1 deletion Documentation/filesystems/overlayfs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ is formed.
At mount time, the two directories given as mount options "lowerdir" and
"upperdir" are combined into a merged directory:

mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper,\
mount -t overlay overlay -olowerdir=/lower,upperdir=/upper,\
workdir=/work /merged

The "workdir" needs to be an empty directory on the same filesystem
Expand Down
7 changes: 4 additions & 3 deletions MAINTAINERS
Original file line number Diff line number Diff line change
Expand Up @@ -6888,11 +6888,12 @@ F: drivers/scsi/osd/
F: include/scsi/osd_*
F: fs/exofs/

OVERLAYFS FILESYSTEM
OVERLAY FILESYSTEM
M: Miklos Szeredi <miklos@szeredi.hu>
L: linux-fsdevel@vger.kernel.org
L: linux-unionfs@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs.git
S: Supported
F: fs/overlayfs/*
F: fs/overlayfs/
F: Documentation/filesystems/overlayfs.txt

P54 WIRELESS DRIVER
Expand Down
2 changes: 1 addition & 1 deletion fs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ obj-$(CONFIG_QNX6FS_FS) += qnx6/
obj-$(CONFIG_AUTOFS4_FS) += autofs4/
obj-$(CONFIG_ADFS_FS) += adfs/
obj-$(CONFIG_FUSE_FS) += fuse/
obj-$(CONFIG_OVERLAYFS_FS) += overlayfs/
obj-$(CONFIG_OVERLAY_FS) += overlayfs/
obj-$(CONFIG_UDF_FS) += udf/
obj-$(CONFIG_SUN_OPENPROMFS) += openpromfs/
obj-$(CONFIG_OMFS_FS) += omfs/
Expand Down
1 change: 1 addition & 0 deletions fs/dcache.c
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,7 @@ void d_prune_aliases(struct inode *inode)
struct dentry *parent = lock_parent(dentry);
if (likely(!dentry->d_lockref.count)) {
__dentry_kill(dentry);
dput(parent);
goto restart;
}
if (parent)
Expand Down
42 changes: 21 additions & 21 deletions fs/isofs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -170,27 +170,6 @@ struct iso9660_options{
s32 sbsector;
};

/*
* Compute the hash for the isofs name corresponding to the dentry.
*/
static int
isofs_hash_common(struct qstr *qstr, int ms)
{
const char *name;
int len;

len = qstr->len;
name = qstr->name;
if (ms) {
while (len && name[len-1] == '.')
len--;
}

qstr->hash = full_name_hash(name, len);

return 0;
}

/*
* Compute the hash for the isofs name corresponding to the dentry.
*/
Expand Down Expand Up @@ -263,6 +242,27 @@ isofs_dentry_cmpi(const struct dentry *parent, const struct dentry *dentry,
}

#ifdef CONFIG_JOLIET
/*
* Compute the hash for the isofs name corresponding to the dentry.
*/
static int
isofs_hash_common(struct qstr *qstr, int ms)
{
const char *name;
int len;

len = qstr->len;
name = qstr->name;
if (ms) {
while (len && name[len-1] == '.')
len--;
}

qstr->hash = full_name_hash(name, len);

return 0;
}

static int
isofs_hash_ms(const struct dentry *dentry, struct qstr *qstr)
{
Expand Down
2 changes: 1 addition & 1 deletion fs/overlayfs/Kconfig
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
config OVERLAYFS_FS
config OVERLAY_FS
tristate "Overlay filesystem support"
help
An overlay filesystem combines two filesystems - an 'upper' filesystem
Expand Down
4 changes: 2 additions & 2 deletions fs/overlayfs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@
# Makefile for the overlay filesystem.
#

obj-$(CONFIG_OVERLAYFS_FS) += overlayfs.o
obj-$(CONFIG_OVERLAY_FS) += overlay.o

overlayfs-objs := super.o inode.o dir.o readdir.o copy_up.o
overlay-objs := super.o inode.o dir.o readdir.o copy_up.o
31 changes: 19 additions & 12 deletions fs/overlayfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -284,8 +284,7 @@ static struct dentry *ovl_clear_empty(struct dentry *dentry,
return ERR_PTR(err);
}

static struct dentry *ovl_check_empty_and_clear(struct dentry *dentry,
enum ovl_path_type type)
static struct dentry *ovl_check_empty_and_clear(struct dentry *dentry)
{
int err;
struct dentry *ret = NULL;
Expand All @@ -294,8 +293,17 @@ static struct dentry *ovl_check_empty_and_clear(struct dentry *dentry,
err = ovl_check_empty_dir(dentry, &list);
if (err)
ret = ERR_PTR(err);
else if (type == OVL_PATH_MERGE)
ret = ovl_clear_empty(dentry, &list);
else {
/*
* If no upperdentry then skip clearing whiteouts.
*
* Can race with copy-up, since we don't hold the upperdir
* mutex. Doesn't matter, since copy-up can't create a
* non-empty directory from an empty one.
*/
if (ovl_dentry_upper(dentry))
ret = ovl_clear_empty(dentry, &list);
}

ovl_cache_free(&list);

Expand Down Expand Up @@ -487,8 +495,7 @@ static int ovl_link(struct dentry *old, struct inode *newdir,
return err;
}

static int ovl_remove_and_whiteout(struct dentry *dentry,
enum ovl_path_type type, bool is_dir)
static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir)
{
struct dentry *workdir = ovl_workdir(dentry);
struct inode *wdir = workdir->d_inode;
Expand All @@ -500,7 +507,7 @@ static int ovl_remove_and_whiteout(struct dentry *dentry,
int err;

if (is_dir) {
opaquedir = ovl_check_empty_and_clear(dentry, type);
opaquedir = ovl_check_empty_and_clear(dentry);
err = PTR_ERR(opaquedir);
if (IS_ERR(opaquedir))
goto out;
Expand All @@ -515,9 +522,10 @@ static int ovl_remove_and_whiteout(struct dentry *dentry,
if (IS_ERR(whiteout))
goto out_unlock;

if (type == OVL_PATH_LOWER) {
upper = ovl_dentry_upper(dentry);
if (!upper) {
upper = lookup_one_len(dentry->d_name.name, upperdir,
dentry->d_name.len);
dentry->d_name.len);
err = PTR_ERR(upper);
if (IS_ERR(upper))
goto kill_whiteout;
Expand All @@ -529,7 +537,6 @@ static int ovl_remove_and_whiteout(struct dentry *dentry,
} else {
int flags = 0;

upper = ovl_dentry_upper(dentry);
if (opaquedir)
upper = opaquedir;
err = -ESTALE;
Expand Down Expand Up @@ -648,7 +655,7 @@ static int ovl_do_remove(struct dentry *dentry, bool is_dir)
cap_raise(override_cred->cap_effective, CAP_CHOWN);
old_cred = override_creds(override_cred);

err = ovl_remove_and_whiteout(dentry, type, is_dir);
err = ovl_remove_and_whiteout(dentry, is_dir);

revert_creds(old_cred);
put_cred(override_cred);
Expand Down Expand Up @@ -781,7 +788,7 @@ static int ovl_rename2(struct inode *olddir, struct dentry *old,
}

if (overwrite && (new_type == OVL_PATH_LOWER || new_type == OVL_PATH_MERGE) && new_is_dir) {
opaquedir = ovl_check_empty_and_clear(new, new_type);
opaquedir = ovl_check_empty_and_clear(new);
err = PTR_ERR(opaquedir);
if (IS_ERR(opaquedir)) {
opaquedir = NULL;
Expand Down
27 changes: 18 additions & 9 deletions fs/overlayfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -235,26 +235,36 @@ int ovl_setxattr(struct dentry *dentry, const char *name,
return err;
}

static bool ovl_need_xattr_filter(struct dentry *dentry,
enum ovl_path_type type)
{
return type == OVL_PATH_UPPER && S_ISDIR(dentry->d_inode->i_mode);
}

ssize_t ovl_getxattr(struct dentry *dentry, const char *name,
void *value, size_t size)
{
if (ovl_path_type(dentry->d_parent) == OVL_PATH_MERGE &&
ovl_is_private_xattr(name))
struct path realpath;
enum ovl_path_type type = ovl_path_real(dentry, &realpath);

if (ovl_need_xattr_filter(dentry, type) && ovl_is_private_xattr(name))
return -ENODATA;

return vfs_getxattr(ovl_dentry_real(dentry), name, value, size);
return vfs_getxattr(realpath.dentry, name, value, size);
}

ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size)
{
struct path realpath;
enum ovl_path_type type = ovl_path_real(dentry, &realpath);
ssize_t res;
int off;

res = vfs_listxattr(ovl_dentry_real(dentry), list, size);
res = vfs_listxattr(realpath.dentry, list, size);
if (res <= 0 || size == 0)
return res;

if (ovl_path_type(dentry->d_parent) != OVL_PATH_MERGE)
if (!ovl_need_xattr_filter(dentry, type))
return res;

/* filter out private xattrs */
Expand All @@ -279,17 +289,16 @@ int ovl_removexattr(struct dentry *dentry, const char *name)
{
int err;
struct path realpath;
enum ovl_path_type type;
enum ovl_path_type type = ovl_path_real(dentry, &realpath);

err = ovl_want_write(dentry);
if (err)
goto out;

if (ovl_path_type(dentry->d_parent) == OVL_PATH_MERGE &&
ovl_is_private_xattr(name))
err = -ENODATA;
if (ovl_need_xattr_filter(dentry, type) && ovl_is_private_xattr(name))
goto out_drop_write;

type = ovl_path_real(dentry, &realpath);
if (type == OVL_PATH_LOWER) {
err = vfs_getxattr(realpath.dentry, name, NULL, 0);
if (err < 0)
Expand Down
39 changes: 16 additions & 23 deletions fs/overlayfs/readdir.c
Original file line number Diff line number Diff line change
Expand Up @@ -274,37 +274,40 @@ static int ovl_dir_mark_whiteouts(struct dentry *dir,
return 0;
}

static inline int ovl_dir_read_merged(struct path *upperpath,
struct path *lowerpath,
struct list_head *list)
static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list)
{
int err;
struct path lowerpath;
struct path upperpath;
struct ovl_readdir_data rdd = {
.ctx.actor = ovl_fill_merge,
.list = list,
.root = RB_ROOT,
.is_merge = false,
};

if (upperpath->dentry) {
err = ovl_dir_read(upperpath, &rdd);
ovl_path_lower(dentry, &lowerpath);
ovl_path_upper(dentry, &upperpath);

if (upperpath.dentry) {
err = ovl_dir_read(&upperpath, &rdd);
if (err)
goto out;

if (lowerpath->dentry) {
err = ovl_dir_mark_whiteouts(upperpath->dentry, &rdd);
if (lowerpath.dentry) {
err = ovl_dir_mark_whiteouts(upperpath.dentry, &rdd);
if (err)
goto out;
}
}
if (lowerpath->dentry) {
if (lowerpath.dentry) {
/*
* Insert lowerpath entries before upperpath ones, this allows
* offsets to be reasonably constant
*/
list_add(&rdd.middle, rdd.list);
rdd.is_merge = true;
err = ovl_dir_read(lowerpath, &rdd);
err = ovl_dir_read(&lowerpath, &rdd);
list_del(&rdd.middle);
}
out:
Expand All @@ -329,8 +332,6 @@ static void ovl_seek_cursor(struct ovl_dir_file *od, loff_t pos)
static struct ovl_dir_cache *ovl_cache_get(struct dentry *dentry)
{
int res;
struct path lowerpath;
struct path upperpath;
struct ovl_dir_cache *cache;

cache = ovl_dir_cache(dentry);
Expand All @@ -347,10 +348,7 @@ static struct ovl_dir_cache *ovl_cache_get(struct dentry *dentry)
cache->refcount = 1;
INIT_LIST_HEAD(&cache->entries);

ovl_path_lower(dentry, &lowerpath);
ovl_path_upper(dentry, &upperpath);

res = ovl_dir_read_merged(&upperpath, &lowerpath, &cache->entries);
res = ovl_dir_read_merged(dentry, &cache->entries);
if (res) {
ovl_cache_free(&cache->entries);
kfree(cache);
Expand Down Expand Up @@ -452,10 +450,10 @@ static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end,
/*
* Need to check if we started out being a lower dir, but got copied up
*/
if (!od->is_upper && ovl_path_type(dentry) == OVL_PATH_MERGE) {
if (!od->is_upper && ovl_path_type(dentry) != OVL_PATH_LOWER) {
struct inode *inode = file_inode(file);

realfile =lockless_dereference(od->upperfile);
realfile = lockless_dereference(od->upperfile);
if (!realfile) {
struct path upperpath;

Expand Down Expand Up @@ -538,14 +536,9 @@ const struct file_operations ovl_dir_operations = {
int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list)
{
int err;
struct path lowerpath;
struct path upperpath;
struct ovl_cache_entry *p;

ovl_path_upper(dentry, &upperpath);
ovl_path_lower(dentry, &lowerpath);

err = ovl_dir_read_merged(&upperpath, &lowerpath, list);
err = ovl_dir_read_merged(dentry, list);
if (err)
return err;

Expand Down
Loading

0 comments on commit ecde006

Please sign in to comment.