OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [fs/] [super.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1627 jcastillo
/*
2
 *  linux/fs/super.c
3
 *
4
 *  Copyright (C) 1991, 1992  Linus Torvalds
5
 *
6
 *  super.c contains code to handle: - mount structures
7
 *                                   - super-block tables.
8
 *                                   - mount systemcall
9
 *                                   - umount systemcall
10
 *
11
 *  Added options to /proc/mounts
12
 *  Torbjörn Lindh (torbjorn.lindh@gopta.se), April 14, 1996.
13
 *
14
 * GK 2/5/95  -  Changed to support mounting the root fs via NFS
15
 *
16
 *  Added kerneld support: Jacques Gelinas and Bjorn Ekwall
17
 *  Added change_root: Werner Almesberger & Hans Lermen, Feb '96
18
 */
19
 
20
/*
21
 * uClinux revisions for NO_MM
22
 * Copyright (C) 1998  Kenneth Albanowski <kjahds@kjahds.com>,
23
 *                     The Silver Hammer Group, Ltd.
24
 */
25
 
26
#include <stdarg.h>
27
 
28
#include <linux/config.h>
29
#include <linux/sched.h>
30
#include <linux/kernel.h>
31
#include <linux/mount.h>
32
#include <linux/malloc.h>
33
#include <linux/major.h>
34
#include <linux/stat.h>
35
#include <linux/errno.h>
36
#include <linux/string.h>
37
#include <linux/locks.h>
38
#include <linux/mm.h>
39
#include <linux/fd.h>
40
 
41
#include <asm/system.h>
42
#include <asm/segment.h>
43
#include <asm/bitops.h>
44
 
45
#ifdef CONFIG_KERNELD
46
#include <linux/kerneld.h>
47
#endif
48
 
49
#include <linux/nfs_fs.h>
50
#include <linux/nfs_fs_sb.h>
51
#include <linux/nfs_mount.h>
52
 
53
extern void wait_for_keypress(void);
54
extern struct file_operations * get_blkfops(unsigned int major);
55
extern void blkdev_release (struct inode *);
56
extern void rd_load_secondary(void);
57
 
58
extern int root_mountflags;
59
 
60
static int do_remount_sb(struct super_block *sb, int flags, char * data);
61
 
62
/* this is initialized in init/main.c */
63
kdev_t ROOT_DEV;
64
 
65
struct super_block super_blocks[NR_SUPER];
66
static struct file_system_type *file_systems = (struct file_system_type *) NULL;
67
static struct vfsmount *vfsmntlist = (struct vfsmount *) NULL,
68
                       *vfsmnttail = (struct vfsmount *) NULL,
69
                       *mru_vfsmnt = (struct vfsmount *) NULL;
70
 
71
/*
72
 * This part handles the management of the list of mounted filesystems.
73
 */
74
struct vfsmount *lookup_vfsmnt(kdev_t dev)
75
{
76
        struct vfsmount *lptr;
77
 
78
        if (vfsmntlist == (struct vfsmount *)NULL)
79
                return ((struct vfsmount *)NULL);
80
 
81
        if (mru_vfsmnt != (struct vfsmount *)NULL &&
82
            mru_vfsmnt->mnt_dev == dev)
83
                return (mru_vfsmnt);
84
 
85
        for (lptr = vfsmntlist;
86
             lptr != (struct vfsmount *)NULL;
87
             lptr = lptr->mnt_next)
88
                if (lptr->mnt_dev == dev) {
89
                        mru_vfsmnt = lptr;
90
                        return (lptr);
91
                }
92
 
93
        return ((struct vfsmount *)NULL);
94
        /* NOTREACHED */
95
}
96
 
97
struct vfsmount *add_vfsmnt(kdev_t dev, const char *dev_name, const char *dir_name)
98
{
99
        struct vfsmount *lptr;
100
        char *tmp;
101
 
102
        lptr = (struct vfsmount *)kmalloc(sizeof(struct vfsmount), GFP_KERNEL);
103
        if (!lptr)
104
                return NULL;
105
        memset(lptr, 0, sizeof(struct vfsmount));
106
 
107
        lptr->mnt_dev = dev;
108
        lptr->mnt_sem.count = 1;
109
        if (dev_name && !getname(dev_name, &tmp)) {
110
                if ((lptr->mnt_devname =
111
                    (char *) kmalloc(strlen(tmp)+1, GFP_KERNEL)) != (char *)NULL)
112
                        strcpy(lptr->mnt_devname, tmp);
113
                putname(tmp);
114
        }
115
        if (dir_name && !getname(dir_name, &tmp)) {
116
                if ((lptr->mnt_dirname =
117
                    (char *) kmalloc(strlen(tmp)+1, GFP_KERNEL)) != (char *)NULL)
118
                        strcpy(lptr->mnt_dirname, tmp);
119
                putname(tmp);
120
        }
121
 
122
        if (vfsmntlist == (struct vfsmount *)NULL) {
123
                vfsmntlist = vfsmnttail = lptr;
124
        } else {
125
                vfsmnttail->mnt_next = lptr;
126
                vfsmnttail = lptr;
127
        }
128
        return (lptr);
129
}
130
 
131
void remove_vfsmnt(kdev_t dev)
132
{
133
        struct vfsmount *lptr, *tofree;
134
 
135
        if (vfsmntlist == (struct vfsmount *)NULL)
136
                return;
137
        lptr = vfsmntlist;
138
        if (lptr->mnt_dev == dev) {
139
                tofree = lptr;
140
                vfsmntlist = lptr->mnt_next;
141
                if (vfsmnttail->mnt_dev == dev)
142
                        vfsmnttail = vfsmntlist;
143
        } else {
144
                while (lptr->mnt_next != (struct vfsmount *)NULL) {
145
                        if (lptr->mnt_next->mnt_dev == dev)
146
                                break;
147
                        lptr = lptr->mnt_next;
148
                }
149
                tofree = lptr->mnt_next;
150
                if (tofree == (struct vfsmount *)NULL)
151
                        return;
152
                lptr->mnt_next = lptr->mnt_next->mnt_next;
153
                if (vfsmnttail->mnt_dev == dev)
154
                        vfsmnttail = lptr;
155
        }
156
        if (tofree == mru_vfsmnt)
157
                mru_vfsmnt = NULL;
158
        kfree(tofree->mnt_devname);
159
        kfree(tofree->mnt_dirname);
160
        kfree_s(tofree, sizeof(struct vfsmount));
161
}
162
 
163
int register_filesystem(struct file_system_type * fs)
164
{
165
        struct file_system_type ** tmp;
166
 
167
        if (!fs)
168
                return -EINVAL;
169
        if (fs->next)
170
                return -EBUSY;
171
        tmp = &file_systems;
172
        while (*tmp) {
173
                if (strcmp((*tmp)->name, fs->name) == 0)
174
                        return -EBUSY;
175
                tmp = &(*tmp)->next;
176
        }
177
        *tmp = fs;
178
        return 0;
179
}
180
 
181
#ifdef CONFIG_MODULES
182
int unregister_filesystem(struct file_system_type * fs)
183
{
184
        struct file_system_type ** tmp;
185
 
186
        tmp = &file_systems;
187
        while (*tmp) {
188
                if (fs == *tmp) {
189
                        *tmp = fs->next;
190
                        fs->next = NULL;
191
                        return 0;
192
                }
193
                tmp = &(*tmp)->next;
194
        }
195
        return -EINVAL;
196
}
197
#endif
198
 
199
static int fs_index(const char * __name)
200
{
201
        struct file_system_type * tmp;
202
        char * name;
203
        int err, index;
204
 
205
        err = getname(__name, &name);
206
        if (err)
207
                return err;
208
        index = 0;
209
        for (tmp = file_systems ; tmp ; tmp = tmp->next) {
210
                if (strcmp(tmp->name, name) == 0) {
211
                        putname(name);
212
                        return index;
213
                }
214
                index++;
215
        }
216
        putname(name);
217
        return -EINVAL;
218
}
219
 
220
static int fs_name(unsigned int index, char * buf)
221
{
222
        struct file_system_type * tmp;
223
        int err, len;
224
 
225
        tmp = file_systems;
226
        while (tmp && index > 0) {
227
                tmp = tmp->next;
228
                index--;
229
        }
230
        if (!tmp)
231
                return -EINVAL;
232
        len = strlen(tmp->name) + 1;
233
        err = verify_area(VERIFY_WRITE, buf, len);
234
        if (err)
235
                return err;
236
        memcpy_tofs(buf, tmp->name, len);
237
        return 0;
238
}
239
 
240
static int fs_maxindex(void)
241
{
242
        struct file_system_type * tmp;
243
        int index;
244
 
245
        index = 0;
246
        for (tmp = file_systems ; tmp ; tmp = tmp->next)
247
                index++;
248
        return index;
249
}
250
 
251
/*
252
 * Whee.. Weird sysv syscall.
253
 */
254
asmlinkage int sys_sysfs(int option, ...)
255
{
256
        va_list args;
257
        int retval = -EINVAL;
258
        unsigned int index;
259
 
260
        va_start(args, option);
261
        switch (option) {
262
                case 1:
263
                        retval = fs_index(va_arg(args, const char *));
264
                        break;
265
 
266
                case 2:
267
                        index = va_arg(args, unsigned int);
268
                        retval = fs_name(index, va_arg(args, char *));
269
                        break;
270
 
271
                case 3:
272
                        retval = fs_maxindex();
273
                        break;
274
        }
275
        va_end(args);
276
        return retval;
277
}
278
 
279
static struct proc_fs_info {
280
        int flag;
281
        char *str;
282
} fs_info[] = {
283
        { MS_NOEXEC, ",noexec" },
284
        { MS_NOSUID, ",nosuid" },
285
        { MS_NODEV, ",nodev" },
286
        { MS_SYNCHRONOUS, ",sync" },
287
        { MS_MANDLOCK, ",mand" },
288
        { MS_NOATIME, ",noatime" },
289
#ifdef MS_NOSUB                 /* Can't find this except in mount.c */
290
        { MS_NOSUB, ",nosub" },
291
#endif
292
        { 0, NULL }
293
};
294
 
295
static struct proc_nfs_info {
296
        int flag;
297
        char *str;
298
} nfs_info[] = {
299
        { NFS_MOUNT_SOFT, ",soft" },
300
        { NFS_MOUNT_INTR, ",intr" },
301
        { NFS_MOUNT_POSIX, ",posix" },
302
        { NFS_MOUNT_NOCTO, ",nocto" },
303
        { NFS_MOUNT_NOAC, ",noac" },
304
        { 0, NULL }
305
};
306
 
307
int get_filesystem_info( char *buf )
308
{
309
        struct vfsmount *tmp = vfsmntlist;
310
        struct proc_fs_info *fs_infop;
311
        struct proc_nfs_info *nfs_infop;
312
        struct nfs_server *nfss;
313
        int len = 0;
314
 
315
        while ( tmp && len < PAGE_SIZE - 160)
316
        {
317
                len += sprintf( buf + len, "%s %s %s %s",
318
                        tmp->mnt_devname, tmp->mnt_dirname, tmp->mnt_sb->s_type->name,
319
                        tmp->mnt_flags & MS_RDONLY ? "ro" : "rw" );
320
                for (fs_infop = fs_info; fs_infop->flag; fs_infop++) {
321
                  if (tmp->mnt_flags & fs_infop->flag) {
322
                    strcpy(buf + len, fs_infop->str);
323
                    len += strlen(fs_infop->str);
324
                  }
325
                }
326
                if (!strcmp("nfs", tmp->mnt_sb->s_type->name)) {
327
                        nfss = &tmp->mnt_sb->u.nfs_sb.s_server;
328
                        if (nfss->rsize != NFS_DEF_FILE_IO_BUFFER_SIZE) {
329
                                len += sprintf(buf+len, ",rsize=%d",
330
                                               nfss->rsize);
331
                        }
332
                        if (nfss->wsize != NFS_DEF_FILE_IO_BUFFER_SIZE) {
333
                                len += sprintf(buf+len, ",wsize=%d",
334
                                               nfss->wsize);
335
                        }
336
                        if (nfss->timeo != 7*HZ/10) {
337
                                len += sprintf(buf+len, ",timeo=%d",
338
                                               nfss->timeo*10/HZ);
339
                        }
340
                        if (nfss->retrans != 3) {
341
                                len += sprintf(buf+len, ",retrans=%d",
342
                                               nfss->retrans);
343
                        }
344
                        if (nfss->acregmin != 3*HZ) {
345
                                len += sprintf(buf+len, ",acregmin=%d",
346
                                               nfss->acregmin/HZ);
347
                        }
348
                        if (nfss->acregmax != 60*HZ) {
349
                                len += sprintf(buf+len, ",acregmax=%d",
350
                                               nfss->acregmax/HZ);
351
                        }
352
                        if (nfss->acdirmin != 30*HZ) {
353
                                len += sprintf(buf+len, ",acdirmin=%d",
354
                                               nfss->acdirmin/HZ);
355
                        }
356
                        if (nfss->acdirmax != 60*HZ) {
357
                                len += sprintf(buf+len, ",acdirmax=%d",
358
                                               nfss->acdirmax/HZ);
359
                        }
360
                        for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) {
361
                                if (nfss->flags & nfs_infop->flag) {
362
                                        strcpy(buf + len, nfs_infop->str);
363
                                        len += strlen(nfs_infop->str);
364
                                }
365
                        }
366
                        len += sprintf(buf+len, ",addr=%s",
367
                                       nfss->hostname);
368
                }
369
                len += sprintf( buf + len, " 0 0\n" );
370
                tmp = tmp->mnt_next;
371
        }
372
 
373
        return len;
374
}
375
 
