lkml.org 
[lkml]   [1999]   [Jan]   [26]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[PATCH] 2.2.0 NTFS driver memory leaks & checking
Hi all,

This is a patch against 2.2.0 for the NTFS driver which

- fixes a small memory leak, and
- checks for kmalloc() failure every where it is used and
copes appropriately

This should stop the out of memory Oops, though it doesn't address the
obscene memory usage issue - I'm going to play with vmalloc() rather
than kmalloc() and see what happens.

S.

--
%DCL-MEM-BAD, bad memory
VMS-F-PDGERS, pudding between the ears
Only in linux/fs/ntfs/: .attr.o.flags
Only in linux/fs/ntfs/: .dir.o.flags
Only in linux/fs/ntfs/: .fs.o.flags
Only in linux/fs/ntfs/: .inode.o.flags
Only in linux/fs/ntfs/: .ntfs.o.flags
Only in linux/fs/ntfs/: .super.o.flags
Only in linux/fs/ntfs/: .support.o.flags
Only in linux/fs/ntfs/: .sysctl.o.flags
Only in linux/fs/ntfs/: .util.o.flags
diff -ur vanilla/fs/ntfs/attr.c linux/fs/ntfs/attr.c
--- vanilla/fs/ntfs/attr.c Sun Jan 3 17:23:02 1999
+++ linux/fs/ntfs/attr.c Wed Jan 27 00:28:49 1999
@@ -19,7 +19,8 @@

