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

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [uclinux/] [uClinux-2.0.x/] [fs/] [super.c] - Blame information for rev 199

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
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
printk("%s - %s:%d\n",__FILE__,__FUNCTION__,__LINE__);
520
        if (!dev)
521
                return NULL;
522
printk("%s - %s:%d\n",__FILE__,__FUNCTION__,__LINE__);
523
        check_disk_change(dev);
524
        s = get_super(dev);
525
printk("%s - %s:%d\n",__FILE__,__FUNCTION__,__LINE__);
526
        if (s)
527
                return s;
528
printk("%s - %s:%d\n",__FILE__,__FUNCTION__,__LINE__);
529
        if (!(type = get_fs_type(name))) {
530
                printk("VFS: on device %s: get_fs_type(%s) failed\n",
531
                       kdevname(dev), name);
532
                return NULL;
533
        }
534
printk("%s - %s:%d\n",__FILE__,__FUNCTION__,__LINE__);
535
        for (s = 0+super_blocks ;; s++) {
536
                if (s >= NR_SUPER+super_blocks)
537
                        return NULL;
538
                if (!(s->s_dev))
539
                        break;
540
        }
541
printk("%s - %s:%d\n",__FILE__,__FUNCTION__,__LINE__);
542
        s->s_dev = dev;
543
        s->s_flags = flags;
544
        if (!type->read_super(s,data, silent)) {
545
                s->s_dev = 0;
546
                return NULL;
547
        }
548
printk("%s - %s:%d\n",__FILE__,__FUNCTION__,__LINE__);
549
        s->s_dev = dev;
550
        s->s_covered = NULL;
551
        s->s_rd_only = 0;
552
        s->s_dirt = 0;
553
        s->s_type = type;
554
        return s;
555
}
556
 
557
/*
558
 * Unnamed block devices are dummy devices used by virtual
559
 * filesystems which don't use real block-devices.  -- jrs
560
 */
561
 
562
static unsigned int unnamed_dev_in_use[256/(8*sizeof(unsigned int))] = { 0, };
563
 
564
kdev_t get_unnamed_dev(void)
565
{
566
        int i;
567
 
568
        for (i = 1; i < 256; i++) {
569
                if (!set_bit(i,unnamed_dev_in_use))
570
                        return MKDEV(UNNAMED_MAJOR, i);
571
        }
572
        printk("VFS: Sorry, out of unnamed devices\n");
573
        return 0;
574
}
575
 
576
void put_unnamed_dev(kdev_t dev)
577
{
578
        if (!dev)
579
                return;
580
        if (MAJOR(dev) == UNNAMED_MAJOR &&
581
            clear_bit(MINOR(dev), unnamed_dev_in_use))
582
                return;
583
        printk("VFS: put_unnamed_dev: freeing unused device %s\n",
584
                        kdevname(dev));
585
}
586
 
587
static int do_umount(kdev_t dev,int unmount_root)
588
{
589
        struct super_block * sb;
590
        int retval;
591
 
592
        if (dev==ROOT_DEV && !unmount_root) {
593
                /*
594
                 * Special case for "unmounting" root. We just try to remount
595
                 * it readonly, and sync() the device.
596
                 */
597
                if (!(sb=get_super(dev)))
598
                        return -ENOENT;
599
                if (!(sb->s_flags & MS_RDONLY)) {
600
                        /*
601
                         * Make sure all quotas are turned off on this device we need to mount
602
                         * it readonly so no more writes by the quotasystem.
603
                         * If later on the remount fails too bad there are no quotas running
604
                         * anymore. Turn them on again by hand.
605
                         */
606
                        quota_off(dev, -1);
607
                        fsync_dev(dev);
608
                        retval = do_remount_sb(sb, MS_RDONLY, 0);
609
                        if (retval)
610
                                return retval;
611
                }
612
                return 0;
613
        }
614
        if (!(sb=get_super(dev)) || !(sb->s_covered))
615
                return -ENOENT;
616
        if (!sb->s_covered->i_mount)
617
                printk("VFS: umount(%s): mounted inode has i_mount=NULL\n",
618
                       kdevname(dev));
619
        /*
620
         * Before checking if the filesystem is still busy make sure the kernel
621
         * doesn't hold any quotafiles open on that device. If the umount fails
622
         * too bad there are no quotas running anymore. Turn them on again by hand.
623
         */
624
        quota_off(dev, -1);
625
        if (!fs_may_umount(dev, sb->s_mounted))
626
                return -EBUSY;
627
        sb->s_covered->i_mount = NULL;
628
        iput(sb->s_covered);
629
        sb->s_covered = NULL;
630
        iput(sb->s_mounted);
631
        sb->s_mounted = NULL;
632
        if (sb->s_op && sb->s_op->write_super && sb->s_dirt)
633
                sb->s_op->write_super(sb);
634
        put_super(dev);
635
        remove_vfsmnt(dev);
636
        return 0;
637
}
638
 
