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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [fs/] [umsdos/] [inode.c] - Blame information for rev 1777

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

Line No. Rev Author Line
1 1628 jcastillo
/*
2
 *  linux/fs/umsdos/inode.c
3
 *
4
 *      Written 1993 by Jacques Gelinas
5
 *      Inspired from linux/fs/msdos/... by Werner Almesberger
6
 *
7
 */
8
 
9
#include <linux/module.h>
10
 
11
#include <linux/fs.h>
12
#include <linux/msdos_fs.h>
13
#include <linux/kernel.h>
14
#include <linux/sched.h>
15
#include <linux/errno.h>
16
#include <asm/segment.h>
17
#include <linux/string.h>
18
#include <linux/stat.h>
19
#include <linux/umsdos_fs.h>
20
 
21
struct inode *pseudo_root=NULL;         /* Useful to simulate the pseudo DOS */
22
                                                                        /* directory. See UMSDOS_readdir_x() */
23
 
24
/* #Specification: convention / PRINTK Printk and printk
25
        Here is the convention for the use of printk inside fs/umsdos
26
 
27
        printk carry important message (error or status).
28
        Printk is for debugging (it is a macro defined at the beginning of
29
                   most source.
30
        PRINTK is a nulled Printk macro.
31
 
32
        This convention makes the source easier to read, and Printk easier
33
        to shut off.
34
*/
35
#define PRINTK(x)
36
#define Printk(x) printk x
37
 
38
 
39
void UMSDOS_put_inode(struct inode *inode)
40
{
41
        PRINTK (("put inode %x owner %x pos %d dir %x\n",inode
42
                ,inode->u.umsdos_i.i_emd_owner,inode->u.umsdos_i.pos
43
                ,inode->u.umsdos_i.i_emd_dir));
44
        if (inode != NULL && inode == pseudo_root){
45
                printk ("Umsdos: Oops releasing pseudo_root. Notify jacques@solucorp.qc.ca\n");
46
        }
47
        fat_put_inode(inode);
48
}
49
 
50
 
51
void UMSDOS_put_super(struct super_block *sb)
52
{
53
        msdos_put_super(sb);
54
        MOD_DEC_USE_COUNT;
55
}
56
 
57
 
58
void UMSDOS_statfs(struct super_block *sb,struct statfs *buf, int bufsiz)
59
{
60
        fat_statfs(sb,buf,bufsiz);
61
}
62
 
63
 
64
/*
65
        Call msdos_lookup, but set back the original msdos function table.
66
        Return 0 if ok, or a negative error code if not.
67
*/
68
int umsdos_real_lookup (
69
        struct inode *dir,
70
        const char *name,
71
        int len,
72
        struct inode **result)  /* Will hold inode of the file, if successful */
73
{
74
        int ret;
75
        dir->i_count++;
76
        ret = msdos_lookup (dir,name,len,result);
77
        return ret;
78
}
79
/*
80
        Complete the setup of an directory inode.
81
        First, it completes the function pointers, then
82
        it locates the EMD file. If the EMD is there, then plug the
83
        umsdos function table. If not, use the msdos one.
84
*/
85
void umsdos_setup_dir_inode (struct inode *inode)
86
{
87
        inode->u.umsdos_i.i_emd_dir = 0;
88
        {
89
                struct inode *emd_dir = umsdos_emd_dir_lookup (inode,0);
90
                extern struct inode_operations umsdos_rdir_inode_operations;
91
                inode->i_op = emd_dir != NULL
92
                        ? &umsdos_dir_inode_operations
93
                        : &umsdos_rdir_inode_operations;
94
                iput (emd_dir);
95
        }
96
}
97
/*
98
        Add some info into an inode so it can find its owner quickly
99
*/
100
void umsdos_set_dirinfo(
101
        struct inode *inode,
102
        struct inode *dir,
103
        off_t f_pos)
104
{
105
        struct inode *emd_owner = umsdos_emd_dir_lookup(dir,1);
106
        inode->u.umsdos_i.i_dir_owner = dir->i_ino;
107
        inode->u.umsdos_i.i_emd_owner = emd_owner->i_ino;
108
        iput (emd_owner);
109
        inode->u.umsdos_i.pos = f_pos;
110
}
111
/*
112
        Tells if an Umsdos inode has been "patched" once.
113
        Return != 0 if so.
114
*/
115
int umsdos_isinit (struct inode *inode)
116
{
117
#if     1
118
        return inode->u.umsdos_i.i_emd_owner != 0;
119
#elif 0
120
        return inode->i_atime != 0;
121
#else
122
        return inode->i_count > 1;
123
#endif
124
}
125
/*
126
        Connect the proper tables in the inode and add some info.
127
*/
128
void umsdos_patch_inode (
129
        struct inode *inode,
130
        struct inode *dir,              /* May be NULL */
131
        off_t f_pos)
