2003-10-06 10:02:57

by Kiernan, Michael

[permalink] [raw]
Subject: do_IRQ: stack overflow

Can anyone help me debug/(fix!) a stack overflow? (see attachment).

redhat 7.3, dual xeon 2.8GHz
2.4.20-20.7bigmem, but also occurs with 2.4.18-27.7bigmem and
non-bigmem versions.

Thanks,
Mike


Attachments:
xup.txt (52.38 kB)
xup.txt

2003-10-17 12:20:57

by Trond Myklebust

[permalink] [raw]
Subject: Re: do_IRQ: stack overflow

>>>>> " " == Michael Kiernan <Kiernan> writes:

> For the record; Steve's patch resolved this.

...but does the latest 2.4.22-bk snapshot?

I'd prefer not avoid having to convert all the nfs_fh and nfs_fattr
structures to use dynamic allocation if at all possible. Removing the
unused readdirplus-specific fields in struct nfs_entry is by far my
first choice for a solution. Now that has been done, then we can start
to worry about the remaining cases.

So has anybody ever seen stack overflow errors in any of the other
functions that allocate nfs_fh/nfs_fattr on the stack? That would be
mainly in nfs_lookup() and nfs_lookup_revalidate().

Cheers,
Trond


-------------------------------------------------------
This SF.net email is sponsored by: SF.net Giveback Program.
SourceForge.net hosts over 70,000 Open Source Projects.
See the people who have HELPED US provide better services:
Click here: http://sourceforge.net/supporters.php
_______________________________________________
NFS maillist - [email protected]
https://lists.sourceforge.net/lists/listinfo/nfs

2003-10-06 11:58:19

by Steve Dickson

[permalink] [raw]
Subject: Re: do_IRQ: stack overflow

--- linux-2.4.20/fs/nfs/inode.c.orig 2003-10-06 07:35:33.000000000 -0400
+++ linux-2.4.20/fs/nfs/inode.c 2003-10-06 07:38:35.000000000 -0400
@@ -1139,6 +1139,8 @@ extern int nfs_init_readpagecache(void);
extern int nfs_destroy_readpagecache(void);
extern int nfs_init_writepagecache(void);
extern int nfs_destroy_writepagecache(void);
+extern int nfs_init_diroppagecache(void);
+extern void nfs_destroy_diroppagecache(void);

/*
* Initialize NFS
@@ -1159,6 +1161,10 @@ static int __init init_nfs_fs(void)
if (err)
return err;

+ err = nfs_init_diroppagecache();
+ if (err)
+ return err;
+
#ifdef CONFIG_PROC_FS
rpc_proc_register(&nfs_rpcstat);
#endif
@@ -1167,6 +1173,7 @@ static int __init init_nfs_fs(void)

static void __exit exit_nfs_fs(void)
{
+ nfs_destroy_diroppagecache();
nfs_destroy_writepagecache();
nfs_destroy_readpagecache();
nfs_destroy_nfspagecache();
--- linux-2.4.20/fs/nfs/dir.c.orig 2003-10-06 07:35:31.000000000 -0400
+++ linux-2.4.20/fs/nfs/dir.c 2003-10-06 07:38:35.000000000 -0400
@@ -71,6 +71,51 @@ struct inode_operations nfs_dir_inode_op
revalidate: nfs_revalidate,
setattr: nfs_notify_change,
};
+static kmem_cache_t *nfs_ddata_cachep;
+
+int nfs_init_diroppagecache(void)
+{
+ nfs_ddata_cachep = kmem_cache_create("nfs_diropt_data",
+ sizeof(struct nfs_fh) + sizeof(struct nfs_fattr),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ if (nfs_ddata_cachep == NULL)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void nfs_destroy_diroppagecache(void)
+{
+ if (kmem_cache_destroy(nfs_ddata_cachep))
+ printk(KERN_INFO "nfs_diropt_data: not all structures were freed\n");
+}
+static __inline__ int
+nfs_dirop_alloc(struct nfs_fh **fh, struct nfs_fattr **fattr)
+{
+ void *mem;
+ static int len = sizeof(struct nfs_fh) + sizeof(struct nfs_fattr);
+
+ mem = kmem_cache_alloc(nfs_ddata_cachep, GFP_NOFS);
+ if (mem == NULL)
+ return -ENOMEM;
+
+ memset(mem, 0, len);
+ *fh = (struct nfs_fh *)mem;
+ *fattr = (struct nfs_fattr *) (mem + sizeof(struct nfs_fh));
+
+ return 0;
+}
+static __inline__ void
+nfs_dirop_free(struct nfs_fh *fh, struct nfs_fattr *fattr)
+{
+ void *mem = ((void *)fh < (void *)fattr ?
+ (void *)fh : (void *)fattr);
+
+ kmem_cache_free(nfs_ddata_cachep, mem);
+
+ return;
+}

static loff_t nfs_dir_llseek(struct file *file, loff_t offset, int origin)
{
@@ -373,12 +418,16 @@ static int nfs_readdir(struct file *filp
nfs_readdir_descriptor_t my_desc,
*desc = &my_desc;
struct nfs_entry my_entry;
+ struct nfs_fh *fh;
+ struct nfs_fattr *fattr;
long res;

res = nfs_revalidate(dentry);
if (res < 0)
return res;

+ if (nfs_dirop_alloc(&fh, &fattr))
+ return -ENOMEM;
/*
* filp->f_pos points to the file offset in the page cache.
* but if the cache has meanwhile been zapped, we need to
@@ -387,6 +436,8 @@ static int nfs_readdir(struct file *filp
*/
memset(desc, 0, sizeof(*desc));
memset(&my_entry, 0, sizeof(my_entry));
+ my_entry.fh = fh;
+ my_entry.fattr = fattr;

