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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [fs/] [umsdos/] [inode.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
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
#include <linux/module.h>
9
 
10
#include <linux/init.h>
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/uaccess.h>
17
#include <linux/string.h>
18
#include <linux/stat.h>
19
#include <linux/umsdos_fs.h>
20
#include <linux/list.h>
21
#include <linux/pagemap.h>
22
 
23
extern struct dentry_operations umsdos_dentry_operations;
24
 
25
struct dentry *saved_root;      /* Original root if changed */
26
struct inode *pseudo_root;      /* Useful to simulate the pseudo DOS */
27
                                        /* directory. See UMSDOS_readdir_x() */
28
 
29
static struct dentry *check_pseudo_root(struct super_block *);
30
 
31
 
32
void UMSDOS_put_inode (struct inode *inode)
33
{
34
        PRINTK ((KERN_DEBUG
35
                "put inode %p (%lu) pos %lu count=%d\n"
36
                 ,inode, inode->i_ino
37
                 ,inode->u.umsdos_i.pos
38
                 ,atomic_read(&inode->i_count)));
39
 
40
        if (inode == pseudo_root) {
41
                Printk ((KERN_ERR "Umsdos: debug: releasing pseudo_root - ino=%lu count=%d\n", inode->i_ino, atomic_read(&inode->i_count)));
42
        }
43
 
44
        if (atomic_read(&inode->i_count) == 1)
45
                inode->u.umsdos_i.i_patched = 0;
46
}
47
 
48
 
49
void UMSDOS_put_super (struct super_block *sb)
50
{
51
        Printk ((KERN_DEBUG "UMSDOS_put_super: entering\n"));
52
        if (saved_root && pseudo_root && sb->s_dev == ROOT_DEV) {
53
                shrink_dcache_parent(saved_root);
54
                dput(saved_root);
55
                saved_root = NULL;
56
                pseudo_root = NULL;
57
        }
58
        msdos_put_super (sb);
59
}
60
 
61
 
62
/*
63
 * Complete the setup of a directory dentry based on its
64
 * EMD/non-EMD status.  If it has an EMD, then plug the
65
 * umsdos function table. If not, use the msdos one.
66
 */
67
void umsdos_setup_dir(struct dentry *dir)
68
{
69
        struct inode *inode = dir->d_inode;
70
 
71
        if (!S_ISDIR(inode->i_mode))
72
                printk(KERN_ERR "umsdos_setup_dir: %s/%s not a dir!\n",
73
                        dir->d_parent->d_name.name, dir->d_name.name);
74
 
75
        init_waitqueue_head (&inode->u.umsdos_i.dir_info.p);
76
        inode->u.umsdos_i.dir_info.looking = 0;
77
        inode->u.umsdos_i.dir_info.creating = 0;
78
        inode->u.umsdos_i.dir_info.pid = 0;
79
 
80
        inode->i_op = &umsdos_rdir_inode_operations;
81
        inode->i_fop = &umsdos_rdir_operations;
82
        if (umsdos_have_emd(dir)) {
83
Printk((KERN_DEBUG "umsdos_setup_dir: %s/%s using EMD\n",
84
dir->d_parent->d_name.name, dir->d_name.name));
85
                inode->i_op = &umsdos_dir_inode_operations;
86
                inode->i_fop = &umsdos_dir_operations;
87
        }
88
}
89
 
90
 
91
/*
92
 * Add some info into an inode so it can find its owner quickly
93
 */
94
void umsdos_set_dirinfo_new (struct dentry *dentry, off_t f_pos)
95
{
96
        struct inode *inode = dentry->d_inode;
97
        struct dentry *demd;
98
 
99
        inode->u.umsdos_i.pos = f_pos;
100
 
101
        /* now check the EMD file */
102
        demd = umsdos_get_emd_dentry(dentry->d_parent);
103
        if (!IS_ERR(demd)) {
104
                dput(demd);
105
        }
106
        return;
107
}
108
 
109
static struct inode_operations umsdos_file_inode_operations = {
110
        truncate:       fat_truncate,
111
        setattr:        UMSDOS_notify_change,
112
};
113
 
114
static struct inode_operations umsdos_symlink_inode_operations = {
115
        readlink:       page_readlink,
116
        follow_link:    page_follow_link,
117
        setattr:        UMSDOS_notify_change,
118
};
119
 
120
/*
121
 * Connect the proper tables in the inode and add some info.
122
 */
123
/* #Specification: inode / umsdos info
124
 * The first time an inode is seen (inode->i_count == 1),
125
 * the inode number of the EMD file which controls this inode
126
 * is tagged to this inode. It allows operations such as
127
 * notify_change to be handled.
128
 */
129
void umsdos_patch_dentry_inode(struct dentry *dentry, off_t f_pos)
130
{
131
        struct inode *inode = dentry->d_inode;
132
 
133
PRINTK (("umsdos_patch_dentry_inode: inode=%lu\n", inode->i_ino));
134
 
135
        /*
136
         * Classify the inode based on EMD/non-EMD status.
137
         */
138
PRINTK (("umsdos_patch_inode: call umsdos_set_dirinfo_new(%p,%lu)\n",
139
dentry, f_pos));
140
        umsdos_set_dirinfo_new(dentry, f_pos);
141
 
142
        inode->i_op = &umsdos_file_inode_operations;
143
        if (S_ISREG (inode->i_mode)) {
144
                /* address_space operations already set */
145
        } else if (S_ISDIR (inode->i_mode)) {
146
                umsdos_setup_dir(dentry);
147
        } else if (S_ISLNK (inode->i_mode)) {
148
                /* address_space operations already set */
149
                inode->i_op = &umsdos_symlink_inode_operations;
150
        } else
151
                init_special_inode(inode, inode->i_mode,
152
                                        kdev_t_to_nr(inode->i_rdev));
153
}
154
 
155
 
156
/*
157
 * lock the parent dir before starting ...
158
 * also handles hardlink converting
159
 */
160
int UMSDOS_notify_change (struct dentry *dentry, struct iattr *attr)
161
{
162
        struct inode *dir, *inode;
163
        struct umsdos_info info;
164
        struct dentry *temp, *old_dentry = NULL;
165
        int ret;
166
 
167
        ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len,
168
                                &info);
169
        if (ret)
170
                goto out;
171
        ret = umsdos_findentry (dentry->d_parent, &info, 0);
172
        if (ret) {
173
printk("UMSDOS_notify_change: %s/%s not in EMD, ret=%d\n",
174
dentry->d_parent->d_name.name, dentry->d_name.name, ret);
175
                goto out;
176
        }
177
 
178
        if (info.entry.flags & UMSDOS_HLINK) {
179
                /*
180
                 * In order to get the correct (real) inode, we just drop
181
                 * the original dentry.
182
                 */
183
                d_drop(dentry);
184
Printk(("UMSDOS_notify_change: hard link %s/%s, fake=%s\n",
185
dentry->d_parent->d_name.name, dentry->d_name.name, info.fake.fname));
186
 
187
                /* Do a real lookup to get the short name dentry */
188
                temp = umsdos_covered(dentry->d_parent, info.fake.fname,
189
                                                info.fake.len);
190
                ret = PTR_ERR(temp);
191
                if (IS_ERR(temp))
192
                        goto out;
193
 
194
                /* now resolve the link ... */
195
                temp = umsdos_solve_hlink(temp);
196
                ret = PTR_ERR(temp);
197
                if (IS_ERR(temp))
198
                        goto out;
199
                old_dentry = dentry;
200
                dentry = temp;  /* so umsdos_notify_change_locked will operate on that */
201
        }
202
 
203
        dir = dentry->d_parent->d_inode;
204
        inode = dentry->d_inode;
205
 
206
        ret = inode_change_ok (inode, attr);
207
        if (ret)
208
                goto out;
209
 
210
        down(&dir->i_sem);
211
        ret = umsdos_notify_change_locked(dentry, attr);
212
        up(&dir->i_sem);
213
        if (ret == 0)
214
                ret = inode_setattr (inode, attr);
215
out:
216
        if (old_dentry)
217
                dput (dentry);  /* if we had to use fake dentry for hardlinks, dput() it now */
218
        return ret;
219
}
220
 
