cifs: add refcounting to cifs_readdata structures

This isn't strictly necessary for the async readpages code, but the
uncached version will need to be able to collect the replies after
issuing the calls. Add a kref to cifs_readdata and use change the
code to take and put references appropriately.

Signed-off-by: Jeff Layton <jlayton@redhat.com>
This commit is contained in:
Jeff Layton 2012-05-16 07:13:17 -04:00 committed by Steve French
parent 8d5ce4d23c
commit 6993f74a5b
3 changed files with 19 additions and 7 deletions

View File

@ -464,6 +464,7 @@ extern int SMBencrypt(unsigned char *passwd, const unsigned char *c8,
/* asynchronous read support */ /* asynchronous read support */
struct cifs_readdata { struct cifs_readdata {
struct kref refcount;
struct cifsFileInfo *cfile; struct cifsFileInfo *cfile;
struct address_space *mapping; struct address_space *mapping;
__u64 offset; __u64 offset;
@ -478,6 +479,7 @@ struct cifs_readdata {
struct kvec iov[1]; struct kvec iov[1];
}; };
void cifs_readdata_release(struct kref *refcount);
int cifs_async_readv(struct cifs_readdata *rdata); int cifs_async_readv(struct cifs_readdata *rdata);
/* asynchronous write support */ /* asynchronous write support */

View File

@ -1635,12 +1635,15 @@ cifs_async_readv(struct cifs_readdata *rdata)
rdata->iov[0].iov_base = smb; rdata->iov[0].iov_base = smb;
rdata->iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4; rdata->iov[0].iov_len = be32_to_cpu(smb->hdr.smb_buf_length) + 4;
kref_get(&rdata->refcount);
rc = cifs_call_async(tcon->ses->server, rdata->iov, 1, rc = cifs_call_async(tcon->ses->server, rdata->iov, 1,
cifs_readv_receive, cifs_readv_callback, cifs_readv_receive, cifs_readv_callback,
rdata, false); rdata, false);
if (rc == 0) if (rc == 0)
cifs_stats_inc(&tcon->num_reads); cifs_stats_inc(&tcon->num_reads);
else
kref_put(&rdata->refcount, cifs_readdata_release);
cifs_small_buf_release(smb); cifs_small_buf_release(smb);
return rc; return rc;

View File

@ -2347,16 +2347,22 @@ cifs_readdata_alloc(unsigned int nr_vecs, work_func_t complete)
rdata = kzalloc(sizeof(*rdata) + rdata = kzalloc(sizeof(*rdata) +
sizeof(struct kvec) * nr_vecs, GFP_KERNEL); sizeof(struct kvec) * nr_vecs, GFP_KERNEL);
if (rdata != NULL) { if (rdata != NULL) {
kref_init(&rdata->refcount);
INIT_WORK(&rdata->work, complete); INIT_WORK(&rdata->work, complete);
INIT_LIST_HEAD(&rdata->pages); INIT_LIST_HEAD(&rdata->pages);
} }
return rdata; return rdata;
} }
static void void
cifs_readdata_free(struct cifs_readdata *rdata) cifs_readdata_release(struct kref *refcount)
{ {
cifsFileInfo_put(rdata->cfile); struct cifs_readdata *rdata = container_of(refcount,
struct cifs_readdata, refcount);
if (rdata->cfile)
cifsFileInfo_put(rdata->cfile);
kfree(rdata); kfree(rdata);
} }
@ -2651,7 +2657,7 @@ cifs_readv_complete(struct work_struct *work)
page_cache_release(page); page_cache_release(page);
} }
cifs_readdata_free(rdata); kref_put(&rdata->refcount, cifs_readdata_release);
} }
static int static int
@ -2837,9 +2843,8 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
} }
spin_lock(&cifs_file_list_lock); spin_lock(&cifs_file_list_lock);
cifsFileInfo_get(open_file);
spin_unlock(&cifs_file_list_lock); spin_unlock(&cifs_file_list_lock);
rdata->cfile = open_file; rdata->cfile = cifsFileInfo_get(open_file);
rdata->mapping = mapping; rdata->mapping = mapping;
rdata->offset = offset; rdata->offset = offset;
rdata->bytes = bytes; rdata->bytes = bytes;
@ -2864,9 +2869,11 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
unlock_page(page); unlock_page(page);
page_cache_release(page); page_cache_release(page);
} }
cifs_readdata_free(rdata); kref_put(&rdata->refcount, cifs_readdata_release);
break; break;
} }
kref_put(&rdata->refcount, cifs_readdata_release);
} }
return rc; return rc;