376
int get_filesystem_list(char * buf)
377
{
378
        int len = 0;
379
        struct file_system_type * tmp;
380
 
381
        tmp = file_systems;
382
        while (tmp && len < PAGE_SIZE - 80) {
383
                len += sprintf(buf+len, "%s\t%s\n",
384
                        tmp->requires_dev ? "" : "nodev",
385
                        tmp->name);
386
                tmp = tmp->next;
387
        }
388
        return len;
389
}
390
 
391
struct file_system_type *get_fs_type(const char *name)
392
{
393
        struct file_system_type * fs = file_systems;
394
 
395
        if (!name)
396
                return fs;
397
        for (fs = file_systems; fs && strcmp(fs->name, name); fs = fs->next)
398
                ;
399
#ifdef CONFIG_KERNELD
400
        if (!fs && (request_module(name) == 0)) {
401
                for (fs = file_systems; fs && strcmp(fs->name, name); fs = fs->next)
402
                        ;
403
        }
404
#endif
405
 
406
        return fs;
407
}
408
 
409
void __wait_on_super(struct super_block * sb)
410
{
411
        struct wait_queue wait = { current, NULL };
412
 
413
        add_wait_queue(&sb->s_wait, &wait);
414
repeat:
415
        current->state = TASK_UNINTERRUPTIBLE;
416
        if (sb->s_lock) {
417
                schedule();
418
                goto repeat;
419
        }
420
        remove_wait_queue(&sb->s_wait, &wait);
421
        current->state = TASK_RUNNING;
422
}
423
 