639
/*
640
 * Now umount can handle mount points as well as block devices.
641
 * This is important for filesystems which use unnamed block devices.
642
 *
643
 * There is a little kludge here with the dummy_inode.  The current
644
 * vfs release functions only use the r_dev field in the inode so
645
 * we give them the info they need without using a real inode.
646
 * If any other fields are ever needed by any block device release
647
 * functions, they should be faked here.  -- jrs
648
 */
649
 
650
asmlinkage int sys_umount(char * name)
651
{
652
        struct inode * inode;
653
        kdev_t dev;
654
        int retval;
655
        struct inode dummy_inode;
656
 
657
        if (!suser())
658
                return -EPERM;
659
        retval = namei(name, &inode);
660
        if (retval) {
661
                retval = lnamei(name, &inode);
662
                if (retval)
663
                        return retval;
664
        }
665
        if (S_ISBLK(inode->i_mode)) {
666
                dev = inode->i_rdev;
667
                if (IS_NODEV(inode)) {
668
                        iput(inode);
669
                        return -EACCES;
670
                }
671
        } else {
672
                if (!inode->i_sb || inode != inode->i_sb->s_mounted) {
673
                        iput(inode);
674
                        return -EINVAL;
675
                }
676
                dev = inode->i_sb->s_dev;
677
                iput(inode);
678
                memset(&dummy_inode, 0, sizeof(dummy_inode));
679
                dummy_inode.i_rdev = dev;
680
                inode = &dummy_inode;
681
        }
682
        if (MAJOR(dev) >= MAX_BLKDEV) {
683
                iput(inode);
684
                return -ENXIO;
685
        }
686
        retval = do_umount(dev,0);
687
        if (!retval) {
688
                fsync_dev(dev);
689
                if (dev != ROOT_DEV) {
690
                        blkdev_release (inode);
691
                        if (MAJOR(dev) == UNNAMED_MAJOR)
692
                                put_unnamed_dev(dev);
693
                }
694
        }
695
        if (inode != &dummy_inode)
696
                iput(inode);
697
        if (retval)
698
                return retval;
699
        fsync_dev(dev);
700
        return 0;
701
}
702
 
703
/*
704
 * do_mount() does the actual mounting after sys_mount has done the ugly
705
 * parameter parsing. When enough time has gone by, and everything uses the
706
 * new mount() parameters, sys_mount() can then be cleaned up.
707
 *
708
 * We cannot mount a filesystem if it has active, used, or dirty inodes.
709
 * We also have to flush all inode-data for this device, as the new mount
710
 * might need new info.
711
 */
712
 
