diff options
| -rw-r--r-- | drivers/block/rbd.c | 2 | ||||
| -rw-r--r-- | fs/ceph/addr.c | 193 | ||||
| -rw-r--r-- | fs/ceph/caps.c | 2 | ||||
| -rw-r--r-- | fs/ceph/inode.c | 46 | ||||
| -rw-r--r-- | fs/ceph/ioctl.c | 34 | ||||
| -rw-r--r-- | fs/ceph/ioctl.h | 55 | ||||
| -rw-r--r-- | fs/ceph/mds_client.c | 11 | ||||
| -rw-r--r-- | fs/ceph/super.c | 61 | ||||
| -rw-r--r-- | fs/ceph/super.h | 19 | ||||
| -rw-r--r-- | include/linux/ceph/libceph.h | 4 | ||||
| -rw-r--r-- | include/linux/ceph/messenger.h | 3 | ||||
| -rw-r--r-- | net/ceph/Kconfig | 14 | ||||
| -rw-r--r-- | net/ceph/ceph_common.c | 47 | ||||
| -rw-r--r-- | net/ceph/messenger.c | 130 | ||||
| -rw-r--r-- | net/ceph/mon_client.c | 79 | ||||
| -rw-r--r-- | net/ceph/msgpool.c | 4 | ||||
| -rw-r--r-- | net/ceph/osd_client.c | 34 |
17 files changed, 483 insertions, 255 deletions
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c index fe3c3249cec4..65cc424359b0 100644 --- a/drivers/block/rbd.c +++ b/drivers/block/rbd.c | |||
| @@ -260,7 +260,7 @@ static struct rbd_client *rbd_client_create(struct ceph_options *opt, | |||
| 260 | kref_init(&rbdc->kref); | 260 | kref_init(&rbdc->kref); |
| 261 | INIT_LIST_HEAD(&rbdc->node); | 261 | INIT_LIST_HEAD(&rbdc->node); |
| 262 | 262 | ||
| 263 | rbdc->client = ceph_create_client(opt, rbdc); | 263 | rbdc->client = ceph_create_client(opt, rbdc, 0, 0); |
| 264 | if (IS_ERR(rbdc->client)) | 264 | if (IS_ERR(rbdc->client)) |
| 265 | goto out_rbdc; | 265 | goto out_rbdc; |
| 266 | opt = NULL; /* Now rbdc->client is responsible for opt */ | 266 | opt = NULL; /* Now rbdc->client is responsible for opt */ |
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 5a3953db8118..4144caf2f9d3 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c | |||
| @@ -228,102 +228,155 @@ static int ceph_readpage(struct file *filp, struct page *page) | |||
| 228 | } | 228 | } |
| 229 | 229 | ||
| 230 | /* | 230 | /* |
| 231 | * Build a vector of contiguous pages from the provided page list. | 231 | * Finish an async read(ahead) op. |
| 232 | */ | 232 | */ |
| 233 | static struct page **page_vector_from_list(struct list_head *page_list, | 233 | static void finish_read(struct ceph_osd_request *req, struct ceph_msg *msg) |
| 234 | unsigned *nr_pages) | ||
| 235 | { | 234 | { |
| 236 | struct page **pages; | 235 | struct inode *inode = req->r_inode; |
| 237 | struct page *page; | 236 | struct ceph_osd_reply_head *replyhead; |
| 238 | int next_index, contig_pages = 0; | 237 | int rc, bytes; |
| 238 | int i; | ||
| 239 | 239 | ||
| 240 | /* build page vector */ | 240 | /* parse reply */ |
| 241 | pages = kmalloc(sizeof(*pages) * *nr_pages, GFP_NOFS); | 241 | replyhead = msg->front.iov_base; |
| 242 | if (!pages) | 242 | WARN_ON(le32_to_cpu(replyhead->num_ops) == 0); |
| 243 | return ERR_PTR(-ENOMEM); | 243 | rc = le32_to_cpu(replyhead->result); |
| 244 | bytes = le32_to_cpu(msg->hdr.data_len); | ||
| 244 | 245 | ||
| 245 | BUG_ON(list_empty(page_list)); | 246 | dout("finish_read %p req %p rc %d bytes %d\n", inode, req, rc, bytes); |
| 246 | next_index = list_entry(page_list->prev, struct page, lru)->index; | 247 | |
| 247 | list_for_each_entry_reverse(page, page_list, lru) { | 248 | /* unlock all pages, zeroing any data we didn't read */ |
| 248 | if (page->index == next_index) { | 249 | for (i = 0; i < req->r_num_pages; i++, bytes -= PAGE_CACHE_SIZE) { |
| 249 | dout("readpages page %d %p\n", contig_pages, page); | 250 | struct page *page = req->r_pages[i]; |
| 250 | pages[contig_pages] = page; | 251 | |
| 251 | contig_pages++; | 252 | if (bytes < (int)PAGE_CACHE_SIZE) { |
| 252 | next_index++; | 253 | /* zero (remainder of) page */ |
| 253 | } else { | 254 | int s = bytes < 0 ? 0 : bytes; |
| 254 | break; | 255 | zero_user_segment(page, s, PAGE_CACHE_SIZE); |
| 255 | } | 256 | } |
| 257 | dout("finish_read %p uptodate %p idx %lu\n", inode, page, | ||
| 258 | page->index); | ||
| 259 | flush_dcache_page(page); | ||
| 260 | SetPageUptodate(page); | ||
| 261 | unlock_page(page); | ||
| 262 | page_cache_release(page); | ||
| 256 | } | 263 | } |
| 257 | *nr_pages = contig_pages; | 264 | kfree(req->r_pages); |
| 258 | return pages; | ||
| 259 | } | 265 | } |
| 260 | 266 | ||
| 261 | /* | 267 | /* |
| 262 | * Read multiple pages. Leave pages we don't read + unlock in page_list; | 268 | * start an async read(ahead) operation. return nr_pages we submitted |
| 263 | * the caller (VM) cleans them up. | 269 | * a read for on success, or negative error code. |
| 264 | */ | 270 | */ |
| 265 | static int ceph_readpages(struct file *file, struct address_space *mapping, | 271 | static int start_read(struct inode *inode, struct list_head *page_list, int max) |
| 266 | struct list_head *page_list, unsigned nr_pages) | ||
| 267 | { | 272 | { |
| 268 | struct inode *inode = file->f_dentry->d_inode; | ||
| 269 | struct ceph_inode_info *ci = ceph_inode(inode); | ||
| 270 | struct ceph_osd_client *osdc = | 273 | struct ceph_osd_client *osdc = |
| 271 | &ceph_inode_to_client(inode)->client->osdc; | 274 | &ceph_inode_to_client(inode)->client->osdc; |
| 272 | int rc = 0; | 275 | struct ceph_inode_info *ci = ceph_inode(inode); |
| 273 | struct page **pages; | 276 | struct page *page = list_entry(page_list->prev, struct page, lru); |
| 274 | loff_t offset; | 277 | struct ceph_osd_request *req; |
| 278 | u64 off; | ||
| 275 | u64 len; | 279 | u64 len; |
| 280 | int i; | ||
| 281 | struct page **pages; | ||
| 282 | pgoff_t next_index; | ||
| 283 | int nr_pages = 0; | ||
| 284 | int ret; | ||
| 276 | 285 | ||
| 277 | dout("readpages %p file %p nr_pages %d\n", | 286 | off = page->index << PAGE_CACHE_SHIFT; |
| 278 | inode, file, nr_pages); | ||
| 279 | |||
| 280 | pages = page_vector_from_list(page_list, &nr_pages); | ||
| 281 | if (IS_ERR(pages)) | ||
| 282 | return PTR_ERR(pages); | ||
| 283 | 287 | ||
| 284 | /* guess read extent */ | 288 | /* count pages */ |
| 285 | offset = pages[0]->index << PAGE_CACHE_SHIFT; | 289 | next_index = page->index; |
| 290 | list_for_each_entry_reverse(page, page_list, lru) { | ||
| 291 | if (page->index != next_index) | ||
| 292 | break; | ||
| 293 | nr_pages++; | ||
| 294 | next_index++; | ||
| 295 | if (max && nr_pages == max) | ||
| 296 | break; | ||
| 297 | } | ||
| 286 | len = nr_pages << PAGE_CACHE_SHIFT; | 298 | len = nr_pages << PAGE_CACHE_SHIFT; |
| 287 | rc = ceph_osdc_readpages(osdc, ceph_vino(inode), &ci->i_layout, | 299 | dout("start_read %p nr_pages %d is %lld~%lld\n", inode, nr_pages, |
| 288 | offset, &len, | 300 | off, len); |
| 289 | ci->i_truncate_seq, ci->i_truncate_size, | 301 | |
| 290 | pages, nr_pages, 0); | 302 | req = ceph_osdc_new_request(osdc, &ci->i_layout, ceph_vino(inode), |
| 291 | if (rc == -ENOENT) | 303 | off, &len, |
| 292 | rc = 0; | 304 | CEPH_OSD_OP_READ, CEPH_OSD_FLAG_READ, |
| 293 | if (rc < 0) | 305 | NULL, 0, |
| 294 | goto out; | 306 | ci->i_truncate_seq, ci->i_truncate_size, |
| 295 | 307 | NULL, false, 1, 0); | |
| 296 | for (; !list_empty(page_list) && len > 0; | 308 | if (!req) |
| 297 | rc -= PAGE_CACHE_SIZE, len -= PAGE_CACHE_SIZE) { | 309 | return -ENOMEM; |
| 298 | struct page *page = | ||
| 299 | list_entry(page_list->prev, struct page, lru); | ||
| 300 | 310 | ||
| 311 | /* build page vector */ | ||
| 312 | nr_pages = len >> PAGE_CACHE_SHIFT; | ||
| 313 | pages = kmalloc(sizeof(*pages) * nr_pages, GFP_NOFS); | ||
| 314 | ret = -ENOMEM; | ||
| 315 | if (!pages) | ||
| 316 | goto out; | ||
| 317 | for (i = 0; i < nr_pages; ++i) { | ||
| 318 | page = list_entry(page_list->prev, struct page, lru); | ||
| 319 | BUG_ON(PageLocked(page)); | ||
| 301 | list_del(&page->lru); | 320 | list_del(&page->lru); |
| 302 | 321 | ||
| 303 | if (rc < (int)PAGE_CACHE_SIZE) { | 322 | dout("start_read %p adding %p idx %lu\n", inode, page, |
| 304 | /* zero (remainder of) page */ | 323 | page->index); |
| 305 | int s = rc < 0 ? 0 : rc; | 324 | if (add_to_page_cache_lru(page, &inode->i_data, page->index, |
| 306 | zero_user_segment(page, s, PAGE_CACHE_SIZE); | ||
| 307 | } | ||
| 308 | |||
| 309 | if (add_to_page_cache_lru(page, mapping, page->index, | ||
| 310 | GFP_N | ||
