// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (C) 2011 Novell Inc.
* Copyright (C) 2016 Red Hat, Inc.
*/
#include <linux/fs.h>
#include <linux/mount.h>
#include <linux/slab.h>
#include <linux/cred.h>
#include <linux/xattr.h>
#include <linux/exportfs.h>
#include <linux/fileattr.h>
#include <linux/uuid.h>
#include <linux/namei.h>
#include <linux/ratelimit.h>
#include "overlayfs.h"
int ovl_want_write(struct dentry *dentry)
{
struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
return mnt_want_write(ovl_upper_mnt(ofs));
}
void ovl_drop_write(struct dentry *dentry)
{
struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
mnt_drop_write(ovl_upper_mnt(ofs));
}
struct dentry *ovl_workdir(struct dentry *dentry)
{
struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
return ofs->workdir;
}
const struct cred *ovl_override_creds(struct super_block *sb)
{
struct ovl_fs *ofs = sb->s_fs_info;
return override_creds(ofs->creator_cred);
}
/*
* Check if underlying fs supports file handles and try to determine encoding
* type, in order to deduce maximum inode number used by fs.
*
* Return 0 if file handles are not supported.
* Return 1 (FILEID_INO32_GEN) if fs uses the default 32bit inode encoding.
* Return -1 if fs uses a non default encoding with unknown inode size.
*/
int ovl_can_decode_fh(struct super_block *sb)
{
if (!capable(CAP_DAC_READ_SEARCH))
return 0;
if (!sb->s_export_op || !sb->s_export_op->fh_to_dentry)
return 0;
return sb->s_export_op->encode_fh ? -1 : FILEID_INO32_GEN;
}
struct dentry *ovl_indexdir(struct super_block *sb)
{
struct ovl_fs *ofs = sb->s_fs_info;
return ofs->indexdir;
}
/* Index all files on copy up. For now only enabled for NFS export */
bool ovl_index_all(struct super_block *sb)
{
struct ovl_fs *ofs = sb->s_fs_info;
return ofs->config.nfs_export && ofs->config.index;
}
/* Verify lower origin on lookup. For now only enabled for NFS export */
bool ovl_verify_lower(struct super_block *sb)
{
struct ovl_fs *ofs = sb->s_fs_info;
return ofs->config.nfs_export && ofs->config.index;
}
struct ovl_path *ovl_stack_alloc(unsigned int n)
{
return kcalloc(n, sizeof(struct ovl_path), GFP_KERNEL);
}
void ovl_stack_cpy(struct ovl_path *dst, struct ovl_path *src, unsigned int n)
{
unsigned int i;
memcpy(dst, src, sizeof(struct ovl_path) * n);
for (i = 0; i < n; i++)
dget(src[i].dentry);
}
void ovl_stack_put(struct ovl_path *stack, unsigned int n)
{
unsigned int i;
for (i = 0; stack && i < n; i++)
dput(stack[i].dentry);
}
void ovl_stack_free(struct ovl_path *stack, unsigned int n)
{
ovl_stack_put(stack, n);
kfree(stack);
}
struct ovl_entry *ovl_alloc_entry(unsigned int numlower)
{
size_t size = offsetof(struct ovl_entry, __lowerstack[numlower]);
struct ovl_entry *oe = kzalloc(size, GFP_KERNEL);
if (oe)
oe->__numlower = numlower;
return oe;
}
void ovl_free_entry(struct ovl_entry *oe)
{
ovl_stack_put(ovl_lowerstack(oe), ovl_numlower(oe));
kfree(oe);
}
#define OVL_D_REVALIDATE (DCACHE_OP_REVALIDATE | DCACHE_OP_WEAK_REVALIDATE)
bool