713
int do_mount(kdev_t dev, const char * dev_name, const char * dir_name, const char * type, int flags, void * data)
714
{
715
        struct inode * dir_i;
716
        struct super_block * sb;
717
        struct vfsmount *vfsmnt;
718
        int error;
719
 
720
        if (!(flags & MS_RDONLY) && dev && is_read_only(dev))
721
                return -EACCES;
722
                /*flags |= MS_RDONLY;*/
723
        error = namei(dir_name, &dir_i);
724
        if (error)
725
                return error;
726
        if (dir_i->i_count != 1 || dir_i->i_mount) {
727
                iput(dir_i);
728
                return -EBUSY;
729
        }
730
        if (!S_ISDIR(dir_i->i_mode)) {
731
                iput(dir_i);
732
                return -ENOTDIR;
733
        }
734
        if (!fs_may_mount(dev)) {
735
                iput(dir_i);
736
                return -EBUSY;
737
        }
738
        sb = read_super(dev,type,flags,data,0);
739
        if (!sb) {
740
                iput(dir_i);
741
                return -EINVAL;
742
        }
743
        if (sb->s_covered) {
744
                iput(dir_i);
745
                return -EBUSY;
746
        }
747
        vfsmnt = add_vfsmnt(dev, dev_name, dir_name);
748
        if (vfsmnt) {
749
                vfsmnt->mnt_sb = sb;
750
                vfsmnt->mnt_flags = flags;
751
        }
752
        sb->s_covered = dir_i;
753
        dir_i->i_mount = sb->s_mounted;
754
        return 0;                /* we don't iput(dir_i) - see umount */
755
}
756
 
757
 
758
/*
759
 * Alters the mount flags of a mounted file system. Only the mount point
760
 * is used as a reference - file system type and the device are ignored.
761
 * FS-specific mount options can't be altered by remounting.
762
 */
763
 
764
static int do_remount_sb(struct super_block *sb, int flags, char *data)
765
{
766
        int retval;
767
        struct vfsmount *vfsmnt;
768
 
769
        if (!(flags & MS_RDONLY) && sb->s_dev && is_read_only(sb->s_dev))
770
                return -EACCES;
771
                /*flags |= MS_RDONLY;*/
772
        /* If we are remounting RDONLY, make sure there are no rw files open */
773
        if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY))
774
                if (!fs_may_remount_ro(sb->s_dev))
775
                        return -EBUSY;
776
        if (sb->s_op && sb->s_op->remount_fs) {
777
                retval = sb->s_op->remount_fs(sb, &flags, data);
778
                if (retval)
779
                        return retval;
780
        }
781
        sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);
782
        vfsmnt = lookup_vfsmnt(sb->s_dev);
783
        if (vfsmnt)
784
                vfsmnt->mnt_flags = sb->s_flags;
785
        return 0;
786
}
787
 
788
static int do_remount(const char *dir,int flags,char *data)
789
{
790
        struct inode *dir_i;
791
        int retval;
792
 
793
        retval = namei(dir, &dir_i);
794
        if (retval)
795
                return retval;
796
        if (dir_i != dir_i->i_sb->s_mounted) {
797
                iput(dir_i);
798
                return -EINVAL;
799
        }
800
        retval = do_remount_sb(dir_i->i_sb, flags, data);
801
        iput(dir_i);
802
        return retval;
803
}
804
 
805
static int copy_mount_options (const void * data, unsigned long *where)
806
{
807
        int i;
808
        unsigned long page;
809
#ifndef NO_MM
810
        struct vm_area_struct * vma;
811
#endif /* !NO_MM */
812
 
813
        *where = 0;
814
        if (!data)
815
                return 0;
816
 
817
#ifndef NO_MM
818
        vma = find_vma(current->mm, (unsigned long) data);
819
        if (!vma || (unsigned long) data < vma->vm_start)
820
                return -EFAULT;
821
        if (!(vma->vm_flags & VM_READ))
822
                return -EFAULT;
823
        i = vma->vm_end - (unsigned long) data;
824
        if (PAGE_SIZE <= (unsigned long) i)
825
                i = PAGE_SIZE-1;
826
#else /* NO_MM */
827
        i = PAGE_SIZE-1;
828
#endif /* NO_MM */
829
        if (!(page = __get_free_page(GFP_KERNEL))) {
830
                return -ENOMEM;
831
        }
832
        memcpy_fromfs((void *) page,data,i);
833
        *where = page;
834
        return 0;
835
}
836
 