desc->file = filp;
desc->target = filp->f_pos;
@@ -414,6 +465,8 @@ static int nfs_readdir(struct file *filp
break;
}
}
+ nfs_dirop_free(fh, fattr);
+
if (desc->error < 0)
return desc->error;
if (res < 0)
@@ -497,8 +550,11 @@ static int nfs_lookup_revalidate(struct
struct inode *dir;
struct inode *inode;
int error;
- struct nfs_fh fhandle;
- struct nfs_fattr fattr;
+ struct nfs_fh *fhandle;
+ struct nfs_fattr *fattr;
+
+ if (nfs_dirop_alloc(&fhandle, &fattr))
+ return 0;

lock_kernel();
dir = dentry->d_parent->d_inode;
@@ -526,17 +582,18 @@ static int nfs_lookup_revalidate(struct
if (NFS_STALE(inode))
goto out_bad;

- error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr);
+ error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr);
if (error)
goto out_bad;
- if (memcmp(NFS_FH(inode), &fhandle, sizeof(struct nfs_fh))!= 0)
+ if (memcmp(NFS_FH(inode), fhandle, sizeof(struct nfs_fh))!= 0)
goto out_bad;
- if ((error = nfs_refresh_inode(inode, &fattr)) != 0)
+ if ((error = nfs_refresh_inode(inode, fattr)) != 0)
goto out_bad;

nfs_renew_times(dentry);
out_valid:
unlock_kernel();
+ nfs_dirop_free(fhandle, fattr);
return 1;
out_bad:
NFS_CACHEINV(dir);
@@ -550,6 +607,7 @@ static int nfs_lookup_revalidate(struct
}
d_drop(dentry);
unlock_kernel();
+ nfs_dirop_free(fhandle, fattr);
return 0;
}