424
void sync_supers(kdev_t dev)
425
{
426
        struct super_block * sb;
427
 
428
        for (sb = super_blocks + 0 ; sb < super_blocks + NR_SUPER ; sb++) {
429
                if (!sb->s_dev)
430
                        continue;
431
                if (dev && sb->s_dev != dev)
432
                        continue;
433
                wait_on_super(sb);
434
                if (!sb->s_dev || !sb->s_dirt)
435
                        continue;
436
                if (dev && (dev != sb->s_dev))
437
                        continue;
438
                if (sb->s_op && sb->s_op->write_super)
439
                        sb->s_op->write_super(sb);
440
        }
441
}
442
 
443
static struct super_block * get_super(kdev_t dev)
444
{
445
        struct super_block * s;
446
 
447
        if (!dev)
448
                return NULL;
449
        s = 0+super_blocks;
450
        while (s < NR_SUPER+super_blocks)
451
                if (s->s_dev == dev) {
452
                        wait_on_super(s);
453
                        if (s->s_dev == dev)
454
                                return s;
455
                        s = 0+super_blocks;
456
                } else
457
                        s++;
458
        return NULL;
459
}
460
 
461
void put_super(kdev_t dev)
462
{
463
        struct super_block * sb;
464
 
465
        if (dev == ROOT_DEV) {
466
                printk("VFS: Root device %s: prepare for armageddon\n",
467
                       kdevname(dev));
468
                return;
469
        }
470
        if (!(sb = get_super(dev)))
471
                return;
472
        if (sb->s_covered) {
473
                printk("VFS: Mounted device %s - tssk, tssk\n",
474
                       kdevname(dev));
475
                return;
476
        }
477
        if (sb->s_op && sb->s_op->put_super)
478
                sb->s_op->put_super(sb);
479
}
480
 