837
/*
838
 * Flags is a 16-bit value that allows up to 16 non-fs dependent flags to
839
 * be given to the mount() call (ie: read-only, no-dev, no-suid etc).
840
 *
841
 * data is a (void *) that can point to any structure up to
842
 * PAGE_SIZE-1 bytes, which can contain arbitrary fs-dependent
843
 * information (or be NULL).
844
 *
845
 * NOTE! As old versions of mount() didn't use this setup, the flags
846
 * has to have a special 16-bit magic number in the hight word:
847
 * 0xC0ED. If this magic word isn't present, the flags and data info
848
 * isn't used, as the syscall assumes we are talking to an older
849
 * version that didn't understand them.
850
 */
851
asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type,
852
        unsigned long new_flags, void * data)
853
{
854
        struct file_system_type * fstype;
855
        struct inode * inode;
856
        struct file_operations * fops;
857
        kdev_t dev;
858
        int retval;
859
        const char * t;
860
        unsigned long flags = 0;
861
        unsigned long page = 0;
862
 
863
        if (!suser())
864
                return -EPERM;
865
        if ((new_flags &
866
             (MS_MGC_MSK | MS_REMOUNT)) == (MS_MGC_VAL | MS_REMOUNT)) {
867
                retval = copy_mount_options (data, &page);
868
                if (retval < 0)
869
                        return retval;
870
                retval = do_remount(dir_name,
871
                                    new_flags & ~MS_MGC_MSK & ~MS_REMOUNT,
872
                                    (char *) page);
873
                free_page(page);
874
                return retval;
875
        }
876
        retval = copy_mount_options (type, &page);
877
        if (retval < 0)
878
                return retval;
879
        fstype = get_fs_type((char *) page);
880
        free_page(page);
881
        if (!fstype)
882
                return -ENODEV;
883
        t = fstype->name;
884
        fops = NULL;
885
        if (fstype->requires_dev) {
886
                retval = namei(dev_name, &inode);
887
                if (retval)
888
                        return retval;
889
                if (!S_ISBLK(inode->i_mode)) {
890
                        iput(inode);
891
                        return -ENOTBLK;
892
                }
893
                if (IS_NODEV(inode)) {
894
                        iput(inode);
895
                        return -EACCES;
896
                }
897
                dev = inode->i_rdev;
898
                if (MAJOR(dev) >= MAX_BLKDEV) {
899
                        iput(inode);
900
                        return -ENXIO;
901
                }
902
                fops = get_blkfops(MAJOR(dev));
903
                if (!fops) {
904
                        iput(inode);
905
                        return -ENOTBLK;
906
                }
907
                if (fops->open) {
908
                        struct file dummy;      /* allows read-write or read-only flag */
909
                        memset(&dummy, 0, sizeof(dummy));
910
                        dummy.f_inode = inode;
911
                        dummy.f_mode = (new_flags & MS_RDONLY) ? 1 : 3;
912
                        retval = fops->open(inode, &dummy);
913
                        if (retval) {
914
                                iput(inode);
915
                                return retval;
916
                        }
917
                }
918
 
919
        } else {
920
                if (!(dev = get_unnamed_dev()))
921
                        return -EMFILE;
922
                inode = NULL;
923
        }
924
        page = 0;
925
        if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL) {
926
                flags = new_flags & ~MS_MGC_MSK;
927
                retval = copy_mount_options(data, &page);
928
                if (retval < 0) {
929
                        iput(inode);
930
                        return retval;
931
                }
932
        }
933
        retval = do_mount(dev,dev_name,dir_name,t,flags,(void *) page);
934
        free_page(page);
935
        if (retval && !fstype->requires_dev)
936
                put_unnamed_dev(dev);
937
        if (retval && fops && fops->release)
938
                fops->release(inode, NULL);
939
        iput(inode);
940
        return retval;
941
}
942
 
943
static void do_mount_root(void)
944
{
945
        struct file_system_type * fs_type;
946
        struct super_block * sb;
947
        struct vfsmount *vfsmnt;
948
        struct inode * inode, d_inode;
949
        struct file filp;
950
        int retval;
951
printk("do_mount_root1\n");
952
#ifdef CONFIG_ROOT_NFS
953
        if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR)
