summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1998-03-18 17:17:51 +0000
committerRalf Baechle <ralf@linux-mips.org>1998-03-18 17:17:51 +0000
commitf1382dc4850bb459d24a81c6cb0ef93ea7bd4a79 (patch)
tree225271a3d5dcd4e9dea5ee393556abd754c964b1 /fs
parent135b00fc2e90e605ac2a96b20b0ebd93851a3f89 (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')
-rw-r--r--fs/buffer.c6
-rw-r--r--fs/coda/Makefile2
-rw-r--r--fs/coda/cache.c196
-rw-r--r--fs/coda/cnode.c59
-rw-r--r--fs/coda/coda_linux.c23
-rw-r--r--fs/coda/dir.c104
-rw-r--r--fs/coda/file.c49
-rw-r--r--fs/coda/inode.c (renamed from fs/coda/super.c)35
-rw-r--r--fs/coda/psdev.c4
-rw-r--r--fs/coda/upcall.c55
-rw-r--r--fs/devices.c13
-rw-r--r--fs/exec.c8
-rw-r--r--fs/fcntl.c39
-rw-r--r--fs/filesystems.c8
-rw-r--r--fs/hfs/ChangeLog53
-rw-r--r--fs/hfs/Makefile2
-rw-r--r--fs/hfs/catalog.c403
-rw-r--r--fs/hfs/dir.c19
-rw-r--r--fs/hfs/dir_cap.c16
-rw-r--r--fs/hfs/dir_dbl.c19
-rw-r--r--fs/hfs/dir_nat.c10
-rw-r--r--fs/hfs/file.c16
-rw-r--r--fs/hfs/file_cap.c5
-rw-r--r--fs/hfs/file_hdr.c13
-rw-r--r--fs/hfs/hfs.h13
-rw-r--r--fs/hfs/inode.c45
-rw-r--r--fs/hfs/string.c11
-rw-r--r--fs/hfs/super.c15
-rw-r--r--fs/hfs/sysdep.c39
-rw-r--r--fs/hfs/version.c2
-rw-r--r--fs/ncpfs/Config.in2
-rw-r--r--fs/ncpfs/Makefile3
-rw-r--r--fs/ncpfs/dir.c2
-rw-r--r--fs/ncpfs/inode.c4
-rw-r--r--fs/ncpfs/ioctl.c33
-rw-r--r--fs/ncpfs/ncpsign_kernel.c114
-rw-r--r--fs/ncpfs/ncpsign_kernel.h16
-rw-r--r--fs/nfs/inode.c21
-rw-r--r--fs/nfs/nfs2xdr.c65
-rw-r--r--fs/nls/nls_base.c8
-rw-r--r--fs/ntfs/fs.c10
-rw-r--r--fs/open.c35
-rw-r--r--fs/proc/array.c30
-rw-r--r--fs/proc/base.c2
-rw-r--r--fs/proc/fd.c4
-rw-r--r--fs/proc/inode.c8
-rw-r--r--fs/proc/mem.c2
-rw-r--r--fs/proc/root.c12
-rw-r--r--fs/super.c10
-rw-r--r--fs/umsdos/README-WIP.txt75
-rw-r--r--fs/umsdos/dir.c12
-rw-r--r--fs/umsdos/emd.c155
-rw-r--r--fs/umsdos/inode.c33
-rw-r--r--fs/umsdos/namei.c54
-rw-r--r--fs/umsdos/symlink.c3
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(&current->sigmask_lock);
- pending = current->blocked.sig[0] & current->signal.sig[0];
- spin_unlock_irq(&current->sigmask_lock);
-
/* if this process really wants to die, let it go */
- if ( sigismember(&pending, SIGKILL) ||
- sigismember(&pending, SIGINT) )
+ if ( sigismember(&current->signal, SIGKILL) ||
+ sigismember(&current->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)) ||
diff --git a/fs/exec.c b/fs/exec.c
index f023054c6..c3d420973 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -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, &current->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);
diff --git a/fs/open.c b/fs/open.c
index 5b0ff9924..204294cc3 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -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;