aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-03-22 19:26:10 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2011-03-22 19:26:10 -0400
commitab70a1d7c7fc6665d83f41b5ce790ff8376e0b81 (patch)
treedee8acafa2dfb87cde4ddba68eff5e1c75557469 /net
parent0adfc56ce8fdc5c17630434e49f30536ba7b8559 (diff)
parent68da9ba4eeadae86ad42e52b80822fbd56971267 (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ericvh/v9fs: [net/9p]: Introduce basic flow-control for VirtIO transport. 9p: use the updated offset given by generic_write_checks [net/9p] Don't re-pin pages on retrying virtqueue_add_buf(). [net/9p] Set the condition just before waking up. [net/9p] unconditional wake_up to proc waiting for space on VirtIO ring fs/9p: Add v9fs_dentry2v9ses fs/9p: Attach writeback_fid on first open with WR flag fs/9p: Open writeback fid in O_SYNC mode fs/9p: Use truncate_setsize instead of vmtruncate net/9p: Fix compile warning net/9p: Convert the in the 9p rpc call path to GFP_NOFS fs/9p: Fix race in initializing writeback fid
Diffstat (limited to 'net')
-rw-r--r--net/9p/client.c10
-rw-r--r--net/9p/protocol.c6
-rw-r--r--net/9p/trans_common.c10
-rw-r--r--net/9p/trans_fd.c2
-rw-r--r--net/9p/trans_rdma.c6
-rw-r--r--net/9p/trans_virtio.c72
-rw-r--r--net/9p/util.c2
7 files changed, 64 insertions, 44 deletions
diff --git a/net/9p/client.c b/net/9p/client.c
index 347ec0cd2718..2ccbf04d37df 100644
--- a/net/9p/client.c
+++ b/net/9p/client.c
@@ -223,7 +223,7 @@ static struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag)
223 223
224 req = &c->reqs[row][col]; 224 req = &c->reqs[row][col];
225 if (!req->tc) { 225 if (!req->tc) {
226 req->wq = kmalloc(sizeof(wait_queue_head_t), GFP_KERNEL); 226 req->wq = kmalloc(sizeof(wait_queue_head_t), GFP_NOFS);
227 if (!req->wq) { 227 if (!req->wq) {
228 printk(KERN_ERR "Couldn't grow tag array\n"); 228 printk(KERN_ERR "Couldn't grow tag array\n");
229 return ERR_PTR(-ENOMEM); 229 return ERR_PTR(-ENOMEM);
@@ -233,17 +233,17 @@ static struct p9_req_t *p9_tag_alloc(struct p9_client *c, u16 tag)
233 P9_TRANS_PREF_PAYLOAD_SEP) { 233 P9_TRANS_PREF_PAYLOAD_SEP) {
234 int alloc_msize = min(c->msize, 4096); 234 int alloc_msize = min(c->msize, 4096);
235 req->tc = kmalloc(sizeof(struct p9_fcall)+alloc_msize, 235 req->tc = kmalloc(sizeof(struct p9_fcall)+alloc_msize,
236 GFP_KERNEL); 236 GFP_NOFS);
237 req->tc->capacity = alloc_msize; 237 req->tc->capacity = alloc_msize;
238 req->rc = kmalloc(sizeof(struct p9_fcall)+alloc_msize, 238 req->rc = kmalloc(sizeof(struct p9_fcall)+alloc_msize,
239 GFP_KERNEL); 239 GFP_NOFS);
240 req->rc->capacity = alloc_msize; 240 req->rc->capacity = alloc_msize;
241 } else { 241 } else {
242 req->tc = kmalloc(sizeof(struct p9_fcall)+c->msize, 242 req->tc = kmalloc(sizeof(struct p9_fcall)+c->msize,
243 GFP_KERNEL); 243 GFP_NOFS);
244 req->tc->capacity = c->msize; 244 req->tc->capacity = c->msize;
245 req->rc = kmalloc(sizeof(struct p9_fcall)+c->msize, 245 req->rc = kmalloc(sizeof(struct p9_fcall)+c->msize,
246 GFP_KERNEL); 246 GFP_NOFS);
247 req->rc->capacity = c->msize; 247 req->rc->capacity = c->msize;
248 } 248 }
249 if ((!req->tc) || (!req->rc)) { 249 if ((!req->tc) || (!req->rc)) {
diff --git a/net/9p/protocol.c b/net/9p/protocol.c
index 2ce515b859b3..8a4084fa8b5a 100644
--- a/net/9p/protocol.c
+++ b/net/9p/protocol.c
@@ -205,7 +205,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
205 if (errcode) 205 if (errcode)
206 break; 206 break;
207 207
208 *sptr = kmalloc(len + 1, GFP_KERNEL); 208 *sptr = kmalloc(len + 1, GFP_NOFS);
209 if (*sptr == NULL) { 209 if (*sptr == NULL) {
210 errcode = -EFAULT; 210 errcode = -EFAULT;
211 break; 211 break;
@@ -273,7 +273,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
273 if (!errcode) { 273 if (!errcode) {
274 *wnames = 274 *wnames =
275 kmalloc(sizeof(char *) * *nwname, 275 kmalloc(sizeof(char *) * *nwname,
276 GFP_KERNEL); 276 GFP_NOFS);
277 if (!*wnames) 277 if (!*wnames)
278 errcode = -ENOMEM; 278 errcode = -ENOMEM;
279 } 279 }
@@ -317,7 +317,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
317 *wqids = 317 *wqids =
318 kmalloc(*nwqid * 318 kmalloc(*nwqid *
319 sizeof(struct p9_qid), 319 sizeof(struct p9_qid),
320 GFP_KERNEL); 320 GFP_NOFS);
321 if (*wqids == NULL) 321 if (*wqids == NULL)
322 errcode = -ENOMEM; 322 errcode = -ENOMEM;
323 } 323 }
diff --git a/net/9p/trans_common.c b/net/9p/trans_common.c
index d62b9aa58df8..9172ab78fcb0 100644
--- a/net/9p/trans_common.c
+++ b/net/9p/trans_common.c
@@ -41,9 +41,9 @@ EXPORT_SYMBOL(p9_release_req_pages);
41int 41int
42p9_nr_pages(struct p9_req_t *req) 42p9_nr_pages(struct p9_req_t *req)
43{ 43{
44 int start_page, end_page; 44 unsigned long start_page, end_page;
45 start_page = (unsigned long long)req->tc->pubuf >> PAGE_SHIFT; 45 start_page = (unsigned long)req->tc->pubuf >> PAGE_SHIFT;
46 end_page = ((unsigned long long)req->tc->pubuf + req->tc->pbuf_size + 46 end_page = ((unsigned long)req->tc->pubuf + req->tc->pbuf_size +
47 PAGE_SIZE - 1) >> PAGE_SHIFT; 47 PAGE_SIZE - 1) >> PAGE_SHIFT;
48 return end_page - start_page; 48 return end_page - start_page;
49} 49}
@@ -69,8 +69,8 @@ p9_payload_gup(struct p9_req_t *req, size_t *pdata_off, int *pdata_len,
69 *pdata_off = (size_t)req->tc->pubuf & (PAGE_SIZE-1); 69 *pdata_off = (size_t)req->tc->pubuf & (PAGE_SIZE-1);
70 70
71 if (*pdata_off) 71 if (*pdata_off)
72 first_page_bytes = min((PAGE_SIZE - *pdata_off), 72 first_page_bytes = min(((size_t)PAGE_SIZE - *pdata_off),
73 req->tc->pbuf_size); 73 req->tc->pbuf_size);
74 74
75 rpinfo = req->tc->private; 75 rpinfo = req->tc->private;
76 pdata_mapped_pages = get_user_pages_fast((unsigned long)req->tc->pubuf, 76 pdata_mapped_pages = get_user_pages_fast((unsigned long)req->tc->pubuf,
diff --git a/net/9p/trans_fd.c b/net/9p/trans_fd.c
index a30471e51740..aa5672b15eae 100644
--- a/net/9p/trans_fd.c
+++ b/net/9p/trans_fd.c
@@ -350,7 +350,7 @@ static void p9_read_work(struct work_struct *work)
350 350
351 if (m->req->rc == NULL) { 351 if (m->req->rc == NULL) {
352 m->req->rc = kmalloc(sizeof(struct p9_fcall) + 352 m->req->rc = kmalloc(sizeof(struct p9_fcall) +
353 m->client->msize, GFP_KERNEL); 353 m->client->msize, GFP_NOFS);
354 if (!m->req->rc) { 354 if (!m->req->rc) {
355 m->req = NULL; 355 m->req = NULL;
356 err = -ENOMEM; 356 err = -ENOMEM;
diff --git a/net/9p/trans_rdma.c b/net/9p/trans_rdma.c
index 29a54ccd213d..150e0c4bbf40 100644
--- a/net/9p/trans_rdma.c
+++ b/net/9p/trans_rdma.c
@@ -424,7 +424,7 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req)
424 struct p9_rdma_context *rpl_context = NULL; 424 struct p9_rdma_context *rpl_context = NULL;
425 425
426 /* Allocate an fcall for the reply */ 426 /* Allocate an fcall for the reply */
427 rpl_context = kmalloc(sizeof *rpl_context, GFP_KERNEL); 427 rpl_context = kmalloc(sizeof *rpl_context, GFP_NOFS);
428 if (!rpl_context) { 428 if (!rpl_context) {
429 err = -ENOMEM; 429 err = -ENOMEM;
430 goto err_close; 430 goto err_close;
@@ -437,7 +437,7 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req)
437 */ 437 */
438 if (!req->rc) { 438 if (!req->rc) {
439 req->rc = kmalloc(sizeof(struct p9_fcall)+client->msize, 439 req->rc = kmalloc(sizeof(struct p9_fcall)+client->msize,
440 GFP_KERNEL); 440 GFP_NOFS);
441 if (req->rc) { 441 if (req->rc) {
442 req->rc->sdata = (char *) req->rc + 442 req->rc->sdata = (char *) req->rc +
443 sizeof(struct p9_fcall); 443 sizeof(struct p9_fcall);
@@ -468,7 +468,7 @@ static int rdma_request(struct p9_client *client, struct p9_req_t *req)
468 req->rc = NULL; 468 req->rc = NULL;
469 469
470 /* Post the request */ 470 /* Post the request */
471 c = kmalloc(sizeof *c, GFP_KERNEL); 471 c = kmalloc(sizeof *c, GFP_NOFS);
472 if (!c) { 472 if (!c) {
473 err = -ENOMEM; 473 err = -ENOMEM;
474 goto err_free1; 474 goto err_free1;
diff --git a/net/9p/trans_virtio.c b/net/9p/trans_virtio.c
index 9b550ed9c711..e8f046b07182 100644
--- a/net/9p/trans_virtio.c
+++ b/net/9p/trans_virtio.c
@@ -43,6 +43,7 @@
43#include <net/9p/client.h> 43#include <net/9p/client.h>
44#include <net/9p/transport.h> 44#include <net/9p/transport.h>
45#include <linux/scatterlist.h> 45#include <linux/scatterlist.h>
46#include <linux/swap.h>
46#include <linux/virtio.h> 47#include <linux/virtio.h>
47#include <linux/virtio_9p.h> 48#include <linux/virtio_9p.h>
48#include "trans_common.h" 49#include "trans_common.h"
@@ -51,6 +52,8 @@
51 52
52/* a single mutex to manage channel initialization and attachment */ 53/* a single mutex to manage channel initialization and attachment */
53static DEFINE_MUTEX(virtio_9p_lock); 54static DEFINE_MUTEX(virtio_9p_lock);
55static DECLARE_WAIT_QUEUE_HEAD(vp_wq);
56static atomic_t vp_pinned = ATOMIC_INIT(0);
54 57
55/** 58/**
56 * struct virtio_chan - per-instance transport information 59 * struct virtio_chan - per-instance transport information
@@ -78,7 +81,10 @@ struct virtio_chan {
78 struct virtqueue *vq; 81 struct virtqueue *vq;
79 int ring_bufs_avail; 82 int ring_bufs_avail;
80 wait_queue_head_t *vc_wq; 83 wait_queue_head_t *vc_wq;
81 84 /* This is global limit. Since we don't have a global structure,
85 * will be placing it in each channel.
86 */
87 int p9_max_pages;
82 /* Scatterlist: can be too big for stack. */ 88 /* Scatterlist: can be too big for stack. */
83 struct scatterlist sg[VIRTQUEUE_NUM]; 89 struct scatterlist sg[VIRTQUEUE_NUM];
84 90
@@ -141,34 +147,36 @@ static void req_done(struct virtqueue *vq)
141 147
142 P9_DPRINTK(P9_DEBUG_TRANS, ": request done\n"); 148 P9_DPRINTK(P9_DEBUG_TRANS, ": request done\n");
143 149
144 do { 150 while (1) {
145 spin_lock_irqsave(&chan->lock, flags); 151 spin_lock_irqsave(&chan->lock, flags);
146 rc = virtqueue_get_buf(chan->vq, &len); 152 rc = virtqueue_get_buf(chan->vq, &len);
147 153
148 if (rc != NULL) { 154 if (rc == NULL) {
149 if (!chan->ring_bufs_avail) {
150 chan->ring_bufs_avail = 1;
151 wake_up(chan->vc_wq);
152 }
153 spin_unlock_irqrestore(&chan->lock, flags);
154 P9_DPRINTK(P9_DEBUG_TRANS, ": rc %p\n", rc);
155 P9_DPRINTK(P9_DEBUG_TRANS, ": lookup tag %d\n",
156 rc->tag);
157 req = p9_tag_lookup(chan->client, rc->tag);
158 req->status = REQ_STATUS_RCVD;
159 if (req->tc->private) {
160 struct trans_rpage_info *rp = req->tc->private;
161 /*Release pages */
162 p9_release_req_pages(rp);
163 if (rp->rp_alloc)
164 kfree(rp);
165 req->tc->private = NULL;
166 }
167 p9_client_cb(chan->client, req);
168 } else {
169 spin_unlock_irqrestore(&chan->lock, flags); 155 spin_unlock_irqrestore(&chan->lock, flags);
156 break;
157 }
158
159 chan->ring_bufs_avail = 1;
160 spin_unlock_irqrestore(&chan->lock, flags);
161 /* Wakeup if anyone waiting for VirtIO ring space. */
162 wake_up(chan->vc_wq);
163 P9_DPRINTK(P9_DEBUG_TRANS, ": rc %p\n", rc);
164 P9_DPRINTK(P9_DEBUG_TRANS, ": lookup tag %d\n", rc->tag);
165 req = p9_tag_lookup(chan->client, rc->tag);
166 if (req->tc->private) {
167 struct trans_rpage_info *rp = req->tc->private;
168 int p = rp->rp_nr_pages;
169 /*Release pages */
170 p9_release_req_pages(rp);
171 atomic_sub(p, &vp_pinned);
172 wake_up(&vp_wq);
173 if (rp->rp_alloc)
174 kfree(rp);
175 req->tc->private = NULL;
170 } 176 }
171 } while (rc != NULL); 177 req->status = REQ_STATUS_RCVD;
178 p9_client_cb(chan->client, req);
179 }
172} 180}
173 181
174/** 182/**
@@ -263,7 +271,6 @@ p9_virtio_request(struct p9_client *client, struct p9_req_t *req)
263 271
264 P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request\n"); 272 P9_DPRINTK(P9_DEBUG_TRANS, "9p debug: virtio request\n");
265 273
266req_retry:
267 req->status = REQ_STATUS_SENT; 274 req->status = REQ_STATUS_SENT;
268 275
269 if (req->tc->pbuf_size && (req->tc->pubuf && P9_IS_USER_CONTEXT)) { 276 if (req->tc->pbuf_size && (req->tc->pubuf && P9_IS_USER_CONTEXT)) {
@@ -271,6 +278,14 @@ req_retry:
271 int rpinfo_size = sizeof(struct trans_rpage_info) + 278 int rpinfo_size = sizeof(struct trans_rpage_info) +
272 sizeof(struct page *) * nr_pages; 279 sizeof(struct page *) * nr_pages;
273 280
281 if (atomic_read(&vp_pinned) >= chan->p9_max_pages) {
282 err = wait_event_interruptible(vp_wq,
283 atomic_read(&vp_pinned) < chan->p9_max_pages);
284 if (err == -ERESTARTSYS)
285 return err;
286 P9_DPRINTK(P9_DEBUG_TRANS, "9p: May gup pages now.\n");
287 }
288
274 if (rpinfo_size <= (req->tc->capacity - req->tc->size)) { 289 if (rpinfo_size <= (req->tc->capacity - req->tc->size)) {
275 /* We can use sdata */ 290 /* We can use sdata */
276 req->tc->private = req->tc->sdata + req->tc->size; 291 req->tc->private = req->tc->sdata + req->tc->size;
@@ -293,9 +308,12 @@ req_retry:
293 if (rpinfo->rp_alloc) 308 if (rpinfo->rp_alloc)
294 kfree(rpinfo); 309 kfree(rpinfo);
295 return err; 310 return err;
311 } else {
312 atomic_add(rpinfo->rp_nr_pages, &vp_pinned);
296 } 313 }
297 } 314 }
298 315
316req_retry_pinned:
299 spin_lock_irqsave(&chan->lock, flags); 317 spin_lock_irqsave(&chan->lock, flags);
300 318
301 /* Handle out VirtIO ring buffers */ 319 /* Handle out VirtIO ring buffers */
@@ -356,7 +374,7 @@ req_retry:
356 return err; 374 return err;
357 375
358 P9_DPRINTK(P9_DEBUG_TRANS, "9p:Retry virtio request\n"); 376 P9_DPRINTK(P9_DEBUG_TRANS, "9p:Retry virtio request\n");
359 goto req_retry; 377 goto req_retry_pinned;
360 } else { 378 } else {
361 spin_unlock_irqrestore(&chan->lock, flags); 379 spin_unlock_irqrestore(&chan->lock, flags);
362 P9_DPRINTK(P9_DEBUG_TRANS, 380 P9_DPRINTK(P9_DEBUG_TRANS,
@@ -453,6 +471,8 @@ static int p9_virtio_probe(struct virtio_device *vdev)
453 } 471 }
454 init_waitqueue_head(chan->vc_wq); 472 init_waitqueue_head(chan->vc_wq);
455 chan->ring_bufs_avail = 1; 473 chan->ring_bufs_avail = 1;
474 /* Ceiling limit to avoid denial of service attacks */
475 chan->p9_max_pages = nr_free_buffer_pages()/4;
456 476
457 mutex_lock(&virtio_9p_lock); 477 mutex_lock(&virtio_9p_lock);
458 list_add_tail(&chan->chan_list, &virtio_chan_list); 478 list_add_tail(&chan->chan_list, &virtio_chan_list);
diff --git a/net/9p/util.c b/net/9p/util.c
index e048701a72d2..b84619b5ba22 100644
--- a/net/9p/util.c
+++ b/net/9p/util.c
@@ -92,7 +92,7 @@ int p9_idpool_get(struct p9_idpool *p)
92 unsigned long flags; 92 unsigned long flags;
93 93
94retry: 94retry:
95 if (idr_pre_get(&p->pool, GFP_KERNEL) == 0) 95 if (idr_pre_get(&p->pool, GFP_NOFS) == 0)
96 return 0; 96 return 0;
97 97
98 spin_lock_irqsave(&p->lock, flags); 98 spin_lock_irqsave(&p->lock, flags);