481
asmlinkage int sys_ustat(dev_t dev, struct ustat * ubuf)
482
{
483
        struct super_block *s;
484
        struct ustat tmp;
485
        struct statfs sbuf;
486
        unsigned long old_fs;
487
        int error;
488
 
489
        s = get_super(to_kdev_t(dev));
490
        if (s == NULL)
491
                return -EINVAL;
492
 
493
        if (!(s->s_op->statfs))
494
                return -ENOSYS;
495
 
496
        error = verify_area(VERIFY_WRITE,ubuf,sizeof(struct ustat));
497
        if (error)
498
                return error;
499
 
500
        old_fs = get_fs();
501
        set_fs(get_ds());
502
        s->s_op->statfs(s,&sbuf,sizeof(struct statfs));
503
        set_fs(old_fs);
504
 
505
        memset(&tmp,0,sizeof(struct ustat));
506
        tmp.f_tfree = sbuf.f_bfree;
507
        tmp.f_tinode = sbuf.f_ffree;
508
 
509
        memcpy_tofs(ubuf,&tmp,sizeof(struct ustat));
510
        return 0;
511
}
512
 
513
static struct super_block * read_super(kdev_t dev,const char *name,int flags,
514
                                       void *data, int silent)
515
{
516
        struct super_block * s;
517
        struct file_system_type *type;
518
 
519
        if (!dev)
520
                return NULL;
521
        check_disk_change(dev);
522
        s = get_super(dev);
523
        if (s)
524
                return s;
525
        if (!(type = get_fs_type(name))) {
526
                printk("VFS: on device %s: get_fs_type(%s) failed\n",
527
                       kdevname(dev), name);
528
                return NULL;
529
        }
530
        for (s = 0+super_blocks ;; s++) {
531
                if (s >= NR_SUPER+super_blocks)
532
                        return NULL;
533
                if (!(s->s_dev))
534
                        break;
535
        }
536
        s->s_dev = dev;
537
        s->s_flags = flags;
538
        if (!type->read_super(s,data, silent)) {
539
                s->s_dev = 0;
540
                return NULL;
541
        }
542
        s->s_dev = dev;
543
        s->s_covered = NULL;
544
        s->s_rd_only = 0;
545
        s->s_dirt = 0;
546
        s->s_type = type;
547
        return s;
548
}
549
 
550
/*
551
 * Unnamed block devices are dummy devices used by virtual
552
 * filesystems which don't use real block-devices.  -- jrs
553
 */
554
 
555
static unsigned int unnamed_dev_in_use[256/(8*sizeof(unsigned int))] = { 0, };
556
 
557
kdev_t get_unnamed_dev(void)
558
{
559
        int i;
560
 
561
        for (i = 1; i < 256; i++) {
562
                if (!set_bit(i,unnamed_dev_in_use))
563
                        return MKDEV(UNNAMED_MAJOR, i);
564
        }
565
        printk("VFS: Sorry, out of unnamed devices\n");
566
        return 0;
567
}
568
 
569
void put_unnamed_dev(kdev_t dev)
570
{
571
        if (!dev)
572
                return;
573
        if (MAJOR(dev) == UNNAMED_MAJOR &&
574
            clear_bit(MINOR(dev), unnamed_dev_in_use))
575
                return;
576
        printk("VFS: put_unnamed_dev: freeing unused device %s\n",
577
                        kdevname(dev));
578
}
579
 
580
static int do_umount(kdev_t dev,int unmount_root)
581
{
582
        struct super_block * sb;
583
        int retval;
584
 
585
        if (dev==ROOT_DEV && !unmount_root) {
586
                /*
587
                 * Special case for "unmounting" root. We just try to remount
588
                 * it readonly, and sync() the device.
589
                 */
590
                if (!(sb=get_super(dev)))
591
                        return -ENOENT;
592
                if (!(sb->s_flags & MS_RDONLY)) {
593
                        /*
594
                         * Make sure all quotas are turned off on this device we need to mount
595
                         * it readonly so no more writes by the quotasystem.
596
                         * If later on the remount fails too bad there are no quotas running
597
                         * anymore. Turn them on again by hand.
598
                         */
599
                        quota_off(dev, -1);
600
                        fsync_dev(dev);
601
                        retval = do_remount_sb(sb, MS_RDONLY, 0);
602
                        if (retval)
603
                                return retval;
604
                }
605
                return 0;
606
        }
607
        if (!(sb=get_super(dev)) || !(sb->s_covered))
608
                return -ENOENT;
609
        if (!sb->s_covered->i_mount)
610
                printk("VFS: umount(%s): mounted inode has i_mount=NULL\n",
611
                       kdevname(dev));
612
        /*
613
         * Before checking if the filesystem is still busy make sure the kernel
614
         * doesn't hold any quotafiles open on that device. If the umount fails
615
         * too bad there are no quotas running anymore. Turn them on again by hand.
616
         */
617
        quota_off(dev, -1);
618
        if (!fs_may_umount(dev, sb->s_mounted))
619
                return -EBUSY;
620
        sb->s_covered->i_mount = NULL;
621
        iput(sb->s_covered);
622
        sb->s_covered = NULL;
623
        iput(sb->s_mounted);
624
        sb->s_mounted = NULL;
625
        if (sb->s_op && sb->s_op->write_super && sb->s_dirt)
626
                sb->s_op->write_super(sb);
627
        put_super(dev);
628
        remove_vfsmnt(dev);
629
        return 0;
630
}
631
 
632
/*
633
 * Now umount can handle mount points as well as block devices.
634
 * This is important for filesystems which use unnamed block devices.
635
 *
636
 * There is a little kludge here with the dummy_inode.  The current
637
 * vfs release functions only use the r_dev field in the inode so
638
 * we give them the info they need without using a real inode.
639
 * If any other fields are ever needed by any block device release
640
 * functions, they should be faked here.  -- jrs
641
 */
642
 
643
asmlinkage int sys_umount(char * name)
644
{
645
        struct inode * inode;
646
        kdev_t dev;
647
        int retval;
648
        struct inode dummy_inode;
649
 
650
        if (!suser())
651
                return -EPERM;
652
        retval = namei(name, &inode);
653
        if (retval) {
654
                retval = lnamei(name, &inode);
655
                if (retval)
656
                        return retval;
657
        }
658
        if (S_ISBLK(inode->i_mode)) {
659
                dev = inode->i_rdev;
660
                if (IS_NODEV(inode)) {
661
                        iput(inode);
662
                        return -EACCES;
663
                }
664
        } else {
665
                if (!inode->i_sb || inode != inode->i_sb->s_mounted) {
666
                        iput(inode);
667
                        return -EINVAL;
668
                }
669
                dev = inode->i_sb->s_dev;
670
                iput(inode);
671
                memset(&dummy_inode, 0, sizeof(dummy_inode));
672
                dummy_inode.i_rdev = dev;
673
                inode = &dummy_inode;
674
        }
675
        if (MAJOR(dev) >= MAX_BLKDEV) {
676
                iput(inode);
677
                return -ENXIO;
678
        }
679
        retval = do_umount(dev,0);
680
        if (!retval) {
681
                fsync_dev(dev);
682
                if (dev != ROOT_DEV) {
683
                        blkdev_release (inode);
684
                        if (MAJOR(dev) == UNNAMED_MAJOR)
685
                                put_unnamed_dev(dev);
686
                }
687
        }
688
        if (inode != &dummy_inode)
689
                iput(inode);
690
        if (retval)
691
                return retval;
692
        fsync_dev(dev);
693
        return 0;
694
}
695
 
696
/*
697
 * do_mount() does the actual mounting after sys_mount has done the ugly
698
 * parameter parsing. When enough time has gone by, and everything uses the
699
 * new mount() parameters, sys_mount() can then be cleaned up.
700
 *
701
 * We cannot mount a filesystem if it has active, used, or dirty inodes.
702
 * We also have to flush all inode-data for this device, as the new mount
703
 * might need new info.
704
 */
705
 
706
int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, const char * type, int flags, void * data)
707
{
708
        struct inode * dir_i;
709
        struct super_block * sb;
710
        struct vfsmount *vfsmnt;
711
        int error;
712
 
713
        if (!(flags & MS_RDONLY) && dev && is_read_only(dev))
714
                return -EACCES;
715
                /*flags |= MS_RDONLY;*/
716
        error = namei(dir_name, &dir_i);
717
        if (error)
718
                return error;
719
        if (dir_i->i_count != 1 || dir_i->i_mount) {
720
                iput(dir_i);
721
                return -EBUSY;
722
        }
723
        if (!S_ISDIR(dir_i->i_mode)) {
724
                iput(dir_i);
725
                return -ENOTDIR;
726
        }
727
        if (!fs_may_mount(dev)) {
728
                iput(dir_i);
729
                return -EBUSY;
730
        }
731
        sb = read_super(dev,type,flags,data,0);
732
        if (!sb) {
733
                iput(dir_i);
734
                return -EINVAL;
735
        }
736
        if (sb->s_covered) {
737
                iput(dir_i);
738
                return -EBUSY;
739
        }
740
        vfsmnt = add_vfsmnt(dev, dev_name, dir_name);
741
        if (vfsmnt) {
742
                vfsmnt->mnt_sb = sb;
743
                vfsmnt->mnt_flags = flags;
744
        }
745
        sb->s_covered = dir_i;
746
        dir_i->i_mount = sb->s_mounted;
747
        return 0;                /* we don't iput(dir_i) - see umount */
748
}
749
 
