/* * This routine checks whether a floppy has been changed, and * invalidates all buffer-cache-entries in that case. This * is a relatively slow routine, so we have to try to minimize using * it. Thus it is called only upon a 'mount' or 'open'. This * is the best way of combining speed and utility, I think. * People changing diskettes in the middle of an operation deserve * to loose :-) * * NOTE! Although currently this is only for floppies, the idea is * that any additional removable block-device will use this routine, * and that mount/open needn't know that floppies/whatever are * special. */ void check_disk_change(int dev) { int i; struct buffer_head * bh; switch(MAJOR(dev)){ case 2: /* floppy disc */ if (!(bh = getblk(dev,0,1024))) return; i = floppy_change(bh); brelse(bh); break; #if defined(CONFIG_BLK_DEV_SR) && defined(CONFIG_SCSI) case 11: /* CDROM */ i = check_cdrom_media_change(dev, 0); if (i) printk("Flushing buffers and inodes for CDROM\n"); break; #endif default: return; }; if (!i) return; for (i=0 ; i<NR_SUPER ; i++) if (super_block[i].s_dev == dev) put_super(super_block[i].s_dev); invalidate_inodes(dev); invalidate_buffers(dev); }
/* * This routine checks whether a removable media has been changed, * and invalidates all buffer-cache-entries in that case. This * is a relatively slow routine, so we have to try to minimize using * it. Thus it is called only upon a 'mount' or 'open'. This * is the best way of combining speed and utility, I think. * People changing diskettes in the middle of an operation deserve * to loose :-) */ int check_disk_change(kdev_t dev) { int i; struct file_operations * fops; struct super_block * sb; i = MAJOR(dev); if (i >= MAX_BLKDEV || (fops = blkdevs[i].fops) == NULL) return 0; if (fops->check_media_change == NULL) return 0; if (!fops->check_media_change(dev)) return 0; printk(KERN_DEBUG "VFS: Disk change detected on device %s\n", bdevname(dev)); sb = get_super(dev); if (sb && invalidate_inodes(sb)) printk("VFS: busy inodes on changed media.\n"); invalidate_buffers(dev); if (fops->revalidate) fops->revalidate(dev); return 1; }
/* * This routine checks whether a removable media has been changed, * and invalidates all buffer-cache-entries in that case. This * is a relatively slow routine, so we have to try to minimize using * it. Thus it is called only upon a 'mount' or 'open'. This * is the best way of combining speed and utility, I think. * People changing diskettes in the middle of an operation deserve * to loose :-) */ int check_disk_change(kdev_t dev) { int i; struct file_operations * fops; i = MAJOR(dev); if (i >= MAX_BLKDEV || (fops = blkdevs[i].fops) == NULL) return 0; if (fops->check_media_change == NULL) return 0; if (!fops->check_media_change(dev)) return 0; printk(KERN_DEBUG "VFS: Disk change detected on device %s\n", kdevname(dev)); for (i=0 ; i<NR_SUPER ; i++) if (super_blocks[i].s_dev == dev) put_super(super_blocks[i].s_dev); invalidate_inodes(dev); invalidate_buffers(dev); if (fops->revalidate) fops->revalidate(dev); return 1; }
//// 检查磁盘是否更换,如果已更换就使对应高速缓冲区无效。 void check_disk_change( int dev ) { int i; // 是软盘设备吗?如果不是则退出。 if( MAJOR( dev ) != 2 ) { return; } // 测试对应软盘是否已更换,如果没有则退出。 if( !floppy_change( dev & 0x03 ) ) { return; } // 软盘已经更换,所以释放对应设备的i 节点位图和逻辑块位图所占的高速缓冲区;并使该设备的 // i 节点和数据块信息所占的高速缓冲区无效。 for( i = 0; i < NR_SUPER; i++ ) { if( super_block[i].s_dev == dev ) { put_super( super_block[i].s_dev ); } } invalidate_inodes( dev ); invalidate_buffers( dev ); }
/* * This is called if the connection has gone bad ... * try to kill off all the current inodes. */ void smb_invalidate_inodes(struct smb_sb_info *server) { VERBOSE("\n"); shrink_dcache_sb(SB_of(server)); invalidate_inodes(SB_of(server)); }
// 回收超级块 static void myfs_kill_sb(struct super_block *sb) { kfree(sb->s_fs_info); if (invalidate_inodes(sb, 1)) // 强制毁灭所有inode及其dirty页 printk("myfs: Eliminate all inodes finished partially!\n"); kill_litter_super(sb); }
static int do_remount_sb(struct super_block *sb, int flags, char *data) { int retval; struct vfsmount *vfsmnt; /* * Invalidate the inodes, as some mount options may be changed. * N.B. If we are changing media, we should check the return * from invalidate_inodes ... can't allow _any_ open files. */ invalidate_inodes(sb); if (!(flags & MS_RDONLY) && sb->s_dev && is_read_only(sb->s_dev)) return -EACCES; /*flags |= MS_RDONLY;*/ /* If we are remounting RDONLY, make sure there are no rw files open */ if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY)) if (!fs_may_remount_ro(sb)) return -EBUSY; if (sb->s_op && sb->s_op->remount_fs) { retval = sb->s_op->remount_fs(sb, &flags, data); if (retval) return retval; } sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK); vfsmnt = lookup_vfsmnt(sb->s_dev); if (vfsmnt) vfsmnt->mnt_flags = sb->s_flags; return 0; }
/* * This routine checks whether a floppy has been changed, and * invalidates all buffer-cache-entries in that case. This * is a relatively slow routine, so we have to try to minimize using * it. Thus it is called only upon a 'mount' or 'open'. This * is the best way of combining speed and utility, I think. * People changing diskettes in the middle of an operation deserve * to loose :-) * * NOTE! Although currently this is only for floppies, the idea is * that any additional removable block-device will use this routine, * and that mount/open needn't know that floppies/whatever are * special. */ void check_disk_change(dev_t dev) { int i; struct buffer_head * bh; switch(MAJOR(dev)){ case FLOPPY_MAJOR: if (!(bh = getblk(dev,0,1024))) return; i = floppy_change(bh); brelse(bh); break; #if defined(CONFIG_BLK_DEV_SD) && defined(CONFIG_SCSI) case SCSI_DISK_MAJOR: i = check_scsidisk_media_change(dev, 0); break; #endif #if defined(CONFIG_BLK_DEV_SR) && defined(CONFIG_SCSI) case SCSI_CDROM_MAJOR: i = check_cdrom_media_change(dev, 0); break; #endif #if defined(CONFIG_CDU31A) case CDU31A_CDROM_MAJOR: i = check_cdu31a_media_change(dev, 0); break; #endif #if defined(CONFIG_MCD) case MITSUMI_CDROM_MAJOR: i = check_mcd_media_change(dev, 0); break; #endif default: return; }; if (!i) return; printk("VFS: Disk change detected on device %d/%d\n", MAJOR(dev), MINOR(dev)); for (i=0 ; i<NR_SUPER ; i++) if (super_blocks[i].s_dev == dev) put_super(super_blocks[i].s_dev); invalidate_inodes(dev); invalidate_buffers(dev); #if defined(CONFIG_BLK_DEV_SD) && defined(CONFIG_SCSI) /* This is trickier for a removable hardisk, because we have to invalidate all of the partitions that lie on the disk. */ if (MAJOR(dev) == SCSI_DISK_MAJOR) revalidate_scsidisk(dev, 0); #endif }
/* * This routine checks whether a floppy has been changed, and * invalidates all buffer-cache-entries in that case. This * is a relatively slow routine, so we have to try to minimize using * it. Thus it is called only upon a 'mount' or 'open'. This * is the best way of combining speed and utility, I think. * People changing diskettes in the middle of an operation deserve * to loose :-) * * NOTE! Although currently this is only for floppies, the idea is * that any additional removable block-device will use this routine, * and that mount/open needn't know that floppies/whatever are * special. */ void check_disk_change(int dev) { int i; if (MAJOR(dev) != 2) return; if (!floppy_change(dev & 0x03)) return; for (i=0 ; i<NR_SUPER ; i++) if (super_block[i].s_dev == dev) put_super(super_block[i].s_dev); invalidate_inodes(dev); invalidate_buffers(dev); }
/* * This routine checks whether a floppy has been changed, and * invalidates all buffer-cache-entries in that case. This * is a relatively slow routine, so we have to try to minimize using * it. Thus it is called only upon a 'mount' or 'open'. This * is the best way of combining speed and utility, I think. * People changing diskettes in the middle of an operation deserve * to loose :-) * * NOTE! Although currently this is only for floppies, the idea is * that any additional removable block-device will use this routine, * and that mount/open needn't know that floppies/whatever are * special. */ void check_disk_change(int dev) { int i; struct buffer_head * bh; if (MAJOR(dev) != 2) return; if (!(bh = getblk(dev,0))) return; i = floppy_change(bh); brelse(bh); if (!i) return; for (i=0 ; i<NR_SUPER ; i++) if (super_block[i].s_dev == dev) put_super(super_block[i].s_dev); invalidate_inodes(dev); invalidate_buffers(dev); }
static int ext2_remount (struct super_block * sb, int * flags, char * data) { struct ext2_sb_info * sbi = EXT2_SB(sb); struct ext2_super_block * es; unsigned long old_mount_opt = sbi->s_mount_opt; struct ext2_mount_options old_opts; unsigned long old_sb_flags; int err; lock_kernel(); /* Store the old options */ old_sb_flags = sb->s_flags; old_opts.s_mount_opt = sbi->s_mount_opt; old_opts.s_resuid = sbi->s_resuid; old_opts.s_resgid = sbi->s_resgid; /* * Allow the "check" option to be passed as a remount option. */ if (!parse_options (data, sbi)) { err = -EINVAL; goto restore_opts; } sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | ((sbi->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); ext2_xip_verify_sb(sb); /* see if bdev supports xip, unset EXT2_MOUNT_XIP if not */ if ((ext2_use_xip(sb)) && (sb->s_blocksize != PAGE_SIZE)) { printk("XIP: Unsupported blocksize\n"); err = -EINVAL; goto restore_opts; } es = sbi->s_es; if (((sbi->s_mount_opt & EXT2_MOUNT_XIP) != (old_mount_opt & EXT2_MOUNT_XIP)) && invalidate_inodes(sb)) { ext2_warning(sb, __func__, "refusing change of xip flag " "with busy inodes while remounting"); sbi->s_mount_opt &= ~EXT2_MOUNT_XIP; sbi->s_mount_opt |= old_mount_opt & EXT2_MOUNT_XIP; } if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) { unlock_kernel(); return 0; } if (*flags & MS_RDONLY) { if (le16_to_cpu(es->s_state) & EXT2_VALID_FS || !(sbi->s_mount_state & EXT2_VALID_FS)) { unlock_kernel(); return 0; } /* * OK, we are remounting a valid rw partition rdonly, so set * the rdonly flag and then mark the partition as valid again. */ es->s_state = cpu_to_le16(sbi->s_mount_state); es->s_mtime = cpu_to_le32(get_seconds()); } else { __le32 ret = EXT2_HAS_RO_COMPAT_FEATURE(sb, ~EXT2_FEATURE_RO_COMPAT_SUPP); if (ret) { printk("EXT2-fs: %s: couldn't remount RDWR because of " "unsupported optional features (%x).\n", sb->s_id, le32_to_cpu(ret)); err = -EROFS; goto restore_opts; } /* * Mounting a RDONLY partition read-write, so reread and * store the current valid flag. (It may have been changed * by e2fsck since we originally mounted the partition.) */ sbi->s_mount_state = le16_to_cpu(es->s_state); if (!ext2_setup_super (sb, es, 0)) sb->s_flags &= ~MS_RDONLY; } ext2_sync_super(sb, es); unlock_kernel(); return 0; restore_opts: sbi->s_mount_opt = old_opts.s_mount_opt; sbi->s_resuid = old_opts.s_resuid; sbi->s_resgid = old_opts.s_resgid; sb->s_flags = old_sb_flags; unlock_kernel(); return err; }
static int rd_ioctl(register struct inode *inode, struct file *file, unsigned int cmd, unsigned int arg) { unsigned long size; unsigned int i; int j, k, target = DEVICE_NR(inode->i_rdev); if (!suser()) return -EPERM; debug2("RD: ioctl %d %s\n", target, (cmd ? "kill" : "make")); switch (cmd) { case RDCREATE: if (rd_info[target].flags && RD_BUSY) { return -EBUSY; } else { /* allocate memory */ #if 0 rd_info[target].size = 0; #endif k = -1; for (i = 0; i <= (arg - 1) / ((SEG_SIZE / 1024) * P_SIZE); i++) { j = find_free_seg(); /* find free place in queue */ debug1("RD: ioctl find_free_seg() = %d\n", j); if (j == -1) { rd_dealloc(target); return -ENOMEM; } if (i == 0) rd_info[target].index = j; if (i == (arg / ((SEG_SIZE / 1024) * P_SIZE))) /* size in 16 byte pagez = (arg % 64) * 64 */ size = (arg % ((SEG_SIZE / 1024) * P_SIZE)) * ((SEG_SIZE / 1024) * P_SIZE); else size = SEG_SIZE; rd_segment[j].segment = mm_alloc(size); if (rd_segment[j].segment == -1) { rd_dealloc(target); return -ENOMEM; } debug4("RD: ioctl pass: %d, allocated %d pages, rd_segment[%d].segment = 0x%x\n", i, (int) size, j, rd_segment[j].segment); /* recalculate int size to reflect size in sectors, not pages */ size = size / DIVISOR; rd_segment[j].seg_size = size; /* size in sectors */ debug2("RD: ioctl rd_segment[%d].seg_size = %d sectors\n", j, rd_segment[j].seg_size); rd_info[target].size += rd_segment[j].seg_size; /* size in 512 B blocks */ size = (long) rd_segment[j].seg_size * SECTOR_SIZE; debug1("RD: ioctl size = %ld\n", size); /* this terrible hack makes sure fmemset clears whole segment even if size == 64 KB :) */ if (size != ((long) SEG_SIZE * (long) P_SIZE)) { debug2("RD: ioctl calling fmemset(0, 0x%x, 0, %d) ..\n", rd_segment[j].segment, (int) size); fmemset(0, rd_segment[j].segment, 0, (int) size); /* clear seg_size * SECTOR_SIZE bytes */ } else { debug2("RD: ioctl calling fmemset(0, 0x%x, 0, %d) ..\n", rd_segment[j].segment, (int) (size / 2)); fmemset(0, rd_segment[j].segment, 0, (int) (size / 2)); /* we could hardcode 32768 instead of size / 2 here */ debug3("rd_ioctl(): calling fmemset(%d, 0x%x, 0, %d) ..\n", (int) (size / 2), rd_segment[j].segment, (int) (size / 2)); fmemset((size / 2), rd_segment[j].segment, 0, (int) (size / 2)); } if (k != -1) rd_segment[k].next = j; /* set link to next index */ k = j; } rd_info[target].flags = RD_BUSY; debug3("RD: ioctl ramdisk %d created, size = %d blocks, index = %d\n", target, rd_info[target].size, rd_info[target].index); } debug("RD: ioctl about to return 0\n"); return 0; case RDDESTROY: if (rd_info[target].flags && RD_BUSY) { invalidate_inodes(inode->i_rdev); invalidate_buffers(inode->i_rdev); rd_dealloc(target); rd_info[target].flags = 0; return 0; } else return -EINVAL; } return -EINVAL; }
static int flash_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int minor; struct flashpartition *part; struct flashchipinfo *finfo; if (!inode || !inode->i_rdev) return -EINVAL; minor = MINOR(inode->i_rdev); if(minor < FLASH_MINOR) return -EINVAL; /* only ioctl's for flash devices */ part = &partitions[minor - FLASH_MINOR]; switch(cmd) { case FLASHIO_CHIPINFO: if(!suser()) return -EACCES; if(arg == 0) return -EINVAL; finfo = (struct flashchipinfo *)arg; /* TODO: verify arg */ finfo->isValid = chips[0].isValid; finfo->manufacturer_id = chips[0].manufacturer_id; finfo->device_id = chips[0].device_id; finfo->size = chips[0].size; finfo->sectorsize = chips[0].sectorsize; return 0; case FLASHIO_ERASEALL: FDEBUG(printk("flash_ioctl(): Got FLASHIO_ERASEALL request.\n")); if(!part->start) return -EINVAL; if(!suser()) return -EACCES; /* Invalidate all pages and buffers */ invalidate_inodes(inode->i_rdev); invalidate_buffers(inode->i_rdev); /* * Start the erasure, then sleep and wake up now and * then to see if it's done. We use the waitqueue to * make sure we don't start erasing in the middle of * a write, or that nobody start using the flash while * we're erasing. * * TODO: break up partition erases that spans more than one * chip. */ flash_safe_acquire(part); flash_init_erase(part->start, part->size); #if 1 flash_finalize_erase(part->start, part->size); #else while (flash_is_busy(part->start) || !flash_pos_is_clean(part->start)) { current->state = TASK_INTERRUPTIBLE; current->timeout = jiffies + HZ / 2; schedule(); } #endif flash_safe_release(part); return 0; default: return -EPERM; } return -EPERM; }
static int do_umount(kdev_t dev, int unmount_root, int flags) { struct super_block * sb; int retval; retval = -ENOENT; sb = get_super(dev); if (!sb || !sb->s_root) goto out; /* * Before checking whether the filesystem is still busy, * make sure the kernel doesn't hold any quota files open * on the device. If the umount fails, too bad -- there * are no quotas running any more. Just turn them on again. */ DQUOT_OFF(dev); acct_auto_close(dev); /* * If we may have to abort operations to get out of this * mount, and they will themselves hold resources we must * allow the fs to do things. In the Unix tradition of * 'Gee thats tricky lets do it in userspace' the umount_begin * might fail to complete on the first run through as other tasks * must return, and the like. Thats for the mount program to worry * about for the moment. */ if( (flags&MNT_FORCE) && sb->s_op->umount_begin) sb->s_op->umount_begin(sb); /* * Shrink dcache, then fsync. This guarantees that if the * filesystem is quiescent at this point, then (a) only the * root entry should be in use and (b) that root entry is * clean. */ shrink_dcache_sb(sb); fsync_dev(dev); if (dev==ROOT_DEV && !unmount_root) { /* * Special case for "unmounting" root ... * we just try to remount it readonly. */ retval = 0; if (!(sb->s_flags & MS_RDONLY)) retval = do_remount_sb(sb, MS_RDONLY, 0); return retval; } retval = d_umount(sb); if (retval) goto out; if (sb->s_op) { if (sb->s_op->write_super && sb->s_dirt) sb->s_op->write_super(sb); } lock_super(sb); if (sb->s_op) { if (sb->s_op->put_super) sb->s_op->put_super(sb); } /* Forget any remaining inodes */ if (invalidate_inodes(sb)) { printk("VFS: Busy inodes after unmount. " "Self-destruct in 5 seconds. Have a nice day...\n"); } sb->s_dev = 0; /* Free the superblock */ unlock_super(sb); remove_vfsmnt(dev); out: return retval; }