132
{
133
        /*
134
                This function is called very early to setup the inode, somewhat
135
                too early (called by UMSDOS_read_inode). At this point, we can't
136
                do to much, such as lookup up EMD files and so on. This causes
137
                confusion in the kernel. This is why some initialisation
138
                will be done when dir != NULL only.
139
 
140
                UMSDOS do run piggy back on top of msdos fs. It looks like something
141
                is missing in the VFS to accommodate stacked fs. Still unclear what
142
                (quite honestly).
143
 
144
                Well, maybe one! A new entry "may_unmount" which would allow
145
                the stacked fs to allocate some inode permanently and release
146
                them at the end. Doing that now introduce a problem. unmount
147
                always fail because some inodes are in use.
148
        */
149
        if (!umsdos_isinit(inode)){
150
                inode->u.umsdos_i.i_emd_dir = 0;
151
                if (S_ISREG(inode->i_mode)){
152
                        if (inode->i_op->bmap != NULL){
153
                                inode->i_op = &umsdos_file_inode_operations;
154
                        }else{
155
                                inode->i_op = &umsdos_file_inode_operations_no_bmap;
156
                        }
157
                }else if (S_ISDIR(inode->i_mode)){
158
                        if (dir != NULL){
159
                                umsdos_setup_dir_inode(inode);
160
                        }
161
                }else if (S_ISLNK(inode->i_mode)){
162
                        inode->i_op = &umsdos_symlink_inode_operations;
163
                }else if (S_ISCHR(inode->i_mode)){
164
                        inode->i_op = &chrdev_inode_operations;
165
                }else if (S_ISBLK(inode->i_mode)){
166
                        inode->i_op = &blkdev_inode_operations;
167
                }else if (S_ISFIFO(inode->i_mode)){
168
                        init_fifo(inode);
169
                }
170
                if (dir != NULL){
171
                        /* #Specification: inode / umsdos info
172
                                The first time an inode is seen (inode->i_count == 1),
173
                                the inode number of the EMD file which control this inode
174
                                is tagged to this inode. It allows operation such
175
                                as notify_change to be handled.
176
                        */
177
                        /*
178
                                This is done last because it also control the
179
                                status of umsdos_isinit()
180
                        */
181
                        umsdos_set_dirinfo (inode,dir,f_pos);
182
                }
183
        }else if (dir != NULL){
184
                /*
185
                        Test to see if the info is maintained.
186
                        This should be removed when the file system will be proven.
187
                */
188
                struct inode *emd_owner = umsdos_emd_dir_lookup(dir,1);
189
                iput (emd_owner);
190
                if (emd_owner->i_ino != inode->u.umsdos_i.i_emd_owner){
191
                        printk ("UMSDOS: *** EMD_OWNER ??? *** ino = %ld %ld <> %ld "
192
                                ,inode->i_ino,emd_owner->i_ino,inode->u.umsdos_i.i_emd_owner);
193
                }
194
        }
195
}
196
/*
197
        Get the inode of the directory which owns this inode.
198
        Return 0 if ok, -EIO if error.
199
*/
200
int umsdos_get_dirowner(
201
        struct inode *inode,
202
        struct inode **result)  /* Hold NULL if any error */
203
                                                        /* else, the inode of the directory */
