/* Load an inode from disk. */ void UMSDOS_read_inode(struct inode *inode) { PRINTK (("read inode %x ino = %d ",inode,inode->i_ino)); msdos_read_inode(inode); PRINTK (("ino = %d %d\n",inode->i_ino,inode->i_count)); if (S_ISDIR(inode->i_mode) && (inode->u.umsdos_i.u.dir_info.creating != 0 || inode->u.umsdos_i.u.dir_info.looking != 0 || waitqueue_active(&inode->u.umsdos_i.u.dir_info.p))){ Printk (("read inode %d %d %p\n" ,inode->u.umsdos_i.u.dir_info.creating ,inode->u.umsdos_i.u.dir_info.looking ,inode->u.umsdos_i.u.dir_info.p)); } /* #Specification: Inode / post initialisation To completely initialise an inode, we need access to the owner directory, so we can locate more info in the EMD file. This is not available the first time the inode is access, we use a value in the inode to tell if it has been finally initialised. At first, we have tried testing i_count but it was causing problem. It is possible that two or more process use the newly accessed inode. While the first one block during the initialisation (probably while reading the EMD file), the others believe all is well because i_count > 1. They go banana with a broken inode. See umsdos_lookup_patch and umsdos_patch_inode. */ umsdos_patch_inode(inode,NULL,0); }
static int msdos_create_entry(struct inode *dir,char *name,int is_dir, struct inode **result) { struct buffer_head *bh; struct msdos_dir_entry *de; int res,ino; if ((res = msdos_scan(dir,NULL,&bh,&de,&ino)) < 0) { if (dir->i_ino == MSDOS_ROOT_INO) return -ENOSPC; if ((res = msdos_add_cluster(dir)) < 0) return res; if ((res = msdos_scan(dir,NULL,&bh,&de,&ino)) < 0) return res; } memcpy(de->name,name,MSDOS_NAME); de->attr = is_dir ? ATTR_DIR : ATTR_ARCH; de->start = 0; date_unix2dos(CURRENT_TIME,&de->time,&de->date); de->size = 0; bh->b_dirt = 1; if (*result = iget(dir->i_dev,ino)) msdos_read_inode(*result); brelse(bh); if (!*result) return -EIO; (*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime = CURRENT_TIME; (*result)->i_dirt = 1; return 0; }
static int rename_same_dir(struct inode *old_dir,char *old_name, struct inode *new_dir,char *new_name,struct buffer_head *old_bh, struct msdos_dir_entry *old_de,int old_ino) { struct buffer_head *new_bh; struct msdos_dir_entry *new_de; struct inode *new_inode,*old_inode; int new_ino; int exists; if (!strncmp(old_name,new_name,MSDOS_NAME)) return 0; exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino) >= 0; if (*(unsigned char *) old_de->name == DELETED_FLAG) { if (exists) brelse(new_bh); return -ENOENT; } if (exists) { if (!(new_inode = iget(new_dir->i_dev,new_ino))) { brelse(new_bh); return -EIO; } if (S_ISDIR(new_inode->i_mode)) { iput(new_inode); brelse(new_bh); return -EPERM; } new_inode->i_nlink = 0; MSDOS_I(new_inode)->i_busy = 1; new_inode->i_dirt = 1; new_de->name[0] = DELETED_FLAG; new_bh->b_dirt = 1; iput(new_inode); brelse(new_bh); } memcpy(old_de->name,new_name,MSDOS_NAME); old_bh->b_dirt = 1; if (MSDOS_SB(old_dir->i_sb)->conversion == 'a') /* update binary info */ if (old_inode = iget(old_dir->i_dev,old_ino)) { msdos_read_inode(old_inode); iput(old_inode); } return 0; }
static int rename_diff_dir(struct inode *old_dir,char *old_name, struct inode *new_dir,char *new_name,struct buffer_head *old_bh, struct msdos_dir_entry *old_de,int old_ino) { struct buffer_head *new_bh,*free_bh,*dotdot_bh; struct msdos_dir_entry *new_de,*free_de,*dotdot_de; struct inode *old_inode,*new_inode,*free_inode,*dotdot_inode,*walk; int new_ino,free_ino,dotdot_ino; int error,exists,ino; if (old_dir->i_dev != new_dir->i_dev) return -EINVAL; if (old_ino == new_dir->i_ino) return -EINVAL; if (!(walk = iget(new_dir->i_dev,new_dir->i_ino))) return -EIO; while (walk->i_ino != MSDOS_ROOT_INO) { ino = msdos_parent_ino(walk,1); iput(walk); if (ino < 0) return ino; if (ino == old_ino) return -EINVAL; if (!(walk = iget(new_dir->i_dev,ino))) return -EIO; } iput(walk); if ((error = msdos_scan(new_dir,NULL,&free_bh,&free_de,&free_ino)) < 0) return error; exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino) >= 0; if (!(old_inode = iget(old_dir->i_dev,old_ino))) { brelse(free_bh); if (exists) brelse(new_bh); return -EIO; } if (*(unsigned char *) old_de->name == DELETED_FLAG) { iput(old_inode); brelse(free_bh); if (exists) brelse(new_bh); return -ENOENT; } new_inode = NULL; /* to make GCC happy */ if (exists) { if (!(new_inode = iget(new_dir->i_dev,new_ino))) { iput(old_inode); brelse(new_bh); return -EIO; } if (S_ISDIR(new_inode->i_mode)) { iput(new_inode); iput(old_inode); brelse(new_bh); return -EPERM; } new_inode->i_nlink = 0; MSDOS_I(new_inode)->i_busy = 1; new_inode->i_dirt = 1; new_de->name[0] = DELETED_FLAG; new_bh->b_dirt = 1; } memcpy(free_de,old_de,sizeof(struct msdos_dir_entry)); memcpy(free_de->name,new_name,MSDOS_NAME); if (!(free_inode = iget(new_dir->i_dev,free_ino))) { free_de->name[0] = DELETED_FLAG; /* Don't mark free_bh as dirty. Both states are supposed to be equivalent. */ brelse(free_bh); if (exists) { iput(new_inode); brelse(new_bh); } return -EIO; } msdos_read_inode(free_inode); MSDOS_I(old_inode)->i_busy = 1; cache_inval_inode(old_inode); old_inode->i_dirt = 1; old_de->name[0] = DELETED_FLAG; old_bh->b_dirt = 1; free_bh->b_dirt = 1; if (!exists) iput(free_inode); else { MSDOS_I(new_inode)->i_depend = free_inode; MSDOS_I(free_inode)->i_old = new_inode; /* free_inode is put when putting new_inode */ iput(new_inode); brelse(new_bh); } if (S_ISDIR(old_inode->i_mode)) { if ((error = msdos_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh, &dotdot_de,&dotdot_ino)) < 0) goto rename_done; if (!(dotdot_inode = iget(old_inode->i_dev,dotdot_ino))) { brelse(dotdot_bh); error = -EIO; goto rename_done; } dotdot_de->start = MSDOS_I(dotdot_inode)->i_start = MSDOS_I(new_dir)->i_start; dotdot_inode->i_dirt = 1; dotdot_bh->b_dirt = 1; iput(dotdot_inode); brelse(dotdot_bh); old_dir->i_nlink--; new_dir->i_nlink++; /* no need to mark them dirty */ } error = 0; rename_done: brelse(free_bh); iput(old_inode); return error; }