2 * linux/fs/umsdos/inode.c
4 * Written 1993 by Jacques Gelinas
5 * Inspired from linux/fs/msdos/... by Werner Almesberger
8 #include <linux/module.h>
10 #include <linux/init.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>
22 extern struct dentry_operations umsdos_dentry_operations
;
23 extern struct inode_operations umsdos_rdir_inode_operations
;
26 struct dentry
*saved_root
= NULL
; /* Original root if changed */
27 struct inode
*pseudo_root
= NULL
; /* Useful to simulate the pseudo DOS */
28 /* directory. See UMSDOS_readdir_x() */
30 static struct dentry
*check_pseudo_root(struct super_block
*);
34 * Initialize a private filp
36 void fill_new_filp (struct file
*filp
, struct dentry
*dentry
)
39 printk(KERN_ERR
"fill_new_filp: NULL dentry!\n");
41 memset (filp
, 0, sizeof (struct file
));
43 filp
->f_flags
= O_RDWR
;
44 filp
->f_dentry
= dentry
;
45 filp
->f_op
= &umsdos_file_operations
;
50 void UMSDOS_put_inode (struct inode
*inode
)
53 "put inode %p (%lu) owner %lu pos %lu dir %lu count=%d\n"
55 ,inode
->u
.umsdos_i
.i_emd_owner
, inode
->u
.umsdos_i
.pos
56 ,inode
->u
.umsdos_i
.i_emd_dir
, inode
->i_count
));
58 if (inode
== pseudo_root
) {
59 printk (KERN_ERR
"Umsdos: Oops releasing pseudo_root."
60 " Notify jacques@solucorp.qc.ca\n");
63 inode
->u
.umsdos_i
.i_patched
= 0;
64 fat_put_inode (inode
);
68 void UMSDOS_put_super (struct super_block
*sb
)
70 Printk ((KERN_DEBUG
"UMSDOS_put_super: entering\n"));
72 shrink_dcache_parent(saved_root
);
73 printk("UMSDOS_put_super: freeing saved root, d_count=%d\n",
85 * Complete the setup of a directory dentry based on its
86 * EMD/non-EMD status. If it has an EMD, then plug the
87 * umsdos function table. If not, use the msdos one.
89 void umsdos_setup_dir(struct dentry
*dir
)
91 struct inode
*inode
= dir
->d_inode
;
93 if (!S_ISDIR(inode
->i_mode
))
94 printk(KERN_ERR
"umsdos_setup_dir: %s/%s not a dir!\n",
95 dir
->d_parent
->d_name
.name
, dir
->d_name
.name
);
97 inode
->u
.umsdos_i
.i_emd_dir
= 0;
98 inode
->i_op
= &umsdos_rdir_inode_operations
;
99 if (umsdos_have_emd(dir
)) {
100 Printk((KERN_DEBUG
"umsdos_setup_dir: %s/%s using EMD\n",
101 dir
->d_parent
->d_name
.name
, dir
->d_name
.name
));
102 inode
->i_op
= &umsdos_dir_inode_operations
;
108 * Add some info into an inode so it can find its owner quickly
110 void umsdos_set_dirinfo_new (struct dentry
*dentry
, off_t f_pos
)
112 struct inode
*inode
= dentry
->d_inode
;
115 inode
->u
.umsdos_i
.i_emd_owner
= 0;
116 inode
->u
.umsdos_i
.pos
= f_pos
;
118 /* now check the EMD file */
119 demd
= umsdos_get_emd_dentry(dentry
->d_parent
);
122 inode
->u
.umsdos_i
.i_emd_owner
= demd
->d_inode
->i_ino
;
131 * Connect the proper tables in the inode and add some info.
133 /* #Specification: inode / umsdos info
134 * The first time an inode is seen (inode->i_count == 1),
135 * the inode number of the EMD file which controls this inode
136 * is tagged to this inode. It allows operations such as
137 * notify_change to be handled.
139 void umsdos_patch_dentry_inode(struct dentry
*dentry
, off_t f_pos
)
141 struct inode
*inode
= dentry
->d_inode
;
143 PRINTK (("umsdos_patch_dentry_inode: inode=%lu\n", inode
->i_ino
));
146 * Classify the inode based on EMD/non-EMD status.
148 PRINTK (("umsdos_patch_inode: call umsdos_set_dirinfo_new(%p,%lu)\n",
150 umsdos_set_dirinfo_new(dentry
, f_pos
);
152 inode
->u
.umsdos_i
.i_emd_dir
= 0;
153 if (S_ISREG (inode
->i_mode
)) {
154 if (MSDOS_SB (inode
->i_sb
)->cvf_format
) {
155 if (MSDOS_SB (inode
->i_sb
)->cvf_format
->flags
& CVF_USE_READPAGE
) {
156 inode
->i_op
= &umsdos_file_inode_operations_readpage
;
158 inode
->i_op
= &umsdos_file_inode_operations_no_bmap
;
161 if (inode
->i_op
->bmap
!= NULL
) {
162 inode
->i_op
= &umsdos_file_inode_operations
;
164 inode
->i_op
= &umsdos_file_inode_operations_no_bmap
;
167 } else if (S_ISDIR (inode
->i_mode
)) {
168 umsdos_setup_dir(dentry
);
169 } else if (S_ISLNK (inode
->i_mode
)) {
170 inode
->i_op
= &umsdos_symlink_inode_operations
;
171 } else if (S_ISCHR (inode
->i_mode
)) {
172 inode
->i_op
= &chrdev_inode_operations
;
173 } else if (S_ISBLK (inode
->i_mode
)) {
174 inode
->i_op
= &blkdev_inode_operations
;
175 } else if (S_ISFIFO (inode
->i_mode
)) {
182 * Load an inode from disk.
184 /* #Specification: Inode / post initialisation
185 * To completely initialise an inode, we need access to the owner
186 * directory, so we can locate more info in the EMD file. This is
187 * not available the first time the inode is accessed, so we use
188 * a value in the inode to tell if it has been finally initialised.
190 * New inodes are obtained by the lookup and create routines, and
191 * each of these must ensure that the inode gets patched.
193 void UMSDOS_read_inode (struct inode
*inode
)
195 Printk ((KERN_DEBUG
"UMSDOS_read_inode %p ino = %lu ",
196 inode
, inode
->i_ino
));
197 msdos_read_inode (inode
);
199 /* inode needs patching */
200 inode
->u
.umsdos_i
.i_patched
= 0;
204 int umsdos_notify_change_locked(struct dentry
*, struct iattr
*);
206 * lock the parent dir before starting ...
208 int UMSDOS_notify_change (struct dentry
*dentry
, struct iattr
*attr
)
210 struct inode
*dir
= dentry
->d_parent
->d_inode
;
214 ret
= umsdos_notify_change_locked(dentry
, attr
);
220 * Must be called with the parent lock held.
222 int umsdos_notify_change_locked(struct dentry
*dentry
, struct iattr
*attr
)
224 struct inode
*inode
= dentry
->d_inode
;
228 struct umsdos_dirent entry
;
230 Printk(("UMSDOS_notify_change: entering for %s/%s (%d)\n",
231 dentry
->d_parent
->d_name
.name
, dentry
->d_name
.name
, inode
->u
.umsdos_i
.i_patched
));
233 ret
= inode_change_ok (inode
, attr
);
235 printk("UMSDOS_notify_change: %s/%s change not OK, ret=%d\n",
236 dentry
->d_parent
->d_name
.name
, dentry
->d_name
.name
, ret
);
240 if (inode
->i_nlink
== 0)
242 if (inode
->i_ino
== UMSDOS_ROOT_INO
)
245 /* get the EMD file dentry */
246 demd
= umsdos_get_emd_dentry(dentry
->d_parent
);
251 if (!demd
->d_inode
) {
253 "UMSDOS_notify_change: no EMD file %s/%s\n",
254 demd
->d_parent
->d_name
.name
, demd
->d_name
.name
);
259 /* don't do anything if this is the EMD itself */
260 if (inode
== demd
->d_inode
)
263 /* This inode is not a EMD file nor an inode used internally
264 * by MSDOS, so we can update its status.
268 fill_new_filp (&filp
, demd
);
269 filp
.f_pos
= inode
->u
.umsdos_i
.pos
;
270 Printk(("UMSDOS_notify_change: %s/%s reading at %d\n",
271 dentry
->d_parent
->d_name
.name
, dentry
->d_name
.name
, (int) filp
.f_pos
));
273 /* Read only the start of the entry since we don't touch the name */
274 ret
= umsdos_emd_dir_read (&filp
, (char *) &entry
, UMSDOS_REC_SIZE
);
277 "umsdos_notify_change: %s/%s EMD read error, ret=%d\n",
278 dentry
->d_parent
->d_name
.name
, dentry
->d_name
.name
,ret
);
281 if (attr
->ia_valid
& ATTR_UID
)
282 entry
.uid
= attr
->ia_uid
;
283 if (attr
->ia_valid
& ATTR_GID
)
284 entry
.gid
= attr
->ia_gid
;
285 if (attr
->ia_valid
& ATTR_MODE
)
286 entry
.mode
= attr
->ia_mode
;
287 if (attr
->ia_valid
& ATTR_ATIME
)
288 entry
.atime
= attr
->ia_atime
;
289 if (attr
->ia_valid
& ATTR_MTIME
)
290 entry
.mtime
= attr
->ia_mtime
;
291 if (attr
->ia_valid
& ATTR_CTIME
)
292 entry
.ctime
= attr
->ia_ctime
;
294 entry
.nlink
= inode
->i_nlink
;
295 filp
.f_pos
= inode
->u
.umsdos_i
.pos
;
296 ret
= umsdos_emd_dir_write (&filp
, (char *) &entry
, UMSDOS_REC_SIZE
);
299 "umsdos_notify_change: %s/%s EMD write error, ret=%d\n",
300 dentry
->d_parent
->d_name
.name
, dentry
->d_name
.name
,ret
);
302 Printk (("notify pos %lu ret %d nlink %d ",
303 inode
->u
.umsdos_i
.pos
, ret
, entry
.nlink
));
304 /* #Specification: notify_change / msdos fs
305 * notify_change operation are done only on the
306 * EMD file. The msdos fs is not even called.
308 #ifdef UMSDOS_DEBUG_VERBOSE
309 if (entry
.flags
& UMSDOS_HIDDEN
)
310 printk("umsdos_notify_change: %s/%s hidden, nlink=%d, ret=%d\n",
311 dentry
->d_parent
->d_name
.name
, dentry
->d_name
.name
, entry
.nlink
, ret
);
318 inode_setattr (inode
, attr
);
324 * Update the disk with the inode content
326 void UMSDOS_write_inode (struct inode
*inode
)
328 struct iattr newattrs
;
330 PRINTK (("UMSDOS_write_inode emd %d (FIXME: missing notify_change)\n",
331 inode
->u
.umsdos_i
.i_emd_owner
));
332 fat_write_inode (inode
);
333 newattrs
.ia_mtime
= inode
->i_mtime
;
334 newattrs
.ia_atime
= inode
->i_atime
;
335 newattrs
.ia_ctime
= inode
->i_ctime
;
336 newattrs
.ia_valid
= ATTR_MTIME
| ATTR_ATIME
| ATTR_CTIME
;
338 * UMSDOS_notify_change is convenient to call here
339 * to update the EMD entry associated with this inode.
340 * But it has the side effect to re"dirt" the inode.
343 * UMSDOS_notify_change (inode, &newattrs);
345 * inode->i_state &= ~I_DIRTY; / * FIXME: this doesn't work. We need to remove ourselves from list on dirty inodes. /mn/ */
349 static struct super_operations umsdos_sops
=
351 UMSDOS_read_inode
, /* read_inode */
352 UMSDOS_write_inode
, /* write_inode */
353 UMSDOS_put_inode
, /* put_inode */
354 fat_delete_inode
, /* delete_inode */
355 UMSDOS_notify_change
, /* notify_change */
356 UMSDOS_put_super
, /* put_super */
357 NULL
, /* write_super */
358 fat_statfs
, /* statfs */
359 NULL
/* remount_fs */
363 * Read the super block of an Extended MS-DOS FS.
365 struct super_block
*UMSDOS_read_super (struct super_block
*sb
, void *data
,
368 struct super_block
*res
;
369 struct dentry
*new_root
;
372 MSDOS_SB(sb
)->options
.isvfat
= 0;
374 * Call msdos-fs to mount the disk.
375 * Note: this returns res == sb or NULL
377 res
= msdos_read_super (sb
, data
, silent
);
381 printk (KERN_INFO
"UMSDOS dentry-pre 0.84 "
382 "(compatibility level %d.%d, fast msdos)\n",
383 UMSDOS_VERSION
, UMSDOS_RELEASE
);
385 sb
->s_op
= &umsdos_sops
;
386 MSDOS_SB(sb
)->options
.dotsOK
= 0; /* disable hidden==dotfile */
388 /* install our dentry operations ... */
389 sb
->s_root
->d_op
= &umsdos_dentry_operations
;
390 umsdos_patch_dentry_inode(sb
->s_root
, 0);
392 /* Check whether to change to the /linux root */
393 new_root
= check_pseudo_root(sb
);
397 if (new_root
->d_op
!= &umsdos_dentry_operations
)
398 printk("umsdos_read_super: pseudo-root wrong ops!\n");
400 pseudo_root
= new_root
->d_inode
;
402 saved_root
= sb
->s_root
;
403 sb
->s_root
= new_root
;
404 printk(KERN_INFO
"UMSDOS: changed to alternate root\n");
407 /* if d_count is not 1, mount will fail with -EBUSY! */
408 if (sb
->s_root
->d_count
> 1) {
409 shrink_dcache_sb(sb
);
410 if (sb
->s_root
->d_count
> 1) {
411 printk(KERN_ERR
"UMSDOS: root count %d > 1 !", sb
->s_root
->d_count
);
417 printk(KERN_INFO
"UMSDOS: msdos_read_super failed, mount aborted.\n");
424 * Check for an alternate root if we're the root device.
426 static struct dentry
*check_pseudo_root(struct super_block
*sb
)
428 struct dentry
*root
, *init
;
431 * Check whether we're mounted as the root device.
432 * If so, this should be the only superblock.
434 if (sb
->s_list
.next
->next
!= &sb
->s_list
)
436 printk("check_pseudo_root: mounted as root\n");
438 root
= lookup_dentry(UMSDOS_PSDROOT_NAME
, dget(sb
->s_root
), 0);
443 printk("check_pseudo_root: found %s/%s\n",
444 root
->d_parent
->d_name
.name
, root
->d_name
.name
);
446 /* look for /sbin/init */
447 init
= lookup_dentry("sbin/init", dget(root
), 0);
453 /* check for other files? */
457 printk("check_pseudo_root: found %s/%s, enabling pseudo-root\n",
458 init
->d_parent
->d_name
.name
, init
->d_name
.name
);
462 /* Alternate root not found ... */
470 static struct file_system_type umsdos_fs_type
=
478 __initfunc (int init_umsdos_fs (void))
480 return register_filesystem (&umsdos_fs_type
);
486 int init_module (void)
488 return init_umsdos_fs ();
491 void cleanup_module (void)
493 unregister_filesystem (&umsdos_fs_type
);