204
{
205
        int ret = -EIO;
206
        unsigned long ino = inode->u.umsdos_i.i_dir_owner;
207
        *result = NULL;
208
        if (ino == 0){
209
                printk ("UMSDOS: umsdos_get_dirowner ino == 0\n");
210
        }else{
211
                struct inode *dir = *result = iget(inode->i_sb,ino);
212
                if (dir != NULL){
213
                        umsdos_patch_inode (dir,NULL,0);
214
                        ret = 0;
215
                }
216
        }
217
        return ret;
218
}
219
/*
220
        Load an inode from disk.
221
*/
222
void UMSDOS_read_inode(struct inode *inode)
223
{
224
        PRINTK (("read inode %x ino = %d ",inode,inode->i_ino));
225
        msdos_read_inode(inode);
226
        PRINTK (("ino = %d %ld\n",inode->i_ino,inode->i_count));
227
        if (S_ISDIR(inode->i_mode)
228
                && (inode->u.umsdos_i.u.dir_info.creating != 0
229
                        || inode->u.umsdos_i.u.dir_info.looking != 0
230
                        || waitqueue_active(&inode->u.umsdos_i.u.dir_info.p))){
231
                Printk (("read inode %d %d %p\n"
232
                        ,inode->u.umsdos_i.u.dir_info.creating
233
                        ,inode->u.umsdos_i.u.dir_info.looking
234
                        ,inode->u.umsdos_i.u.dir_info.p));
235
        }
236
        /* #Specification: Inode / post initialisation
237
                To completely initialise an inode, we need access to the owner
238
                directory, so we can locate more info in the EMD file. This is
239
                not available the first time the inode is access, we use
240
                a value in the inode to tell if it has been finally initialised.
241
 
242
                At first, we have tried testing i_count but it was causing
243
                problem. It is possible that two or more process use the
244
                newly accessed inode. While the first one block during
245
                the initialisation (probably while reading the EMD file), the
246
                others believe all is well because i_count > 1. They go banana
247
                with a broken inode. See umsdos_lookup_patch and umsdos_patch_inode.
248
        */
249
        umsdos_patch_inode(inode,NULL,0);
250
}
251
 
252
/*
253
        Update the disk with the inode content
254
*/
255
void UMSDOS_write_inode(struct inode *inode)
256
{
257
        struct iattr newattrs;
258
 
259
        PRINTK (("UMSDOS_write_inode emd %d\n",inode->u.umsdos_i.i_emd_owner));
260
        fat_write_inode(inode);
261
        newattrs.ia_mtime = inode->i_mtime;
262
        newattrs.ia_atime = inode->i_atime;
263
        newattrs.ia_ctime = inode->i_ctime;
264
        newattrs.ia_valid = ATTR_MTIME | ATTR_ATIME | ATTR_CTIME;
265
        /*
266
                UMSDOS_notify_change is convenient to call here
267
                to update the EMD entry associated with this inode.
268
                But it has the side effect to re"dirt" the inode.
269
        */
270
        UMSDOS_notify_change (inode, &newattrs);
271
        inode->i_dirt = 0;
272
}
273
 
274
int UMSDOS_notify_change(struct inode *inode, struct iattr *attr)
275
{
276
        int ret = 0;
277
 
278
        if ((ret = inode_change_ok(inode, attr)) != 0)
279
                return ret;
280
 
281
        if (inode->i_nlink > 0){
282
                /* #Specification: notify_change / i_nlink > 0
283
                        notify change is only done for inode with nlink > 0. An inode
284
                        with nlink == 0 is no longer associated with any entry in
285
                        the EMD file, so there is nothing to update.
286
                */
287
                unsigned long i_emd_owner = inode->u.umsdos_i.i_emd_owner;
288
                if (inode == inode->i_sb->s_mounted){
289
                        /* #Specification: root inode / attributes
290
                                I don't know yet how this should work. Normally
291
                                the attributes (permissions bits, owner, times) of
292
                                a directory are stored in the EMD file of its parent.
293
 
294
                                One thing we could do is store the attributes of the root
295
                                inode in its own EMD file. A simple entry named "." could
296
                                be used for this special case. It would be read once
297
                                when the file system is mounted and update in
298
                                UMSDOS_notify_change() (right here).
299
 
300
                                I am not sure of the behavior of the root inode for
301
                                a real UNIX file system. For now, this is a nop.
302
                        */
303
                }else if (i_emd_owner != 0xffffffff && i_emd_owner != 0){
304
                        /* This inode is not a EMD file nor an inode used internally
305
                                by MSDOS, so we can update its status.
306
                                See emd.c
307
                        */
308
                        struct inode *emd_owner = iget (inode->i_sb,i_emd_owner);
309
                        PRINTK (("notify change %p ",inode));
310
                        if (emd_owner == NULL){
311
                                printk ("UMSDOS: emd_owner = NULL ???");
312
                                ret = -EPERM;
313
                        }else{
314
                                struct file filp;
315
                                struct umsdos_dirent entry;
316
                                filp.f_pos = inode->u.umsdos_i.pos;
317
                                filp.f_reada = 0;
318
                                PRINTK (("pos = %d ",filp.f_pos));
319
                                /* Read only the start of the entry since we don't touch */
320
                                /* the name */
321
                                ret = umsdos_emd_dir_read (emd_owner,&filp,(char*)&entry
322
                                        ,UMSDOS_REC_SIZE);
323
                                if (ret == 0){
324
                                        if (attr->ia_valid & ATTR_UID)
325
                                                entry.uid = attr->ia_uid;
326
                                        if (attr->ia_valid & ATTR_GID)
327
                                                entry.gid = attr->ia_gid;
328
                                        if (attr->ia_valid & ATTR_MODE)
329
                                                entry.mode = attr->ia_mode;
330
                                        if (attr->ia_valid & ATTR_ATIME)
331
                                                entry.atime = attr->ia_atime;
332
                                        if (attr->ia_valid & ATTR_MTIME)
333
                                                entry.mtime = attr->ia_mtime;
334
                                        if (attr->ia_valid & ATTR_CTIME)
335
                                                entry.ctime = attr->ia_ctime;
336
 
337
                                        entry.nlink = inode->i_nlink;
338
                                        filp.f_pos = inode->u.umsdos_i.pos;
339
                                        ret = umsdos_emd_dir_write (emd_owner,&filp,(char*)&entry
340
                                                ,UMSDOS_REC_SIZE);
341
 
342
                                        PRINTK (("notify pos %d ret %d nlink %d "
343
                                                ,inode->u.umsdos_i.pos
344
                                                ,ret,entry.nlink));
345
                                        /* #Specification: notify_change / msdos fs
346
                                                notify_change operation are done only on the
347
                                                EMD file. The msdos fs is not even called.
348
                                        */
349
                                }
350
                                iput (emd_owner);
351
                        }
352
                        PRINTK (("\n"));
353
                }
354
        }
355
        if (ret == 0)
356
                inode_setattr(inode, attr);
357
        return ret;
358
}
359
 
360
/* #Specification: function name / convention
361
        A simple convention for function name has been used in
362
        the UMSDOS file system. First all function use the prefix
363
        umsdos_ to avoid name clash with other part of the kernel.
364
 
365
        And standard VFS entry point use the prefix UMSDOS (upper case)
366
        so it's easier to tell them apart.
367
*/
368
 
369
static struct super_operations umsdos_sops = {
370
        UMSDOS_read_inode,
371
        UMSDOS_notify_change,
372
        UMSDOS_write_inode,
373
        UMSDOS_put_inode,
374
        UMSDOS_put_super,
375
        NULL, /* added in 0.96c */
376
        UMSDOS_statfs,
377
        NULL
378
};
379
 
380
/*
381
        Read the super block of an Extended MS-DOS FS.
382
*/
383
struct super_block *UMSDOS_read_super(
384
        struct super_block *s,
385
        void *data,
386
        int silent)