750
 
751
/*
752
 * Alters the mount flags of a mounted file system. Only the mount point
753
 * is used as a reference - file system type and the device are ignored.
754
 * FS-specific mount options can't be altered by remounting.
755
 */
756
 
757
static int do_remount_sb(struct super_block *sb, int flags, char *data)
758
{
759
        int retval;
760
        struct vfsmount *vfsmnt;
761
 
762
        if (!(flags & MS_RDONLY) && sb->s_dev && is_read_only(sb->s_dev))
763
                return -EACCES;
764
                /*flags |= MS_RDONLY;*/
765
        /* If we are remounting RDONLY, make sure there are no rw files open */
766
        if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY))
767
                if (!fs_may_remount_ro(sb->s_dev))
768
                        return -EBUSY;
769
        if (sb->s_op && sb->s_op->remount_fs) {
770
                retval = sb->s_op->remount_fs(sb, &flags, data);
771
                if (retval)
772
                        return retval;
773
        }
774
        sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);
775
        vfsmnt = lookup_vfsmnt(sb->s_dev);
776
        if (vfsmnt)
777
                vfsmnt->mnt_flags = sb->s_flags;
778
        return 0;
779
}
780
 
781
static int do_remount(const char *dir,int flags,char *data)
782
{
783
        struct inode *dir_i;
784
        int retval;
785
 
786
        retval = namei(dir, &dir_i);
787
        if (retval)
788
                return retval;
789
        if (dir_i != dir_i->i_sb->s_mounted) {
790
                iput(dir_i);
791
                return -EINVAL;
792
        }
793
        retval = do_remount_sb(dir_i->i_sb, flags, data);
794
        iput(dir_i);
795
        return retval;
796
}
797
 
798
static int copy_mount_options (const void * data, unsigned long *where)
799
{
800
        int i;
801
        unsigned long page;
802
#ifndef NO_MM
803
        struct vm_area_struct * vma;
804
#endif /* !NO_MM */
805
 
806
        *where = 0;
807
        if (!data)
808
                return 0;
809
 
810
#ifndef NO_MM
811
        vma = find_vma(current->mm, (unsigned long) data);
812
        if (!vma || (unsigned long) data < vma->vm_start)
813
                return -EFAULT;
814
        if (!(vma->vm_flags & VM_READ))
815
                return -EFAULT;
816
        i = vma->vm_end - (unsigned long) data;
817
        if (PAGE_SIZE <= (unsigned long) i)
818
                i = PAGE_SIZE-1;
819
#else /* NO_MM */
820
        i = PAGE_SIZE-1;
821
#endif /* NO_MM */
822
        if (!(page = __get_free_page(GFP_KERNEL))) {
823
                return -ENOMEM;
824
        }
825
        memcpy_fromfs((void *) page,data,i);
826
        *where = page;
827
        return 0;
828
}
829
 
830
/*
831
 * Flags is a 16-bit value that allows up to 16 non-fs dependent flags to
832
 * be given to the mount() call (ie: read-only, no-dev, no-suid etc).
833
 *
834
 * data is a (void *) that can point to any structure up to
835
 * PAGE_SIZE-1 bytes, which can contain arbitrary fs-dependent
836
 * information (or be NULL).
837
 *
838
 * NOTE! As old versions of mount() didn't use this setup, the flags
839
 * has to have a special 16-bit magic number in the hight word:
840
 * 0xC0ED. If this magic word isn't present, the flags and data info
841
 * isn't used, as the syscall assumes we are talking to an older
842
 * version that didn't understand them.
843
 */
844
asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
845
        unsigned long new_flags, void * data)