221
 
222
/*
223
 * Must be called with the parent lock held.
224
 */
225
int umsdos_notify_change_locked(struct dentry *dentry, struct iattr *attr)
226
{
227
        struct inode *inode = dentry->d_inode;
228
        struct dentry *demd;
229
        struct address_space *mapping;
230
        struct page *page;
231
        int ret = 0;
232
        struct umsdos_dirent *entry;
233
        int offs;
234
 
235
Printk(("UMSDOS_notify_change: entering for %s/%s (%d)\n",
236
dentry->d_parent->d_name.name, dentry->d_name.name, inode->u.umsdos_i.i_patched));
237
 
238
        if (inode->i_nlink == 0)
239
                goto out;
240
        if (inode->i_ino == UMSDOS_ROOT_INO)
241
                goto out;
242
 
243
        /* get the EMD file dentry */
244
        demd = umsdos_get_emd_dentry(dentry->d_parent);
245
        ret = PTR_ERR(demd);
246
        if (IS_ERR(demd))
247
                goto out;
248
        ret = 0;
249
        /* don't do anything if directory is not promoted to umsdos yet */
250
        if (!demd->d_inode) {
251
                Printk((KERN_DEBUG
252
                        "UMSDOS_notify_change: no EMD file %s/%s\n",
253
                        demd->d_parent->d_name.name, demd->d_name.name));
254
                goto out_dput;
255
        }
256
 
257
        /* don't do anything if this is the EMD itself */
258
        if (inode == demd->d_inode)
259
                goto out_dput;
260
 
261
        /* This inode is not a EMD file nor an inode used internally
262
         * by MSDOS, so we can update its status.
263
         * See emd.c
264
         */
265
 
266
        /* Read only the start of the entry since we don't touch the name */
267
        mapping = demd->d_inode->i_mapping;
268
        offs = inode->u.umsdos_i.pos & ~PAGE_CACHE_MASK;
269
        ret = -ENOMEM;
270
        page=grab_cache_page(mapping,inode->u.umsdos_i.pos>>PAGE_CACHE_SHIFT);
271
        if (!page)
272
                goto out_dput;
273
        ret=mapping->a_ops->prepare_write(NULL,page,offs,offs+UMSDOS_REC_SIZE);
274
        if (ret)
275
                goto out_unlock;
276
        entry = (struct umsdos_dirent *) (page_address(page) + offs);
277
        if (attr->ia_valid & ATTR_UID)
278
                entry->uid = cpu_to_le16(attr->ia_uid);
279
        if (attr->ia_valid & ATTR_GID)
280
                entry->gid = cpu_to_le16(attr->ia_gid);
281
        if (attr->ia_valid & ATTR_MODE)
282
                entry->mode = cpu_to_le16(attr->ia_mode);
283
        if (attr->ia_valid & ATTR_ATIME)
284
                entry->atime = cpu_to_le32(attr->ia_atime);
285
        if (attr->ia_valid & ATTR_MTIME)
286
                entry->mtime = cpu_to_le32(attr->ia_mtime);
287
        if (attr->ia_valid & ATTR_CTIME)
288
                entry->ctime = cpu_to_le32(attr->ia_ctime);
289
        entry->nlink = cpu_to_le16(inode->i_nlink);
290
        ret=mapping->a_ops->commit_write(NULL,page,offs,offs+UMSDOS_REC_SIZE);
291
        if (ret)
292
                printk(KERN_WARNING
293
                        "umsdos_notify_change: %s/%s EMD write error, ret=%d\n",
294
                        dentry->d_parent->d_name.name, dentry->d_name.name,ret);
295
 
296
        /* #Specification: notify_change / msdos fs
297
         * notify_change operation are done only on the
298
         * EMD file. The msdos fs is not even called.
299
         */
300
out_unlock:
301
        UnlockPage(page);
302
        page_cache_release(page);
303
out_dput:
304
        dput(demd);
305
out:
306
        return ret;
307
}
308
 