954
                if (nfs_root_init(nfs_root_name, nfs_root_addrs) < 0) {
955
                        printk(KERN_ERR "Root-NFS: Unable to contact NFS "
956
                            "server for root fs, using /dev/fd0 instead\n");
957
                        ROOT_DEV = MKDEV(FLOPPY_MAJOR, 0);
958
                }
959
        if (MAJOR(ROOT_DEV) == UNNAMED_MAJOR) {
960
                ROOT_DEV = 0;
961
                if ((fs_type = get_fs_type("nfs"))) {
962
                        sb = &super_blocks[0];
963
                        while (sb->s_dev) sb++;
964
                        sb->s_dev = get_unnamed_dev();
965
                        sb->s_flags = root_mountflags & ~MS_RDONLY;
966
                        if (nfs_root_mount(sb) >= 0) {
967
                                inode = sb->s_mounted;
968
                                inode->i_count += 3 ;
969
                                sb->s_covered = inode;
970
                                sb->s_rd_only = 0;
971
                                sb->s_dirt = 0;
972
                                sb->s_type = fs_type;
973
                                current->fs->pwd = inode;
974
                                current->fs->root = inode;
975
                                ROOT_DEV = sb->s_dev;
976
                                printk (KERN_NOTICE "VFS: Mounted root (nfs filesystem).\n");
977
                                vfsmnt = add_vfsmnt(ROOT_DEV, "/dev/root", "/");
978
                                if (!vfsmnt)
979
                                        panic("VFS: add_vfsmnt failed for NFS root.\n");
980
                                vfsmnt->mnt_sb = sb;
981
                                vfsmnt->mnt_flags = sb->s_flags;
982
                                return;
983
                        }
984
                        sb->s_dev = 0;
985
                }
986
                if (!ROOT_DEV) {
987
                        printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n");
988
                        ROOT_DEV = MKDEV(FLOPPY_MAJOR, 0);
989
                }
990
        }
991
#endif
992
 
993
#ifdef CONFIG_BLK_DEV_FD
994
        if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {
995
#ifdef CONFIG_BLK_DEV_INITRD
996
                extern int rd_doload;
997
#endif
998
                floppy_eject();
999
#ifndef CONFIG_BLK_DEV_RAM
1000
                printk(KERN_NOTICE "(Warning, this kernel has no ramdisk support)\n");
1001
#endif
1002
#ifdef CONFIG_BLK_DEV_INITRD
1003
                /* rd_doload is 2 for a dual initrd/ramload setup */
1004
                if(rd_doload==2)
1005
                        rd_load_secondary();
1006
                else
1007
#endif          
1008
                {
1009
                        printk(KERN_NOTICE "VFS: Insert root floppy and press ENTER\n");
1010
                        wait_for_keypress();
1011
                }
1012
        }
1013
#endif
1014
 
1015
        memset(&filp, 0, sizeof(filp));
1016
        memset(&d_inode, 0, sizeof(d_inode));
1017
        d_inode.i_rdev = ROOT_DEV;
1018
        filp.f_inode = &d_inode;
1019
        if ( root_mountflags & MS_RDONLY)
1020
                filp.f_mode = 1; /* read only */
1021
        else
1022
                filp.f_mode = 3; /* read write */
1023
printk("do_mount_root2\n");
1024
        retval = blkdev_open(&d_inode, &filp);
1025
        if (retval == -EROFS) {
1026
                root_mountflags |= MS_RDONLY;
1027
                filp.f_mode = 1;
1028
                retval = blkdev_open(&d_inode, &filp);
1029
        }
1030
printk("do_mount_root3\n");
1031
        if (retval)
1032
                /*
1033
                 * Allow the user to distinguish between failed open
1034
                 * and bad superblock on root device.
1035
                 */
1036
                printk("VFS: Cannot open root device %s\n",
1037
                       kdevname(ROOT_DEV));