846
{
847
        struct file_system_type * fstype;
848
        struct inode * inode;
849
        struct file_operations * fops;
850
        kdev_t dev;
851
        int retval;
852
        const char * t;
853
        unsigned long flags = 0;
854
        unsigned long page = 0;
855
 
856
        if (!suser())
857
                return -EPERM;
858
        if ((new_flags &
859
             (MS_MGC_MSK | MS_REMOUNT)) == (MS_MGC_VAL | MS_REMOUNT)) {
860
                retval = copy_mount_options (data, &page);
861
                if (retval < 0)
862
                        return retval;
863
                retval = do_remount(dir_name,
864
                                    new_flags & ~MS_MGC_MSK & ~MS_REMOUNT,
865
                                    (char *) page);
866
                free_page(page);
867
                return retval;
868
        }
869
        retval = copy_mount_options (type, &page);
870
        if (retval < 0)
871
                return retval;
872
        fstype = get_fs_type((char *) page);
873
        free_page(page);
874
        if (!fstype)
875
                return -ENODEV;
876
        t = fstype->name;
877
        fops = NULL;
878
        if (fstype->requires_dev) {
879
                retval = namei(dev_name, &inode);
880
                if (retval)
881
                        return retval;
882
                if (!S_ISBLK(inode->i_mode)) {
883
                        iput(inode);
884
                        return -ENOTBLK;
885
                }
886
                if (IS_NODEV(inode)) {
887
                        iput(inode);
888
                        return -EACCES;
889
                }
890
                dev = inode->i_rdev;
891
                if (MAJOR(dev) >= MAX_BLKDEV) {
892
                        iput(inode);
893
                        return -ENXIO;
894
                }
895
                fops = get_blkfops(MAJOR(dev));
896
                if (!fops) {
897
                        iput(inode);
898
                        return -ENOTBLK;
899
                }
900
                if (fops->open) {
901
                        struct file dummy;      /* allows read-write or read-only flag */
902
                        memset(&dummy, 0, sizeof(dummy));
903
                        dummy.f_inode = inode;
904
                        dummy.f_mode = (new_flags & MS_RDONLY) ? 1 : 3;
905
                        retval = fops->open(inode, &dummy);
906
                        if (retval) {
907
                                iput(inode);
908
                                return retval;
909
                        }
910
                }
911
 
912
        } else {
913
                if (!(dev = get_unnamed_dev()))
914
                        return -EMFILE;
915
                inode = NULL;
916
        }
917
        page = 0;
918
        if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL) {
919
                flags = new_flags & ~MS_MGC_MSK;
920
                retval = copy_mount_options(data, &page);
921
                if (retval < 0) {
922
                        iput(inode);
923
                        return retval;
924
                }
925
        }
926
        retval = do_mount(dev,dev_name,dir_name,t,flags,(void *) page);
927
        free_page(page);
928
        if (retval && !fstype->requires_dev)
929
                put_unnamed_dev(dev);
930
        if (retval && fops && fops->release)
931
                fops->release(inode, NULL);
932
        iput(inode);
933
        return retval;
934
}
935
 
936
static void do_mount_root(void)
937
{
938
        struct file_system_type * fs_type;
939
        struct super_block * sb;
940
        struct vfsmount *vfsmnt;
941
        struct inode * inode, d_inode;
942
        struct file filp;
943
        int retval;
944
 
945
#ifdef CONFIG_ROOT_NFS
946
        if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR)
947
                if (nfs_root_init(nfs_root_name, nfs_root_addrs) < 0) {
948
                        printk(KERN_ERR "Root-NFS: Unable to contact NFS "
949
                            "server for root fs, using /dev/fd0 instead\n");
950
                        ROOT_DEV = MKDEV(FLOPPY_MAJOR, 0);
951
                }
952
        if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) {
953
                ROOT_DEV = 0;
954
                if ((fs_type = get_fs_type("nfs"))) {
955
                        sb = &super_blocks[0];
956
                        while (sb->s_dev) sb++;
957
                        sb->s_dev = get_unnamed_dev();
958
                        sb->s_flags = root_mountflags & ~MS_RDONLY;
959
                        if (nfs_root_mount(sb) >= 0) {
960
                                inode = sb->s_mounted;
961
                                inode->i_count += 3 ;
962
                                sb->s_covered = inode;
963
                                sb->s_rd_only = 0;
964
                                sb->s_dirt = 0;
965
                                sb->s_type = fs_type;
966
                                current->fs->pwd = inode;
967
                                current->fs->root = inode;
968
                                ROOT_DEV = sb->s_dev;
969
                                printk (KERN_NOTICE "VFS: Mounted root (nfs filesystem).\n");
970
                                vfsmnt = add_vfsmnt(ROOT_DEV, "/dev/root", "/");
971
                                if (!vfsmnt)
972
                                        panic("VFS: add_vfsmnt failed for NFS root.\n");
973
                                vfsmnt->mnt_sb = sb;
974
                                vfsmnt->mnt_flags = sb->s_flags;
975
                                return;
976
                        }
977
                        sb->s_dev = 0;
978
                }
979
                if (!ROOT_DEV) {
980
                        printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n");
981
                        ROOT_DEV = MKDEV(FLOPPY_MAJOR, 0);
982
                }
983
        }
984
#endif
985
 
986
#ifdef CONFIG_BLK_DEV_FD
987
        if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {
988
#ifdef CONFIG_BLK_DEV_INITRD
989
                extern int rd_doload;
990
#endif
991
                floppy_eject();
992
#ifndef CONFIG_BLK_DEV_RAM
993
                printk(KERN_NOTICE "(Warning, this kernel has no ramdisk support)\n");
994
#endif
995
#ifdef CONFIG_BLK_DEV_INITRD
996
                /* rd_doload is 2 for a dual initrd/ramload setup */
997
                if(rd_doload==2)
998
                        rd_load_secondary();
999
                else
1000
#endif          
1001
                {
1002
                        printk(KERN_NOTICE "VFS: Insert root floppy and press ENTER\n");
1003
                        wait_for_keypress();
1004
                }
1005
        }
1006
#endif
1007
 
1008
        memset(&filp, 0, sizeof(filp));
1009
        memset(&d_inode, 0, sizeof(d_inode));
1010
        d_inode.i_rdev = ROOT_DEV;
1011
        filp.f_inode = &d_inode;
1012
        if ( root_mountflags & MS_RDONLY)
1013
                filp.f_mode = 1; /* read only */
1014
        else
1015
                filp.f_mode = 3; /* read write */
1016
 
1017
        retval = blkdev_open(&d_inode, &filp);
1018
        if (retval == -EROFS) {
1019
                root_mountflags |= MS_RDONLY;
1020
                filp.f_mode = 1;
1021
                retval = blkdev_open(&d_inode, &filp);
1022
        }
1023
 
1024
        if (retval)
1025
                /*
1026
                 * Allow the user to distinguish between failed open
1027
                 * and bad superblock on root device.
1028
                 */
1029
                printk("VFS: Cannot open root device %s\n",
1030
                       kdevname(ROOT_DEV));
1031
        else for (fs_type = file_systems ; fs_type ; fs_type = fs_type->next) {
1032
 
1033
                if (!fs_type->requires_dev)
1034
                        continue;
1035
 
1036
                sb = read_super(ROOT_DEV,fs_type->name,root_mountflags,NULL,0);
1037
                if (sb) {
1038
 
1039
                        inode = sb->s_mounted;
1040
                        inode->i_count += 3 ;   /* NOTE! it is logically used 4 times, not 1 */
1041
                        sb->s_covered = inode;
1042
                        sb->s_flags = root_mountflags;
1043
                        current->fs->pwd = inode;
1044
                        current->fs->root = inode;
1045
                        printk ("VFS: Mounted root (%s filesystem)%s.\n",
1046
                                fs_type->name,
1047
                                (sb->s_flags & MS_RDONLY) ? " readonly" : "");
1048
                        vfsmnt = add_vfsmnt(ROOT_DEV, "/dev/root", "/");
1049
                        if (!vfsmnt)
1050
                                panic("VFS: add_vfsmnt failed for root fs");
1051
                        vfsmnt->mnt_sb = sb;
1052
                        vfsmnt->mnt_flags = root_mountflags;
1053
                        return;
1054
                }
1055
        }
1056
        panic("VFS: Unable to mount root fs on %s",
1057
                kdevname(ROOT_DEV));
1058
}
1059
 
1060
 
1061
void mount_root(void)
1062
{
1063
        memset(super_blocks, 0, sizeof(super_blocks));
1064
        do_mount_root();
1065
}
1066
 
1067
 
1068
#ifdef CONFIG_BLK_DEV_INITRD
1069
 
1070
int change_root(kdev_t new_root_dev,const char *put_old)
1071
{
1072
        kdev_t old_root_dev;
1073
        struct vfsmount *vfsmnt;
1074
        struct inode *old_root,*old_pwd,*inode;
1075
        unsigned long old_fs;
1076
        int error;
1077
 
1078
        old_root = current->fs->root;
1079
        old_pwd = current->fs->pwd;
1080
        old_root_dev = ROOT_DEV;
1081
        if (!fs_may_mount(new_root_dev)) {
1082
                printk(KERN_CRIT "New root is busy. Staying in initrd.\n");
1083
                return -EBUSY;
1084
        }
1085
        ROOT_DEV = new_root_dev;
1086
        do_mount_root();
1087
        old_fs = get_fs();
1088
        set_fs(get_ds());
1089
        error = namei(put_old,&inode);
1090
        if (error) inode = NULL;
1091
        set_fs(old_fs);
1092
        if (!error && (inode->i_count != 1 || inode->i_mount)) error = -EBUSY;
1093
        if (!error && !S_ISDIR(inode->i_mode)) error = -ENOTDIR;
1094
        iput(old_root); /* current->fs->root */
1095
        iput(old_pwd); /* current->fs->pwd */
1096
        if (error) {
1097
                int umount_error;
1098
 
1099
                if (inode) iput(inode);
1100
                printk(KERN_NOTICE "Trying to unmount old root ... ");
1101
                old_root->i_mount = old_root;
1102
                        /* does this belong into do_mount_root ? */
1103
                umount_error = do_umount(old_root_dev,1);
1104
                if (umount_error) printk(KERN_ERR "error %d\n",umount_error);
1105
                else {
1106
                        printk("okay\n");
1107
                        invalidate_buffers(old_root_dev);
1108
                }
1109
                return umount_error ? error : 0;
1110
        }
1111
        iput(old_root); /* sb->s_covered */
1112
        remove_vfsmnt(old_root_dev);
1113
        vfsmnt = add_vfsmnt(old_root_dev,"/dev/root.old",put_old);
1114
        if (!vfsmnt) printk(KERN_CRIT "Trouble: add_vfsmnt failed\n");
1115
        else {
1116
                vfsmnt->mnt_sb = old_root->i_sb;
1117
                vfsmnt->mnt_sb->s_covered = inode;
1118
                vfsmnt->mnt_flags = vfsmnt->mnt_sb->s_flags;
1119
        }
1120
        inode->i_mount = old_root;
1121
        return 0;
1122
}
1123
 
1124
#endif

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.