root/fs/umsdos/inode.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. UMSDOS_put_inode
  2. UMSDOS_put_super
  3. UMSDOS_statfs
  4. umsdos_real_lookup
  5. umsdos_setup_dir_inode
  6. umsdos_set_dirinfo
  7. umsdos_isinit
  8. umsdos_patch_inode
  9. umsdos_get_dirowner
  10. UMSDOS_read_inode
  11. UMSDOS_write_inode
  12. UMSDOS_notify_change
  13. UMSDOS_read_super
  14. init_module
  15. cleanup_module

   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][next][first][last][top][bottom][index][help] */
  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][next][first][last][top][bottom][index][help] */
  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, int bufsiz)
     /* [previous][next][first][last][top][bottom][index][help] */
  65 {
  66         msdos_statfs(sb,buf,bufsiz);
  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][next][first][last][top][bottom][index][help] */
  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][next][first][last][top][bottom][index][help] */
  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][next][first][last][top][bottom][index][help] */
 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][next][first][last][top][bottom][index][help] */
 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][next][first][last][top][bottom][index][help] */
 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][next][first][last][top][bottom][index][help] */
 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][next][first][last][top][bottom][index][help] */
 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][next][first][last][top][bottom][index][help] */
 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][next][first][last][top][bottom][index][help] */
 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][next][first][last][top][bottom][index][help] */
 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][next][first][last][top][bottom][index][help] */
 511 {
 512         register_filesystem(&umsdos_fs_type);
 513         return 0;
 514 }
 515 
 516 void cleanup_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 517 {
 518         unregister_filesystem(&umsdos_fs_type);
 519 }
 520 
 521 #endif
 522 

/* [previous][next][first][last][top][bottom][index][help] */