309
 
310
/*
311
 * Update the disk with the inode content
312
 */
313
void UMSDOS_write_inode (struct inode *inode, int wait)
314
{
315
        struct iattr newattrs;
316
 
317
        fat_write_inode (inode, wait);
318
        newattrs.ia_mtime = inode->i_mtime;
319
        newattrs.ia_atime = inode->i_atime;
320
        newattrs.ia_ctime = inode->i_ctime;
321
        newattrs.ia_valid = ATTR_MTIME | ATTR_ATIME | ATTR_CTIME;
322
        /*
323
         * UMSDOS_notify_change is convenient to call here
324
         * to update the EMD entry associated with this inode.
325
         * But it has the side effect to re"dirt" the inode.
326
         */
327
/*
328
 * UMSDOS_notify_change (inode, &newattrs);
329
 
330
 * inode->i_state &= ~I_DIRTY; / * FIXME: this doesn't work.  We need to remove ourselves from list on dirty inodes. /mn/ */
331
}
332
 
333
 
334
static struct super_operations umsdos_sops =
335
{
336
        write_inode:    UMSDOS_write_inode,
337
        put_inode:      UMSDOS_put_inode,
338
        delete_inode:   fat_delete_inode,
339
        put_super:      UMSDOS_put_super,
340
        statfs:         UMSDOS_statfs,
341
        clear_inode:    fat_clear_inode,
342
};
343
 
344
int UMSDOS_statfs(struct super_block *sb,struct statfs *buf)
345
{
346
        int ret;
347
        ret = fat_statfs (sb, buf);
348
        if (!ret)
349
                buf->f_namelen = UMSDOS_MAXNAME;
350
        return ret;
351
}
352
 