/* Look if an attribute already exists in the inode, and if not, create it */
static int
-new_attr(ntfs_inode *ino,int type,void *name,int namelen,int *pos, int *found)
+new_attr(ntfs_inode *ino,int type,void *name,int namelen,int *pos, int *found,
+ int do_search )
{
int do_insert=0;
int i;
@@ -28,15 +29,17 @@
{
int n=min(namelen,ino->attrs[i].namelen);
int s=ntfs_uni_strncmp(ino->attrs[i].name,name,n);
- /*
- * We assume that each attribute can be uniquely
- * identified by inode
- * number, attribute type and attribute name.
- */
- if(ino->attrs[i].type==type && ino->attrs[i].namelen==namelen && !s){
- *found=1;
- *pos=i;
- return 0;
+ if( do_search ) {
+ /*
+ * We assume that each attribute can be uniquely
+ * identified by inode
+ * number, attribute type and attribute name.
+ */
+ if(ino->attrs[i].type==type && ino->attrs[i].namelen==namelen && !s){
+ *found=1;
+ *pos=i;
+ return 0;
+ }
}
/* attributes are ordered by type, then by name */
if(ino->attrs[i].type>type || (ino->attrs[i].type==type && s==1)){
@@ -48,17 +51,21 @@
/* re-allocate space */
if(ino->attr_count % 8 ==0)
{
- ntfs_attribute* old=ino->attrs;
- ino->attrs = (ntfs_attribute*)ntfs_malloc((ino->attr_count+8)*
+ ntfs_attribute* new;
+ new = (ntfs_attribute*)ntfs_malloc((ino->attr_count+8)*
sizeof(ntfs_attribute));
- if(old){
- ntfs_memcpy(ino->attrs,old,ino->attr_count*sizeof(ntfs_attribute));
- ntfs_free(old);
+ if( !new )
+ return ENOMEM;
+ if( ino->attrs ) {
+ ntfs_memcpy( new, ino->attrs, ino->attr_count*sizeof(ntfs_attribute) );
+ ntfs_free( ino->attrs );
}
+ ino->attrs = new;
}
if(do_insert)
ntfs_memmove(ino->attrs+i+1,ino->attrs+i,(ino->attr_count-i)*
sizeof(ntfs_attribute));
+
ino->attr_count++;
ino->attrs[i].type=type;
ino->attrs[i].namelen=namelen;
@@ -86,14 +93,16 @@
{
/* (re-)allocate space if necessary */
if(attr->d.r.len % 8 == 0) {
- ntfs_runlist* old;
- old=attr->d.r.runlist;
- attr->d.r.runlist=ntfs_malloc((attr->d.r.len+8)*sizeof(ntfs_runlist));
- if(old) {
- ntfs_memcpy(attr->d.r.runlist,old,attr->d.r.len
+ ntfs_runlist* new;
+ new = ntfs_malloc((attr->d.r.len+8)*sizeof(ntfs_runlist));
+ if( !new )
+ return;
+ if( attr->d.r.runlist ) {
+ ntfs_memcpy(new, attr->d.r.runlist, attr->d.r.len
*sizeof(ntfs_runlist));
- ntfs_free(old);
+ ntfs_free( attr->d.r.runlist );
}
+ attr->d.r.runlist = new;
}
if(attr->d.r.len>cnum)
ntfs_memmove(attr->d.r.runlist+cnum+1,attr->d.r.runlist+cnum,
@@ -208,8 +217,10 @@
v=attr->d.data;
if(newsize){
attr->d.data=ntfs_malloc(newsize);
- if(!attr->d.data)
+ if(!attr->d.data) {
+ ntfs_free(v);
return ENOMEM;
+ }
if(newsize>oldsize)
ntfs_bzero((char*)attr->d.data+oldsize,
newsize-oldsize);
@@ -279,12 +290,20 @@
if(aname){
namelen=strlen(aname);
name=ntfs_malloc(2*namelen);
+ if( !name )
+ return ENOMEM;
ntfs_ascii2uni(name,aname,namelen);
}else{
name=0;
namelen=0;
}
- new_attr(ino,anum,name,namelen,&i,&found);
+
+ error = new_attr(ino,anum,name,namelen,&i,&found,1);
+ if( error ) {
+ ntfs_free( name );
+ return error;
+ }
+
if(found){
ntfs_free(name);
return EEXIST;
@@ -309,6 +328,10 @@
}else
attr->indexed=0;
attr->d.data=ntfs_malloc(dsize);
+
+ if( !attr->d.data )
+ return ENOMEM;
+
ntfs_memcpy(attr->d.data,data,dsize);
return 0;
}
@@ -366,6 +389,7 @@
int namelen;
void *data;
ntfs_attribute *attr;
+ int error;

type = NTFS_GETU32(attrdata);
namelen = NTFS_GETU8(attrdata+9);
@@ -376,15 +400,30 @@
{
/* 1 Unicode character fits in 2 bytes */
name=ntfs_malloc(2*namelen);
+ if( !name )
+ return ENOMEM;
+
ntfs_memcpy(name,attrdata+NTFS_GETU16(attrdata+10),2*namelen);
}
- new_attr(ino,type,name,namelen,&i,&found);
+
+ error = new_attr(ino,type,name,namelen,&i,&found,1);
+ if( error ) {
+ if( name ) ntfs_free( name );
+ return error;
+ }
+
/* We can have in one inode two attributes with type 0x00000030 (File Name)
and without name */
if(found && /*FIXME*/type!=ino->vol->at_file_name)
{
ntfs_process_runs(ino,ino->attrs+i,attrdata);
return 0;
+ } else if( found ) {
+ /* Don't understand the above, but I know it leaks memory below
+ as it overwrites a found entry without freeing it. So here we
+ call new_attr again but this time ask it to always allocate a
+ new entry */
+ new_attr(ino,type,name,namelen,&i,&found,0);
}
attr=ino->attrs+i;
attr->resident=NTFS_GETU8(attrdata+8)==0;
@@ -395,6 +434,8 @@
attr->size=NTFS_GETU16(attrdata+0x10);
data=attrdata+NTFS_GETU16(attrdata+0x14);
attr->d.data = (void*)ntfs_malloc(attr->size);
+ if( !attr->d.data )
+ return ENOMEM;
ntfs_memcpy(attr->d.data,data,attr->size);
attr->indexed=NTFS_GETU16(attrdata+0x16);
}else{
Only in linux/fs/ntfs/: attr.c.orig
Only in linux/fs/ntfs/: attr.c.rej
Only in linux/fs/ntfs/: attr.o
diff -ur vanilla/fs/ntfs/dir.c linux/fs/ntfs/dir.c
--- vanilla/fs/ntfs/dir.c Sun Jan 3 17:23:02 1999
+++ linux/fs/ntfs/dir.c Tue Jan 26 23:44:58 1999
@@ -166,6 +166,8 @@
int nr_fix = s1/vol->blocksize+1;
int hsize;
char *record=ntfs_malloc(s1);
+ if( !record )
+ return ENOMEM;
ntfs_bzero(record,s1);
/* magic */
ntfs_memcpy(record,"INDX",4);
@@ -395,8 +397,9 @@
goto out;
}
index = ntfs_malloc(ino->vol->index_recordsize);
- if(!index)
- goto out;
+ if(!index) {
+ error = ENOMEM; goto out;
+ }
walk.dir = ino;
walk.block = -1;
walk.result = walk.new_entry = 0;
@@ -485,6 +488,9 @@
int oldblock;
ntfs_io io;

+ if( !record )
+ return ENOMEM;
+
io.fn_put=ntfs_put;
io.param=record;
io.size=length;
@@ -683,6 +689,9 @@
char *root=ntfs_malloc(length);
ntfs_io io;

+ if( !root )
+ return ENOMEM;
+
io.fn_put=ntfs_put;
io.param=root;
io.size=length;
@@ -747,6 +756,8 @@
/* are we still in the index root */
if(*p_high==0){
buf=ntfs_malloc(length=vol->mft_recordsize);
+ if( !buf )
+ return ENOMEM;
io.fn_put=ntfs_put;
io.param=buf;
io.size=length;
@@ -762,6 +773,8 @@
}else{ /* we are in an index record */
length=ino->u.index.recordsize;
buf=ntfs_malloc(length);
+ if( !buf )
+ return ENOMEM;
io.fn_put=ntfs_put;
io.param=buf;
io.size=length;
@@ -821,6 +834,9 @@
return 0;
}
buf=ntfs_malloc(length=attr->size);
+ if( !buf )
+ return ENOMEM;
+
io.param=buf;
io.size=length;
error=ntfs_read_attr(ino,vol->at_bitmap,I30,0,&io);
Only in linux/fs/ntfs/: dir.o
diff -ur vanilla/fs/ntfs/fs.c linux/fs/ntfs/fs.c
--- vanilla/fs/ntfs/fs.c Sun Jan 3 17:23:02 1999
+++ linux/fs/ntfs/fs.c Wed Jan 27 00:14:12 1999
@@ -387,6 +387,8 @@
if(error)
return error;
item=ntfs_malloc(ITEM_SIZE);
+ if( !item )
+ return ENOMEM;
/* ntfs_getdir will place the directory entry into item,
and the first long long is the MFT record number */
walk.type=BY_NAME;
@@ -707,6 +709,7 @@
#ifdef NTFS_IN_LINUX_KERNEL
ino=&inode->u.ntfs_i;
#else
+ /* FIXME: check for ntfs_malloc failure */
ino=(ntfs_inode*)ntfs_malloc(sizeof(ntfs_inode));
inode->u.generic_ip=ino;
#endif
@@ -816,6 +819,7 @@
struct statfs fs;
struct inode *mft;
ntfs_volume *vol;
+ int error;

ntfs_debug(DEBUG_OTHER, "ntfs_statfs\n");
vol=NTFS_SB2VOL(sb);
@@ -823,7 +827,9 @@
fs.f_type=NTFS_SUPER_MAGIC;
fs.f_bsize=vol->clustersize;

- fs.f_blocks=ntfs_get_volumesize(NTFS_SB2VOL(sb));
+ error = ntfs_get_volumesize( NTFS_SB2VOL( sb ), &fs.f_blocks );
+ if( error )
+ return error;
fs.f_bfree=ntfs_get_free_cluster_count(vol->bitmap);
fs.f_bavail=fs.f_bfree;

Only in linux/fs/ntfs/: fs.o
diff -ur vanilla/fs/ntfs/inode.c linux/fs/ntfs/inode.c
--- vanilla/fs/ntfs/inode.c Sun Jan 3 17:23:02 1999
+++ linux/fs/ntfs/inode.c Tue Jan 26 23:50:46 1999
@@ -165,13 +165,16 @@
/* (re-)allocate space if necessary */
if(ino->record_count % 8==0)
{
- int *old=ino->records;
- ino->records=ntfs_malloc((ino->record_count+8)*sizeof(int));
- if(old) {
+ int *new;
+ new = ntfs_malloc((ino->record_count+8)*sizeof(int));
+ if( !new )
+ return;
+ if( ino->records ) {
for(i=0;i<ino->record_count;i++)
- ino->records[i]=old[i];
- ntfs_free(old);
+ new[i] = ino->records[i];
+ ntfs_free( ino->records );
}
+ ino->records = new;
}
ino->records[ino->record_count]=mftno;
ino->record_count++;
@@ -179,8 +182,10 @@
do{
type=NTFS_GETU32(it);
len=NTFS_GETU32(it+4);
- if(type!=-1)
+ if(type!=-1) {
+ /* FIXME: check ntfs_insert_attribute for failure (e.g. no mem)? */
ntfs_insert_attribute(ino,it);
+ }
it+=len;
}while(type!=-1); /* attribute list ends with type -1 */
}
@@ -195,6 +200,8 @@
int last_mft=-1;
int len=*plen;
mft=ntfs_malloc(ino->vol->mft_recordsize);
+ if( !mft )
+ return ENOMEM;
while(len>8)
{
l=NTFS_GETU16(alist+4);
@@ -239,6 +246,8 @@
return;
}
buf=ntfs_malloc(1024);
+ if( !buf )
+ return;
delta=0;
for(offset=0;datasize;datasize-=len)
{
@@ -271,6 +280,8 @@
ino->i_number=inum;
ino->vol=vol;
ino->attr=buf=ntfs_malloc(vol->mft_recordsize);
+ if( !buf )
+ return ENOMEM;
error=ntfs_read_mft_record(vol,inum,ino->attr);
if(error){
ntfs_debug(DEBUG_OTHER, "init inode: %x failed\n",inum);
@@ -1108,6 +1119,8 @@
/* work out the size */
size = 0x42 + 2 * length;
data = ntfs_malloc(size);
+ if( !data )
+ return ENOMEM;
ntfs_bzero(data,size);

/* search for a position */
@@ -1238,10 +1251,17 @@
result->sequence_number=NTFS_GETU16(buffer)+1;
result->vol=vol;
result->attr=ntfs_malloc(vol->mft_recordsize);
+ if( !result->attr )
+ return ENOMEM;
result->attr_count=0;
result->attrs=0;
result->record_count=1;
result->records=ntfs_malloc(8*sizeof(int));
+ if( !result->records ) {
+ ntfs_free( result->attr );
+ result->attr = NULL;
+ return ENOMEM;
+ }
result->records[0]=result->i_number;
error=add_mft_header(result);
if(error)
Only in linux/fs/ntfs/: inode.o
Only in linux/fs/ntfs/: ntfs.o
diff -ur vanilla/fs/ntfs/super.c linux/fs/ntfs/super.c
--- vanilla/fs/ntfs/super.c Sun Jan 3 17:23:02 1999
+++ linux/fs/ntfs/super.c Wed Jan 27 00:05:32 1999
@@ -113,6 +113,8 @@
ntfs_io io;
#define UPCASE_LENGTH 256
upcase->vol->upcase = ntfs_malloc(2*UPCASE_LENGTH);
+ if( !upcase->vol->upcase )
+ return;
upcase->vol->upcase_length = UPCASE_LENGTH;
io.fn_put=ntfs_put;
io.fn_get=0;
@@ -246,11 +248,22 @@
return 0;
}

-int ntfs_get_volumesize(ntfs_volume *vol)
+/*
+ * Writes the volume size into vol_size. Returns 0 if successful
+ * or error.
+ */
+int ntfs_get_volumesize(ntfs_volume *vol, long *vol_size )
{
ntfs_io io;
- char *cluster0=ntfs_malloc(vol->clustersize);
ntfs_u64 size;
+ char *cluster0;
+
+ if( !vol_size )
+ return EFAULT;
+
+ cluster0=ntfs_malloc(vol->clustersize);
+ if( !cluster0 )
+ return ENOMEM;

io.fn_put=ntfs_put;
io.fn_get=ntfs_get;
@@ -262,7 +275,8 @@
ntfs_free(cluster0);
/* FIXME: more than 2**32 cluster */
/* FIXME: gcc will emit udivdi3 if we don't truncate it */
- return ((unsigned int)size)/vol->clusterfactor;
+ *vol_size = ((unsigned long)size)/vol->clusterfactor;
+ return 0;
}

static int nc[16]={4,3,3,2,3,2,2,1,3,2,2,1,2,1,1,0};
@@ -460,6 +474,8 @@
int start;

bits=ntfs_malloc(2048);
+ if( !bits )
+ return ENOMEM;
io.fn_put=ntfs_put;
io.fn_get=ntfs_get;
io.param=bits;
diff -ur vanilla/fs/ntfs/super.h linux/fs/ntfs/super.h
--- vanilla/fs/ntfs/super.h Sun Jan 3 17:23:02 1999
+++ linux/fs/ntfs/super.h Wed Jan 27 00:12:18 1999
@@ -10,7 +10,7 @@
#define ALLOC_REQUIRE_SIZE 2

int ntfs_get_free_cluster_count(ntfs_inode *bitmap);
-int ntfs_get_volumesize(ntfs_volume *vol);
+int ntfs_get_volumesize(ntfs_volume *vol, long *vol_size );
int ntfs_init_volume(ntfs_volume *vol,char *boot);
int ntfs_load_special_files(ntfs_volume *vol);
int ntfs_release_volume(ntfs_volume *vol);
Only in linux/fs/ntfs/: super.o
diff -ur vanilla/fs/ntfs/support.c linux/fs/ntfs/support.c
--- vanilla/fs/ntfs/support.c Sun Jan 3 17:23:02 1999
+++ linux/fs/ntfs/support.c Wed Jan 27 00:07:00 1999
@@ -246,6 +246,10 @@
if(!(vol->nct & nct_uni_xlate))goto inval;
/* realloc */
buf=ntfs_malloc(*out_len+3);
+ if( !buf ) {
+ ntfs_free( result );
+ return ENOMEM;
+ }
memcpy(buf,result,o);
ntfs_free(result);
result=buf;
Only in linux/fs/ntfs/: support.o
Only in linux/fs/ntfs/: sysctl.o
Only in linux/fs/ntfs/: util.o
\
 
 \ /
  Last update: 2005-03-22 13:50    [W:0.040 / U:1.460 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site