📄 shmem.c
字号:
}static const struct inode_operations shmem_symlink_inline_operations = { .readlink = generic_readlink, .follow_link = shmem_follow_link_inline,};static const struct inode_operations shmem_symlink_inode_operations = { .truncate = shmem_truncate, .readlink = generic_readlink, .follow_link = shmem_follow_link, .put_link = shmem_put_link,};#ifdef CONFIG_TMPFS_POSIX_ACL/* * Superblocks without xattr inode operations will get security.* xattr * support from the VFS "for free". As soon as we have any other xattrs * like ACLs, we also need to implement the security.* handlers at * filesystem level, though. */static size_t shmem_xattr_security_list(struct inode *inode, char *list, size_t list_len, const char *name, size_t name_len){ return security_inode_listsecurity(inode, list, list_len);}static int shmem_xattr_security_get(struct inode *inode, const char *name, void *buffer, size_t size){ if (strcmp(name, "") == 0) return -EINVAL; return xattr_getsecurity(inode, name, buffer, size);}static int shmem_xattr_security_set(struct inode *inode, const char *name, const void *value, size_t size, int flags){ if (strcmp(name, "") == 0) return -EINVAL; return security_inode_setsecurity(inode, name, value, size, flags);}static struct xattr_handler shmem_xattr_security_handler = { .prefix = XATTR_SECURITY_PREFIX, .list = shmem_xattr_security_list, .get = shmem_xattr_security_get, .set = shmem_xattr_security_set,};static struct xattr_handler *shmem_xattr_handlers[] = { &shmem_xattr_acl_access_handler, &shmem_xattr_acl_default_handler, &shmem_xattr_security_handler, NULL};#endifstatic struct dentry *shmem_get_parent(struct dentry *child){ return ERR_PTR(-ESTALE);}static int shmem_match(struct inode *ino, void *vfh){ __u32 *fh = vfh; __u64 inum = fh[2]; inum = (inum << 32) | fh[1]; return ino->i_ino == inum && fh[0] == ino->i_generation;}static struct dentry *shmem_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, int fh_type){ struct inode *inode; struct dentry *dentry = NULL; u64 inum = fid->raw[2]; inum = (inum << 32) | fid->raw[1]; if (fh_len < 3) return NULL; inode = ilookup5(sb, (unsigned long)(inum + fid->raw[0]), shmem_match, fid->raw); if (inode) { dentry = d_find_alias(inode); iput(inode); } return dentry;}static int shmem_encode_fh(struct dentry *dentry, __u32 *fh, int *len, int connectable){ struct inode *inode = dentry->d_inode; if (*len < 3) return 255; if (hlist_unhashed(&inode->i_hash)) { /* Unfortunately insert_inode_hash is not idempotent, * so as we hash inodes here rather than at creation * time, we need a lock to ensure we only try * to do it once */ static DEFINE_SPINLOCK(lock); spin_lock(&lock); if (hlist_unhashed(&inode->i_hash)) __insert_inode_hash(inode, inode->i_ino + inode->i_generation); spin_unlock(&lock); } fh[0] = inode->i_generation; fh[1] = inode->i_ino; fh[2] = ((__u64)inode->i_ino) >> 32; *len = 3; return 1;}static const struct export_operations shmem_export_ops = { .get_parent = shmem_get_parent, .encode_fh = shmem_encode_fh, .fh_to_dentry = shmem_fh_to_dentry,};static int shmem_parse_options(char *options, struct shmem_sb_info *sbinfo, bool remount){ char *this_char, *value, *rest; while (options != NULL) { this_char = options; for (;;) { /* * NUL-terminate this option: unfortunately, * mount options form a comma-separated list, * but mpol's nodelist may also contain commas. */ options = strchr(options, ','); if (options == NULL) break; options++; if (!isdigit(*options)) { options[-1] = '\0'; break; } } if (!*this_char) continue; if ((value = strchr(this_char,'=')) != NULL) { *value++ = 0; } else { printk(KERN_ERR "tmpfs: No value for mount option '%s'\n", this_char); return 1; } if (!strcmp(this_char,"size")) { unsigned long long size; size = memparse(value,&rest); if (*rest == '%') { size <<= PAGE_SHIFT; size *= totalram_pages; do_div(size, 100); rest++; } if (*rest) goto bad_val; sbinfo->max_blocks = DIV_ROUND_UP(size, PAGE_CACHE_SIZE); } else if (!strcmp(this_char,"nr_blocks")) { sbinfo->max_blocks = memparse(value, &rest); if (*rest) goto bad_val; } else if (!strcmp(this_char,"nr_inodes")) { sbinfo->max_inodes = memparse(value, &rest); if (*rest) goto bad_val; } else if (!strcmp(this_char,"mode")) { if (remount) continue; sbinfo->mode = simple_strtoul(value, &rest, 8) & 07777; if (*rest) goto bad_val; } else if (!strcmp(this_char,"uid")) { if (remount) continue; sbinfo->uid = simple_strtoul(value, &rest, 0); if (*rest) goto bad_val; } else if (!strcmp(this_char,"gid")) { if (remount) continue; sbinfo->gid = simple_strtoul(value, &rest, 0); if (*rest) goto bad_val; } else if (!strcmp(this_char,"mpol")) { if (mpol_parse_str(value, &sbinfo->mpol, 1)) goto bad_val; } else { printk(KERN_ERR "tmpfs: Bad mount option %s\n", this_char); return 1; } } return 0;bad_val: printk(KERN_ERR "tmpfs: Bad value '%s' for mount option '%s'\n", value, this_char); return 1;}static int shmem_remount_fs(struct super_block *sb, int *flags, char *data){ struct shmem_sb_info *sbinfo = SHMEM_SB(sb); struct shmem_sb_info config = *sbinfo; unsigned long blocks; unsigned long inodes; int error = -EINVAL; if (shmem_parse_options(data, &config, true)) return error; spin_lock(&sbinfo->stat_lock); blocks = sbinfo->max_blocks - sbinfo->free_blocks; inodes = sbinfo->max_inodes - sbinfo->free_inodes; if (config.max_blocks < blocks) goto out; if (config.max_inodes < inodes) goto out; /* * Those tests also disallow limited->unlimited while any are in * use, so i_blocks will always be zero when max_blocks is zero; * but we must separately disallow unlimited->limited, because * in that case we have no record of how much is already in use. */ if (config.max_blocks && !sbinfo->max_blocks) goto out; if (config.max_inodes && !sbinfo->max_inodes) goto out; error = 0; sbinfo->max_blocks = config.max_blocks; sbinfo->free_blocks = config.max_blocks - blocks; sbinfo->max_inodes = config.max_inodes; sbinfo->free_inodes = config.max_inodes - inodes; mpol_put(sbinfo->mpol); sbinfo->mpol = config.mpol; /* transfers initial ref */out: spin_unlock(&sbinfo->stat_lock); return error;}static int shmem_show_options(struct seq_file *seq, struct vfsmount *vfs){ struct shmem_sb_info *sbinfo = SHMEM_SB(vfs->mnt_sb); if (sbinfo->max_blocks != shmem_default_max_blocks()) seq_printf(seq, ",size=%luk", sbinfo->max_blocks << (PAGE_CACHE_SHIFT - 10)); if (sbinfo->max_inodes != shmem_default_max_inodes()) seq_printf(seq, ",nr_inodes=%lu", sbinfo->max_inodes); if (sbinfo->mode != (S_IRWXUGO | S_ISVTX)) seq_printf(seq, ",mode=%03o", sbinfo->mode); if (sbinfo->uid != 0) seq_printf(seq, ",uid=%u", sbinfo->uid); if (sbinfo->gid != 0) seq_printf(seq, ",gid=%u", sbinfo->gid); shmem_show_mpol(seq, sbinfo->mpol); return 0;}#endif /* CONFIG_TMPFS */static void shmem_put_super(struct super_block *sb){ kfree(sb->s_fs_info); sb->s_fs_info = NULL;}static int shmem_fill_super(struct super_block *sb, void *data, int silent){ struct inode *inode; struct dentry *root; struct shmem_sb_info *sbinfo; int err = -ENOMEM; /* Round up to L1_CACHE_BYTES to resist false sharing */ sbinfo = kmalloc(max((int)sizeof(struct shmem_sb_info), L1_CACHE_BYTES), GFP_KERNEL); if (!sbinfo) return -ENOMEM; sbinfo->max_blocks = 0; sbinfo->max_inodes = 0; sbinfo->mode = S_IRWXUGO | S_ISVTX; sbinfo->uid = current_fsuid(); sbinfo->gid = current_fsgid(); sbinfo->mpol = NULL; sb->s_fs_info = sbinfo;#ifdef CONFIG_TMPFS /* * Per default we only allow half of the physical ram per * tmpfs instance, limiting inodes to one per page of lowmem; * but the internal instance is left unlimited. */ if (!(sb->s_flags & MS_NOUSER)) { sbinfo->max_blocks = shmem_default_max_blocks(); sbinfo->max_inodes = shmem_default_max_inodes(); if (shmem_parse_options(data, sbinfo, false)) { err = -EINVAL; goto failed; } } sb->s_export_op = &shmem_export_ops;#else sb->s_flags |= MS_NOUSER;#endif spin_lock_init(&sbinfo->stat_lock); sbinfo->free_blocks = sbinfo->max_blocks; sbinfo->free_inodes = sbinfo->max_inodes; sb->s_maxbytes = SHMEM_MAX_BYTES; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = TMPFS_MAGIC; sb->s_op = &shmem_ops; sb->s_time_gran = 1;#ifdef CONFIG_TMPFS_POSIX_ACL sb->s_xattr = shmem_xattr_handlers; sb->s_flags |= MS_POSIXACL;#endif inode = shmem_get_inode(sb, S_IFDIR | sbinfo->mode, 0, VM_NORESERVE); if (!inode) goto failed; inode->i_uid = sbinfo->uid; inode->i_gid = sbinfo->gid; root = d_alloc_root(inode); if (!root) goto failed_iput; sb->s_root = root; return 0;failed_iput: iput(inode);failed: shmem_put_super(sb); return err;}static struct kmem_cache *shmem_inode_cachep;static struct inode *shmem_alloc_inode(struct super_block *sb){ struct shmem_inode_info *p; p = (struct shmem_inode_info *)kmem_cache_alloc(shmem_inode_cachep, GFP_KERNEL); if (!p) return NULL; return &p->vfs_inode;}static void shmem_destroy_inode(struct inode *inode){ if ((inode->i_mode & S_IFMT) == S_IFREG) { /* only struct inode is valid if it's an inline symlink */ mpol_free_shared_policy(&SHMEM_I(inode)->policy); } shmem_acl_destroy_inode(inode); kmem_cache_free(shmem_inode_cachep, SHMEM_I(inode));}static void init_once(void *foo){ struct shmem_inode_info *p = (struct shmem_inode_info *) foo; inode_init_once(&p->vfs_inode);#ifdef CONFIG_TMPFS_POSIX_ACL p->i_acl = NULL; p->i_default_acl = NULL;#endif}static int init_inodecache(void){ shmem_inode_cachep = kmem_cache_create("shmem_inode_cache", sizeof(struct shmem_inode_info), 0, SLAB_PANIC, init_once); return 0;}static void destroy_inodecache(void){ kmem_cache_destroy(shmem_inode_cachep);}static const struct address_space_operations shmem_aops = { .writepage = shmem_writepage, .set_page_dirty = __set_page_dirty_no_writeback,#ifdef CONFIG_TMPFS .readpage = shmem_readpage, .write_begin = shmem_write_begin, .write_end = shmem_write_end,#endif .migratepage = migrate_page,};static const struct file_operations shmem_file_operations = { .mmap = shmem_mmap,#ifdef CONFIG_TMPFS .llseek = generic_file_llseek, .read = do_sync_read, .write = do_sync_write, .aio_read = shmem_file_aio_read, .aio_write = generic_file_aio_write, .fsync = simple_sync_file, .splice_read = generic_file_splice_read, .splice_write = generic_file_splice_write,#endif};static const struct inode_operations shmem_inode_operations = { .truncate = shmem_truncate, .setattr = shmem_notify_change, .truncate_range = shmem_truncate_range,#ifdef CONFIG_TMPFS_POSIX_ACL .setxattr = generic_setxattr, .getxattr = generic_getxattr, .listxattr = generic_listxattr, .removexattr = generic_removexattr, .permission = shmem_permission,#endif};static const struct inode_operations shmem_dir_inode_operations = {#ifdef CONFIG_TMPFS .create = shmem_create, .lookup = simple_lookup, .link = shmem_link, .unlink = shmem_unlink, .symlink = shmem_symlink, .mkdir = shmem_mkdir, .rmdir = shmem_rmdir, .mknod = shmem_mknod, .rename = shmem_rename,#endif#ifdef CONFIG_TMPFS_POSIX_ACL .setattr = shmem_notify_change, .setxattr = generic_setxattr, .getxattr = generic_getxattr, .listxattr = generic_listxattr, .removexattr = generic_removexattr, .permission = shmem_permission,#endif};static const struct inode_operations shmem_special_inode_operations = {#ifdef CONFIG_TMPFS_POSIX_ACL .setattr = shmem_notify_change, .setxattr = generic_setxattr, .getxattr = generic_getxattr, .listxattr = generic_listxattr, .removexattr = generic_removexattr, .permission = shmem_permission,#endif};static const struct super_operations shmem_ops = { .alloc_inode = shmem_alloc_inode, .destroy_inode = shmem_destroy_inode,#ifdef CONFIG_TMPFS .statfs = shmem_statfs, .remount_fs = shmem_remount_fs, .show_options = shmem_show_options,#endif .delete_inode = shmem_delete_inode, .drop_inode = generic_delete_inode, .put_super = shmem_put_super,};static struct vm_operations_struct shmem_vm_ops = { .fault = shmem_fault,#ifdef CONFIG_NUMA .set_policy
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -