* Copyright (c) 1998-2022 Erez Zadok
* Copyright (c) 2009 Shrikar Archak
* Copyright (c) 2003-2022 Stony Brook University
* Copyright (c) 2003-2022 The Research Foundation of SUNY
*/
#include <linux/backing-dev-defs.h>
#include <linux/ratelimit.h>
#include <linux/slab.h>
#include <linux/parser.h>
#include "sharefs.h"
enum {
OPT_USER_ID,
OPT_OVERRIDE,
OPT_OVERRIDE_SUPPORT_DELETE,
OPT_ERR,
};
static match_table_t sharefs_tokens = {
{ OPT_USER_ID, "user_id=%s" },
{ OPT_OVERRIDE, "override" },
{ OPT_OVERRIDE_SUPPORT_DELETE, "override_support_delete" },
{ OPT_ERR, NULL }
};
int sharefs_parse_options(struct sharefs_sb_info *sbi, const char *data)
{
char *p = NULL;
char *name = NULL;
char *options = NULL;
char *options_src = NULL;
substring_t args[MAX_OPT_ARGS];
unsigned int user_id = 0;
int err = 0;
options = kstrdup(data, GFP_KERNEL);
if (data && !options) {
err = -ENOMEM;
goto out;
}
options_src = options;
while ((p = strsep(&options_src, ",")) != NULL) {
int token;
if (!*p)
continue;
args[0].to = args[0].from = NULL;
token = match_token(p, sharefs_tokens, args);
switch (token) {
case OPT_USER_ID:
name = match_strdup(&args[0]);
if (name) {
err = kstrtouint(name, 10, &user_id);
kfree(name);
name = NULL;
if (err)
goto out;
sbi->user_id = user_id;
}
break;
case OPT_OVERRIDE:
sbi->override = true;
break;
case OPT_OVERRIDE_SUPPORT_DELETE:
sbi->override_support_delete = true;
break;
default:
err = -EINVAL;
goto out;
}
}
out:
kfree(options);
return err;
}
* The inode cache is used with alloc_inode for both our inode info and the
* vfs inode.
*/
static struct kmem_cache *sharefs_inode_cachep;
static void sharefs_put_super(struct super_block *sb)
{
struct sharefs_sb_info *spd;
struct super_block *s;
spd = SHAREFS_SB(sb);
if (!spd)
return;
s = sharefs_lower_super(sb);
sharefs_set_lower_super(sb, NULL);
atomic_dec(&s->s_active);
kfree(spd);
sb->s_fs_info = NULL;
}
static int sharefs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
int err;
struct path lower_path;
sharefs_get_lower_path(dentry, &lower_path);
err = vfs_statfs(&lower_path, buf);
sharefs_put_lower_path(dentry, &lower_path);
buf->f_type = SHAREFS_SUPER_MAGIC;
return err;
}
* Called by iput() when the inode reference count reached zero
* and the inode is not hashed anywhere. Used to clear anything
* that needs to be, before the inode is completely destroyed and put
* on the inode free list.
*/
static void sharefs_evict_inode(struct inode *inode)
{
struct inode *lower_inode;
truncate_inode_pages(&inode->i_data, 0);
clear_inode(inode);
* Decrement a reference to a lower_inode, which was incremented
* by our read_inode when it was created initially.
*/
lower_inode = sharefs_lower_inode(inode);
sharefs_set_lower_inode(inode, NULL);
iput(lower_inode);
}
void __sharefs_log(const char *level, const bool ratelimited,
const char *function, const char *fmt, ...)
{
struct va_format vaf;
va_list args;
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
if (ratelimited)
printk_ratelimited("%s sharefs: %s() %pV\n", level,
function, &vaf);
else
printk("%s sharefs: %s() %pV\n", level, function, &vaf);
va_end(args);
}
static struct inode *sharefs_alloc_inode(struct super_block *sb)
{
struct sharefs_inode_info *i;
i = kmem_cache_alloc(sharefs_inode_cachep, GFP_KERNEL);
if (!i)
return NULL;
memset(i, 0, offsetof(struct sharefs_inode_info, vfs_inode));
atomic64_set(&i->vfs_inode.i_version, 1);
return &i->vfs_inode;
}
static void sharefs_destroy_inode(struct inode *inode)
{
kmem_cache_free(sharefs_inode_cachep, SHAREFS_I(inode));
}
static void init_once(void *obj)
{
struct sharefs_inode_info *i = obj;
inode_init_once(&i->vfs_inode);
}
int sharefs_init_inode_cache(void)
{
int err = 0;
sharefs_inode_cachep =
kmem_cache_create("sharefs_inode_cache",
sizeof(struct sharefs_inode_info), 0,
SLAB_RECLAIM_ACCOUNT, init_once);
if (!sharefs_inode_cachep)
err = -ENOMEM;
return err;
}
void sharefs_destroy_inode_cache(void)
{
if (sharefs_inode_cachep)
kmem_cache_destroy(sharefs_inode_cachep);
}
const struct super_operations sharefs_sops = {
.put_super = sharefs_put_super,
.statfs = sharefs_statfs,
.evict_inode = sharefs_evict_inode,
.alloc_inode = sharefs_alloc_inode,
.destroy_inode = sharefs_destroy_inode,
};