~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to arch/s390/hypfs/inode.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

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