📄 inode.c
字号:
switch (mode & S_IFMT) { default: init_special_inode(inode, mode, dev); break; case S_IFREG: inode->i_op = &hugetlbfs_inode_operations; inode->i_fop = &hugetlbfs_file_operations; break; case S_IFDIR: inode->i_op = &hugetlbfs_dir_inode_operations; inode->i_fop = &simple_dir_operations; /* directory inodes start off with i_nlink == 2 (for "." entry) */ inc_nlink(inode); break; case S_IFLNK: inode->i_op = &page_symlink_inode_operations; break; } } return inode;}/* * File creation. Allocate an inode, and we're done.. */static int hugetlbfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev){ struct inode *inode; int error = -ENOSPC; gid_t gid; if (dir->i_mode & S_ISGID) { gid = dir->i_gid; if (S_ISDIR(mode)) mode |= S_ISGID; } else { gid = current->fsgid; } inode = hugetlbfs_get_inode(dir->i_sb, current->fsuid, gid, mode, dev); if (inode) { dir->i_ctime = dir->i_mtime = CURRENT_TIME; d_instantiate(dentry, inode); dget(dentry); /* Extra count - pin the dentry in core */ error = 0; } return error;}static int hugetlbfs_mkdir(struct inode *dir, struct dentry *dentry, int mode){ int retval = hugetlbfs_mknod(dir, dentry, mode | S_IFDIR, 0); if (!retval) inc_nlink(dir); return retval;}static int hugetlbfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd){ return hugetlbfs_mknod(dir, dentry, mode | S_IFREG, 0);}static int hugetlbfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname){ struct inode *inode; int error = -ENOSPC; gid_t gid; if (dir->i_mode & S_ISGID) gid = dir->i_gid; else gid = current->fsgid; inode = hugetlbfs_get_inode(dir->i_sb, current->fsuid, gid, S_IFLNK|S_IRWXUGO, 0); if (inode) { int l = strlen(symname)+1; error = page_symlink(inode, symname, l); if (!error) { d_instantiate(dentry, inode); dget(dentry); } else iput(inode); } dir->i_ctime = dir->i_mtime = CURRENT_TIME; return error;}/* * mark the head page dirty */static int hugetlbfs_set_page_dirty(struct page *page){ struct page *head = compound_head(page); SetPageDirty(head); return 0;}static int hugetlbfs_statfs(struct dentry *dentry, struct kstatfs *buf){ struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(dentry->d_sb); buf->f_type = HUGETLBFS_MAGIC; buf->f_bsize = HPAGE_SIZE; if (sbinfo) { spin_lock(&sbinfo->stat_lock); /* If no limits set, just report 0 for max/free/used * blocks, like simple_statfs() */ if (sbinfo->max_blocks >= 0) { buf->f_blocks = sbinfo->max_blocks; buf->f_bavail = buf->f_bfree = sbinfo->free_blocks; buf->f_files = sbinfo->max_inodes; buf->f_ffree = sbinfo->free_inodes; } spin_unlock(&sbinfo->stat_lock); } buf->f_namelen = NAME_MAX; return 0;}static void hugetlbfs_put_super(struct super_block *sb){ struct hugetlbfs_sb_info *sbi = HUGETLBFS_SB(sb); if (sbi) { sb->s_fs_info = NULL; kfree(sbi); }}static inline int hugetlbfs_dec_free_inodes(struct hugetlbfs_sb_info *sbinfo){ if (sbinfo->free_inodes >= 0) { spin_lock(&sbinfo->stat_lock); if (unlikely(!sbinfo->free_inodes)) { spin_unlock(&sbinfo->stat_lock); return 0; } sbinfo->free_inodes--; spin_unlock(&sbinfo->stat_lock); } return 1;}static void hugetlbfs_inc_free_inodes(struct hugetlbfs_sb_info *sbinfo){ if (sbinfo->free_inodes >= 0) { spin_lock(&sbinfo->stat_lock); sbinfo->free_inodes++; spin_unlock(&sbinfo->stat_lock); }}static struct kmem_cache *hugetlbfs_inode_cachep;static struct inode *hugetlbfs_alloc_inode(struct super_block *sb){ struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(sb); struct hugetlbfs_inode_info *p; if (unlikely(!hugetlbfs_dec_free_inodes(sbinfo))) return NULL; p = kmem_cache_alloc(hugetlbfs_inode_cachep, GFP_KERNEL); if (unlikely(!p)) { hugetlbfs_inc_free_inodes(sbinfo); return NULL; } return &p->vfs_inode;}static void hugetlbfs_destroy_inode(struct inode *inode){ hugetlbfs_inc_free_inodes(HUGETLBFS_SB(inode->i_sb)); mpol_free_shared_policy(&HUGETLBFS_I(inode)->policy); kmem_cache_free(hugetlbfs_inode_cachep, HUGETLBFS_I(inode));}static const struct address_space_operations hugetlbfs_aops = { .readpage = hugetlbfs_readpage, .write_begin = hugetlbfs_write_begin, .write_end = hugetlbfs_write_end, .set_page_dirty = hugetlbfs_set_page_dirty,};static void init_once(struct kmem_cache *cachep, void *foo){ struct hugetlbfs_inode_info *ei = (struct hugetlbfs_inode_info *)foo; inode_init_once(&ei->vfs_inode);}const struct file_operations hugetlbfs_file_operations = { .read = hugetlbfs_read, .mmap = hugetlbfs_file_mmap, .fsync = simple_sync_file, .get_unmapped_area = hugetlb_get_unmapped_area,};static const struct inode_operations hugetlbfs_dir_inode_operations = { .create = hugetlbfs_create, .lookup = simple_lookup, .link = simple_link, .unlink = simple_unlink, .symlink = hugetlbfs_symlink, .mkdir = hugetlbfs_mkdir, .rmdir = simple_rmdir, .mknod = hugetlbfs_mknod, .rename = simple_rename, .setattr = hugetlbfs_setattr,};static const struct inode_operations hugetlbfs_inode_operations = { .setattr = hugetlbfs_setattr,};static const struct super_operations hugetlbfs_ops = { .alloc_inode = hugetlbfs_alloc_inode, .destroy_inode = hugetlbfs_destroy_inode, .statfs = hugetlbfs_statfs, .delete_inode = hugetlbfs_delete_inode, .drop_inode = hugetlbfs_drop_inode, .put_super = hugetlbfs_put_super,};static inthugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig){ char *p, *rest; substring_t args[MAX_OPT_ARGS]; int option; if (!options) return 0; while ((p = strsep(&options, ",")) != NULL) { int token; if (!*p) continue; token = match_token(p, tokens, args); switch (token) { case Opt_uid: if (match_int(&args[0], &option)) goto bad_val; pconfig->uid = option; break; case Opt_gid: if (match_int(&args[0], &option)) goto bad_val; pconfig->gid = option; break; case Opt_mode: if (match_octal(&args[0], &option)) goto bad_val; pconfig->mode = option & 0777U; break; case Opt_size: { unsigned long long size; /* memparse() will accept a K/M/G without a digit */ if (!isdigit(*args[0].from)) goto bad_val; size = memparse(args[0].from, &rest); if (*rest == '%') { size <<= HPAGE_SHIFT; size *= max_huge_pages; do_div(size, 100); } pconfig->nr_blocks = (size >> HPAGE_SHIFT); break; } case Opt_nr_inodes: /* memparse() will accept a K/M/G without a digit */ if (!isdigit(*args[0].from)) goto bad_val; pconfig->nr_inodes = memparse(args[0].from, &rest); break; default: printk(KERN_ERR "hugetlbfs: Bad mount option: \"%s\"\n", p); return -EINVAL; break; } } return 0;bad_val: printk(KERN_ERR "hugetlbfs: Bad value '%s' for mount option '%s'\n", args[0].from, p); return 1;}static inthugetlbfs_fill_super(struct super_block *sb, void *data, int silent){ struct inode * inode; struct dentry * root; int ret; struct hugetlbfs_config config; struct hugetlbfs_sb_info *sbinfo; config.nr_blocks = -1; /* No limit on size by default */ config.nr_inodes = -1; /* No limit on number of inodes by default */ config.uid = current->fsuid; config.gid = current->fsgid; config.mode = 0755; ret = hugetlbfs_parse_options(data, &config); if (ret) return ret; sbinfo = kmalloc(sizeof(struct hugetlbfs_sb_info), GFP_KERNEL); if (!sbinfo) return -ENOMEM; sb->s_fs_info = sbinfo; spin_lock_init(&sbinfo->stat_lock); sbinfo->max_blocks = config.nr_blocks; sbinfo->free_blocks = config.nr_blocks; sbinfo->max_inodes = config.nr_inodes; sbinfo->free_inodes = config.nr_inodes; sb->s_maxbytes = MAX_LFS_FILESIZE; sb->s_blocksize = HPAGE_SIZE; sb->s_blocksize_bits = HPAGE_SHIFT; sb->s_magic = HUGETLBFS_MAGIC; sb->s_op = &hugetlbfs_ops; sb->s_time_gran = 1; inode = hugetlbfs_get_inode(sb, config.uid, config.gid, S_IFDIR | config.mode, 0); if (!inode) goto out_free; root = d_alloc_root(inode); if (!root) { iput(inode); goto out_free; } sb->s_root = root; return 0;out_free: kfree(sbinfo); return -ENOMEM;}int hugetlb_get_quota(struct address_space *mapping, long delta){ int ret = 0; struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(mapping->host->i_sb); if (sbinfo->free_blocks > -1) { spin_lock(&sbinfo->stat_lock); if (sbinfo->free_blocks - delta >= 0) sbinfo->free_blocks -= delta; else ret = -ENOMEM; spin_unlock(&sbinfo->stat_lock); } return ret;}void hugetlb_put_quota(struct address_space *mapping, long delta){ struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(mapping->host->i_sb); if (sbinfo->free_blocks > -1) { spin_lock(&sbinfo->stat_lock); sbinfo->free_blocks += delta; spin_unlock(&sbinfo->stat_lock); }}static int hugetlbfs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *data, struct vfsmount *mnt){ return get_sb_nodev(fs_type, flags, data, hugetlbfs_fill_super, mnt);}static struct file_system_type hugetlbfs_fs_type = { .name = "hugetlbfs", .get_sb = hugetlbfs_get_sb, .kill_sb = kill_litter_super,};static struct vfsmount *hugetlbfs_vfsmount;static int can_do_hugetlb_shm(void){ return likely(capable(CAP_IPC_LOCK) || in_group_p(sysctl_hugetlb_shm_group) || can_do_mlock());}struct file *hugetlb_file_setup(const char *name, size_t size){ int error = -ENOMEM; struct file *file; struct inode *inode; struct dentry *dentry, *root; struct qstr quick_string; if (!hugetlbfs_vfsmount) return ERR_PTR(-ENOENT); if (!can_do_hugetlb_shm()) return ERR_PTR(-EPERM); if (!user_shm_lock(size, current->user)) return ERR_PTR(-ENOMEM); root = hugetlbfs_vfsmount->mnt_root; quick_string.name = name; quick_string.len = strlen(quick_string.name); quick_string.hash = 0; dentry = d_alloc(root, &quick_string); if (!dentry) goto out_shm_unlock; error = -ENOSPC; inode = hugetlbfs_get_inode(root->d_sb, current->fsuid, current->fsgid, S_IFREG | S_IRWXUGO, 0); if (!inode) goto out_dentry; error = -ENOMEM; if (hugetlb_reserve_pages(inode, 0, size >> HPAGE_SHIFT)) goto out_inode; d_instantiate(dentry, inode); inode->i_size = size; inode->i_nlink = 0; error = -ENFILE; file = alloc_file(hugetlbfs_vfsmount, dentry, FMODE_WRITE | FMODE_READ, &hugetlbfs_file_operations); if (!file) goto out_inode; return file;out_inode: iput(inode);out_dentry: dput(dentry);out_shm_unlock: user_shm_unlock(size, current->user); return ERR_PTR(error);}static int __init init_hugetlbfs_fs(void){ int error; struct vfsmount *vfsmount; error = bdi_init(&hugetlbfs_backing_dev_info); if (error) return error; hugetlbfs_inode_cachep = kmem_cache_create("hugetlbfs_inode_cache", sizeof(struct hugetlbfs_inode_info), 0, 0, init_once); if (hugetlbfs_inode_cachep == NULL) goto out2; error = register_filesystem(&hugetlbfs_fs_type); if (error) goto out; vfsmount = kern_mount(&hugetlbfs_fs_type); if (!IS_ERR(vfsmount)) { hugetlbfs_vfsmount = vfsmount; return 0; } error = PTR_ERR(vfsmount); out: if (error) kmem_cache_destroy(hugetlbfs_inode_cachep); out2: bdi_destroy(&hugetlbfs_backing_dev_info); return error;}static void __exit exit_hugetlbfs_fs(void){ kmem_cache_destroy(hugetlbfs_inode_cachep); unregister_filesystem(&hugetlbfs_fs_type); bdi_destroy(&hugetlbfs_backing_dev_info);}module_init(init_hugetlbfs_fs)module_exit(exit_hugetlbfs_fs)MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -