linux_dsm_epyc7002/fs/aufs/loop.c
AuxXxilium 5fa3ea047a init: add dsm gpl source
Signed-off-by: AuxXxilium <info@auxxxilium.tech>
2024-07-05 18:00:04 +02:00

149 lines
3.6 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2005-2019 Junjiro R. Okajima
*
* This program, aufs is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
* support for loopback block device as a branch
*/
#include "aufs.h"
/* added into drivers/block/loop.c */
static struct file *(*backing_file_func)(struct super_block *sb);
/*
* test if two lower dentries have overlapping branches.
*/
int au_test_loopback_overlap(struct super_block *sb, struct dentry *h_adding)
{
struct super_block *h_sb;
struct file *backing_file;
if (unlikely(!backing_file_func)) {
/* don't load "loop" module here */
backing_file_func = symbol_get(loop_backing_file);
if (unlikely(!backing_file_func))
/* "loop" module is not loaded */
return 0;
}
h_sb = h_adding->d_sb;
backing_file = backing_file_func(h_sb);
if (!backing_file)
return 0;
h_adding = backing_file->f_path.dentry;
/*
* h_adding can be local NFS.
* in this case aufs cannot detect the loop.
*/
if (unlikely(h_adding->d_sb == sb))
return 1;
return !!au_test_subdir(h_adding, sb->s_root);
}
/* true if a kernel thread named 'loop[0-9].*' accesses a file */
int au_test_loopback_kthread(void)
{
int ret;
struct task_struct *tsk = current;
char c, comm[sizeof(tsk->comm)];
ret = 0;
if (tsk->flags & PF_KTHREAD) {
get_task_comm(comm, tsk);
c = comm[4];
ret = ('0' <= c && c <= '9'
&& !strncmp(comm, "loop", 4));
}
return ret;
}
/* ---------------------------------------------------------------------- */
#define au_warn_loopback_step 16
static int au_warn_loopback_nelem = au_warn_loopback_step;
static unsigned long *au_warn_loopback_array;
void au_warn_loopback(struct super_block *h_sb)
{
int i, new_nelem;
unsigned long *a, magic;
static DEFINE_SPINLOCK(spin);
magic = h_sb->s_magic;
spin_lock(&spin);
a = au_warn_loopback_array;
for (i = 0; i < au_warn_loopback_nelem && *a; i++)
if (a[i] == magic) {
spin_unlock(&spin);
return;
}
/* h_sb is new to us, print it */
if (i < au_warn_loopback_nelem) {
a[i] = magic;
goto pr;
}
/* expand the array */
new_nelem = au_warn_loopback_nelem + au_warn_loopback_step;
a = au_kzrealloc(au_warn_loopback_array,
au_warn_loopback_nelem * sizeof(unsigned long),
new_nelem * sizeof(unsigned long), GFP_ATOMIC,
/*may_shrink*/0);
if (a) {
au_warn_loopback_nelem = new_nelem;
au_warn_loopback_array = a;
a[i] = magic;
goto pr;
}
spin_unlock(&spin);
AuWarn1("realloc failed, ignored\n");
return;
pr:
spin_unlock(&spin);
pr_warn("you may want to try another patch for loopback file "
"on %s(0x%lx) branch\n", au_sbtype(h_sb), magic);
}
int au_loopback_init(void)
{
int err;
struct super_block *sb __maybe_unused;
BUILD_BUG_ON(sizeof(sb->s_magic) != sizeof(*au_warn_loopback_array));
err = 0;
au_warn_loopback_array = kcalloc(au_warn_loopback_step,
sizeof(unsigned long), GFP_NOFS);
if (unlikely(!au_warn_loopback_array))
err = -ENOMEM;
return err;
}
void au_loopback_fin(void)
{
if (backing_file_func)
symbol_put(loop_backing_file);
au_kfree_try_rcu(au_warn_loopback_array);
}