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