387
{
388
        /* #Specification: mount / options
389
                Umsdos run on top of msdos. Currently, it supports no
390
                mount option, but happily pass all option received to
391
                the msdos driver. I am not sure if all msdos mount option
392
                make sense with Umsdos. Here are at least those who
393
                are useful.
394
                        uid=
395
                        gid=
396
 
397
                These options affect the operation of umsdos in directories
398
                which do not have an EMD file. They behave like normal
399
                msdos directory, with all limitation of msdos.
400
        */
401
        struct super_block *sb;
402
        MOD_INC_USE_COUNT;
403
        sb = msdos_read_super(s,data,silent);
404
        printk ("UMSDOS Beta 0.6 (compatibility level %d.%d, fast msdos)\n"
405
                ,UMSDOS_VERSION,UMSDOS_RELEASE);
406
        if (sb != NULL){
407
                MSDOS_SB(sb)->options.dotsOK = 0;  /* disable hidden==dotfile */
408
                sb->s_op = &umsdos_sops;
409
                PRINTK (("umsdos_read_super %p\n",sb->s_mounted));
410
                umsdos_setup_dir_inode (sb->s_mounted);
411
                PRINTK (("End umsdos_read_super\n"));
412
                if (s == super_blocks){
413
                        /* #Specification: pseudo root / mount
414
                                When a umsdos fs is mounted, a special handling is done
415
                                if it is the root partition. We check for the presence
416
                                of the file /linux/etc/init or /linux/etc/rc or
417
                                /linux/sbin/init. If one is there, we do a chroot("/linux").
418
 
419
                                We check both because (see init/main.c) the kernel
420
                                try to exec init at different place and if it fails
421
                                it tries /bin/sh /etc/rc. To be consistent with
422
                                init/main.c, many more test would have to be done
423
                                to locate init. Any complain ?
424
 
425
                                The chroot is done manually in init/main.c but the
426
                                info (the inode) is located at mount time and store
427
                                in a global variable (pseudo_root) which is used at
428
                                different place in the umsdos driver. There is no
429
                                need to store this variable elsewhere because it
430
                                will always be one, not one per mount.
431
 
432
                                This feature allows the installation
433
                                of a linux system within a DOS system in a subdirectory.
434
 
435
                                A user may install its linux stuff in c:\linux
436
                                avoiding any clash with existing DOS file and subdirectory.
437
                                When linux boots, it hides this fact, showing a normal
438
                                root directory with /etc /bin /tmp ...
439
 
440
                                The word "linux" is hardcoded in /usr/include/linux/umsdos_fs.h
441
                                in the macro UMSDOS_PSDROOT_NAME.
442
                        */
443
 
444
                        struct inode *pseudo;
445
                        Printk (("Mounting root\n"));
446
                        if (umsdos_real_lookup (sb->s_mounted,UMSDOS_PSDROOT_NAME
447
                                        ,UMSDOS_PSDROOT_LEN,&pseudo)==0
448
                                && S_ISDIR(pseudo->i_mode)){
449
                                struct inode *etc = NULL;
450
                                struct inode *sbin = NULL;
451
                                int pseudo_ok = 0;
452
                                Printk (("/%s is there\n",UMSDOS_PSDROOT_NAME));
453
                                if (umsdos_real_lookup (pseudo,"etc",3,&etc)==0
454
                                        && S_ISDIR(etc->i_mode)){
455
                                        struct inode *init = NULL;
456
                                        struct inode *rc = NULL;
457
                                        Printk (("/%s/etc is there\n",UMSDOS_PSDROOT_NAME));
458
                                        if ((umsdos_real_lookup (etc,"init",4,&init)==0
459
                                                        && S_ISREG(init->i_mode))
460
                                                || (umsdos_real_lookup (etc,"rc",2,&rc)==0
461
                                                        && S_ISREG(rc->i_mode))){
462
                                                pseudo_ok = 1;
463
                                        }
464
                                        iput (init);
465
                                        iput (rc);
466
                                }
467
                                if (!pseudo_ok
468
                                        && umsdos_real_lookup (pseudo,"sbin",4,&sbin)==0
469
                                        && S_ISDIR(sbin->i_mode)){
470
                                        struct inode *init = NULL;
471
                                        Printk (("/%s/sbin is there\n",UMSDOS_PSDROOT_NAME));
472
                                        if (umsdos_real_lookup (sbin,"init",4,&init)==0
473
                                                        && S_ISREG(init->i_mode)){
474
                                                pseudo_ok = 1;
475
                                        }
476
                                        iput (init);
477
                                }
478
                                if (pseudo_ok){
479
                                        umsdos_setup_dir_inode (pseudo);
480
                                        Printk (("Activating pseudo root /%s\n",UMSDOS_PSDROOT_NAME));
481
                                        pseudo_root = pseudo;
482
                                        pseudo->i_count++;
483
                                        pseudo = NULL;
484
                                }
485
                                iput (sbin);
486
                                iput (etc);
487
                        }
488
                        iput (pseudo);
489
                }
490
        } else {
491
                MOD_DEC_USE_COUNT;
492
        }
493
        return sb;
494
}
495
 
496
 
497
 
498
static struct file_system_type umsdos_fs_type = {
499
        UMSDOS_read_super, "umsdos", 1, NULL
500
};
501
 
502
int init_umsdos_fs(void)
503
{
504
        return register_filesystem(&umsdos_fs_type);
505
}
506
 
507
#ifdef MODULE
508
int init_module(void)
509
{
510
        int status;
511
 
512
        if ((status = init_umsdos_fs()) == 0)
513
                register_symtab(0);
514
        return status;
515
}
516
 
517
void cleanup_module(void)
518
{
519
        unregister_filesystem(&umsdos_fs_type);
520
}
521
 
522
#endif
523
 

powered by: WebSVN 2.1.0

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