353
/*
354
 * Read the super block of an Extended MS-DOS FS.
355
 */
356
struct super_block *UMSDOS_read_super (struct super_block *sb, void *data,
357
                                      int silent)
358
{
359
        struct super_block *res;
360
        struct dentry *new_root;
361
 
362
        /*
363
         * Call msdos-fs to mount the disk.
364
         * Note: this returns res == sb or NULL
365
         */
366
        res = msdos_read_super (sb, data, silent);
367
 
368
        if (!res)
369
                goto out_fail;
370
 
371
        printk (KERN_INFO "UMSDOS 0.86k "
372
                "(compatibility level %d.%d, fast msdos)\n",
373
                UMSDOS_VERSION, UMSDOS_RELEASE);
374
 
375
        sb->s_op = &umsdos_sops;
376
        MSDOS_SB(sb)->options.dotsOK = 0;        /* disable hidden==dotfile */
377
 
378
        /* install our dentry operations ... */
379
        sb->s_root->d_op = &umsdos_dentry_operations;
380
 
381
        umsdos_patch_dentry_inode(sb->s_root, 0);
382
 
383
        /* Check whether to change to the /linux root */
384
        new_root = check_pseudo_root(sb);
385
 
386
        if (new_root) {
387
                /* sanity check */
388
                if (new_root->d_op != &umsdos_dentry_operations)
389
                        printk("umsdos_read_super: pseudo-root wrong ops!\n");
390
 
391
                pseudo_root = new_root->d_inode;
392
                saved_root = sb->s_root;
393
                printk(KERN_INFO "UMSDOS: changed to alternate root\n");
394
                dget (sb->s_root); sb->s_root = dget(new_root);
395
        }
396
        return sb;
397
 
398
out_fail:
399
        printk(KERN_INFO "UMSDOS: msdos_read_super failed, mount aborted.\n");
400
        return NULL;
401
}
402
 
403
/*
404
 * Check for an alternate root if we're the root device.
405
 */
406
 
407
extern kdev_t ROOT_DEV;
408
static struct dentry *check_pseudo_root(struct super_block *sb)
409
{
410
        struct dentry *root, *sbin, *init;
411
 
412
        /*
413
         * Check whether we're mounted as the root device.
414
         * must check like this, because we can be used with initrd
415
         */
416
 
417
        if (sb->s_dev != ROOT_DEV)
418
                goto out_noroot;
419
 
420
        /*
421
         * lookup_dentry needs a (so far non-existent) root.
422
         */
423
        printk(KERN_INFO "check_pseudo_root: mounted as root\n");
424
        root = lookup_one_len(UMSDOS_PSDROOT_NAME, sb->s_root,UMSDOS_PSDROOT_LEN);
425
        if (IS_ERR(root))
426
                goto out_noroot;
427
 
428
        if (!root->d_inode || !S_ISDIR(root->d_inode->i_mode))
429
                goto out_dput;
430
 
431
printk(KERN_INFO "check_pseudo_root: found %s/%s\n",
432
root->d_parent->d_name.name, root->d_name.name);
433
 
434
        /* look for /sbin/init */
435
        sbin = lookup_one_len("sbin", root, 4);
436
        if (IS_ERR(sbin))
437
                goto out_dput;
438
        if (!sbin->d_inode || !S_ISDIR(sbin->d_inode->i_mode))
439
                goto out_dput_sbin;
440
        init = lookup_one_len("init", sbin, 4);
441
        if (IS_ERR(init))
442
                goto out_dput_sbin;
443
        if (!init->d_inode)
444
                goto out_dput_init;
445
        printk(KERN_INFO "check_pseudo_root: found %s/%s, enabling pseudo-root\n", init->d_parent->d_name.name, init->d_name.name);
446
        dput(sbin);
447
        dput(init);
448
        return root;
449
 
450
        /* Alternate root not found ... */
451
out_dput_init:
452
        dput(init);
453
out_dput_sbin:
454
        dput(sbin);
455
out_dput:
456
        dput(root);
457
out_noroot:
458
        return NULL;
459
}
460
 
461
 
462
static DECLARE_FSTYPE_DEV(umsdos_fs_type, "umsdos", UMSDOS_read_super);
463
 
464
static int __init init_umsdos_fs (void)
465
{
466
        return register_filesystem (&umsdos_fs_type);
467
}
468
 
469
static void __exit exit_umsdos_fs (void)
470
{
471
        unregister_filesystem (&umsdos_fs_type);
472
}
473
 
474
EXPORT_NO_SYMBOLS;
475
 
476
module_init(init_umsdos_fs)
477
module_exit(exit_umsdos_fs)
478
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

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