]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - fs/nfs/direct.c
NFSv4: Ensure that we track the NFSv4 lock state in read/write requests.
[net-next-2.6.git] / fs / nfs / direct.c
index ad4cd31d6050d22c2a6267b005bab48b84f70f66..064a80961677fbf3c62e309a4f15693e391ed7e6 100644 (file)
@@ -69,6 +69,7 @@ struct nfs_direct_req {
 
        /* I/O parameters */
        struct nfs_open_context *ctx;           /* file open context info */
+       struct nfs_lock_context *l_ctx;         /* Lock context info */
        struct kiocb *          iocb;           /* controlling i/o request */
        struct inode *          inode;          /* target file of i/o */
 
@@ -160,6 +161,7 @@ static inline struct nfs_direct_req *nfs_direct_req_alloc(void)
        INIT_LIST_HEAD(&dreq->rewrite_list);
        dreq->iocb = NULL;
        dreq->ctx = NULL;
+       dreq->l_ctx = NULL;
        spin_lock_init(&dreq->lock);
        atomic_set(&dreq->io_count, 0);
        dreq->count = 0;
@@ -173,6 +175,8 @@ static void nfs_direct_req_free(struct kref *kref)
 {
        struct nfs_direct_req *dreq = container_of(kref, struct nfs_direct_req, kref);
 
+       if (dreq->l_ctx != NULL)
+               nfs_put_lock_context(dreq->l_ctx);
        if (dreq->ctx != NULL)
                put_nfs_open_context(dreq->ctx);
        kmem_cache_free(nfs_direct_cachep, dreq);
@@ -336,6 +340,7 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_direct_req *dreq,
                data->cred = msg.rpc_cred;
                data->args.fh = NFS_FH(inode);
                data->args.context = ctx;
+               data->args.lock_context = dreq->l_ctx;
                data->args.offset = pos;
                data->args.pgbase = pgbase;
                data->args.pages = data->pagevec;
@@ -416,24 +421,28 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
 static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov,
                               unsigned long nr_segs, loff_t pos)
 {
-       ssize_t result = 0;
+       ssize_t result = -ENOMEM;
        struct inode *inode = iocb->ki_filp->f_mapping->host;
        struct nfs_direct_req *dreq;
 
        dreq = nfs_direct_req_alloc();
-       if (!dreq)
-               return -ENOMEM;
+       if (dreq == NULL)
+               goto out;
 
        dreq->inode = inode;
        dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp));
+       dreq->l_ctx = nfs_get_lock_context(dreq->ctx);
+       if (dreq->l_ctx == NULL)
+               goto out_release;
        if (!is_sync_kiocb(iocb))
                dreq->iocb = iocb;
 
        result = nfs_direct_read_schedule_iovec(dreq, iov, nr_segs, pos);
        if (!result)
                result = nfs_direct_wait(dreq);
+out_release:
        nfs_direct_req_release(dreq);
-
+out:
        return result;
 }
 
@@ -574,6 +583,7 @@ static void nfs_direct_commit_schedule(struct nfs_direct_req *dreq)
        data->args.offset = 0;
        data->args.count = 0;
        data->args.context = dreq->ctx;
+       data->args.lock_context = dreq->l_ctx;
        data->res.count = 0;
        data->res.fattr = &data->fattr;
        data->res.verf = &data->verf;
@@ -761,6 +771,7 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_direct_req *dreq,
                data->cred = msg.rpc_cred;
                data->args.fh = NFS_FH(inode);
                data->args.context = ctx;
+               data->args.lock_context = dreq->l_ctx;
                data->args.offset = pos;
                data->args.pgbase = pgbase;
                data->args.pages = data->pagevec;
@@ -845,7 +856,7 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov,
                                unsigned long nr_segs, loff_t pos,
                                size_t count)
 {
-       ssize_t result = 0;
+       ssize_t result = -ENOMEM;
        struct inode *inode = iocb->ki_filp->f_mapping->host;
        struct nfs_direct_req *dreq;
        size_t wsize = NFS_SERVER(inode)->wsize;
@@ -853,7 +864,7 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov,
 
        dreq = nfs_direct_req_alloc();
        if (!dreq)
-               return -ENOMEM;
+               goto out;
        nfs_alloc_commit_data(dreq);
 
        if (dreq->commit_data == NULL || count < wsize)
@@ -861,14 +872,18 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov,
 
        dreq->inode = inode;
        dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp));
+       dreq->l_ctx = nfs_get_lock_context(dreq->ctx);
+       if (dreq->l_ctx != NULL)
+               goto out_release;
        if (!is_sync_kiocb(iocb))
                dreq->iocb = iocb;
 
        result = nfs_direct_write_schedule_iovec(dreq, iov, nr_segs, pos, sync);
        if (!result)
                result = nfs_direct_wait(dreq);
+out_release:
        nfs_direct_req_release(dreq);
-
+out:
        return result;
 }