@@ -596,8 +654,8 @@ static struct dentry *nfs_lookup(struct
{
struct inode *inode;
int error;
- struct nfs_fh fhandle;
- struct nfs_fattr fattr;
+ struct nfs_fh *fhandle;
+ struct nfs_fattr *fattr;

dfprintk(VFS, "NFS: lookup(%s/%s)\n",
dentry->d_parent->d_name.name, dentry->d_name.name);
@@ -607,15 +665,17 @@ static struct dentry *nfs_lookup(struct
goto out;

error = -ENOMEM;
+ if (nfs_dirop_alloc(&fhandle, &fattr))
+ goto out;
dentry->d_op = &nfs_dentry_operations;

- error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, &fhandle, &fattr);
+ error = NFS_PROTO(dir)->lookup(dir, &dentry->d_name, fhandle, fattr);
inode = NULL;
if (error == -ENOENT)
goto no_entry;
if (!error) {
error = -EACCES;
- inode = nfs_fhget(dentry, &fhandle, &fattr);
+ inode = nfs_fhget(dentry, fhandle, fattr);
if (inode) {
no_entry:
d_add(dentry, inode);
@@ -624,6 +684,7 @@ static struct dentry *nfs_lookup(struct
nfs_renew_times(dentry);
}
out:
+ nfs_dirop_free(fhandle, fattr);
return ERR_PTR(error);
}

@@ -663,13 +724,16 @@ out_err:
static int nfs_create(struct inode *dir, struct dentry *dentry, int mode)
{
struct iattr attr;
- struct nfs_fattr fattr;
- struct nfs_fh fhandle;
+ struct nfs_fattr *fattr;
+ struct nfs_fh *fhandle;
int error;

dfprintk(VFS, "NFS: create(%x/%ld, %s\n",
dir->i_dev, dir->i_ino, dentry->d_name.name);

+ if (nfs_dirop_alloc(&fhandle, &fattr))
+ return -ENOMEM;
+
attr.ia_mode = mode;
attr.ia_valid = ATTR_MODE;

@@ -681,11 +745,13 @@ static int nfs_create(struct inode *dir,
*/
nfs_zap_caches(dir);
error = NFS_PROTO(dir)->create(dir, &dentry->d_name,
- &attr, 0, &fhandle, &fattr);
+ &attr, 0, fhandle, fattr);
if (!error)
- error = nfs_instantiate(dentry, &fhandle, &fattr);
+ error = nfs_instantiate(dentry, fhandle, fattr);
else
d_drop(dentry);
+
+ nfs_dirop_free(fhandle, fattr);
return error;
}

@@ -695,23 +761,28 @@ static int nfs_create(struct inode *dir,
static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
{
struct iattr attr;
- struct nfs_fattr fattr;
- struct nfs_fh fhandle;
+ struct nfs_fattr *fattr;
+ struct nfs_fh *fhandle;
int error;

dfprintk(VFS, "NFS: mknod(%x/%ld, %s\n",
dir->i_dev, dir->i_ino, dentry->d_name.name);

+ if (nfs_dirop_alloc(&fhandle, &fattr))
+ return -ENOMEM;
+
attr.ia_mode = mode;
attr.ia_valid = ATTR_MODE;

nfs_zap_caches(dir);
error = NFS_PROTO(dir)->mknod(dir, &dentry->d_name, &attr, rdev,
- &fhandle, &fattr);
+ fhandle, fattr);
if (!error)
- error = nfs_instantiate(dentry, &fhandle, &fattr);
+ error = nfs_instantiate(dentry, fhandle, fattr);
else
d_drop(dentry);
+
+ nfs_dirop_free(fhandle, fattr);
return error;
}

@@ -721,13 +792,16 @@ static int nfs_mknod(struct inode *dir,
static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{
struct iattr attr;
- struct nfs_fattr fattr;
- struct nfs_fh fhandle;
+ struct nfs_fattr *fattr;
+ struct nfs_fh *fhandle;
int error;

dfprintk(VFS, "NFS: mkdir(%x/%ld, %s\n",
dir->i_dev, dir->i_ino, dentry->d_name.name);

+ if (nfs_dirop_alloc(&fhandle, &fattr))
+ return -ENOMEM;
+
attr.ia_valid = ATTR_MODE;
attr.ia_mode = mode | S_IFDIR;

@@ -741,12 +815,14 @@ static int nfs_mkdir(struct inode *dir,
d_drop(dentry);
#endif
nfs_zap_caches(dir);
- error = NFS_PROTO(dir)->mkdir(dir, &dentry->d_name, &attr, &fhandle,
- &fattr);
+ error = NFS_PROTO(dir)->mkdir(dir, &dentry->d_name, &attr, fhandle,
+ fattr);
if (!error)
- error = nfs_instantiate(dentry, &fhandle, &fattr);
+ error = nfs_instantiate(dentry, fhandle, fattr);
else
d_drop(dentry);
+
+ nfs_dirop_free(fhandle, fattr);
return error;
}

--- linux-2.4.20/fs/nfs/nfs3xdr.c.orig 2003-10-06 07:35:31.000000000 -0400
+++ linux-2.4.20/fs/nfs/nfs3xdr.c 2003-10-06 07:38:35.000000000 -0400
@@ -625,10 +625,10 @@ nfs3_decode_dirent(u32 *p, struct nfs_en
entry->cookie = nfs_transform_cookie64(cookie);

if (plus) {
- p = xdr_decode_post_op_attr(p, &entry->fattr);
+ p = xdr_decode_post_op_attr(p, entry->fattr);
/* In fact, a post_op_fh3: */
if (*p++) {
- p = xdr_decode_fhandle(p, &entry->fh);
+ p = xdr_decode_fhandle(p, entry->fh);
/* Ugh -- server reply was truncated */
if (p == NULL) {
dprintk("NFS: FH truncated\n");
@@ -638,7 +638,7 @@ nfs3_decode_dirent(u32 *p, struct nfs_en
} else {
/* If we don't get a file handle, the attrs
* aren't worth a lot. */
- entry->fattr.valid = 0;
+ entry->fattr->valid = 0;
}
}

--- linux-2.4.20/include/linux/nfs_xdr.h.orig 2002-11-28 18:53:15.000000000 -0500
+++ linux-2.4.20/include/linux/nfs_xdr.h 2003-10-06 07:38:35.000000000 -0400
@@ -109,8 +109,8 @@ struct nfs_entry {
const char * name;
unsigned int len;
int eof;
- struct nfs_fh fh;
- struct nfs_fattr fattr;
+ struct nfs_fh *fh;
+ struct nfs_fattr *fattr;
};

/*


Attachments:
linux-2.4.20-nfs-stackoverflow.patch (9.13 kB)

2003-10-17 07:19:43

by Kiernan, Michael

[permalink] [raw]
Subject: RE: do_IRQ: stack overflow

For the record; Steve's patch resolved this.

-----Original Message-----
From: Steve Dickson [mailto:[email protected]]
Sent: 06 October 2003 13:58
To: Kiernan, Michael
Cc: [email protected]
Subject: Re: [NFS] do_IRQ: stack overflow


Kiernan, Michael wrote:

>Can anyone help me debug/(fix!) a stack overflow? (see attachment).
>
>redhat 7.3, dual xeon 2.8GHz
>2.4.20-20.7bigmem, but also occurs with 2.4.18-27.7bigmem and
>non-bigmem versions.
>
>
See if this helps....

SteveD.