diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-12-16 05:34:03 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1997-12-16 05:34:03 +0000 |
commit | 967c65a99059fd459b956c1588ce0ba227912c4e (patch) | |
tree | 8224d013ff5d255420713d05610c7efebd204d2a /fs | |
parent | e20c1cc1656a66a2773bca4591a895cbc12696ff (diff) |
Merge with Linux 2.1.72, part 1.
Diffstat (limited to 'fs')
53 files changed, 1904 insertions, 2168 deletions
diff --git a/fs/Config.in b/fs/Config.in index d7826af19..b8c293955 100644 --- a/fs/Config.in +++ b/fs/Config.in @@ -23,7 +23,7 @@ dep_tristate 'VFAT (Windows-95) fs support' CONFIG_VFAT_FS $CONFIG_FAT_FS bool '/proc filesystem support' CONFIG_PROC_FS if [ "$CONFIG_INET" = "y" ]; then tristate 'NFS filesystem support' CONFIG_NFS_FS - if [ "$CONFIG_NFS_FS" = "y" ]; then + if [ "$CONFIG_NFS_FS" = "y" -a "$CONFIG_IP_PNP" = "y" ]; then bool ' Root file system on NFS' CONFIG_ROOT_NFS if [ "$CONFIG_ROOT_NFS" = "y" ]; then bool ' BOOTP support' CONFIG_RNFS_BOOTP @@ -43,6 +43,7 @@ if [ "$CONFIG_INET" = "y" ]; then define_bool CONFIG_LOCKD n fi fi + tristate 'Coda filesystem support (advanced network fs)' CONFIG_CODA_FS tristate 'SMB filesystem support (to mount WfW shares etc..)' CONFIG_SMB_FS if [ "$CONFIG_SMB_FS" != "n" ]; then bool 'SMB Win95 bug work-around' CONFIG_SMB_WIN95 diff --git a/fs/Makefile b/fs/Makefile index 0b0f5f5ee..9e212be70 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -16,7 +16,7 @@ O_OBJS = open.o read_write.o devices.o file_table.o buffer.o \ inode.o dcache.o attr.o bad_inode.o $(BINFMTS) MOD_LIST_NAME := FS_MODULES -ALL_SUB_DIRS = minix ext2 fat msdos vfat proc isofs nfs umsdos \ +ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs umsdos \ hpfs sysv smbfs ncpfs ufs affs romfs autofs lockd nfsd nls ifeq ($(CONFIG_QUOTA),y) @@ -29,6 +29,14 @@ ifeq ($(CONFIG_TRANS_NAMES),y) O_OBJS += nametrans.o endif +ifeq ($(CONFIG_CODA_FS),y) +SUB_DIRS += coda +else + ifeq ($(CONFIG_CODA_FS),m) + MOD_SUB_DIRS += coda + endif +endif + ifeq ($(CONFIG_MINIX_FS),y) SUB_DIRS += minix else diff --git a/fs/affs/Changes b/fs/affs/Changes index b19c24ae6..06736aa3a 100644 --- a/fs/affs/Changes +++ b/fs/affs/Changes @@ -12,16 +12,96 @@ Known bugs: apparently not causing the failure, as directory reads basically work (but all files are of size 0). Alas, I've got no alpha to debug. :-( -- If an affs mounted filesystem is exported via - nfs, it cannot be written to. - As soon as I have my network up and running, I'll - try to fix this. + - The partition checker (drivers/block/genhd.c) doesn't work with devices which have 256 byte blocks (some very old SCSI drives). +- The feature to automatically make the fs clean + might leave a trashed file system with the + bitmap flag set valid. + +- The blocks from deleted directories are + sometimes reclaimed only at umount time. + Please direct bug reports to: hjw@zvw.de +Version 3.6 +----------- + +- dentry changes. (Thanks to Jes Sorensen for his help.) + +- Fixed bug in balloc(): Superblock was not set dirty after + the bitmap was changed, so the bitmap wasn't sync'd. + +- Fixed nasty bug in find_new_zone(): If the current + zone number was zero, the loop didn't terminate, + causing a solid lock-up. + +- Removed support for old-style directory reads. + +- Fixed bug in add_entry(): When doing a sorted insert, + the pointer to the next entry in the hash chain wasn't + correctly byte-swapped. Since most of the users of the + affs use it on a 68k, they didn't notice. But why did + I not find this during my tests? + +- Fixed some oversights (version wasn't updated on some + directory changes). + +- Handling of hard links rewritten. To the VFS + they appear now as normal unix links. They are + now resolved only once in lookup(). The backside + is that unlink(), rename() and rmdir() have to + be smart about them, but the result is worth the + effort. This also led to some code cleanup. + +- Changed name type to unsigned char; the test for + invalid filenames didn't work correctly. + (Thanks to Michael Krause for pointing at this.) + +- Changed mapping of executable flag. + +- Changed all network byte-order macros to the + recommended ones. + +- Added a remount function, so attempts to remount + a dircache filesystem or one with errors read/write + can be trapped. Previously, ro remounts didn't + flush the super block, and rw remounts didn't + create allocation zones ... + +- Call shrink_dcache_parent() in rmdir(). + (Thanks to Bill Hawes.) + +- Permission checks in unlink(). + +- Allow mounting of volumes with superfluous + bitmap pointers read only, also allows them + to be remounted read/write. + +- Owner/Group defaults now to the fs user (i.e. + the one that mounted it) instead of root. This + obsoletes the mount options uid and gid. + +- Argument to volume option could overflow the + name buffer. It is now silently truncated to + 30 characters. (Damnit! This kind of bug + is too embarrassing.) + +- Split inode.c into 2 files, the superblock + routines desperately wanted their own file. + +- truncate() didn't allocate an extension block + cache. If a file was extended by means of + truncate(), this led to an Oops. + +- fsuser is now checked last. + +- rename() will not ignore changes in filename + casing any more (though mv(1) still won't allow + you to do "mv oldname OldName"). + Version 3.5 ----------- diff --git a/fs/affs/Makefile b/fs/affs/Makefile index 77cb4225f..1dba61b41 100644 --- a/fs/affs/Makefile +++ b/fs/affs/Makefile @@ -8,7 +8,7 @@ # Note 2! The CFLAGS definitions are now in the main makefile... O_TARGET := affs.o -O_OBJS := namei.o inode.o file.o dir.o amigaffs.o bitmap.o symlink.o +O_OBJS := super.o namei.o inode.o file.o dir.o amigaffs.o bitmap.o symlink.o M_OBJS := $(O_TARGET) include $(TOPDIR)/Rules.make diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c index 7ddb54a62..68c61753b 100644 --- a/fs/affs/amigaffs.c +++ b/fs/affs/amigaffs.c @@ -8,6 +8,7 @@ * Please send bug reports to: hjw@zvw.de */ +#define DEBUG 0 #include <stdarg.h> #include <linux/stat.h> #include <linux/sched.h> @@ -30,7 +31,7 @@ static char ErrorBuffer[256]; pointed to by FH_DATA. The length of the name is returned. */ int -affs_get_file_name(int bsize, void *fh_data, char **name) +affs_get_file_name(int bsize, void *fh_data, unsigned char **name) { struct file_end *file_end; @@ -42,100 +43,142 @@ affs_get_file_name(int bsize, void *fh_data, char **name) *name = "***BAD_FILE***"; return 14; } - *name = (char *)&file_end->file_name[1]; + *name = (unsigned char *)&file_end->file_name[1]; return file_end->file_name[0]; } -/* Find the predecessor in the hash chain */ +/* Insert a header block (file) into the directory (next). + * This routine assumes that the caller has the superblock locked. + */ int -affs_fix_hash_pred(struct inode *startino, int startoffset, s32 key, s32 newkey) +affs_insert_hash(unsigned long next, struct buffer_head *file, struct inode *inode) { - struct buffer_head *bh = NULL; - s32 nextkey; - s32 ptype, stype; - int retval; + struct buffer_head *bh; + s32 ino; + int offset; + + offset = affs_hash_name(FILE_END(file->b_data,inode)->file_name+1, + FILE_END(file->b_data,inode)->file_name[0], + AFFS_I2FSTYPE(inode),AFFS_I2HSIZE(inode)) + 6; + ino = be32_to_cpu(((struct dir_front *)file->b_data)->own_key); + + pr_debug("AFFS: insert_hash(dir_ino=%lu,ino=%d)\n",next,ino); + + FILE_END(file->b_data,inode)->parent = cpu_to_be32(next); - nextkey = startino->i_ino; - retval = -ENOENT; - lock_super(startino->i_sb); while (1) { - pr_debug("AFFS: fix_hash_pred(): next key=%d, offset=%d\n",nextkey,startoffset); - if (nextkey == 0) + if (!(bh = affs_bread(inode->i_dev,next,AFFS_I2BSIZE(inode)))) + return -EIO; + next = be32_to_cpu(((s32 *)bh->b_data)[offset]); + if (!next || next > ino) break; - if (!(bh = affs_bread(startino->i_dev,nextkey,AFFS_I2BSIZE(startino)))) + offset = AFFS_I2BSIZE(inode) / 4 - 4; + affs_brelse(bh); + } + + DIR_END(file->b_data,inode)->hash_chain = cpu_to_be32(next); + ((s32 *)bh->b_data)[offset] = cpu_to_be32(ino); + affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5); + mark_buffer_dirty(bh,1); + affs_brelse(bh); + + return 0; +} +/* Remove a header block from it's hash table (directory). + * 'inode' may be any inode on the partition, it's only + * used for calculating the block size and superblock + * reference. + */ + +int +affs_remove_hash(struct buffer_head *dbh, struct inode *inode) +{ + s32 ownkey; + s32 key; + s32 ptype; + s32 stype; + int offset; + int retval; + struct buffer_head *bh; + + ownkey = be32_to_cpu(((struct dir_front *)dbh->b_data)->own_key); + key = be32_to_cpu(FILE_END(dbh->b_data,inode)->parent); + offset = affs_hash_name(FILE_END(dbh->b_data,inode)->file_name+1, + FILE_END(dbh->b_data,inode)->file_name[0], + AFFS_I2FSTYPE(inode),AFFS_I2HSIZE(inode)) + 6; + pr_debug("AFFS: remove_hash(dir=%d, ino=%d, hashval=%d)\n",key,ownkey,offset-6); + retval = -ENOENT; + + lock_super(inode->i_sb); + while (key) { + if (!(bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)))) { + retval = -EIO; break; - if (affs_checksum_block(AFFS_I2BSIZE(startino),bh->b_data,&ptype,&stype) + } + if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&ptype,&stype) || ptype != T_SHORT || (stype != ST_FILE && stype != ST_USERDIR && stype != ST_LINKFILE && stype != ST_LINKDIR && stype != ST_ROOT && stype != ST_SOFTLINK)) { - affs_error(startino->i_sb,"affs_fix_hash_pred", - "Bad block in link chain (ptype=%d, stype=%d)",ptype,stype); + affs_error(inode->i_sb,"affs_remove_hash", + "Bad block in hash chain (key=%d, ptype=%d, stype=%d, ownkey=%d)", + key,ptype,stype,ownkey); affs_brelse(bh); + retval = -EINVAL; break; } - nextkey = htonl(((s32 *)bh->b_data)[startoffset]); - if (nextkey == key) { - ((s32 *)bh->b_data)[startoffset] = newkey; - affs_fix_checksum(AFFS_I2BSIZE(startino),bh->b_data,5); + key = be32_to_cpu(((s32 *)bh->b_data)[offset]); + if (ownkey == key) { + ((s32 *)bh->b_data)[offset] = FILE_END(dbh->b_data,inode)->hash_chain; + affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5); mark_buffer_dirty(bh,1); affs_brelse(bh); retval = 0; break; } affs_brelse(bh); - startoffset = AFFS_I2BSIZE(startino) / 4 - 4; + offset = AFFS_I2BSIZE(inode) / 4 - 4; } - unlock_super(startino->i_sb); + unlock_super(inode->i_sb); return retval; } -/* Remove inode from link chain */ +/* Remove header from link chain */ int -affs_fix_link_pred(struct inode *startino, s32 key, s32 newkey) +affs_remove_link(struct buffer_head *dbh, struct inode *inode) { - struct buffer_head *bh = NULL; - s32 nextkey; - int offset; - s32 etype = 0; - s32 ptype, stype; int retval; - - offset = AFFS_I2BSIZE(startino) / 4 - 10; - nextkey = startino->i_ino; - retval = -ENOENT; - lock_super(startino->i_sb); - while (1) { - if (nextkey == 0) - break; - pr_debug("AFFS: find_link_pred(): next key=%d\n",nextkey); - if (!(bh = affs_bread(startino->i_dev,nextkey,AFFS_I2BSIZE(startino)))) - break; - if (affs_checksum_block(AFFS_I2BSIZE(startino),bh->b_data,&ptype,&stype) - || ptype != T_SHORT) { - affs_brelse(bh); + s32 key; + s32 ownkey; + s32 ptype; + s32 stype; + struct buffer_head *bh; + + ownkey = be32_to_cpu((DIR_FRONT(dbh)->own_key)); + key = be32_to_cpu(FILE_END(dbh->b_data,inode)->original); + retval = -ENOENT; + + pr_debug("AFFS: remove_link(link=%d, original=%d)\n",ownkey,key); + + lock_super(inode->i_sb); + while (key) { + if (!(bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)))) { + retval = -EIO; break; } - if (!etype) { - if (stype != ST_FILE && stype != ST_USERDIR) { - affs_brelse(bh); - break; - } - if (stype == ST_FILE) - etype = ST_LINKFILE; - else - etype = ST_LINKDIR; - } else if (stype != etype) { + if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&ptype,&stype)) { + affs_error(inode->i_sb,"affs_remove_link","Checksum error (block %d)",key); affs_brelse(bh); - retval = -EPERM; + retval = -EINVAL; break; } - nextkey = htonl(((s32 *)bh->b_data)[offset]); - if (nextkey == key) { - FILE_END(bh->b_data,startino)->link_chain = newkey; - affs_fix_checksum(AFFS_I2BSIZE(startino),bh->b_data,5); + key = be32_to_cpu(FILE_END(bh->b_data,inode)->link_chain); + if (ownkey == key) { + FILE_END(bh->b_data,inode)->link_chain = + FILE_END(dbh->b_data,inode)->link_chain; + affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5); mark_buffer_dirty(bh,1); affs_brelse(bh); retval = 0; @@ -143,10 +186,102 @@ affs_fix_link_pred(struct inode *startino, s32 key, s32 newkey) } affs_brelse(bh); } - unlock_super(startino->i_sb); + unlock_super(inode->i_sb); + return retval; } +/* Remove a filesystem object. If the object to be removed has + * links to it, one of the links must be changed to inherit + * the file or directory. As above, any inode will do. + * The buffer will not be freed. If the header is a link, the + * block will be marked as free. + * This function returns a negative error number in case of + * an error, else 0 if the inode is to be deleted or 1 if not. + */ + +int +affs_remove_header(struct buffer_head *bh, struct inode *inode) +{ + struct buffer_head *link_bh; + struct inode *dir; + unsigned long link_ino; + unsigned long orig_ino; + unsigned int dir_ino; + int error; + + pr_debug("AFFS: remove_header(key=%ld)\n",be32_to_cpu(DIR_FRONT(bh)->own_key)); + + /* Mark directory as changed. We do this before anything else, + * as it must be done anyway and doesn't hurt even if an + * error occures later. + */ + dir = iget(inode->i_sb,be32_to_cpu(FILE_END(bh->b_data,inode)->parent)); + if (!dir) + return -EIO; + dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->i_version++; + mark_inode_dirty(dir); + iput(dir); + + orig_ino = be32_to_cpu(FILE_END(bh->b_data,inode)->original); + if (orig_ino) { /* This is just a link. Nothing much to do. */ + pr_debug(" Removing link.\n"); + if ((error = affs_remove_link(bh,inode))) + return error; + if ((error = affs_remove_hash(bh,inode))) + return error; + affs_free_block(inode->i_sb,be32_to_cpu(DIR_FRONT(bh)->own_key)); + return 1; + } + + link_ino = be32_to_cpu(FILE_END(bh->b_data,inode)->link_chain); + if (link_ino) { /* This is the complicated case. Yuck. */ + pr_debug(" Removing original with links to it.\n"); + /* Unlink the object and its first link from their directories. */ + if ((error = affs_remove_hash(bh,inode))) + return error; + if (!(link_bh = affs_bread(inode->i_dev,link_ino,AFFS_I2BSIZE(inode)))) + return -EIO; + if ((error = affs_remove_hash(link_bh,inode))) { + affs_brelse(link_bh); + return error; + } + /* Fix link chain. */ + if ((error = affs_remove_link(link_bh,inode))) { + affs_brelse(link_bh); + return error; + } + /* Rename link to object. */ + memcpy(FILE_END(bh->b_data,inode)->file_name, + FILE_END(link_bh->b_data,inode)->file_name,32); + /* Insert object into dir the link was in. */ + dir_ino = be32_to_cpu(FILE_END(link_bh->b_data,inode)->parent); + if ((error = affs_insert_hash(dir_ino,bh,inode))) { + affs_brelse(link_bh); + return error; + } + affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5); + mark_buffer_dirty(bh,1); + affs_brelse(link_bh); + affs_free_block(inode->i_sb,link_ino); + /* Mark the link's parent dir as changed, too. */ + if (!(dir = iget(inode->i_sb,dir_ino))) + return -EIO; + dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->i_version++; + mark_inode_dirty(dir); + iput(dir); + return 1; + } + /* Plain file/dir. This is the simplest case. */ + pr_debug(" Removing plain file/dir.\n"); + if ((error = affs_remove_hash(bh,inode))) + return error; + return 0; +} + + /* Checksum a block, do various consistency checks and optionally return the blocks type number. DATA points to the block. If their pointers are non-null, *PTYPE and *STYPE are set to the primary and secondary @@ -162,14 +297,14 @@ affs_checksum_block(int bsize, void *data, s32 *ptype, s32 *stype) bsize /= 4; if (ptype) - *ptype = htonl(((s32 *)data)[0]); + *ptype = be32_to_cpu(((s32 *)data)[0]); if (stype) - *stype = htonl(((s32 *)data)[bsize - 1]); + *stype = be32_to_cpu(((s32 *)data)[bsize - 1]); sum = 0; p = data; while (bsize--) - sum += htonl(*p++); + sum += be32_to_cpu(*p++); return sum; } @@ -180,9 +315,9 @@ affs_fix_checksum(int bsize, void *data, int cspos) u32 cs; cs = affs_checksum_block(bsize,data,NULL,NULL); - ocs = htonl (((u32 *)data)[cspos]); + ocs = be32_to_cpu(((u32 *)data)[cspos]); ocs -= cs; - ((u32 *)data)[cspos] = htonl(ocs); + ((u32 *)data)[cspos] = be32_to_cpu(ocs); } void @@ -191,7 +326,7 @@ secs_to_datestamp(time_t secs, struct DateStamp *ds) u32 days; u32 minute; - secs -= sys_tz.tz_minuteswest * 60 +((8 * 365 + 2) * 24 * 60 * 60); + secs -= sys_tz.tz_minuteswest * 60 + ((8 * 365 + 2) * 24 * 60 * 60); if (secs < 0) secs = 0; days = secs / 86400; @@ -199,9 +334,9 @@ secs_to_datestamp(time_t secs, struct DateStamp *ds) minute = secs / 60; secs -= minute * 60; - ds->ds_Days = htonl(days); - ds->ds_Minute = htonl(minute); - ds->ds_Tick = htonl(secs * 50); + ds->ds_Days = be32_to_cpu(days); + ds->ds_Minute = be32_to_cpu(minute); + ds->ds_Tick = be32_to_cpu(secs * 50); } int @@ -268,6 +403,7 @@ affs_error(struct super_block *sb, const char *function, const char *fmt, ...) if (!(sb->s_flags & MS_RDONLY)) printk(KERN_WARNING "AFFS: Remounting filesystem read-only\n"); sb->s_flags |= MS_RDONLY; + sb->u.affs_sb.s_flags |= SF_READONLY; /* Don't allow to remount rw */ } void @@ -279,6 +415,50 @@ affs_warning(struct super_block *sb, const char *function, const char *fmt, ...) vsprintf(ErrorBuffer,fmt,args); va_end(args); - printk(KERN_WARNING "AFFS error (device %s): %s(): %s\n",kdevname(sb->s_dev), + printk(KERN_WARNING "AFFS warning (device %s): %s(): %s\n",kdevname(sb->s_dev), function,ErrorBuffer); } + +/* Check if the name is valid for a affs object. */ + +int +affs_check_name(const unsigned char *name, int len) +{ + int i; + + if (len > 30) +#ifdef AFFS_NO_TRUNCATE + return -ENAMETOOLONG; +#else + len = 30; +#endif + + for (i = 0; i < len; i++) { + if (name[i] < ' ' || name[i] == ':' + || (name[i] > 0x7e && name[i] < 0xa0)) + return -EINVAL; + } + + return 0; +} + +/* This function copies name to bstr, with at most 30 + * characters length. The bstr will be prepended by + * a length byte. + * NOTE: The name will must be already checked by + * affs_check_name()! + */ + +int +affs_copy_name(unsigned char *bstr, const unsigned char *name) +{ + int len; + + for (len = 0; len < 30; len++) { + bstr[len + 1] = name[len]; + if (name[len] == '\0') + break; + } + bstr[0] = len; + return len; +} diff --git a/fs/affs/bitmap.c b/fs/affs/bitmap.c index a7382db4c..832214e79 100644 --- a/fs/affs/bitmap.c +++ b/fs/affs/bitmap.c @@ -91,7 +91,7 @@ affs_free_block(struct super_block *sb, s32 block) block); else { sb->u.affs_sb.s_alloc[zone_no].az_free++; - ((u32 *)bm->bm_bh->b_data)[0] = ntohl(htonl(((u32 *)bm->bm_bh->b_data)[0]) - blk); + ((u32 *)bm->bm_bh->b_data)[0] = cpu_to_be32(be32_to_cpu(((u32 *)bm->bm_bh->b_data)[0]) - blk); mark_buffer_dirty(bm->bm_bh,1); sb->s_dirt = 1; } @@ -136,7 +136,7 @@ found: fwb = zone->z_bm->bm_firstblk + (i - 1) * 32; lock_super(sb); zone->z_start = i; - w = ~htonl(bm[i]); + w = ~be32_to_cpu(bm[i]); fb = find_first_zero_bit(&w,32); if (fb > 31 || !test_and_clear_bit(fb ^ BO_EXBITS,&bm[i])) { unlock_super(sb); @@ -163,10 +163,11 @@ found: az->az_free--; } } - w = ~w - htonl(bm[i]); - bm[0] = ntohl(htonl(bm[0]) + w); + w = ~w - be32_to_cpu(bm[i]); + bm[0] = cpu_to_be32(be32_to_cpu(bm[0]) + w); unlock_super(sb); mark_buffer_dirty(zone->z_bm->bm_bh,1); + sb->s_dirt = 1; zone->z_lru_time = jiffies; return block; @@ -208,8 +209,6 @@ affs_find_new_zone(struct super_block *sb, int zone_no) } while (1) { - if (i >= sb->u.affs_sb.s_num_az) - i = 0; az = &sb->u.affs_sb.s_alloc[i]; if (!az->az_count) { if (az->az_free > min) { @@ -223,7 +222,9 @@ affs_find_new_zone(struct super_block *sb, int zone_no) lusers = az->az_count; bestused = i; } - if (++i == zone->z_az_no) { /* Seen all */ + if (++i >= sb->u.affs_sb.s_num_az) + i = 0; + if (i == zone->z_az_no) { /* Seen all */ if (bestno >= 0) { i = bestno; } else { @@ -279,7 +280,7 @@ affs_new_header(struct inode *inode) } init_block: if (!(bh = getblk(inode->i_dev,block,AFFS_I2BSIZE(inode)))) { - affs_error(inode->i_sb,"new_header","Cannot read block %d",block); + affs_error(inode->i_sb,"new_header","Cannot get block %d",block); return 0; } memset(bh->b_data,0,AFFS_I2BSIZE(inode)); @@ -357,7 +358,7 @@ found: init_block: if (!(bh = getblk(inode->i_dev,block,sb->s_blocksize))) { - affs_error(inode->i_sb,"new_data","Cannot read block %d",block); + affs_error(inode->i_sb,"new_data","Cannot get block %d",block); return 0; } memset(bh->b_data,0,sb->s_blocksize); diff --git a/fs/affs/dir.c b/fs/affs/dir.c index 95bf3080c..d98ab280d 100644 --- a/fs/affs/dir.c +++ b/fs/affs/dir.c @@ -13,6 +13,7 @@ * */ +#define DEBUG 0 #include <asm/uaccess.h> #include <linux/errno.h> #include <linux/fs.h> @@ -24,8 +25,7 @@ #include <linux/amigaffs.h> static int affs_readdir(struct file *, void *, filldir_t); -static ssize_t affs_dir_read(struct file * filp, char * buf, - size_t count, loff_t *ppos); +static ssize_t affs_dir_read(struct file *, char *, size_t, loff_t *); static struct file_operations affs_dir_operations = { NULL, /* lseek - default */ @@ -55,11 +55,15 @@ struct inode_operations affs_dir_inode_operations = { NULL, /* mknod */ affs_rename, /* rename */ NULL, /* readlink */ + NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ NULL, /* truncate */ - NULL /* permissions */ + NULL, /* permissions */ + NULL, /* smap */ + NULL, /* updatepage */ + NULL /* revalidate */ }; static ssize_t @@ -76,15 +80,14 @@ affs_readdir(struct file *filp, void *dirent, filldir_t filldir) int hash_pos; int chain_pos; unsigned long ino; - unsigned long old; int stored; - char *name; - struct buffer_head *dir_bh; - struct buffer_head *fh_bh; - struct inode *dir; - struct inode *inode = filp->f_dentry->d_inode; + unsigned char *name; + struct buffer_head *dir_bh; + struct buffer_head *fh_bh; + struct inode *dir; + struct inode *inode = filp->f_dentry->d_inode; - pr_debug("AFFS: readdir(ino=%ld,f_pos=%lu)\n",inode->i_ino,filp->f_pos); + pr_debug("AFFS: readdir(ino=%lu,f_pos=%lu)\n",inode->i_ino,(unsigned long)filp->f_pos); if (!inode || !S_ISDIR(inode->i_mode)) return -EBADF; @@ -93,8 +96,7 @@ affs_readdir(struct file *filp, void *dirent, filldir_t filldir) dir_bh = NULL; fh_bh = NULL; dir = NULL; - old = filp->f_pos & 0x80000000; - filp->f_pos &= 0x7FFFFFFF; + ino = inode->i_ino; if (filp->f_pos == 0) { filp->private_data = (void *)0; @@ -106,18 +108,11 @@ affs_readdir(struct file *filp, void *dirent, filldir_t filldir) } if (filp->f_pos == 1) { if (filldir(dirent,"..",2,filp->f_pos,affs_parent_ino(inode)) < 0) { - filp->f_pos |= 0x80000000; return stored; } filp->f_pos = 2; stored++; } - - /* Read original if this is a link */ - ino = inode->u.affs_i.i_original ? inode->u.affs_i.i_original : inode->i_ino; - if (!(dir = iget(inode->i_sb,ino))) - return stored; - chain_pos = (filp->f_pos - 2) & 0xffff; hash_pos = (filp->f_pos - 2) >> 16; if (chain_pos == 0xffff) { @@ -126,27 +121,29 @@ affs_readdir(struct file *filp, void *dirent, filldir_t filldir) hash_pos++; filp->f_pos = ((hash_pos << 16) | chain_pos) + 2; } - if (!(dir_bh = affs_bread(inode->i_dev,ino,AFFS_I2BSIZE(inode)))) + if (!(dir_bh = affs_bread(inode->i_dev,inode->i_ino, + AFFS_I2BSIZE(inode)))) goto readdir_done; - while (!stored || !old) { + while (1) { while (hash_pos < AFFS_I2HSIZE(inode) && !((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos]) hash_pos++; if (hash_pos >= AFFS_I2HSIZE(inode)) - goto readdir_done; + break; - i = htonl(((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos]); + i = be32_to_cpu(((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos]); j = chain_pos; + /* If the directory hasn't changed since the last call to readdir(), * we can jump directly to where we left off. */ - if (filp->private_data && filp->f_version == dir->i_version) { + if (filp->private_data && filp->f_version == inode->i_version) { i = (s32)filp->private_data; j = 0; pr_debug("AFFS: readdir() left off=%d\n",i); } - filp->f_version = dir->i_version; + filp->f_version = inode->i_version; pr_debug("AFFS: hash_pos=%d chain_pos=%d\n",hash_pos,chain_pos); while (i) { if (!(fh_bh = affs_bread(inode->i_dev,i,AFFS_I2BSIZE(inode)))) { @@ -154,7 +151,7 @@ affs_readdir(struct file *filp, void *dirent, filldir_t filldir) goto readdir_done; } ino = i; - i = htonl(FILE_END(fh_bh->b_data,inode)->hash_chain); + i = be32_to_cpu(FILE_END(fh_bh->b_data,inode)->hash_chain); if (j == 0) break; affs_brelse(fh_bh); @@ -163,7 +160,7 @@ affs_readdir(struct file *filp, void *dirent, filldir_t filldir) } if (fh_bh) { namelen = affs_get_file_name(AFFS_I2BSIZE(inode),fh_bh->b_data,&name); - pr_debug("AFFS: readdir(): filldir(..,\"%.*s\",ino=%lu), i=%d\n", + pr_debug("AFFS: readdir(): filldir(\"%.*s\",ino=%lu), i=%d\n", namelen,name,ino,i); filp->private_data = (void *)ino; if (filldir(dirent,name,namelen,filp->f_pos,ino) < 0) @@ -182,10 +179,8 @@ affs_readdir(struct file *filp, void *dirent, filldir_t filldir) } readdir_done: - filp->f_pos |= old; affs_brelse(dir_bh); affs_brelse(fh_bh); - iput(dir); pr_debug("AFFS: readdir()=%d\n",stored); return stored; } diff --git a/fs/affs/file.c b/fs/affs/file.c index 273de8ebe..df130db03 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c @@ -36,13 +36,10 @@ #endif static int affs_bmap(struct inode *inode, int block); -static struct buffer_head * affs_getblock(struct inode *inode, s32 block); -static ssize_t affs_file_read_ofs(struct file *filp, char *buf, - size_t count, loff_t *ppos); -static ssize_t affs_file_write(struct file *filp, const char *buf, - size_t count, loff_t *ppos); -static ssize_t affs_file_write_ofs(struct file *filp, const char *buf, - size_t count, loff_t *ppos); +static struct buffer_head *affs_getblock(struct inode *inode, s32 block); +static ssize_t affs_file_read_ofs(struct file *filp, char *buf, size_t count, loff_t *ppos); +static ssize_t affs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos); +static ssize_t affs_file_write_ofs(struct file *filp, const char *buf, size_t cnt, loff_t *ppos); static int affs_release_file(struct inode *inode, struct file *filp); static int alloc_ext_cache(struct inode *inode); @@ -56,7 +53,11 @@ static struct file_operations affs_file_operations = { generic_file_mmap, /* mmap */ NULL, /* no special open */ affs_release_file, /* release */ - file_fsync /* brute force, but works */ + file_fsync, /* brute force, but works */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ + NULL /* lock */ }; struct inode_operations affs_file_inode_operations = { @@ -71,12 +72,15 @@ struct inode_operations affs_file_inode_operations = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ + NULL, /* follow_link */ generic_readpage, /* readpage */ NULL, /* writepage */ affs_bmap, /* bmap */ affs_truncate, /* truncate */ NULL, /* permission */ - NULL /* smap */ + NULL, /* smap */ + NULL, /* updatepage */ + NULL /* revalidate */ }; static struct file_operations affs_file_operations_ofs = { @@ -89,7 +93,11 @@ static struct file_operations affs_file_operations_ofs = { NULL, /* mmap */ NULL, /* no special open */ affs_release_file, /* release */ - file_fsync /* brute force, but works */ + file_fsync, /* brute force, but works */ + NULL, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ + NULL /* lock */ }; struct inode_operations affs_file_inode_operations_ofs = { @@ -104,12 +112,15 @@ struct inode_operations affs_file_inode_operations_ofs = { NULL, /* mknod */ NULL, /* rename */ NULL, /* readlink */ + NULL, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ affs_truncate, /* truncate */ NULL, /* permission */ - NULL /* smap */ + NULL, /* smap */ + NULL, /* updatepage */ + NULL /* revalidate */ }; #define AFFS_ISINDEX(x) ((x < 129) || \ @@ -255,7 +266,7 @@ affs_bmap(struct inode *inode, int block) /* Try to find the requested key in the cache. * In order to speed this up as much as possible, - * the cache line lookup is done in a seperate + * the cache line lookup is done in a separate * step. */ @@ -306,7 +317,7 @@ affs_bmap(struct inode *inode, int block) affs_brelse(bh); return 0; } - nkey = htonl(FILE_END(bh->b_data,inode)->extension); + nkey = be32_to_cpu(FILE_END(bh->b_data,inode)->extension); if (block < AFFS_I2HSIZE(inode)) { /* Fill cache as much as possible */ if (keycount) { @@ -314,7 +325,7 @@ affs_bmap(struct inode *inode, int block) keycount = keycount < AFFS_I2HSIZE(inode) - block ? keycount : AFFS_I2HSIZE(inode) - block; for (i = 0; i < keycount; i++) - kc->kc_keys[i] = htonl(AFFS_BLOCK(bh->b_data,inode,block + i)); + kc->kc_keys[i] = be32_to_cpu(AFFS_BLOCK(bh->b_data,inode,block + i)); kc->kc_last = kc->kc_first + i - 1; } break; @@ -331,11 +342,20 @@ affs_bmap(struct inode *inode, int block) kc->kc_this_key = key; kc->kc_this_seq = ext; kc->kc_next_key = nkey; - key = htonl(AFFS_BLOCK(bh->b_data,inode,block)); + key = be32_to_cpu(AFFS_BLOCK(bh->b_data,inode,block)); affs_brelse(bh); return key; } +/* With the affs, getting a random block from a file is not + * a simple business. Since this fs does not allow holes, + * it may be neccessary to allocate all the missing blocks + * inbetween, as well as some new extension blocks. The OFS + * is even worse: All data blocks contain pointers to the + * next ones, so you have to fix [n-1] after allocating [n]. + * What a mess. + */ + static struct buffer_head * affs_getblock(struct inode *inode, s32 block) { @@ -368,7 +388,7 @@ affs_getblock(struct inode *inode, s32 block) pt = ext ? T_LIST : T_SHORT; pbh = NULL; - for (;;) { + for (;;) { /* Loop over header block and extension blocks */ bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)); if (!bh) return NULL; @@ -379,12 +399,12 @@ affs_getblock(struct inode *inode, s32 block) affs_brelse(bh); return NULL; } - j = htonl(((struct file_front *)bh->b_data)->block_count); + j = be32_to_cpu(((struct file_front *)bh->b_data)->block_count); cf = 0; while (j < AFFS_I2HSIZE(inode) && j <= block) { if (ofs && !pbh && inode->u.affs_i.i_lastblock >= 0) { if (j > 0) - pbh = affs_bread(inode->i_dev,ntohl(AFFS_BLOCK(bh->b_data,inode,j - 1)), + pbh = affs_bread(inode->i_dev,cpu_to_be32(AFFS_BLOCK(bh->b_data,inode,j - 1)), AFFS_I2BSIZE(inode)); else pbh = affs_getblock(inode,inode->u.affs_i.i_lastblock); @@ -406,7 +426,7 @@ affs_getblock(struct inode *inode, s32 block) continue; } unlock_super(inode->i_sb); - AFFS_BLOCK(bh->b_data,inode,j) = ntohl(nkey); + AFFS_BLOCK(bh->b_data,inode,j) = cpu_to_be32(nkey); if (ofs) { ebh = affs_bread(inode->i_dev,nkey,AFFS_I2BSIZE(inode)); if (!ebh) { @@ -417,12 +437,12 @@ affs_getblock(struct inode *inode, s32 block) break; } inode->u.affs_i.i_lastblock++; - DATA_FRONT(ebh)->primary_type = ntohl(T_DATA); - DATA_FRONT(ebh)->header_key = ntohl(inode->i_ino); - DATA_FRONT(ebh)->sequence_number = ntohl(inode->u.affs_i.i_lastblock + 1); + DATA_FRONT(ebh)->primary_type = cpu_to_be32(T_DATA); + DATA_FRONT(ebh)->header_key = cpu_to_be32(inode->i_ino); + DATA_FRONT(ebh)->sequence_number = cpu_to_be32(inode->u.affs_i.i_lastblock + 1); if (pbh) { - DATA_FRONT(pbh)->data_size = ntohl(AFFS_I2BSIZE(inode) - 24); - DATA_FRONT(pbh)->next_data = ntohl(nkey); + DATA_FRONT(pbh)->data_size = cpu_to_be32(AFFS_I2BSIZE(inode) - 24); + DATA_FRONT(pbh)->next_data = cpu_to_be32(nkey); affs_fix_checksum(AFFS_I2BSIZE(inode),pbh->b_data,5); mark_buffer_dirty(pbh,0); mark_buffer_dirty(ebh,0); @@ -437,7 +457,7 @@ affs_getblock(struct inode *inode, s32 block) if (pt == T_SHORT) ((struct file_front *)bh->b_data)->first_data = AFFS_BLOCK(bh->b_data,inode,0); - ((struct file_front *)bh->b_data)->block_count = ntohl(j); + ((struct file_front *)bh->b_data)->block_count = cpu_to_be32(j); affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5); mark_buffer_dirty(bh,1); } @@ -453,7 +473,7 @@ affs_getblock(struct inode *inode, s32 block) } block -= AFFS_I2HSIZE(inode); - key = htonl(FILE_END(bh->b_data,inode)->extension); + key = be32_to_cpu(FILE_END(bh->b_data,inode)->extension); if (!key) { key = affs_new_header(inode); if (!key) { @@ -465,12 +485,12 @@ affs_getblock(struct inode *inode, s32 block) affs_free_block(inode->i_sb,key); return NULL; } - ((struct file_front *)ebh->b_data)->primary_type = ntohl(T_LIST); - ((struct file_front *)ebh->b_data)->own_key = ntohl(key); - FILE_END(ebh->b_data,inode)->secondary_type = ntohl(ST_FILE); - FILE_END(ebh->b_data,inode)->parent = ntohl(inode->i_ino); + ((struct file_front *)ebh->b_data)->primary_type = cpu_to_be32(T_LIST); + ((struct file_front *)ebh->b_data)->own_key = cpu_to_be32(key); + FILE_END(ebh->b_data,inode)->secondary_type = cpu_to_be32(ST_FILE); + FILE_END(ebh->b_data,inode)->parent = cpu_to_be32(inode->i_ino); affs_fix_checksum(AFFS_I2BSIZE(inode),ebh->b_data,5); - FILE_END(bh->b_data,inode)->extension = ntohl(key); + FILE_END(bh->b_data,inode)->extension = cpu_to_be32(key); affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5); mark_buffer_dirty(bh,1); affs_brelse(bh); @@ -487,8 +507,8 @@ affs_getblock(struct inode *inode, s32 block) } kc->kc_this_key = key; kc->kc_this_seq = ext; - kc->kc_next_key = htonl(FILE_END(bh->b_data,inode)->extension); - key = htonl(AFFS_BLOCK(bh->b_data,inode,block)); + kc->kc_next_key = be32_to_cpu(FILE_END(bh->b_data,inode)->extension); + key = be32_to_cpu(AFFS_BLOCK(bh->b_data,inode,block)); affs_brelse(bh); if (!key) return NULL; @@ -499,14 +519,15 @@ affs_getblock(struct inode *inode, s32 block) static ssize_t affs_file_read_ofs(struct file *filp, char *buf, size_t count, loff_t *ppos) { - struct inode *inode = filp->f_dentry->d_inode; - char *start; - ssize_t left, offset, size, sector; - ssize_t blocksize; - struct buffer_head *bh; - void *data; + struct inode *inode = filp->f_dentry->d_inode; + char *start; + ssize_t left, offset, size, sector; + ssize_t blocksize; + struct buffer_head *bh; + void *data; - pr_debug("AFFS: file_read_ofs(ino=%lu,pos=%lu,%d)\n",inode->i_ino,(long)*ppos,count); + pr_debug("AFFS: file_read_ofs(ino=%lu,pos=%lu,%d)\n",inode->i_ino, + (unsigned long)*ppos,count); if (!inode) { affs_error(inode->i_sb,"file_read_ofs","Inode = NULL"); @@ -553,40 +574,25 @@ affs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos) ssize_t c; ssize_t blocksize; struct buffer_head *bh; - struct inode *ino; char *p; - /* Not that I wanted to be POSIX compliant ... */ if (!count) return 0; pr_debug("AFFS: file_write(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino, - (unsigned long)*ppos,count); + (unsigned long)*ppos,count); - ino = NULL; if (!inode) { affs_error(inode->i_sb,"file_write","Inode = NULL"); return -EINVAL; } - if (inode->u.affs_i.i_original) { - ino = iget(inode->i_sb,inode->u.affs_i.i_original); - if (!ino) { - affs_error(inode->i_sb,"file_write", - "Could not follow link from inode %lu to %d", - inode->i_ino,inode->u.affs_i.i_original); - return -EINVAL; - } - inode = ino; - } if (!S_ISREG(inode->i_mode)) { affs_error(inode->i_sb,"file_write", "Trying to write to non-regular file (mode=%07o)", inode->i_mode); - iput(inode); return -EINVAL; } if (!inode->u.affs_i.i_ec) { if (alloc_ext_cache(inode)) { - iput(inode); return -ENOMEM; } } @@ -617,8 +623,14 @@ affs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos) break; } } - p = (pos % blocksize) + bh->b_data; - copy_from_user(p,buf,c); + p = (pos % blocksize) + bh->b_data; + c -= copy_from_user(p,buf,c); + if (!c) { + affs_brelse(bh); + if (!written) + written = -EFAULT; + break; + } update_vm_cache(inode,pos,p,c); mark_buffer_uptodate(bh,1); mark_buffer_dirty(bh,0); @@ -630,22 +642,20 @@ affs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos) if (pos > inode->i_size) inode->i_size = pos; inode->i_mtime = inode->i_ctime = CURRENT_TIME; - *ppos = pos; + *ppos = pos; mark_inode_dirty(inode); - iput(ino); return written; } static ssize_t affs_file_write_ofs(struct file *filp, const char *buf, size_t count, loff_t *ppos) { - struct inode *inode = filp->f_dentry->d_inode; + struct inode *inode = filp->f_dentry->d_inode; off_t pos; ssize_t written; ssize_t c; ssize_t blocksize; struct buffer_head *bh; - struct inode *ino; char *p; pr_debug("AFFS: file_write_ofs(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino, @@ -657,24 +667,17 @@ affs_file_write_ofs(struct file *filp, const char *buf, size_t count, loff_t *pp affs_error(inode->i_sb,"file_write_ofs","Inode = NULL"); return -EINVAL; } - ino = NULL; - if (inode->u.affs_i.i_original) { - ino = iget(inode->i_sb,inode->u.affs_i.i_original); - if (!ino) { - affs_error(inode->i_sb,"file_write_ofs", - "Could not follow link from inode %lu to %d", - inode->i_ino,inode->u.affs_i.i_original); - return -EINVAL; - } - inode = ino; - } if (!S_ISREG(inode->i_mode)) { affs_error(inode->i_sb,"file_write_ofs", "Trying to write to non-regular file (mode=%07o)", inode->i_mode); - iput(inode); return -EINVAL; } + if (!inode->u.affs_i.i_ec) { + if (alloc_ext_cache(inode)) { + return -ENOMEM; + } + } if (filp->f_flags & O_APPEND) pos = inode->i_size; else @@ -703,14 +706,20 @@ affs_file_write_ofs(struct file *filp, const char *buf, size_t count, loff_t *pp break; } } - p = (pos % blocksize) + bh->b_data + 24; - copy_from_user(p,buf,c); + p = (pos % blocksize) + bh->b_data + 24; + c -= copy_from_user(p,buf,c); + if (!c) { + affs_brelse(bh); + if (!written) + written = -EFAULT; + break; + } update_vm_cache(inode,pos,p,c); pos += c; buf += c; written += c; - DATA_FRONT(bh)->data_size = ntohl(htonl(DATA_FRONT(bh)->data_size) + c); + DATA_FRONT(bh)->data_size = cpu_to_be32(be32_to_cpu(DATA_FRONT(bh)->data_size) + c); affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5); mark_buffer_uptodate(bh,1); mark_buffer_dirty(bh,0); @@ -721,7 +730,6 @@ affs_file_write_ofs(struct file *filp, const char *buf, size_t count, loff_t *pp *ppos = pos; inode->i_mtime = inode->i_ctime = CURRENT_TIME; mark_inode_dirty(inode); - iput(ino); return written; } @@ -730,7 +738,6 @@ affs_truncate(struct inode *inode) { struct buffer_head *bh; struct buffer_head *ebh; - struct inode *ino; struct affs_zone *zone; int first; int block; @@ -745,20 +752,16 @@ affs_truncate(struct inode *inode) pr_debug("AFFS: file_truncate(inode=%ld,size=%lu)\n",inode->i_ino,inode->i_size); - ino = NULL; - if (inode->u.affs_i.i_original) { - ino = iget(inode->i_sb,inode->u.affs_i.i_original); - if (!ino) { - affs_error(inode->i_sb,"truncate","Cannot follow link from %lu to %d", - inode->i_ino,inode->u.affs_i.i_original); - return; - } - inode = ino; - } blocksize = AFFS_I2BSIZE(inode) - ((inode->i_sb->u.affs_sb.s_flags & SF_OFS) ? 24 : 0); first = (inode->i_size + blocksize - 1) / blocksize; if (inode->u.affs_i.i_lastblock < first - 1) { - bh = affs_getblock(inode,first - 1); + if (!inode->u.affs_i.i_ec) { + if (alloc_ext_cache(inode)) { + /* Fine! No way to indicate an error. What can we do? */ + return; + } + } + bh = affs_getblock(inode,first - 1); while (inode->u.affs_i.i_pa_cnt) { /* Free any preallocated blocks */ affs_free_block(inode->i_sb, @@ -778,12 +781,11 @@ affs_truncate(struct inode *inode) inode->i_size = blocksize * (inode->u.affs_i.i_lastblock + 1); } else if (inode->i_sb->u.affs_sb.s_flags & SF_OFS) { rem = inode->i_size % blocksize; - DATA_FRONT(bh)->data_size = ntohl(rem ? rem : blocksize); + DATA_FRONT(bh)->data_size = cpu_to_be32(rem ? rem : blocksize); affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5); mark_buffer_dirty(bh,0); } affs_brelse(bh); - iput(ino); return; } ekey = inode->i_ino; @@ -794,8 +796,8 @@ affs_truncate(struct inode *inode) affs_error(inode->i_sb,"truncate","Cannot read block %d",ekey); break; } - ptype = htonl(((struct file_front *)bh->b_data)->primary_type); - stype = htonl(FILE_END(bh->b_data,inode)->secondary_type); + ptype = be32_to_cpu(((struct file_front *)bh->b_data)->primary_type); + stype = be32_to_cpu(FILE_END(bh->b_data,inode)->secondary_type); if (ekey == inode->i_ino && ptype == T_SHORT && stype == ST_LINKFILE && LINK_END(bh->b_data,inode)->original == 0) { pr_debug("AFFS: truncate(): dumping link\n"); @@ -812,7 +814,7 @@ affs_truncate(struct inode *inode) freethis = first == 0 && ekey != inode->i_ino; for (block = first; block < AFFS_I2HSIZE(inode); block++) { keyp = &AFFS_BLOCK(bh->b_data,inode,block); - key = htonl(*keyp); + key = be32_to_cpu(*keyp); if (key) { *keyp = 0; affs_free_block(inode->i_sb,key); @@ -822,18 +824,18 @@ affs_truncate(struct inode *inode) } } keyp = &GET_END_PTR(struct file_end,bh->b_data,AFFS_I2BSIZE(inode))->extension; - key = htonl(*keyp); + key = be32_to_cpu(*keyp); if (first <= AFFS_I2HSIZE(inode)) { - ((struct file_front *)bh->b_data)->block_count = htonl(first); + ((struct file_front *)bh->b_data)->block_count = be32_to_cpu(first); first = 0; *keyp = 0; if ((inode->i_sb->u.affs_sb.s_flags & SF_OFS) && first > 0) { - block = htonl(AFFS_BLOCK(bh->b_data,inode,first - 1)); + block = be32_to_cpu(AFFS_BLOCK(bh->b_data,inode,first - 1)); if ((ebh = affs_bread(inode->i_dev,block,AFFS_I2BSIZE(inode)))) { if(!(affs_checksum_block(AFFS_I2BSIZE(inode),ebh->b_data, &ptype,NULL))) { rem = inode->i_size % blocksize; - rem = ntohl(rem ? blocksize : rem); + rem = cpu_to_be32(rem ? blocksize : rem); ((struct data_front *)ebh->b_data)->data_size = rem; ((struct data_front *)ebh->b_data)->next_data = 0; affs_fix_checksum(AFFS_I2BSIZE(inode),ebh->b_data,5); @@ -866,7 +868,6 @@ affs_truncate(struct inode *inode) } } - iput(ino); } static int @@ -900,6 +901,8 @@ alloc_ext_cache(struct inode *inode) s32 key; int i; + pr_debug("AFFS: alloc_ext_cache(ino=%lu)\n",inode->i_ino); + lock_super(inode->i_sb); if (!inode->u.affs_i.i_ec) { inode->u.affs_i.i_ec = (struct ext_cache *)get_free_page(GFP_KERNEL); diff --git a/fs/affs/inode.c b/fs/affs/inode.c index 1999902eb..676e43470 100644 --- a/fs/affs/inode.c +++ b/fs/affs/inode.c @@ -10,7 +10,7 @@ * (C) 1991 Linus Torvalds - minix filesystem */ -#include <linux/module.h> +#define DEBUG 0 #include <linux/errno.h> #include <linux/fs.h> #include <linux/malloc.h> @@ -30,106 +30,17 @@ #include <asm/system.h> #include <asm/uaccess.h> -/* AmigaOS allows file names with up to 30 characters length. - * Names longer than that will be silently truncated. If you - * want to disallow this, comment out the following #define. - * Creating filesystem objects with longer names will then - * result in an error (ENAMETOOLONG). - */ -/*#define NO_TRUNCATE */ - extern int *blk_size[]; extern struct timezone sys_tz; #define MIN(a,b) (((a)<(b))?(a):(b)) -static int affs_notify_change(struct inode *inode, struct iattr *attr); -static void affs_put_inode(struct inode *inode); -static void affs_read_inode(struct inode *inode); -static void affs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz); -static void affs_write_inode(struct inode *inode); - -static void -affs_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 void -affs_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 */ -}; - unsigned long affs_parent_ino(struct inode *dir) { int root_ino = (dir->i_sb->u.affs_sb.s_root_block); - if (!S_ISDIR (dir->i_mode)) { + if (!S_ISDIR(dir->i_mode)) { affs_error(dir->i_sb,"parent_ino","Trying to get parent of non-directory"); return root_ino; } @@ -138,524 +49,10 @@ affs_parent_ino(struct inode *dir) return dir->u.affs_i.i_parent; } -static int -parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, s32 *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. - */ - -static 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; - s32 root_block; - int size; - u32 chksum; - u32 *bm; - s32 ptype, stype; - int mapidx; - int num_bm; - int i, j; - s32 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(KERN_ERR "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(KERN_ERR "AFFS: 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 depends on the block size. */ - - s->u.affs_sb.s_hashsize = 0; - if (blocksize > 0) { - i = blocksize; - j = blocksize; - } else { - i = 512; - j = 4096; - } - for (blocksize = i, key = 0; blocksize <= j; 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; - set_blocksize(dev,blocksize); - - /* The root block location that was calculated above is not - * correct if the partition size is an odd number of 512- - * byte blocks, which will be rounded down to a number of - * 1024-byte blocks, and if there were an even number of - * reserved blocks. Ideally, all partition checkers should - * report the real number of blocks of the real blocksize, - * but since this just cannot be done, we have to try to - * find the root block anyways. In the above case, it is one - * block behind the calculated one. So we check this one, too. - */ - for (num_bm = 0; num_bm < 2; num_bm++) { - pr_debug("AFFS: Dev %s - trying bs=%d bytes, root at %u, " - "size=%d blocks, %d reserved\n",kdevname(dev),blocksize, - s->u.affs_sb.s_root_block + num_bm,size,reserved); - bh = affs_bread(dev,s->u.affs_sb.s_root_block + num_bm,blocksize); - if (!bh) { - printk(KERN_ERR "AFFS: Cannot 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; - s->u.affs_sb.s_root_block += num_bm; - key = 1; - break; - } - } - if (key) - break; - affs_brelse(bh); - bh = NULL; - } - if (!key) { - affs_brelse(bh); - if (!silent) - printk(KERN_ERR "AFFS: Cannot 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(KERN_NOTICE "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(KERN_ERR "AFFS: Unknown filesystem on device %s: %08X\n", - kdevname(dev),chksum); - affs_brelse(bb); - goto out; - } - affs_brelse(bb); - } else { - printk(KERN_ERR "AFFS: Cannot read boot block\n"); - goto out; - } - if (mount_flags & SF_VERBOSE) { - chksum = ntohl(chksum); - printk(KERN_NOTICE "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(KERN_ERR "AFFS: Cannot read root block\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(KERN_ERR "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(KERN_NOTICE "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(KERN_ERR "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(KERN_WARNING "AFFS: Bitmap (%d,key=%lu) invalid - " - "mounting %s read only.\n",mapidx,htonl(bm[i]), - kdevname(dev)); - s->s_flags |= MS_RDONLY; - } - /* Mark unused bits in the last word as allocated */ - if (size <= s->s_blocksize * 8 - 32) { /* last bitmap */ - ptype = size / 32 + 1; /* word number */ - key = size & 0x1F; /* used bits */ - if (key) { - chksum = ntohl(0x7FFFFFFF >> (31 - key)); - ((u32 *)bb->b_data)[ptype] &= chksum; - affs_fix_checksum(s->s_blocksize,bb->b_data,0); - mark_buffer_dirty(bb,1); - } - ptype = (size + 31) & ~0x1F; - size = 0; - s->u.affs_sb.s_flags |= SF_BM_VALID; - } else { - ptype = s->s_blocksize * 8 - 32; - size -= ptype; - } - s->u.affs_sb.s_bitmap[mapidx].bm_firstblk = offset; - s->u.affs_sb.s_bitmap[mapidx].bm_bh = NULL; - s->u.affs_sb.s_bitmap[mapidx].bm_key = htonl(bm[i]); - s->u.affs_sb.s_bitmap[mapidx].bm_count = 0; - offset += ptype; - - for (j = 0; ptype > 0; j++, az_no++, ptype -= key) { - key = MIN(ptype,AFFS_ZONE_SIZE); /* size in bits */ - s->u.affs_sb.s_alloc[az_no].az_size = key / 32; - s->u.affs_sb.s_alloc[az_no].az_free = - affs_count_free_bits(key / 8,bb->b_data + - j * (AFFS_ZONE_SIZE / 8) + 4); - } - affs_brelse(bb); - } else { - printk(KERN_ERR "AFFS: Cannot read bitmap\n"); - goto out; - } - } - key = htonl(bm[stype]); /* Next block of bitmap pointers */ - ptype = 0; - stype = s->s_blocksize / 4 - 1; - affs_brelse(bh); - if (key) { - if (!(bh = affs_bread(s->s_dev,key,s->s_blocksize))) { - printk(KERN_ERR "AFFS: Cannot read bitmap extension\n"); - goto out; - } - } else - bh = NULL; - } - if (mapidx != num_bm) { - printk(KERN_ERR "AFFS: Got only %d bitmap blocks, expected %d\n",mapidx,num_bm); - goto out; - } -nobitmap: - s->u.affs_sb.s_bm_count = mapidx; - - /* set up enough so that it can read an inode */ - - s->s_dev = dev; - s->s_op = &affs_sops; - s->s_root = d_alloc_root(iget(s,root_block),NULL); - s->s_dirt = 1; - unlock_super(s); - - if (!(s->s_root)) { - s->s_dev = 0; - printk(KERN_ERR "AFFS: get root inode failed\n"); - MOD_DEC_USE_COUNT; - return NULL; - } - - /* create data zones if the fs is mounted r/w */ - - if (!(s->s_flags & MS_RDONLY)) { - ROOT_END(s->u.affs_sb.s_root_bh->b_data,s->s_root->d_inode)->bm_flag = 0; - secs_to_datestamp(CURRENT_TIME,&ROOT_END(s->u.affs_sb.s_root_bh->b_data, - s->s_root->d_inode)->disk_altered); - affs_fix_checksum(s->s_blocksize,s->u.affs_sb.s_root_bh->b_data,5); - mark_buffer_dirty(s->u.affs_sb.s_root_bh,1); - affs_make_zones(s); - } - - pr_debug("AFFS: s_flags=%lX\n",s->s_flags); - return s; - - out: /* Kick out for various error conditions */ - affs_brelse (bh); - affs_brelse(s->u.affs_sb.s_root_bh); - if (s->u.affs_sb.s_bitmap) - kfree(s->u.affs_sb.s_bitmap); - set_blocksize(dev,BLOCK_SIZE); - s->s_dev = 0; - unlock_super(s); - MOD_DEC_USE_COUNT; - return NULL; -} - -static void -affs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz) -{ - int free; - struct statfs tmp; - - pr_debug("AFFS: statfs() partsize=%d, reserved=%d\n",sb->u.affs_sb.s_partition_size, - sb->u.affs_sb.s_reserved); - - free = affs_count_free_blocks(sb); - tmp.f_type = AFFS_SUPER_MAGIC; - tmp.f_bsize = sb->s_blocksize; - tmp.f_blocks = sb->u.affs_sb.s_partition_size - sb->u.affs_sb.s_reserved; - tmp.f_bfree = free; - tmp.f_bavail = free; - tmp.f_files = 0; - tmp.f_ffree = 0; - copy_to_user(buf,&tmp,bufsiz); -} - -static void +void affs_read_inode(struct inode *inode) { - struct buffer_head *bh, *lbh; + struct buffer_head *bh; struct file_front *file_front; struct file_end *file_end; s32 block; @@ -665,7 +62,6 @@ affs_read_inode(struct inode *inode) pr_debug("AFFS: read_inode(%lu)\n",inode->i_ino); - lbh = NULL; block = inode->i_ino; if (!(bh = affs_bread(inode->i_dev,block,AFFS_I2BSIZE(inode)))) { affs_error(inode->i_sb,"read_inode","Cannot read block %d",block); @@ -680,10 +76,10 @@ affs_read_inode(struct inode *inode) file_front = (struct file_front *)bh->b_data; file_end = GET_END_PTR(struct file_end, bh->b_data,AFFS_I2BSIZE(inode)); - prot = (htonl(file_end->protect) & ~0x10) ^ FIBF_OWNER; + prot = (be32_to_cpu(file_end->protect) & ~0x10) ^ FIBF_OWNER; inode->u.affs_i.i_protect = prot; - inode->u.affs_i.i_parent = htonl(file_end->parent); + inode->u.affs_i.i_parent = be32_to_cpu(file_end->parent); inode->u.affs_i.i_original = 0; inode->u.affs_i.i_zone = 0; inode->u.affs_i.i_hlink = 0; @@ -702,31 +98,28 @@ affs_read_inode(struct inode *inode) if (inode->i_sb->u.affs_sb.s_flags & SF_SETUID) inode->i_uid = inode->i_sb->u.affs_sb.s_uid; - else { - id = htons(file_end->owner_uid); - if (inode->i_sb->u.affs_sb.s_flags & SF_MUFS) { - if (id == 0 || id == 0xFFFF) - id ^= ~0; - } + id = be16_to_cpu(file_end->owner_uid); + if (id == 0 || inode->i_sb->u.affs_sb.s_flags & SF_SETUID) + inode->i_uid = inode->i_sb->u.affs_sb.s_uid; + else if (id == 0xFFFF && inode->i_sb->u.affs_sb.s_flags & SF_MUFS) + inode->i_uid = 0; + else inode->i_uid = id; - } - if (inode->i_sb->u.affs_sb.s_flags & SF_SETGID) + + id = be16_to_cpu(file_end->owner_gid); + if (id == 0 || inode->i_sb->u.affs_sb.s_flags & SF_SETGID) inode->i_gid = inode->i_sb->u.affs_sb.s_gid; - else { - id = htons(file_end->owner_gid); - if (inode->i_sb->u.affs_sb.s_flags & SF_MUFS) { - if (id == 0 || id == 0xFFFF) - id ^= ~0; - } + else if (id == 0xFFFF && inode->i_sb->u.affs_sb.s_flags & SF_MUFS) + inode->i_gid = 0; + else inode->i_gid = id; - } - switch (htonl(file_end->secondary_type)) { + switch (be32_to_cpu(file_end->secondary_type)) { case ST_ROOT: inode->i_uid = inode->i_sb->u.affs_sb.s_uid; inode->i_gid = inode->i_sb->u.affs_sb.s_gid; case ST_USERDIR: - if (htonl(file_end->secondary_type) == ST_USERDIR || + if (be32_to_cpu(file_end->secondary_type) == ST_USERDIR || inode->i_sb->u.affs_sb.s_flags & SF_SETMODE) { if (inode->i_mode & S_IRUSR) inode->i_mode |= S_IXUSR; @@ -740,25 +133,16 @@ affs_read_inode(struct inode *inode) inode->i_size = 0; break; case ST_LINKDIR: - inode->u.affs_i.i_original = htonl(file_end->original); - inode->u.affs_i.i_hlink = 1; - inode->i_mode |= S_IFDIR; - inode->i_size = 0; - break; + affs_error(inode->i_sb,"read_inode","inode is LINKDIR"); + affs_brelse(bh); + return; case ST_LINKFILE: - inode->u.affs_i.i_original = htonl(file_end->original); - inode->u.affs_i.i_hlink = 1; - if (!(lbh = affs_bread(inode->i_dev,inode->u.affs_i.i_original, - AFFS_I2BSIZE(inode)))) { - affs_brelse(bh); - affs_error(inode->i_sb,"read_inode","Cannot read block %lu", - inode->i_ino); - return; - } - file_end = GET_END_PTR(struct file_end,lbh->b_data,AFFS_I2BSIZE(inode)); + affs_error(inode->i_sb,"read_inode","inode is LINKFILE"); + affs_brelse(bh); + return; case ST_FILE: inode->i_mode |= S_IFREG; - inode->i_size = htonl(file_end->byte_size); + inode->i_size = be32_to_cpu(file_end->byte_size); if (inode->i_sb->u.affs_sb.s_flags & SF_OFS) block = AFFS_I2BSIZE(inode) - 24; else @@ -772,13 +156,12 @@ affs_read_inode(struct inode *inode) } inode->i_mtime = inode->i_atime = inode->i_ctime - = (htonl(file_end->created.ds_Days) * (24 * 60 * 60) + - htonl(file_end->created.ds_Minute) * 60 + - htonl(file_end->created.ds_Tick) / 50 + + = (be32_to_cpu(file_end->created.ds_Days) * (24 * 60 * 60) + + be32_to_cpu(file_end->created.ds_Minute) * 60 + + be32_to_cpu(file_end->created.ds_Tick) / 50 + ((8 * 365 + 2) * 24 * 60 * 60)) + sys_tz.tz_minuteswest * 60; affs_brelse(bh); - affs_brelse(lbh); inode->i_op = NULL; if (S_ISREG(inode->i_mode)) { @@ -793,7 +176,7 @@ affs_read_inode(struct inode *inode) inode->i_op = &affs_symlink_inode_operations; } -static void +void affs_write_inode(struct inode *inode) { struct buffer_head *bh; @@ -810,11 +193,11 @@ affs_write_inode(struct inode *inode) return; } file_end = GET_END_PTR(struct file_end, bh->b_data,AFFS_I2BSIZE(inode)); - if (file_end->secondary_type == htonl(ST_ROOT)) { + if (file_end->secondary_type == be32_to_cpu(ST_ROOT)) { secs_to_datestamp(inode->i_mtime,&ROOT_END(bh->b_data,inode)->disk_altered); } else { - file_end->protect = ntohl(inode->u.affs_i.i_protect ^ FIBF_OWNER); - file_end->byte_size = ntohl(inode->i_size); + file_end->protect = cpu_to_be32(inode->u.affs_i.i_protect ^ FIBF_OWNER); + file_end->byte_size = cpu_to_be32(inode->i_size); secs_to_datestamp(inode->i_mtime,&file_end->created); if (!(inode->i_ino == inode->i_sb->u.affs_sb.s_root_block)) { uid = inode->i_uid; @@ -826,9 +209,9 @@ affs_write_inode(struct inode *inode) gid = inode->i_gid ^ ~0; } if (!(inode->i_sb->u.affs_sb.s_flags & SF_SETUID)) - file_end->owner_uid = ntohs(uid); + file_end->owner_uid = cpu_to_be16(uid); if (!(inode->i_sb->u.affs_sb.s_flags & SF_SETGID)) - file_end->owner_gid = ntohs(gid); + file_end->owner_gid = cpu_to_be16(gid); } } affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5); @@ -836,7 +219,7 @@ affs_write_inode(struct inode *inode) brelse(bh); } -static int +int affs_notify_change(struct inode *inode, struct iattr *attr) { int error; @@ -864,19 +247,23 @@ affs_notify_change(struct inode *inode, struct iattr *attr) return 0; } -static void +void affs_put_inode(struct inode *inode) { pr_debug("AFFS: put_inode(ino=%lu, nlink=%u)\n",inode->i_ino,inode->i_nlink); lock_super(inode->i_sb); if (inode->u.affs_i.i_ec) { + pr_debug("AFFS: freeing ext cache\n"); free_page((unsigned long)inode->u.affs_i.i_ec); inode->u.affs_i.i_ec = NULL; } unlock_super(inode->i_sb); - if (inode->i_nlink) { - return; - } +} + +void +affs_delete_inode(struct inode *inode) +{ + pr_debug("AFFS: delete_inode(ino=%lu, nlink=%u)\n",inode->i_ino,inode->i_nlink); inode->i_size = 0; if (S_ISREG(inode->i_mode) && !inode->u.affs_i.i_hlink) affs_truncate(inode); @@ -916,15 +303,15 @@ affs_new_inode(const struct inode *dir) inode->i_blksize = 0; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; - inode->u.affs_i.i_original = 0; - inode->u.affs_i.i_parent = dir->i_ino; - inode->u.affs_i.i_zone = 0; - inode->u.affs_i.i_hlink = 0; - inode->u.affs_i.i_pa_cnt = 0; - inode->u.affs_i.i_pa_next = 0; - inode->u.affs_i.i_pa_last = 0; - inode->u.affs_i.i_ec = NULL; - inode->u.affs_i.i_lastblock = -1; + inode->u.affs_i.i_original = 0; + inode->u.affs_i.i_parent = dir->i_ino; + inode->u.affs_i.i_zone = 0; + inode->u.affs_i.i_hlink = 0; + inode->u.affs_i.i_pa_cnt = 0; + inode->u.affs_i.i_pa_next = 0; + inode->u.affs_i.i_pa_last = 0; + inode->u.affs_i.i_ec = NULL; + inode->u.affs_i.i_lastblock = -1; insert_inode_hash(inode); mark_inode_dirty(inode); @@ -934,23 +321,27 @@ affs_new_inode(const struct inode *dir) int affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode, - const char *name, int len, int type) + struct dentry *dentry, int type) { struct buffer_head *dir_bh; struct buffer_head *inode_bh; struct buffer_head *link_bh; - struct buffer_head *ibh; int retval; - int i; - s32 next; + const unsigned char *name = dentry->d_name.name; + int len = dentry->d_name.len; - pr_debug("AFFS: add_entry(dir=%lu,inode=%lu,\"%*s\",type=%d\n",dir->i_ino,inode->i_ino, + pr_debug("AFFS: add_entry(dir=%lu,inode=%lu,\"%*s\",type=%d)\n",dir->i_ino,inode->i_ino, len,name,type); - dir_bh = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir)); - inode_bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode)); - link_bh = NULL; - retval = -EIO; + if ((retval = affs_check_name(name,len))) + return retval; + if (len > 30) + len = 30; + + dir_bh = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir)); + inode_bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode)); + link_bh = NULL; + retval = -EIO; if (!dir_bh || !inode_bh) goto addentry_done; if (link) { @@ -958,57 +349,21 @@ affs_add_entry(struct inode *dir, struct inode *link, struct inode *inode, if (!link_bh) goto addentry_done; } - ((struct dir_front *)inode_bh->b_data)->primary_type = ntohl(T_SHORT); - ((struct dir_front *)inode_bh->b_data)->own_key = ntohl(inode->i_ino); - - retval = -ENAMETOOLONG; - if (len > 30) -#ifdef NO_TRUNCATE - goto addentry_done; -#else - len = 30; -#endif - - /* Check if name is valid */ - retval = -EINVAL; - for (i = 0; i < len; i++) { - if (name[i] < ' ' || name[i] == ':' - || ((unsigned char)name[i] > 0x7e && (unsigned char)name[i] < 0xa0)) - goto addentry_done; - } - retval = 0; - DIR_END(inode_bh->b_data,inode)->dir_name[0] = len; + ((struct dir_front *)inode_bh->b_data)->primary_type = cpu_to_be32(T_SHORT); + ((struct dir_front *)inode_bh->b_data)->own_key = cpu_to_be32(inode->i_ino); + DIR_END(inode_bh->b_data,inode)->dir_name[0] = len; strncpy(DIR_END(inode_bh->b_data,inode)->dir_name + 1,name,len); - DIR_END(inode_bh->b_data,inode)->secondary_type = ntohl(type); - DIR_END(inode_bh->b_data,inode)->parent = ntohl(dir->i_ino); - - i = affs_hash_name(name,len,AFFS_I2FSTYPE(dir),AFFS_I2HSIZE(dir)) + 6; - next = dir->i_ino; - - /* Alas, we have to search the insertion point with a locked sb */ + DIR_END(inode_bh->b_data,inode)->secondary_type = cpu_to_be32(type); + DIR_END(inode_bh->b_data,inode)->parent = cpu_to_be32(dir->i_ino); lock_super(inode->i_sb); - while (1) { - if (!(ibh = affs_bread(dir->i_dev,next,AFFS_I2BSIZE(dir)))) - goto addentry_done; - next = htonl(((s32 *)ibh->b_data)[i]); - if (!next || next > inode->i_ino) - break; - i = AFFS_I2BSIZE(dir) / 4 - 4; - affs_brelse(ibh); - } - - DIR_END(inode_bh->b_data,inode)->hash_chain = next; - ((s32 *)ibh->b_data)[i] = ntohl(inode->i_ino); - affs_fix_checksum(AFFS_I2BSIZE(dir),ibh->b_data,5); - mark_buffer_dirty(ibh,1); - affs_brelse(ibh); + retval = affs_insert_hash(dir->i_ino,inode_bh,dir); if (link_bh) { - LINK_END(inode_bh->b_data,inode)->original = ntohl(link->i_ino); + LINK_END(inode_bh->b_data,inode)->original = cpu_to_be32(link->i_ino); LINK_END(inode_bh->b_data,inode)->link_chain = FILE_END(link_bh->b_data,link)->link_chain; - FILE_END(link_bh->b_data,link)->link_chain = ntohl(inode->i_ino); + FILE_END(link_bh->b_data,link)->link_chain = cpu_to_be32(inode->i_ino); affs_fix_checksum(AFFS_I2BSIZE(link),link_bh->b_data,5); link->i_version = ++event; mark_inode_dirty(link); @@ -1032,32 +387,3 @@ addentry_done: return retval; } - -static struct file_system_type affs_fs_type = { - "affs", - FS_REQUIRES_DEV, - affs_read_super, - NULL -}; - -__initfunc(int init_affs_fs(void)) -{ - return register_filesystem(&affs_fs_type); -} - -#ifdef MODULE -EXPORT_NO_SYMBOLS; - -int -init_module(void) -{ - return register_filesystem(&affs_fs_type); -} - -void -cleanup_module(void) -{ - unregister_filesystem(&affs_fs_type); -} - -#endif diff --git a/fs/affs/namei.c b/fs/affs/namei.c index d82f13c7f..2ec0401d5 100644 --- a/fs/affs/namei.c +++ b/fs/affs/namei.c @@ -8,6 +8,7 @@ * (C) 1991 Linus Torvalds - minix filesystem */ +#define DEBUG 0 #include <linux/sched.h> #include <linux/affs_fs.h> #include <linux/kernel.h> @@ -20,8 +21,6 @@ #include <linux/errno.h> -static int affs_fixup(struct buffer_head *bh, struct inode *inode); - /* Simple toupper() for DOS\1 */ static inline unsigned int @@ -45,7 +44,7 @@ affs_intl_toupper(unsigned int ch) */ static int -affs_match(const char *name, int len, const char *compare, int dlen, int intl) +affs_match(const unsigned char *name, int len, const unsigned char *compare, int dlen, int intl) { if (!compare) return 0; @@ -62,14 +61,14 @@ affs_match(const char *name, int len, const char *compare, int dlen, int intl) return 0; if (intl) { while (dlen--) { - if (affs_intl_toupper(*name & 0xFF) != affs_intl_toupper(*compare & 0xFF)) + if (affs_intl_toupper(*name) != affs_intl_toupper(*compare)) return 0; name++; compare++; } } else { while (dlen--) { - if (affs_toupper(*name & 0xFF) != affs_toupper(*compare & 0xFF)) + if (affs_toupper(*name) != affs_toupper(*compare)) return 0; name++; compare++; @@ -79,7 +78,7 @@ affs_match(const char *name, int len, const char *compare, int dlen, int intl) } int -affs_hash_name(const char *name, int len, int intl, int hashsize) +affs_hash_name(const unsigned char *name, int len, int intl, int hashsize) { unsigned int i, x; @@ -97,14 +96,15 @@ affs_hash_name(const char *name, int len, int intl, int hashsize) } static struct buffer_head * -affs_find_entry(struct inode *dir, const char *name, int namelen, - unsigned long *ino) +affs_find_entry(struct inode *dir, struct dentry *dentry, unsigned long *ino) { - struct buffer_head *bh; - int intl; - s32 key; + struct buffer_head *bh; + int intl; + s32 key; + const char *name = dentry->d_name.name; + int namelen = dentry->d_name.len; - pr_debug("AFFS: find_entry(%.*s)=\n",namelen,name); + pr_debug("AFFS: find_entry(\"%.*s\")\n",namelen,name); intl = AFFS_I2FSTYPE(dir); bh = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir)); @@ -123,7 +123,7 @@ affs_find_entry(struct inode *dir, const char *name, int namelen, key = AFFS_GET_HASHENTRY(bh->b_data,affs_hash_name(name,namelen,intl,AFFS_I2HSIZE(dir))); for (;;) { - char *cname; + unsigned char *cname; int cnamelen; affs_brelse(bh); @@ -137,154 +137,127 @@ affs_find_entry(struct inode *dir, const char *name, int namelen, cnamelen = affs_get_file_name(AFFS_I2BSIZE(dir),bh->b_data,&cname); if (affs_match(name,namelen,cname,cnamelen,intl)) break; - key = htonl(FILE_END(bh->b_data,dir)->hash_chain); + key = be32_to_cpu(FILE_END(bh->b_data,dir)->hash_chain); } *ino = key; return bh; } int -affs_lookup(struct inode *dir, const char *name, int len, struct inode **result) +affs_lookup(struct inode *dir, struct dentry *dentry) { - int res; - unsigned long ino; - struct buffer_head *bh; - - pr_debug("AFFS: lookup(%.*s)\n",len,name); + unsigned long ino; + struct buffer_head *bh; + struct inode *inode; - *result = NULL; - if (!dir) - return -ENOENT; + pr_debug("AFFS: lookup(\"%.*s\")\n",(int)dentry->d_name.len,dentry->d_name.name); - res = -ENOENT; - if (S_ISDIR(dir->i_mode)) { - if ((bh = affs_find_entry(dir,name,len,&ino))) { - if (FILE_END(bh->b_data,dir)->original) - ino = htonl(FILE_END(bh->b_data,dir)->original); - affs_brelse(bh); - if ((*result = iget(dir->i_sb,ino))) - res = 0; - else - res = -EACCES; - } + inode = NULL; + bh = affs_find_entry(dir,dentry,&ino); + if (bh) { + if (FILE_END(bh->b_data,dir)->original) + ino = be32_to_cpu(FILE_END(bh->b_data,dir)->original); + affs_brelse(bh); + inode = iget(dir->i_sb,ino); + if (!inode) + return -EACCES; } - iput(dir); - return res; + d_add(dentry,inode); + return 0; } int -affs_unlink(struct inode *dir, const char *name, int len) +affs_unlink(struct inode *dir, struct dentry *dentry) { int retval; struct buffer_head *bh; unsigned long ino; struct inode *inode; - pr_debug("AFFS: unlink(dir=%ld,\"%.*s\")\n",dir->i_ino,len,name); + pr_debug("AFFS: unlink(dir=%ld,\"%.*s\")\n",dir->i_ino, + (int)dentry->d_name.len,dentry->d_name.name); bh = NULL; - inode = NULL; retval = -ENOENT; - if (!(bh = affs_find_entry(dir,name,len,&ino))) { - goto unlink_done; - } - if (!(inode = iget(dir->i_sb,ino))) { + if (!dir) goto unlink_done; - } - if (S_ISDIR(inode->i_mode)) { - retval = -EPERM; + if (!(bh = affs_find_entry(dir,dentry,&ino))) goto unlink_done; - } - if ((retval = affs_fix_hash_pred(dir,affs_hash_name(name,len,AFFS_I2FSTYPE(dir), - AFFS_I2HSIZE(dir)) + 6,ino, - FILE_END(bh->b_data,dir)->hash_chain))) + inode = dentry->d_inode; + retval = -EPERM; + if (S_ISDIR(inode->i_mode)) goto unlink_done; - - if ((retval = affs_fixup(bh,inode))) + if (current->fsuid != inode->i_uid && + current->fsuid != dir->i_uid && !fsuser()) goto unlink_done; - inode->i_nlink=0; - mark_inode_dirty(inode); + if ((retval = affs_remove_header(bh,inode)) < 0) + goto unlink_done; + + inode->i_nlink = retval; inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; - dir->i_version = ++event; - mark_inode_dirty(dir); + mark_inode_dirty(inode); + retval = 0; + d_delete(dentry); unlink_done: affs_brelse(bh); - iput(inode); - iput(dir); return retval; } int -affs_create(struct inode *dir, const char *name, int len, int mode, struct inode **result) +affs_create(struct inode *dir, struct dentry *dentry, int mode) { struct inode *inode; int error; - pr_debug("AFFS: create(%lu,\"%.*s\",0%o)\n",dir->i_ino,len,name,mode); + pr_debug("AFFS: create(%lu,\"%.*s\",0%o)\n",dir->i_ino,(int)dentry->d_name.len, + dentry->d_name.name,mode); - *result = NULL; - if (!dir || !dir->i_sb) { - iput(dir); - return -EINVAL; - } + if (!dir) + return -ENOENT; inode = affs_new_inode(dir); - if (!inode) { - iput (dir); + if (!inode) return -ENOSPC; - } - inode->i_mode = mode; + + pr_debug(" -- ino=%lu\n",inode->i_ino); if (dir->i_sb->u.affs_sb.s_flags & SF_OFS) inode->i_op = &affs_file_inode_operations_ofs; else inode->i_op = &affs_file_inode_operations; - error = affs_add_entry(dir,NULL,inode,name,len,ST_FILE); + error = affs_add_entry(dir,NULL,inode,dentry,ST_FILE); if (error) { - iput(dir); inode->i_nlink = 0; mark_inode_dirty(inode); iput(inode); - return -ENOSPC; + return error; } + inode->i_mode = mode; inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode); - - iput(dir); - *result = inode; + dir->i_version = ++event; + mark_inode_dirty(dir); + d_instantiate(dentry,inode); return 0; } int -affs_mkdir(struct inode *dir, const char *name, int len, int mode) +affs_mkdir(struct inode *dir, struct dentry *dentry, int mode) { struct inode *inode; - struct buffer_head *bh; - unsigned long i; int error; - pr_debug("AFFS: mkdir(%lu,\"%.*s\",0%o)\n",dir->i_ino,len,name,mode); + pr_debug("AFFS: mkdir(%lu,\"%.*s\",0%o)\n",dir->i_ino, + (int)dentry->d_name.len,dentry->d_name.name,mode); - if (!dir || !dir->i_sb) { - iput(dir); - return -EINVAL; - } - bh = affs_find_entry(dir,name,len,&i); - if (bh) { - affs_brelse(bh); - iput(dir); - return -EEXIST; - } inode = affs_new_inode(dir); - if (!inode) { - iput (dir); + if (!inode) return -ENOSPC; - } + inode->i_op = &affs_dir_inode_operations; - error = affs_add_entry(dir,NULL,inode,name,len,ST_USERDIR); + error = affs_add_entry(dir,NULL,inode,dentry,ST_USERDIR); if (error) { - iput(dir); inode->i_nlink = 0; mark_inode_dirty(inode); iput(inode); @@ -292,9 +265,9 @@ affs_mkdir(struct inode *dir, const char *name, int len, int mode) } inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask); inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode); - - iput(dir); - iput(inode); + dir->i_version = ++event; + mark_inode_dirty(dir); + d_instantiate(dentry,inode); return 0; } @@ -310,26 +283,29 @@ empty_dir(struct buffer_head *bh, int hashsize) } int -affs_rmdir(struct inode *dir, const char *name, int len) +affs_rmdir(struct inode *dir, struct dentry *dentry) { int retval; unsigned long ino; struct inode *inode; struct buffer_head *bh; - pr_debug("AFFS: rmdir(dir=%lu,\"%.*s\")\n",dir->i_ino,len,name); + pr_debug("AFFS: rmdir(dir=%lu,\"%.*s\")\n",dir->i_ino, + (int)dentry->d_name.len,dentry->d_name.name); inode = NULL; + bh = NULL; retval = -ENOENT; - if (!(bh = affs_find_entry(dir,name,len,&ino))) { + if (!dir) goto rmdir_done; - } - if (!(inode = iget(dir->i_sb,ino))) { + if (!(bh = affs_find_entry(dir,dentry,&ino))) goto rmdir_done; - } + + inode = dentry->d_inode; + retval = -EPERM; - if (!fsuser() && current->fsuid != inode->i_uid && - current->fsuid != dir->i_uid) + if (current->fsuid != inode->i_uid && + current->fsuid != dir->i_uid && !fsuser()) goto rmdir_done; if (inode->i_dev != dir->i_dev) goto rmdir_done; @@ -339,6 +315,11 @@ affs_rmdir(struct inode *dir, const char *name, int len) retval = -ENOTDIR; goto rmdir_done; } + down(&inode->i_sem); + if (dentry->d_count > 1) { + shrink_dcache_parent(dentry); + } + up(&inode->i_sem); if (!empty_dir(bh,AFFS_I2HSIZE(inode))) { retval = -ENOTEMPTY; goto rmdir_done; @@ -347,28 +328,21 @@ affs_rmdir(struct inode *dir, const char *name, int len) retval = -EBUSY; goto rmdir_done; } - if ((retval = affs_fix_hash_pred(dir,affs_hash_name(name,len,AFFS_I2FSTYPE(dir), - AFFS_I2HSIZE(dir)) + 6,ino, - FILE_END(bh->b_data,dir)->hash_chain))) - goto rmdir_done; - - if ((retval = affs_fixup(bh,inode))) + if ((retval = affs_remove_header(bh,inode)) < 0) goto rmdir_done; - - inode->i_nlink=0; - mark_inode_dirty(inode); + + inode->i_nlink = retval; inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; - dir->i_version = ++event; - mark_inode_dirty(dir); + retval = 0; + mark_inode_dirty(inode); + d_delete(dentry); rmdir_done: - iput(dir); - iput(inode); affs_brelse(bh); return retval; } int -affs_symlink(struct inode *dir, const char *name, int len, const char *symname) +affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) { struct buffer_head *bh; struct inode *inode; @@ -377,20 +351,19 @@ affs_symlink(struct inode *dir, const char *name, int len, const char *symname) int i, maxlen; char c, lc; - pr_debug("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino,len,name,symname); + pr_debug("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino, + (int)dentry->d_name.len,dentry->d_name.name,symname); maxlen = 4 * AFFS_I2HSIZE(dir) - 1; inode = affs_new_inode(dir); - if (!inode) { - iput(dir); + if (!inode) return -ENOSPC; - } + inode->i_op = &affs_symlink_inode_operations; inode->i_mode = S_IFLNK | 0777; inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode); bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode)); if (!bh) { - iput(dir); inode->i_nlink = 0; mark_inode_dirty(inode); iput(inode); @@ -427,157 +400,135 @@ affs_symlink(struct inode *dir, const char *name, int len, const char *symname) mark_buffer_dirty(bh,1); affs_brelse(bh); mark_inode_dirty(inode); - bh = affs_find_entry(dir,name,len,&tmp); + bh = affs_find_entry(dir,dentry,&tmp); if (bh) { inode->i_nlink = 0; iput(inode); affs_brelse(bh); - iput(dir); return -EEXIST; } - i = affs_add_entry(dir,NULL,inode,name,len,ST_SOFTLINK); + i = affs_add_entry(dir,NULL,inode,dentry,ST_SOFTLINK); if (i) { inode->i_nlink = 0; mark_inode_dirty(inode); iput(inode); affs_brelse(bh); - iput(dir); return i; } - iput(dir); - iput(inode); + dir->i_version = ++event; + d_instantiate(dentry,inode); return 0; } int -affs_link(struct inode *oldinode, struct inode *dir, const char *name, int len) +affs_link(struct inode *oldinode, struct inode *dir, struct dentry *dentry) { struct inode *inode; struct buffer_head *bh; unsigned long i; int error; - pr_debug("AFFS: link(%lu,%lu,\"%.*s\")\n",oldinode->i_ino,dir->i_ino,len,name); + pr_debug("AFFS: link(%lu,%lu,\"%.*s\")\n",oldinode->i_ino,dir->i_ino, + (int)dentry->d_name.len,dentry->d_name.name); - bh = affs_find_entry(dir,name,len,&i); + bh = affs_find_entry(dir,dentry,&i); if (bh) { affs_brelse(bh); - iput(oldinode); - iput(dir); return -EEXIST; } - if (oldinode->u.affs_i.i_hlink) { - i = oldinode->u.affs_i.i_original; - iput(oldinode); - oldinode = iget(dir->i_sb,i); - if (!oldinode) { - affs_error(oldinode->i_sb,"link","Cannot get original from link"); - iput(dir); - return -ENOENT; - } + if (oldinode->u.affs_i.i_hlink) { /* Cannot happen */ + affs_warning(dir->i_sb,"link","Impossible link to link"); + return -EINVAL; } - inode = affs_new_inode(dir); - if (!inode) { - iput(oldinode); - iput(dir); + if (!(inode = affs_new_inode(dir))) return -ENOSPC; - } + inode->i_op = oldinode->i_op; - inode->i_mode = oldinode->i_mode; - inode->i_uid = oldinode->i_uid; - inode->i_gid = oldinode->i_gid; - inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode); + inode->u.affs_i.i_protect = mode_to_prot(oldinode->i_mode); inode->u.affs_i.i_original = oldinode->i_ino; inode->u.affs_i.i_hlink = 1; + inode->i_mtime = oldinode->i_mtime; if (S_ISDIR(oldinode->i_mode)) - error = affs_add_entry(dir,oldinode,inode,name,len,ST_LINKDIR); + error = affs_add_entry(dir,oldinode,inode,dentry,ST_LINKDIR); else - error = affs_add_entry(dir,oldinode,inode,name,len,ST_LINKFILE); - if (error) { + error = affs_add_entry(dir,oldinode,inode,dentry,ST_LINKFILE); + if (error) inode->i_nlink = 0; - mark_inode_dirty(inode); + else { + dir->i_version = ++event; + mark_inode_dirty(oldinode); + oldinode->i_count++; + d_instantiate(dentry,oldinode); } - iput(dir); + mark_inode_dirty(inode); iput(inode); - iput(oldinode); return error; } +/* This is copied from the ext2 fs. No need to reinvent the wheel. */ + static int -subdir(struct inode *new_inode, struct inode *old_inode) +subdir(struct dentry * new_dentry, struct dentry * old_dentry) { - int ino; - int result; - - new_inode->i_count++; - result = 0; - for (;;) { - if (new_inode == old_inode) { - result = 1; - break; + int result; + + result = 0; + for (;;) { + if (new_dentry != old_dentry) { + struct dentry * parent = new_dentry->d_parent; + if (parent == new_dentry) + break; + new_dentry = parent; + continue; + } + result = 1; + break; } - if (new_inode->i_dev != old_inode->i_dev) - break; - ino = new_inode->i_ino; - if (affs_lookup(new_inode,"..",2,&new_inode)) - break; - if (new_inode->i_ino == ino) - break; - } - iput(new_inode); - return result; + return result; } -/* I'm afraid this might not be race proof. Maybe next time. */ - int -affs_rename(struct inode *old_dir, const char *old_name, int old_len, - struct inode *new_dir, const char *new_name, int new_len) +affs_rename(struct inode *old_dir, struct dentry *old_dentry, + struct inode *new_dir, struct dentry *new_dentry) { - struct inode *old_inode; - struct inode *new_inode; + struct inode *old_inode = old_dentry->d_inode; + struct inode *new_inode = new_dentry->d_inode; struct buffer_head *old_bh; struct buffer_head *new_bh; unsigned long old_ino; unsigned long new_ino; int retval; - pr_debug("AFFS: rename(old=%lu,\"%*s\" to new=%lu,\"%*s\")\n",old_dir->i_ino,old_len,old_name, - new_dir->i_ino,new_len,new_name); + pr_debug("AFFS: rename(old=%lu,\"%*s\" (inode=%p) to new=%lu,\"%*s\" (inode=%p) )\n", + old_dir->i_ino,old_dentry->d_name.len,old_dentry->d_name.name,old_inode, + new_dir->i_ino,new_dentry->d_name.len,new_dentry->d_name.name,new_inode); - if (new_len > 30) - new_len = 30; - goto start_up; -retry: - affs_brelse(old_bh); - affs_brelse(new_bh); - iput(new_inode); - iput(old_inode); - current->counter = 0; - schedule(); -start_up: - old_inode = new_inode = NULL; - old_bh = new_bh = NULL; - retval = -ENOENT; - - old_bh = affs_find_entry(old_dir,old_name,old_len,&old_ino); + if ((retval = affs_check_name(new_dentry->d_name.name,new_dentry->d_name.len))) + return retval; + + new_bh = NULL; + retval = -ENOENT; + old_bh = affs_find_entry(old_dir,old_dentry,&old_ino); if (!old_bh) goto end_rename; - old_inode = iget(old_dir->i_sb,old_ino); - if (!old_inode) + + new_bh = affs_find_entry(new_dir,new_dentry,&new_ino); + if (new_bh && !new_inode) { + affs_error(old_inode->i_sb,"affs_rename", + "No inode for entry found (key=%lu)\n",new_ino); goto end_rename; - new_bh = affs_find_entry(new_dir,new_name,new_len,&new_ino); - if (new_bh) { - new_inode = iget(new_dir->i_sb,new_ino); - if (!new_inode) { /* What does this mean? */ - affs_brelse(new_bh); - new_bh = NULL; - } } - if (new_inode == old_inode) { /* Won't happen */ + if (new_inode == old_inode) { + if (old_ino == new_ino) { /* Filename might have changed case */ + retval = new_dentry->d_name.len < 31 ? new_dentry->d_name.len : 30; + strncpy(DIR_END(old_bh->b_data,old_inode)->dir_name + 1, + new_dentry->d_name.name,retval); + DIR_END(old_bh->b_data,old_inode)->dir_name[0] = retval; + goto new_checksum; + } retval = 0; goto end_rename; } @@ -586,13 +537,13 @@ start_up: if (!S_ISDIR(old_inode->i_mode)) goto end_rename; retval = -EINVAL; - if (subdir(new_dir,old_inode)) + if (subdir(new_dentry,old_dentry)) goto end_rename; retval = -ENOTEMPTY; if (!empty_dir(new_bh,AFFS_I2HSIZE(new_inode))) goto end_rename; retval = -EBUSY; - if (new_inode->i_count > 1) + if (new_dentry->d_count > 1) goto end_rename; } if (S_ISDIR(old_inode->i_mode)) { @@ -600,142 +551,43 @@ start_up: if (new_inode && !S_ISDIR(new_inode->i_mode)) goto end_rename; retval = -EINVAL; - if (subdir(new_dir,old_inode)) + if (subdir(new_dentry,old_dentry)) goto end_rename; if (affs_parent_ino(old_inode) != old_dir->i_ino) goto end_rename; } - /* Unlink destination if existent */ + /* Unlink destination if it already exists */ if (new_inode) { - if ((retval = affs_fix_hash_pred(new_dir,affs_hash_name(new_name,new_len, - AFFS_I2FSTYPE(new_dir),AFFS_I2HSIZE(new_dir)) + 6, - new_ino, - FILE_END(new_bh->b_data,new_dir)->hash_chain))) - goto retry; - if ((retval = affs_fixup(new_bh,new_inode))) - goto retry; - mark_buffer_dirty(new_bh,1); - new_dir->i_version = ++event; - mark_inode_dirty(new_dir); - new_inode->i_nlink = 0; + if ((retval = affs_remove_header(new_bh,new_dir)) < 0) + goto end_rename; + new_inode->i_nlink = retval; mark_inode_dirty(new_inode); + if (new_inode->i_ino == new_ino) + new_inode->i_nlink = 0; } - retval = affs_fix_hash_pred(old_dir,affs_hash_name(old_name,old_len,AFFS_I2FSTYPE(old_dir), - AFFS_I2HSIZE(old_dir)) + 6,old_ino, - FILE_END(old_bh->b_data,old_dir)->hash_chain); - if (retval) - goto retry; - - retval = affs_add_entry(new_dir,NULL,old_inode,new_name,new_len, - htonl(FILE_END(old_bh->b_data,old_dir)->secondary_type)); + /* Remove header from its parent directory. */ + if ((retval = affs_remove_hash(old_bh,old_dir))) + goto end_rename; + /* And insert it into the new directory with the new name. */ + affs_copy_name(FILE_END(old_bh->b_data,old_inode)->file_name,new_dentry->d_name.name); + if ((retval = affs_insert_hash(new_dir->i_ino,old_bh,new_dir))) + goto end_rename; +new_checksum: + affs_fix_checksum(AFFS_I2BSIZE(new_dir),old_bh->b_data,5); - new_dir->i_ctime = new_dir->i_mtime = old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME; + new_dir->i_ctime = new_dir->i_mtime = old_dir->i_ctime + = old_dir->i_mtime = CURRENT_TIME; new_dir->i_version = ++event; old_dir->i_version = ++event; + retval = 0; mark_inode_dirty(new_dir); mark_inode_dirty(old_dir); mark_buffer_dirty(old_bh,1); + d_move(old_dentry,new_dentry); end_rename: affs_brelse(old_bh); affs_brelse(new_bh); - iput(new_inode); - iput(old_inode); - iput(old_dir); - iput(new_dir); return retval; } - -static int -affs_fixup(struct buffer_head *bh, struct inode *inode) -{ - s32 key, link_key; - s32 type; - struct buffer_head *nbh; - struct inode *ofinode; - - type = htonl(FILE_END(bh->b_data,inode)->secondary_type); - if (type == ST_LINKFILE || type == ST_LINKDIR) { - key = htonl(LINK_END(bh->b_data,inode)->original); - LINK_END(bh->b_data,inode)->original = 0; - if (!key) { - affs_error(inode->i_sb,"fixup","Hard link without original: ino=%lu", - inode->i_ino); - return -ENOENT; - } - if (!(ofinode = iget(inode->i_sb,key))) - return -ENOENT; - type = affs_fix_link_pred(ofinode,inode->i_ino, - FILE_END(bh->b_data,inode)->link_chain); - iput(ofinode); - return type; - } else if (type == ST_FILE || type == ST_USERDIR) { - if ((key = htonl(FILE_END(bh->b_data,inode)->link_chain))) { - /* Get first link, turn it to a file */ - if (!(ofinode = iget(inode->i_sb,key))) { - affs_error(inode->i_sb,"fixup","Cannot read block %d",key); - return -ENOENT; - } - if (!ofinode->u.affs_i.i_hlink) { - affs_error(inode->i_sb,"fixup", - "First link to %lu (%d) is not a link", - inode->i_ino,key); - iput(ofinode); - return -ENOENT; - } - if (!(nbh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)))) { - affs_error(inode->i_sb,"fixup","Cannot read block %d",key); - iput(ofinode); - return -ENOENT; - } - lock_super(inode->i_sb); - memcpy(nbh->b_data + 8,bh->b_data + 8,AFFS_I2BSIZE(inode) - 208); - FILE_END(nbh->b_data,inode)->byte_size = FILE_END(bh->b_data,inode)-> - byte_size; - FILE_END(nbh->b_data,inode)->extension = FILE_END(bh->b_data,inode)-> - extension; - FILE_END(nbh->b_data,inode)->secondary_type = FILE_END(bh->b_data,inode)-> - secondary_type; - FILE_END(nbh->b_data,inode)->original = 0; - - ofinode->u.affs_i.i_original = 0; - ofinode->u.affs_i.i_hlink = 0; - ofinode->i_size = inode->i_size; - ofinode->i_uid = inode->i_uid; - ofinode->i_gid = inode->i_gid; - mark_inode_dirty(ofinode); - link_key = ofinode->i_ino; - - /* Let all remaining links point to the new file */ - while (1) { - affs_fix_checksum(AFFS_I2BSIZE(inode),nbh->b_data,5); - mark_buffer_dirty(nbh,1); - key = htonl(FILE_END(nbh->b_data,inode)->link_chain); - affs_brelse(nbh); - iput(ofinode); - if (!key || !(nbh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)))) - break; - if ((ofinode = iget(inode->i_sb,key))) { - if (!ofinode->u.affs_i.i_hlink) - affs_error(inode->i_sb,"fixup", - "Inode %d in link chain is not a link", - key); - ofinode->u.affs_i.i_original = link_key; - mark_inode_dirty(ofinode); - FILE_END(nbh->b_data,inode)->original = htonl(link_key); - } else - affs_error(inode->i_sb,"fixup","Cannot read block %d",key); - } - /* Turn old inode to a link */ - inode->u.affs_i.i_hlink = 1; - unlock_super(inode->i_sb); - } - return 0; - } else if (type == ST_SOFTLINK) { - return 0; - } else { - affs_error(inode->i_sb,"fixup","Bad secondary type (%d)",type); - return -EBADF; - } -} diff --git a/fs/affs/symlink.c b/fs/affs/symlink.c index 24d1ed118..22042158a 100644 --- a/fs/affs/symlink.c +++ b/fs/affs/symlink.c @@ -19,7 +19,8 @@ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) -static int affs_readlink(struct inode *, char *, int); +static int affs_readlink(struct inode *, char *, int); +static struct dentry *affs_follow_link(struct inode *inode, struct dentry *base); struct inode_operations affs_symlink_inode_operations = { NULL, /* no file-operations */ @@ -33,9 +34,13 @@ struct inode_operations affs_symlink_inode_operations = { NULL, /* mknod */ NULL, /* rename */ affs_readlink, /* readlink */ + affs_follow_link, /* follow_link */ + NULL, /* readpage */ + NULL, /* writepage */ NULL, /* bmap */ NULL, /* truncate */ - NULL /* permission */ + NULL, /* permission */ + NULL /* smap */ }; static int @@ -46,21 +51,24 @@ affs_readlink(struct inode *inode, char *buffer, int buflen) int i, j; char c; char lc; + char *pf; pr_debug("AFFS: readlink(ino=%lu,buflen=%d)\n",inode->i_ino,buflen); bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode)); - i = 0; - j = 0; if (!bh) { - affs_error(inode->i_sb,"readlink","Cannot read block %lu\n",inode->i_ino); - goto symlink_end; + affs_warning(inode->i_sb,"follow_link","Unable to read i-node block %lu\n", + inode->i_ino); + return -EIO; } lf = (struct slink_front *)bh->b_data; lc = 0; + i = 0; + j = 0; + pf = inode->i_sb->u.affs_sb.s_prefix ? inode->i_sb->u.affs_sb.s_prefix : "/"; if (strchr(lf->symname,':')) { /* Handle assign or volume name */ - while (i < buflen && (c = inode->i_sb->u.affs_sb.s_prefix[i])) { + while (i < buflen && (c = pf[i])) { put_user(c,buffer++); i++; } @@ -84,8 +92,64 @@ affs_readlink(struct inode *inode, char *buffer, int buflen) lc = c; i++, j++; } -symlink_end: - iput(inode); affs_brelse(bh); return i; } + +static struct dentry * +affs_follow_link(struct inode *inode, struct dentry *base) +{ + struct buffer_head *bh; + struct slink_front *lf; + char *buffer; + int i, j; + char c; + char lc; + char *pf; + + pr_debug("AFFS: follow_link(ino=%lu)\n",inode->i_ino); + + if (!(buffer = kmalloc(1024,GFP_KERNEL))) { + dput(base); + return ERR_PTR(-ENOSPC); + } + bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode)); + if (!bh) { + affs_warning(inode->i_sb,"follow_link","Unable to read i-node block %lu\n", + inode->i_ino); + kfree(buffer); + dput(base); + return ERR_PTR(-EIO); + } + i = 0; + j = 0; + lf = (struct slink_front *)bh->b_data; + lc = 0; + pf = inode->i_sb->u.affs_sb.s_prefix ? inode->i_sb->u.affs_sb.s_prefix : "/"; + + if (strchr(lf->symname,':')) { /* Handle assign or volume name */ + while (i < 1023 && (c = pf[i])) + buffer[i++] = c; + while (i < 1023 && lf->symname[j] != ':') + buffer[i++] = lf->symname[j++]; + if (i < 1023) + buffer[i++] = '/'; + j++; + lc = '/'; + } + while (i < 1023 && (c = lf->symname[j])) { + if (c == '/' && lc == '/' && i < 1020) { /* parent dir */ + buffer[i++] = '.'; + buffer[i++] = '.'; + } + buffer[i++] = c; + lc = c; + j++; + } + buffer[i] = '\0'; + affs_brelse(bh); + base = lookup_dentry(buffer,base,1); + kfree(buffer); + return base; +} + diff --git a/fs/autofs/waitq.c b/fs/autofs/waitq.c index 7e4558d9d..607b4314e 100644 --- a/fs/autofs/waitq.c +++ b/fs/autofs/waitq.c @@ -42,31 +42,36 @@ void autofs_catatonic_mode(struct autofs_sb_info *sbi) static int autofs_write(struct file *file, const void *addr, int bytes) { - unsigned long fs; - unsigned long old_signal; + unsigned long sigpipe, flags; + mm_segment_t fs; const char *data = (const char *)addr; - int written = 0; + ssize_t wr = 0; /** WARNING: this is not safe for writing more than PIPE_BUF bytes! **/ + sigpipe = sigismember(¤t->signal, SIGPIPE); + /* Save pointer to user space and point back to kernel space */ fs = get_fs(); set_fs(KERNEL_DS); - old_signal = current->signal; - - while ( bytes && (written = file->f_op->write(file,data,bytes,&file->f_pos)) > 0 ) { - data += written; - bytes -= written; + while (bytes && + (wr = file->f_op->write(file,data,bytes,&file->f_pos)) > 0) { + data += wr; + bytes -= wr; } - if ( written == -EPIPE && !(old_signal & (1 << (SIGPIPE-1))) ) { - /* Keep the currently executing process from receiving a - SIGPIPE unless it was already supposed to get one */ - current->signal &= ~(1 << (SIGPIPE-1)); - } set_fs(fs); + /* Keep the currently executing process from receiving a + SIGPIPE unless it was already supposed to get one */ + if (wr == -EPIPE && !sigpipe) { + spin_lock_irqsave(¤t->sigmask_lock, flags); + sigdelset(¤t->signal, SIGPIPE); + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); + } + return (bytes > 0); } diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c index 511dca04a..9a4a460e8 100644 --- a/fs/binfmt_aout.c +++ b/fs/binfmt_aout.c @@ -82,7 +82,7 @@ do_aout_core_dump(long signr, struct pt_regs * regs) struct dentry * dentry = NULL; struct inode * inode = NULL; struct file file; - unsigned long fs; + mm_segment_t fs; int has_dumped = 0; char corefile[6+sizeof(current->comm)]; unsigned long dump_start, dump_size; diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index bb59cdfaf..47345a358 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -428,7 +428,7 @@ do_load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) unsigned int interpreter_type = INTERPRETER_NONE; unsigned char ibcs2_interpreter; int i; - unsigned long old_fs; + mm_segment_t old_fs; unsigned long error; struct elf_phdr * elf_ppnt, *elf_phdata; int elf_exec_fileno; @@ -1082,7 +1082,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs) struct file file; struct dentry *dentry; struct inode *inode; - unsigned long fs; + mm_segment_t fs; char corefile[6+sizeof(current->comm)]; int segs; int i; diff --git a/fs/buffer.c b/fs/buffer.c index 1c8ab164e..941580f3e 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -582,21 +582,23 @@ struct buffer_head *efind_buffer(kdev_t dev, int block, int size) */ struct buffer_head * get_hash_table(kdev_t dev, int block, int size) { + struct buffer_head * bh; for (;;) { - struct buffer_head * bh; - - bh=find_buffer(dev,block,size); + bh = find_buffer(dev,block,size); if (!bh) - return bh; + break; bh->b_count++; bh->b_lru_time = jiffies; - wait_on_buffer(bh); + if (!test_bit(BH_Lock, &bh->b_state)) + break; + __wait_on_buffer(bh); if (bh->b_dev == dev && bh->b_blocknr == block && bh->b_size == size) - return bh; + break; bh->b_count--; } + return bh; } unsigned int get_hardblocksize(kdev_t dev) @@ -790,50 +792,87 @@ repeat: } /* - * If we achieved at least half of our goal, return now. + * If there are dirty buffers, do a non-blocking wake-up. + * This increases the chances of having buffers available + * for the next call ... */ - if (obtained >= (needed >> 1)) - return; - - /* Too bad, that was not enough. Try a little harder to grow some. */ - if (nr_free_pages > min_free_pages + 5) { - if (grow_buffers(GFP_BUFFER, size)) { - obtained += PAGE_SIZE; - goto repeat; - } - } + if (nr_buffers_type[BUF_DIRTY]) + wakeup_bdflush(0); /* - * Make one more attempt to allocate some buffers. + * Allocate buffers to reach half our goal, if possible. + * Since the allocation doesn't block, there's no reason + * to search the buffer lists again. Then return if there + * are _any_ free buffers. */ - if (grow_buffers(GFP_ATOMIC, size)) + while (obtained < (needed >> 1) && + nr_free_pages > min_free_pages + 5 && + grow_buffers(GFP_BUFFER, size)) obtained += PAGE_SIZE; + if (free_list[BUFSIZE_INDEX(size)]) + return; + + /* + * If there are dirty buffers, wait while bdflush writes + * them out. The buffers become locked, but we can just + * wait for one to unlock ... + */ + if (nr_buffers_type[BUF_DIRTY]) + wakeup_bdflush(1); + + /* + * In order to prevent a buffer shortage from exhausting + * the system's reserved pages, we force tasks to wait + * before using reserved pages for buffers. This is easily + * accomplished by waiting on an unused locked buffer. + */ + if ((bh = lru_list[BUF_LOCKED]) != NULL) { + for (i = nr_buffers_type[BUF_LOCKED]; i--; bh = bh->b_next_free) + { + if (bh->b_size != size) + continue; + if (bh->b_count) + continue; + if (!buffer_locked(bh)) + continue; + if (buffer_dirty(bh) || buffer_protected(bh)) + continue; + if (MAJOR(bh->b_dev) == LOOP_MAJOR) + continue; + /* + * We've found an unused, locked, non-dirty buffer of + * the correct size. Claim it so no one else can, + * then wait for it to unlock. + */ + bh->b_count++; + wait_on_buffer(bh); + bh->b_count--; + /* + * Loop back to harvest this (and maybe other) buffers. + */ + goto repeat; + } + } + /* - * If we got any buffers, or another task freed some, - * return now to let this task proceed. + * Convert a reserved page into buffers ... should happen only rarely. */ - if (obtained || free_list[BUFSIZE_INDEX(size)]) { + if (nr_free_pages > (min_free_pages >> 1) && + grow_buffers(GFP_ATOMIC, size)) { #ifdef BUFFER_DEBUG -printk("refill_freelist: obtained %d of %d, free list=%d\n", -obtained, needed, free_list[BUFSIZE_INDEX(size)] != NULL); +printk("refill_freelist: used reserve page\n"); #endif return; } /* - * System is _very_ low on memory ... wake up bdflush and wait. + * System is _very_ low on memory ... sleep and try later. */ #ifdef BUFFER_DEBUG -printk("refill_freelist: waking bdflush\n"); +printk("refill_freelist: task %s waiting for buffers\n", current->comm); #endif - wakeup_bdflush(1); - /* - * While we slept, other tasks may have needed buffers and entered - * refill_freelist. This could be a big problem ... reset the - * needed amount to the absolute minimum. - */ - needed = size; + schedule(); goto repeat; } @@ -1944,7 +1983,10 @@ int bdflush(void * unused) /* If there are still a lot of dirty buffers around, skip the sleep and flush some more */ if(ndirty == 0 || nr_buffers_type[BUF_DIRTY] <= nr_buffers * bdf_prm.b_un.nfract/100) { - current->signal = 0; + spin_lock_irq(¤t->sigmask_lock); + flush_signals(current); + spin_unlock_irq(¤t->sigmask_lock); + interruptible_sleep_on(&bdflush_wait); } } diff --git a/fs/dcache.c b/fs/dcache.c index 6c59851c3..a2aaeeaec 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -129,7 +129,7 @@ out: return; } - printk("Negative d_count (%d) for %s/%s\n", + printk(KERN_CRIT "Negative d_count (%d) for %s/%s\n", count, dentry->d_parent->d_name.name, dentry->d_name.name); @@ -378,7 +378,7 @@ resume: if (!list_empty(&dentry->d_subdirs)) { this_parent = dentry; #ifdef DCACHE_DEBUG -printk("select_parent: descending to %s/%s, found=%d\n", +printk(KERN_DEBUG "select_parent: descending to %s/%s, found=%d\n", dentry->d_parent->d_name.name, dentry->d_name.name, found); #endif goto repeat; @@ -391,7 +391,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name, found); next = this_parent->d_child.next; this_parent = this_parent->d_parent; #ifdef DCACHE_DEBUG -printk("select_parent: ascending to %s/%s, found=%d\n", +printk(KERN_DEBUG "select_parent: ascending to %s/%s, found=%d\n", this_parent->d_parent->d_name.name, this_parent->d_name.name, found); #endif goto resume; @@ -439,7 +439,7 @@ void check_dcache_memory() goal = 50; count = select_dcache(32, goal); #ifdef DCACHE_DEBUG -printk("check_dcache_memory: goal=%d, count=%d\n", goal, count); +printk(KERN_DEBUG "check_dcache_memory: goal=%d, count=%d\n", goal, count); #endif if (count) { prune_dcache(count); @@ -678,7 +678,7 @@ void d_add(struct dentry * entry, struct inode * inode) void d_move(struct dentry * dentry, struct dentry * target) { if (!dentry->d_inode) - printk("VFS: moving negative dcache entry\n"); + printk(KERN_WARNING "VFS: moving negative dcache entry\n"); /* Move the dentry to the target hash queue */ list_del(&dentry->d_hash); diff --git a/fs/dquot.c b/fs/dquot.c index cf2b91c0a..4e2c60162 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -222,7 +222,7 @@ static void write_dquot(struct dquot *dquot) { short type = dquot->dq_type; struct file *filp = dquot->dq_mnt->mnt_quotas[type]; - unsigned long fs; + mm_segment_t fs; loff_t offset; if (!(dquot->dq_flags & DQ_MOD) || (filp == (struct file *)NULL)) @@ -246,7 +246,7 @@ static void read_dquot(struct dquot *dquot) { short type = dquot->dq_type; struct file *filp = dquot->dq_mnt->mnt_quotas[type]; - unsigned long fs; + mm_segment_t fs; loff_t offset; if (filp == (struct file *)NULL) @@ -261,7 +261,7 @@ unsigned long copy_strings(int argc,char ** argv,unsigned long *page, unsigned long p, int from_kmem) { char *str; - unsigned long old_fs; + mm_segment_t old_fs; if (!p) return 0; /* bullet-proofing */ @@ -374,7 +374,7 @@ int read_exec(struct dentry *dentry, unsigned long offset, } else file.f_pos = offset; if (to_kmem) { - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); set_fs(get_ds()); result = file.f_op->read(&file, addr, count, &file.f_pos); set_fs(old_fs); @@ -459,22 +459,29 @@ static inline int make_private_signals(void) } /* + * If make_private_signals() made a copy of the signal table, decrement the + * refcount of the original table, and free it if necessary. + * We don't do that in make_private_signals() so that we can back off + * in flush_old_exec() if an error occurs after calling make_private_signals(). + */ + +static inline void release_old_signals(struct signal_struct * oldsig) +{ + if (current->sig == oldsig) + return; + if (atomic_dec_and_test(&oldsig->count)) + kfree(oldsig); +} + +/* * These functions flushes out all traces of the currently running executable * so that a new one can be started */ -static inline void flush_old_signals(struct signal_struct *sig) +static inline void flush_old_signals(struct task_struct *t) { - int i; - struct sigaction * sa = sig->action; - - for (i=32 ; i != 0 ; i--) { - sa->sa_mask = 0; - sa->sa_flags = 0; - if (sa->sa_handler != SIG_IGN) - sa->sa_handler = NULL; - sa++; - } + flush_signals(t); + flush_signal_handlers(t); } static inline void flush_old_files(struct files_struct * files) @@ -517,6 +524,9 @@ int flush_old_exec(struct linux_binprm * bprm) retval = exec_mmap(); if (retval) goto flush_failed; + /* This is the point of no return */ + release_old_signals(oldsig); + if (current->euid == current->uid && current->egid == current->gid) current->dumpable = 1; name = bprm->filename; @@ -535,7 +545,7 @@ int flush_old_exec(struct linux_binprm * bprm) permission(bprm->dentry->d_inode,MAY_READ)) current->dumpable = 0; - flush_old_signals(current->sig); + flush_old_signals(current); flush_old_files(current->files); return 0; diff --git a/fs/fat/file.c b/fs/fat/file.c index f3a4f6cec..c1357f784 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -155,7 +155,7 @@ static void fat_prefetch ( /* Read a file into user space */ -ssize_t fat_file_read( +static ssize_t fat_file_read_text( struct file *filp, char *buf, size_t count, @@ -270,6 +270,17 @@ ssize_t fat_file_read( return buf-start; } +ssize_t fat_file_read( + struct file *filp, + char *buf, + size_t count, + loff_t *ppos) +{ + struct inode *inode = filp->f_dentry->d_inode; + if (!MSDOS_I(inode)->i_binary) + return fat_file_read_text(filp, buf, count, ppos); + return generic_file_read(filp, buf, count, ppos); +} /* Write to a file either from user space */ diff --git a/fs/fat/mmap.c b/fs/fat/mmap.c index 545874a04..48cbc7b4f 100644 --- a/fs/fat/mmap.c +++ b/fs/fat/mmap.c @@ -60,7 +60,7 @@ static unsigned long fat_file_mmap_nopage( filp.f_pos = pos; need_read = PAGE_SIZE - clear; { - unsigned long cur_fs = get_fs(); + mm_segment_t cur_fs = get_fs(); set_fs (KERNEL_DS); cur_read = fat_file_read (&filp, (char*)page, need_read, &filp.f_pos); diff --git a/fs/fcntl.c b/fs/fcntl.c index 99561051d..8743916ee 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -178,7 +178,7 @@ static void send_sigio(int pid, uid_t uid, uid_t euid) (euid ^ p->suid) && (euid ^ p->uid) && (uid ^ p->suid) && (uid ^ p->uid)) continue; - p->signal |= 1 << (SIGIO-1); + send_sig(SIGIO, p, 1); if (p->state == TASK_INTERRUPTIBLE && signal_pending(p)) wake_up_process(p); } diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index b77e9facd..88cf1fd4a 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -33,6 +33,7 @@ * wrong information within the volume descriptors. */ #define IGNORE_WRONG_MULTI_VOLUME_SPECS +#define BEQUIET #ifdef LEAK_CHECK static int check_malloc = 0; @@ -237,7 +238,7 @@ static unsigned int isofs_get_last_session(kdev_t dev) * we would destroy the kernels idea about FS on root * mount in read_super... [chexum] */ - unsigned long old_fs=get_fs(); + mm_segment_t old_fs=get_fs(); inode_fake.i_rdev=dev; ms_info.addr_format=CDROM_LBA; set_fs(KERNEL_DS); @@ -500,7 +501,8 @@ struct super_block *isofs_read_super(struct super_block *s,void *data, s->s_flags |= MS_RDONLY /* | MS_NODEV | MS_NOSUID */; brelse(bh); - + +#ifndef BEQUIET printk(KERN_DEBUG "Max size:%ld Log zone size:%ld\n", s->u.isofs_sb.s_max_size, 1UL << s->u.isofs_sb.s_log_zone_size); @@ -509,6 +511,7 @@ struct super_block *isofs_read_super(struct super_block *s,void *data, (isonum_733(rootp->extent) + isonum_711(rootp->ext_attr_length)) << s -> u.isofs_sb.s_log_zone_size); if(high_sierra) printk(KERN_DEBUG "Disc in High Sierra format.\n"); +#endif unlock_super(s); /* set up enough so that it can read an inode */ @@ -541,7 +544,9 @@ struct super_block *isofs_read_super(struct super_block *s,void *data, } } set_blocksize(dev, opt.blocksize); +#ifndef BEQUIET printk(KERN_DEBUG "Forcing new log zone size:%d\n", opt.blocksize); +#endif } #ifdef CONFIG_JOLIET diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c index 1bedcf9be..f638084b6 100644 --- a/fs/isofs/namei.c +++ b/fs/isofs/namei.c @@ -66,7 +66,7 @@ static struct buffer_head * isofs_find_entry(struct inode * dir, unsigned char bufbits = ISOFS_BUFFER_BITS(dir); unsigned int block, i, f_pos, offset, inode_number = 0; /* shut gcc up */ - struct buffer_head * bh; + struct buffer_head * bh , * retval = NULL; unsigned int old_offset; int dlen, match; char * dpnt; @@ -86,7 +86,7 @@ static struct buffer_head * isofs_find_entry(struct inode * dir, block = isofs_bmap(dir,f_pos >> bufbits); if (!block || !(bh = bread(dir->i_dev,block,bufsize))) return NULL; - + while (f_pos < dir->i_size) { /* if de is in kmalloc'd memory, do not point to the @@ -118,13 +118,14 @@ static struct buffer_head * isofs_find_entry(struct inode * dir, + ISOFS_BLOCK_SIZE); } brelse(bh); + bh = NULL; if (f_pos >= dir->i_size) - return 0; + break; block = isofs_bmap(dir,f_pos>>bufbits); if (!block || !(bh = bread(dir->i_dev,block,bufsize))) - return NULL; + break; continue; /* Will kick out if past end of directory */ } @@ -145,7 +146,7 @@ static struct buffer_head * isofs_find_entry(struct inode * dir, block = isofs_bmap(dir,f_pos>>bufbits); if (!block || !(bh_next = bread(dir->i_dev,block,bufsize))) - return NULL; + break; de = (struct iso_directory_record *) kmalloc(offset - old_offset, GFP_KERNEL); @@ -162,14 +163,14 @@ static struct buffer_head * isofs_find_entry(struct inode * dir, if (dir->i_sb->u.isofs_sb.s_rock || dir->i_sb->u.isofs_sb.s_joliet_level) { - page = (unsigned char *) - __get_free_page(GFP_KERNEL); - if (!page) return NULL; + if (! page) { + page = (unsigned char *) + __get_free_page(GFP_KERNEL); + if (!page) break; + } } if (dir->i_sb->u.isofs_sb.s_rock && ((i = get_rock_ridge_filename(de, page, dir)))) { - if (i == -1) - goto out;/* Relocated deep directory */ dlen = i; dpnt = page; #ifdef CONFIG_JOLIET @@ -203,8 +204,6 @@ static struct buffer_head * isofs_find_entry(struct inode * dir, { match = isofs_match(namelen,name,dpnt,dlen); } - - if (page) free_page((unsigned long) page); if (match) { if(inode_number == -1) { /* Should only happen for the '..' entry */ @@ -213,16 +212,16 @@ static struct buffer_head * isofs_find_entry(struct inode * dir, find_rock_ridge_relocation(de,dir)); } *ino = inode_number; - if(de_not_in_buf) - kfree(de); - return bh; + retval = bh; + bh = NULL; + break; } } - out: - brelse(bh); + if (page) free_page((unsigned long) page); + if (bh) brelse(bh); if(de_not_in_buf) kfree(de); - return NULL; + return retval; } int isofs_lookup(struct inode * dir, struct dentry * dentry) diff --git a/fs/lockd/clntproc.c b/fs/lockd/clntproc.c index c25a19c97..d0c70c276 100644 --- a/fs/lockd/clntproc.c +++ b/fs/lockd/clntproc.c @@ -90,7 +90,8 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) struct nfs_server *nfssrv = NFS_SERVER(inode); struct nlm_host *host; struct nlm_rqst reqst, *call = &reqst; - unsigned long oldmask; + sigset_t oldset; + unsigned long flags; int status; /* Always use NLM version 1 over UDP for now... */ @@ -114,16 +115,21 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) } /* Keep the old signal mask */ - oldmask = current->blocked; + spin_lock_irqsave(¤t->sigmask_lock, flags); + oldset = current->blocked; /* If we're cleaning up locks because the process is exiting, * perform the RPC call asynchronously. */ if (cmd == F_SETLK && fl->fl_type == F_UNLCK - && (current->flags & PF_EXITING)) { - current->blocked = ~0UL; /* Mask all signals */ + && (current->flags & PF_EXITING)) { + sigfillset(¤t->blocked); /* Mask all signals */ + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); + call = nlmclnt_alloc_call(); call->a_flags = RPC_TASK_ASYNC; } else { + spin_unlock_irqrestore(¤t->sigmask_lock, flags); call->a_flags = 0; } call->a_host = host; @@ -145,7 +151,10 @@ nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl) if (status < 0 && (call->a_flags & RPC_TASK_ASYNC)) rpc_free(call); - current->blocked = oldmask; + spin_lock_irqsave(¤t->sigmask_lock, flags); + current->blocked = oldset; + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); done: dprintk("lockd: clnt proc returns %d\n", status); @@ -454,11 +463,16 @@ int nlmclnt_cancel(struct nlm_host *host, struct file_lock *fl) { struct nlm_rqst *req; - unsigned long oldmask = current->blocked; + unsigned long flags; + sigset_t oldset; int status; /* Block all signals while setting up call */ - current->blocked = ~0UL; + spin_lock_irqsave(¤t->sigmask_lock, flags); + oldset = current->blocked; + sigfillset(¤t->blocked); + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); do { req = (struct nlm_rqst *) rpc_allocate(RPC_TASK_ASYNC, @@ -474,7 +488,11 @@ nlmclnt_cancel(struct nlm_host *host, struct file_lock *fl) if (status < 0) rpc_free(req); - current->blocked = oldmask; + spin_lock_irqsave(¤t->sigmask_lock, flags); + current->blocked = oldset; + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); + return status; } diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index c5f77ef89..e649cf633 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -37,8 +37,7 @@ #define NLMDBG_FACILITY NLMDBG_SVC #define LOCKD_BUFSIZE (1024 + NLMSSVC_XDRSIZE) -#define BLOCKABLE_SIGS (~(_S(SIGKILL) | _S(SIGSTOP))) -#define _S(sig) (1 << ((sig) - 1)) +#define BLOCKABLE_SIGS (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) extern struct svc_program nlmsvc_program; struct nlmsvc_binding * nlmsvc_ops = NULL; @@ -65,7 +64,6 @@ static void lockd(struct svc_rqst *rqstp) { struct svc_serv *serv = rqstp->rq_server; - sigset_t oldsigmask; int err = 0; /* Lock module and set up kernel thread */ @@ -118,8 +116,11 @@ lockd(struct svc_rqst *rqstp) */ while ((nlmsvc_users || !signalled()) && nlmsvc_pid == current->pid) { - if (signalled()) - current->signal = 0; + if (signalled()) { + spin_lock_irq(¤t->sigmask_lock); + flush_signals(current); + spin_unlock_irq(¤t->sigmask_lock); + } /* * Retry any blocked locks that have been notified by @@ -162,10 +163,17 @@ lockd(struct svc_rqst *rqstp) } /* Process request with all signals blocked. */ - oldsigmask = current->blocked; - current->blocked = BLOCKABLE_SIGS; + spin_lock_irq(¤t->sigmask_lock); + siginitsetinv(¤t->blocked, ~BLOCKABLE_SIGS); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + svc_process(serv, rqstp); - current->blocked = oldsigmask; + + spin_lock_irq(¤t->sigmask_lock); + sigemptyset(¤t->blocked); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); /* Unlock export hash tables */ if (nlmsvc_ops) diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c index 0c2380de3..ce405d8d5 100644 --- a/fs/lockd/svcsubs.c +++ b/fs/lockd/svcsubs.c @@ -24,24 +24,25 @@ * Global file hash table */ #define FILE_NRHASH 32 -#define FILE_HASH(dhash) ((dhash) & FILE_NRHASH) +#define FILE_HASH_BITS 5 static struct nlm_file * nlm_files[FILE_NRHASH]; static struct semaphore nlm_file_sema = MUTEX; +static unsigned int file_hash(dev_t dev, ino_t ino) +{ + unsigned long tmp = (unsigned long) ino | (unsigned long) dev; + tmp = tmp + (tmp >> FILE_HASH_BITS) + (tmp >> FILE_HASH_BITS*2); + return tmp & (FILE_NRHASH - 1); +} + /* * Lookup file info. If it doesn't exist, create a file info struct * and open a (VFS) file for the given inode. * - * The NFS filehandle must have been validated prior to this call, - * as we assume that the dentry pointer is valid. - * * FIXME: * Note that we open the file O_RDONLY even when creating write locks. * This is not quite right, but for now, we assume the client performs * the proper R/W checking. - * - * The dentry in the FH may not be validated .. can we call this with - * the full svc_fh? */ u32 nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result, @@ -49,40 +50,38 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result, { struct nlm_file *file; struct knfs_fh *fh = (struct knfs_fh *) f; - struct dentry *dentry = fh->fh_dcookie; - unsigned int hash = FILE_HASH(dentry->d_name.hash); + unsigned int hash = file_hash(fh->fh_dev, fh->fh_ino); u32 nfserr; - dprintk("lockd: nlm_file_lookup(%s/%s)\n", - dentry->d_parent->d_name.name, dentry->d_name.name); + dprintk("lockd: nlm_file_lookup(%s/%ld)\n", + kdevname(fh->fh_dev), fh->fh_ino); /* Lock file table */ down(&nlm_file_sema); for (file = nlm_files[hash]; file; file = file->f_next) { - if (file->f_handle.fh_dcookie == dentry - && !memcmp(&file->f_handle, fh, sizeof(*fh))) + if (file->f_handle.fh_dcookie == fh->fh_dcookie && + !memcmp(&file->f_handle, fh, sizeof(*fh))) goto found; } - dprintk("lockd: creating file for %s/%s\n", - dentry->d_parent->d_name.name, dentry->d_name.name); - if (!(file = (struct nlm_file *) kmalloc(sizeof(*file), GFP_KERNEL))) { - up(&nlm_file_sema); - return nlm_lck_denied_nolocks; - } + dprintk("lockd: creating file for %s/%ld\n", + kdevname(fh->fh_dev), fh->fh_ino); + nfserr = nlm_lck_denied_nolocks; + file = (struct nlm_file *) kmalloc(sizeof(*file), GFP_KERNEL); + if (!file) + goto out_unlock; memset(file, 0, sizeof(*file)); file->f_handle = *fh; file->f_sema = MUTEX; /* Open the file. Note that this must not sleep for too long, else - * we would lock up lockd:-) So no NFS re-exports, folks. */ + * we would lock up lockd:-) So no NFS re-exports, folks. + */ if ((nfserr = nlmsvc_ops->fopen(rqstp, fh, &file->f_file)) != 0) { dprintk("lockd: open failed (nfserr %ld)\n", ntohl(nfserr)); - kfree(file); - up(&nlm_file_sema); - return nlm_lck_denied; + goto out_free; } file->f_next = nlm_files[hash]; @@ -91,9 +90,17 @@ nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result, found: dprintk("lockd: found file %p (count %d)\n", file, file->f_count); *result = file; - up(&nlm_file_sema); file->f_count++; - return 0; + nfserr = 0; + +out_unlock: + up(&nlm_file_sema); + return nfserr; + +out_free: + kfree(file); + nfserr = nlm_lck_denied; + goto out_unlock; } /* @@ -102,11 +109,12 @@ found: static inline void nlm_delete_file(struct nlm_file *file) { - struct dentry *dentry = file->f_file.f_dentry; + struct inode *inode = file->f_file.f_dentry->d_inode; struct nlm_file **fp, *f; - dprintk("lockd: closing file %p\n", dentry); - fp = nlm_files + FILE_HASH(dentry->d_name.hash); + dprintk("lockd: closing file %s/%ld\n", + kdevname(inode->i_dev), inode->i_ino); + fp = nlm_files + file_hash(inode->i_dev, inode->i_ino); while ((f = *fp) != NULL) { if (f == file) { *fp = file->f_next; diff --git a/fs/locks.c b/fs/locks.c index 3f4c2c287..278193f56 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -402,11 +402,11 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l) switch (flock.l_type) { case F_RDLCK: - if (!(filp->f_mode & 1)) + if (!(filp->f_mode & FMODE_READ)) return (-EBADF); break; case F_WRLCK: - if (!(filp->f_mode & 2)) + if (!(filp->f_mode & FMODE_WRITE)) return (-EBADF); break; case F_UNLCK: diff --git a/fs/namei.c b/fs/namei.c index 242363824..2e7c4bff6 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -131,7 +131,7 @@ static inline int do_getname(const char *filename, char *page) unsigned long len = PAGE_SIZE; if ((unsigned long) filename >= TASK_SIZE) { - if (get_fs() != KERNEL_DS) + if (!segment_eq(get_fs(), KERNEL_DS)) return -EFAULT; } else if (TASK_SIZE - (unsigned long) filename < PAGE_SIZE) len = TASK_SIZE - (unsigned long) filename; @@ -737,10 +737,9 @@ static inline int do_mkdir(const char * pathname, int mode) goto exit; dir = lock_parent(dentry); - error = PTR_ERR(dir); if (IS_ERR(dir)) - goto exit; + goto exit_dput; error = -EEXIST; if (dentry->d_inode) @@ -765,6 +764,7 @@ static inline int do_mkdir(const char * pathname, int mode) exit_lock: unlock_dir(dir); +exit_dput: dput(dentry); exit: return error; @@ -798,10 +798,9 @@ static inline int do_rmdir(const char * name) goto exit; dir = lock_parent(dentry); - error = PTR_ERR(dir); if (IS_ERR(dir)) - goto exit; + goto exit_dput; error = -ENOENT; if (!dentry->d_inode) @@ -838,6 +837,7 @@ static inline int do_rmdir(const char * name) exit_lock: unlock_dir(dir); +exit_dput: dput(dentry); exit: return error; @@ -871,10 +871,9 @@ static inline int do_unlink(const char * name) goto exit; dir = lock_parent(dentry); - error = PTR_ERR(dir); if (IS_ERR(dir)) - goto exit; + goto exit_dput; error = -ENOENT; if (!dentry->d_inode) @@ -911,6 +910,7 @@ static inline int do_unlink(const char * name) exit_lock: unlock_dir(dir); +exit_dput: dput(dentry); exit: return error; @@ -945,10 +945,9 @@ static inline int do_symlink(const char * oldname, const char * newname) goto exit; dir = lock_parent(dentry); - error = PTR_ERR(dir); if (IS_ERR(dir)) - goto exit; + goto exit_dput; error = -EEXIST; if (dentry->d_inode) @@ -972,6 +971,7 @@ static inline int do_symlink(const char * oldname, const char * newname) exit_lock: unlock_dir(dir); +exit_dput: dput(dentry); exit: return error; @@ -1016,10 +1016,9 @@ static inline int do_link(const char * oldname, const char * newname) goto exit_old; dir = lock_parent(new_dentry); - error = PTR_ERR(dir); if (IS_ERR(dir)) - goto exit; + goto exit_new; error = -ENOENT; inode = old_dentry->d_inode; @@ -1059,6 +1058,7 @@ static inline int do_link(const char * oldname, const char * newname) exit_lock: unlock_dir(dir); +exit_new: dput(new_dentry); exit_old: dput(old_dentry); diff --git a/fs/nametrans.c b/fs/nametrans.c index 15c98ed70..fbd456045 100644 --- a/fs/nametrans.c +++ b/fs/nametrans.c @@ -168,7 +168,7 @@ char* env_transl(void) int i; if(current && current->mm && (env = (char*)current->mm->env_start) - && get_ds() != get_fs() + && !segment_eq(get_ds(), get_fs()) && current->mm->env_end>=current->mm->env_start+10 && !verify_area(VERIFY_READ,env,10)) { for(i=0; i<10; i++) { diff --git a/fs/ncpfs/mmap.c b/fs/ncpfs/mmap.c index 56275034d..2a140ea55 100644 --- a/fs/ncpfs/mmap.c +++ b/fs/ncpfs/mmap.c @@ -40,7 +40,7 @@ static unsigned long ncp_file_mmap_nopage(struct vm_area_struct *area, unsigned long tmp; int bufsize; int pos; - unsigned long fs; + mm_segment_t fs; page = __get_free_page(GFP_KERNEL); if (!page) diff --git a/fs/ncpfs/sock.c b/fs/ncpfs/sock.c index 08055ac5e..cc8326c05 100644 --- a/fs/ncpfs/sock.c +++ b/fs/ncpfs/sock.c @@ -75,14 +75,12 @@ static int _send(struct socket *sock, const void *buff, int len) #define NCP_SLACK_SPACE 1024 -#define _S(nr) (1<<((nr)-1)) - static int do_ncp_rpc_call(struct ncp_server *server, int size) { struct file *file; struct inode *inode; struct socket *sock; - unsigned long fs; + mm_segment_t fs; int result; char *start = server->packet; poll_table wait_table; @@ -93,7 +91,8 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size) int major_timeout_seen; int acknowledge_seen; int n; - unsigned long old_mask; + sigset_t old_set; + unsigned long mask, flags; /* We have to check the result, so store the complete header */ struct ncp_request_header request = @@ -115,17 +114,25 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size) retrans = server->m.retry_count; major_timeout_seen = 0; acknowledge_seen = 0; - old_mask = current->blocked; - current->blocked |= ~(_S(SIGKILL) -#if 0 - | _S(SIGSTOP) -#endif - | ((server->m.flags & NCP_MOUNT_INTR) - ? ((current->sig->action[SIGINT - 1].sa_handler == SIG_DFL - ? _S(SIGINT) : 0) - | (current->sig->action[SIGQUIT - 1].sa_handler == SIG_DFL - ? _S(SIGQUIT) : 0)) - : 0)); + + spin_lock_irqsave(¤t->sigmask_lock, flags); + old_set = current->blocked; + mask = sigmask(SIGKILL) | sigmask(SIGSTOP); + if (server->m.flags & NCP_MOUNT_INTR) { + /* FIXME: This doesn't seem right at all. So, like, + we can't handle SIGINT and get whatever to stop? + What if we've blocked it ourselves? What about + alarms? Why, in fact, are we mucking with the + sigmask at all? -- r~ */ + if (current->sig->action[SIGINT - 1].sa_handler == SIG_DFL) + mask |= sigmask(SIGINT); + if (current->sig->action[SIGQUIT - 1].sa_handler == SIG_DFL) + mask |= sigmask(SIGQUIT); + } + siginitmaskinv(¤t->blocked, mask); + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); + fs = get_fs(); set_fs(get_ds()); for (n = 0, timeout = init_timeout;; n++, timeout <<= 1) { @@ -269,7 +276,12 @@ static int do_ncp_rpc_call(struct ncp_server *server, int size) printk(KERN_ERR "NCP: result=%d\n", result); result = -EIO; } + + spin_lock_irqsave(¤t->sigmask_lock, flags); current->blocked = old_mask; + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); + set_fs(fs); return result; } diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 9e1d936dd..c74c73243 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -498,6 +498,12 @@ static int nfs_lookup(struct inode *dir, struct dentry * dentry) error = -EACCES; inode = nfs_fhget(dir->i_sb, &fhandle, &fattr); if (inode) { +#ifdef NFS_PARANOIA +if (inode->i_count > 1) +printk("nfs_lookup: %s/%s ino=%ld in use, count=%d, nlink=%d\n", +dentry->d_parent->d_name.name, dentry->d_name.name, +inode->i_ino, inode->i_count, inode->i_nlink); +#endif no_entry: dentry->d_op = &nfs_dentry_operations; d_add(dentry, inode); @@ -512,14 +518,20 @@ out: /* * Code common to create, mkdir, and mknod. */ -static int nfs_instantiate(struct inode *dir, struct dentry *dentry, - struct nfs_fattr *fattr, struct nfs_fh *fhandle) +static int nfs_instantiate(struct dentry *dentry, struct nfs_fattr *fattr, + struct nfs_fh *fhandle) { struct inode *inode; int error = -EACCES; - inode = nfs_fhget(dir->i_sb, fhandle, fattr); + inode = nfs_fhget(dentry->d_sb, fhandle, fattr); if (inode) { +#ifdef NFS_PARANOIA +if (inode->i_count > 1) +printk("nfs_instantiate: %s/%s ino=%ld in use, count=%d, nlink=%d\n", +dentry->d_parent->d_name.name, dentry->d_name.name, +inode->i_ino, inode->i_count, inode->i_nlink); +#endif d_instantiate(dentry, inode); nfs_renew_times(dentry); error = 0; @@ -563,14 +575,9 @@ static int nfs_create(struct inode *dir, struct dentry * dentry, int mode) error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir), dentry->d_name.name, &sattr, &fhandle, &fattr); if (!error) - error = nfs_instantiate(dir, dentry, &fattr, &fhandle); - else { -#ifdef NFS_PARANOIA -printk("nfs_create: %s/%s failed, error=%d\n", -dentry->d_parent->d_name.name, dentry->d_name.name, error); -#endif + error = nfs_instantiate(dentry, &fattr, &fhandle); + else d_drop(dentry); - } out: return error; } @@ -606,14 +613,9 @@ static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rde error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir), dentry->d_name.name, &sattr, &fhandle, &fattr); if (!error) - error = nfs_instantiate(dir, dentry, &fattr, &fhandle); - else { -#ifdef NFS_PARANOIA -printk("nfs_mknod: %s/%s failed, error=%d\n", -dentry->d_parent->d_name.name, dentry->d_name.name, error); -#endif + error = nfs_instantiate(dentry, &fattr, &fhandle); + else d_drop(dentry); - } return error; } @@ -645,13 +647,22 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) nfs_invalidate_dircache(dir); error = nfs_proc_mkdir(NFS_SERVER(dir), NFS_FH(dir), dentry->d_name.name, &sattr, &fhandle, &fattr); - if (!error) - error = nfs_instantiate(dir, dentry, &fattr, &fhandle); - else { -#ifdef NFS_PARANOIA -printk("nfs_mkdir: %s/%s failed, error=%d\n", -dentry->d_parent->d_name.name, dentry->d_name.name, error); -#endif + if (!error) { + /* + * Some AIX servers reportedly fail to fill out the fattr. + * Check for a bad mode value and complain, then drop the + * dentry to force a new lookup. + */ + if (!S_ISDIR(fattr.mode)) { + static int complain = 0; + if (!complain++) + printk("NFS: buggy server! fattr mode=%x\n", + fattr.mode); + goto drop; + } + error = nfs_instantiate(dentry, &fattr, &fhandle); + } else { + drop: d_drop(dentry); } return error; @@ -662,12 +673,12 @@ dentry->d_parent->d_name.name, dentry->d_name.name, error); * use count prior to the operation, and return EBUSY if it has * multiple users. * - * Update inode->i_nlink immediately after a successful operation. - * (See comments for nfs_unlink.) + * We update inode->i_nlink and free the inode prior to the operation + * to avoid possible races if the server reuses the inode. */ static int nfs_rmdir(struct inode *dir, struct dentry *dentry) { - int error; + int error, rehash = 0; dfprintk(VFS, "NFS: rmdir(%x/%ld, %s\n", dir->i_dev, dir->i_ino, dentry->d_name.name); @@ -688,13 +699,31 @@ static int nfs_rmdir(struct inode *dir, struct dentry *dentry) if (dentry->d_count > 1) goto out; } - /* Drop the dentry to force a new lookup */ - d_drop(dentry); - error = nfs_proc_rmdir(NFS_SERVER(dir), NFS_FH(dir), dentry->d_name.name); +#ifdef NFS_PARANOIA +if (dentry->d_inode->i_count > 1) +printk("nfs_rmdir: %s/%s inode busy?? i_count=%d, i_nlink=%d\n", +dentry->d_parent->d_name.name, dentry->d_name.name, +dentry->d_inode->i_count, dentry->d_inode->i_nlink); +#endif + /* + * Unhash the dentry while we remove the directory. + */ + if (!list_empty(&dentry->d_hash)) { + d_drop(dentry); + rehash = 1; + } + /* + * Update i_nlink and free the inode before unlinking. + */ + if (dentry->d_inode->i_nlink) + dentry->d_inode->i_nlink --; + d_delete(dentry); + nfs_invalidate_dircache(dir); + error = nfs_proc_rmdir(NFS_SERVER(dir), + NFS_FH(dir), dentry->d_name.name); if (!error) { - if (dentry->d_inode->i_nlink) - dentry->d_inode->i_nlink --; - nfs_invalidate_dircache(dir); + if (rehash) + d_add(dentry, NULL); nfs_renew_times(dentry); } out: @@ -867,6 +896,12 @@ dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count); #endif goto out; } +#ifdef NFS_PARANOIA +if (inode && inode->i_count > 1) +printk("nfs_safe_remove: %s/%s inode busy?? i_count=%d, i_nlink=%d\n", +dentry->d_parent->d_name.name, dentry->d_name.name, +inode->i_count, inode->i_nlink); +#endif /* * Unhash the dentry while we remove the file ... */ @@ -874,29 +909,22 @@ dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count); d_drop(dentry); rehash = 1; } - error = nfs_proc_remove(NFS_SERVER(dir), - NFS_FH(dir), dentry->d_name.name); /* - * ... then restore the hashed state. This ensures that the - * dentry can't become busy after having its file deleted. + * Update i_nlink and free the inode before unlinking. */ - if (rehash) { - d_add(dentry, inode); - } -#ifdef NFS_PARANOIA -if (dentry->d_count > 1) -printk("nfs_safe_remove: %s/%s busy after delete?? d_count=%d\n", -dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count); -if (inode && inode->i_count > 1) -printk("nfs_safe_remove: %s/%s inode busy?? i_count=%d\n", -dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_count); -#endif - if (!error) { - nfs_invalidate_dircache(dir); - if (inode && inode->i_nlink) + if (inode) { + if (inode->i_nlink) inode->i_nlink --; d_delete(dentry); } + nfs_invalidate_dircache(dir); + error = nfs_proc_remove(NFS_SERVER(dir), + NFS_FH(dir), dentry->d_name.name); + /* + * Rehash the negative dentry if the operation succeeded. + */ + if (!error && rehash) + d_add(dentry, NULL); out: return error; } @@ -1144,7 +1172,7 @@ do_rename: */ if (!list_empty(&new_dentry->d_hash)) { d_drop(new_dentry); - rehash = 1; + rehash = update; } error = nfs_proc_rename(NFS_SERVER(old_dir), NFS_FH(old_dir), old_dentry->d_name.name, diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 0f3bd5ed3..7b53bc8ef 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -113,7 +113,8 @@ nfs_file_read(struct file * file, char * buf, size_t count, loff_t *ppos) ssize_t result; dfprintk(VFS, "nfs: read(%x/%ld, %lu@%lu)\n", - inode->i_dev, inode->i_ino, count, + inode->i_dev, inode->i_ino, + (unsigned long) count, (unsigned long) *ppos); result = nfs_revalidate_inode(NFS_SERVER(inode), inode); @@ -167,7 +168,7 @@ nfs_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos) dfprintk(VFS, "nfs: write(%x/%ld (%d), %lu@%lu)\n", inode->i_dev, inode->i_ino, inode->i_count, - count, (unsigned long) *ppos); + (unsigned long) count, (unsigned long) *ppos); if (!inode) { printk("nfs_file_write: inode = NULL\n"); diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index 3b06d4c36..b7c7dfba7 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c @@ -229,7 +229,7 @@ __initfunc(static int root_dev_chg_route(int op, struct device *dev, __u32 dest, __u32 mask, __u32 gw)) { struct rtentry route; - unsigned long oldfs; + mm_segment_t oldfs; int err; memset(&route, 0, sizeof(struct rtentry)); /* or else! */ @@ -608,7 +608,7 @@ root_bind_udp_sock(struct socket *sock, u32 addr, u16 port)) */ static inline int root_send_udp(struct socket *sock, void *buf, int size) { - u32 oldfs; + mm_segment_t oldfs; int result; struct msghdr msg; struct iovec iov; @@ -632,7 +632,7 @@ static inline int root_send_udp(struct socket *sock, void *buf, int size) */ static inline int root_recv_udp(struct socket *sock, void *buf, int size) { - u32 oldfs; + mm_segment_t oldfs; int result; struct msghdr msg; struct iovec iov; diff --git a/fs/nfsd/lockd.c b/fs/nfsd/lockd.c index 6e161d62b..ccca2cc7c 100644 --- a/fs/nfsd/lockd.c +++ b/fs/nfsd/lockd.c @@ -16,6 +16,9 @@ #define NFSDDBG_FACILITY NFSDDBG_LOCKD +/* + * Note: we hold the dentry use count while the file is open. + */ static u32 nlm_fopen(struct svc_rqst *rqstp, struct knfs_fh *f, struct file *filp) { @@ -27,6 +30,8 @@ nlm_fopen(struct svc_rqst *rqstp, struct knfs_fh *f, struct file *filp) fh.fh_dverified = 0; nfserr = nfsd_open(rqstp, &fh, S_IFREG, 0, filp); + if (!nfserr) + dget(filp->f_dentry); fh_put(&fh); return nfserr; } @@ -35,6 +40,7 @@ static void nlm_fclose(struct file *filp) { nfsd_close(filp); + dput(filp->f_dentry); } struct nlmsvc_binding nfsd_nlm_ops = { diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index 84d296834..051061add 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -35,9 +35,9 @@ #define NFSDDBG_FACILITY NFSDDBG_SVC #define NFSD_BUFSIZE (1024 + NFSSVC_MAXBLKSIZE) -#define BLOCKABLE_SIGS (~(_S(SIGKILL) | _S(SIGSTOP))) -#define SHUTDOWN_SIGS (_S(SIGKILL)|_S(SIGINT)|_S(SIGTERM)) -#define _S(sig) (1 << ((sig) - 1)) + +#define BLOCKABLE_SIGS (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) +#define SHUTDOWN_SIGS (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM)) extern struct svc_program nfsd_program; static void nfsd(struct svc_rqst *rqstp); @@ -96,7 +96,6 @@ static void nfsd(struct svc_rqst *rqstp) { struct svc_serv *serv = rqstp->rq_server; - sigset_t oldsigmask; int oldumask, err; lock_kernel(); @@ -108,7 +107,7 @@ nfsd(struct svc_rqst *rqstp) sprintf(current->comm, "nfsd"); oldumask = current->fs->umask; /* Set umask to 0. */ - current->blocked |= ~SHUTDOWN_SIGS; + siginitsetinv(¤t->blocked, SHUTDOWN_SIGS); current->fs->umask = 0; nfssvc_boot = xtime; /* record boot time */ lockd_up(); /* start lockd */ @@ -142,10 +141,17 @@ nfsd(struct svc_rqst *rqstp) serv->sv_stats->rpcbadclnt++; } else { /* Process request with all signals blocked. */ - oldsigmask = current->blocked; - current->blocked = BLOCKABLE_SIGS; + spin_lock_irq(¤t->sigmask_lock); + siginitsetinv(¤t->blocked, ~BLOCKABLE_SIGS); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); + svc_process(serv, rqstp); - current->blocked = oldsigmask; + + spin_lock_irq(¤t->sigmask_lock); + siginitsetinv(¤t->blocked, SHUTDOWN_SIGS); + recalc_sigpending(current); + spin_unlock_irq(¤t->sigmask_lock); } /* Unlock export hash tables */ @@ -157,8 +163,9 @@ nfsd(struct svc_rqst *rqstp) } else { unsigned int signo; - for (signo = 0; signo < 32; signo++) - if (current->signal & current->blocked & (1<<signo)) + for (signo = 1; signo <= _NSIG; signo++) + if (sigismember(¤t->signal, signo) && + !sigismember(¤t->blocked, signo)) break; printk(KERN_WARNING "nfsd: terminating on signal %d\n", signo); } diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 4579cddec..81b9a3f79 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -240,24 +240,24 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access, err; access = wflag? MAY_WRITE : MAY_READ; - if ((err = fh_verify(rqstp, fhp, type, access)) != 0) + err = fh_verify(rqstp, fhp, type, access); + if (err) goto out; dentry = fhp->fh_dentry; inode = dentry->d_inode; /* Disallow access to files with the append-only bit set or - * with mandatory locking enabled */ + * with mandatory locking enabled + */ err = nfserr_perm; if (IS_APPEND(inode) || IS_ISMNDLK(inode)) goto out; if (!inode->i_op || !inode->i_op->default_file_ops) goto out; - if (wflag && (err = get_write_access(inode)) != 0) { - err = nfserrno(-err); - goto out; - } + if (wflag && (err = get_write_access(inode)) != 0) + goto out_nfserr; memset(filp, 0, sizeof(*filp)); filp->f_op = inode->i_op->default_file_ops; @@ -267,7 +267,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, filp->f_dentry = dentry; err = 0; - if (filp->f_op->open) { + if (filp->f_op && filp->f_op->open) { err = filp->f_op->open(inode, filp); if (err) { if (wflag) @@ -277,9 +277,11 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, * is really on callers stack frame. -DaveM */ filp->f_count--; - err = nfserrno(-err); } } +out_nfserr: + if (err) + err = nfserrno(-err); out: return err; } @@ -360,7 +362,7 @@ nfsd_read(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, char *buf, struct dentry *dentry; struct inode *inode; struct file file; - unsigned long oldfs; + mm_segment_t oldfs; int err; if ((err = nfsd_open(rqstp, fhp, S_IFREG, OPEN_READ, &file)) != 0) @@ -420,7 +422,7 @@ nfsd_write(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, struct file file; struct dentry *dentry; struct inode *inode; - unsigned long oldfs; + mm_segment_t oldfs; int err; if (!cnt) @@ -633,14 +635,16 @@ nfsd_truncate(struct svc_rqst *rqstp, struct svc_fh *fhp, unsigned long size) struct iattr newattrs; int err; - if ((err = fh_verify(rqstp, fhp, S_IFREG, MAY_WRITE|MAY_TRUNC)) != 0) - return err; + err = fh_verify(rqstp, fhp, S_IFREG, MAY_WRITE | MAY_TRUNC); + if (err) + goto out; dentry = fhp->fh_dentry; inode = dentry->d_inode; - if ((err = get_write_access(inode)) != 0) - goto out; + err = get_write_access(inode); + if (err) + goto out_nfserr; /* Things look sane, lock and do it. */ fh_lock(fhp); @@ -654,8 +658,11 @@ nfsd_truncate(struct svc_rqst *rqstp, struct svc_fh *fhp, unsigned long size) } put_write_access(inode); fh_unlock(fhp); +out_nfserr: + if (err) + err = nfserrno(-err); out: - return (err ? nfserrno(-err) : 0); + return err; } /* @@ -668,10 +675,11 @@ nfsd_readlink(struct svc_rqst *rqstp, struct svc_fh *fhp, char *buf, int *lenp) { struct dentry *dentry; struct inode *inode; - unsigned long oldfs; + mm_segment_t oldfs; int err; - if ((err = fh_verify(rqstp, fhp, S_IFLNK, MAY_READ)) != 0) + err = fh_verify(rqstp, fhp, S_IFLNK, MAY_READ); + if (err) goto out; dentry = fhp->fh_dentry; @@ -715,7 +723,8 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp, if (!flen || !plen) goto out; - if ((err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE)) != 0) + err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE); + if (err) goto out; dentry = fhp->fh_dentry; @@ -762,17 +771,20 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, struct inode *dirp, *dest; int err; - if ((err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_CREATE) != 0) || - (err = fh_verify(rqstp, tfhp, S_IFREG, MAY_NOP)) != 0) - return err; + err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_CREATE); + if (err) + goto out; + err = fh_verify(rqstp, tfhp, S_IFREG, MAY_NOP); + if (err) + goto out; ddir = ffhp->fh_dentry; dirp = ddir->d_inode; - dnew = lookup_dentry(fname, dget(ddir), 1); + dnew = lookup_dentry(fname, dget(ddir), 0); err = PTR_ERR(dnew); if (IS_ERR(dnew)) - return nfserrno(-err); + goto out_nfserr; err = -EEXIST; if (dnew->d_inode) @@ -805,7 +817,11 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp, } dput_and_out: dput(dnew); - return (err ? nfserrno(-err) : 0); +out_nfserr: + if (err) + err = nfserrno(-err); +out: + return err; } /* More "hidden treasure" from the generic VFS. -DaveM */ @@ -836,9 +852,12 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, struct inode *fdir, *tdir; int err; - if ((err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_REMOVE) != 0) - || (err = fh_verify(rqstp, tfhp, S_IFDIR, MAY_CREATE)) != 0) - return err; + err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_REMOVE); + if (err) + goto out; + err = fh_verify(rqstp, tfhp, S_IFDIR, MAY_CREATE); + if (err) + goto out; fdentry = ffhp->fh_dentry; fdir = fdentry->d_inode; @@ -846,18 +865,19 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen, tdentry = tfhp->fh_dentry; tdir = tdentry->d_inode; + /* N.B. We shouldn't need this ... dentry layer handles it */ if (!flen || (fname[0] == '.' && (flen == 1 || (flen == 2 && fname[1] == '.'))) || !tlen || (tname[0] == '.' && (tlen == 1 || (tlen == 2 && tname[1] == '.')))) return nfserr_perm; - odentry = lookup_dentry(fname, dget(fdentry), 1); + odentry = lookup_dentry(fname, dget(fdentry), 0); err = PTR_ERR(odentry); if (IS_ERR(odentry)) goto out_no_unlock; - ndentry = lookup_dentry(tname, dget(tdentry), 1); + ndentry = lookup_dentry(tname, dget(tdentry), 0); err = PTR_ERR(ndentry); if (IS_ERR(ndentry)) goto out_dput_old; @@ -883,7 +903,10 @@ out_unlock: out_dput_old: dput(odentry); out_no_unlock: - return (err ? nfserrno(-err) : 0); + if (err) + err = nfserrno(-err); +out: + return err; } /* @@ -898,10 +921,13 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, struct inode *dirp; int err; + /* N.B. We shouldn't need this test ... handled by dentry layer */ + err = nfserr_acces; if (!flen || isdotent(fname, flen)) - return nfserr_acces; - if ((err = fh_verify(rqstp, fhp, S_IFDIR, MAY_REMOVE)) != 0) - return err; + goto out; + err = fh_verify(rqstp, fhp, S_IFDIR, MAY_REMOVE); + if (err) + goto out; dentry = fhp->fh_dentry; dirp = dentry->d_inode; @@ -909,7 +935,7 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, rdentry = lookup_dentry(fname, dget(dentry), 0); err = PTR_ERR(rdentry); if (IS_ERR(rdentry)) - goto out; + goto out_nfserr; fh_lock(fhp); if (type == S_IFDIR) { @@ -926,8 +952,12 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, dput(rdentry); if (!err && EX_ISSYNC(fhp->fh_export)) write_inode_now(dirp); + +out_nfserr: + if (err) + err = nfserrno(-err); out: - return (err ? nfserrno(-err) : 0); + return err; } /* @@ -1019,7 +1049,7 @@ nfsd_statfs(struct svc_rqst *rqstp, struct svc_fh *fhp, struct statfs *stat) struct dentry *dentry; struct inode *inode; struct super_block *sb; - unsigned long oldfs; + mm_segment_t oldfs; int err; err = fh_verify(rqstp, fhp, 0, MAY_NOP); @@ -12,8 +12,8 @@ #include <linux/termios.h> #include <linux/mm.h> #include <linux/file.h> +#include <linux/poll.h> -#include <asm/poll.h> #include <asm/uaccess.h> /* diff --git a/fs/proc/array.c b/fs/proc/array.c index 4e22dfa16..88d10d2bc 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -48,6 +48,7 @@ #include <linux/swap.h> #include <linux/slab.h> #include <linux/smp.h> +#include <linux/signal.h> #include <asm/uaccess.h> #include <asm/pgtable.h> @@ -664,37 +665,60 @@ static inline char * task_mem(struct task_struct *p, char *buffer) return buffer; } -static inline char * task_sig(struct task_struct *p, char *buffer) +char * render_sigset_t(sigset_t *set, char *buffer) { - buffer += sprintf(buffer, - "SigPnd:\t%08lx\n" - "SigBlk:\t%08lx\n", - p->signal, p->blocked); + int i = _NSIG, x; + do { + i -= 4, x = 0; + if (sigismember(set, i+1)) x |= 1; + if (sigismember(set, i+2)) x |= 2; + if (sigismember(set, i+3)) x |= 4; + if (sigismember(set, i+4)) x |= 8; + *buffer++ = (x < 10 ? '0' : 'a' - 10) + x; + } while (i >= 4); + *buffer = 0; + return buffer; +} + +static void collect_sigign_sigcatch(struct task_struct *p, sigset_t *ign, + sigset_t *catch) +{ + struct k_sigaction *k; + int i; + + sigemptyset(ign); + sigemptyset(catch); + if (p->sig) { - struct sigaction * action = p->sig->action; - unsigned long sig_ign = 0, sig_caught = 0; - unsigned long bit = 1; - int i; - - for (i = 0; i < 32; i++) { - switch((unsigned long) action->sa_handler) { - case 0: - break; - case 1: - sig_ign |= bit; - break; - default: - sig_caught |= bit; - } - bit <<= 1; - action++; + k = p->sig->action; + for (i = 1; i <= _NSIG; ++i, ++k) { + if (k->sa.sa_handler == SIG_IGN) + sigaddset(ign, i); + else if (k->sa.sa_handler != SIG_DFL) + sigaddset(catch, i); } - - buffer += sprintf(buffer, - "SigIgn:\t%08lx\n" - "SigCgt:\t%08lx\n", - sig_ign, sig_caught); } +} + +static inline char * task_sig(struct task_struct *p, char *buffer) +{ + sigset_t ign, catch; + + buffer += sprintf(buffer, "SigPnd:\t"); + buffer = render_sigset_t(&p->signal, buffer); + *buffer++ = '\n'; + buffer += sprintf(buffer, "SigBlk:\t"); + buffer = render_sigset_t(&p->blocked, buffer); + *buffer++ = '\n'; + + collect_sigign_sigcatch(p, &ign, &catch); + buffer += sprintf(buffer, "SigIgn:\t"); + buffer = render_sigset_t(&ign, buffer); + *buffer++ = '\n'; + buffer += sprintf(buffer, "SigCat:\t"); + buffer = render_sigset_t(&catch, buffer); + *buffer++ = '\n'; + return buffer; } @@ -715,10 +739,14 @@ static int get_status(int pid, char * buffer) static int get_stat(int pid, char * buffer) { struct task_struct *tsk = find_task_by_pid(pid); - unsigned long sigignore=0, sigcatch=0, wchan; - unsigned long vsize, eip, esp; + unsigned long vsize, eip, esp, wchan; long priority, nice; - int i,tty_pgrp; + int tty_pgrp; + sigset_t sigign, sigcatch; + char signal_str[sizeof(sigset_t)*2+1]; + char blocked_str[sizeof(sigset_t)*2+1]; + char sigign_str[sizeof(sigset_t)*2+1]; + char sigcatch_str[sizeof(sigset_t)*2+1]; char state; if (!tsk) @@ -737,22 +765,15 @@ static int get_stat(int pid, char * buffer) eip = KSTK_EIP(tsk); esp = KSTK_ESP(tsk); } + wchan = get_wchan(tsk); - if (tsk->sig) { - unsigned long bit = 1; - for(i=0; i<32; ++i) { - switch((unsigned long) tsk->sig->action[i].sa_handler) { - case 0: - break; - case 1: - sigignore |= bit; - break; - default: - sigcatch |= bit; - } - bit <<= 1; - } - } + + collect_sigign_sigcatch(tsk, &sigign, &sigcatch); + render_sigset_t(&tsk->signal, signal_str); + render_sigset_t(&tsk->blocked, blocked_str); + render_sigset_t(&sigign, sigign_str); + render_sigset_t(&sigcatch, sigcatch_str); + if (tsk->tty) tty_pgrp = tsk->tty->pgrp; else @@ -767,7 +788,7 @@ static int get_stat(int pid, char * buffer) return sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \ %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \ -%lu %lu %lu %lu %lu %lu %lu %lu\n", +%lu %s %s %s %s %lu %lu %lu\n", pid, tsk->comm, state, @@ -798,10 +819,10 @@ static int get_stat(int pid, char * buffer) tsk->mm ? tsk->mm->start_stack : 0, esp, eip, - tsk->signal, - tsk->blocked, - sigignore, - sigcatch, + signal_str, + blocked_str, + sigign_str, + sigcatch_str, wchan, tsk->nswap, tsk->cnswap); diff --git a/fs/proc/proc_tty.c b/fs/proc/proc_tty.c index 470b7bffb..9523ff9f0 100644 --- a/fs/proc/proc_tty.c +++ b/fs/proc/proc_tty.c @@ -49,8 +49,10 @@ static int tty_drivers_read_proc(char *page, char **start, off_t off, case TTY_DRIVER_TYPE_SYSTEM: if (p->subtype == SYSTEM_TYPE_TTY) type = "system:/dev/tty"; - else if (p->subtype == SYSTEM_TYPE_CONSOLE) + else if (p->subtype == SYSTEM_TYPE_SYSCONS) type = "system:console"; + else if (p->subtype == SYSTEM_TYPE_CONSOLE) + type = "system:vtmaster"; else type = "system"; break; diff --git a/fs/select.c b/fs/select.c index d804d58b3..4c88f0437 100644 --- a/fs/select.c +++ b/fs/select.c @@ -24,10 +24,10 @@ #include <linux/malloc.h> #include <linux/smp.h> #include <linux/smp_lock.h> +#include <linux/poll.h> #include <asm/uaccess.h> #include <asm/system.h> -#include <asm/poll.h> #define ROUND_UP(x,y) (((x)+(y)-1)/(y)) #define DEFAULT_POLLMASK (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM) @@ -39,9 +39,10 @@ * understand what I'm doing here, then you understand how the linux * sleep/wakeup mechanism works. * - * Two very simple procedures, poll_wait() and free_wait() make all the work. - * poll_wait() is an inline-function defined in <linux/sched.h>, as all select/poll - * functions have to call it to add an entry to the poll table. + * Two very simple procedures, poll_wait() and free_wait() make all the + * work. poll_wait() is an inline-function defined in <linux/sched.h>, + * as all select/poll functions have to call it to add an entry to the + * poll table. */ /* @@ -61,26 +62,6 @@ static void free_wait(poll_table * p) } } -/* - * For the kernel fd_set we use a fixed set-size for allocation purposes. - * This set-size doesn't necessarily bear any relation to the size the user - * uses, but should preferably obviously be larger than any possible user - * size (NR_OPEN bits). - * - * We need 6 bitmaps (in/out/ex for both incoming and outgoing), and we - * allocate one page for all the bitmaps. Thus we have 8*PAGE_SIZE bits, - * to be divided by 6. And we'd better make sure we round to a full - * long-word (in fact, we'll round to 64 bytes). - */ -#define KFDS_64BLOCK ((PAGE_SIZE/(6*64))*64) -#define KFDS_NR (KFDS_64BLOCK*8 > NR_OPEN ? NR_OPEN : KFDS_64BLOCK*8) -typedef unsigned long kernel_fd_set[KFDS_NR/(8*sizeof(unsigned long))]; - -typedef struct { - kernel_fd_set in, out, ex; - kernel_fd_set res_in, res_out, res_ex; -} fd_set_buffer; - #define __IN(in) (in) #define __OUT(in) (in + sizeof(kernel_fd_set)/sizeof(unsigned long)) #define __EX(in) (in + 2*sizeof(kernel_fd_set)/sizeof(unsigned long)) @@ -141,11 +122,28 @@ get_max: #define POLLOUT_SET (POLLWRBAND | POLLWRNORM | POLLOUT | POLLERR) #define POLLEX_SET (POLLPRI) -static int do_select(int n, fd_set_buffer *fds, poll_table *wait) +int do_select(int n, fd_set_buffer *fds, unsigned long timeout) { + poll_table wait_table, *wait; int retval; int i; + lock_kernel(); + + wait = NULL; + current->timeout = timeout; + if (timeout) { + struct poll_table_entry *entry = (struct poll_table_entry *) + __get_free_page(GFP_KERNEL); + if (!entry) { + retval = -ENOMEM; + goto out_nowait; + } + wait_table.nr = 0; + wait_table.entry = entry; + wait = &wait_table; + } + retval = max_select_fd(n, fds); if (retval < 0) goto out; @@ -154,33 +152,36 @@ static int do_select(int n, fd_set_buffer *fds, poll_table *wait) for (;;) { struct file ** fd = current->files->fd; current->state = TASK_INTERRUPTIBLE; - for (i = 0 ; i < n ; i++,fd++) { + for (i = 0 ; i < n ; i++, fd++) { unsigned long bit = BIT(i); unsigned long *in = MEM(i,fds->in); + unsigned long mask; + struct file *file; - if (bit & BITS(in)) { - struct file * file = *fd; - unsigned int mask = POLLNVAL; - if (file) { - mask = DEFAULT_POLLMASK; - if (file->f_op && file->f_op->poll) - mask = file->f_op->poll(file, wait); - } - if ((mask & POLLIN_SET) && ISSET(bit, __IN(in))) { - SET(bit, __RES_IN(in)); - retval++; - wait = NULL; - } - if ((mask & POLLOUT_SET) && ISSET(bit, __OUT(in))) { - SET(bit, __RES_OUT(in)); - retval++; - wait = NULL; - } - if ((mask & POLLEX_SET) && ISSET(bit, __EX(in))) { - SET(bit, __RES_EX(in)); - retval++; - wait = NULL; - } + if (!(bit & BITS(in))) + continue; + + file = *fd; + mask = POLLNVAL; + if (file) { + mask = DEFAULT_POLLMASK; + if (file->f_op && file->f_op->poll) + mask = file->f_op->poll(file, wait); + } + if ((mask & POLLIN_SET) && ISSET(bit, __IN(in))) { + SET(bit, __RES_IN(in)); + retval++; + wait = NULL; + } + if ((mask & POLLOUT_SET) && ISSET(bit, __OUT(in))) { + SET(bit, __RES_OUT(in)); + retval++; + wait = NULL; + } + if ((mask & POLLEX_SET) && ISSET(bit, __EX(in))) { + SET(bit, __RES_EX(in)); + retval++; + wait = NULL; } } wait = NULL; @@ -189,82 +190,18 @@ static int do_select(int n, fd_set_buffer *fds, poll_table *wait) schedule(); } current->state = TASK_RUNNING; -out: - return retval; -} - -/* - * We do a VERIFY_WRITE here even though we are only reading this time: - * we'll write to it eventually.. - * - * Use "unsigned long" accesses to let user-mode fd_set's be long-aligned. - */ -static int __get_fd_set(unsigned long nr, unsigned long * fs_pointer, unsigned long * fdset) -{ - /* round up nr to nearest "unsigned long" */ - nr = (nr + 8*sizeof(unsigned long)-1) / (8*sizeof(unsigned long)); - if (fs_pointer) { - int error = verify_area(VERIFY_WRITE,fs_pointer, - nr*sizeof(unsigned long)); - if (!error) { - while (nr) { - __get_user(*fdset, fs_pointer); - nr--; - fs_pointer++; - fdset++; - } - } - return error; - } - while (nr) { - *fdset = 0; - nr--; - fdset++; - } - return 0; -} -static void __set_fd_set(long nr, unsigned long * fs_pointer, unsigned long * fdset) -{ - if (!fs_pointer) - return; - while (nr >= 0) { - __put_user(*fdset, fs_pointer); - nr -= 8 * sizeof(unsigned long); - fdset++; - fs_pointer++; +out: + if (timeout) { + free_wait(&wait_table); + free_page((unsigned long) wait_table.entry); } +out_nowait: + current->timeout = 0; + unlock_kernel(); + return retval; } -/* We can do long accesses here, kernel fdsets are always long-aligned */ -static inline void __zero_fd_set(long nr, unsigned long * fdset) -{ - while (nr >= 0) { - *fdset = 0; - nr -= 8 * sizeof(unsigned long); - fdset++; - } -} - -/* - * Note a few subtleties: we use "long" for the dummy, not int, and we do a - * subtract by 1 on the nr of file descriptors. The former is better for - * machines with long > int, and the latter allows us to test the bit count - * against "zero or positive", which can mostly be just a sign bit test.. - * - * Unfortunately this scheme falls apart on big endian machines where - * sizeof(long) > sizeof(int) (ie. V9 Sparc). -DaveM - */ - -#define get_fd_set(nr,fsp,fdp) \ -__get_fd_set(nr, (unsigned long *) (fsp), (unsigned long *) (fdp)) - -#define set_fd_set(nr,fsp,fdp) \ -__set_fd_set((nr)-1, (unsigned long *) (fsp), (unsigned long *) (fdp)) - -#define zero_fd_set(nr,fdp) \ -__zero_fd_set((nr)-1, (unsigned long *) (fdp)) - /* * We can actually return ERESTARTSYS instead of EINTR, but I'd * like to be certain this leads to no problems. So I return @@ -273,64 +210,50 @@ __zero_fd_set((nr)-1, (unsigned long *) (fdp)) * Update: ERESTARTSYS breaks at least the xview clock binary, so * I'm trying ERESTARTNOHAND which restart only when you want to. */ -asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp) +asmlinkage int +sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct timeval *tvp) { - int error; fd_set_buffer *fds; unsigned long timeout; - poll_table wait_table, *wait; + int ret; - lock_kernel(); timeout = ~0UL; if (tvp) { - error = -EFAULT; - if (!access_ok(VERIFY_WRITE, tvp, sizeof(*tvp))) - goto out_nowait; - error = __get_user(timeout, &tvp->tv_usec); - if (error) - goto out_nowait; - timeout = ROUND_UP(timeout,(1000000/HZ)); - { - unsigned long tmp; - error = __get_user(tmp, &tvp->tv_sec); - if (error) - goto out_nowait; - timeout += tmp * (unsigned long) HZ; - } + time_t sec, usec; + + if ((ret = verify_area(VERIFY_READ, tvp, sizeof(*tvp))) + || (ret = __get_user(sec, &tvp->tv_sec)) + || (ret = __get_user(usec, &tvp->tv_usec))) + goto out_nofds; + + timeout = ROUND_UP(usec, 1000000/HZ); + timeout += sec * (unsigned long) HZ; if (timeout) timeout += jiffies + 1; } - error = -ENOMEM; - wait = NULL; - current->timeout = timeout; - if (timeout) { - struct poll_table_entry *entry; - entry = (struct poll_table_entry *) __get_free_page(GFP_KERNEL); - if (!entry) - goto out_nowait; - wait_table.nr = 0; - wait_table.entry = entry; - wait = &wait_table; - } + ret = -ENOMEM; fds = (fd_set_buffer *) __get_free_page(GFP_KERNEL); if (!fds) goto out_nofds; - error = -EINVAL; + ret = -EINVAL; if (n < 0) goto out; if (n > KFDS_NR) n = KFDS_NR; - if ((error = get_fd_set(n, inp, &fds->in)) || - (error = get_fd_set(n, outp, &fds->out)) || - (error = get_fd_set(n, exp, &fds->ex))) goto out; - zero_fd_set(n, &fds->res_in); - zero_fd_set(n, &fds->res_out); - zero_fd_set(n, &fds->res_ex); - error = do_select(n, fds, wait); + if ((ret = get_fd_set(n, inp, fds->in)) || + (ret = get_fd_set(n, outp, fds->out)) || + (ret = get_fd_set(n, exp, fds->ex))) + goto out; + zero_fd_set(n, fds->res_in); + zero_fd_set(n, fds->res_out); + zero_fd_set(n, fds->res_ex); + + ret = do_select(n, fds, timeout); + if (tvp && !(current->personality & STICKY_TIMEOUTS)) { unsigned long timeout = current->timeout - jiffies - 1; - unsigned long sec = 0, usec = 0; + time_t sec = 0, usec = 0; if ((long) timeout > 0) { sec = timeout / HZ; usec = timeout % HZ; @@ -340,27 +263,24 @@ asmlinkage int sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, struct put_user(usec, &tvp->tv_usec); } current->timeout = 0; - if (error < 0) + + if (ret < 0) goto out; - if (!error) { - error = -ERESTARTNOHAND; + if (!ret) { + ret = -ERESTARTNOHAND; if (signal_pending(current)) goto out; - error = 0; + ret = 0; } - set_fd_set(n, inp, &fds->res_in); - set_fd_set(n, outp, &fds->res_out); - set_fd_set(n, exp, &fds->res_ex); + + set_fd_set(n, inp, fds->res_in); + set_fd_set(n, outp, fds->res_out); + set_fd_set(n, exp, fds->res_ex); + out: free_page((unsigned long) fds); out_nofds: - if (wait) { - free_wait(&wait_table); - free_page((unsigned long) wait->entry); - } -out_nowait: - unlock_kernel(); - return error; + return ret; } static int do_poll(unsigned int nfds, struct pollfd *fds, poll_table *wait) diff --git a/fs/smbfs/sock.c b/fs/smbfs/sock.c index f14836199..45a0790fc 100644 --- a/fs/smbfs/sock.c +++ b/fs/smbfs/sock.c @@ -26,8 +26,6 @@ #define SMBFS_PARANOIA 1 /* #define SMBFS_DEBUG_VERBOSE 1 */ -#define _S(nr) (1<<((nr)-1)) - static int _recvfrom(struct socket *socket, unsigned char *ubuf, int size, unsigned flags) @@ -89,7 +87,7 @@ smb_data_callback(struct sock *sk, int len) struct socket *socket = sk->socket; unsigned char peek_buf[4]; int result; - unsigned long fs; + mm_segment_t fs; fs = get_fs(); set_fs(get_ds()); @@ -324,7 +322,7 @@ smb_get_length(struct socket *socket, unsigned char *header) { int result; unsigned char peek_buf[4]; - unsigned long fs; + mm_segment_t fs; re_recv: fs = get_fs(); @@ -599,8 +597,9 @@ out_error: int smb_request(struct smb_sb_info *server) { - unsigned long old_mask; - unsigned long fs; + unsigned long flags, sigpipe; + mm_segment_t fs; + sigset_t old_set; int len, result; unsigned char *buffer; @@ -619,8 +618,13 @@ smb_request(struct smb_sb_info *server) len = smb_len(buffer) + 4; pr_debug("smb_request: len = %d cmd = 0x%X\n", len, buffer[8]); - old_mask = current->blocked; - current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP)); + spin_lock_irqsave(¤t->sigmask_lock, flags); + sigpipe = sigismember(¤t->signal, SIGPIPE); + old_set = current->blocked; + siginitsetinv(¤t->blocked, sigmask(SIGKILL)|sigmask(SIGSTOP)); + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); + fs = get_fs(); set_fs(get_ds()); @@ -629,9 +633,15 @@ smb_request(struct smb_sb_info *server) { result = smb_receive(server); } + /* read/write errors are handled by errno */ - current->signal &= ~_S(SIGPIPE); - current->blocked = old_mask; + spin_lock_irqsave(¤t->sigmask_lock, flags); + if (result == -EPIPE && !sigpipe) + sigdelset(¤t->signal, SIGPIPE); + current->blocked = old_set; + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); + set_fs(fs); if (result >= 0) @@ -758,8 +768,9 @@ smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command, int *lrdata, unsigned char **rdata, int *lrparam, unsigned char **rparam) { - unsigned long old_mask; - unsigned long fs; + sigset_t old_set; + unsigned long flags, sigpipe; + mm_segment_t fs; int result; pr_debug("smb_trans2_request: com=%d, ld=%d, lp=%d\n", @@ -778,8 +789,13 @@ smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command, if ((result = smb_dont_catch_keepalive(server)) != 0) goto bad_conn; - old_mask = current->blocked; - current->blocked |= ~(_S(SIGKILL) | _S(SIGSTOP)); + spin_lock_irqsave(¤t->sigmask_lock, flags); + sigpipe = sigismember(¤t->signal, SIGPIPE); + old_set = current->blocked; + siginitsetinv(¤t->blocked, sigmask(SIGKILL)|sigmask(SIGSTOP)); + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); + fs = get_fs(); set_fs(get_ds()); @@ -790,9 +806,15 @@ smb_trans2_request(struct smb_sb_info *server, __u16 trans2_command, result = smb_receive_trans2(server, lrdata, rdata, lrparam, rparam); } + /* read/write errors are handled by errno */ - current->signal &= ~_S(SIGPIPE); - current->blocked = old_mask; + spin_lock_irqsave(¤t->sigmask_lock, flags); + if (result == -EPIPE && !sigpipe) + sigdelset(¤t->signal, SIGPIPE); + current->blocked = old_set; + recalc_sigpending(current); + spin_unlock_irqrestore(¤t->sigmask_lock, flags); + set_fs(fs); if (result >= 0) diff --git a/fs/super.c b/fs/super.c index b9e40e385..22c26a07e 100644 --- a/fs/super.c +++ b/fs/super.c @@ -461,7 +461,7 @@ asmlinkage int sys_ustat(dev_t dev, struct ustat * ubuf) struct super_block *s; struct ustat tmp; struct statfs sbuf; - unsigned long old_fs; + mm_segment_t old_fs; int err = -EINVAL; lock_kernel(); diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c index b3586b58f..bb8828efa 100644 --- a/fs/sysv/namei.c +++ b/fs/sysv/namei.c @@ -10,6 +10,11 @@ * sysv/namei.c * Copyright (C) 1993 Bruno Haible */ +/* + 7 Dec 1997 - updated to use dentries by Krzysztof G. Baranowski + <kgb@manjak.knm.org.pl> + */ + #include <linux/sched.h> #include <linux/kernel.h> @@ -100,31 +105,29 @@ static struct buffer_head * sysv_find_entry(struct inode * dir, return NULL; } -int sysv_lookup(struct inode * dir,const char * name, int len, - struct inode ** result) +int sysv_lookup(struct inode * dir, struct dentry * dentry) { int ino; + struct inode * inode = NULL; struct sysv_dir_entry * de; struct buffer_head * bh; - *result = NULL; if (!dir) return -ENOENT; if (!S_ISDIR(dir->i_mode)) { - iput(dir); return -ENOENT; } - if (!(bh = sysv_find_entry(dir,name,len,&de))) { - iput(dir); + if (!(bh = sysv_find_entry(dir, dentry->d_name.name, + dentry->d_name.len, &de))) { return -ENOENT; } ino = de->inode; brelse(bh); - if (!(*result = iget(dir->i_sb,ino))) { - iput(dir); + inode = iget(dir->i_sb,ino); + + if (!inode) return -EACCES; - } - iput(dir); + d_add(dentry, inode); return 0; } @@ -201,42 +204,37 @@ static int sysv_add_entry(struct inode * dir, return 0; } -int sysv_create(struct inode * dir,const char * name, int len, int mode, - struct inode ** result) +int sysv_create(struct inode * dir, struct dentry * dentry, int mode) { int error; struct inode * inode; struct buffer_head * bh; struct sysv_dir_entry * de; - *result = NULL; if (!dir) return -ENOENT; inode = sysv_new_inode(dir); - if (!inode) { - iput(dir); + if (!inode) return -ENOSPC; - } inode->i_op = &sysv_file_inode_operations; inode->i_mode = mode; mark_inode_dirty(inode); - error = sysv_add_entry(dir,name,len, &bh ,&de); + error = sysv_add_entry(dir,dentry->d_name.name, + dentry->d_name.len, &bh, &de); if (error) { inode->i_nlink--; mark_inode_dirty(inode); iput(inode); - iput(dir); return error; } de->inode = inode->i_ino; mark_buffer_dirty(bh, 1); brelse(bh); - iput(dir); - *result = inode; + d_instantiate(dentry, inode); return 0; } -int sysv_mknod(struct inode * dir, const char * name, int len, int mode, int rdev) +int sysv_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev) { int error; struct inode * inode; @@ -245,17 +243,15 @@ int sysv_mknod(struct inode * dir, const char * name, int len, int mode, int rde if (!dir) return -ENOENT; - bh = sysv_find_entry(dir,name,len,&de); + bh = sysv_find_entry(dir,dentry->d_name.name, + dentry->d_name.len,&de); if (bh) { brelse(bh); - iput(dir); return -EEXIST; } inode = sysv_new_inode(dir); - if (!inode) { - iput(dir); + if (!inode) return -ENOSPC; - } inode->i_uid = current->fsuid; inode->i_mode = mode; inode->i_op = NULL; @@ -277,53 +273,45 @@ int sysv_mknod(struct inode * dir, const char * name, int len, int mode, int rde if (S_ISBLK(mode) || S_ISCHR(mode)) inode->i_rdev = to_kdev_t(rdev); mark_inode_dirty(inode); - error = sysv_add_entry(dir, name, len, &bh, &de); + error = sysv_add_entry(dir, dentry->d_name.name, dentry->d_name.len, &bh, &de); if (error) { inode->i_nlink--; mark_inode_dirty(inode); iput(inode); - iput(dir); return error; } de->inode = inode->i_ino; mark_buffer_dirty(bh, 1); brelse(bh); - iput(dir); - iput(inode); + d_instantiate(dentry, inode); return 0; } -int sysv_mkdir(struct inode * dir, const char * name, int len, int mode) +int sysv_mkdir(struct inode * dir, struct dentry *dentry, int mode) { int error; struct inode * inode; struct buffer_head * bh, *dir_block; struct sysv_dir_entry * de; - if (!dir) { - iput(dir); + if (!dir) return -EINVAL; - } - bh = sysv_find_entry(dir,name,len,&de); + bh = sysv_find_entry(dir, dentry->d_name.name, + dentry->d_name.len, &de); if (bh) { brelse(bh); - iput(dir); return -EEXIST; } if (dir->i_nlink >= dir->i_sb->sv_link_max) { - iput(dir); return -EMLINK; } inode = sysv_new_inode(dir); - if (!inode) { - iput(dir); + if (!inode) return -ENOSPC; - } inode->i_op = &sysv_dir_inode_operations; inode->i_size = 2 * SYSV_DIRSIZE; dir_block = sysv_file_bread(inode,0,1); if (!dir_block) { - iput(dir); inode->i_nlink--; mark_inode_dirty(inode); iput(inode); @@ -342,9 +330,9 @@ int sysv_mkdir(struct inode * dir, const char * name, int len, int mode) if (dir->i_mode & S_ISGID) inode->i_mode |= S_ISGID; mark_inode_dirty(inode); - error = sysv_add_entry(dir, name, len, &bh, &de); - if (error) { - iput(dir); + error = sysv_add_entry(dir, dentry->d_name.name, + dentry->d_name.len, &bh, &de); + if (error) { inode->i_nlink=0; iput(inode); return error; @@ -353,10 +341,9 @@ int sysv_mkdir(struct inode * dir, const char * name, int len, int mode) mark_buffer_dirty(bh, 1); dir->i_nlink++; mark_inode_dirty(dir); - iput(dir); - iput(inode); brelse(bh); - return 0; + d_instantiate(dentry, inode); + return 0; } /* @@ -419,7 +406,7 @@ bad_dir: return 1; } -int sysv_rmdir(struct inode * dir, const char * name, int len) +int sysv_rmdir(struct inode * dir, struct dentry * dentry) { int retval; struct inode * inode; @@ -427,13 +414,14 @@ int sysv_rmdir(struct inode * dir, const char * name, int len) struct sysv_dir_entry * de; inode = NULL; - bh = sysv_find_entry(dir,name,len,&de); + bh = sysv_find_entry(dir, dentry->d_name.name, + dentry->d_name.len, &de); retval = -ENOENT; if (!bh) goto end_rmdir; retval = -EPERM; - if (!(inode = iget(dir->i_sb, de->inode))) - goto end_rmdir; + inode = dentry->d_inode; + if ((dir->i_mode & S_ISVTX) && !fsuser() && current->fsuid != inode->i_uid && current->fsuid != dir->i_uid) @@ -467,15 +455,14 @@ int sysv_rmdir(struct inode * dir, const char * name, int len) dir->i_nlink--; inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; mark_inode_dirty(dir); + d_delete(dentry); retval = 0; end_rmdir: - iput(dir); - iput(inode); brelse(bh); return retval; } -int sysv_unlink(struct inode * dir, const char * name, int len) +int sysv_unlink(struct inode * dir, struct dentry * dentry) { int retval; struct inode * inode; @@ -485,16 +472,16 @@ int sysv_unlink(struct inode * dir, const char * name, int len) repeat: retval = -ENOENT; inode = NULL; - bh = sysv_find_entry(dir,name,len,&de); + bh = sysv_find_entry(dir, dentry->d_name.name, + dentry->d_name.len, &de); if (!bh) goto end_unlink; - if (!(inode = iget(dir->i_sb, de->inode))) - goto end_unlink; + inode = dentry->d_inode; + retval = -EPERM; if (S_ISDIR(inode->i_mode)) goto end_unlink; if (de->inode != inode->i_ino) { - iput(inode); brelse(bh); current->counter = 0; schedule(); @@ -510,7 +497,7 @@ repeat: } if (!inode->i_nlink) { printk("Deleting nonexistent file (%s:%lu), %d\n", - kdevname(inode->i_dev), + kdevname(inode->i_dev), inode->i_ino, inode->i_nlink); inode->i_nlink=1; } @@ -521,15 +508,15 @@ repeat: inode->i_nlink--; inode->i_ctime = dir->i_ctime; mark_inode_dirty(inode); + d_delete(dentry); retval = 0; end_unlink: brelse(bh); - iput(inode); - iput(dir); return retval; } -int sysv_symlink(struct inode * dir, const char * name, int len, const char * symname) +int sysv_symlink(struct inode * dir, struct dentry * dentry, + const char * symname) { struct sysv_dir_entry * de; struct inode * inode; @@ -540,15 +527,13 @@ int sysv_symlink(struct inode * dir, const char * name, int len, const char * sy char c; struct buffer_head * bh; - if (!(inode = sysv_new_inode(dir))) { - iput(dir); + if (!(inode = sysv_new_inode(dir))) return -ENOSPC; - } + inode->i_mode = S_IFLNK | 0777; inode->i_op = &sysv_symlink_inode_operations; name_block = sysv_file_bread(inode,0,1); if (!name_block) { - iput(dir); inode->i_nlink--; mark_inode_dirty(inode); iput(inode); @@ -564,94 +549,81 @@ int sysv_symlink(struct inode * dir, const char * name, int len, const char * sy brelse(name_block); inode->i_size = i; mark_inode_dirty(inode); - bh = sysv_find_entry(dir,name,len,&de); + bh = sysv_find_entry(dir, dentry->d_name.name, + dentry->d_name.len, &de); if (bh) { inode->i_nlink--; mark_inode_dirty(inode); iput(inode); brelse(bh); - iput(dir); return -EEXIST; } - i = sysv_add_entry(dir, name, len, &bh, &de); + i = sysv_add_entry(dir, dentry->d_name.name, + dentry->d_name.len, &bh, &de); if (i) { inode->i_nlink--; mark_inode_dirty(inode); iput(inode); - iput(dir); return i; } de->inode = inode->i_ino; mark_buffer_dirty(bh, 1); brelse(bh); - iput(dir); - iput(inode); + d_instantiate(dentry, inode); return 0; } -int sysv_link(struct inode * oldinode, struct inode * dir, const char * name, int len) +int sysv_link(struct inode * oldinode, struct inode * dir, + struct dentry * dentry) { int error; struct sysv_dir_entry * de; struct buffer_head * bh; if (S_ISDIR(oldinode->i_mode)) { - iput(oldinode); - iput(dir); return -EPERM; } if (oldinode->i_nlink >= oldinode->i_sb->sv_link_max) { - iput(oldinode); - iput(dir); return -EMLINK; } - bh = sysv_find_entry(dir,name,len,&de); + bh = sysv_find_entry(dir, dentry->d_name.name, + dentry->d_name.len, &de); if (bh) { brelse(bh); - iput(dir); - iput(oldinode); return -EEXIST; } - error = sysv_add_entry(dir, name, len, &bh, &de); + error = sysv_add_entry(dir, dentry->d_name.name, + dentry->d_name.len, &bh, &de); if (error) { - iput(dir); - iput(oldinode); return error; } de->inode = oldinode->i_ino; mark_buffer_dirty(bh, 1); brelse(bh); - iput(dir); oldinode->i_nlink++; oldinode->i_ctime = CURRENT_TIME; mark_inode_dirty(oldinode); - iput(oldinode); + d_instantiate(dentry, oldinode); return 0; } /* return 1 if `new' is a subdir of `old' on the same device */ -static int subdir(struct inode * new_inode, struct inode * old_inode) +static int subdir(struct dentry * new_dentry, struct dentry * old_dentry) { - int ino; - int result; - - new_inode->i_count++; - result = 0; - for (;;) { - if (new_inode == old_inode) { - result = 1; - break; - } - if (new_inode->i_dev != old_inode->i_dev) - break; - ino = new_inode->i_ino; - if (sysv_lookup(new_inode,"..",2,&new_inode)) - break; - if (new_inode->i_ino == ino) /* root dir reached ? */ - break; - } - iput(new_inode); - return result; + int result = 0; + + for (;;) { + if (new_dentry != old_dentry) { + struct dentry * parent = new_dentry->d_parent; + if (parent == new_dentry) + break; + new_dentry = parent; + continue; + } + result = 1; + break; + } + return result; } #define PARENT_INO(buffer) \ @@ -716,7 +688,7 @@ start_up: if (!S_ISDIR(old_inode->i_mode)) goto end_rename; retval = -EINVAL; - if (subdir(new_dir, old_inode)) + if (subdir(new_dentry, old_dentry)) goto end_rename; retval = -ENOTEMPTY; if (!empty_dir(new_inode)) @@ -735,7 +707,7 @@ start_up: if (new_inode && !S_ISDIR(new_inode->i_mode)) goto end_rename; retval = -EINVAL; - if (subdir(new_dir, old_inode)) + if (subdir(new_dentry, old_dentry)) goto end_rename; retval = -EIO; dir_bh = sysv_file_bread(old_inode,0,0); diff --git a/fs/ufs/Makefile b/fs/ufs/Makefile index b5fa2bd48..0a74c36c7 100644 --- a/fs/ufs/Makefile +++ b/fs/ufs/Makefile @@ -9,7 +9,7 @@ O_TARGET := ufs.o O_OBJS := ufs_dir.o ufs_file.o ufs_inode.o ufs_namei.o \ - ufs_super.o ufs_symlink.o + ufs_super.o ufs_symlink.o ufs_swab.o M_OBJS := $(O_TARGET) include $(TOPDIR)/Rules.make diff --git a/fs/ufs/ufs_dir.c b/fs/ufs/ufs_dir.c index e91847df3..c64f38684 100644 --- a/fs/ufs/ufs_dir.c +++ b/fs/ufs/ufs_dir.c @@ -6,12 +6,13 @@ * Laboratory for Computer Science Research Computing Facility * Rutgers, The State University of New Jersey * - * $Id: ufs_dir.c,v 1.10 1997/06/05 01:29:06 davem Exp $ + * swab support by Francois-Rene Rideau <rideau@ens.fr> 19970406 * */ #include <linux/fs.h> -#include <linux/ufs_fs.h> + +#include "ufs_swab.h" /* * This is blatantly stolen from ext2fs @@ -26,12 +27,18 @@ ufs_readdir (struct file * filp, void * dirent, filldir_t filldir) struct buffer_head * bh; struct ufs_direct * de; struct super_block * sb; + int de_reclen; + __u32 s_flags, bytesex; + /* Isn't that already done but the upper layer??? */ if (!inode || !S_ISDIR(inode->i_mode)) return -EBADF; + sb = inode->i_sb; + s_flags = sb->u.ufs_sb.s_flags; + bytesex = s_flags & UFS_BYTESEX; - if (inode->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) { + if (s_flags & UFS_DEBUG) { printk("ufs_readdir: ino %lu f_pos %lu\n", inode->i_ino, (unsigned long) filp->f_pos); ufs_print_inode(inode); @@ -48,7 +55,8 @@ ufs_readdir (struct file * filp, void * dirent, filldir_t filldir) bh = bread (sb->s_dev, blk, sb->s_blocksize); if (!bh) { /* XXX - error - skip to the next block */ - printk("ufs_readdir: dir inode %lu has a hole at offset %lu\n", + printk("ufs_readdir: " + "dir inode %lu has a hole at offset %lu\n", inode->i_ino, (unsigned long int)filp->f_pos); filp->f_pos += sb->s_blocksize - offset; continue; @@ -61,7 +69,7 @@ revalidate: * to make sure. */ if (filp->f_version != inode->i_version) { for (i = 0; i < sb->s_blocksize && i < offset; ) { - de = (struct ufs_direct *) + de = (struct ufs_direct *) (bh->b_data + i); /* It's too expensive to do a full * dirent test each time round this @@ -69,28 +77,30 @@ revalidate: * least that it is non-zero. A * failure will be detected in the * dirent test below. */ - if (ufs_swab16(de->d_reclen) < 1) + de_reclen = SWAB16(de->d_reclen); + if (de_reclen < 1) break; - i += ufs_swab16(de->d_reclen); + i += de_reclen; } offset = i; filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1)) | offset; filp->f_version = inode->i_version; } - - while (!error && filp->f_pos < inode->i_size + + while (!error && filp->f_pos < inode->i_size && offset < sb->s_blocksize) { de = (struct ufs_direct *) (bh->b_data + offset); /* XXX - put in a real ufs_check_dir_entry() */ - if ((ufs_swab16(de->d_reclen) == 0) - || (ufs_swab16(de->d_namlen) == 0)) { + if ((de->d_reclen == 0) || (de->d_namlen == 0)) { + /* SWAB16() was unneeded -- compare to 0 */ filp->f_pos = (filp->f_pos & (sb->s_blocksize - 1)) + sb->s_blocksize; brelse(bh); return stored; } #if 0 if (!ext2_check_dir_entry ("ext2_readdir", inode, de, + /* XXX - beware about de having to be swabped somehow */ bh, offset)) { /* On error, skip the f_pos to the next block. */ @@ -100,8 +110,9 @@ revalidate: return stored; } #endif /* XXX */ - offset += ufs_swab16(de->d_reclen); - if (ufs_swab32(de->d_ino)) { + offset += SWAB16(de->d_reclen); + if (de->d_ino) { + /* SWAB16() was unneeded -- compare to 0 */ /* We might block in the next section * if the data destination is * currently swapped out. So, use a @@ -110,18 +121,18 @@ revalidate: * during the copy operation. */ unsigned long version = inode->i_version; - if (inode->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) { + if (s_flags & UFS_DEBUG) { printk("ufs_readdir: filldir(%s,%u)\n", - de->d_name, ufs_swab32(de->d_ino)); + de->d_name, SWAB32(de->d_ino)); } - error = filldir(dirent, de->d_name, ufs_swab16(de->d_namlen), filp->f_pos, ufs_swab32(de->d_ino)); + error = filldir(dirent, de->d_name, SWAB16(de->d_namlen), filp->f_pos, SWAB32(de->d_ino)); if (error) break; if (version != inode->i_version) goto revalidate; stored ++; } - filp->f_pos += ufs_swab16(de->d_reclen); + filp->f_pos += SWAB16(de->d_reclen); } offset = 0; brelse (bh); @@ -140,7 +151,7 @@ static struct file_operations ufs_dir_operations = { NULL, /* read */ NULL, /* write */ ufs_readdir, /* readdir */ - NULL, /* poll */ + NULL, /* select */ NULL, /* ioctl */ NULL, /* mmap */ NULL, /* open */ diff --git a/fs/ufs/ufs_file.c b/fs/ufs/ufs_file.c index 72161d2bd..7471156a0 100644 --- a/fs/ufs/ufs_file.c +++ b/fs/ufs/ufs_file.c @@ -18,7 +18,7 @@ static struct file_operations ufs_file_operations = { generic_file_read, /* read */ NULL, /* write */ NULL, /* readdir */ - NULL, /* poll */ + NULL, /* select */ NULL, /* ioctl */ generic_file_mmap, /* mmap */ NULL, /* open */ diff --git a/fs/ufs/ufs_inode.c b/fs/ufs/ufs_inode.c index c55092d54..75329c584 100644 --- a/fs/ufs/ufs_inode.c +++ b/fs/ufs/ufs_inode.c @@ -6,7 +6,8 @@ * Laboratory for Computer Science Research Computing Facility * Rutgers, The State University of New Jersey * - * $Id: ufs_inode.c,v 1.9 1997/07/17 02:24:14 davem Exp $ + * Clean swab support on 19970406 + * by Francois-Rene Rideau <rideau@ens.fr> * */ @@ -14,6 +15,8 @@ #include <linux/ufs_fs.h> #include <linux/sched.h> +#include "ufs_swab.h" + void ufs_print_inode(struct inode * inode) { printk("ino %lu mode 0%6.6o lk %d uid %d gid %d" @@ -41,14 +44,14 @@ static inline int block_bmap (struct inode *inode, int block, int nr) { struct buffer_head *bh; int tmp; - + __u32 bytesex = inode->i_sb->u.ufs_sb.s_flags & UFS_BYTESEX; /* XXX Split in fsize big blocks (Can't bread 8Kb). */ tmp = nr >> (inode->i_sb->u.ufs_sb.s_fshift - 2); bh = bread (inode->i_dev, block + tmp, inode->i_sb->u.ufs_sb.s_fsize); if (!bh) return 0; nr &= ~(inode->i_sb->u.ufs_sb.s_fmask) >> 2; - tmp = ufs_swab32(((__u32 *)bh->b_data)[nr]); + tmp = SWAB32(((__u32 *)bh->b_data)[nr]); brelse (bh); return tmp; } @@ -113,6 +116,7 @@ void ufs_read_inode(struct inode * inode) struct super_block * sb; struct ufs_inode * ufsip; struct buffer_head * bh; + __u32 bytesex = inode->i_sb->u.ufs_sb.s_flags & UFS_BYTESEX; sb = inode->i_sb; @@ -144,8 +148,8 @@ void ufs_read_inode(struct inode * inode) /* * Copy data to the in-core inode. */ - inode->i_mode = ufs_swab16(ufsip->ui_mode); - inode->i_nlink = ufs_swab16(ufsip->ui_nlink); + inode->i_mode = SWAB16(ufsip->ui_mode); + inode->i_nlink = SWAB16(ufsip->ui_nlink); if (inode->i_nlink == 0) { /* XXX */ printk("ufs_read_inode: zero nlink ino %lu dev %u/%u\n", @@ -158,7 +162,7 @@ void ufs_read_inode(struct inode * inode) MAJOR(inode->i_dev), MINOR(inode->i_dev)); } /* XXX - debugging */ - if (ufs_swab32(ufsip->ui_gen) == 0) { + if (SWAB32(ufsip->ui_gen) == 0) { printk("ufs_read_inode: zero gen ino %lu pblk %lu dev %u/%u\n", inode->i_ino, ufs_cgimin(inode->i_sb, ufs_ino2cg(inode)) + @@ -172,33 +176,33 @@ void ufs_read_inode(struct inode * inode) * random users can't get at these files, since they get dynamically * "chown()ed" to root. */ - if (ufs_swab16(ufsip->ui_suid) == UFS_USEEFT) { + if (SWAB16(ufsip->ui_suid) == UFS_USEEFT) { /* EFT */ inode->i_uid = 0; printk("ufs_read_inode: EFT uid %u ino %lu dev %u/%u, using %u\n", - ufs_swab32(ufsip->ui_uid), inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev), + SWAB32(ufsip->ui_uid), inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev), inode->i_uid); } else { - inode->i_uid = ufs_swab16(ufsip->ui_suid); + inode->i_uid = SWAB16(ufsip->ui_suid); } - if (ufs_swab16(ufsip->ui_sgid) == UFS_USEEFT) { + if (SWAB16(ufsip->ui_sgid) == UFS_USEEFT) { /* EFT */ inode->i_gid = 0; printk("ufs_read_inode: EFT gid %u ino %lu dev %u/%u, using %u\n", - ufs_swab32(ufsip->ui_gid), inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev), + SWAB32(ufsip->ui_gid), inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev), inode->i_gid); } else { - inode->i_gid = ufs_swab16(ufsip->ui_sgid); + inode->i_gid = SWAB16(ufsip->ui_sgid); } /* - * Linux i_size is 32 bits, so some files on a UFS filesystem may not + * Linux i_size is 32 bits on most architectures, + * so some files on a UFS filesystem may not * be readable. I let people access the first 32 bits worth of them. * for the rw code, we may want to mark these inodes as read-only. * XXX - bug Linus to make i_size a __u64 instead of a __u32. */ - inode->u.ufs_i.i_size = ((__u64)(ufs_swab32(ufsip->ui_size.val[0]))<<32) | - (__u64)(ufs_swab32(ufsip->ui_size.val[1])); + inode->u.ufs_i.i_size = SWAB64(ufsip->ui_size); /* KRR - Just type cast inode->u.ufs_i.i_size into off_t and * worry about overflow later */ @@ -210,11 +214,11 @@ void ufs_read_inode(struct inode * inode) * want to keep this data, but for the moment I think I'll just write * zeros for these fields when writing out inodes. */ - inode->i_atime = ufsip->ui_atime.tv_sec; - inode->i_mtime = ufsip->ui_mtime.tv_sec; - inode->i_ctime = ufsip->ui_ctime.tv_sec; + inode->i_atime = SWAB32(ufsip->ui_atime.tv_sec); + inode->i_mtime = SWAB32(ufsip->ui_mtime.tv_sec); + inode->i_ctime = SWAB32(ufsip->ui_ctime.tv_sec); inode->i_blksize = sb->u.ufs_sb.s_fsize; - inode->i_blocks = ufs_swab32(ufsip->ui_blocks); + inode->i_blocks = SWAB32(ufsip->ui_blocks); inode->i_version = ++event; /* see linux/kernel/sched.c */ if (S_ISREG(inode->i_mode)) { @@ -246,11 +250,11 @@ void ufs_read_inode(struct inode * inode) int i; for (i = 0; i < UFS_NDADDR; i++) { - inode->u.ufs_i.i_data[i] = ufs_swab32(ufsip->ui_db[i]); + inode->u.ufs_i.i_data[i] = SWAB32(ufsip->ui_db[i]); } for (i = 0; i < UFS_NINDIR; i++) { inode->u.ufs_i.i_data[UFS_IND_BLOCK + i] = - ufs_swab32(ufsip->ui_ib[i]); + SWAB32(ufsip->ui_ib[i]); } } @@ -261,18 +265,17 @@ void ufs_read_inode(struct inode * inode) * the code. */ if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { - inode->i_rdev = (kdev_t)((__u64)(ufs_swab32(ufsip->ui_db[0]))<<32) | - (__u64)(ufs_swab32(ufsip->ui_db[1])); + inode->i_rdev = (kdev_t)SWAB64(*(__u64*)&ufsip->ui_db); } /* XXX - implement fast and slow symlinks */ - inode->u.ufs_i.i_flags = ufs_swab32(ufsip->ui_flags); - inode->u.ufs_i.i_gen = ufs_swab32(ufsip->ui_gen); /* XXX - is this i_version? */ - inode->u.ufs_i.i_shadow = ufs_swab32(ufsip->ui_shadow); /* XXX */ - inode->u.ufs_i.i_uid = ufs_swab32(ufsip->ui_uid); - inode->u.ufs_i.i_gid = ufs_swab32(ufsip->ui_gid); - inode->u.ufs_i.i_oeftflag = ufs_swab32(ufsip->ui_oeftflag); + inode->u.ufs_i.i_flags = SWAB32(ufsip->ui_flags); + inode->u.ufs_i.i_gen = SWAB32(ufsip->ui_gen); /* XXX - is this i_version? */ + inode->u.ufs_i.i_shadow = SWAB32(ufsip->ui_shadow); /* XXX */ + inode->u.ufs_i.i_uid = SWAB32(ufsip->ui_uid); + inode->u.ufs_i.i_gid = SWAB32(ufsip->ui_gid); + inode->u.ufs_i.i_oeftflag = SWAB32(ufsip->ui_oeftflag); brelse(bh); @@ -307,4 +310,3 @@ void ufs_put_inode (struct inode * inode) return; } - diff --git a/fs/ufs/ufs_namei.c b/fs/ufs/ufs_namei.c index ec9ec3119..6cf8c6c39 100644 --- a/fs/ufs/ufs_namei.c +++ b/fs/ufs/ufs_namei.c @@ -6,48 +6,62 @@ * Laboratory for Computer Science Research Computing Facility * Rutgers, The State University of New Jersey * - * $Id: ufs_namei.c,v 1.9 1997/07/22 06:40:12 davem Exp $ + * Clean swab support by Francois-Rene Rideau <rideau@ens.fr> 19970406 + * Ported to 2.1.62 by Francois-Rene Rideau <rideau@ens.fr> 19971109 * */ #include <linux/fs.h> #include <linux/ufs_fs.h> - #include <linux/string.h> +#include "ufs_swab.h" /* * NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure. * stolen from ext2fs */ -static int ufs_match (int len, const char * const name, struct ufs_direct * d) +static int ufs_match (int len, const char * const name, struct ufs_direct * d, __u32 bytesex) { if (!d || len > UFS_MAXNAMLEN) /* XXX - name space */ return 0; /* * "" means "." ---> so paths like "/usr/lib//libc.a" work */ - if (!len && (ufs_swab16(d->d_namlen) == 1) && (d->d_name[0] == '.') && - (d->d_name[1] == '\0')) - return 1; - if (len != ufs_swab16(d->d_namlen)) + if (!len && (SWAB16(d->d_namlen) == 1) && (d->d_name[0] == '.') && + (d->d_name[1] == '\0')) + return 1; + if (len != SWAB16(d->d_namlen)) return 0; return !memcmp(name, d->d_name, len); } -/* XXX - this is a mess, especially for endianity */ -int ufs_lookup (struct inode * dir, struct qstr *qname, - struct inode ** result) +int ufs_lookup (struct inode *dir, struct dentry *dentry) { + /* XXX - this is all fucked up! */ + /* XXX - and it's been broken since linux has this new dentry interface: + * allows reading of files, but screws the whole dcache, even outside + * of the ufs partition, so that umount'ing won't suffice to fix it -- + * reboot needed + */ unsigned long int lfragno, fragno; struct buffer_head * bh; struct ufs_direct * d; - const char *name = qname->name; - int len = qname->len; + const char *name = dentry->d_name.name; + int len = dentry->d_name.len; + __u32 bytesex; + struct inode *inode; + + /* XXX - isn't that already done by the upper layer? */ + if (!dir || !S_ISDIR(dir->i_mode)) + return -EBADF; + + bytesex = dir->i_sb->u.ufs_sb.s_flags & UFS_BYTESEX; if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) printk("Passed name: %s\nPassed length: %d\n", name, len); - /* + + /* debugging hacks: * Touching /xyzzy in a filesystem toggles debugging messages. */ if ((len == 5) && !(memcmp(name, "xyzzy", len)) && @@ -56,8 +70,8 @@ int ufs_lookup (struct inode * dir, struct qstr *qname, printk("UFS debugging %s\n", (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) ? "on": "off"); - iput(dir); - return(-ENOENT); + goto not_found; + /*return(-ENOENT);*/ } /* @@ -69,8 +83,8 @@ int ufs_lookup (struct inode * dir, struct qstr *qname, printk("UFS inode debugging %s\n", (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG_INODE) ? "on": "off"); - iput(dir); - return(-ENOENT); + goto not_found; + /*return(-ENOENT);*/ } if ((len == 7) && !(memcmp(name, "xyzzy.n", len)) && @@ -79,8 +93,8 @@ int ufs_lookup (struct inode * dir, struct qstr *qname, printk("UFS namei debugging %s\n", (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG_NAMEI) ? "on": "off"); - iput(dir); - return(-ENOENT); + goto not_found; + /*return(-ENOENT);*/ } if ((len == 7) && !(memcmp(name, "xyzzy.l", len)) && @@ -89,10 +103,13 @@ int ufs_lookup (struct inode * dir, struct qstr *qname, printk("UFS symlink debugging %s\n", (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG_LINKS) ? "on": "off"); - iput(dir); - return(-ENOENT); + goto not_found; + /*return(-ENOENT);*/ } + + /* Now for the real thing */ + if (dir->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_NAMEI)) { printk("ufs_lookup: called for ino %lu name %s\n", dir->i_ino, name); @@ -109,21 +126,22 @@ int ufs_lookup (struct inode * dir, struct qstr *qname, } if (fragno == 0) { /* XXX - bug bug bug */ - iput(dir); - return(-ENOENT); + goto not_found; + /*return(-ENOENT);*/ } bh = bread(dir->i_dev, fragno, dir->i_sb->s_blocksize); if (bh == NULL) { - printk("ufs_lookup: bread failed: ino %lu, lfragno %lu", + printk("ufs_lookup: bread failed: " + "ino %lu, lfragno %lu", dir->i_ino, lfragno); - iput(dir); return(-EIO); } d = (struct ufs_direct *)(bh->b_data); - while (((char *)d - bh->b_data + ufs_swab16(d->d_reclen)) <= + while (((char *)d - bh->b_data + SWAB16(d->d_reclen)) <= dir->i_sb->s_blocksize) { /* XXX - skip block if d_reclen or d_namlen is 0 */ - if ((ufs_swab16(d->d_reclen) == 0) || (ufs_swab16(d->d_namlen) == 0)) { + if ((d->d_reclen == 0) || (d->d_namlen == 0)) { + /* no need to SWAB16(): test against 0 */ if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) { printk("ufs_lookup: skipped space in directory, ino %lu\n", dir->i_ino); @@ -131,32 +149,43 @@ int ufs_lookup (struct inode * dir, struct qstr *qname, break; } if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) { - printk("lfragno 0x%lx direct d 0x%x d_ino %u " - "d_reclen %u d_namlen %u d_name `%s'\n", - lfragno, (unsigned int)((unsigned long)d), - ufs_swab32(d->d_ino), ufs_swab16(d->d_reclen), - ufs_swab16(d->d_namlen), d->d_name); + printk("lfragno 0x%lx " + "direct d 0x%x " + "d_ino %u " + "d_reclen %u " + "d_namlen %u d_name `%s'\n", + lfragno, + (unsigned int)((unsigned long)d), + SWAB32(d->d_ino), + SWAB16(d->d_reclen), + SWAB16(d->d_namlen),d->d_name); } - if ((ufs_swab16(d->d_namlen) == len) && + if ((SWAB16(d->d_namlen) == len) && /* XXX - don't use strncmp() - see ext2fs */ - (ufs_match(len, name, d))) { + (ufs_match(len, name, d, bytesex))) { /* We have a match */ - *result = iget(dir->i_sb, ufs_swab32(d->d_ino)); - brelse(bh); - iput(dir); +/* XXX - I only superficially understand how things work, + * so use at your own risk... -- Fare' + */ + inode = iget(dir->i_sb, SWAB32(d->d_ino)); + brelse(bh); + if(!inode) { return -EACCES; } + d_add(dentry,inode); return(0); } else { /* XXX - bounds checking */ if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) { - printk("ufs_lookup: wanted (%s,%d) got (%s,%d)\n", - name, len, d->d_name, ufs_swab16(d->d_namlen)); + printk("ufs_lookup: " + "wanted (%s,%d) got (%s,%d)\n", + name, len, + d->d_name, SWAB16(d->d_namlen)); } } - d = (struct ufs_direct *)((char *)d + ufs_swab16(d->d_reclen)); + d = (struct ufs_direct *)((char *)d + SWAB16(d->d_reclen)); } brelse(bh); } - iput(dir); - return(-ENOENT); + not_found: + d_add(dentry,NULL); + return(0); } - diff --git a/fs/ufs/ufs_super.c b/fs/ufs/ufs_super.c index c2ee0ded7..a3c32ccce 100644 --- a/fs/ufs/ufs_super.c +++ b/fs/ufs/ufs_super.c @@ -8,8 +8,6 @@ * * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be) * - * $Id: ufs_super.c,v 1.25 1997/07/17 02:24:15 davem Exp $ - * */ /* @@ -18,6 +16,9 @@ * * Module usage counts added on 96/04/29 by * Gertjan van Wingerde <gertjan@cs.vu.nl> + * + * Clean swab support on 19970406 by + * Francois-Rene Rideau <rideau@ens.fr> */ #include <linux/config.h> @@ -28,20 +29,20 @@ #include <linux/ufs_fs.h> #include <linux/locks.h> #include <linux/init.h> - #include <asm/uaccess.h> -int ufs_need_swab = 0; +#include "ufs_swab.h" struct super_block * ufs_read_super(struct super_block * sb, void * data, int silent); void ufs_put_super (struct super_block * sb); -void ufs_statfs(struct super_block * sb, struct statfs * buf, int bufsize); +int ufs_statfs(struct super_block * sb, struct statfs * buf, int bufsize); static struct super_operations ufs_super_ops = { ufs_read_inode, - NULL, /* notify_change() */ NULL, /* XXX - ufs_write_inode() */ ufs_put_inode, + NULL, /* XXX - ufs_delete_inode() */ + NULL, /* notify_change() */ ufs_put_super, NULL, /* XXX - ufs_write_super() */ ufs_statfs, @@ -113,8 +114,9 @@ ufs_print_super_stuff(struct super_block * sb, struct ufs_superblock * usb) struct super_block * ufs_read_super(struct super_block * sb, void * data, int silent) { - struct ufs_superblock * usb; + struct ufs_superblock * usb; /* normalized to local byteorder */ struct buffer_head * bh1, *bh2; + __u32 bytesex = 0; /* sb->s_dev and sb->s_flags are set by our caller * data is the mystery argument to sys_mount() @@ -132,9 +134,7 @@ ufs_read_super(struct super_block * sb, void * data, int silent) if (!(bh1 = bread(sb->s_dev, UFS_SBLOCK/BLOCK_SIZE, BLOCK_SIZE)) || !(bh2 = bread(sb->s_dev, (UFS_SBLOCK + BLOCK_SIZE)/BLOCK_SIZE, BLOCK_SIZE))) { - if (bh1) { - brelse(bh1); - } + brelse(bh1); printk ("ufs_read_super: unable to read superblock\n"); goto ufs_read_super_lose; @@ -156,32 +156,35 @@ ufs_read_super(struct super_block * sb, void * data, int silent) brelse(bh1); brelse(bh2); - ufs_need_swab = 0; - sb->s_magic = ufs_swab32(usb->fs_magic); - if (sb->s_magic != UFS_MAGIC) { - ufs_need_swab = 1; - sb->s_magic = ufs_swab32(usb->fs_magic); - if (sb->s_magic != UFS_MAGIC) { - printk ("ufs_read_super: bad magic number 0x%8.8lx " - "on dev %d/%d\n", sb->s_magic, + switch (le32_to_cpup(&usb->fs_magic)) { + case UFS_MAGIC: + bytesex = UFS_LITTLE_ENDIAN; + ufs_superblock_le_to_cpus(usb); + break; + case UFS_CIGAM: + bytesex = UFS_BIG_ENDIAN; + ufs_superblock_be_to_cpus(usb); + break; + /* usb is now normalized to local byteorder */ + default: + printk ("ufs_read_super: bad magic number 0x%8.8x " + "on dev %d/%d\n", usb->fs_magic, MAJOR(sb->s_dev), MINOR(sb->s_dev)); - goto ufs_read_super_lose; - } } /* We found a UFS filesystem on this device. */ /* XXX - parse args */ - if (ufs_swab32(usb->fs_bsize) != UFS_BSIZE) { - printk("ufs_read_super: fs_bsize %d != %d\n", ufs_swab32(usb->fs_bsize), + if (usb->fs_bsize != UFS_BSIZE) { + printk("ufs_read_super: fs_bsize %d != %d\n", usb->fs_bsize, UFS_BSIZE); goto ufs_read_super_lose; } - if (ufs_swab32(usb->fs_fsize) != UFS_FSIZE) { - printk("ufs_read_super: fs_fsize %d != %d\n", ufs_swab32(usb->fs_fsize), + if (usb->fs_fsize != UFS_FSIZE) { + printk("ufs_read_super: fs_fsize %d != %d\n", usb->fs_fsize, UFS_FSIZE); goto ufs_read_super_lose; } @@ -190,7 +193,7 @@ ufs_read_super(struct super_block * sb, void * data, int silent) printk("ufs_read_super: fs last mounted on \"%s\"\n", usb->fs_fsmnt); #endif - if (ufs_swab32(usb->fs_state) == UFS_FSOK - ufs_swab32(usb->fs_time)) { + if (usb->fs_state == UFS_FSOK - usb->fs_time) { switch(usb->fs_clean) { case UFS_FSCLEAN: #ifdef DEBUG_UFS_SUPER @@ -225,35 +228,35 @@ ufs_read_super(struct super_block * sb, void * data, int silent) /* XXX - sanity check sb fields */ /* KRR - Why are we not using fs_bsize for blocksize? */ - sb->s_blocksize = ufs_swab32(usb->fs_fsize); - sb->s_blocksize_bits = ufs_swab32(usb->fs_fshift); + sb->s_blocksize = usb->fs_fsize; + sb->s_blocksize_bits = usb->fs_fshift; /* XXX - sb->s_lock */ sb->s_op = &ufs_super_ops; sb->dq_op = 0; /* XXX */ - /* KRR - defined above - sb->s_magic = usb->fs_magic; */ + sb->s_magic = usb->fs_magic; /* sb->s_time */ /* sb->s_wait */ /* XXX - sb->u.ufs_sb */ sb->u.ufs_sb.s_raw_sb = usb; /* XXX - maybe move this to the top */ - sb->u.ufs_sb.s_flags = 0; - sb->u.ufs_sb.s_ncg = ufs_swab32(usb->fs_ncg); - sb->u.ufs_sb.s_ipg = ufs_swab32(usb->fs_ipg); - sb->u.ufs_sb.s_fpg = ufs_swab32(usb->fs_fpg); - sb->u.ufs_sb.s_fsize = ufs_swab32(usb->fs_fsize); - sb->u.ufs_sb.s_fmask = ufs_swab32(usb->fs_fmask); - sb->u.ufs_sb.s_fshift = ufs_swab32(usb->fs_fshift); - sb->u.ufs_sb.s_bsize = ufs_swab32(usb->fs_bsize); - sb->u.ufs_sb.s_bmask = ufs_swab32(usb->fs_bmask); - sb->u.ufs_sb.s_bshift = ufs_swab32(usb->fs_bshift); - sb->u.ufs_sb.s_iblkno = ufs_swab32(usb->fs_iblkno); - sb->u.ufs_sb.s_dblkno = ufs_swab32(usb->fs_dblkno); - sb->u.ufs_sb.s_cgoffset = ufs_swab32(usb->fs_cgoffset); - sb->u.ufs_sb.s_cgmask = ufs_swab32(usb->fs_cgmask); - sb->u.ufs_sb.s_inopb = ufs_swab32(usb->fs_inopb); - sb->u.ufs_sb.s_lshift = ufs_swab32(usb->fs_bshift) - ufs_swab32(usb->fs_fshift); - sb->u.ufs_sb.s_lmask = ~((ufs_swab32(usb->fs_fmask) - ufs_swab32(usb->fs_bmask)) - >> ufs_swab32(usb->fs_fshift)); - sb->u.ufs_sb.s_fsfrag = ufs_swab32(usb->fs_frag); /* XXX - rename this later */ + sb->u.ufs_sb.s_flags = bytesex | UFS_DEBUG_INITIAL ; + sb->u.ufs_sb.s_ncg = usb->fs_ncg; + sb->u.ufs_sb.s_ipg = usb->fs_ipg; + sb->u.ufs_sb.s_fpg = usb->fs_fpg; + sb->u.ufs_sb.s_fsize = usb->fs_fsize; + sb->u.ufs_sb.s_fmask = usb->fs_fmask; + sb->u.ufs_sb.s_fshift = usb->fs_fshift; + sb->u.ufs_sb.s_bsize = usb->fs_bsize; + sb->u.ufs_sb.s_bmask = usb->fs_bmask; + sb->u.ufs_sb.s_bshift = usb->fs_bshift; + sb->u.ufs_sb.s_iblkno = usb->fs_iblkno; + sb->u.ufs_sb.s_dblkno = usb->fs_dblkno; + sb->u.ufs_sb.s_cgoffset = usb->fs_cgoffset; + sb->u.ufs_sb.s_cgmask = usb->fs_cgmask; + sb->u.ufs_sb.s_inopb = usb->fs_inopb; + sb->u.ufs_sb.s_lshift = usb->fs_bshift - usb->fs_fshift; + sb->u.ufs_sb.s_lmask = ~((usb->fs_fmask - usb->fs_bmask) + >> usb->fs_fshift); + sb->u.ufs_sb.s_fsfrag = usb->fs_frag; /* XXX - rename this later */ sb->s_root = d_alloc_root(iget(sb, UFS_ROOTINO), NULL); #ifdef DEBUG_UFS_SUPER @@ -285,6 +288,7 @@ void ufs_put_super (struct super_block * sb) sb->s_dev = 0; /* XXX - free allocated kernel memory */ + /* includes freeing usb page */ unlock_super (sb); MOD_DEC_USE_COUNT; @@ -292,11 +296,12 @@ void ufs_put_super (struct super_block * sb) return; } -void ufs_statfs(struct super_block * sb, struct statfs * buf, int bufsiz) +int ufs_statfs(struct super_block * sb, struct statfs * buf, int bufsiz) { struct statfs tmp; struct statfs *sp = &tmp; struct ufs_superblock *fsb = sb->u.ufs_sb.s_raw_sb; + /* fsb was already normalized during mounting */ unsigned long used, avail; if (sb->u.ufs_sb.s_flags & UFS_DEBUG) { @@ -305,13 +310,13 @@ void ufs_statfs(struct super_block * sb, struct statfs * buf, int bufsiz) sp->f_type = sb->s_magic; sp->f_bsize = sb->s_blocksize; - sp->f_blocks = ufs_swab32(fsb->fs_dsize); - sp->f_bfree = ufs_swab32(fsb->fs_cstotal.cs_nbfree) * - ufs_swab32(fsb->fs_frag) + - ufs_swab32(fsb->fs_cstotal.cs_nffree); + sp->f_blocks = fsb->fs_dsize; + sp->f_bfree = fsb->fs_cstotal.cs_nbfree * + fsb->fs_frag + + fsb->fs_cstotal.cs_nffree; avail = sp->f_blocks - (sp->f_blocks / 100) * - ufs_swab32(fsb->fs_minfree); + fsb->fs_minfree; used = sp->f_blocks - sp->f_bfree; if (avail > used) sp->f_bavail = avail - used; @@ -319,11 +324,10 @@ void ufs_statfs(struct super_block * sb, struct statfs * buf, int bufsiz) sp->f_bavail = 0; sp->f_files = sb->u.ufs_sb.s_ncg * sb->u.ufs_sb.s_ipg; - sp->f_ffree = ufs_swab32(fsb->fs_cstotal.cs_nifree); - sp->f_fsid.val[0] = ufs_swab32(fsb->fs_id[0]); - sp->f_fsid.val[1] = ufs_swab32(fsb->fs_id[1]); + sp->f_ffree = fsb->fs_cstotal.cs_nifree; + sp->f_fsid.val[0] = fsb->fs_id[0]; + sp->f_fsid.val[1] = fsb->fs_id[1]; sp->f_namelen = UFS_MAXNAMLEN; - copy_to_user(buf, sp, bufsiz); - return; + return copy_to_user(buf, sp, bufsiz) ? -EFAULT : 0; } diff --git a/fs/ufs/ufs_symlink.c b/fs/ufs/ufs_symlink.c index d98f99ff7..76d5fbf11 100644 --- a/fs/ufs/ufs_symlink.c +++ b/fs/ufs/ufs_symlink.c @@ -6,7 +6,7 @@ * Laboratory for Computer Science Research Computing Facility * Rutgers, The State University of New Jersey * - * $Id: ufs_symlink.c,v 1.9 1997/06/05 01:29:11 davem Exp $ + * Ported to 2.1.62 by Francois-Rene Rideau <rideau@ens.fr> 19971109 * */ @@ -16,6 +16,8 @@ #include <asm/uaccess.h> +extern int ufs_bmap (struct inode *, int); + static int ufs_readlink(struct inode * inode, char * buffer, int buflen) { @@ -30,6 +32,10 @@ ufs_readlink(struct inode * inode, char * buffer, int buflen) inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev)); } + if (!S_ISLNK(inode->i_mode)) { + return -EINVAL; + } + if (buflen > inode->i_sb->s_blocksize - 1) buflen = inode->i_sb->s_blocksize - 1; if (inode->i_blocks) { @@ -38,16 +44,16 @@ ufs_readlink(struct inode * inode, char * buffer, int buflen) if (inode->i_sb->u.ufs_sb.s_flags &(UFS_DEBUG|UFS_DEBUG_LINKS)) { printk("ufs_readlink: bmap got %lu for ino %lu\n", block, inode->i_ino); - } + } bh = bread(inode->i_dev, block, BLOCK_SIZE); if (!bh) { - iput (inode); printk("ufs_readlink: can't read block 0 for ino %lu on dev %u/%u\n", inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev)); return 0; } link = bh->b_data; + /* no need to bswap */ } else { link = (char *)&(inode->u.ufs_i.i_data[0]); @@ -57,18 +63,54 @@ ufs_readlink(struct inode * inode, char * buffer, int buflen) i++; put_user (c, buffer++); } - iput (inode); - if (bh) - brelse (bh); + brelse (bh); return i; } +/* + * XXX - blatantly stolen from minix fs + */ +static struct dentry * +ufs_follow_link(struct inode * inode, struct dentry * base) +{ + unsigned long int block; + struct buffer_head * bh = NULL; + char * link; + + if (inode->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_LINKS)) { + printk("ufs_follow_link: called on ino %lu dev %u/%u\n", + inode->i_ino, MAJOR(inode->i_dev), MINOR(inode->i_dev)); + } + + if (inode->i_blocks) { + /* read the link from disk */ + /* XXX - error checking */ + block = ufs_bmap(inode, 0); + bh = bread(inode->i_dev, block, BLOCK_SIZE); + if (bh == NULL) { + printk("ufs_follow_link: can't read block 0 for ino %lu on dev %u/%u\n", + inode->i_ino, MAJOR(inode->i_dev), + MINOR(inode->i_dev)); + dput(base); + return ERR_PTR(-EIO); + } + link = bh->b_data; + } else { + /* fast symlink */ + link = (char *)&(inode->u.ufs_i.i_data[0]); + } + base = lookup_dentry(link, base, 1); + brelse (bh); + return base; +} + + static struct file_operations ufs_symlink_operations = { NULL, /* lseek */ NULL, /* read */ NULL, /* write */ NULL, /* readdir */ - NULL, /* poll */ + NULL, /* select */ NULL, /* ioctl */ NULL, /* mmap */ NULL, /* open */ @@ -90,12 +132,11 @@ struct inode_operations ufs_symlink_inode_operations = { NULL, /* rmdir */ NULL, /* mknod */ NULL, /* rename */ - ufs_readlink, /* readlink */ + &ufs_readlink, /* readlink */ + &ufs_follow_link, /* follow_link */ NULL, /* readpage */ NULL, /* writepage */ NULL, /* bmap */ NULL, /* truncate */ NULL, /* permission */ - NULL, /* smap */ }; - diff --git a/fs/umsdos/emd.c b/fs/umsdos/emd.c index a40f3bbeb..86002ddeb 100644 --- a/fs/umsdos/emd.c +++ b/fs/umsdos/emd.c @@ -29,7 +29,7 @@ long umsdos_file_read_kmem (struct inode *inode, unsigned long count) { int ret; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); set_fs (KERNEL_DS); ret = fat_file_read(inode,filp,buf,count); set_fs (old_fs); @@ -44,7 +44,7 @@ long umsdos_file_write_kmem (struct inode *inode, unsigned long count) { int ret; - unsigned long old_fs = get_fs(); + mm_segment_t old_fs = get_fs(); set_fs (KERNEL_DS); ret = fat_file_write(inode,filp,buf,count); set_fs (old_fs); diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c index c1ff4176c..8aacb6dfd 100644 --- a/fs/vfat/namei.c +++ b/fs/vfat/namei.c @@ -5,7 +5,7 @@ * * Windows95/Windows NT compatible extended MSDOS filesystem * by Gordon Chaffee Copyright (C) 1995. Send bug reports for the - * VFAT filesystem to <chaffee@plateau.cs.berkeley.edu>. Specify + * VFAT filesystem to <chaffee@cs.berkeley.edu>. Specify * what file operation caused you trouble and if you can duplicate * the problem, send a script that demonstrates it. */ @@ -20,6 +20,7 @@ #include <linux/kernel.h> #include <linux/errno.h> #include <linux/string.h> +#include <linux/ctype.h> #include <linux/stat.h> #include <linux/mm.h> #include <linux/malloc.h> @@ -38,12 +39,6 @@ # define CHECK_STACK check_stack(__FILE__, __LINE__) #endif -/* - * XXX: It would be better to use the tolower from linux/ctype.h, - * but _ctype is needed and it is not exported. - */ -#define tolower(c) (((c) >= 'A' && (c) <= 'Z') ? (c)-('A'-'a') : (c)) - struct vfat_find_info { const char *name; int len; @@ -229,10 +224,15 @@ static void dump_de(struct msdos_dir_entry *de) /* MS-DOS "device special files" */ -static const char *reserved_names[] = { - "CON ","PRN ","NUL ","AUX ", - "LPT1 ","LPT2 ","LPT3 ","LPT4 ", - "COM1 ","COM2 ","COM3 ","COM4 ", +static const char *reserved3_names[] = { + "con ", "prn ", "nul ", "aux ", NULL +}; + +static const char *reserved4_names[] = { + "com1 ", "com2 ", "com3 ", "com4 ", "com5 ", + "com6 ", "com7 ", "com8 ", "com9 ", + "lpt1 ", "lpt2 ", "lpt3 ", "lpt4 ", "lpt5 ", + "lpt6 ", "lpt7 ", "lpt8 ", "lpt9 ", NULL }; @@ -245,16 +245,32 @@ static int vfat_find(struct inode *dir,struct qstr* name, int find_long,int new_filename,int is_dir, struct slot_info *sinfo_out); -/* Checks the validity of an long MS-DOS filename */ +static int strnicmp(const char *s1, const char *s2, int len) +{ + int n = 0; + while (*s1 && *s2 && (tolower(*s1) == tolower(*s2))) { + s1++; s2++; n++; + if (n == len) return 0; + } + if (*s1 == 0 && *s2 == 0) return 0; + if (*s1 && *s2) { + if (*s1 > *s2) return 1; + return -1; + } + if (*s1) return 1; + return -1; +} + +/* Checks the validity of a long MS-DOS filename */ /* Returns negative number on error, 0 for a normal * return, and 1 for . or .. */ static int vfat_valid_longname(const char *name, int len, int dot_dirs, int xlate) { - const char **reserved; + const char **reserved, *walk; unsigned char c; - int i; + int i, baselen; if (IS_FREE(name)) return -EINVAL; if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.'))) { @@ -271,9 +287,21 @@ static int vfat_valid_longname(const char *name, int len, int dot_dirs, return -EINVAL; } } - if (len == 3 || len == 4) { - for (reserved = reserved_names; *reserved; reserved++) - if (!strncmp(name,*reserved,8)) return -EINVAL; + if (len < 3) return 0; + + for (walk = name; *walk != 0 && *walk != '.'; walk++); + baselen = walk - name; + + if (baselen == 3) { + for (reserved = reserved3_names; *reserved; reserved++) { + if (!strnicmp(name,*reserved,baselen)) + return -EINVAL; + } + } else if (baselen == 4) { + for (reserved = reserved4_names; *reserved; reserved++) { + if (!strnicmp(name,*reserved,baselen)) + return -EINVAL; + } } return 0; } @@ -284,6 +312,7 @@ static int vfat_valid_shortname(const char *name,int len, const char *walk, **reserved; unsigned char c; int space; + int baselen; if (IS_FREE(name)) return -EINVAL; if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.'))) { @@ -312,7 +341,9 @@ static int vfat_valid_shortname(const char *name,int len, if (c != '.') return -EINVAL; } while (c != '.' && len--) c = *walk++; + baselen = walk - name; if (c == '.') { + baselen--; if (len >= 4) return -EINVAL; while (len > 0 && walk-name < (MSDOS_NAME+1)) { c = *walk++; @@ -329,8 +360,13 @@ static int vfat_valid_shortname(const char *name,int len, if (space) return -EINVAL; if (len) return -EINVAL; } - for (reserved = reserved_names; *reserved; reserved++) - if (!strncmp(name,*reserved,8)) return -EINVAL; + if (baselen == 3) { + for (reserved = reserved3_names; *reserved; reserved++) + if (!strnicmp(name,*reserved,baselen)) return -EINVAL; + } else if (baselen == 4) { + for (reserved = reserved4_names; *reserved; reserved++) + if (!strnicmp(name,*reserved,baselen)) return -EINVAL; + } return 0; } @@ -341,7 +377,7 @@ static int vfat_valid_shortname(const char *name,int len, */ static int vfat_format_name(const char *name,int len,char *res, - int dot_dirs,int utf8) + int dot_dirs,int utf8) { char *walk; const char **reserved; @@ -396,8 +432,10 @@ static int vfat_format_name(const char *name,int len,char *res, if (len) return -EINVAL; } while (walk-res < MSDOS_NAME) *walk++ = ' '; - for (reserved = reserved_names; *reserved; reserved++) - if (!strncmp(res,*reserved,8)) return -EINVAL; + for (reserved = reserved3_names; *reserved; reserved++) + if (!strnicmp(res,*reserved,8)) return -EINVAL; + for (reserved = reserved4_names; *reserved; reserved++) + if (!strnicmp(res,*reserved,8)) return -EINVAL; return 0; } @@ -605,8 +643,8 @@ static loff_t vfat_find_free_slots(struct inode *dir,int slots) /* Directory slots of busy deleted files aren't available yet. */ done = !MSDOS_I(inode)->i_busy; /* PRINTK(("inode %d still busy\n", ino)); */ + iput(inode); } - iput(inode); } if (done) { row++; @@ -995,7 +1033,6 @@ cleanup: int vfat_lookup(struct inode *dir,struct dentry *dentry) { int res; - struct inode *next; struct slot_info sinfo; struct inode *result; @@ -1014,7 +1051,7 @@ int vfat_lookup(struct inode *dir,struct dentry *dentry) if (!result->i_sb || (result->i_sb->s_magic != MSDOS_SUPER_MAGIC)) { /* crossed a mount point into a non-msdos fs */ - d_add(dentry,result); + d_add(dentry,NULL); return 0; } if (MSDOS_I(result)->i_busy) { /* mkdir in progress */ @@ -1023,18 +1060,7 @@ int vfat_lookup(struct inode *dir,struct dentry *dentry) return 0; } PRINTK (("vfat_lookup 6\n")); - while (MSDOS_I(result)->i_old) { - next = MSDOS_I(result)->i_old; - iput(result); - if (!(result = iget(next->i_sb,next->i_ino))) { - fat_fs_panic(dir->i_sb,"vfat_lookup: Can't happen"); - iput(dir); - return -ENOENT; - } - } - PRINTK (("vfat_lookup 7\n")); d_add(dentry,result); - PRINTK (("vfat_lookup 8\n")); return 0; } @@ -1091,10 +1117,12 @@ int vfat_create(struct inode *dir,struct dentry* dentry,int mode) result=NULL; fat_lock_creation(); res = vfat_create_entry(dir,&dentry->d_name,0,&result); - if (res < 0) PRINTK(("vfat_create: unable to get new entry\n")); - fat_unlock_creation(); - d_instantiate(dentry,result); + if (res < 0) { + PRINTK(("vfat_create: unable to get new entry\n")); + } else { + d_instantiate(dentry,result); + } return res; } @@ -1123,9 +1151,10 @@ static int vfat_create_a_dotdir(struct inode *dir,struct inode *parent, de->adate = de->cdate = de->date; de->size = 0; fat_mark_buffer_dirty(sb, bh, 1); - if ((dot = iget(dir->i_sb,ino)) != NULL) - vfat_read_inode(dot); - if (!dot) return -EIO; + dot = iget(dir->i_sb,ino); + if (!dot) + return -EIO; + vfat_read_inode(dot); dot->i_mtime = dot->i_atime = CURRENT_TIME; mark_inode_dirty(dot); if (isdot) { @@ -1192,8 +1221,15 @@ static int vfat_empty(struct inode *dir) struct buffer_head *bh; struct msdos_dir_entry *de; - if (dir->i_count > 1) + /* + * Prune any child dentries, then verify that + * the directory is empty and not in use. + */ + shrink_dcache_sb(sb); /* should be child prune */ + + if (dir->i_count > 1) { return -EBUSY; + } if (MSDOS_I(dir)->i_start) { /* may be zero in mkdir */ pos = 0; bh = NULL; @@ -1288,7 +1324,6 @@ static int vfat_remove_entry(struct inode *dir,struct slot_info *sinfo, for (i = sinfo->long_slots; i > 0; --i) { res = fat_get_entry(dir, &offset, bh, &de); if (res < 0) { - printk("vfat_remove_entry: problem 1\n"); continue; } de->name[0] = DELETED_FLAG; @@ -1306,24 +1341,17 @@ static int vfat_rmdirx(struct inode *dir,struct dentry* dentry) struct buffer_head *bh; struct slot_info sinfo; - bh = NULL; - res = -EPERM; - if (dentry->d_name.name[0] == '.' && - (dentry->d_name.len == 1 || (dentry->d_name.len == 2 && - dentry->d_name.name[1] == '.'))) - goto rmdir_done; res = vfat_find(dir,&dentry->d_name,1,0,0,&sinfo); if (res >= 0 && sinfo.total_slots > 0) { + bh = NULL; res = vfat_remove_entry(dir,&sinfo,&bh,dentry,1,0); if (res > 0) { res = 0; } dir->i_version = ++event; + if (bh) fat_brelse(sb, bh); } - -rmdir_done: - fat_brelse(sb, bh); return res; } @@ -1331,9 +1359,10 @@ rmdir_done: int vfat_rmdir(struct inode *dir,struct dentry* dentry) { int res; - res = vfat_rmdirx(dir, dentry); - d_delete(dentry); + if (res >= 0) { + d_delete(dentry); + } return res; } @@ -1357,7 +1386,7 @@ static int vfat_unlinkx( } } - fat_brelse(sb, bh); + if (bh) fat_brelse(sb, bh); return res; } @@ -1394,7 +1423,9 @@ int vfat_unlink(struct inode *dir,struct dentry* dentry) int res; res = vfat_unlinkx (dir,dentry,1); - d_delete(dentry); + if (res >= 0) { + d_delete(dentry); + } return res; } @@ -1633,22 +1664,3 @@ void cleanup_module(void) } #endif /* ifdef MODULE */ - - - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 8 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -8 - * c-argdecl-indent: 8 - * c-label-offset: -8 - * c-continued-statement-offset: 8 - * c-continued-brace-offset: 0 - * End: - */ |