1038
        else for (fs_type = file_systems ; fs_type ; fs_type = fs_type->next) {
1039
printk("do_mount_root4\n");
1040
                if (!fs_type->requires_dev)
1041
                        continue;
1042
printk("do_mount_root5\n");
1043
                sb = read_super(ROOT_DEV,fs_type->name,root_mountflags,NULL,0);
1044
                if (sb) {
1045
printk("do_mount_root6\n");
1046
                        inode = sb->s_mounted;
1047
                        inode->i_count += 3 ;   /* NOTE! it is logically used 4 times, not 1 */
1048
                        sb->s_covered = inode;
1049
                        sb->s_flags = root_mountflags;
1050
                        current->fs->pwd = inode;
1051
                        current->fs->root = inode;
1052
                        printk ("VFS: Mounted root (%s filesystem)%s.\n",
1053
                                fs_type->name,
1054
                                (sb->s_flags & MS_RDONLY) ? " readonly" : "");
1055
                        vfsmnt = add_vfsmnt(ROOT_DEV, "/dev/root", "/");
1056
                        if (!vfsmnt)
1057
                                panic("VFS: add_vfsmnt failed for root fs");
1058
                        vfsmnt->mnt_sb = sb;
1059
                        vfsmnt->mnt_flags = root_mountflags;
1060
                        return;
1061
                }
1062
        }
1063
        panic("VFS: Unable to mount root fs on %s",
1064
                kdevname(ROOT_DEV));
1065
}
1066
 
1067
 
1068
void mount_root(void)
1069
{
1070
        memset(super_blocks, 0, sizeof(super_blocks));
1071
        do_mount_root();
1072
}
1073
 
1074
 
1075
#ifdef CONFIG_BLK_DEV_INITRD
1076
 
1077
int change_root(kdev_t new_root_dev,const char *put_old)
1078
{
1079
        kdev_t old_root_dev;
1080
        struct vfsmount *vfsmnt;
1081
        struct inode *old_root,*old_pwd,*inode;
1082
        unsigned long old_fs;
1083
        int error;
1084
 
1085
        old_root = current->fs->root;
1086
        old_pwd = current->fs->pwd;
1087
        old_root_dev = ROOT_DEV;
1088
        if (!fs_may_mount(new_root_dev)) {
1089
                printk(KERN_CRIT "New root is busy. Staying in initrd.\n");
1090
                return -EBUSY;
1091
        }
1092
        ROOT_DEV = new_root_dev;
1093
        do_mount_root();
1094
        old_fs = get_fs();
1095
        set_fs(get_ds());
1096
        error = namei(put_old,&inode);
1097
        if (error) inode = NULL;
1098
        set_fs(old_fs);
1099
        if (!error && (inode->i_count != 1 || inode->i_mount)) error = -EBUSY;
1100
        if (!error && !S_ISDIR(inode->i_mode)) error = -ENOTDIR;
1101
        iput(old_root); /* current->fs->root */
1102
        iput(old_pwd); /* current->fs->pwd */
1103
        if (error) {
1104
                int umount_error;
1105
 
1106
                if (inode) iput(inode);
1107
                printk(KERN_NOTICE "Trying to unmount old root ... ");
1108
                old_root->i_mount = old_root;
1109
                        /* does this belong into do_mount_root ? */
1110
                umount_error = do_umount(old_root_dev,1);
1111
                if (umount_error) printk(KERN_ERR "error %d\n",umount_error);
1112
                else {
1113
                        printk("okay\n");
1114
                        invalidate_buffers(old_root_dev);
1115
                }
1116
                return umount_error ? error : 0;
1117
        }
1118
        iput(old_root); /* sb->s_covered */
1119
        remove_vfsmnt(old_root_dev);
1120
        vfsmnt = add_vfsmnt(old_root_dev,"/dev/root.old",put_old);
1121
        if (!vfsmnt) printk(KERN_CRIT "Trouble: add_vfsmnt failed\n");
1122
        else {
1123
                vfsmnt->mnt_sb = old_root->i_sb;
1124
                vfsmnt->mnt_sb->s_covered = inode;
1125
                vfsmnt->mnt_flags = vfsmnt->mnt_sb->s_flags;
1126
        }
1127
        inode->i_mount = old_root;
1128
        return 0;
1129
}
1130
 
1131
#endif

powered by: WebSVN 2.1.0

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