OpenCloudOS-Kernel/kernel/tkernel/shield_mounts.c

244 lines
4.9 KiB
C

#include <linux/tkernel.h>
#include <linux/seq_file.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/bitops.h>
#include <linux/shield_mounts.h>
#define SHIELD_PATH_MAX 1024
struct mount_pair {
struct list_head list;
char dev_name[SHIELD_PATH_MAX];
char mnt_path[SHIELD_PATH_MAX];
};
static DEFINE_RWLOCK(shield_mounts_lock);
static LIST_HEAD(shield_mounts_list);
static unsigned int shield_mounts_count;
unsigned int sysctl_shield_mounts_max = 512;
bool is_mount_shielded(const char *dev_path, const char *mount_path)
{
bool ret = false;
struct mount_pair *p;
read_lock(&shield_mounts_lock);
list_for_each_entry(p, &shield_mounts_list, list) {
if (!strcmp(p->dev_name, dev_path) &&
!strcmp(p->mnt_path, mount_path)) {
ret = true;
break;
}
}
read_unlock(&shield_mounts_lock);
return ret;
}
static int shield_mounts_search_and_insert(struct mount_pair *item)
{
int ret = -EEXIST;
struct mount_pair *p;
write_lock(&shield_mounts_lock);
list_for_each_entry(p, &shield_mounts_list, list) {
if (!strcmp(p->dev_name, item->dev_name) &&
!strcmp(p->mnt_path, item->mnt_path))
goto unlock;
}
if (shield_mounts_count >= sysctl_shield_mounts_max) {
ret = -ENOMEM;
goto unlock;
}
list_add_tail(&item->list, &shield_mounts_list);
shield_mounts_count++;
ret = 0;
unlock:
write_unlock(&shield_mounts_lock);
return ret;
}
static int shield_mounts_search_and_del(struct mount_pair *item)
{
struct mount_pair *p;
write_lock(&shield_mounts_lock);
list_for_each_entry(p, &shield_mounts_list, list) {
if (!strcmp(p->dev_name, item->dev_name) &&
!strcmp(p->mnt_path, item->mnt_path)) {
list_del(&p->list);
kfree(p);
shield_mounts_count--;
goto unlock;
}
}
unlock:
write_unlock(&shield_mounts_lock);
return 0;
}
/*helper function*/
static void str_escape(char *s, const char *esc)
{
char *p = s;
while (p && *p != '\0') {
char c = *p++;
while (c != '\0' && strchr(esc, c))
c = *p++;
*s++ = c;
}
*s = '\0';
}
/*
* parse buffer to get shield mount info
* "set devpath mountpoint": means to add a new shield mount info
* "clear devpath mountpoint": means to delete an exist one
* */
static int shield_mounts_parse(char *buf, bool *is_set, struct mount_pair *item)
{
char *token;
str_escape(buf, "\t\n");
buf = skip_spaces(buf);
token = strsep(&buf, " ");
if (!token || !*token || !buf)
goto error;
if (!strcmp(token, "set")) {
/* set */
*is_set = true;
} else if (!strcmp(token, "clear")) {
/* clear */
*is_set = false;
} else {
printk(KERN_ERR"set parse error\n");
goto error;
}
buf = skip_spaces(buf);
/* dev path */
token = strsep(&buf, " ");
if (!buf || !token || !*token || strlen(token) > (PATH_MAX-1)) {
printk(KERN_ERR"dev path faild\n");
goto error;
}
memcpy(item->dev_name, token, strlen(token)+1);
/* mnt */
buf = strim(buf);
memcpy(item->mnt_path, buf, strlen(buf)+1);
return 0;
error:
printk(KERN_ERR"Failed to parse shield mounts pair\n");
return -EFAULT;
}
static int shield_mounts_proc_show(struct seq_file *m, void *v)
{
struct mount_pair *p;
read_lock(&shield_mounts_lock);
list_for_each_entry(p, &shield_mounts_list, list) {
seq_printf(m, "%s on %s\n", p->dev_name, p->mnt_path);
}
read_unlock(&shield_mounts_lock);
return 0;
}
static int shield_mounts_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, shield_mounts_proc_show, NULL);
}
static ssize_t shield_mounts_proc_write(struct file *file, const char __user *ubuf,
size_t cnt, loff_t *ppos)
{
char *buffer = NULL;
int ret = cnt;
int order = 1;
bool is_set;
struct mount_pair *item;
/*max file lens for 8k*/
if (!ubuf || cnt > PAGE_SIZE * (1 << order))
return -EINVAL;
buffer = (char *)__get_free_pages(GFP_KERNEL, order);
if (!buffer)
return -ENOMEM;
if (copy_from_user(buffer, ubuf, cnt)) {
ret = -EFAULT;
goto out;
}
buffer[cnt] = 0;
item = kmalloc(sizeof(struct mount_pair), GFP_KERNEL);
if (!item){
printk(KERN_ERR"Failed to malloc mount_pair\n");
ret = -ENOMEM;
goto out;
}
/*parse buffer*/
ret = shield_mounts_parse(buffer, &is_set, item);
if (ret)
goto out1;
if(is_set) {
/*set */
ret = shield_mounts_search_and_insert(item);
if (!ret)
item = NULL;
} else {
/* clear */
ret = shield_mounts_search_and_del(item);
}
if (!ret)
ret = cnt;
out1:
kfree(item);
out:
free_pages((unsigned long) buffer, order);
return ret;
}
int shield_mounts_release(struct inode *inode, struct file *file)
{
return single_release(inode, file);
}
static const struct file_operations shield_mounts_proc_fops = {
.open = shield_mounts_proc_open,
.read = seq_read,
.write = shield_mounts_proc_write,
.llseek = seq_lseek,
.release = shield_mounts_release,
};
static int __init proc_shield_mounts_init(void)
{
proc_create("shield_mounts", 0, proc_tkernel, &shield_mounts_proc_fops);
return 0;
}
late_initcall(proc_shield_mounts_init);