diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-03-18 17:17:51 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-03-18 17:17:51 +0000 |
commit | f1382dc4850bb459d24a81c6cb0ef93ea7bd4a79 (patch) | |
tree | 225271a3d5dcd4e9dea5ee393556abd754c964b1 /fs | |
parent | 135b00fc2e90e605ac2a96b20b0ebd93851a3f89 (diff) |
o Merge with Linux 2.1.90.
o Divide L1 cache sizes by 1024 before printing, makes the numbers a
bit more credible ...
Diffstat (limited to 'fs')
55 files changed, 1236 insertions, 759 deletions
diff --git a/fs/buffer.c b/fs/buffer.c index 7e45b223e..ec844de9f 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -731,7 +731,8 @@ static void refill_freelist(int size) /* We are going to try to locate this much memory. */ needed = bdf_prm.b_un.nrefill * size; - while ((nr_free_pages > min_free_pages*2) && + while ((nr_free_pages > freepages.min*2) && + BUFFER_MEM < (buffer_mem.max_percent * num_physpages / 100) && grow_buffers(GFP_BUFFER, size)) { obtained += PAGE_SIZE; if (obtained >= needed) @@ -815,7 +816,8 @@ repeat: * are _any_ free buffers. */ while (obtained < (needed >> 1) && - nr_free_pages > min_free_pages + 5 && + nr_free_pages > freepages.min + 5 && + BUFFER_MEM < (buffer_mem.max_percent * num_physpages / 100) && grow_buffers(GFP_BUFFER, size)) obtained += PAGE_SIZE; diff --git a/fs/coda/Makefile b/fs/coda/Makefile index 0a4140745..1f2d0a94c 100644 --- a/fs/coda/Makefile +++ b/fs/coda/Makefile @@ -3,7 +3,7 @@ # O_TARGET := coda.o -O_OBJS := psdev.o cache.o cnode.o super.o dir.o file.o upcall.o coda_linux.o\ +O_OBJS := psdev.o cache.o cnode.o inode.o dir.o file.o upcall.o coda_linux.o\ symlink.o pioctl.o sysctl.o M_OBJS := $(O_TARGET) diff --git a/fs/coda/cache.c b/fs/coda/cache.c index 7673bfbdd..cdf586507 100644 --- a/fs/coda/cache.c +++ b/fs/coda/cache.c @@ -24,16 +24,22 @@ #include <linux/coda_fs_i.h> #include <linux/coda_cache.h> -/* Keep various stats */ -struct cfsnc_statistics cfsnc_stat; +static void coda_ccinsert(struct coda_cache *el, struct super_block *sb); +static void coda_cninsert(struct coda_cache *el, struct coda_inode_info *cii); +static void coda_ccremove(struct coda_cache *el); +static void coda_cnremove(struct coda_cache *el); +static void coda_cache_create(struct inode *inode, int mask); +static struct coda_cache * coda_cache_find(struct inode *inode); -/* we need to call INIT_LIST_HEAD on cnp->c_cnhead and sbi->sbi_cchead */ +/* Keep various stats */ +struct cfsnc_statistics cfsnc_stat; -void coda_ccinsert(struct coda_cache *el, struct super_block *sb) +/* insert a acl-cache entry in sb list */ +static void coda_ccinsert(struct coda_cache *el, struct super_block *sb) { struct coda_sb_info *sbi = coda_sbp(sb); -ENTRY; + ENTRY; if ( !sbi || !el) { printk("coda_ccinsert: NULL sbi or el!\n"); return ; @@ -42,17 +48,19 @@ ENTRY; list_add(&el->cc_cclist, &sbi->sbi_cchead); } -void coda_cninsert(struct coda_cache *el, struct coda_inode_info *cnp) +/* insert a acl-cache entry in the inode list */ +static void coda_cninsert(struct coda_cache *el, struct coda_inode_info *cii) { -ENTRY; - if ( !cnp || !el) { - printk("coda_cninsert: NULL cnp or el!\n"); + ENTRY; + if ( !cii || !el) { + printk("coda_cninsert: NULL cii or el!\n"); return ; } - list_add(&el->cc_cnlist, &cnp->c_cnhead); + list_add(&el->cc_cnlist, &cii->c_cnhead); } -void coda_ccremove(struct coda_cache *el) +/* remove a cache entry from the superblock list */ +static void coda_ccremove(struct coda_cache *el) { ENTRY; if (el->cc_cclist.next && el->cc_cclist.prev) @@ -61,7 +69,8 @@ void coda_ccremove(struct coda_cache *el) printk("coda_cnremove: trying to remove 0 entry!"); } -void coda_cnremove(struct coda_cache *el) +/* remove a cache entry from the inode's list */ +static void coda_cnremove(struct coda_cache *el) { ENTRY; if (el->cc_cnlist.next && el->cc_cnlist.prev) @@ -70,10 +79,10 @@ void coda_cnremove(struct coda_cache *el) printk("coda_cnremove: trying to remove 0 entry!"); } - -void coda_cache_create(struct inode *inode, int mask) +/* create a new cache entry and enlist it */ +static void coda_cache_create(struct inode *inode, int mask) { - struct coda_inode_info *cnp = ITOC(inode); + struct coda_inode_info *cii = ITOC(inode); struct super_block *sb = inode->i_sb; struct coda_cache *cc = NULL; ENTRY; @@ -85,17 +94,19 @@ void coda_cache_create(struct inode *inode, int mask) } coda_load_creds(&cc->cc_cred); cc->cc_mask = mask; - coda_cninsert(cc, cnp); + coda_cninsert(cc, cii); coda_ccinsert(cc, sb); } -struct coda_cache * coda_cache_find(struct inode *inode) +/* see if there is a match for the current + credentials already */ +static struct coda_cache * coda_cache_find(struct inode *inode) { - struct coda_inode_info *cnp = ITOC(inode); + struct coda_inode_info *cii = ITOC(inode); struct list_head *lh, *le; struct coda_cache *cc = NULL; - le = lh = &cnp->c_cnhead; + le = lh = &cii->c_cnhead; while( (le = le->next ) != lh ) { /* compare name and creds */ cc = list_entry(le, struct coda_cache, cc_cnlist); @@ -107,6 +118,7 @@ struct coda_cache * coda_cache_find(struct inode *inode) return NULL; } +/* create or extend an acl cache hit */ void coda_cache_enter(struct inode *inode, int mask) { struct coda_cache *cc; @@ -120,17 +132,21 @@ void coda_cache_enter(struct inode *inode, int mask) } } -void coda_cache_clear_cnp(struct coda_inode_info *cnp) +/* remove all cached acl matches from an inode */ +void coda_cache_clear_inode(struct inode *inode) { struct list_head *lh, *le; + struct coda_inode_info *cii; struct coda_cache *cc; + ENTRY; - if ( !cnp ) { - printk("coda_cache_cnp_clear: NULL cnode\n"); + if ( !inode ) { + CDEBUG(D_CACHE, "coda_cache_clear_inode: NULL inode\n"); return; } + cii = ITOC(inode); - lh = le = &cnp->c_cnhead; + lh = le = &cii->c_cnhead; while ( (le = le->next ) != lh ) { cc = list_entry(le, struct coda_cache, cc_cnlist); coda_cnremove(cc); @@ -139,6 +155,7 @@ void coda_cache_clear_cnp(struct coda_inode_info *cnp) } } +/* remove all acl caches */ void coda_cache_clear_all(struct super_block *sb) { struct list_head *lh, *le; @@ -150,6 +167,9 @@ void coda_cache_clear_all(struct super_block *sb) return; } + if ( list_empty(&sbi->sbi_cchead) ) + return; + lh = le = &sbi->sbi_cchead; while ( (le = le->next ) != lh ) { cc = list_entry(le, struct coda_cache, cc_cclist); @@ -159,6 +179,7 @@ void coda_cache_clear_all(struct super_block *sb) } } +/* remove all acl caches for a principal */ void coda_cache_clear_cred(struct super_block *sb, struct coda_cred *cred) { struct list_head *lh, *le; @@ -170,6 +191,9 @@ void coda_cache_clear_cred(struct super_block *sb, struct coda_cred *cred) return; } + if (list_empty(&sbi->sbi_cchead)) + return; + lh = le = &sbi->sbi_cchead; while ( (le = le->next ) != lh ) { cc = list_entry(le, struct coda_cache, cc_cclist); @@ -180,15 +204,17 @@ void coda_cache_clear_cred(struct super_block *sb, struct coda_cred *cred) } } } - + +/* check if the mask has been matched against the acl + already */ int coda_cache_check(struct inode *inode, int mask) { - struct coda_inode_info *cnp = ITOC(inode); + struct coda_inode_info *cii = ITOC(inode); struct list_head *lh, *le; struct coda_cache *cc = NULL; - le = lh = &cnp->c_cnhead; + le = lh = &cii->c_cnhead; while( (le = le->next ) != lh ) { /* compare name and creds */ cc = list_entry(le, struct coda_cache, cc_cnlist); @@ -204,110 +230,70 @@ int coda_cache_check(struct inode *inode, int mask) } -/* DENTRY related stuff */ +/* DCACHE & ZAPPING related stuff */ -/* when the dentry count falls to 0 this is called. If Venus has - asked for it to be flushed, we take it out of the dentry hash - table with d_drop */ - -static void coda_flag_children(struct dentry *parent) +/* the following routines set flags in the inodes. They are + detected by: + - a dentry method: coda_dentry_revalidate (for lookups) + if the flag is C_PURGE + - an inode method coda_revalidate (for attributes) if the + flag is C_ATTR +*/ +static void coda_flag_children(struct dentry *parent, int flag) { struct list_head *child; - struct coda_inode_info *cnp; struct dentry *de; child = parent->d_subdirs.next; while ( child != &parent->d_subdirs ) { de = list_entry(child, struct dentry, d_child); - cnp = ITOC(de->d_inode); - if (cnp) - cnp->c_flags |= C_ZAPFID; - CDEBUG(D_CACHE, "ZAPFID for %s\n", coda_f2s(&cnp->c_fid)); - + coda_flag_inode(de->d_inode, flag); + CDEBUG(D_CACHE, "%d for %*s/%*s\n", flag, + de->d_name.len, de->d_name.name, + de->d_parent->d_name.len, de->d_parent->d_name.name); child = child->next; + if ( !de->d_inode ) + d_drop(de); } return; } -/* flag dentry and possibly children of a dentry with C_ZAPFID */ -void coda_dentry_delete(struct dentry *dentry) -{ - struct inode *inode = dentry->d_inode; - struct coda_inode_info *cnp = NULL; - ENTRY; - if (inode) { - cnp = ITOC(inode); - if ( cnp ) - CHECK_CNODE(cnp); - } else { - CDEBUG(D_CACHE, "No inode for dentry_delete!\n"); - return; - } - - - if ( !cnp ) { - printk("No cnode for dentry_delete!\n"); - return; - } - - if ( cnp->c_flags & (C_ZAPFID | C_ZAPDIR) ) - d_drop(dentry); - if ( (cnp->c_flags & C_ZAPDIR) && S_ISDIR(inode->i_mode) ) { - coda_flag_children(dentry); - } - return; -} - -static void coda_zap_cnode(struct coda_inode_info *cnp, int flags) +void coda_flag_alias_children(struct inode *inode, int flag) { - cnp->c_flags |= flags; - coda_cache_clear_cnp(cnp); + struct list_head *alias; + struct dentry *alias_de; + + if ( !inode ) + return; + alias = inode->i_dentry.next; + while ( alias != &inode->i_dentry ) { + alias_de = list_entry(alias, struct dentry, d_alias); + if ( !alias_de ) { + printk("Corrupt alias list for %*s\n", + alias_de->d_name.len, alias_de->d_name.name); + return; + } + coda_flag_children(alias_de, flag); + alias= alias->next; + } } - - -/* the dache will notice the flags and drop entries (possibly with - children) the moment they are no longer in use */ -void coda_zapfid(struct ViceFid *fid, struct super_block *sb, int flag) +void coda_flag_inode(struct inode *inode, int flag) { - struct inode *inode = NULL; - struct coda_inode_info *cnp; + struct coda_inode_info *cii; - ENTRY; - - if ( !sb ) { - printk("coda_zapfid: no sb!\n"); + if ( !inode ) { + CDEBUG(D_CACHE, " no inode!\n"); return; } + cii = ITOC(inode); + cii->c_flags |= flag; +} - if ( !fid ) { - printk("coda_zapfid: no fid!\n"); - return; - } - if ( coda_fid_is_volroot(fid) ) { - struct list_head *lh, *le; - struct coda_sb_info *sbi = coda_sbp(sb); - le = lh = &sbi->sbi_volroothead; - while ( (le = le->next) != lh ) { - cnp = list_entry(le, struct coda_inode_info, c_volrootlist); - if ( cnp->c_fid.Volume == fid->Volume) - coda_zap_cnode(cnp, flag); - } - return; - } - inode = coda_fid_to_inode(fid, sb); - if ( !inode ) { - CDEBUG(D_CACHE, "coda_zapfid: no inode!\n"); - return; - } - cnp = ITOC(inode); - coda_zap_cnode(cnp, flag); -} - int cfsnc_nc_info(char *buffer, char **start, off_t offset, int length, int dummy) diff --git a/fs/coda/cnode.c b/fs/coda/cnode.c index 67133f275..aa67a22e4 100644 --- a/fs/coda/cnode.c +++ b/fs/coda/cnode.c @@ -15,8 +15,6 @@ extern int coda_print_entry; /* cnode.c */ - - static void coda_fill_inode (struct inode *inode, struct coda_vattr *attr) { CDEBUG(D_SUPER, "ino: %ld\n", inode->i_ino); @@ -56,8 +54,8 @@ int coda_cnode_make(struct inode **inode, ViceFid *fid, struct super_block *sb) ENTRY; /* - * We get inode numbers from Venus -- see venus source - */ + * We get inode numbers from Venus -- see venus source + */ error = venus_getattr(sb, fid, &attr); if ( error ) { @@ -79,7 +77,7 @@ int coda_cnode_make(struct inode **inode, ViceFid *fid, struct super_block *sb) memset(cnp, 0, (int) sizeof(struct coda_inode_info)); cnp->c_fid = *fid; cnp->c_magic = CODA_CNODE_MAGIC; - cnp->c_flags = C_VATTR; + cnp->c_flags = 0; cnp->c_vnode = *inode; INIT_LIST_HEAD(&(cnp->c_cnhead)); INIT_LIST_HEAD(&(cnp->c_volrootlist)); @@ -111,20 +109,51 @@ inline int coda_fideq(ViceFid *fid1, ViceFid *fid2) -/* convert a fid to an inode. Avoids having a hash table - such as present in the Mach minicache */ +/* convert a fid to an inode. Mostly we can compute + the inode number from the FID, but not for volume + mount points: those are in a list */ struct inode *coda_fid_to_inode(ViceFid *fid, struct super_block *sb) { ino_t nr; struct inode *inode; struct coda_inode_info *cnp; -ENTRY; + ENTRY; CDEBUG(D_INODE, "%s\n", coda_f2s(fid)); + if ( !sb ) { + printk("coda_fid_to_inode: no sb!\n"); + return NULL; + } + + if ( !fid ) { + printk("coda_fid_to_inode: no fid!\n"); + return NULL; + } + + + if ( coda_fid_is_volroot(fid) ) { + struct coda_inode_info *cii; + struct list_head *lh, *le; + struct coda_sb_info *sbi = coda_sbp(sb); + le = lh = &sbi->sbi_volroothead; + + while ( (le = le->next) != lh ) { + cii = list_entry(le, struct coda_inode_info, + c_volrootlist); + if ( cii->c_fid.Volume == fid->Volume) { + inode = cii->c_vnode; + CDEBUG(D_INODE, "volume root, found %ld\n", cii->c_vnode->i_ino); + return cii->c_vnode; + } + + } + return NULL; + } + + /* fid is not volume root, hence ino is computable */ nr = coda_f2i(fid); inode = iget(sb, nr); - if ( !inode ) { printk("coda_fid_to_inode: null from iget, sb %p, nr %ld.\n", sb, nr); @@ -133,19 +162,25 @@ ENTRY; /* check if this inode is linked to a cnode */ cnp = ITOC(inode); - if ( cnp->c_magic != CODA_CNODE_MAGIC ) { + CDEBUG(D_INODE, "uninitialized inode. Return.\n"); iput(inode); return NULL; } - /* make sure fid is the one we want */ - if ( !coda_fideq(fid, &(cnp->c_fid)) ) { + /* make sure fid is the one we want; + unfortunately Venus will shamelessly send us mount-symlinks. + These have the same inode as the root of the volume they + mount, but the fid will be wrong. + */ + if ( !coda_fideq(fid, &(cnp->c_fid)) && + !coda_fid_is_volroot(&(cnp->c_fid))) { printk("coda_fid2inode: bad cnode! Tell Peter.\n"); iput(inode); return NULL; } + CDEBUG(D_INODE, "found %ld\n", inode->i_ino); iput(inode); return inode; } diff --git a/fs/coda/coda_linux.c b/fs/coda/coda_linux.c index e968f3add..4fe096df9 100644 --- a/fs/coda/coda_linux.c +++ b/fs/coda/coda_linux.c @@ -32,14 +32,15 @@ int coda_access_cache = 1; /* caller must allocate 36 byte string ! */ char * coda_f2s(ViceFid *f) { - static char s[50]; + static char s[60]; if ( f ) { - sprintf(s, "(%10lx,%10lx,%10lx)", + sprintf(s, "(%-#lx,%-#lx,%-#lx)", f->Volume, f->Vnode, f->Unique); } return s; } +/* recognize special .CONTROL name */ int coda_iscontrol(const char *name, size_t length) { if ((CFS_CONTROLLEN == length) && @@ -48,16 +49,23 @@ int coda_iscontrol(const char *name, size_t length) return 0; } +/* recognize /coda inode */ int coda_isroot(struct inode *i) { if ( i->i_sb->s_root->d_inode == i ) { - return 1; + return 1; } else { - return 0; + return 0; } } - +/* is this a volume root FID */ +int coda_fid_is_volroot(struct ViceFid *fid) +{ + return ( (fid->Vnode == 1) && (fid->Unique == 1 ) ); +} + +/* put the current process credentials in the cred */ void coda_load_creds(struct coda_cred *cred) { cred->cr_uid = (vuid_t) current->uid; @@ -98,11 +106,6 @@ unsigned short coda_flags_to_cflags(unsigned short flags) } -int coda_fid_is_volroot(struct ViceFid *fid) -{ - return ( (fid->Vnode == 1) && (fid->Unique == 1 ) ); -} - /* utility functions below */ void coda_vattr_to_iattr(struct inode *inode, struct coda_vattr *attr) { diff --git a/fs/coda/dir.c b/fs/coda/dir.c index dd20499dc..8fed69242 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c @@ -40,17 +40,21 @@ static int coda_rename(struct inode *old_inode, struct dentry *old_dentry, /* dir file-ops */ static int coda_readdir(struct file *file, void *dirent, filldir_t filldir); +/* dentry ops */ +int coda_dentry_revalidate(struct dentry *de); + /* support routines */ static int coda_venus_readdir(struct file *filp, void *dirent, filldir_t filldir); int coda_fsync(struct file *, struct dentry *dentry); +static int coda_refresh_inode(struct dentry *dentry); struct dentry_operations coda_dentry_operations = { - NULL, /* revalidate */ + coda_dentry_revalidate, /* revalidate */ NULL, /* hash */ NULL, - coda_dentry_delete + NULL, }; struct inode_operations coda_dir_inode_operations = @@ -74,7 +78,7 @@ struct inode_operations coda_dir_inode_operations = coda_permission, /* permission */ NULL, /* smap */ NULL, /* update page */ - NULL /* revalidate */ + coda_revalidate_inode /* revalidate */ }; struct file_operations coda_dir_operations = { @@ -117,7 +121,6 @@ static int coda_lookup(struct inode *dir, struct dentry *entry) } dircnp = ITOC(dir); - CHECK_CNODE(dircnp); if ( length > CFS_MAXNAMLEN ) { printk("name too long: lookup, %s (%*s)\n", @@ -141,9 +144,13 @@ static int coda_lookup(struct inode *dir, struct dentry *entry) (const char *)name, length, &type, &resfid); res_inode = NULL; - if (!error || (error == -CFS_NOCACHE) ) { - if (error == -CFS_NOCACHE) + if (!error) { + if (type & CFS_NOCACHE) { + type &= (~CFS_NOCACHE); + CDEBUG(D_INODE, "dropme set for %s\n", + coda_f2s(&resfid)); dropme = 1; + } error = coda_cnode_make(&res_inode, &resfid, dir->i_sb); if (error) return -error; @@ -152,7 +159,7 @@ static int coda_lookup(struct inode *dir, struct dentry *entry) coda_f2s(&dircnp->c_fid), length, name, error); return error; } - CDEBUG(D_INODE, "lookup: %s is (%s) type %d result %d, dropme %d\n", + CDEBUG(D_INODE, "lookup: %s is (%s), type %d result %d, dropme %d\n", name, coda_f2s(&resfid), type, error, dropme); exit: @@ -228,7 +235,6 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode) CHECK_CNODE(dircnp); if ( length > CFS_MAXNAMLEN ) { - char str[50]; printk("name too long: create, %s(%s)\n", coda_f2s(&dircnp->c_fid), name); return -ENAMETOOLONG; @@ -238,7 +244,6 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode) 0, mode, &newfid, &attrs); if ( error ) { - char str[50]; CDEBUG(D_INODE, "create: %s, result %d\n", coda_f2s(&newfid), error); d_drop(de); @@ -321,7 +326,6 @@ static int coda_link(struct dentry *source_de, struct inode *dir_inode, const char * name = de->d_name.name; int len = de->d_name.len; struct coda_inode_info *dir_cnp, *cnp; - char str[50]; int error; ENTRY; @@ -408,7 +412,6 @@ int coda_unlink(struct inode *dir, struct dentry *de) int error; const char *name = de->d_name.name; int len = de->d_name.len; - char fidstr[50]; ENTRY; @@ -781,3 +784,82 @@ exit: CODA_FREE(buff, size); return error; } + +int coda_dentry_revalidate(struct dentry *de) +{ + int valid = 1; + struct inode *inode = de->d_inode; + struct coda_inode_info *cii; + ENTRY; + + if (inode) { + if (is_bad_inode(inode)) + return 0; + cii = ITOC(de->d_inode); + if (cii->c_flags & C_PURGE) + valid = 0; + } + return valid || coda_isroot(de->d_inode); +} + + +static int coda_refresh_inode(struct dentry *dentry) +{ + struct coda_vattr attr; + int error; + int old_mode; + ino_t old_ino; + struct inode *inode = dentry->d_inode; + struct coda_inode_info *cii = ITOC(inode); + + ENTRY; + error = venus_getattr(inode->i_sb, &(cii->c_fid), &attr); + if ( error ) { + make_bad_inode(inode); + return -EIO; + } + + /* this baby may be lost if: + - it's type changed + - it's ino changed + */ + old_mode = inode->i_mode; + old_ino = inode->i_ino; + coda_vattr_to_iattr(inode, &attr); + + if ((inode->i_ino != old_ino) || + ((old_mode & S_IFMT) != (inode->i_mode & S_IFMT))) { + make_bad_inode(inode); + inode->i_mode = old_mode; + return -EIO; + } + + cii->c_flags &= ~C_VATTR; + return 0; +} + + +/* + * This is called when we want to check if the inode has + * changed on the server. Coda makes this easy since the + * cache manager Venus issues a downcall to the kernel when this + * happens + */ + +int coda_revalidate_inode(struct dentry *dentry) +{ + int error = 0; + struct coda_inode_info *cii = ITOC(dentry->d_inode); + + ENTRY; + CDEBUG(D_INODE, "revalidating: %*s/%*s\n", + dentry->d_name.len, dentry->d_name.name, + dentry->d_parent->d_name.len, dentry->d_parent->d_name.name); + + if ( cii->c_flags & (C_VATTR | C_PURGE )) { + error = coda_refresh_inode(dentry); + } + + return error; +} + diff --git a/fs/coda/file.c b/fs/coda/file.c index b33680cc3..ae1dd9776 100644 --- a/fs/coda/file.c +++ b/fs/coda/file.c @@ -30,7 +30,7 @@ static ssize_t coda_file_read(struct file *f, char *buf, size_t count, loff_t *o static ssize_t coda_file_write(struct file *f, const char *buf, size_t count, loff_t *off); static int coda_file_mmap(struct file * file, struct vm_area_struct * vma); -/* exported from this file */ +/* also exported from this file (used for dirs) */ int coda_fsync(struct file *, struct dentry *dentry); struct inode_operations coda_file_inode_operations = { @@ -43,7 +43,7 @@ struct inode_operations coda_file_inode_operations = { NULL, /* mkdir */ NULL, /* rmdir */ NULL, /* mknod */ - NULL, /* rename */ + NULL, /* rename */ NULL, /* readlink */ NULL, /* follow_link */ coda_readpage, /* readpage */ @@ -53,7 +53,7 @@ struct inode_operations coda_file_inode_operations = { coda_permission, /* permission */ NULL, /* smap */ NULL, /* update page */ - NULL /* revalidate */ + coda_revalidate_inode /* revalidate */ }; struct file_operations coda_file_operations = { @@ -74,41 +74,47 @@ struct file_operations coda_file_operations = { }; /* File file operations */ -static int coda_readpage(struct file * file, struct page * page) +static int coda_readpage(struct file * coda_file, struct page * page) { - struct dentry *de = file->f_dentry; - struct inode *inode = de->d_inode; + struct dentry *de = coda_file->f_dentry; + struct inode *coda_inode = de->d_inode; struct dentry cont_dentry; - struct inode *cont_inode; - struct coda_inode_info *cnp; + struct file cont_file; + struct coda_inode_info *cii; ENTRY; - cnp = ITOC(inode); - CHECK_CNODE(cnp); + cii = ITOC(coda_inode); - if ( ! cnp->c_ovp ) { - printk("coda_readpage: no open inode for ino %ld\n", inode->i_ino); + if ( ! cii->c_ovp ) { + printk("coda_readpage: no open inode for ino %ld, %s\n", + coda_inode->i_ino, de->d_name.name); return -ENXIO; } + + coda_prepare_openfile(coda_inode, coda_file, cii->c_ovp, + &cont_file, &cont_dentry); - cont_inode = cnp->c_ovp; - cont_dentry.d_inode = cont_inode; - - CDEBUG(D_INODE, "coda ino: %ld, cached ino %ld, page offset: %lx\n", inode->i_ino, cont_inode->i_ino, page->offset); + CDEBUG(D_INODE, "coda ino: %ld, cached ino %ld, page offset: %lx\n", + coda_inode->i_ino, cii->c_ovp->i_ino, page->offset); - generic_readpage(&cont_dentry, page); + generic_readpage(&cont_file, page); EXIT; return 0; } static int coda_file_mmap(struct file * file, struct vm_area_struct * vma) { - struct coda_inode_info *cnp; - cnp = ITOC(file->f_dentry->d_inode); - cnp->c_mmcount++; + struct coda_inode_info *cii; + int res; + + ENTRY; + cii = ITOC(file->f_dentry->d_inode); + cii->c_mmcount++; - return generic_file_mmap(file, vma); + res =generic_file_mmap(file, vma); + EXIT; + return res; } static ssize_t coda_file_read(struct file *coda_file, char *buff, @@ -120,7 +126,6 @@ static ssize_t coda_file_read(struct file *coda_file, char *buff, struct file cont_file; struct dentry cont_dentry; int result = 0; - ENTRY; cnp = ITOC(coda_inode); diff --git a/fs/coda/super.c b/fs/coda/inode.c index 5410fb50d..96d07e265 100644 --- a/fs/coda/super.c +++ b/fs/coda/inode.c @@ -4,7 +4,7 @@ * Copryright (C) 1996 Peter J. Braam <braam@maths.ox.ac.uk> and * Michael Callahan <callahan@maths.ox.ac.uk> * - * Rewritten for Linux 2.1.?? Peter Braam <braam@cs.cmu.edu> + * Rewritten for Linux 2.1. Peter Braam <braam@cs.cmu.edu> * Copyright (C) Carnegie Mellon University */ @@ -81,7 +81,6 @@ static struct super_block * coda_read_super(struct super_block *sb, ViceFid fid; kdev_t dev = sb->s_dev; int error; - char str[50]; ENTRY; MOD_INC_USE_COUNT; @@ -180,10 +179,10 @@ static void coda_put_super(struct super_block *sb) /* all filling in of inodes postponed until lookup */ static void coda_read_inode(struct inode *inode) { - struct coda_inode_info *cnp; + struct coda_inode_info *cii; ENTRY; - cnp = ITOC(inode); - cnp->c_magic = 0; + cii = ITOC(inode); + cii->c_magic = 0; return; } @@ -200,32 +199,32 @@ static void coda_put_inode(struct inode *in) static void coda_delete_inode(struct inode *inode) { - struct coda_inode_info *cnp; + struct coda_inode_info *cii; struct inode *open_inode; ENTRY; CDEBUG(D_SUPER, " inode->ino: %ld, count: %d\n", inode->i_ino, inode->i_count); - cnp = ITOC(inode); - if ( inode->i_ino == CTL_INO || cnp->c_magic != CODA_CNODE_MAGIC ) { + cii = ITOC(inode); + if ( inode->i_ino == CTL_INO || cii->c_magic != CODA_CNODE_MAGIC ) { clear_inode(inode); return; } - if ( coda_fid_is_volroot(&cnp->c_fid) ) - list_del(&cnp->c_volrootlist); + if ( coda_fid_is_volroot(&cii->c_fid) ) + list_del(&cii->c_volrootlist); - open_inode = cnp->c_ovp; + open_inode = cii->c_ovp; if ( open_inode ) { CDEBUG(D_SUPER, "DELINO cached file: ino %ld count %d.\n", open_inode->i_ino, open_inode->i_count); - cnp->c_ovp = NULL; + cii->c_ovp = NULL; iput(open_inode); } - coda_cache_clear_cnp(cnp); + coda_cache_clear_inode(inode); inode->u.generic_ip = NULL; clear_inode(inode); @@ -235,24 +234,24 @@ static void coda_delete_inode(struct inode *inode) static int coda_notify_change(struct dentry *de, struct iattr *iattr) { struct inode *inode = de->d_inode; - struct coda_inode_info *cnp; + struct coda_inode_info *cii; struct coda_vattr vattr; int error; ENTRY; memset(&vattr, 0, sizeof(vattr)); - cnp = ITOC(inode); - CHECK_CNODE(cnp); + cii = ITOC(inode); + CHECK_CNODE(cii); coda_iattr_to_vattr(iattr, &vattr); vattr.va_type = C_VNON; /* cannot set type */ CDEBUG(D_SUPER, "vattr.va_mode %o\n", vattr.va_mode); - error = venus_setattr(inode->i_sb, &cnp->c_fid, &vattr); + error = venus_setattr(inode->i_sb, &cii->c_fid, &vattr); if ( !error ) { coda_vattr_to_iattr(inode, &vattr); - coda_cache_clear_cnp(cnp); + coda_cache_clear_inode(inode); } CDEBUG(D_SUPER, "inode.i_mode %o, error %d\n", inode->i_mode, error); diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c index 04333e046..119d14f51 100644 --- a/fs/coda/psdev.c +++ b/fs/coda/psdev.c @@ -65,7 +65,7 @@ extern int cfsnc_nc_info(char *buffer, char **start, off_t offset, int length, i /* statistics */ struct coda_upcallstats coda_callstats; int coda_hard = 0; /* introduces a timeout on upcalls */ -unsigned long coda_timeout = 10; /* .. secs, then signals will dequeue */ +unsigned long coda_timeout = 30; /* .. secs, then signals will dequeue */ extern struct coda_sb_info coda_super_info[MAX_CODADEVS]; struct vcomm psdev_vcomm[MAX_CODADEVS]; @@ -447,7 +447,7 @@ MODULE_AUTHOR("Peter J. Braam <braam@cs.cmu.edu>"); int init_module(void) { int status; - printk(KERN_INFO "Coda Kernel/User communications module 1.0\n"); + printk(KERN_INFO "Coda Kernel/User communications module 2.0\n"); status = init_coda_psdev(); if ( status ) { diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c index ac625ad17..13d3127c6 100644 --- a/fs/coda/upcall.c +++ b/fs/coda/upcall.c @@ -500,7 +500,6 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid, union outputArgs *outp; int insize, outsize, error; int iocsize; - char str[50]; insize = VC_MAXMSGSIZE; UPARG(CFS_IOCTL); @@ -587,7 +586,6 @@ int venus_pioctl(struct super_block *sb, struct ViceFid *fid, static inline void coda_waitfor_upcall(struct vmsg *vmp) { struct wait_queue wait = { current, NULL }; - old_sigset_t pending; vmp->vm_posttime = jiffies; @@ -608,13 +606,9 @@ static inline void coda_waitfor_upcall(struct vmsg *vmp) if ( jiffies > vmp->vm_posttime + coda_timeout * HZ ) break; - spin_lock_irq(¤t->sigmask_lock); - pending = current->blocked.sig[0] & current->signal.sig[0]; - spin_unlock_irq(¤t->sigmask_lock); - /* if this process really wants to die, let it go */ - if ( sigismember(&pending, SIGKILL) || - sigismember(&pending, SIGINT) ) + if ( sigismember(¤t->signal, SIGKILL) || + sigismember(¤t->signal, SIGINT) ) break; else schedule(); @@ -765,10 +759,14 @@ ENTRY; * This call is a result of token expiration. * * The next arise as the result of callbacks on a file or directory. - * CFS_ZAPDIR -- flush the attributes for the dir from its cnode. - * Zap all children of this directory from the namecache. * CFS_ZAPFILE -- flush the cached attributes for a file. - * CFS_ZAPVNODE -- intended to be a zapfile for just one cred. Not used? + + * CFS_ZAPDIR -- flush the attributes for the dir and + * force a new lookup for all the children + of this dir. + + * CFS_ZAPVNODE -- intended to be a zapfile for just one cred. + Not used? * * The next is a result of Venus detecting an inconsistent file. * CFS_PURGEFID -- flush the attribute for the file @@ -803,53 +801,48 @@ int coda_downcall(int opcode, union outputArgs * out, struct super_block *sb) return(0); } case CFS_ZAPDIR : { + struct inode *inode; ViceFid *fid = &out->cfs_zapdir.CodaFid; - char str[50]; if ( !fid ) { printk("ZAPDIR: Null fid\n"); return 0; } CDEBUG(D_DOWNCALL, "zapdir: fid = %s\n", coda_f2s(fid)); clstats(CFS_ZAPDIR); - coda_zapfid(fid, sb, C_ZAPDIR); - return(0); - } - case CFS_ZAPVNODE : { - ViceFid *fid = &out->cfs_zapvnode.VFid; - char str[50]; - struct coda_cred *cred = &out->cfs_zapvnode.cred; - if ( !fid || !cred ) { - printk("ZAPVNODE: Null fid or cred\n"); - return 0; - } - CDEBUG(D_DOWNCALL, "zapvnode: fid = %s\n", coda_f2s(fid)); - coda_zapfid(fid, sb, C_ZAPFID); - coda_cache_clear_cred(sb, cred); - clstats(CFS_ZAPVNODE); + inode = coda_fid_to_inode(fid, sb); + coda_flag_inode(inode, C_VATTR); + coda_cache_clear_inode(inode); + coda_flag_alias_children(inode, C_PURGE); return(0); } + + case CFS_ZAPVNODE : case CFS_ZAPFILE : { + struct inode *inode; struct ViceFid *fid = &out->cfs_zapfile.CodaFid; - char str[50]; clstats(CFS_ZAPFILE); if ( !fid ) { printk("ZAPFILE: Null fid\n"); return 0; } CDEBUG(D_DOWNCALL, "zapfile: fid = %s\n", coda_f2s(fid)); - coda_zapfid(fid, sb, C_ZAPFID); + inode = coda_fid_to_inode(fid, sb); + coda_flag_inode(inode, C_VATTR); + coda_cache_clear_inode(inode); return 0; } case CFS_PURGEFID : { + struct inode *inode; ViceFid *fid = &out->cfs_purgefid.CodaFid; - char str[50]; if ( !fid ) { printk("PURGEFID: Null fid\n"); return 0; } CDEBUG(D_DOWNCALL, "purgefid: fid = %s\n", coda_f2s(fid)); clstats(CFS_PURGEFID); - coda_zapfid(fid, sb, C_ZAPDIR); + inode = coda_fid_to_inode(fid, sb); + coda_flag_inode(inode, C_PURGE); + coda_cache_clear_inode(inode); return 0; } case CFS_REPLACE : { diff --git a/fs/devices.c b/fs/devices.c index 9cae0441e..6a8a60627 100644 --- a/fs/devices.c +++ b/fs/devices.c @@ -6,6 +6,7 @@ * Copyright (C) 1991, 1992 Linus Torvalds * * Added kerneld support: Jacques Gelinas and Bjorn Ekwall + * (changed to kmod) */ #include <linux/config.h> @@ -16,12 +17,12 @@ #include <linux/stat.h> #include <linux/fcntl.h> #include <linux/errno.h> -#ifdef CONFIG_KERNELD -#include <linux/kerneld.h> +#ifdef CONFIG_KMOD +#include <linux/kmod.h> #include <linux/tty.h> -/* serial module kerneld load support */ +/* serial module kmod load support */ struct tty_driver *get_tty_driver(kdev_t device); #define isa_tty_dev(ma) (ma == TTY_MAJOR || ma == TTYAUX_MAJOR) #define need_serial(ma,mi) (get_tty_driver(MKDEV(ma,mi)) == NULL) @@ -74,12 +75,12 @@ static struct file_operations * get_fops( struct file_operations *ret = NULL; if (major < maxdev){ -#ifdef CONFIG_KERNELD +#ifdef CONFIG_KMOD /* * I do get request for device 0. I have no idea why. It happen * at shutdown time for one. Without the following test, the * kernel will happily trigger a request_module() which will - * trigger kerneld and modprobe for nothing (since there + * trigger kmod and modprobe for nothing (since there * is no device with major number == 0. And furthermore * it locks the reboot process :-( * @@ -87,7 +88,7 @@ static struct file_operations * get_fops( * * A. Haritsis <ah@doc.ic.ac.uk>: fix for serial module * though we need the minor here to check if serial dev, - * we pass only the normal major char dev to kerneld + * we pass only the normal major char dev to kmod * as there is no other loadable dev on these majors */ if ((isa_tty_dev(major) && need_serial(major,minor)) || @@ -49,8 +49,9 @@ #include <asm/mmu_context.h> #include <linux/config.h> -#ifdef CONFIG_KERNELD -#include <linux/kerneld.h> + +#ifdef CONFIG_KMOD +#include <linux/kmod.h> #endif asmlinkage int sys_exit(int exit_code); @@ -421,6 +422,7 @@ static int exec_mmap(void) retval = new_page_tables(current); if (retval) goto fail_restore; + up(&mm->mmap_sem); mmput(old_mm); return 0; @@ -697,7 +699,7 @@ int search_binary_handler(struct linux_binprm *bprm,struct pt_regs *regs) } if (retval != -ENOEXEC) { break; -#ifdef CONFIG_KERNELD +#ifdef CONFIG_KMOD }else{ #define printable(c) (((c)=='\t') || ((c)=='\n') || (0x20<=(c) && (c)<=0x7e)) char modname[20]; diff --git a/fs/fcntl.c b/fs/fcntl.c index 8743916ee..5cfeb3658 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -9,6 +9,7 @@ #include <linux/errno.h> #include <linux/stat.h> #include <linux/fcntl.h> +#include <linux/file.h> #include <linux/string.h> #include <linux/mm.h> #include <linux/smp.h> @@ -22,18 +23,32 @@ extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg); static inline int dupfd(unsigned int fd, unsigned int arg) { struct files_struct * files = current->files; + struct file * file; + int error; - if (fd >= NR_OPEN || !files->fd[fd]) - return -EBADF; + error = -EINVAL; if (arg >= NR_OPEN) - return -EINVAL; + goto out; + + error = -EBADF; + file = fget(fd); + if (!file) + goto out; + + error = -EMFILE; arg = find_next_zero_bit(&files->open_fds, NR_OPEN, arg); if (arg >= current->rlim[RLIMIT_NOFILE].rlim_cur) - return -EMFILE; + goto out_putf; FD_SET(arg, &files->open_fds); FD_CLR(arg, &files->close_on_exec); - (files->fd[arg] = files->fd[fd])->f_count++; - return arg; + fd_install(arg, file); + error = arg; +out: + return error; + +out_putf: + fput(file); + goto out; } asmlinkage int sys_dup2(unsigned int oldfd, unsigned int newfd) @@ -41,7 +56,7 @@ asmlinkage int sys_dup2(unsigned int oldfd, unsigned int newfd) int err = -EBADF; lock_kernel(); - if (oldfd >= NR_OPEN || !current->files->fd[oldfd]) + if (!fcheck(oldfd)) goto out; err = newfd; if (newfd == oldfd) @@ -51,7 +66,7 @@ asmlinkage int sys_dup2(unsigned int oldfd, unsigned int newfd) goto out; /* following POSIX.1 6.2.1 */ sys_close(newfd); - err = dupfd(oldfd,newfd); + err = dupfd(oldfd, newfd); out: unlock_kernel(); return err; @@ -62,7 +77,7 @@ asmlinkage int sys_dup(unsigned int fildes) int ret; lock_kernel(); - ret = dupfd(fildes,0); + ret = dupfd(fildes, 0); unlock_kernel(); return ret; } @@ -101,12 +116,13 @@ asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) long err = -EBADF; lock_kernel(); - if (fd >= NR_OPEN || !(filp = current->files->fd[fd])) + filp = fget(fd); + if (!filp) goto out; err = 0; switch (cmd) { case F_DUPFD: - err = dupfd(fd,arg); + err = dupfd(fd, arg); break; case F_GETFD: err = FD_ISSET(fd, ¤t->files->close_on_exec); @@ -158,6 +174,7 @@ asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) err = -EINVAL; break; } + fput(filp); out: unlock_kernel(); return err; diff --git a/fs/filesystems.c b/fs/filesystems.c index 01a2a6d24..f56b35c53 100644 --- a/fs/filesystems.c +++ b/fs/filesystems.c @@ -30,8 +30,8 @@ #include <linux/major.h> #include <linux/smp.h> #include <linux/smp_lock.h> -#ifdef CONFIG_KERNELD -#include <linux/kerneld.h> +#ifdef CONFIG_KMOD +#include <linux/kmod.h> #endif #include <linux/lockd/bind.h> #include <linux/lockd/xdr.h> @@ -192,12 +192,12 @@ asmlinkage sys_nfsservctl(int cmd, void *argp, void *resp) ret = do_nfsservctl(cmd, argp, resp); goto out; } -#ifdef CONFIG_KERNELD +#ifdef CONFIG_KMOD if (request_module ("nfsd") == 0) { if (do_nfsservctl) ret = do_nfsservctl(cmd, argp, resp); } -#endif /* CONFIG_KERNELD */ +#endif /* CONFIG_KMOD */ out: unlock_kernel(); return ret; diff --git a/fs/hfs/ChangeLog b/fs/hfs/ChangeLog index aa465a0a6..c063e3f2d 100644 --- a/fs/hfs/ChangeLog +++ b/fs/hfs/ChangeLog @@ -1,12 +1,55 @@ -Wed Jan 7 19:33:33 1998 a sun <asun@zoology.washington.edu> +Wed Jan 21 14:04:26 1998 a sun <asun@zoology.washington.edu> + + * inode.c, sysdep.c + use d_iput to uncache dentry from catalog entry instead of relying + on put_inode. no more NULL pointer dereferences! + + * catalog.c + cleaned up hfs_cat_put a little. + + ISSUES (non-fatal): mv dir dir2 while creating files in dir screws + up directory counts. + + deletion using netatalk screws up directory + counts. + +Thu Jan 15 19:14:28 1998 a sun <asun@zoology.washington.edu> + + * catalog.c + make deletion happen when requested instead of waiting until + an hfs_cat_put as the dcache can hold onto entries for quite + some time. + +Wed Jan 14 14:43:16 1998 a sun <asun@zoology.washington.edu> + + * catalog.c + the current catalog allocation scheme allocates + PAGE_SIZE/sizeof(struct hfs_cat_entry) entries at a time and keeps + a pool of free entries up to this allocation unit * 8. * inode.c - don't hfs_cat_put in hfs_iget. that's a bad idea and results - in screwed up entry counts. + make sure to always hfs_cat_put if hfs_iget is going to return + NULL. + + * string.c, catalog.c + use linux' hashing method to generate hashes. the old hashing was + getting collisions. catalog.c also has a larger hash table to + prevent collisions. + +Tue Jan 13 13:06:01 1998 a sun <asun@zoology.washington.edu> + + * version.c + bumped to 0.95+asun3 * catalog.c - modified hfs_cat_put to undirty deleted entries without trying to - write them out. + re-wrote to dynamically allocate/delete catalog entries. on a 486, + entries fit into the size-256 slab. + +Wed Jan 7 19:33:33 1998 a sun <asun@zoology.washington.edu> + + * inode.c + don't hfs_cat_put gratuitously in hfs_iget. that's a bad + idea and results in screwed up entry counts. Tue Jan 6 14:38:24 1998 a sun <asun@zoology.washington.edu> diff --git a/fs/hfs/Makefile b/fs/hfs/Makefile index bab9a6e4b..7ea8e6560 100644 --- a/fs/hfs/Makefile +++ b/fs/hfs/Makefile @@ -1,5 +1,5 @@ # -# Makefile for the linux nfs-filesystem routines. +# Makefile for the linux hfs-filesystem routines. # # Note! Dependencies are done automagically by 'make dep', which also # removes any old dependencies. DON'T put your own dependencies here diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c index 4055012f1..2435ceb31 100644 --- a/fs/hfs/catalog.c +++ b/fs/hfs/catalog.c @@ -10,6 +10,7 @@ * * Cache code shamelessly stolen from * linux/fs/inode.c Copyright (C) 1991, 1992 Linus Torvalds + * re-shamelessly stolen Copyright (C) 1997 Linus Torvalds * * In function preconditions the term "valid" applied to a pointer to * a structure means that the pointer is non-NULL and the structure it @@ -24,16 +25,15 @@ /*================ Variable-like macros ================*/ -#define NUM_FREE_ENTRIES 8 - /* Number of hash table slots */ -#define CCACHE_NR 128 - -/* Max number of entries in memory */ -#define CCACHE_MAX 1024 +#define C_HASHBITS 10 +#define C_HASHSIZE (1UL << C_HASHBITS) +#define C_HASHMASK (C_HASHSIZE - 1) -/* Number of entries to fit in a single page on an i386 */ -#define CCACHE_INC ((PAGE_SIZE - sizeof(void *))/sizeof(struct hfs_cat_entry)) +/* Number of entries to fit in a single page on an i386. + * Actually, now it's used to increment the free entry pool. */ +#define CCACHE_INC (PAGE_SIZE/sizeof(struct hfs_cat_entry)) +#define CCACHE_MAX (CCACHE_INC * 8) /*================ File-local data types ================*/ @@ -94,18 +94,11 @@ struct hfs_cat_rec { } u; }; - -struct allocation_unit { - struct allocation_unit *next; - struct hfs_cat_entry entries[CCACHE_INC]; -}; - /*================ File-local variables ================*/ static LIST_HEAD(entry_in_use); -static LIST_HEAD(entry_dirty); /* all the dirty entries */ static LIST_HEAD(entry_unused); -static struct list_head hash_table[CCACHE_NR]; +static struct list_head hash_table[C_HASHSIZE]; spinlock_t entry_lock = SPIN_LOCK_UNLOCKED; @@ -114,8 +107,6 @@ static struct { int nr_free_entries; } entries_stat; -static struct allocation_unit *allocation = NULL; - /*================ File-local functions ================*/ /* @@ -136,13 +127,16 @@ static inline hfs_u32 brec_to_id(struct hfs_brec *brec) * * hash an (struct mdb *) and a (struct hfs_cat_key *) to an integer. */ -static inline unsigned int hashfn(const struct hfs_mdb *mdb, +static inline unsigned long hashfn(const struct hfs_mdb *mdb, const struct hfs_cat_key *key) { #define LSB(X) (((unsigned char *)(&X))[3]) - return ((unsigned int)LSB(mdb->create_date) ^ - (unsigned int)key->ParID[3] ^ - hfs_strhash(&key->CName)) % CCACHE_NR; + unsigned long hash; + + hash = (unsigned long) mdb | (unsigned long) key->ParID[3] | + hfs_strhash(&key->CName); + hash = hash ^ (hash >> C_HASHBITS) ^ (hash >> C_HASHBITS*2); + return hash & C_HASHMASK; #undef LSB } @@ -208,24 +202,7 @@ static void unlock_entry(struct hfs_cat_entry * entry) hfs_wake_up(&entry->wait); } -/* - * clear_entry() - * - * Zero all the fields of an entry and place it on the free list. - */ -static void clear_entry(struct hfs_cat_entry * entry) -{ - wait_on_entry(entry); - /* zero all but the wait queue */ - memset(&entry->wait, 0, - sizeof(*entry) - offsetof(struct hfs_cat_entry, wait)); - INIT_LIST_HEAD(&entry->hash); - INIT_LIST_HEAD(&entry->list); - INIT_LIST_HEAD(&entry->dirty); -} - -/* put entry on mdb dirty list. this only does it if it's on the hash - * list. we also add it to the global dirty list as well. */ +/* put entry on mdb dirty list. */ void hfs_cat_mark_dirty(struct hfs_cat_entry *entry) { struct hfs_mdb *mdb = entry->mdb; @@ -234,153 +211,74 @@ void hfs_cat_mark_dirty(struct hfs_cat_entry *entry) if (!(entry->state & HFS_DIRTY)) { entry->state |= HFS_DIRTY; - /* Only add valid (ie hashed) entries to the - * dirty list */ + /* Only add valid (ie hashed) entries to the dirty list. */ if (!list_empty(&entry->hash)) { list_del(&entry->list); list_add(&entry->list, &mdb->entry_dirty); - INIT_LIST_HEAD(&entry->dirty); - list_add(&entry->dirty, &entry_dirty); } } spin_unlock(&entry_lock); } -/* prune all entries */ -static void dispose_list(struct list_head *head) +/* delete an entry and remove it from the hash table. */ +static void delete_entry(struct hfs_cat_entry *entry) { - struct list_head *next; - int count = 0; - - next = head->next; - for (;;) { - struct list_head * tmp = next; - - next = next->next; - if (tmp == head) - break; - hfs_cat_prune(list_entry(tmp, struct hfs_cat_entry, list)); - count++; - } -} - -/* - * try_to_free_entries works by getting the underlying - * cache system to release entries. it gets called with the entry lock - * held. - * - * count can be up to 2 due to both a resource and data fork being - * listed. we can unuse dirty entries as well. - */ -#define CAN_UNUSE(tmp) (((tmp)->count < 3) && ((tmp)->state <= HFS_DIRTY)) -static int try_to_free_entries(const int goal) -{ - struct list_head *tmp, *head = &entry_in_use; - LIST_HEAD(freeable); - int found = 0, depth = goal << 1; - - /* try freeing from entry_in_use */ - while ((tmp = head->prev) != head && depth--) { - struct hfs_cat_entry *entry = - list_entry(tmp, struct hfs_cat_entry, list); - list_del(tmp); - if (CAN_UNUSE(entry)) { - list_del(&entry->hash); - INIT_LIST_HEAD(&entry->hash); - list_add(tmp, &freeable); - if (++found < goal) - continue; - break; + if (!(entry->state & HFS_DELETED)) { + entry->state |= HFS_DELETED; + list_del(&entry->hash); + INIT_LIST_HEAD(&entry->hash); + + if (entry->type == HFS_CDR_FIL) { + /* free all extents */ + entry->u.file.data_fork.lsize = 0; + hfs_extent_adj(&entry->u.file.data_fork); + entry->u.file.rsrc_fork.lsize = 0; + hfs_extent_adj(&entry->u.file.rsrc_fork); } - list_add(tmp, head); } +} - if (found < goal) { /* try freeing from global dirty list */ - head = &entry_dirty; - depth = goal << 1; - while ((tmp = head->prev) != head && depth--) { - struct hfs_cat_entry *entry = - list_entry(tmp, struct hfs_cat_entry, dirty); - list_del(tmp); - if (CAN_UNUSE(entry)) { - list_del(&entry->hash); - INIT_LIST_HEAD(&entry->hash); - list_del(&entry->list); - INIT_LIST_HEAD(&entry->list); - list_add(&entry->list, &freeable); - if (++found < goal) - continue; - break; - } - list_add(tmp, head); - } - } - - if (found) { - spin_unlock(&entry_lock); - dispose_list(&freeable); - spin_lock(&entry_lock); - } - return found; -} - -/* init_once */ -static inline void init_once(struct hfs_cat_entry *entry) +static inline void init_entry(struct hfs_cat_entry *entry) { - init_waitqueue(&entry->wait); + memset(entry, 0, sizeof(*entry)); + hfs_init_waitqueue(&entry->wait); INIT_LIST_HEAD(&entry->hash); INIT_LIST_HEAD(&entry->list); - INIT_LIST_HEAD(&entry->dirty); } /* - * grow_entries() + * hfs_cat_alloc() * - * Try to allocate more entries, adding them to the free list. this returns - * with the spinlock held if successful + * Try to allocate another entry. */ -static struct hfs_cat_entry *grow_entries(struct hfs_mdb *mdb) +static inline struct hfs_cat_entry *hfs_cat_alloc(void) { - struct allocation_unit *tmp; - struct hfs_cat_entry * entry; - int i; + struct hfs_cat_entry *entry; - spin_unlock(&entry_lock); - if ((entries_stat.nr_entries < CCACHE_MAX) && - HFS_NEW(tmp)) { - spin_lock(&entry_lock); - memset(tmp, 0, sizeof(*tmp)); - tmp->next = allocation; - allocation = tmp; - entry = tmp->entries; - for (i = 1; i < CCACHE_INC; i++) { - entry++; - init_once(entry); - list_add(&entry->list, &entry_unused); - } - init_once(tmp->entries); + if (!HFS_NEW(entry)) + return NULL; - entries_stat.nr_entries += CCACHE_INC; - entries_stat.nr_free_entries += CCACHE_INC - 1; - return tmp->entries; - } + init_entry(entry); + return entry; +} - /* allocation failed. do some pruning and try again */ - spin_lock(&entry_lock); - try_to_free_entries(entries_stat.nr_entries >> 2); - { - struct list_head *tmp = entry_unused.next; - if (tmp != &entry_unused) { - entries_stat.nr_free_entries--; - list_del(tmp); - entry = list_entry(tmp, struct hfs_cat_entry, list); - return entry; - } +/* this gets called with the spinlock held. */ +static int grow_entries(void) +{ + struct hfs_cat_entry *entry; + int i; + + for (i = 0; i < CCACHE_INC; i++) { + if (!(entry = hfs_cat_alloc())) + break; + list_add(&entry->list, &entry_unused); } - spin_unlock(&entry_lock); - return NULL; + entries_stat.nr_entries += i; + entries_stat.nr_free_entries += i; + + return i; } /* @@ -537,7 +435,8 @@ static void __write_entry(const struct hfs_cat_entry *entry, /* * write_entry() * - * Write a modified entry back to the catalog B-tree. + * Write a modified entry back to the catalog B-tree. this gets called + * with the entry locked. */ static void write_entry(struct hfs_cat_entry * entry) { @@ -577,6 +476,7 @@ static void write_entry(struct hfs_cat_entry * entry) } +/* this gets called with the spinlock held. */ static struct hfs_cat_entry *find_entry(struct hfs_mdb *mdb, const struct hfs_cat_key *key) { @@ -592,8 +492,9 @@ static struct hfs_cat_entry *find_entry(struct hfs_mdb *mdb, entry = list_entry(tmp, struct hfs_cat_entry, hash); if (entry->mdb != mdb) continue; - if (hfs_cat_compare(&entry->key, key)) + if (hfs_cat_compare(&entry->key, key)) { continue; + } entry->count++; break; } @@ -609,13 +510,14 @@ static struct hfs_cat_entry *get_new_entry(struct hfs_mdb *mdb, { struct hfs_cat_entry *entry; struct list_head *head = hash(mdb, key); - struct list_head *tmp = entry_unused.next; + struct list_head *tmp; - if (tmp != &entry_unused) { +add_new_entry: + tmp = entry_unused.next; + if ((tmp != &entry_unused) ) { list_del(tmp); entries_stat.nr_free_entries--; entry = list_entry(tmp, struct hfs_cat_entry, list); -add_new_entry: list_add(&entry->list, &entry_in_use); list_add(&entry->hash, head); entry->mdb = mdb; @@ -629,7 +531,8 @@ add_new_entry: if (hfs_bfind(&brec, mdb->cat_tree, HFS_BKEY(key), HFS_BFIND_READ_EQ)) { - /* uh oh. we failed to read the record */ + /* uh oh. we failed to read the record. + * the entry doesn't actually exist. */ entry->state |= HFS_DELETED; goto read_fail; } @@ -651,28 +554,18 @@ add_new_entry: return entry; } - /* - * Uhhuh.. We need to expand. Note that "grow_entries()" will - * release the spinlock, but will return with the lock held - * again if the allocation succeeded. - */ - entry = grow_entries(mdb); - if (entry) { - /* We released the lock, so.. */ - struct hfs_cat_entry * old = find_entry(mdb, key); - if (!old) - goto add_new_entry; - list_add(&entry->list, &entry_unused); - entries_stat.nr_free_entries++; - spin_unlock(&entry_lock); - wait_on_entry(old); - return old; - } - return entry; + /* try to allocate more entries. grow_entries() doesn't release + * the spinlock. */ + if (grow_entries()) + goto add_new_entry; + spin_unlock(&entry_lock); + return NULL; -read_fail: +read_fail: + /* spinlock unlocked already. we don't need to mark the entry + * dirty here because we know that it doesn't exist. */ remove_hash(entry); entry->state &= ~HFS_LOCK; hfs_wake_up(&entry->wait); @@ -694,11 +587,6 @@ static struct hfs_cat_entry *get_entry(struct hfs_mdb *mdb, struct hfs_cat_entry * entry; spin_lock(&entry_lock); - if (!entries_stat.nr_free_entries && - (entries_stat.nr_entries >= CCACHE_MAX)) - goto restock; - -search: entry = find_entry(mdb, key); if (!entry) { return get_new_entry(mdb, key, read); @@ -706,10 +594,6 @@ search: spin_unlock(&entry_lock); wait_on_entry(entry); return entry; - -restock: - try_to_free_entries(8); - goto search; } /* @@ -753,6 +637,9 @@ static void update_dir(struct hfs_mdb *mdb, struct hfs_cat_entry *dir, /* * Add a writer to dir, excluding readers. + * + * XXX: this is wrong. it allows a move to occur when a directory + * is being written to. */ static inline void start_write(struct hfs_cat_entry *dir) { @@ -880,7 +767,10 @@ static int create_entry(struct hfs_cat_entry *parent, struct hfs_cat_key *key, goto done; bail1: + /* entry really didn't exist, so we don't need to really delete it. + * we do need to remove it from the hash, though. */ entry->state |= HFS_DELETED; + remove_hash(entry); unlock_entry(entry); bail2: hfs_cat_put(entry); @@ -900,13 +790,21 @@ done: * entry that the entry is in a consistent state, since another * process may get the entry while we sleep. That is why we * 'goto repeat' after each operation that might sleep. + * + * ADDITIONAL NOTE: the sys_entries will remove themselves from + * the sys_entry list on the final iput, so we don't need + * to worry about them here. + * + * nothing in hfs_cat_put goes to sleep now except + * on the initial entry. */ void hfs_cat_put(struct hfs_cat_entry * entry) { if (entry) { wait_on_entry(entry); - if (!entry->count) {/* just in case */ + /* just in case. this should never happen. */ + if (!entry->count) { hfs_warn("hfs_cat_put: trying to free free entry: %p\n", entry); return; @@ -914,52 +812,41 @@ void hfs_cat_put(struct hfs_cat_entry * entry) spin_lock(&entry_lock); if (!--entry->count) { -repeat: - if ((entry->state & HFS_DELETED)) { - if (entry->type == HFS_CDR_FIL) { - /* free all extents */ - entry->u.file.data_fork.lsize = 0; - hfs_extent_adj(&entry->u.file.data_fork); - entry->u.file.rsrc_fork.lsize = 0; - hfs_extent_adj(&entry->u.file.rsrc_fork); - } - entry->state = 0; - } else if (entry->type == HFS_CDR_FIL) { + if ((entry->state & HFS_DELETED)) + goto entry_deleted; + + if ((entry->type == HFS_CDR_FIL)) { /* clear out any cached extents */ if (entry->u.file.data_fork.first.next) { hfs_extent_free(&entry->u.file.data_fork); - spin_unlock(&entry_lock); - wait_on_entry(entry); - spin_lock(&entry_lock); - goto repeat; } if (entry->u.file.rsrc_fork.first.next) { hfs_extent_free(&entry->u.file.rsrc_fork); - spin_unlock(&entry_lock); - wait_on_entry(entry); - spin_lock(&entry_lock); - goto repeat; } } /* if we put a dirty entry, write it out. */ if ((entry->state & HFS_DIRTY)) { - list_del(&entry->dirty); - INIT_LIST_HEAD(&entry->dirty); - spin_unlock(&entry_lock); + entry->state ^= HFS_DIRTY | HFS_LOCK; write_entry(entry); - spin_lock(&entry_lock); - entry->state &= ~HFS_DIRTY; - goto repeat; + entry->state &= ~HFS_LOCK; } list_del(&entry->hash); +entry_deleted: /* deleted entries have already been removed + * from the hash list. */ list_del(&entry->list); - spin_unlock(&entry_lock); - clear_entry(entry); - spin_lock(&entry_lock); - list_add(&entry->list, &entry_unused); - entries_stat.nr_free_entries++; + if (entries_stat.nr_free_entries > CCACHE_MAX) { + HFS_DELETE(entry); + entries_stat.nr_entries--; + } else { + spin_unlock(&entry_lock); + wait_on_entry(entry); + init_entry(entry); + spin_lock(&entry_lock); + list_add(&entry->list, &entry_unused); + entries_stat.nr_free_entries++; + } } spin_unlock(&entry_lock); } @@ -995,20 +882,37 @@ static void invalidate_list(struct list_head *head, struct hfs_mdb *mdb, if (entry->mdb != mdb) { continue; } + if (!entry->count) { list_del(&entry->hash); INIT_LIST_HEAD(&entry->hash); - list_del(&entry->dirty); - INIT_LIST_HEAD(&entry->dirty); list_del(&entry->list); list_add(&entry->list, dispose); continue; } - hfs_warn("hfs_fs: entry %p(%u:%lu) busy on removed device %s.\n", - entry, entry->count, entry->state, + + hfs_warn("hfs_fs: entry %p(%u) busy on removed device %s.\n", + entry, entry->count, hfs_mdb_name(entry->mdb->sys_mdb)); } +} + +/* delete entries from a list */ +static void delete_list(struct list_head *head) +{ + struct list_head *next = head->next; + struct hfs_cat_entry *entry; + + for (;;) { + struct list_head * tmp = next; + next = next->next; + if (tmp == head) { + break; + } + entry = list_entry(tmp, struct hfs_cat_entry, list); + HFS_DELETE(entry); + } } /* @@ -1026,7 +930,7 @@ void hfs_cat_invalidate(struct hfs_mdb *mdb) invalidate_list(&mdb->entry_dirty, mdb, &throw_away); spin_unlock(&entry_lock); - dispose_list(&throw_away); + delete_list(&throw_away); } /* @@ -1052,9 +956,6 @@ void hfs_cat_commit(struct hfs_mdb *mdb) if (!entry->count) insert = entry_in_use.prev; - /* remove from global dirty list */ - list_del(&entry->dirty); - INIT_LIST_HEAD(&entry->dirty); /* add to in_use list */ list_del(&entry->list); @@ -1077,16 +978,13 @@ void hfs_cat_commit(struct hfs_mdb *mdb) * * Releases all the memory allocated in grow_entries(). * Must call hfs_cat_invalidate() on all MDBs before calling this. + * This only gets rid of the unused pool of entries. all the other + * entry references should have either been freed by cat_invalidate + * or moved onto the unused list. */ void hfs_cat_free(void) { - struct allocation_unit *tmp; - - while (allocation) { - tmp = allocation->next; - HFS_DELETE(allocation); - allocation = tmp; - } + delete_list(&entry_unused); } /* @@ -1272,6 +1170,9 @@ struct hfs_cat_entry *hfs_cat_parent(struct hfs_cat_entry *entry) * Create a new file with the indicated name in the indicated directory. * The file will have the indicated flags, type and creator. * If successful an (struct hfs_cat_entry) is returned in '*result'. + * + * XXX: the presence of "record" probably means that the following two + * aren't currently SMP safe and need spinlocks. */ int hfs_cat_create(struct hfs_cat_entry *parent, struct hfs_cat_key *key, hfs_u8 flags, hfs_u32 type, hfs_u32 creator, @@ -1358,7 +1259,7 @@ int hfs_cat_delete(struct hfs_cat_entry *parent, struct hfs_cat_entry *entry, /* try to delete the file or directory */ if (!error) { - lock_entry(entry); + lock_entry(entry); if ((entry->state & HFS_DELETED)) { /* somebody beat us to it */ error = -ENOENT; @@ -1371,8 +1272,8 @@ int hfs_cat_delete(struct hfs_cat_entry *parent, struct hfs_cat_entry *entry, if (!error) { /* Mark the entry deleted and remove it from the cache */ - entry->state |= HFS_DELETED; - remove_hash(entry); + lock_entry(entry); + delete_entry(entry); /* try to delete the thread entry if it exists */ if (with_thread) { @@ -1380,6 +1281,7 @@ int hfs_cat_delete(struct hfs_cat_entry *parent, struct hfs_cat_entry *entry, (void)hfs_bdelete(mdb->cat_tree, HFS_BKEY(&key)); } + unlock_entry(entry); update_dir(mdb, parent, is_dir, -1); } @@ -1430,10 +1332,12 @@ int hfs_cat_move(struct hfs_cat_entry *old_dir, struct hfs_cat_entry *new_dir, return -EINVAL; } + spin_lock(&entry_lock); while (mdb->rename_lock) { hfs_sleep_on(&mdb->rename_wait); } mdb->rename_lock = 1; + spin_unlock(&entry_lock); /* keep readers from getting confused by changing dir size */ start_write(new_dir); @@ -1501,7 +1405,7 @@ restart: &new_record, is_dir ? 2 + sizeof(DIR_REC) : 2 + sizeof(FIL_REC)); if (error == -EEXIST) { - dest->state |= HFS_DELETED; + delete_entry(dest); unlock_entry(dest); hfs_cat_put(dest); goto restart; @@ -1590,8 +1494,7 @@ have_distinct: /* Something went seriously wrong. The dir/file has been deleted. */ /* XXX try some recovery? */ - entry->state |= HFS_DELETED; - remove_hash(entry); + delete_entry(entry); goto bail1; } } @@ -1620,7 +1523,7 @@ have_distinct: /* delete any pre-existing or place-holder entry */ if (dest) { - dest->state |= HFS_DELETED; + delete_entry(dest); unlock_entry(dest); if (removed && dest->cnid) { *removed = dest; @@ -1639,7 +1542,7 @@ bail2: (void)hfs_bdelete(mdb->cat_tree, HFS_BKEY(new_key)); update_dir(mdb, new_dir, is_dir, -1); bail3: - dest->state |= HFS_DELETED; + delete_entry(dest); } unlock_entry(dest); hfs_cat_put(dest); @@ -1649,8 +1552,10 @@ done: end_write(old_dir); } end_write(new_dir); + spin_lock(&entry_lock); mdb->rename_lock = 0; hfs_wake_up(&mdb->rename_wait); + spin_unlock(&entry_lock); return error; } @@ -1663,7 +1568,7 @@ void hfs_cat_init(void) int i; struct list_head *head = hash_table; - i = CCACHE_NR; + i = C_HASHSIZE; do { INIT_LIST_HEAD(head); head++; diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c index 144d9d42d..afd794155 100644 --- a/fs/hfs/dir.c +++ b/fs/hfs/dir.c @@ -95,7 +95,7 @@ static inline void update_dirs_plus(struct hfs_cat_entry *dir, int is_dir) } /* - * update_dirs_plus() + * update_dirs_minus() * * Update the fields 'i_size', 'i_nlink', 'i_ctime', 'i_mtime' and * 'i_version' of the inodes associated with a directory that has @@ -138,10 +138,9 @@ static inline void mark_inodes_deleted(struct hfs_cat_entry *entry, for (i = 0; i < 4; ++i) { if ((de = entry->sys_entry[i]) && (dentry != de)) { - entry->sys_entry[i] = NULL; - dget(de); - d_delete(de); - dput(de); + dget(de); + d_delete(de); + dput(de); } } } @@ -198,7 +197,7 @@ int hfs_create(struct inode * dir, struct dentry *dentry, int mode) error = -EIO; } else { if (HFS_I(dir)->d_drop_op) - HFS_I(dir)->d_drop_op(HFS_I(dir)->file_type, dentry); + HFS_I(dir)->d_drop_op(dentry, HFS_I(dir)->file_type); d_instantiate(dentry, inode); } } @@ -285,7 +284,7 @@ int hfs_unlink(struct inode * dir, struct dentry *dentry) struct hfs_cat_key key; int error; - if (build_key(&key, dir, dentry->d_name.name, + if (build_key(&key, dir, dentry->d_name.name, dentry->d_name.len)) { error = -EPERM; } else if (!(victim = hfs_cat_get(entry->mdb, &key))) { @@ -386,15 +385,15 @@ int hfs_rename(struct inode *old_dir, struct dentry *old_dentry, } else { /* no existing inodes. just drop negative dentries */ if (HFS_I(new_dir)->d_drop_op) - HFS_I(new_dir)->d_drop_op(HFS_I(new_dir)->file_type, - new_dentry); + HFS_I(new_dir)->d_drop_op(new_dentry, + HFS_I(new_dir)->file_type); update_dirs_plus(new_parent, is_dir); } /* update dcache */ d_move(old_dentry, new_dentry); } - + hfs_cat_put(victim); /* Note that hfs_cat_put(NULL) is safe. */ return error; } diff --git a/fs/hfs/dir_cap.c b/fs/hfs/dir_cap.c index d489c86ca..a7bb7f633 100644 --- a/fs/hfs/dir_cap.c +++ b/fs/hfs/dir_cap.c @@ -1,5 +1,4 @@ -/* linux/fs/hfs/dir_cap.c - * +/* * Copyright (C) 1995-1997 Paul H. Hargrove * This file may be distributed under the terms of the GNU Public License. * @@ -154,11 +153,12 @@ static int cap_lookup(struct inode * dir, struct dentry *dentry) struct hfs_cat_entry *entry; struct hfs_cat_key key; struct inode *inode = NULL; - + if (!dir || !S_ISDIR(dir->i_mode)) { - goto done; + return -ENOENT; } + dentry->d_op = &hfs_dentry_operations; entry = HFS_I(dir)->entry; dtype = HFS_ITYPE(dir->i_ino); @@ -215,13 +215,13 @@ static int cap_lookup(struct inode * dir, struct dentry *dentry) HFS_I(dir)->file_type, dentry); /* Don't return a resource fork for a directory */ - if (inode && (dtype == HFS_CAP_RDIR) && + if (inode && (dtype == HFS_CAP_RDIR) && (HFS_I(inode)->entry->type == HFS_CDR_DIR)) { + iput(inode); /* this does an hfs_cat_put */ inode = NULL; } done: - dentry->d_op = &hfs_dentry_operations; d_add(dentry, inode); return 0; } @@ -261,7 +261,7 @@ static int cap_readdir(struct file * filp, return -EBADF; } - entry = HFS_I(dir)->entry; + entry = HFS_I(dir)->entry; type = HFS_ITYPE(dir->i_ino); skip_dirs = (type == HFS_CAP_RDIR); @@ -368,7 +368,7 @@ static int cap_readdir(struct file * filp, * related calls (create, rename, and mknod). the directory calls * should be immune. the relevant calls in dir.c call drop_dentry * upon successful completion. */ -void hfs_cap_drop_dentry(const ino_t type, struct dentry *dentry) +void hfs_cap_drop_dentry(struct dentry *dentry, const ino_t type) { if (type == HFS_CAP_DATA) { /* given name */ hfs_drop_special(DOT_FINDERINFO, dentry->d_parent, dentry); diff --git a/fs/hfs/dir_dbl.c b/fs/hfs/dir_dbl.c index c97247dc9..553fe8ef9 100644 --- a/fs/hfs/dir_dbl.c +++ b/fs/hfs/dir_dbl.c @@ -135,11 +135,12 @@ static int dbl_lookup(struct inode * dir, struct dentry *dentry) struct hfs_cat_entry *entry; struct hfs_cat_key key; struct inode *inode = NULL; - + if (!dir || !S_ISDIR(dir->i_mode)) { - goto done; + return -ENOENT; } + dentry->d_op = &hfs_dentry_operations; entry = HFS_I(dir)->entry; /* Perform name-mangling */ @@ -175,12 +176,11 @@ static int dbl_lookup(struct inode * dir, struct dentry *dentry) hfs_nameout(dir, &cname, dentry->d_name.name+1, dentry->d_name.len-1); hfs_cat_build_key(entry->cnid, &cname, &key); - inode = hfs_iget(hfs_cat_get(entry->mdb, &key), + inode = hfs_iget(hfs_cat_get(entry->mdb, &key), HFS_DBL_HDR, dentry); } done: - dentry->d_op = &hfs_dentry_operations; d_add(dentry, inode); return 0; } @@ -219,7 +219,7 @@ static int dbl_readdir(struct file * filp, return -EBADF; } - entry = HFS_I(dir)->entry; + entry = HFS_I(dir)->entry; if (filp->f_pos == 0) { /* Entry 0 is for "." */ @@ -414,14 +414,14 @@ static int dbl_rename(struct inode *old_dir, struct dentry *old_dentry, { int error; - if (is_hdr(new_dir, new_dentry->d_name.name, + if (is_hdr(new_dir, new_dentry->d_name.name, new_dentry->d_name.len)) { error = -EPERM; } else { error = hfs_rename(old_dir, old_dentry, new_dir, new_dentry); if ((error == -ENOENT) /*&& !must_be_dir*/ && - is_hdr(old_dir, old_dentry->d_name.name, + is_hdr(old_dir, old_dentry->d_name.name, old_dentry->d_name.len)) { error = -EPERM; } @@ -435,9 +435,8 @@ static int dbl_rename(struct inode *old_dir, struct dentry *old_dentry, * as far as i can tell, the calls that need to do this are the file * related calls (create, rename, and mknod). the directory calls * should be immune. the relevant calls in dir.c call drop_dentry - * upon successful completion. this allocates an array for %name - * on the first attempt to access it. */ -void hfs_dbl_drop_dentry(const ino_t type, struct dentry *dentry) + * upon successful completion. */ +void hfs_dbl_drop_dentry(struct dentry *dentry, const ino_t type) { unsigned char tmp_name[HFS_NAMEMAX + 1]; struct dentry *de = NULL; diff --git a/fs/hfs/dir_nat.c b/fs/hfs/dir_nat.c index 62c9ea2cb..b29bfdc17 100644 --- a/fs/hfs/dir_nat.c +++ b/fs/hfs/dir_nat.c @@ -142,9 +142,10 @@ static int nat_lookup(struct inode * dir, struct dentry *dentry) struct inode *inode = NULL; if (!dir || !S_ISDIR(dir->i_mode)) { - goto done; + return -ENOENT; } + dentry->d_op = &hfs_dentry_operations; entry = HFS_I(dir)->entry; dtype = HFS_ITYPE(dir->i_ino); @@ -200,12 +201,11 @@ static int nat_lookup(struct inode * dir, struct dentry *dentry) if (inode && (dtype == HFS_NAT_HDIR) && (HFS_I(inode)->entry != entry) && (HFS_I(inode)->entry->type == HFS_CDR_DIR)) { - iput(inode); + iput(inode); /* this does an hfs_cat_put */ inode = NULL; } done: - dentry->d_op = &hfs_dentry_operations; d_add(dentry, inode); return 0; } @@ -241,7 +241,7 @@ static int nat_readdir(struct file * filp, return -EBADF; } - entry = HFS_I(dir)->entry; + entry = HFS_I(dir)->entry; type = HFS_ITYPE(dir->i_ino); skip_dirs = (type == HFS_NAT_HDIR); @@ -329,7 +329,7 @@ static int nat_readdir(struct file * filp, * related calls (create, rename, and mknod). the directory calls * should be immune. the relevant calls in dir.c call drop_dentry * upon successful completion. */ -void hfs_nat_drop_dentry(const ino_t type, struct dentry *dentry) +void hfs_nat_drop_dentry(struct dentry *dentry, const ino_t type) { struct dentry *de; diff --git a/fs/hfs/file.c b/fs/hfs/file.c index 26f498305..e12792036 100644 --- a/fs/hfs/file.c +++ b/fs/hfs/file.c @@ -98,11 +98,10 @@ struct buffer_head *hfs_getblk(struct hfs_fork *fork, int block, int create) to the file until we return, so it can't have moved. */ if (tmp) { - hfs_cat_mark_dirty(fork->entry); - return getblk(dev, tmp, HFS_SECTOR_SIZE); + hfs_cat_mark_dirty(fork->entry); + return getblk(dev, tmp, HFS_SECTOR_SIZE); } return NULL; - } else { /* If reading the block, then retry since the location on disk could have changed while @@ -236,6 +235,7 @@ static hfs_rwret_t hfs_file_write(struct file * filp, const char * buf, */ static void hfs_file_truncate(struct inode * inode) { + /*struct inode *inode = dentry->d_inode;*/ struct hfs_fork *fork = HFS_I(inode)->fork; fork->lsize = inode->i_size; @@ -268,7 +268,7 @@ static inline void xlate_to_user(char *buf, const char *data, int count) */ static inline void xlate_from_user(char *data, const char *buf, int count) { - copy_from_user(data, buf, count); + count -= copy_from_user(data, buf, count); while (count--) { if (*data == '\n') { *data = '\r'; @@ -398,16 +398,16 @@ hfs_s32 hfs_do_read(struct inode *inode, struct hfs_fork * fork, hfs_u32 pos, } else { chars = HFS_SECTOR_SIZE - offset; } - count -= chars; - read += chars; p = (*bhe)->b_data + offset; if (convert) { xlate_to_user(buf, p, chars); } else { - copy_to_user(buf, p, chars); + chars -= copy_to_user(buf, p, chars); } brelse(*bhe); + count -= chars; buf += chars; + read += chars; offset = 0; if (++bhe == &buflist[NBUF]) { bhe = buflist; @@ -479,7 +479,7 @@ hfs_s32 hfs_do_write(struct inode *inode, struct hfs_fork * fork, hfs_u32 pos, if (convert) { xlate_from_user(p, buf, c); } else { - copy_from_user(p, buf, c); + c -= copy_from_user(p, buf, c); } update_vm_cache(inode,pos,p,c); pos += c; diff --git a/fs/hfs/file_cap.c b/fs/hfs/file_cap.c index 7c298264a..10f39f751 100644 --- a/fs/hfs/file_cap.c +++ b/fs/hfs/file_cap.c @@ -164,8 +164,7 @@ static hfs_rwret_t cap_info_read(struct file *filp, char *buf, memcount = left; } cap_build_meta(&meta, entry); - /* is copy_to_user guaranteed to write memcount? */ - copy_to_user(buf, ((char *)&meta) + pos, memcount); + memcount -= copy_to_user(buf, ((char *)&meta) + pos, memcount); left -= memcount; read += memcount; pos += memcount; @@ -291,6 +290,8 @@ static hfs_rwret_t cap_info_write(struct file *filp, const char *buf, */ static void cap_info_truncate(struct inode *inode) { + /*struct inode *inode = dentry->d_inode;*/ + if (inode->i_size > HFS_FORK_MAX) { inode->i_size = HFS_FORK_MAX; } diff --git a/fs/hfs/file_hdr.c b/fs/hfs/file_hdr.c index 468a3f518..049381dd0 100644 --- a/fs/hfs/file_hdr.c +++ b/fs/hfs/file_hdr.c @@ -288,12 +288,10 @@ static inline void adjust_forks(struct hfs_cat_entry *entry, (descr->length != entry->u.file.data_fork.lsize)) { entry->u.file.data_fork.lsize = descr->length; hfs_extent_adj(&entry->u.file.data_fork); - hfs_cat_mark_dirty(entry); } else if ((descr->id == HFS_HDR_RSRC) && (descr->length != entry->u.file.rsrc_fork.lsize)) { entry->u.file.rsrc_fork.lsize = descr->length; hfs_extent_adj(&entry->u.file.rsrc_fork); - hfs_cat_mark_dirty(entry); } } } @@ -414,7 +412,7 @@ static hfs_rwret_t hdr_read(struct file * filp, char * buf, } hdr_build_meta(&meta, layout, entry); - copy_to_user(buf, ((char *)&meta) + pos, left); + left -= copy_to_user(buf, ((char *)&meta) + pos, left); count -= left; read += left; pos += left; @@ -531,7 +529,7 @@ static hfs_rwret_t hdr_read(struct file * filp, char * buf, /* transfer the data */ if (p) { - copy_to_user(buf, p + offset, left); + left -= copy_to_user(buf, p + offset, left); } else if (fork) { left = hfs_do_read(inode, fork, offset, buf, left, filp->f_reada != 0); @@ -654,6 +652,7 @@ static hfs_rwret_t hdr_write(struct file *filp, const char *buf, /* Handle possible size changes for the forks */ if (entry->type == HFS_CDR_FIL) { adjust_forks(entry, layout); + hfs_cat_mark_dirty(entry); } } @@ -887,6 +886,8 @@ done: */ static void hdr_truncate(struct inode *inode) { + /*struct inode *inode = dentry->d_inode;*/ + struct hfs_cat_entry *entry = HFS_I(inode)->entry; struct hfs_hdr_layout *layout; size_t size = inode->i_size; int lcv, last; @@ -907,14 +908,14 @@ static void hdr_truncate(struct inode *inode) } if (descr->id == HFS_HDR_RSRC) { - fork = &HFS_I(inode)->entry->u.file.rsrc_fork; + fork = &entry->u.file.rsrc_fork; #if 0 /* Can't yet truncate the data fork via a header file, since there is the * possibility to truncate via the data file, and the only locking is at * the inode level. */ } else if (descr->id == HFS_HDR_DATA) { - fork = &HFS_I(inode)->entry->u.file.data_fork; + fork = &entry->u.file.data_fork; #endif } else { continue; diff --git a/fs/hfs/hfs.h b/fs/hfs/hfs.h index ccc2f0cae..9112a6db8 100644 --- a/fs/hfs/hfs.h +++ b/fs/hfs/hfs.h @@ -11,10 +11,10 @@ #define _HFS_H #include <linux/hfs_sysdep.h> -#include <linux/hfs_fs.h> #define HFS_NEW(X) ((X) = hfs_malloc(sizeof(*(X)))) -#define HFS_DELETE(X) { hfs_free((X), sizeof(*(X))); (X) = NULL; } +#define HFS_DELETE(X) do { hfs_free((X), sizeof(*(X))); (X) = NULL; } \ + while (0) /* offsets to various blocks */ #define HFS_DD_BLK 0 /* Driver Descriptor block */ @@ -337,13 +337,12 @@ struct hfs_file { * This structure holds information about a * file or directory in an HFS filesystem. * - * 'wait' must remain 1st and 'next' 2nd since we do some pointer arithmetic. + * 'wait' must remain 1st and 'hash' 2nd since we do some pointer arithmetic. */ struct hfs_cat_entry { hfs_wait_queue wait; struct list_head hash; struct list_head list; - struct list_head dirty; struct hfs_mdb *mdb; hfs_sysentry sys_entry; struct hfs_cat_key key; @@ -366,7 +365,6 @@ struct hfs_cat_entry { #define HFS_KEYDIRTY 2 #define HFS_LOCK 4 #define HFS_DELETED 8 -#define HFS_SUPERBLK 16 /* * struct hfs_bnode_ref @@ -486,14 +484,11 @@ extern void hfs_mdb_put(struct hfs_mdb *, int); extern int hfs_part_find(hfs_sysmdb, int, int, hfs_s32 *, hfs_s32 *); /* string.c */ -extern unsigned int hfs_strhash(const struct hfs_name *); +extern unsigned long hfs_strhash(const struct hfs_name *); extern int hfs_strcmp(const struct hfs_name *, const struct hfs_name *); extern int hfs_streq(const struct hfs_name *, const struct hfs_name *); extern void hfs_tolower(unsigned char *, int); -/* sysdep.c */ -extern void hfs_cat_prune(struct hfs_cat_entry *); - extern __inline__ struct dentry *hfs_lookup_dentry(const char *name, const int len, struct dentry *base) diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c index a0bf3d576..340e9be79 100644 --- a/fs/hfs/inode.c +++ b/fs/hfs/inode.c @@ -73,17 +73,13 @@ static void init_file_inode(struct inode *inode, hfs_u8 fork) */ void hfs_put_inode(struct inode * inode) { - struct hfs_cat_entry *entry = HFS_I(inode)->entry; - - entry->sys_entry[HFS_ITYPE_TO_INT(HFS_ITYPE(inode->i_ino))] = NULL; - hfs_cat_put(entry); - if (inode->i_count == 1) { - struct hfs_hdr_layout *tmp = HFS_I(inode)->layout; - if (tmp) { - HFS_I(inode)->layout = NULL; - HFS_DELETE(tmp); - } + struct hfs_hdr_layout *tmp = HFS_I(inode)->layout; + + if (tmp) { + HFS_I(inode)->layout = NULL; + HFS_DELETE(tmp); + } } } @@ -153,7 +149,7 @@ int hfs_notify_change(struct dentry *dentry, struct iattr * attr) /* We must change all in-core inodes corresponding to this file. */ for (i = 0; i < 4; ++i) { if (de[i] && (de[i] != dentry)) { - inode_setattr(de[i]->d_inode, attr); + inode_setattr(de[i]->d_inode, attr); } } @@ -213,7 +209,7 @@ int hfs_notify_change(struct dentry *dentry, struct iattr * attr) * benefit from a way to pass an additional (void *) through iget() to * the VFS read_inode() function. * - * hfs_iget no longer touches hfs_cat_entries. + * this will hfs_cat_put() the entry if it fails. */ struct inode *hfs_iget(struct hfs_cat_entry *entry, ino_t type, struct dentry *dentry) @@ -239,25 +235,15 @@ struct inode *hfs_iget(struct hfs_cat_entry *entry, ino_t type, sb = entry->mdb->sys_mdb; sys_entry = &entry->sys_entry[HFS_ITYPE_TO_INT(type)]; - if (*sys_entry && (inode = (*sys_entry)->d_inode)) { - /* There is an existing inode for this file/dir. Use it. */ - ++inode->i_count; - return inode; - } - - if (!(inode = iget(sb, ntohl(entry->cnid) | type))) + if (!(inode = iget(sb, ntohl(entry->cnid) | type))) { + hfs_cat_put(entry); return NULL; + } if (inode->i_dev != sb->s_dev) { - iput(inode); + iput(inode); /* automatically does an hfs_cat_put */ inode = NULL; - } else if (inode->i_mode) { - /* The inode has been initialized by another process. - Note that if hfs_put_inode() is sleeping in hfs_cat_put() - then we still need to attach it to the entry. */ - if (!(*sys_entry)) - *sys_entry = dentry; /* cache dentry */ - } else { + } else if (!inode->i_mode) { /* Initialize the inode */ struct hfs_sb_info *hsb = HFS_SB(sb); @@ -281,10 +267,11 @@ struct inode *hfs_iget(struct hfs_cat_entry *entry, ino_t type, if (!inode->i_mode) { clear_inode(inode); + hfs_cat_put(entry); inode = NULL; - } + } else + *sys_entry = dentry; /* cache dentry */ - *sys_entry = dentry; /* cache dentry */ } return inode; diff --git a/fs/hfs/string.c b/fs/hfs/string.c index cacc0a604..030850b82 100644 --- a/fs/hfs/string.c +++ b/fs/hfs/string.c @@ -81,11 +81,14 @@ static unsigned char casefold[256] = { /* * Hash a string to an integer in a case-independent way */ -unsigned int hfs_strhash(const struct hfs_name *cname) +unsigned long hfs_strhash(const struct hfs_name *cname) { - /* Currently just sum of the 'order' of first and last characters */ - return ((unsigned int)caseorder[cname->Name[0]] + - (unsigned int)caseorder[cname->Name[cname->Len - 1]]); + unsigned long hash = init_name_hash(); + unsigned int i; + for (i = 0; i < cname->Len; i++) { + hash = partial_name_hash(caseorder[cname->Name[i]], hash); + } + return end_name_hash(hash); } /* diff --git a/fs/hfs/super.c b/fs/hfs/super.c index 897130297..9e278d383 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c @@ -163,8 +163,8 @@ static int hfs_statfs(struct super_block *sb, struct statfs *buf, int len) tmp.f_blocks = mdb->alloc_blksz * mdb->fs_ablocks; tmp.f_bfree = mdb->alloc_blksz * mdb->free_ablocks; tmp.f_bavail = tmp.f_bfree; - tmp.f_files = mdb->fs_ablocks; /* According to the statfs manual page, -1 is the */ - tmp.f_ffree = mdb->free_ablocks; /* correct value when the meaning is undefined. */ + tmp.f_files = mdb->fs_ablocks; + tmp.f_ffree = mdb->free_ablocks; tmp.f_namelen = HFS_NAMELEN; return copy_to_user(buf, &tmp, len) ? -EFAULT : 0; @@ -459,16 +459,13 @@ struct super_block *hfs_read_super(struct super_block *s, void *data, if (!root_inode) goto bail_no_root; - /* cache the dentry in the inode */ - s->s_root = - HFS_I(root_inode)->entry->sys_entry[HFS_ITYPE_TO_INT(HFS_ITYPE_NORM)] = - d_alloc_root(root_inode, NULL); + s->s_root = d_alloc_root(root_inode, NULL); if (!s->s_root) goto bail_no_root; - /* HFS_SUPERBLK prevents the root inode from being flushed - * inadvertantly. */ - HFS_I(root_inode)->entry->state = HFS_SUPERBLK; + /* fix up pointers. */ + HFS_I(root_inode)->entry->sys_entry[HFS_ITYPE_TO_INT(HFS_ITYPE_NORM)] = + s->s_root; s->s_root->d_op = &hfs_dentry_operations; /* everything's okay */ diff --git a/fs/hfs/sysdep.c b/fs/hfs/sysdep.c index fc7368a75..659d0b2fc 100644 --- a/fs/hfs/sysdep.c +++ b/fs/hfs/sysdep.c @@ -19,13 +19,16 @@ #include <linux/hfs_fs.h> static int hfs_hash_dentry(struct dentry *, struct qstr *); -static int hfs_compare_dentry (struct dentry *, struct qstr *, struct qstr *); +static int hfs_compare_dentry(struct dentry *, struct qstr *, struct qstr *); +static void hfs_dentry_iput(struct dentry *, struct inode *); struct dentry_operations hfs_dentry_operations = { NULL, /* d_validate(struct dentry *) */ hfs_hash_dentry, /* d_hash */ hfs_compare_dentry, /* d_compare */ - NULL /* d_delete(struct dentry *) */ + NULL, /* d_delete(struct dentry *) */ + NULL, /* d_release(struct dentry *) */ + hfs_dentry_iput /* d_iput(struct dentry *, struct inode *) */ }; /* @@ -55,19 +58,16 @@ hfs_buffer hfs_buffer_get(hfs_sysmdb sys_mdb, int block, int read) { /* dentry case-handling: just lowercase everything */ -/* should we use hfs_strhash? if so, it probably needs to be beefed - * up a little. */ +/* hfs_strhash now uses the same hashing function as the dcache. */ static int hfs_hash_dentry(struct dentry *dentry, struct qstr *this) { - unsigned char name[HFS_NAMELEN]; - int len = this->len; + struct hfs_name cname; - if (len > HFS_NAMELEN) + if ((cname.Len = this->len) > HFS_NAMELEN) return 0; - - strncpy(name, this->name, len); - hfs_tolower(name, len); - this->hash = full_name_hash(name, len); + + strncpy(cname.Name, this->name, this->len); + this->hash = hfs_strhash(&cname); return 0; } @@ -86,18 +86,11 @@ static int hfs_compare_dentry(struct dentry *dentry, struct qstr *a, return hfs_streq(&s1, &s2); } - -/* toss a catalog entry. this does it by dropping the dentry. */ -void hfs_cat_prune(struct hfs_cat_entry *entry) +static void hfs_dentry_iput(struct dentry *dentry, struct inode *inode) { - int i; + struct hfs_cat_entry *entry = HFS_I(inode)->entry; - for (i = 0; i < 4; i++) { - struct dentry *de = entry->sys_entry[i]; - if (de) { - dget(de); - d_drop(de); - dput(de); - } - } + entry->sys_entry[HFS_ITYPE_TO_INT(HFS_ITYPE(inode->i_ino))] = NULL; + hfs_cat_put(entry); + iput(inode); } diff --git a/fs/hfs/version.c b/fs/hfs/version.c index 8eb74084d..8652c1cca 100644 --- a/fs/hfs/version.c +++ b/fs/hfs/version.c @@ -7,4 +7,4 @@ * This file contains the version string for this release. */ -const char hfs_version[]="0.95+asun2"; +const char hfs_version[]="0.95+asun3"; diff --git a/fs/ncpfs/Config.in b/fs/ncpfs/Config.in index 48cf4aa86..bdb973e41 100644 --- a/fs/ncpfs/Config.in +++ b/fs/ncpfs/Config.in @@ -1,7 +1,7 @@ # # NCP Filesystem configuration # -# bool ' Packet singatures' CONFIG_NCPFS_PACKET_SIGNING +bool ' Packet singatures' CONFIG_NCPFS_PACKET_SIGNING bool ' Proprietary file locking' CONFIG_NCPFS_IOCTL_LOCKING bool ' Clear remove/delete inhibit when needed' CONFIG_NCPFS_STRONG bool ' Use NFS namespace if available' CONFIG_NCPFS_NFS_NS diff --git a/fs/ncpfs/Makefile b/fs/ncpfs/Makefile index 5c83ada11..9c33bc515 100644 --- a/fs/ncpfs/Makefile +++ b/fs/ncpfs/Makefile @@ -8,7 +8,8 @@ # Note 2! The CFLAGS definitions are now in the main makefile... O_TARGET := ncpfs.o -O_OBJS := dir.o file.o inode.o ioctl.o mmap.o ncplib_kernel.o sock.o +O_OBJS := dir.o file.o inode.o ioctl.o mmap.o ncplib_kernel.o sock.o \ + ncpsign_kernel.o M_OBJS := $(O_TARGET) # If you want debugging output, please uncomment the following line diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index 8424b2ec7..bec1c55a2 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c @@ -112,7 +112,7 @@ static int ncp_hash_dentry(struct dentry *, struct qstr *); static int ncp_compare_dentry (struct dentry *, struct qstr *, struct qstr *); static void ncp_delete_dentry(struct dentry *); -static struct dentry_operations ncp_dentry_operations = +struct dentry_operations ncp_dentry_operations = { ncp_lookup_validate, /* d_validate(struct dentry *) */ ncp_hash_dentry, /* d_hash */ diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index f11f4640c..c872c2b84 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -25,9 +25,6 @@ #include <linux/fcntl.h> #include <linux/malloc.h> #include <linux/init.h> -#ifdef CONFIG_KERNELD -#include <linux/kerneld.h> -#endif #include <linux/ncp_fs.h> #include "ncplib_kernel.h" @@ -287,6 +284,7 @@ ncp_read_super(struct super_block *sb, void *raw_data, int silent) server->buffer_size = 0; server->conn_status = 0; server->root_dentry = NULL; + server->root_setuped = 0; #ifdef CONFIG_NCPFS_PACKET_SIGNING server->sign_wanted = 0; server->sign_active = 0; diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c index 078d26596..2df6fee09 100644 --- a/fs/ncpfs/ioctl.c +++ b/fs/ncpfs/ioctl.c @@ -32,6 +32,22 @@ int ncp_ioctl(struct inode *inode, struct file *filp, struct ncp_ioctl_request request; struct ncp_fs_info info; +#ifdef NCP_IOC_GETMOUNTUID_INT + /* remove after ncpfs-2.0.13/2.2.0 gets released */ + if ((NCP_IOC_GETMOUNTUID != NCP_IOC_GETMOUNTUID_INT) && + (cmd == NCP_IOC_GETMOUNTUID_INT)) { + int tmp = server->m.mounted_uid; + + if ( (permission(inode, MAY_READ) != 0) + && (current->uid != server->m.mounted_uid)) + { + return -EACCES; + } + if (put_user(tmp, (unsigned int*) arg)) return -EFAULT; + return 0; + } +#endif /* NCP_IOC_GETMOUNTUID_INT */ + switch (cmd) { case NCP_IOC_NCPREQUEST: @@ -80,6 +96,8 @@ int ncp_ioctl(struct inode *inode, struct file *filp, && (current->uid != server->m.mounted_uid)) { return -EACCES; } + if (server->root_setuped) return -EBUSY; + server->root_setuped = 1; return ncp_conn_logged_in(server); case NCP_IOC_GET_FS_INFO: @@ -121,19 +139,6 @@ int ncp_ioctl(struct inode *inode, struct file *filp, put_user(server->m.mounted_uid, (uid_t *) arg); return 0; - case NCP_IOC_GETMOUNTUID_INT: - if ( (permission(inode, MAY_READ) != 0) - && (current->uid != server->m.mounted_uid)) - { - return -EACCES; - } - - { - unsigned int tmp=server->m.mounted_uid; - if (put_user(tmp, (unsigned long*) arg)) return -EFAULT; - } - return 0; - #ifdef CONFIG_NCPFS_MOUNT_SUBDIR case NCP_IOC_GETROOT: { @@ -168,6 +173,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp, { return -EACCES; } + if (server->root_setuped) return -EBUSY; if (copy_from_user(&sr, (struct ncp_setroot_ioctl*)arg, sizeof(sr))) return -EFAULT; @@ -184,6 +190,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp, } } dentry = server->root_dentry; + server->root_setuped = 1; if (dentry) { struct inode* inode = dentry->d_inode; diff --git a/fs/ncpfs/ncpsign_kernel.c b/fs/ncpfs/ncpsign_kernel.c new file mode 100644 index 000000000..bae89c197 --- /dev/null +++ b/fs/ncpfs/ncpsign_kernel.c @@ -0,0 +1,114 @@ +/* + * ncpsign_kernel.c + * + * Arne de Bruijn (arne@knoware.nl), 1997 + * + */ + +#include <linux/config.h> + +#ifdef CONFIG_NCPFS_PACKET_SIGNING + +#include <linux/string.h> +#include <linux/ncp.h> +#include "ncpsign_kernel.h" + +#define rol32(i,c) (((((i)&0xffffffff)<<c)&0xffffffff)| \ + (((i)&0xffffffff)>>(32-c))) +/* i386: 32-bit, little endian, handles mis-alignment */ +#ifdef __i386__ +#define GET_LE32(p) (*(int *)(p)) +#define PUT_LE32(p,v) { *(int *)(p)=v; } +#else +/* from include/ncplib.h */ +#define BVAL(buf,pos) (((__u8 *)(buf))[pos]) +#define PVAL(buf,pos) ((unsigned)BVAL(buf,pos)) +#define BSET(buf,pos,val) (BVAL(buf,pos) = (val)) + +static inline word +WVAL_LH(__u8 * buf, int pos) +{ + return PVAL(buf, pos) | PVAL(buf, pos + 1) << 8; +} +static inline dword +DVAL_LH(__u8 * buf, int pos) +{ + return WVAL_LH(buf, pos) | WVAL_LH(buf, pos + 2) << 16; +} +static inline void +WSET_LH(__u8 * buf, int pos, word val) +{ + BSET(buf, pos, val & 0xff); + BSET(buf, pos + 1, val >> 8); +} +static inline void +DSET_LH(__u8 * buf, int pos, dword val) +{ + WSET_LH(buf, pos, val & 0xffff); + WSET_LH(buf, pos + 2, val >> 16); +} + +#define GET_LE32(p) DVAL_LH(p,0) +#define PUT_LE32(p,v) DSET_LH(p,0,v) +#endif + +#define min(a,b) ((a)<(b)?(a):(b)) + +static void nwsign(char *r_data1, char *r_data2, char *outdata) { + int i; + unsigned int w0,w1,w2,w3; + static int rbit[4]={0, 2, 1, 3}; +#ifdef __i386__ + unsigned int *data2=(int *)r_data2; +#else + unsigned int data2[16]; + for (i=0;i<16;i++) + data2[i]=GET_LE32(r_data2+(i<<2)); +#endif + w0=GET_LE32(r_data1); + w1=GET_LE32(r_data1+4); + w2=GET_LE32(r_data1+8); + w3=GET_LE32(r_data1+12); + for (i=0;i<16;i+=4) { + w0=rol32(w0 + ((w1 & w2) | ((~w1) & w3)) + data2[i+0],3); + w3=rol32(w3 + ((w0 & w1) | ((~w0) & w2)) + data2[i+1],7); + w2=rol32(w2 + ((w3 & w0) | ((~w3) & w1)) + data2[i+2],11); + w1=rol32(w1 + ((w2 & w3) | ((~w2) & w0)) + data2[i+3],19); + } + for (i=0;i<4;i++) { + w0=rol32(w0 + (((w2 | w3) & w1) | (w2 & w3)) + 0x5a827999 + data2[i+0],3); + w3=rol32(w3 + (((w1 | w2) & w0) | (w1 & w2)) + 0x5a827999 + data2[i+4],5); + w2=rol32(w2 + (((w0 | w1) & w3) | (w0 & w1)) + 0x5a827999 + data2[i+8],9); + w1=rol32(w1 + (((w3 | w0) & w2) | (w3 & w0)) + 0x5a827999 + data2[i+12],13); + } + for (i=0;i<4;i++) { + w0=rol32(w0 + ((w1 ^ w2) ^ w3) + 0x6ed9eba1 + data2[rbit[i]+0],3); + w3=rol32(w3 + ((w0 ^ w1) ^ w2) + 0x6ed9eba1 + data2[rbit[i]+8],9); + w2=rol32(w2 + ((w3 ^ w0) ^ w1) + 0x6ed9eba1 + data2[rbit[i]+4],11); + w1=rol32(w1 + ((w2 ^ w3) ^ w0) + 0x6ed9eba1 + data2[rbit[i]+12],15); + } + PUT_LE32(outdata,(w0+GET_LE32(r_data1)) & 0xffffffff); + PUT_LE32(outdata+4,(w1+GET_LE32(r_data1+4)) & 0xffffffff); + PUT_LE32(outdata+8,(w2+GET_LE32(r_data1+8)) & 0xffffffff); + PUT_LE32(outdata+12,(w3+GET_LE32(r_data1+12)) & 0xffffffff); +} + +/* Make a signature for the current packet and add it at the end of the */ +/* packet. */ +void sign_packet(struct ncp_server *server, int *size) { + char data[64]; + + memset(data,0,64); + memcpy(data,server->sign_root,8); + PUT_LE32(data+8,(*size)); + memcpy(data+12,server->packet+sizeof(struct ncp_request_header)-1, + min((*size)-sizeof(struct ncp_request_header)+1,52)); + + nwsign(server->sign_last,data,server->sign_last); + + memcpy(server->packet+(*size),server->sign_last,8); + (*size)+=8; +} + +#endif /* CONFIG_NCPFS_PACKET_SIGNING */ + diff --git a/fs/ncpfs/ncpsign_kernel.h b/fs/ncpfs/ncpsign_kernel.h new file mode 100644 index 000000000..85974f346 --- /dev/null +++ b/fs/ncpfs/ncpsign_kernel.h @@ -0,0 +1,16 @@ +/* + * ncpsign_kernel.h + * + * Arne de Bruijn (arne@knoware.nl), 1997 + * + */ + +#ifndef _NCPSIGN_KERNEL_H +#define _NCPSIGN_KERNEL_H + +#include <linux/ncp_fs.h> +#include <linux/ncp_fs_sb.h> + +void sign_packet(struct ncp_server *server, int *size); + +#endif diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 8300fee67..2de790e42 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -650,10 +650,31 @@ _nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry) inode->i_ino); status = nfs_proc_getattr(server, NFS_FH(dentry), &fattr); if (status) { + int error; + u32 *fh; + struct nfs_fh fhandle; #ifdef NFS_PARANOIA printk("nfs_revalidate_inode: %s/%s getattr failed, ino=%ld, error=%d\n", dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_ino, status); #endif + if (status != -ESTALE) + goto out; + /* + * A "stale filehandle" error ... show the current fh + * and find out what the filehandle should be. + */ + fh = (u32 *) NFS_FH(dentry); + printk("NFS: bad fh %08x%08x%08x%08x%08x%08x%08x%08x\n", + fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]); + error = nfs_proc_lookup(server, NFS_FH(dentry->d_parent), + dentry->d_name.name, &fhandle, &fattr); + if (error) { + printk("NFS: lookup failed, error=%d\n", error); + goto out; + } + fh = (u32 *) &fhandle; + printk(" %08x%08x%08x%08x%08x%08x%08x%08x\n", + fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]); goto out; } diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c index 216aafb80..1c6a74a71 100644 --- a/fs/nfs/nfs2xdr.c +++ b/fs/nfs/nfs2xdr.c @@ -22,6 +22,9 @@ #include <linux/sunrpc/clnt.h> #include <linux/nfs_fs.h> +/* Uncomment this to support servers requiring longword lengths */ +#define NFS_PAD_WRITES 1 + #define NFSDBG_FACILITY NFSDBG_XDR /* #define NFS_PARANOIA 1 */ @@ -181,7 +184,7 @@ nfs_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs_diropargs *args) /* * Arguments to a READ call. Since we read data directly into the page * cache, we also set up the reply iovec here so that iov[1] points - * exactly to the page wewant to fetch. + * exactly to the page we want to fetch. */ static int nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args) @@ -258,18 +261,38 @@ nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res) static int nfs_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args) { + u32 count = args->count; + p = xdr_encode_fhandle(p, args->fh); *p++ = htonl(args->offset); *p++ = htonl(args->offset); - *p++ = htonl(args->count); - *p++ = htonl(args->count); + *p++ = htonl(count); + *p++ = htonl(count); req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); req->rq_svec[1].iov_base = (void *) args->buffer; - req->rq_svec[1].iov_len = args->count; - req->rq_slen += args->count; + req->rq_svec[1].iov_len = count; + req->rq_slen += count; req->rq_snr = 2; +#ifdef NFS_PAD_WRITES + /* + * Some old servers require that the message length + * be a multiple of 4, so we pad it here if needed. + */ + count = ((count + 3) & ~3) - count; + if (count) { +#if 0 +printk("nfs_writeargs: padding write, len=%d, slen=%d, pad=%d\n", +req->rq_svec[1].iov_len, req->rq_slen, count); +#endif + req->rq_svec[2].iov_base = (void *) "\0\0\0"; + req->rq_svec[2].iov_len = count; + req->rq_slen += count; + req->rq_snr = 3; + } +#endif + return 0; } @@ -334,12 +357,21 @@ nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args) static int nfs_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs_readdirargs *args) { - struct rpc_auth *auth = req->rq_task->tk_auth; + struct rpc_task *task = req->rq_task; + struct rpc_auth *auth = task->tk_auth; + u32 bufsiz = args->bufsiz; int replen; + /* + * Some servers (e.g. HP OS 9.5) seem to expect the buffer size + * to be in longwords ... check whether to convert the size. + */ + if (task->tk_client->cl_flags & NFS_CLNTF_BUFSIZE) + bufsiz = bufsiz >> 2; + p = xdr_encode_fhandle(p, args->fh); *p++ = htonl(args->cookie); - *p++ = htonl(args->bufsiz); + *p++ = htonl(bufsiz); /* see above */ req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); /* set up reply iovec */ @@ -380,10 +412,9 @@ static int nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res) { struct iovec *iov = req->rq_rvec; - int status, nr, len; + int status, nr; char *string, *start; - u32 *end; - __u32 fileid, cookie, *entry; + u32 *end, *entry, len, fileid, cookie; if ((status = ntohl(*p++))) return -nfs_stat_to_errno(status); @@ -398,17 +429,25 @@ nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res) end = (u32 *) ((u8 *) p + iov[1].iov_len); /* Get start and end of dirent buffer */ - entry = (__u32 *) res->buffer; + entry = (u32 *) res->buffer; start = (char *) res->buffer; string = (char *) res->buffer + res->bufsiz; for (nr = 0; *p++; nr++) { fileid = ntohl(*p++); len = ntohl(*p++); + /* + * Check whether the server has exceeded our reply buffer, + * and set a flag to convert the size to longwords. + */ if ((p + QUADLEN(len) + 3) > end) { - printk(KERN_WARNING "NFS: short readdir reply! " - "nr=%d, slots=%d, len=%d\n", + struct rpc_clnt *clnt = req->rq_task->tk_client; + printk(KERN_WARNING + "NFS: server %s, readdir reply truncated\n", + clnt->cl_server); + printk(KERN_WARNING "NFS: nr=%d, slots=%d, len=%d\n", nr, (end - p), len); + clnt->cl_flags |= NFS_CLNTF_BUFSIZE; break; } if (len > NFS_MAXNAMLEN) { diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c index 33e6dfd26..afc219838 100644 --- a/fs/nls/nls_base.c +++ b/fs/nls/nls_base.c @@ -12,8 +12,8 @@ #include <linux/config.h> #include <linux/nls.h> #include <linux/malloc.h> -#ifdef CONFIG_KERNELD -#include <linux/kerneld.h> +#ifdef CONFIG_KMOD +#include <linux/kmod.h> #endif #include <asm/byteorder.h> @@ -205,7 +205,7 @@ struct nls_table *find_nls(char *charset) struct nls_table *load_nls(char *charset) { struct nls_table *nls; -#ifdef CONFIG_KERNELD +#ifdef CONFIG_KMOD char buf[40]; int ret; #endif @@ -216,7 +216,7 @@ struct nls_table *load_nls(char *charset) return nls; } -#ifndef CONFIG_KERNELD +#ifndef CONFIG_KMOD return NULL; #else if (strlen(charset) > sizeof(buf) - sizeof("nls_")) { diff --git a/fs/ntfs/fs.c b/fs/ntfs/fs.c index aa6a7c40c..d190b21e4 100644 --- a/fs/ntfs/fs.c +++ b/fs/ntfs/fs.c @@ -776,13 +776,13 @@ struct super_block * ntfs_read_super(struct super_block *sb, struct buffer_head *bh; int i; - /* When the driver is compiled as a module, kerneld must know when it + /* When the driver is compiled as a module, kmod must know when it * can safely remove it from memory. To do this, each module owns a * reference counter. */ MOD_INC_USE_COUNT; /* Don't put ntfs_debug() before MOD_INC_USE_COUNT, printk() can block - * so this could lead to a race condition with kerneld. + * so this could lead to a race condition with kmod. */ ntfs_debug(DEBUG_OTHER, "ntfs_read_super\n"); @@ -939,7 +939,7 @@ __initfunc(int init_ntfs_fs(void)) #ifdef MODULE /* A module is a piece of code which can be inserted in and removed * from the running kernel whenever you want using lsmod, or on demand using - * kerneld + * kmod */ /* No function of this module is needed by another module */ @@ -956,7 +956,7 @@ MODULE_PARM_DESC(ntdebug, "Debug level"); /* When this code is compiled as a module, if you use mount -t ntfs when no * ntfs filesystem is registered (see /proc/filesystems), get_fs_type() in - * fs/super.c asks kerneld to load the module named ntfs in memory. + * fs/super.c asks kmod to load the module named ntfs in memory. * * Therefore, this function is the main entry point in this case */ @@ -965,7 +965,7 @@ int init_module(void) return init_ntfs_fs(); } -/* Called by kerneld just before the kernel removes the module from memory */ +/* Called by kmod just before the kernel removes the module from memory */ void cleanup_module(void) { SYSCTL(0); @@ -681,24 +681,37 @@ out: } /* - * Find an empty file descriptor entry, and mark it busy + * Find an empty file descriptor entry, and mark it busy. */ int get_unused_fd(void) { - int fd; struct files_struct * files = current->files; + int fd, error; + error = -EMFILE; fd = find_first_zero_bit(&files->open_fds, NR_OPEN); /* * N.B. For clone tasks sharing a files structure, this test * will limit the total number of files that can be opened. */ - if (fd < current->rlim[RLIMIT_NOFILE].rlim_cur) { - FD_SET(fd, &files->open_fds); - FD_CLR(fd, &files->close_on_exec); - return fd; + if (fd >= current->rlim[RLIMIT_NOFILE].rlim_cur) + goto out; + + /* Check here for fd > files->max_fds to do dynamic expansion */ + + FD_SET(fd, &files->open_fds); + FD_CLR(fd, &files->close_on_exec); +#if 1 + /* Sanity check */ + if (files->fd[fd] != NULL) { + printk("get_unused_fd: slot %d not NULL!\n", fd); + files->fd[fd] = NULL; } - return -EMFILE; +#endif + error = fd; + +out: + return error; } inline void put_unused_fd(unsigned int fd) @@ -796,15 +809,15 @@ asmlinkage int sys_close(unsigned int fd) { int error; struct file * filp; - struct files_struct * files; lock_kernel(); - files = current->files; error = -EBADF; - if (fd < NR_OPEN && (filp = files->fd[fd]) != NULL) { + filp = fcheck(fd); + if (filp) { + struct files_struct * files = current->files; + files->fd[fd] = NULL; put_unused_fd(fd); FD_CLR(fd, &files->close_on_exec); - files->fd[fd] = NULL; error = close_fp(filp, files); } unlock_kernel(); diff --git a/fs/proc/array.c b/fs/proc/array.c index 5364cea14..33df2c56a 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -446,7 +446,11 @@ static int get_array(struct task_struct *p, unsigned long start, unsigned long e static int get_env(int pid, char * buffer) { - struct task_struct *p = find_task_by_pid(pid); + struct task_struct *p; + + read_lock(&tasklist_lock); + p = find_task_by_pid(pid); + read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */ if (!p || !p->mm) return 0; @@ -455,8 +459,11 @@ static int get_env(int pid, char * buffer) static int get_arg(int pid, char * buffer) { - struct task_struct *p = find_task_by_pid(pid); + struct task_struct *p; + read_lock(&tasklist_lock); + p = find_task_by_pid(pid); + read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */ if (!p || !p->mm) return 0; return get_array(p, p->mm->arg_start, p->mm->arg_end, buffer); @@ -781,8 +788,11 @@ static inline char * task_sig(struct task_struct *p, char *buffer) static int get_status(int pid, char * buffer) { char * orig = buffer; - struct task_struct *tsk = find_task_by_pid(pid); + struct task_struct *tsk; + read_lock(&tasklist_lock); + tsk = find_task_by_pid(pid); + read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */ if (!tsk) return 0; buffer = task_name(tsk, buffer); @@ -794,7 +804,7 @@ 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); + struct task_struct *tsk; unsigned long vsize, eip, esp, wchan; long priority, nice; int tty_pgrp; @@ -805,6 +815,9 @@ static int get_stat(int pid, char * buffer) char sigcatch_str[sizeof(sigset_t)*2+1]; char state; + read_lock(&tasklist_lock); + tsk = find_task_by_pid(pid); + read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */ if (!tsk) return 0; state = *get_task_state(tsk); @@ -959,6 +972,9 @@ static int get_statm(int pid, char * buffer) struct task_struct *tsk = find_task_by_pid(pid); int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0; + read_lock(&tasklist_lock); + tsk = find_task_by_pid(pid); + read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */ if (!tsk) return 0; if (tsk->mm && tsk->mm != &init_mm) { @@ -1041,7 +1057,9 @@ static ssize_t read_maps (int pid, struct file * file, char * buf, goto out; retval = -EINVAL; + read_lock(&tasklist_lock); p = find_task_by_pid(pid); + read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */ if (!p) goto freepage_out; @@ -1152,9 +1170,11 @@ static int get_pidcpu(int pid, char * buffer) { struct task_struct * tsk = current ; int i, len; - + + read_lock(&tasklist_lock); if (pid != tsk->pid) tsk = find_task_by_pid(pid); + read_unlock(&tasklist_lock); /* FIXME!! This should be done after the last use */ if (tsk == NULL) return 0; diff --git a/fs/proc/base.c b/fs/proc/base.c index dc182682a..e535276bb 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -60,12 +60,14 @@ static void proc_pid_fill_inode(struct inode * inode, int fill) int pid = inode->i_ino >> 16; int ino = inode->i_ino & 0xffff; + read_lock(&tasklist_lock); if (fill && (p = find_task_by_pid(pid)) != NULL) { if (p->dumpable || ino == PROC_PID_INO) { inode->i_uid = p->euid; inode->i_gid = p->gid; } } + read_unlock(&tasklist_lock); } /* diff --git a/fs/proc/fd.c b/fs/proc/fd.c index 4baa299fc..8897578d6 100644 --- a/fs/proc/fd.c +++ b/fs/proc/fd.c @@ -96,7 +96,9 @@ static int proc_lookupfd(struct inode * dir, struct dentry * dentry) break; } } + read_lock(&tasklist_lock); p = find_task_by_pid(pid); + read_unlock(&tasklist_lock); /* FIXME!! This should be done only after not using 'p' any more */ if (!pid || !p) return -ENOENT; @@ -149,7 +151,9 @@ static int proc_readfd(struct file * filp, return 0; } + read_lock(&tasklist_lock); p = find_task_by_pid(pid); + read_unlock(&tasklist_lock); /* FIXME!! This should be done only after not using 'p' any more */ if(!p) return 0; tarrayp = p->tarray_ptr; diff --git a/fs/proc/inode.c b/fs/proc/inode.c index c33616604..9a0e29a84 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -260,7 +260,13 @@ void proc_read_inode(struct inode * inode) inode->i_size = 0; pid = ino >> 16; - if (!pid || ((p = find_task_by_pid(pid)) == NULL)) + if (!pid) + return; + read_lock(&tasklist_lock); + p = find_task_by_pid(pid); + read_unlock(&tasklist_lock); /* FIXME!! This should be done only after we have stopped using 'p' */ + + if (!p) return; ino &= 0x0000ffff; diff --git a/fs/proc/mem.c b/fs/proc/mem.c index c49f187c0..1cbdbad9a 100644 --- a/fs/proc/mem.c +++ b/fs/proc/mem.c @@ -83,7 +83,9 @@ static ssize_t mem_read(struct file * file, char * buf, char *tmp; ssize_t scount, i; + read_lock(&tasklist_lock); tsk = get_task(inode->i_ino >> 16); + read_unlock(&tasklist_lock); /* FIXME: This should really be done only afetr not using tsk any more!!! */ if (!tsk) return -ESRCH; addr = *ppos; diff --git a/fs/proc/root.c b/fs/proc/root.c index 3e344bd09..ad3a541cb 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -14,8 +14,8 @@ #include <linux/stat.h> #include <linux/config.h> #include <asm/bitops.h> -#ifdef CONFIG_KERNELD -#include <linux/kerneld.h> +#ifdef CONFIG_KMOD +#include <linux/kmod.h> #endif /* @@ -234,7 +234,7 @@ proc_openprom_deregister(void) } #endif -#if defined(CONFIG_SUN_OPENPROMFS_MODULE) && defined(CONFIG_KERNELD) +#if defined(CONFIG_SUN_OPENPROMFS_MODULE) && defined(CONFIG_KMOD) static int proc_openprom_defreaddir(struct inode * inode, struct file * filp, void * dirent, filldir_t filldir) @@ -812,14 +812,18 @@ static int proc_root_lookup(struct inode * dir, struct dentry * dentry) break; } } + read_lock(&tasklist_lock); p = find_task_by_pid(pid); inode = NULL; if (pid && p) { unsigned long ino = (pid << 16) + PROC_PID_INO; inode = proc_get_inode(dir->i_sb, ino, &proc_pid); - if (!inode) + if (!inode) { + read_unlock(&tasklist_lock); return -EINVAL; + } } + read_unlock(&tasklist_lock); dentry->d_op = &proc_dentry_operations; d_add(dentry, inode); diff --git a/fs/super.c b/fs/super.c index 84ef3ffb8..50a6cb9a6 100644 --- a/fs/super.c +++ b/fs/super.c @@ -37,14 +37,14 @@ #include <asm/uaccess.h> #include <asm/bitops.h> -#ifdef CONFIG_KERNELD -#include <linux/kerneld.h> -#endif - #include <linux/nfs_fs.h> #include <linux/nfs_fs_sb.h> #include <linux/nfs_mount.h> +#ifdef CONFIG_KMOD +#include <linux/kmod.h> +#endif + /* * We use a semaphore to synchronize all mount/umount * activity - imagine the mess if we have a race between @@ -405,7 +405,7 @@ struct file_system_type *get_fs_type(const char *name) return fs; for (fs = file_systems; fs && strcmp(fs->name, name); fs = fs->next) ; -#ifdef CONFIG_KERNELD +#ifdef CONFIG_KMOD if (!fs && (request_module(name) == 0)) { for (fs = file_systems; fs && strcmp(fs->name, name); fs = fs->next) ; diff --git a/fs/umsdos/README-WIP.txt b/fs/umsdos/README-WIP.txt index e48a4d184..ddc2911fc 100644 --- a/fs/umsdos/README-WIP.txt +++ b/fs/umsdos/README-WIP.txt @@ -32,34 +32,42 @@ Notes: possible very minor problems with dentry/inode/... kernel structures (ver - long file names - works - read file - works - switching MSDOS/UMSDOS - works? -- switching UMSDOS/MSDOS - untested -- pseudo root things - commented out mostly currently. To be fixed when +- switching UMSDOS/MSDOS - UNTESTED +- pseudo root things - COMMENTED OUT mostly currently. To be fixed when dentries stuff is straightened out. - resolve symlink - seems to work fully now! - dereference symlink - seems to work fully now! - hard links - seems to work now - special files (block/char device, fifos, sockets...) - seems to work ok. -- other ioctls - mostly untested +- other ioctls - MOSTLY UNTESTED - dangling symlink - UNTESTED ! -- create symlink - WARNING: NONE OF WRITE OPERATIONS FIXED YET! -- create hardlink - WARNING: NONE OF WRITE OPERATIONS FIXED YET! -- create file - creates, but corrupts. after reboot seem ok ? -- create special file - WARNING: NONE OF WRITE OPERATIONS FIXED YET! -- write to file - WARNING: NONE OF WRITE OPERATIONS FIXED YET! -- rename file (same dir) - WARNING: NONE OF WRITE OPERATIONS FIXED YET! -- rename file (dif. dir) - WARNING: NONE OF WRITE OPERATIONS FIXED YET! -- rename dir (same dir) - WARNING: NONE OF WRITE OPERATIONS FIXED YET! -- rename dir (dif. dir) - WARNING: NONE OF WRITE OPERATIONS FIXED YET! -- delete file - WARNING: NONE OF WRITE OPERATIONS FIXED YET! -- delete hardlink - WARNING: NONE OF WRITE OPERATIONS FIXED YET! -- mkdir - WARNING: NONE OF WRITE OPERATIONS FIXED YET! -- rmdir - WARNING: NONE OF WRITE OPERATIONS FIXED YET! -- umssyncing - WARNING: NONE OF WRITE OPERATIONS FIXED YET! +- create symlink - works on short names, but fails (gets + truncated on long ones) (also + due to some dentries problems, it may not + be visible right away always - eg. before + umount/mount) +- create hardlink - WARNING: NOT FIXED YET! +- create file - creates short names, but probs with long ones ? +- create special file - seems to work on short names. +- write to file - seems to work on short names. +- rename file (same dir) - WARNING: NOT FIXED YET! +- rename file (dif. dir) - WARNING: NOT FIXED YET! +- rename dir (same dir) - WARNING: NOT FIXED YET! +- rename dir (dif. dir) - WARNING: NOT FIXED YET! +- delete file - WARNING: NOT FIXED YET! +- notify_change (chown,perms) - seems to work! +- delete hardlink - WARNING: NOT FIXED YET! +- mkdir - seems to work, even with long names ! (but + due to some dentries problems, it may not + be visible right away always - eg. before + umount/mount) +- rmdir - WARNING: NOT FIXED YET! +- umssyncing - does something :-), but NEEDS EXTENSIVE TESTING Notes: moderate dentry/inode kernel structures trashing. Probably some other kernel structures compromised. Have SysRq support compiled in, and use -Sync/Emergency-remount-RO. And don't try mounting read/write yet - and then +Sync/Emergency-remount-RO. And if you don't try mounting read/write - you should have no big problems... Notes2: kernel structures trashing seems to be _MUCH_ lower if no @@ -69,6 +77,17 @@ Notes3: Notes2 is probably somewhat outdated now that hardlink/symlink stuff is supposed to be fixed enough to work, but I haven't got the time to test it. +Note4: on failure of creating of long filenames: MSDOS filename gets +created, and EMD entry gets created. Check: either they mismatch, or EMD +entry contains some wrong flags. + +Note5: rmdir(2) probably fails because do_rmdir calls lock_parent, which +uses dentry->d_parent, which we neglect to set, so it returns -ENOENT. +Probably same problem on unlink(2) ? What to do ? How to set +dentry->d_parent to something useful ?? Must I recurse down whole pathname +and set one by one all directory components ?! or only last one is really +needed ? help ! + ------------------------------------------------------------------------------ Some general notes: @@ -85,7 +104,7 @@ compile/test/reboot/set_environment/recompile cycle by removing 'reboot/set_environment' component that now occures every few cycles. But I need some help from someone knowing about dentries/inodes use more -than I. If you can help, please contact me... I'm mostly worries about +than I. If you can help, please contact me... I'm mostly worried about iget/iput and dget/dput, and deallocating temporary dentries we create. should we destroy temp dentries ? using d_invalidate ? using d_drop ? just dput them ? @@ -96,9 +115,9 @@ any direct Email in few days. If I don't - probably I never got your message. You can try mnalis@open.hr or mnalis@voyager.hr; however mnalis@jagor.srce.hr is preferable one. ------------------------------------------------------------------------------- -some of my notes for myself: +------------------------------------------------------------------------------ +some of my notes for myself /mn/: + hardlinks/symlinks. test with files in not_the_same_dir - also test not_the_same_dir for other file operations like rename etc. @@ -108,3 +127,17 @@ some of my notes for myself: - what about .dotfiles ? working ? multiple dots ? etc.... - fix stuff like dir->i_count++ to atomic_inc(&dir->i_count) and simular? + +- umsdos_create_any - calling msdos_create will create dentry for shor name. Hmmmm..? +- kill_dentry - put it where is needed. Also dput() at needed places. + +- when should dput()/iput() be used ?!! + +- probably problem with filename mangling somewhere, since both create and + write to file work on short filenames, but fail on long ones. Path + components may be of any size (eg. mkfifo /mnt/Very_long_dir2/blah1 will + succeed, but mkfifo /mnt/very_long_filename.txt won't) + + +- what is dir->i_count++ ? locking directory ? should this be lock_parent or +something ? diff --git a/fs/umsdos/dir.c b/fs/umsdos/dir.c index be1af20f7..52a72367e 100644 --- a/fs/umsdos/dir.c +++ b/fs/umsdos/dir.c @@ -31,7 +31,7 @@ extern struct inode *pseudo_root; uses. It's easier to do once than hack all the other instances. Probably safer as well */ -int compat_umsdos_real_lookup(struct inode *dir,const char *name,int len, struct inode **inode) +int compat_umsdos_real_lookup (struct inode *dir,const char *name,int len, struct inode **inode) { int rv; struct dentry *dentry; @@ -39,6 +39,7 @@ int compat_umsdos_real_lookup(struct inode *dir,const char *name,int len, struct dentry = creat_dentry (name, len, NULL); rv = umsdos_real_lookup(dir,dentry); if (inode) *inode = dentry->d_inode; + kill_dentry (dentry); return rv; } @@ -458,6 +459,7 @@ void umsdos_lookup_patch ( if (inode->u.umsdos_i.i_emd_owner==0) printk (KERN_WARNING "emd_owner still 0 ???\n"); } } + struct UMSDOS_DIRENT_K{ off_t f_pos; /* will hold the offset of the entry in EMD */ ino_t ino; @@ -533,6 +535,9 @@ int umsdos_inode2entry ( /* This is a DOS directory */ struct UMSDOS_DIR_SEARCH bufk; struct file filp; + + fill_new_filp (&filp, NULL); + Printk ((KERN_ERR "umsdos_inode2entry emddir==NULL: WARNING: Known filp problem. segfaulting :) /mn/\n")); filp.f_reada = 1; filp.f_pos = 0; @@ -548,6 +553,8 @@ int umsdos_inode2entry ( }else{ /* skip . and .. see umsdos_readdir_x() */ struct file filp; + fill_new_filp (&filp, NULL); + filp.f_reada = 1; filp.f_pos = UMSDOS_SPECIAL_DIRFPOS; Printk ((KERN_ERR "umsdos_inode2entry skip./..: WARNING: Known filp problem. segfaulting :) /mn/\n")); @@ -856,6 +863,9 @@ int umsdos_hlink2inode (struct inode *hlink, struct inode **result) struct file filp; loff_t offs = 0; + fill_new_filp (&filp, NULL); + + dentry_src = creat_dentry ("hlink-mn", 8, hlink); memset (&filp, 0, sizeof (filp)); diff --git a/fs/umsdos/emd.c b/fs/umsdos/emd.c index 169a75a45..8ba6571eb 100644 --- a/fs/umsdos/emd.c +++ b/fs/umsdos/emd.c @@ -14,6 +14,7 @@ #include <linux/string.h> #include <linux/msdos_fs.h> #include <linux/umsdos_fs.h> +#include <linux/dcache.h> #include <asm/uaccess.h> @@ -23,6 +24,29 @@ #define Printk(x) printk x /* + * makes empty filp + * + */ + +void fill_new_filp (struct file *filp, struct dentry *dentry) +{ + Printk (("/mn/ fill_new_filp: filling empty filp at %p\n", filp)); + if (dentry) + Printk ((" dentry=%.*s\n", (int) dentry->d_name.len, dentry->d_name.name)); + else + Printk ((" dentry is NULL ! you must fill it later...\n")); + + memset (filp, 0, sizeof (struct file)); + + filp->f_pos = 0; + filp->f_reada = 1; + filp->f_flags = O_RDWR; + filp->f_dentry = dentry; + filp->f_op = &umsdos_file_operations; /* /mn/ - we have to fill it with SOMETHING */ +} + + +/* * makes dentry. for name name with length len. /mn/ * if inode is not NULL, puts it also. * @@ -34,19 +58,49 @@ struct dentry *creat_dentry (const char *name, const int len, struct inode *inod struct qstr qname; if (inode) - Printk (("/mn/ creat_dentry: creating dentry with inode=%lu for %.*s\n", inode->i_ino, len, name)); + Printk ((KERN_DEBUG "/mn/ creat_dentry: creating dentry with inode=%lu for %.*s\n", inode->i_ino, len, name)); else - Printk (("/mn/ creat_dentry: creating empty dentry for %.*s\n", len, name)); + Printk ((KERN_DEBUG "/mn/ creat_dentry: creating empty dentry for %.*s\n", len, name)); qname.name = name; qname.len = len; qname.hash = 0; ret = d_alloc (parent,&qname); /* create new dentry */ - ret->d_inode = inode; + ret->d_inode = NULL; + + if (inode) d_add (ret, inode); + +/* ret->d_inode = inode; /mn/ FIXME this was old, replaced by d_add, delete this ! */ return ret; } +/* + * removes temporary dentry created by creat_dentry + * + */ + +void kill_dentry (struct dentry *dentry) +{ + if (dentry) { + Printk (("/mn/ kill_dentry: kill_dentry %.*s :", (int) dentry->d_name.len, dentry->d_name.name)); + if (dentry->d_inode) + Printk (("inode=%lu\n", dentry->d_inode->i_ino)); + else + Printk (("inode is NULL\n")); + + /* FIXME: is this ok ?! /mn/ */ + /* d_invalidate (dentry); */ + /*dput (dentry);*/ + } else { + Printk (("/mn/ kill_dentry: dentry is NULL ?!\n")); + } + + + Printk ((KERN_DEBUG "/mn/ kill_dentry: exiting...\n")); + return; +} + /* @@ -126,23 +180,24 @@ ssize_t umsdos_file_read_kmem (struct inode *emd_dir, /* - Write to a file from kernel space -*/ -ssize_t umsdos_file_write_kmem (struct inode *emd_dir, - struct file *filp, + * Write to file from kernel space. + * Does the real job, assumes all structures are initialized ! + */ + + +ssize_t umsdos_file_write_kmem_real (struct file *filp, const char *buf, size_t count, - loff_t *offs - ) + loff_t *offs) { - int ret; + ssize_t ret; mm_segment_t old_fs = get_fs(); - struct dentry *old_dentry; - Printk ((KERN_ERR " STARTED WRITE_KMEM /mn/\n")); + set_fs (KERNEL_DS); Printk ((KERN_ERR "umsdos_file_write_kmem /mn/: Checkin: filp=%p, buf=%p, size=%d, offs=%p\n", filp, buf, count, offs)); - Printk ((KERN_ERR " using emd=%ld\n", emd_dir->i_ino)); + Printk ((KERN_ERR " struct dentry=%p\n", filp->f_dentry)); + Printk ((KERN_ERR " struct inode=%p\n", filp->f_dentry->d_inode)); Printk ((KERN_ERR " inode=%lu, i_size=%lu\n", filp->f_dentry->d_inode->i_ino, filp->f_dentry->d_inode->i_size)); Printk ((KERN_ERR " ofs=%ld\n",(unsigned long) *offs)); Printk ((KERN_ERR " f_pos=%Lu\n", filp->f_pos)); @@ -152,23 +207,49 @@ ssize_t umsdos_file_write_kmem (struct inode *emd_dir, Printk ((KERN_ERR " f_owner=%d\n", filp->f_owner.uid)); Printk ((KERN_ERR " f_version=%ld\n", filp->f_version)); Printk ((KERN_ERR " f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin)); + + ret = fat_file_write (filp, buf, count, offs); + PRINTK ((KERN_ERR "fat_file_write returned with %ld!\n", ret)); + + set_fs (old_fs); + return ret; +} + + +/* + * Write to a file from kernel space + */ + +ssize_t umsdos_file_write_kmem (struct inode *emd_dir, + struct file *filp, + const char *buf, + size_t count, + loff_t *offs + ) +{ + int ret; + struct dentry *old_dentry; + - set_fs (KERNEL_DS); + Printk ((KERN_ERR " STARTED WRITE_KMEM /mn/\n")); + Printk ((KERN_ERR " using emd=%ld\n", emd_dir->i_ino)); + old_dentry=filp->f_dentry; /* save it */ filp->f_dentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, emd_dir); - *offs = filp->f_pos; - ret = fat_file_write (filp, buf, count, offs); - PRINTK ((KERN_ERR "fat_file_write returned with %ld!\n", ret)); + *offs = filp->f_pos; /* FIXME, in read_kmem also: offs is not used so why pass it ?!!! /mn/ */ + + ret=umsdos_file_write_kmem_real (filp, buf, count, offs); filp->f_pos = *offs; filp->f_dentry=old_dentry; - set_fs (old_fs); return ret; } + + /* Write a block of bytes into one EMD file. The block of data is NOT in user space. @@ -201,7 +282,7 @@ ssize_t umsdos_emd_dir_write (struct inode *emd_dir, #endif if (offs) myofs=*offs; /* if offs is not NULL, read it */ - Printk (("umsdos_emd_dir_write /mn/: calling write_kmem with %p, %p, %p, %ld, %Ld\n", emd_dir, filp, buf, count, myofs)); + Printk (("umsdos_emd_dir_write /mn/: calling write_kmem with %p, %p, %p, %d, %Ld\n", emd_dir, filp, buf, count, myofs)); written = umsdos_file_write_kmem (emd_dir, filp, buf, count, &myofs); Printk (("umsdos_emd_dir_write /mn/: write_kmem returned\n")); if (offs) *offs=myofs; /* if offs is not NULL, store myofs there */ @@ -216,6 +297,12 @@ ssize_t umsdos_emd_dir_write (struct inode *emd_dir, d->rdev = le16_to_cpu (d->rdev); d->mode = le16_to_cpu (d->mode); #endif + +#ifdef 1 + if (written != count) Printk ((KERN_ERR "umsdos_emd_dir_write: ERROR: written (%d) != count (%d)\n", written, count)); +#endif + + return written != count ? -EIO : 0; } @@ -409,7 +496,9 @@ int umsdos_writeentry ( struct file filp; struct umsdos_dirent *entry = &info->entry; struct umsdos_dirent entry0; - + + fill_new_filp (&filp, NULL); + Printk (("umsdos_writeentry /mn/: entering...\n")); emd_dentry=creat_dentry ("wremd_mn", 8, emd_dir); @@ -444,7 +533,7 @@ int umsdos_writeentry ( filp.f_op = &umsdos_file_operations; /* /mn/ - we have to fill it with dummy values so we won't segfault */ ret = umsdos_emd_dir_write (emd_dir, &filp, (char*)entry, info->recsize, NULL); - Printk (("emd_dir_write returned !\n")); + Printk (("emd_dir_write returned with %d!\n", ret)); if (ret != 0){ printk ("UMSDOS: problem with EMD file. Can't write\n"); }else{ @@ -452,7 +541,7 @@ int umsdos_writeentry ( /* dir->i_dirt = 1; FIXME iput/dput ??? */ } - Printk (("umsdos_writeentry /mn/: returning...\n")); + Printk (("umsdos_writeentry /mn/: returning %d...\n", ret)); return ret; } @@ -541,10 +630,13 @@ static int umsdos_find ( record, multiple contiguous record are allocated. */ int ret = -ENOENT; - /* FIXME -- /mn/ fixed ? */ - struct inode *emd_dir = umsdos_emd_dir_lookup (dir, 1); + struct inode *emd_dir; + struct umsdos_dirent *entry = &info->entry; + + Printk (("umsdos_find: locating %.*s in dir %lu\n", entry->name_len, entry->name, dir->i_ino)); + + emd_dir = umsdos_emd_dir_lookup (dir, 1); if (emd_dir != NULL){ - struct umsdos_dirent *entry = &info->entry; int recsize = info->recsize; struct { off_t posok; /* Position available to store the entry */ @@ -560,11 +652,7 @@ static int umsdos_find ( dentry = creat_dentry ("umsfind-mn", 10, emd_dir); - buf.filp.f_pos = 0; - buf.filp.f_reada = 1; - buf.filp.f_flags = O_RDONLY; - buf.filp.f_dentry = dentry; - buf.filp.f_op = &umsdos_file_operations; /* /mn/ - we have to fill it with dummy values so we won't segfault */ + fill_new_filp (&buf.filp, dentry); buf.pos = 0; buf.size = 0; @@ -631,6 +719,8 @@ static int umsdos_find ( umsdos_manglename(info); } *pt_emd_dir = emd_dir; + + Printk (("umsdos_find: returning %d\n", ret)); return ret; } @@ -651,7 +741,7 @@ int umsdos_newentry ( ret = -EEXIST; }else if (ret == -ENOENT){ ret = umsdos_writeentry(dir,emd_dir,info,0); - Printk (("umsdos_newentry EDM ret = %d\n",ret)); + Printk (("umsdos_newentry EMD ret = %d\n",ret)); } iput (emd_dir); return ret; @@ -729,6 +819,8 @@ int umsdos_isempty (struct inode *dir) /* If the EMD file does not exist, it is certainly empty :-) */ if (emd_dir != NULL){ struct file filp; + fill_new_filp (&filp, NULL); + /* Find an empty slot */ memset (&filp, 0, sizeof (filp)); @@ -779,6 +871,7 @@ int umsdos_findentry ( } } iput (emd_dir); + Printk (("umsdos_findentry: returning %d\n", ret)); return ret; } diff --git a/fs/umsdos/inode.c b/fs/umsdos/inode.c index 059a780e3..e8b65558c 100644 --- a/fs/umsdos/inode.c +++ b/fs/umsdos/inode.c @@ -105,7 +105,7 @@ void umsdos_setup_dir_inode (struct inode *inode) inode->i_op = &umsdos_dir_inode_operations; } - iput (emd_dir); +/* iput (emd_dir); FIXME /mn/ ! */ } } @@ -119,9 +119,10 @@ void umsdos_set_dirinfo( off_t f_pos) { struct inode *emd_owner; - /* FIXME, I don't have a clue on this one */ - Printk ((KERN_WARNING "umsdos_set_dirinfo: /mn/ FIXME: no clue\n")); + /* FIXME, I don't have a clue on this one - /mn/ hmmm ? ok ? */ +/* Printk ((KERN_WARNING "umsdos_set_dirinfo: /mn/ FIXME: no clue. inode=%lu dir=%lu\n", inode->i_ino, dir->i_ino));*/ emd_owner = umsdos_emd_dir_lookup(dir,1); + Printk (("umsdos_set_dirinfo: emd_owner is %lu for dir %lu\n", emd_owner->i_ino, dir->i_ino)); inode->u.umsdos_i.i_dir_owner = dir->i_ino; inode->u.umsdos_i.i_emd_owner = emd_owner->i_ino; iput (emd_owner); @@ -317,10 +318,10 @@ void UMSDOS_write_inode(struct inode *inode) /* FIXME inode->i_dirt = 0; */ } -int UMSDOS_notify_change(struct dentry *dentry, struct iattr *attr) + +int internal_notify_change(struct inode *inode, struct iattr *attr) { int ret = 0; - struct inode *inode = dentry->d_inode; Printk ((KERN_ERR "UMSDOS_notify_change: /mn/ completly untested\n")); @@ -362,10 +363,15 @@ int UMSDOS_notify_change(struct dentry *dentry, struct iattr *attr) }else{ struct file filp; struct umsdos_dirent entry; + struct dentry *emd_dentry; loff_t offs; - offs = 0; + + emd_dentry = creat_dentry ("notify_emd", 10, emd_owner); + fill_new_filp (&filp, emd_dentry); + filp.f_pos = inode->u.umsdos_i.pos; filp.f_reada = 0; + offs = filp.f_pos; /* FIXME: /mn/ is this ok ? */ Printk (("pos = %Lu ", filp.f_pos)); /* Read only the start of the entry since we don't touch */ /* the name */ @@ -386,7 +392,7 @@ int UMSDOS_notify_change(struct dentry *dentry, struct iattr *attr) entry.nlink = inode->i_nlink; filp.f_pos = inode->u.umsdos_i.pos; - offs = 0; /* FIXME */ + offs = filp.f_pos; /* FIXME: /mn/ is this ok ? */ ret = umsdos_emd_dir_write (emd_owner, &filp, (char*)&entry, UMSDOS_REC_SIZE, &offs); Printk (("notify pos %lu ret %d nlink %d " @@ -407,6 +413,15 @@ int UMSDOS_notify_change(struct dentry *dentry, struct iattr *attr) return ret; } + +int UMSDOS_notify_change(struct dentry *dentry, struct iattr *attr) +{ + return internal_notify_change (dentry->d_inode, attr); +} + + + + /* #Specification: function name / convention A simple convention for function name has been used in the UMSDOS file system. First all function use the prefix @@ -457,7 +472,7 @@ struct super_block *UMSDOS_read_super( PRINTK ((KERN_DEBUG "UMSDOS /mn/: sb = %p\n",sb)); res = msdos_read_super(sb,data,silent); PRINTK ((KERN_DEBUG "UMSDOS /mn/: res = %p\n",res)); - printk (KERN_INFO "UMSDOS dentry-WIP-Beta 0.82-1 (compatibility level %d.%d, fast msdos)\n", UMSDOS_VERSION, UMSDOS_RELEASE); + printk (KERN_INFO "UMSDOS dentry-WIP-Beta 0.82-2 (compatibility level %d.%d, fast msdos)\n", UMSDOS_VERSION, UMSDOS_RELEASE); if (res == NULL) { MOD_DEC_USE_COUNT; return NULL; } @@ -504,7 +519,7 @@ struct super_block *UMSDOS_read_super( The word "linux" is hardcoded in /usr/include/linux/umsdos_fs.h in the macro UMSDOS_PSDROOT_NAME. */ - struct dentry *root, *etc, *etc_rc, *init, *sbin; /* FIXME */ + struct dentry *root, *etc, *etc_rc, *init, *sbin; root = creat_dentry (UMSDOS_PSDROOT_NAME, strlen(UMSDOS_PSDROOT_NAME), NULL); sbin = creat_dentry ("sbin", 4, NULL); diff --git a/fs/umsdos/namei.c b/fs/umsdos/namei.c index 76c486405..dcea137fe 100644 --- a/fs/umsdos/namei.c +++ b/fs/umsdos/namei.c @@ -39,6 +39,7 @@ static int umsdos_waitcreate(struct inode *dir) } return ret; } + /* Wait for any lookup process to finish */ @@ -48,6 +49,7 @@ static void umsdos_waitlookup (struct inode *dir) sleep_on(&dir->u.umsdos_i.u.dir_info.p); } } + /* Lock all other process out of this directory. */ @@ -90,6 +92,7 @@ void umsdos_lockcreate (struct inode *dir) dir->u.umsdos_i.u.dir_info.pid = current->pid; umsdos_waitlookup (dir); } + /* Lock all other process out of those two directories. */ @@ -115,6 +118,7 @@ static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2) umsdos_waitlookup(dir1); umsdos_waitlookup(dir2); } + /* Wait until creation is finish in this directory. */ @@ -157,6 +161,7 @@ void umsdos_startlookup (struct inode *dir){} static void umsdos_unlockcreate (struct inode *dir){} void umsdos_endlookup (struct inode *dir){} #endif + static int umsdos_nevercreat( struct inode *dir, struct dentry *dentry, @@ -210,7 +215,11 @@ static int umsdos_create_any ( /* file */ { - int ret = umsdos_nevercreat(dir,dentry,-EEXIST); + int ret; + + Printk (("umsdos_create_any /mn/: create %.*s in dir=%lu - nevercreat=/", (int) dentry->d_name.len, dentry->d_name.name, dir->i_ino)); + ret = umsdos_nevercreat(dir,dentry,-EEXIST); + Printk (("%d/\n", ret)); if (ret == 0){ struct umsdos_info info; ret = umsdos_parse(dentry->d_name.name,dentry->d_name.len,&info); @@ -237,8 +246,8 @@ static int umsdos_create_any ( if (ret == 0){ struct inode *inode = dentry->d_inode; umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos); - Printk (("inode %p[%d] ",inode,inode->i_count)); - Printk (("Creation OK: [%lu] %.*s %d pos %ld\n", dir->i_ino, + Printk (("inode %p[%lu], count=%d ",inode, inode->i_ino, inode->i_count)); + Printk (("Creation OK: [dir %lu] %.*s pid=%d pos %ld\n", dir->i_ino, info.fake.len, info.fake.fname, current->pid, info.f_pos)); }else{ /* #Specification: create / file exist in DOS @@ -276,9 +285,10 @@ static int umsdos_create_any ( umsdos_unlockcreate(dir); } } - d_add(dentry,dir); + /* d_add(dentry,dir); /mn/ FIXME: msdos_create already did this for short name ! */ return ret; } + /* Initialise the new_entry from the old for a rename operation. (Only useful for umsdos_rename_f() below). @@ -425,6 +435,7 @@ static int umsdos_rename_f( Printk (("\n")); return ret; } + /* Setup un Symbolic link or a (pseudo) hard link Return a negative error code or 0 if ok. @@ -456,11 +467,13 @@ static int umsdos_symlink_x( if (ret == 0){ int len = strlen(symname); struct file filp; - filp.f_pos = 0; + loff_t myofs=0; + fill_new_filp (&filp, dentry); + /* Make the inode acceptable to MSDOS FIXME */ Printk ((KERN_ERR "umsdos_symlink_x: FIXME /mn/ Here goes the crash.. known wrong code...\n")); - ret = umsdos_file_write_kmem (dentry->d_inode, &filp,symname,ret,NULL); /* FIXME /mn/: dentry->d_inode->i_ino is totaly wrong, just put in to compile the beast... - PTW dentry->d_inode is "less incorrect" */ + Printk ((KERN_WARNING " symname=%s ; dentry name=%.*s (ino=%lu)\n", symname, (int) dentry->d_name.len, dentry->d_name.name, dentry->d_inode->i_ino)); + ret = umsdos_file_write_kmem_real (&filp, symname, len, &myofs); /* dput(dentry); ?? where did this come from FIXME */ if (ret >= 0){ if (ret != len){ @@ -480,6 +493,7 @@ static int umsdos_symlink_x( Printk (("\n")); return ret; } + /* Setup un Symbolic link. Return a negative error code or 0 if ok. @@ -492,6 +506,7 @@ int UMSDOS_symlink( { return umsdos_symlink_x (dir,dentry,symname,S_IFLNK|0777,0); } + /* Add a link to an inode in a directory */ @@ -671,6 +686,9 @@ int UMSDOS_link ( Printk (("umsdos_link %d\n",ret)); return ret; } + + + /* Add a new file into the alternate directory. The file is added to the real MSDOS directory. If successful, it @@ -680,13 +698,16 @@ int UMSDOS_link ( */ int UMSDOS_create ( struct inode *dir, - struct dentry *dentry, /* Length of the name */ + struct dentry *dentry, int mode /* Permission bit + file type ??? */ ) /* Will hold the inode of the newly created */ /* file */ { return umsdos_create_any (dir,dentry,mode,0,0); } + + + /* Add a sub-directory in a directory */ @@ -735,7 +756,7 @@ int UMSDOS_mkdir( ret = compat_umsdos_real_lookup (dir,info.fake.fname, info.fake.len,&subdir); if (ret == 0){ - struct inode *result; +/* struct inode *result; FIXME /mn/ hmmm what is this supposed to be ? */ struct dentry *tdentry; tdentry = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL); @@ -753,9 +774,10 @@ int UMSDOS_mkdir( } } Printk (("umsdos_mkdir %d\n",ret)); - dput (dentry); +/* dput (dentry); FIXME /mn/ */ return ret; } + /* Add a new device special file into a directory. */ @@ -779,8 +801,9 @@ int UMSDOS_mknod( for ordinary files was causing major trouble with hard link in particular and other parts of the kernel I guess. */ + int ret = umsdos_create_any (dir,dentry,mode,rdev,0); - dput(dentry); +/* dput(dentry); /mn/ FIXME! */ return ret; } @@ -952,13 +975,20 @@ int UMSDOS_unlink ( struct inode * dir, struct dentry *dentry) { - int ret = umsdos_nevercreat(dir,dentry,-EPERM); + int ret; + Printk ((" *** UMSDOS_unlink entering /mn/ *** \n")); + + ret = umsdos_nevercreat(dir,dentry,-EPERM); + + Printk (("UMSDOS_unlink /mn/: nevercreat=%d\n", ret)); + if (ret == 0){ struct umsdos_info info; ret = umsdos_parse (dentry->d_name.name,dentry->d_name.len,&info); if (ret == 0){ umsdos_lockcreate(dir); ret = umsdos_findentry(dir,&info,1); + Printk (("UMSDOS_unlink: findentry returned %d\n", ret)); if (ret == 0){ Printk (("UMSDOS_unlink %.*s ",info.fake.len,info.fake.fname)); /* check sticky bit */ diff --git a/fs/umsdos/symlink.c b/fs/umsdos/symlink.c index 38baba6ca..3ed550742 100644 --- a/fs/umsdos/symlink.c +++ b/fs/umsdos/symlink.c @@ -39,7 +39,8 @@ static int umsdos_readlink_x ( int ret; loff_t loffs = 0; struct file filp; - + + fill_new_filp (&filp, NULL); ret = dentry->d_inode->i_size; |