📄 dlmfs.c
字号:
/* -*- mode: c; c-basic-offset: 8; -*- * vim: noexpandtab sw=8 ts=8 sts=0: * * dlmfs.c * * Code which implements the kernel side of a minimal userspace * interface to our DLM. This file handles the virtual file system * used for communication with userspace. Credit should go to ramfs, * which was a template for the fs side of this module. * * Copyright (C) 2003, 2004 Oracle. All rights reserved. * * This program 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, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 021110-1307, USA. *//* Simple VFS hooks based on: *//* * Resizable simple ram filesystem for Linux. * * Copyright (C) 2000 Linus Torvalds. * 2000 Transmeta Corp. */#include <linux/module.h>#include <linux/fs.h>#include <linux/pagemap.h>#include <linux/types.h>#include <linux/slab.h>#include <linux/highmem.h>#include <linux/init.h>#include <linux/string.h>#include <linux/smp_lock.h>#include <linux/backing-dev.h>#include <asm/uaccess.h>#include "cluster/nodemanager.h"#include "cluster/heartbeat.h"#include "cluster/tcp.h"#include "dlmapi.h"#include "userdlm.h"#include "dlmfsver.h"#define MLOG_MASK_PREFIX ML_DLMFS#include "cluster/masklog.h"static struct super_operations dlmfs_ops;static struct file_operations dlmfs_file_operations;static struct inode_operations dlmfs_dir_inode_operations;static struct inode_operations dlmfs_root_inode_operations;static struct inode_operations dlmfs_file_inode_operations;static kmem_cache_t *dlmfs_inode_cache;struct workqueue_struct *user_dlm_worker;/* * decodes a set of open flags into a valid lock level and a set of flags. * returns < 0 if we have invalid flags * flags which mean something to us: * O_RDONLY -> PRMODE level * O_WRONLY -> EXMODE level * * O_NONBLOCK -> LKM_NOQUEUE */static int dlmfs_decode_open_flags(int open_flags, int *level, int *flags){ if (open_flags & (O_WRONLY|O_RDWR)) *level = LKM_EXMODE; else *level = LKM_PRMODE; *flags = 0; if (open_flags & O_NONBLOCK) *flags |= LKM_NOQUEUE; return 0;}static int dlmfs_file_open(struct inode *inode, struct file *file){ int status, level, flags; struct dlmfs_filp_private *fp = NULL; struct dlmfs_inode_private *ip; if (S_ISDIR(inode->i_mode)) BUG(); mlog(0, "open called on inode %lu, flags 0x%x\n", inode->i_ino, file->f_flags); status = dlmfs_decode_open_flags(file->f_flags, &level, &flags); if (status < 0) goto bail; /* We don't want to honor O_APPEND at read/write time as it * doesn't make sense for LVB writes. */ file->f_flags &= ~O_APPEND; fp = kmalloc(sizeof(*fp), GFP_NOFS); if (!fp) { status = -ENOMEM; goto bail; } fp->fp_lock_level = level; ip = DLMFS_I(inode); status = user_dlm_cluster_lock(&ip->ip_lockres, level, flags); if (status < 0) { /* this is a strange error to return here but I want * to be able userspace to be able to distinguish a * valid lock request from one that simply couldn't be * granted. */ if (flags & LKM_NOQUEUE && status == -EAGAIN) status = -ETXTBSY; kfree(fp); goto bail; } file->private_data = fp;bail: return status;}static int dlmfs_file_release(struct inode *inode, struct file *file){ int level, status; struct dlmfs_inode_private *ip = DLMFS_I(inode); struct dlmfs_filp_private *fp = (struct dlmfs_filp_private *) file->private_data; if (S_ISDIR(inode->i_mode)) BUG(); mlog(0, "close called on inode %lu\n", inode->i_ino); status = 0; if (fp) { level = fp->fp_lock_level; if (level != LKM_IVMODE) user_dlm_cluster_unlock(&ip->ip_lockres, level); kfree(fp); file->private_data = NULL; } return 0;}static ssize_t dlmfs_file_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos){ int bytes_left; ssize_t readlen; char *lvb_buf; struct inode *inode = filp->f_dentry->d_inode; mlog(0, "inode %lu, count = %zu, *ppos = %llu\n", inode->i_ino, count, *ppos); if (*ppos >= i_size_read(inode)) return 0; if (!count) return 0; if (!access_ok(VERIFY_WRITE, buf, count)) return -EFAULT; /* don't read past the lvb */ if ((count + *ppos) > i_size_read(inode)) readlen = i_size_read(inode) - *ppos; else readlen = count - *ppos; lvb_buf = kmalloc(readlen, GFP_NOFS); if (!lvb_buf) return -ENOMEM; user_dlm_read_lvb(inode, lvb_buf, readlen); bytes_left = __copy_to_user(buf, lvb_buf, readlen); readlen -= bytes_left; kfree(lvb_buf); *ppos = *ppos + readlen; mlog(0, "read %zd bytes\n", readlen); return readlen;}static ssize_t dlmfs_file_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos){ int bytes_left; ssize_t writelen; char *lvb_buf; struct inode *inode = filp->f_dentry->d_inode; mlog(0, "inode %lu, count = %zu, *ppos = %llu\n", inode->i_ino, count, *ppos); if (*ppos >= i_size_read(inode)) return -ENOSPC; if (!count) return 0; if (!access_ok(VERIFY_READ, buf, count)) return -EFAULT; /* don't write past the lvb */ if ((count + *ppos) > i_size_read(inode)) writelen = i_size_read(inode) - *ppos; else writelen = count - *ppos; lvb_buf = kmalloc(writelen, GFP_NOFS); if (!lvb_buf) return -ENOMEM; bytes_left = copy_from_user(lvb_buf, buf, writelen); writelen -= bytes_left; if (writelen) user_dlm_write_lvb(inode, lvb_buf, writelen); kfree(lvb_buf); *ppos = *ppos + writelen; mlog(0, "wrote %zd bytes\n", writelen); return writelen;}static void dlmfs_init_once(void *foo, kmem_cache_t *cachep, unsigned long flags){ struct dlmfs_inode_private *ip = (struct dlmfs_inode_private *) foo; if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR) { ip->ip_dlm = NULL; ip->ip_parent = NULL; inode_init_once(&ip->ip_vfs_inode); }}static struct inode *dlmfs_alloc_inode(struct super_block *sb){ struct dlmfs_inode_private *ip; ip = kmem_cache_alloc(dlmfs_inode_cache, SLAB_NOFS); if (!ip) return NULL; return &ip->ip_vfs_inode;}static void dlmfs_destroy_inode(struct inode *inode){ kmem_cache_free(dlmfs_inode_cache, DLMFS_I(inode));}static void dlmfs_clear_inode(struct inode *inode){ int status; struct dlmfs_inode_private *ip; if (!inode) return; mlog(0, "inode %lu\n", inode->i_ino); ip = DLMFS_I(inode); if (S_ISREG(inode->i_mode)) { status = user_dlm_destroy_lock(&ip->ip_lockres); if (status < 0) mlog_errno(status); iput(ip->ip_parent); goto clear_fields; } mlog(0, "we're a directory, ip->ip_dlm = 0x%p\n", ip->ip_dlm); /* we must be a directory. If required, lets unregister the * dlm context now. */ if (ip->ip_dlm) user_dlm_unregister_context(ip->ip_dlm);clear_fields: ip->ip_parent = NULL; ip->ip_dlm = NULL;}static struct backing_dev_info dlmfs_backing_dev_info = { .ra_pages = 0, /* No readahead */#ifdef BACKING_DEV_CAPABILITIES .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK,#else .memory_backed = 1, /* Does not contribute to dirty memory */#endif};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -