?? inode.c
字號:
/* * linux/fs/affs/inode.c * * (c) 1996 Hans-Joachim Widmaier - Rewritten * * (C) 1993 Ray Burr - Modified for Amiga FFS filesystem. * * (C) 1992 Eric Youngdale Modified for ISO9660 filesystem. * * (C) 1991 Linus Torvalds - minix filesystem */#include <linux/module.h>#include <linux/errno.h>#include <linux/fs.h>#include <linux/malloc.h>#include <linux/stat.h>#include <linux/sched.h>#include <linux/affs_fs.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/string.h>#include <linux/locks.h>#include <linux/errno.h>#include <linux/genhd.h>#include <linux/amigaffs.h>#include <linux/major.h>#include <linux/blkdev.h>#include <asm/system.h>#include <asm/segment.h>extern int *blk_size[];extern struct timezone sys_tz;#define MIN(a,b) (((a)<(b))?(a):(b))voidaffs_put_super(struct super_block *sb){ int i; pr_debug("affs_put_super()\n"); lock_super(sb); for (i = 0; i < sb->u.affs_sb.s_bm_count; i++) affs_brelse(sb->u.affs_sb.s_bitmap[i].bm_bh); if (!(sb->s_flags & MS_RDONLY)) { ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->bm_flag = htonl(1); secs_to_datestamp(CURRENT_TIME, &ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->disk_altered); affs_fix_checksum(sb->s_blocksize,sb->u.affs_sb.s_root_bh->b_data,5); mark_buffer_dirty(sb->u.affs_sb.s_root_bh,1); } if (sb->u.affs_sb.s_flags & SF_PREFIX) kfree(sb->u.affs_sb.s_prefix); kfree(sb->u.affs_sb.s_bitmap); affs_brelse(sb->u.affs_sb.s_root_bh); /* I'm not happy with this. It would be better to save the previous * value of this devices blksize_size[][] in the super block and * restore it here, but with the affs superblock being quite large * already ... */ set_blocksize(sb->s_dev,BLOCK_SIZE); sb->s_dev = 0; unlock_super(sb); MOD_DEC_USE_COUNT; return;}static voidaffs_write_super(struct super_block *sb){ int i, clean = 2; if (!(sb->s_flags & MS_RDONLY)) { lock_super(sb); for (i = 0, clean = 1; i < sb->u.affs_sb.s_bm_count; i++) { if (sb->u.affs_sb.s_bitmap[i].bm_bh) { if (buffer_dirty(sb->u.affs_sb.s_bitmap[i].bm_bh)) { clean = 0; break; } } } unlock_super(sb); ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->bm_flag = htonl(clean); secs_to_datestamp(CURRENT_TIME, &ROOT_END_S(sb->u.affs_sb.s_root_bh->b_data,sb)->disk_altered); affs_fix_checksum(sb->s_blocksize,sb->u.affs_sb.s_root_bh->b_data,5); mark_buffer_dirty(sb->u.affs_sb.s_root_bh,1); sb->s_dirt = !clean; /* redo until bitmap synced */ } else sb->s_dirt = 0; pr_debug("AFFS: write_super() at %d, clean=%d\n",CURRENT_TIME,clean);}static struct super_operations affs_sops = { affs_read_inode, affs_notify_change, affs_write_inode, affs_put_inode, affs_put_super, affs_write_super, affs_statfs, NULL /* remount */};intaffs_parent_ino(struct inode *dir){ int root_ino = (dir->i_sb->u.affs_sb.s_root_block); if (!S_ISDIR (dir->i_mode)) { printk ("affs_parent_ino: argument is not a directory\n"); return root_ino; } if (dir->i_ino == root_ino) return root_ino; return dir->u.affs_i.i_parent;}static intparse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, int *root, int *blocksize, char **prefix, char *volume, unsigned long *mount_opts){ char *this_char, *value; int f; /* Fill in defaults */ *uid = 0; *gid = 0; *reserved = 2; *root = -1; *blocksize = -1; *prefix = "/"; volume[0] = ':'; volume[1] = 0; *mount_opts = 0; if (!options) return 1; for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) { f = 0; if ((value = strchr(this_char,'=')) != NULL) *value++ = 0; if (!strcmp(this_char,"protect")) { if (value) { printk("AFFS: option protect does not take an argument\n"); return 0; } *mount_opts |= SF_IMMUTABLE; } else if (!strcmp(this_char,"verbose")) { if (value) { printk("AFFS: option verbose does not take an argument\n"); return 0; } *mount_opts |= SF_VERBOSE; } else if ((f = !strcmp(this_char,"uid")) || !strcmp(this_char,"setuid")) { if (!value) *uid = current->uid; else if (!*value) { printk("AFFS: argument for uid option missing\n"); return 0; } else { *uid = simple_strtoul(value,&value,0); if (*value) return 0; if (!f) *mount_opts |= SF_SETUID; } } else if ((f = !strcmp(this_char,"gid")) || !strcmp(this_char,"setgid")) { if (!value) *gid = current->gid; else if (!*value) { printk("AFFS: argument for gid option missing\n"); return 0; } else { *gid = simple_strtoul(value,&value,0); if (*value) return 0; if (!f) *mount_opts |= SF_SETGID; } } else if (!strcmp(this_char,"prefix")) { if (!value) { printk("AFFS: The prefix option requires an argument\n"); return 0; } *prefix = kmalloc(strlen(value) + 1,GFP_KERNEL); if (!*prefix) return 0; strcpy(*prefix,value); *mount_opts |= SF_PREFIX; } else if (!strcmp(this_char,"volume")) { if (!value) { printk("AFFS: The volume option requires an argument\n"); return 0; } if (strlen(value) > 30) value[30] = 0; strcpy(volume,value); } else if (!strcmp(this_char,"mode")) { if (!value || !*value) { printk("AFFS: The mode option requires an argument\n"); return 0; } *mode = simple_strtoul(value,&value,8) & 0777; if (*value) return 0; *mount_opts |= SF_SETMODE; } else if (!strcmp(this_char,"reserved")) { if (!value || !*value) { printk("AFFS: The reserved option requires an argument\n"); return 0; } *reserved = simple_strtoul(value,&value,0); if (*value) return 0; } else if (!strcmp(this_char,"root")) { if (!value || !*value) { printk("AFFS: The root option requires an argument\n"); return 0; } *root = simple_strtoul(value,&value,0); if (*value) return 0; } else if (!strcmp(this_char,"bs")) { if (!value || !*value) { printk("AFFS: The bs option requires an argument\n"); return 0; } *blocksize = simple_strtoul(value,&value,0); if (*value) return 0; if (*blocksize != 512 && *blocksize != 1024 && *blocksize != 2048 && *blocksize != 4096) { printk ("AFFS: Invalid blocksize (512, 1024, 2048, 4096 allowed).\n"); return 0; } } /* Silently ignore the quota options */ else if (!strcmp (this_char, "grpquota") || !strcmp (this_char, "noquota") || !strcmp (this_char, "quota") || !strcmp (this_char, "usrquota")) ; else { printk("AFFS: Unrecognized mount option %s\n", this_char); return 0; } } return 1;}/* This function definitely needs to be split up. Some fine day I'll * hopefully have the guts to do so. Until then: sorry for the mess. */struct super_block *affs_read_super(struct super_block *s,void *data, int silent){ struct buffer_head *bh = NULL; struct buffer_head *bb; kdev_t dev = s->s_dev; int root_block; int size; __u32 chksum; __u32 *bm; int ptype, stype; int mapidx; int num_bm; int i, j; int key; int blocksize; uid_t uid; gid_t gid; int reserved; int az_no; unsigned long mount_flags; unsigned long offset; pr_debug("affs_read_super(%s)\n",data ? (const char *)data : "no options"); MOD_INC_USE_COUNT; if (!parse_options(data,&uid,&gid,&i,&reserved,&root_block, &blocksize,&s->u.affs_sb.s_prefix,s->u.affs_sb.s_volume,&mount_flags)) { s->s_dev = 0; printk("AFFS: error parsing options.\n"); MOD_DEC_USE_COUNT; return NULL; } lock_super(s); /* Get the size of the device in 512-byte blocks. * If we later see that the partition uses bigger * blocks, we will have to change it. */ size = blksize_size[MAJOR(dev)][MINOR(dev)]; size = (size ? size : BLOCK_SIZE) / 512 * blk_size[MAJOR(dev)][MINOR(dev)]; s->u.affs_sb.s_bitmap = NULL; s->u.affs_sb.s_root_bh = NULL; s->u.affs_sb.s_flags = mount_flags; s->u.affs_sb.s_mode = i; s->u.affs_sb.s_uid = uid; s->u.affs_sb.s_gid = gid; if (size == 0) { s->s_dev = 0; unlock_super(s); printk("affs_read_super: could not determine device size\n"); goto out; } s->u.affs_sb.s_partition_size = size; s->u.affs_sb.s_reserved = reserved; /* Try to find root block. Its location may depend on the block size. */ s->u.affs_sb.s_hashsize = 0; if (blocksize > 0) { chksum = blocksize; num_bm = blocksize; } else { chksum = 512; num_bm = 4096; } for (blocksize = chksum; blocksize <= num_bm; blocksize <<= 1, size >>= 1) { if (root_block < 0) s->u.affs_sb.s_root_block = (reserved + size - 1) / 2; else s->u.affs_sb.s_root_block = root_block; pr_debug("Trying bs=%d bytes, root at %d, size=%d blocks (%d reserved)\n", blocksize,s->u.affs_sb.s_root_block,size,reserved); set_blocksize(dev,blocksize); bh = affs_bread(dev,s->u.affs_sb.s_root_block,blocksize); if (!bh) { printk("AFFS: unable to read root block\n"); goto out; } if (!affs_checksum_block(blocksize,bh->b_data,&ptype,&stype) && ptype == T_SHORT && stype == ST_ROOT) { s->s_blocksize = blocksize; s->u.affs_sb.s_hashsize = blocksize / 4 - 56; break; } affs_brelse(bh); bh = NULL; } if (!s->u.affs_sb.s_hashsize) { affs_brelse(bh); if (!silent) printk("AFFS: Can't find a valid root block on device %s\n",kdevname(dev)); goto out; } root_block = s->u.affs_sb.s_root_block; s->u.affs_sb.s_partition_size = size; s->s_blocksize_bits = blocksize == 512 ? 9 : blocksize == 1024 ? 10 : blocksize == 2048 ? 11 : 12; /* Find out which kind of FS we have */ bb = affs_bread(dev,0,s->s_blocksize); if (bb) { chksum = htonl(*(__u32 *)bb->b_data); /* Dircache filesystems are compatible with non-dircache ones * when reading. As long as they aren't supported, writing is * not recommended. */ if ((chksum == FS_DCFFS || chksum == MUFS_DCFFS || chksum == FS_DCOFS || chksum == MUFS_DCOFS) && !(s->s_flags & MS_RDONLY)) { printk("AFFS: Dircache FS - mounting %s read only.\n",kdevname(dev)); s->s_flags |= MS_RDONLY; } switch (chksum) { case MUFS_FS: case MUFS_INTLFFS: s->u.affs_sb.s_flags |= SF_MUFS; /* fall thru */ case FS_INTLFFS: s->u.affs_sb.s_flags |= SF_INTL; break; case MUFS_DCFFS: case MUFS_FFS: s->u.affs_sb.s_flags |= SF_MUFS; break; case FS_DCFFS: case FS_FFS: break; case MUFS_OFS: s->u.affs_sb.s_flags |= SF_MUFS; /* fall thru */ case FS_OFS: s->u.affs_sb.s_flags |= SF_OFS; break; case MUFS_DCOFS: case MUFS_INTLOFS: s->u.affs_sb.s_flags |= SF_MUFS; case FS_DCOFS: case FS_INTLOFS: s->u.affs_sb.s_flags |= SF_INTL | SF_OFS; break; default: printk("AFFS: Unknown filesystem on device %s: %08X\n", kdevname(dev),chksum); affs_brelse(bb); goto out; } affs_brelse(bb); } else { printk("AFFS: Can't get boot block.\n"); goto out; } if (mount_flags & SF_VERBOSE) { chksum = ntohl(chksum); printk("AFFS: Mounting volume \"%*s\": Type=%.3s\\%c, Blocksize=%d\n", GET_END_PTR(struct root_end,bh->b_data,blocksize)->disk_name[0], &GET_END_PTR(struct root_end,bh->b_data,blocksize)->disk_name[1], (char *)&chksum,((char *)&chksum)[3] + '0',blocksize); } s->s_magic = AFFS_SUPER_MAGIC; s->s_flags |= MS_NODEV | MS_NOSUID; /* Keep super block in cache */ if (!(s->u.affs_sb.s_root_bh = affs_bread(dev,root_block,s->s_blocksize))) { printk("AFFS: Can't read root block a second time\n"); goto out; } /* Allocate space for bitmaps, zones and others */ size = s->u.affs_sb.s_partition_size - reserved; num_bm = (size + s->s_blocksize * 8 - 32 - 1) / (s->s_blocksize * 8 - 32); az_no = (size + AFFS_ZONE_SIZE - 1) / (AFFS_ZONE_SIZE - 32); ptype = num_bm * sizeof(struct affs_bm_info) + az_no * sizeof(struct affs_alloc_zone) + MAX_ZONES * sizeof(struct affs_zone); pr_debug("num_bm=%d, az_no=%d, sum=%d\n",num_bm,az_no,ptype); if (!(s->u.affs_sb.s_bitmap = kmalloc(ptype,GFP_KERNEL))) { printk("AFFS: Not enough memory.\n"); goto out; } memset(s->u.affs_sb.s_bitmap,0,ptype); s->u.affs_sb.s_zones = (struct affs_zone *)&s->u.affs_sb.s_bitmap[num_bm]; s->u.affs_sb.s_alloc = (struct affs_alloc_zone *)&s->u.affs_sb.s_zones[MAX_ZONES]; s->u.affs_sb.s_num_az = az_no; mapidx = 0; if (ROOT_END_S(bh->b_data,s)->bm_flag == 0) { if (!(s->s_flags & MS_RDONLY)) { printk("AFFS: Bitmap invalid - mounting %s read only.\n",kdevname(dev)); s->s_flags |= MS_RDONLY; } affs_brelse(bh); bh = NULL; goto nobitmap; } /* The following section is ugly, I know. Especially because of the * reuse of some variables that are not named properly. */ key = root_block; ptype = s->s_blocksize / 4 - 49; stype = ptype + 25; offset = s->u.affs_sb.s_reserved; az_no = 0; while (bh) { bm = (__u32 *)bh->b_data; for (i = ptype; i < stype && bm[i]; i++, mapidx++) { if (mapidx >= num_bm) { printk("AFFS: Not enough bitmap space!?\n"); goto out; } bb = affs_bread(s->s_dev,htonl(bm[i]),s->s_blocksize); if (bb) { if (affs_checksum_block(s->s_blocksize,bb->b_data,NULL,NULL) && !(s->s_flags & MS_RDONLY)) { printk("AFFS: Bitmap (%d,key=%lu) invalid - "
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -