1/*
2 *  arch/s390/hypfs/inode.c
3 *    Hypervisor filesystem for Linux on s390.
4 *
5 *    Copyright (C) IBM Corp. 2006
6 *    Author(s): Michael Holzheu <holzheu@de.ibm.com>
7 */
8
9#include <linux/types.h>
10#include <linux/errno.h>
11#include <linux/fs.h>
12#include <linux/namei.h>
13#include <linux/vfs.h>
14#include <linux/pagemap.h>
15#include <linux/gfp.h>
16#include <linux/time.h>
17#include <linux/parser.h>
18#include <linux/sysfs.h>
19#include <linux/module.h>
20#include <asm/ebcdic.h>
21#include "hypfs.h"
22
23#define HYPFS_MAGIC 0x687970	/* ASCII 'hyp' */
24#define TMP_SIZE 64		/* size of temporary buffers */
25
26static struct dentry *hypfs_create_update_file(struct super_block *sb,
27					       struct dentry *dir);
28
29struct hypfs_sb_info {
30	uid_t uid;			/* uid used for files and dirs */
31	gid_t gid;			/* gid used for files and dirs */
32	struct dentry *update_file;	/* file to trigger update */
33	time_t last_update;		/* last update time in secs since 1970 */
34	struct mutex lock;		/* lock to protect update process */
35};
36
37static const struct file_operations hypfs_file_ops;
38static struct file_system_type hypfs_type;
39static struct super_operations hypfs_s_ops;
40
41/* start of list of all dentries, which have to be deleted on update */
42static struct dentry *hypfs_last_dentry;
43
44static void hypfs_update_update(struct super_block *sb)
45{
46	struct hypfs_sb_info *sb_info = sb->s_fs_info;
47	struct inode *inode = sb_info->update_file->d_inode;
48
49	sb_info->last_update = get_seconds();
50	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
51}
52
53/* directory tree removal functions */
54
55static void hypfs_add_dentry(struct dentry *dentry)
56{
57	dentry->d_fsdata = hypfs_last_dentry;
58	hypfs_last_dentry = dentry;
59}
60
61static void hypfs_remove(struct dentry *dentry)
62{
63	struct dentry *parent;
64
65	parent = dentry->d_parent;
66	if (S_ISDIR(dentry->d_inode->i_mode))
67		simple_rmdir(parent->d_inode, dentry);
68	else
69		simple_unlink(parent->d_inode, dentry);
70	d_delete(dentry);
71	dput(dentry);
72}
73
74static void hypfs_delete_tree(struct dentry *root)
75{
76	while (hypfs_last_dentry) {
77		struct dentry *next_dentry;
78		next_dentry = hypfs_last_dentry->d_fsdata;
79		hypfs_remove(hypfs_last_dentry);
80		hypfs_last_dentry = next_dentry;
81	}
82}
83
84static struct inode *hypfs_make_inode(struct super_block *sb, int mode)
85{
86	struct inode *ret = new_inode(sb);
87
88	if (ret) {
89		struct hypfs_sb_info *hypfs_info = sb->s_fs_info;
90		ret->i_mode = mode;
91		ret->i_uid = hypfs_info->uid;
92		ret->i_gid = hypfs_info->gid;
93		ret->i_blocks = 0;
94		ret->i_atime = ret->i_mtime = ret->i_ctime = CURRENT_TIME;
95		if (mode & S_IFDIR)
96			ret->i_nlink = 2;
97		else
98			ret->i_nlink = 1;
99	}
100	return ret;
101}
102
103static void hypfs_drop_inode(struct inode *inode)
104{
105	kfree(inode->i_private);
106	generic_delete_inode(inode);
107}
108
109static int hypfs_open(struct inode *inode, struct file *filp)
110{
111	char *data = filp->f_path.dentry->d_inode->i_private;
112	struct hypfs_sb_info *fs_info;
113
114	if (filp->f_mode & FMODE_WRITE) {
115		if (!(inode->i_mode & S_IWUGO))
116			return -EACCES;
117	}
118	if (filp->f_mode & FMODE_READ) {
119		if (!(inode->i_mode & S_IRUGO))
120			return -EACCES;
121	}
122
123	fs_info = inode->i_sb->s_fs_info;
124	if(data) {
125		mutex_lock(&fs_info->lock);
126		filp->private_data = kstrdup(data, GFP_KERNEL);
127		if (!filp->private_data) {
128			mutex_unlock(&fs_info->lock);
129			return -ENOMEM;
130		}
131		mutex_unlock(&fs_info->lock);
132	}
133	return 0;
134}
135
136static ssize_t hypfs_aio_read(struct kiocb *iocb, const struct iovec *iov,
137			      unsigned long nr_segs, loff_t offset)
138{
139	char *data;
140	size_t len;
141	struct file *filp = iocb->ki_filp;
142	char __user *buf = iov[0].iov_base;
143	size_t count = iov[0].iov_len;
144
145	if (nr_segs != 1) {
146		count = -EINVAL;
147		goto out;
148	}
149
150	data = filp->private_data;
151	len = strlen(data);
152	if (offset > len) {
153		count = 0;
154		goto out;
155	}
156	if (count > len - offset)
157		count = len - offset;
158	if (copy_to_user(buf, data + offset, count)) {
159		count = -EFAULT;
160		goto out;
161	}
162	iocb->ki_pos += count;
163	file_accessed(filp);
164out:
165	return count;
166}
167static ssize_t hypfs_aio_write(struct kiocb *iocb, const struct iovec *iov,
168			      unsigned long nr_segs, loff_t offset)
169{
170	int rc;
171	struct super_block *sb;
172	struct hypfs_sb_info *fs_info;
173	size_t count = iov_length(iov, nr_segs);
174
175	sb = iocb->ki_filp->f_path.dentry->d_inode->i_sb;
176	fs_info = sb->s_fs_info;
177	/*
178	 * Currently we only allow one update per second for two reasons:
179	 * 1. diag 204 is VERY expensive
180	 * 2. If several processes do updates in parallel and then read the
181	 *    hypfs data, the likelihood of collisions is reduced, if we restrict
182	 *    the minimum update interval. A collision occurs, if during the
183	 *    data gathering of one process another process triggers an update
184	 *    If the first process wants to ensure consistent data, it has
185	 *    to restart data collection in this case.
186	 */
187	mutex_lock(&fs_info->lock);
188	if (fs_info->last_update == get_seconds()) {
189		rc = -EBUSY;
190		goto out;
191	}
192	hypfs_delete_tree(sb->s_root);
193	if (MACHINE_IS_VM)
194		rc = hypfs_vm_create_files(sb, sb->s_root);
195	else
196		rc = hypfs_diag_create_files(sb, sb->s_root);
197	if (rc) {
198		printk(KERN_ERR "hypfs: Update failed\n");
199		hypfs_delete_tree(sb->s_root);
200		goto out;
201	}
202	hypfs_update_update(sb);
203	rc = count;
204out:
205	mutex_unlock(&fs_info->lock);
206	return rc;
207}
208
209static int hypfs_release(struct inode *inode, struct file *filp)
210{
211	kfree(filp->private_data);
212	return 0;
213}
214
215enum { opt_uid, opt_gid, opt_err };
216
217static match_table_t hypfs_tokens = {
218	{opt_uid, "uid=%u"},
219	{opt_gid, "gid=%u"},
220	{opt_err, NULL}
221};
222
223static int hypfs_parse_options(char *options, struct super_block *sb)
224{
225	char *str;
226	substring_t args[MAX_OPT_ARGS];
227
228	if (!options)
229		return 0;
230	while ((str = strsep(&options, ",")) != NULL) {
231		int token, option;
232		struct hypfs_sb_info *hypfs_info = sb->s_fs_info;
233
234		if (!*str)
235			continue;
236		token = match_token(str, hypfs_tokens, args);
237		switch (token) {
238		case opt_uid:
239			if (match_int(&args[0], &option))
240				return -EINVAL;
241			hypfs_info->uid = option;
242			break;
243		case opt_gid:
244			if (match_int(&args[0], &option))
245				return -EINVAL;
246			hypfs_info->gid = option;
247			break;
248		case opt_err:
249		default:
250			printk(KERN_ERR "hypfs: Unrecognized mount option "
251			       "\"%s\" or missing value\n", str);
252			return -EINVAL;
253		}
254	}
255	return 0;
256}
257
258static int hypfs_fill_super(struct super_block *sb, void *data, int silent)
259{
260	struct inode *root_inode;
261	struct dentry *root_dentry;
262	int rc = 0;
263	struct hypfs_sb_info *sbi;
264
265	sbi = kzalloc(sizeof(struct hypfs_sb_info), GFP_KERNEL);
266	if (!sbi)
267		return -ENOMEM;
268	mutex_init(&sbi->lock);
269	sbi->uid = current->uid;
270	sbi->gid = current->gid;
271	sb->s_fs_info = sbi;
272	sb->s_blocksize = PAGE_CACHE_SIZE;
273	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
274	sb->s_magic = HYPFS_MAGIC;
275	sb->s_op = &hypfs_s_ops;
276	if (hypfs_parse_options(data, sb)) {
277		rc = -EINVAL;
278		goto err_alloc;
279	}
280	root_inode = hypfs_make_inode(sb, S_IFDIR | 0755);
281	if (!root_inode) {
282		rc = -ENOMEM;
283		goto err_alloc;
284	}
285	root_inode->i_op = &simple_dir_inode_operations;
286	root_inode->i_fop = &simple_dir_operations;
287	root_dentry = d_alloc_root(root_inode);
288	if (!root_dentry) {
289		iput(root_inode);
290		rc = -ENOMEM;
291		goto err_alloc;
292	}
293	if (MACHINE_IS_VM)
294		rc = hypfs_vm_create_files(sb, root_dentry);
295	else
296		rc = hypfs_diag_create_files(sb, root_dentry);
297	if (rc)
298		goto err_tree;
299	sbi->update_file = hypfs_create_update_file(sb, root_dentry);
300	if (IS_ERR(sbi->update_file)) {
301		rc = PTR_ERR(sbi->update_file);
302		goto err_tree;
303	}
304	hypfs_update_update(sb);
305	sb->s_root = root_dentry;
306	return 0;
307
308err_tree:
309	hypfs_delete_tree(root_dentry);
310	d_genocide(root_dentry);
311	dput(root_dentry);
312err_alloc:
313	kfree(sbi);
314	return rc;
315}
316
317static int hypfs_get_super(struct file_system_type *fst, int flags,
318			const char *devname, void *data, struct vfsmount *mnt)
319{
320	return get_sb_single(fst, flags, data, hypfs_fill_super, mnt);
321}
322
323static void hypfs_kill_super(struct super_block *sb)
324{
325	struct hypfs_sb_info *sb_info = sb->s_fs_info;
326
327	if (sb->s_root) {
328		hypfs_delete_tree(sb->s_root);
329		hypfs_remove(sb_info->update_file);
330		kfree(sb->s_fs_info);
331		sb->s_fs_info = NULL;
332	}
333	kill_litter_super(sb);
334}
335
336static struct dentry *hypfs_create_file(struct super_block *sb,
337					struct dentry *parent, const char *name,
338					char *data, mode_t mode)
339{
340	struct dentry *dentry;
341	struct inode *inode;
342	struct qstr qname;
343
344	qname.name = name;
345	qname.len = strlen(name);
346	qname.hash = full_name_hash(name, qname.len);
347	dentry = lookup_one_len(name, parent, strlen(name));
348	if (IS_ERR(dentry))
349		return ERR_PTR(-ENOMEM);
350	inode = hypfs_make_inode(sb, mode);
351	if (!inode) {
352		dput(dentry);
353		return ERR_PTR(-ENOMEM);
354	}
355	if (mode & S_IFREG) {
356		inode->i_fop = &hypfs_file_ops;
357		if (data)
358			inode->i_size = strlen(data);
359		else
360			inode->i_size = 0;
361	} else if (mode & S_IFDIR) {
362		inode->i_op = &simple_dir_inode_operations;
363		inode->i_fop = &simple_dir_operations;
364		parent->d_inode->i_nlink++;
365	} else
366		BUG();
367	inode->i_private = data;
368	d_instantiate(dentry, inode);
369	dget(dentry);
370	return dentry;
371}
372
373struct dentry *hypfs_mkdir(struct super_block *sb, struct dentry *parent,
374			   const char *name)
375{
376	struct dentry *dentry;
377
378	dentry = hypfs_create_file(sb, parent, name, NULL, S_IFDIR | DIR_MODE);
379	if (IS_ERR(dentry))
380		return dentry;
381	hypfs_add_dentry(dentry);
382	parent->d_inode->i_nlink++;
383	return dentry;
384}
385
386static struct dentry *hypfs_create_update_file(struct super_block *sb,
387					       struct dentry *dir)
388{
389	struct dentry *dentry;
390
391	dentry = hypfs_create_file(sb, dir, "update", NULL,
392				   S_IFREG | UPDATE_FILE_MODE);
393	/*
394	 * We do not put the update file on the 'delete' list with
395	 * hypfs_add_dentry(), since it should not be removed when the tree
396	 * is updated.
397	 */
398	return dentry;
399}
400
401struct dentry *hypfs_create_u64(struct super_block *sb, struct dentry *dir,
402				const char *name, __u64 value)
403{
404	char *buffer;
405	char tmp[TMP_SIZE];
406	struct dentry *dentry;
407
408	snprintf(tmp, TMP_SIZE, "%lld\n", (unsigned long long int)value);
409	buffer = kstrdup(tmp, GFP_KERNEL);
410	if (!buffer)
411		return ERR_PTR(-ENOMEM);
412	dentry =
413	    hypfs_create_file(sb, dir, name, buffer, S_IFREG | REG_FILE_MODE);
414	if (IS_ERR(dentry)) {
415		kfree(buffer);
416		return ERR_PTR(-ENOMEM);
417	}
418	hypfs_add_dentry(dentry);
419	return dentry;
420}
421
422struct dentry *hypfs_create_str(struct super_block *sb, struct dentry *dir,
423				const char *name, char *string)
424{
425	char *buffer;
426	struct dentry *dentry;
427
428	buffer = kmalloc(strlen(string) + 2, GFP_KERNEL);
429	if (!buffer)
430		return ERR_PTR(-ENOMEM);
431	sprintf(buffer, "%s\n", string);
432	dentry =
433	    hypfs_create_file(sb, dir, name, buffer, S_IFREG | REG_FILE_MODE);
434	if (IS_ERR(dentry)) {
435		kfree(buffer);
436		return ERR_PTR(-ENOMEM);
437	}
438	hypfs_add_dentry(dentry);
439	return dentry;
440}
441
442static const struct file_operations hypfs_file_ops = {
443	.open		= hypfs_open,
444	.release	= hypfs_release,
445	.read		= do_sync_read,
446	.write		= do_sync_write,
447	.aio_read	= hypfs_aio_read,
448	.aio_write	= hypfs_aio_write,
449};
450
451static struct file_system_type hypfs_type = {
452	.owner		= THIS_MODULE,
453	.name		= "s390_hypfs",
454	.get_sb		= hypfs_get_super,
455	.kill_sb	= hypfs_kill_super
456};
457
458static struct super_operations hypfs_s_ops = {
459	.statfs		= simple_statfs,
460	.drop_inode	= hypfs_drop_inode,
461};
462
463static decl_subsys(s390, NULL, NULL);
464
465static int __init hypfs_init(void)
466{
467	int rc;
468
469	if (MACHINE_IS_VM) {
470		if (hypfs_vm_init())
471			/* no diag 2fc, just exit */
472			return -ENODATA;
473	} else {
474		if (hypfs_diag_init()) {
475			rc = -ENODATA;
476			goto fail_diag;
477		}
478	}
479	kobj_set_kset_s(&s390_subsys, hypervisor_subsys);
480	rc = subsystem_register(&s390_subsys);
481	if (rc)
482		goto fail_sysfs;
483	rc = register_filesystem(&hypfs_type);
484	if (rc)
485		goto fail_filesystem;
486	return 0;
487
488fail_filesystem:
489	subsystem_unregister(&s390_subsys);
490fail_sysfs:
491	if (!MACHINE_IS_VM)
492		hypfs_diag_exit();
493fail_diag:
494	printk(KERN_ERR "hypfs: Initialization failed with rc = %i.\n", rc);
495	return rc;
496}
497
498static void __exit hypfs_exit(void)
499{
500	if (!MACHINE_IS_VM)
501		hypfs_diag_exit();
502	unregister_filesystem(&hypfs_type);
503	subsystem_unregister(&s390_subsys);
504}
505
506module_init(hypfs_init)
507module_exit(hypfs_exit)
508
509MODULE_LICENSE("GPL");
510MODULE_AUTHOR("Michael Holzheu <holzheu@de.ibm.com>");
511MODULE_DESCRIPTION("s390 Hypervisor Filesystem");
512