1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-1.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Hypervisor filesystem for Linux on s390.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright IBM Corp. 2006, 2008
6*4882a593Smuzhiyun * Author(s): Michael Holzheu <holzheu@de.ibm.com>
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #define KMSG_COMPONENT "hypfs"
10*4882a593Smuzhiyun #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #include <linux/types.h>
13*4882a593Smuzhiyun #include <linux/errno.h>
14*4882a593Smuzhiyun #include <linux/fs.h>
15*4882a593Smuzhiyun #include <linux/fs_context.h>
16*4882a593Smuzhiyun #include <linux/fs_parser.h>
17*4882a593Smuzhiyun #include <linux/namei.h>
18*4882a593Smuzhiyun #include <linux/vfs.h>
19*4882a593Smuzhiyun #include <linux/slab.h>
20*4882a593Smuzhiyun #include <linux/pagemap.h>
21*4882a593Smuzhiyun #include <linux/time.h>
22*4882a593Smuzhiyun #include <linux/sysfs.h>
23*4882a593Smuzhiyun #include <linux/init.h>
24*4882a593Smuzhiyun #include <linux/kobject.h>
25*4882a593Smuzhiyun #include <linux/seq_file.h>
26*4882a593Smuzhiyun #include <linux/uio.h>
27*4882a593Smuzhiyun #include <asm/ebcdic.h>
28*4882a593Smuzhiyun #include "hypfs.h"
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun #define HYPFS_MAGIC 0x687970 /* ASCII 'hyp' */
31*4882a593Smuzhiyun #define TMP_SIZE 64 /* size of temporary buffers */
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun static struct dentry *hypfs_create_update_file(struct dentry *dir);
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun struct hypfs_sb_info {
36*4882a593Smuzhiyun kuid_t uid; /* uid used for files and dirs */
37*4882a593Smuzhiyun kgid_t gid; /* gid used for files and dirs */
38*4882a593Smuzhiyun struct dentry *update_file; /* file to trigger update */
39*4882a593Smuzhiyun time64_t last_update; /* last update, CLOCK_MONOTONIC time */
40*4882a593Smuzhiyun struct mutex lock; /* lock to protect update process */
41*4882a593Smuzhiyun };
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun static const struct file_operations hypfs_file_ops;
44*4882a593Smuzhiyun static struct file_system_type hypfs_type;
45*4882a593Smuzhiyun static const struct super_operations hypfs_s_ops;
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun /* start of list of all dentries, which have to be deleted on update */
48*4882a593Smuzhiyun static struct dentry *hypfs_last_dentry;
49*4882a593Smuzhiyun
hypfs_update_update(struct super_block * sb)50*4882a593Smuzhiyun static void hypfs_update_update(struct super_block *sb)
51*4882a593Smuzhiyun {
52*4882a593Smuzhiyun struct hypfs_sb_info *sb_info = sb->s_fs_info;
53*4882a593Smuzhiyun struct inode *inode = d_inode(sb_info->update_file);
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun sb_info->last_update = ktime_get_seconds();
56*4882a593Smuzhiyun inode->i_atime = inode->i_mtime = inode->i_ctime = current_time(inode);
57*4882a593Smuzhiyun }
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun /* directory tree removal functions */
60*4882a593Smuzhiyun
hypfs_add_dentry(struct dentry * dentry)61*4882a593Smuzhiyun static void hypfs_add_dentry(struct dentry *dentry)
62*4882a593Smuzhiyun {
63*4882a593Smuzhiyun dentry->d_fsdata = hypfs_last_dentry;
64*4882a593Smuzhiyun hypfs_last_dentry = dentry;
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun
hypfs_remove(struct dentry * dentry)67*4882a593Smuzhiyun static void hypfs_remove(struct dentry *dentry)
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun struct dentry *parent;
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun parent = dentry->d_parent;
72*4882a593Smuzhiyun inode_lock(d_inode(parent));
73*4882a593Smuzhiyun if (simple_positive(dentry)) {
74*4882a593Smuzhiyun if (d_is_dir(dentry))
75*4882a593Smuzhiyun simple_rmdir(d_inode(parent), dentry);
76*4882a593Smuzhiyun else
77*4882a593Smuzhiyun simple_unlink(d_inode(parent), dentry);
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun d_drop(dentry);
80*4882a593Smuzhiyun dput(dentry);
81*4882a593Smuzhiyun inode_unlock(d_inode(parent));
82*4882a593Smuzhiyun }
83*4882a593Smuzhiyun
hypfs_delete_tree(struct dentry * root)84*4882a593Smuzhiyun static void hypfs_delete_tree(struct dentry *root)
85*4882a593Smuzhiyun {
86*4882a593Smuzhiyun while (hypfs_last_dentry) {
87*4882a593Smuzhiyun struct dentry *next_dentry;
88*4882a593Smuzhiyun next_dentry = hypfs_last_dentry->d_fsdata;
89*4882a593Smuzhiyun hypfs_remove(hypfs_last_dentry);
90*4882a593Smuzhiyun hypfs_last_dentry = next_dentry;
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun }
93*4882a593Smuzhiyun
hypfs_make_inode(struct super_block * sb,umode_t mode)94*4882a593Smuzhiyun static struct inode *hypfs_make_inode(struct super_block *sb, umode_t mode)
95*4882a593Smuzhiyun {
96*4882a593Smuzhiyun struct inode *ret = new_inode(sb);
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun if (ret) {
99*4882a593Smuzhiyun struct hypfs_sb_info *hypfs_info = sb->s_fs_info;
100*4882a593Smuzhiyun ret->i_ino = get_next_ino();
101*4882a593Smuzhiyun ret->i_mode = mode;
102*4882a593Smuzhiyun ret->i_uid = hypfs_info->uid;
103*4882a593Smuzhiyun ret->i_gid = hypfs_info->gid;
104*4882a593Smuzhiyun ret->i_atime = ret->i_mtime = ret->i_ctime = current_time(ret);
105*4882a593Smuzhiyun if (S_ISDIR(mode))
106*4882a593Smuzhiyun set_nlink(ret, 2);
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun return ret;
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun
hypfs_evict_inode(struct inode * inode)111*4882a593Smuzhiyun static void hypfs_evict_inode(struct inode *inode)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun clear_inode(inode);
114*4882a593Smuzhiyun kfree(inode->i_private);
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun
hypfs_open(struct inode * inode,struct file * filp)117*4882a593Smuzhiyun static int hypfs_open(struct inode *inode, struct file *filp)
118*4882a593Smuzhiyun {
119*4882a593Smuzhiyun char *data = file_inode(filp)->i_private;
120*4882a593Smuzhiyun struct hypfs_sb_info *fs_info;
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun if (filp->f_mode & FMODE_WRITE) {
123*4882a593Smuzhiyun if (!(inode->i_mode & S_IWUGO))
124*4882a593Smuzhiyun return -EACCES;
125*4882a593Smuzhiyun }
126*4882a593Smuzhiyun if (filp->f_mode & FMODE_READ) {
127*4882a593Smuzhiyun if (!(inode->i_mode & S_IRUGO))
128*4882a593Smuzhiyun return -EACCES;
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun fs_info = inode->i_sb->s_fs_info;
132*4882a593Smuzhiyun if(data) {
133*4882a593Smuzhiyun mutex_lock(&fs_info->lock);
134*4882a593Smuzhiyun filp->private_data = kstrdup(data, GFP_KERNEL);
135*4882a593Smuzhiyun if (!filp->private_data) {
136*4882a593Smuzhiyun mutex_unlock(&fs_info->lock);
137*4882a593Smuzhiyun return -ENOMEM;
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun mutex_unlock(&fs_info->lock);
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun return nonseekable_open(inode, filp);
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun
hypfs_read_iter(struct kiocb * iocb,struct iov_iter * to)144*4882a593Smuzhiyun static ssize_t hypfs_read_iter(struct kiocb *iocb, struct iov_iter *to)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun struct file *file = iocb->ki_filp;
147*4882a593Smuzhiyun char *data = file->private_data;
148*4882a593Smuzhiyun size_t available = strlen(data);
149*4882a593Smuzhiyun loff_t pos = iocb->ki_pos;
150*4882a593Smuzhiyun size_t count;
151*4882a593Smuzhiyun
152*4882a593Smuzhiyun if (pos < 0)
153*4882a593Smuzhiyun return -EINVAL;
154*4882a593Smuzhiyun if (pos >= available || !iov_iter_count(to))
155*4882a593Smuzhiyun return 0;
156*4882a593Smuzhiyun count = copy_to_iter(data + pos, available - pos, to);
157*4882a593Smuzhiyun if (!count)
158*4882a593Smuzhiyun return -EFAULT;
159*4882a593Smuzhiyun iocb->ki_pos = pos + count;
160*4882a593Smuzhiyun file_accessed(file);
161*4882a593Smuzhiyun return count;
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun
hypfs_write_iter(struct kiocb * iocb,struct iov_iter * from)164*4882a593Smuzhiyun static ssize_t hypfs_write_iter(struct kiocb *iocb, struct iov_iter *from)
165*4882a593Smuzhiyun {
166*4882a593Smuzhiyun int rc;
167*4882a593Smuzhiyun struct super_block *sb = file_inode(iocb->ki_filp)->i_sb;
168*4882a593Smuzhiyun struct hypfs_sb_info *fs_info = sb->s_fs_info;
169*4882a593Smuzhiyun size_t count = iov_iter_count(from);
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun /*
172*4882a593Smuzhiyun * Currently we only allow one update per second for two reasons:
173*4882a593Smuzhiyun * 1. diag 204 is VERY expensive
174*4882a593Smuzhiyun * 2. If several processes do updates in parallel and then read the
175*4882a593Smuzhiyun * hypfs data, the likelihood of collisions is reduced, if we restrict
176*4882a593Smuzhiyun * the minimum update interval. A collision occurs, if during the
177*4882a593Smuzhiyun * data gathering of one process another process triggers an update
178*4882a593Smuzhiyun * If the first process wants to ensure consistent data, it has
179*4882a593Smuzhiyun * to restart data collection in this case.
180*4882a593Smuzhiyun */
181*4882a593Smuzhiyun mutex_lock(&fs_info->lock);
182*4882a593Smuzhiyun if (fs_info->last_update == ktime_get_seconds()) {
183*4882a593Smuzhiyun rc = -EBUSY;
184*4882a593Smuzhiyun goto out;
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun hypfs_delete_tree(sb->s_root);
187*4882a593Smuzhiyun if (MACHINE_IS_VM)
188*4882a593Smuzhiyun rc = hypfs_vm_create_files(sb->s_root);
189*4882a593Smuzhiyun else
190*4882a593Smuzhiyun rc = hypfs_diag_create_files(sb->s_root);
191*4882a593Smuzhiyun if (rc) {
192*4882a593Smuzhiyun pr_err("Updating the hypfs tree failed\n");
193*4882a593Smuzhiyun hypfs_delete_tree(sb->s_root);
194*4882a593Smuzhiyun goto out;
195*4882a593Smuzhiyun }
196*4882a593Smuzhiyun hypfs_update_update(sb);
197*4882a593Smuzhiyun rc = count;
198*4882a593Smuzhiyun iov_iter_advance(from, count);
199*4882a593Smuzhiyun out:
200*4882a593Smuzhiyun mutex_unlock(&fs_info->lock);
201*4882a593Smuzhiyun return rc;
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun
hypfs_release(struct inode * inode,struct file * filp)204*4882a593Smuzhiyun static int hypfs_release(struct inode *inode, struct file *filp)
205*4882a593Smuzhiyun {
206*4882a593Smuzhiyun kfree(filp->private_data);
207*4882a593Smuzhiyun return 0;
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun
210*4882a593Smuzhiyun enum { Opt_uid, Opt_gid, };
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun static const struct fs_parameter_spec hypfs_fs_parameters[] = {
213*4882a593Smuzhiyun fsparam_u32("gid", Opt_gid),
214*4882a593Smuzhiyun fsparam_u32("uid", Opt_uid),
215*4882a593Smuzhiyun {}
216*4882a593Smuzhiyun };
217*4882a593Smuzhiyun
hypfs_parse_param(struct fs_context * fc,struct fs_parameter * param)218*4882a593Smuzhiyun static int hypfs_parse_param(struct fs_context *fc, struct fs_parameter *param)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun struct hypfs_sb_info *hypfs_info = fc->s_fs_info;
221*4882a593Smuzhiyun struct fs_parse_result result;
222*4882a593Smuzhiyun kuid_t uid;
223*4882a593Smuzhiyun kgid_t gid;
224*4882a593Smuzhiyun int opt;
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun opt = fs_parse(fc, hypfs_fs_parameters, param, &result);
227*4882a593Smuzhiyun if (opt < 0)
228*4882a593Smuzhiyun return opt;
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun switch (opt) {
231*4882a593Smuzhiyun case Opt_uid:
232*4882a593Smuzhiyun uid = make_kuid(current_user_ns(), result.uint_32);
233*4882a593Smuzhiyun if (!uid_valid(uid))
234*4882a593Smuzhiyun return invalf(fc, "Unknown uid");
235*4882a593Smuzhiyun hypfs_info->uid = uid;
236*4882a593Smuzhiyun break;
237*4882a593Smuzhiyun case Opt_gid:
238*4882a593Smuzhiyun gid = make_kgid(current_user_ns(), result.uint_32);
239*4882a593Smuzhiyun if (!gid_valid(gid))
240*4882a593Smuzhiyun return invalf(fc, "Unknown gid");
241*4882a593Smuzhiyun hypfs_info->gid = gid;
242*4882a593Smuzhiyun break;
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun return 0;
245*4882a593Smuzhiyun }
246*4882a593Smuzhiyun
hypfs_show_options(struct seq_file * s,struct dentry * root)247*4882a593Smuzhiyun static int hypfs_show_options(struct seq_file *s, struct dentry *root)
248*4882a593Smuzhiyun {
249*4882a593Smuzhiyun struct hypfs_sb_info *hypfs_info = root->d_sb->s_fs_info;
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun seq_printf(s, ",uid=%u", from_kuid_munged(&init_user_ns, hypfs_info->uid));
252*4882a593Smuzhiyun seq_printf(s, ",gid=%u", from_kgid_munged(&init_user_ns, hypfs_info->gid));
253*4882a593Smuzhiyun return 0;
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun
hypfs_fill_super(struct super_block * sb,struct fs_context * fc)256*4882a593Smuzhiyun static int hypfs_fill_super(struct super_block *sb, struct fs_context *fc)
257*4882a593Smuzhiyun {
258*4882a593Smuzhiyun struct hypfs_sb_info *sbi = sb->s_fs_info;
259*4882a593Smuzhiyun struct inode *root_inode;
260*4882a593Smuzhiyun struct dentry *root_dentry, *update_file;
261*4882a593Smuzhiyun int rc;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun sb->s_blocksize = PAGE_SIZE;
264*4882a593Smuzhiyun sb->s_blocksize_bits = PAGE_SHIFT;
265*4882a593Smuzhiyun sb->s_magic = HYPFS_MAGIC;
266*4882a593Smuzhiyun sb->s_op = &hypfs_s_ops;
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun root_inode = hypfs_make_inode(sb, S_IFDIR | 0755);
269*4882a593Smuzhiyun if (!root_inode)
270*4882a593Smuzhiyun return -ENOMEM;
271*4882a593Smuzhiyun root_inode->i_op = &simple_dir_inode_operations;
272*4882a593Smuzhiyun root_inode->i_fop = &simple_dir_operations;
273*4882a593Smuzhiyun sb->s_root = root_dentry = d_make_root(root_inode);
274*4882a593Smuzhiyun if (!root_dentry)
275*4882a593Smuzhiyun return -ENOMEM;
276*4882a593Smuzhiyun if (MACHINE_IS_VM)
277*4882a593Smuzhiyun rc = hypfs_vm_create_files(root_dentry);
278*4882a593Smuzhiyun else
279*4882a593Smuzhiyun rc = hypfs_diag_create_files(root_dentry);
280*4882a593Smuzhiyun if (rc)
281*4882a593Smuzhiyun return rc;
282*4882a593Smuzhiyun update_file = hypfs_create_update_file(root_dentry);
283*4882a593Smuzhiyun if (IS_ERR(update_file))
284*4882a593Smuzhiyun return PTR_ERR(update_file);
285*4882a593Smuzhiyun sbi->update_file = update_file;
286*4882a593Smuzhiyun hypfs_update_update(sb);
287*4882a593Smuzhiyun pr_info("Hypervisor filesystem mounted\n");
288*4882a593Smuzhiyun return 0;
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun
hypfs_get_tree(struct fs_context * fc)291*4882a593Smuzhiyun static int hypfs_get_tree(struct fs_context *fc)
292*4882a593Smuzhiyun {
293*4882a593Smuzhiyun return get_tree_single(fc, hypfs_fill_super);
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun
hypfs_free_fc(struct fs_context * fc)296*4882a593Smuzhiyun static void hypfs_free_fc(struct fs_context *fc)
297*4882a593Smuzhiyun {
298*4882a593Smuzhiyun kfree(fc->s_fs_info);
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun static const struct fs_context_operations hypfs_context_ops = {
302*4882a593Smuzhiyun .free = hypfs_free_fc,
303*4882a593Smuzhiyun .parse_param = hypfs_parse_param,
304*4882a593Smuzhiyun .get_tree = hypfs_get_tree,
305*4882a593Smuzhiyun };
306*4882a593Smuzhiyun
hypfs_init_fs_context(struct fs_context * fc)307*4882a593Smuzhiyun static int hypfs_init_fs_context(struct fs_context *fc)
308*4882a593Smuzhiyun {
309*4882a593Smuzhiyun struct hypfs_sb_info *sbi;
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun sbi = kzalloc(sizeof(struct hypfs_sb_info), GFP_KERNEL);
312*4882a593Smuzhiyun if (!sbi)
313*4882a593Smuzhiyun return -ENOMEM;
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun mutex_init(&sbi->lock);
316*4882a593Smuzhiyun sbi->uid = current_uid();
317*4882a593Smuzhiyun sbi->gid = current_gid();
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun fc->s_fs_info = sbi;
320*4882a593Smuzhiyun fc->ops = &hypfs_context_ops;
321*4882a593Smuzhiyun return 0;
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun
hypfs_kill_super(struct super_block * sb)324*4882a593Smuzhiyun static void hypfs_kill_super(struct super_block *sb)
325*4882a593Smuzhiyun {
326*4882a593Smuzhiyun struct hypfs_sb_info *sb_info = sb->s_fs_info;
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun if (sb->s_root)
329*4882a593Smuzhiyun hypfs_delete_tree(sb->s_root);
330*4882a593Smuzhiyun if (sb_info && sb_info->update_file)
331*4882a593Smuzhiyun hypfs_remove(sb_info->update_file);
332*4882a593Smuzhiyun kfree(sb->s_fs_info);
333*4882a593Smuzhiyun sb->s_fs_info = NULL;
334*4882a593Smuzhiyun kill_litter_super(sb);
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun
hypfs_create_file(struct dentry * parent,const char * name,char * data,umode_t mode)337*4882a593Smuzhiyun static struct dentry *hypfs_create_file(struct dentry *parent, const char *name,
338*4882a593Smuzhiyun char *data, umode_t mode)
339*4882a593Smuzhiyun {
340*4882a593Smuzhiyun struct dentry *dentry;
341*4882a593Smuzhiyun struct inode *inode;
342*4882a593Smuzhiyun
343*4882a593Smuzhiyun inode_lock(d_inode(parent));
344*4882a593Smuzhiyun dentry = lookup_one_len(name, parent, strlen(name));
345*4882a593Smuzhiyun if (IS_ERR(dentry)) {
346*4882a593Smuzhiyun dentry = ERR_PTR(-ENOMEM);
347*4882a593Smuzhiyun goto fail;
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun inode = hypfs_make_inode(parent->d_sb, mode);
350*4882a593Smuzhiyun if (!inode) {
351*4882a593Smuzhiyun dput(dentry);
352*4882a593Smuzhiyun dentry = ERR_PTR(-ENOMEM);
353*4882a593Smuzhiyun goto fail;
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun if (S_ISREG(mode)) {
356*4882a593Smuzhiyun inode->i_fop = &hypfs_file_ops;
357*4882a593Smuzhiyun if (data)
358*4882a593Smuzhiyun inode->i_size = strlen(data);
359*4882a593Smuzhiyun else
360*4882a593Smuzhiyun inode->i_size = 0;
361*4882a593Smuzhiyun } else if (S_ISDIR(mode)) {
362*4882a593Smuzhiyun inode->i_op = &simple_dir_inode_operations;
363*4882a593Smuzhiyun inode->i_fop = &simple_dir_operations;
364*4882a593Smuzhiyun inc_nlink(d_inode(parent));
365*4882a593Smuzhiyun } else
366*4882a593Smuzhiyun BUG();
367*4882a593Smuzhiyun inode->i_private = data;
368*4882a593Smuzhiyun d_instantiate(dentry, inode);
369*4882a593Smuzhiyun dget(dentry);
370*4882a593Smuzhiyun fail:
371*4882a593Smuzhiyun inode_unlock(d_inode(parent));
372*4882a593Smuzhiyun return dentry;
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun
hypfs_mkdir(struct dentry * parent,const char * name)375*4882a593Smuzhiyun struct dentry *hypfs_mkdir(struct dentry *parent, const char *name)
376*4882a593Smuzhiyun {
377*4882a593Smuzhiyun struct dentry *dentry;
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun dentry = hypfs_create_file(parent, name, NULL, S_IFDIR | DIR_MODE);
380*4882a593Smuzhiyun if (IS_ERR(dentry))
381*4882a593Smuzhiyun return dentry;
382*4882a593Smuzhiyun hypfs_add_dentry(dentry);
383*4882a593Smuzhiyun return dentry;
384*4882a593Smuzhiyun }
385*4882a593Smuzhiyun
hypfs_create_update_file(struct dentry * dir)386*4882a593Smuzhiyun static struct dentry *hypfs_create_update_file(struct dentry *dir)
387*4882a593Smuzhiyun {
388*4882a593Smuzhiyun struct dentry *dentry;
389*4882a593Smuzhiyun
390*4882a593Smuzhiyun dentry = hypfs_create_file(dir, "update", NULL,
391*4882a593Smuzhiyun S_IFREG | UPDATE_FILE_MODE);
392*4882a593Smuzhiyun /*
393*4882a593Smuzhiyun * We do not put the update file on the 'delete' list with
394*4882a593Smuzhiyun * hypfs_add_dentry(), since it should not be removed when the tree
395*4882a593Smuzhiyun * is updated.
396*4882a593Smuzhiyun */
397*4882a593Smuzhiyun return dentry;
398*4882a593Smuzhiyun }
399*4882a593Smuzhiyun
hypfs_create_u64(struct dentry * dir,const char * name,__u64 value)400*4882a593Smuzhiyun struct dentry *hypfs_create_u64(struct dentry *dir,
401*4882a593Smuzhiyun const char *name, __u64 value)
402*4882a593Smuzhiyun {
403*4882a593Smuzhiyun char *buffer;
404*4882a593Smuzhiyun char tmp[TMP_SIZE];
405*4882a593Smuzhiyun struct dentry *dentry;
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun snprintf(tmp, TMP_SIZE, "%llu\n", (unsigned long long int)value);
408*4882a593Smuzhiyun buffer = kstrdup(tmp, GFP_KERNEL);
409*4882a593Smuzhiyun if (!buffer)
410*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
411*4882a593Smuzhiyun dentry =
412*4882a593Smuzhiyun hypfs_create_file(dir, name, buffer, S_IFREG | REG_FILE_MODE);
413*4882a593Smuzhiyun if (IS_ERR(dentry)) {
414*4882a593Smuzhiyun kfree(buffer);
415*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
416*4882a593Smuzhiyun }
417*4882a593Smuzhiyun hypfs_add_dentry(dentry);
418*4882a593Smuzhiyun return dentry;
419*4882a593Smuzhiyun }
420*4882a593Smuzhiyun
hypfs_create_str(struct dentry * dir,const char * name,char * string)421*4882a593Smuzhiyun struct dentry *hypfs_create_str(struct dentry *dir,
422*4882a593Smuzhiyun const char *name, char *string)
423*4882a593Smuzhiyun {
424*4882a593Smuzhiyun char *buffer;
425*4882a593Smuzhiyun struct dentry *dentry;
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun buffer = kmalloc(strlen(string) + 2, GFP_KERNEL);
428*4882a593Smuzhiyun if (!buffer)
429*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
430*4882a593Smuzhiyun sprintf(buffer, "%s\n", string);
431*4882a593Smuzhiyun dentry =
432*4882a593Smuzhiyun hypfs_create_file(dir, name, buffer, S_IFREG | REG_FILE_MODE);
433*4882a593Smuzhiyun if (IS_ERR(dentry)) {
434*4882a593Smuzhiyun kfree(buffer);
435*4882a593Smuzhiyun return ERR_PTR(-ENOMEM);
436*4882a593Smuzhiyun }
437*4882a593Smuzhiyun hypfs_add_dentry(dentry);
438*4882a593Smuzhiyun return dentry;
439*4882a593Smuzhiyun }
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun static const struct file_operations hypfs_file_ops = {
442*4882a593Smuzhiyun .open = hypfs_open,
443*4882a593Smuzhiyun .release = hypfs_release,
444*4882a593Smuzhiyun .read_iter = hypfs_read_iter,
445*4882a593Smuzhiyun .write_iter = hypfs_write_iter,
446*4882a593Smuzhiyun .llseek = no_llseek,
447*4882a593Smuzhiyun };
448*4882a593Smuzhiyun
449*4882a593Smuzhiyun static struct file_system_type hypfs_type = {
450*4882a593Smuzhiyun .owner = THIS_MODULE,
451*4882a593Smuzhiyun .name = "s390_hypfs",
452*4882a593Smuzhiyun .init_fs_context = hypfs_init_fs_context,
453*4882a593Smuzhiyun .parameters = hypfs_fs_parameters,
454*4882a593Smuzhiyun .kill_sb = hypfs_kill_super
455*4882a593Smuzhiyun };
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun static const struct super_operations hypfs_s_ops = {
458*4882a593Smuzhiyun .statfs = simple_statfs,
459*4882a593Smuzhiyun .evict_inode = hypfs_evict_inode,
460*4882a593Smuzhiyun .show_options = hypfs_show_options,
461*4882a593Smuzhiyun };
462*4882a593Smuzhiyun
hypfs_init(void)463*4882a593Smuzhiyun static int __init hypfs_init(void)
464*4882a593Smuzhiyun {
465*4882a593Smuzhiyun int rc;
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun hypfs_dbfs_init();
468*4882a593Smuzhiyun
469*4882a593Smuzhiyun if (hypfs_diag_init()) {
470*4882a593Smuzhiyun rc = -ENODATA;
471*4882a593Smuzhiyun goto fail_dbfs_exit;
472*4882a593Smuzhiyun }
473*4882a593Smuzhiyun if (hypfs_vm_init()) {
474*4882a593Smuzhiyun rc = -ENODATA;
475*4882a593Smuzhiyun goto fail_hypfs_diag_exit;
476*4882a593Smuzhiyun }
477*4882a593Smuzhiyun hypfs_sprp_init();
478*4882a593Smuzhiyun if (hypfs_diag0c_init()) {
479*4882a593Smuzhiyun rc = -ENODATA;
480*4882a593Smuzhiyun goto fail_hypfs_sprp_exit;
481*4882a593Smuzhiyun }
482*4882a593Smuzhiyun rc = sysfs_create_mount_point(hypervisor_kobj, "s390");
483*4882a593Smuzhiyun if (rc)
484*4882a593Smuzhiyun goto fail_hypfs_diag0c_exit;
485*4882a593Smuzhiyun rc = register_filesystem(&hypfs_type);
486*4882a593Smuzhiyun if (rc)
487*4882a593Smuzhiyun goto fail_filesystem;
488*4882a593Smuzhiyun return 0;
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun fail_filesystem:
491*4882a593Smuzhiyun sysfs_remove_mount_point(hypervisor_kobj, "s390");
492*4882a593Smuzhiyun fail_hypfs_diag0c_exit:
493*4882a593Smuzhiyun hypfs_diag0c_exit();
494*4882a593Smuzhiyun fail_hypfs_sprp_exit:
495*4882a593Smuzhiyun hypfs_sprp_exit();
496*4882a593Smuzhiyun hypfs_vm_exit();
497*4882a593Smuzhiyun fail_hypfs_diag_exit:
498*4882a593Smuzhiyun hypfs_diag_exit();
499*4882a593Smuzhiyun pr_err("Initialization of hypfs failed with rc=%i\n", rc);
500*4882a593Smuzhiyun fail_dbfs_exit:
501*4882a593Smuzhiyun hypfs_dbfs_exit();
502*4882a593Smuzhiyun return rc;
503*4882a593Smuzhiyun }
504*4882a593Smuzhiyun device_initcall(hypfs_init)
505