aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYan, Zheng <zyan@redhat.com>2014-09-16 07:15:28 -0400
committerSage Weil <sage@redhat.com>2014-10-14 15:56:49 -0400
commit25e6bae356502cde283f1804111b44e6fad20fc2 (patch)
tree8825e784ff921f4dd27e42b321c1a26cf26b9632
parente4339d28f640a7c0d92903bcf389a2dfa281270d (diff)
ceph: use pagelist to present MDS request data
Current code uses page array to present MDS request data. Pages in the array are allocated/freed by caller of ceph_mdsc_do_request(). If request is interrupted, the pages can be freed while they are still being used by the request message. The fix is use pagelist to present MDS request data. Pagelist is reference counted. Signed-off-by: Yan, Zheng <zyan@redhat.com> Reviewed-by: Sage Weil <sage@redhat.com>
-rw-r--r--fs/ceph/mds_client.c14
-rw-r--r--fs/ceph/mds_client.h4
-rw-r--r--fs/ceph/xattr.c49
3 files changed, 28 insertions, 39 deletions
diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index b4430ce1b3f6..f8f774e6f868 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -543,6 +543,8 @@ void ceph_mdsc_release_request(struct kref *kref)
543 } 543 }
544 kfree(req->r_path1); 544 kfree(req->r_path1);
545 kfree(req->r_path2); 545 kfree(req->r_path2);
546 if (req->r_pagelist)
547 ceph_pagelist_release(req->r_pagelist);
546 put_request_session(req); 548 put_request_session(req);
547 ceph_unreserve_caps(req->r_mdsc, &req->r_caps_reservation); 549 ceph_unreserve_caps(req->r_mdsc, &req->r_caps_reservation);
548 kfree(req); 550 kfree(req);
@@ -1916,13 +1918,15 @@ static struct ceph_msg *create_request_message(struct ceph_mds_client *mdsc,
1916 msg->front.iov_len = p - msg->front.iov_base; 1918 msg->front.iov_len = p - msg->front.iov_base;
1917 msg->hdr.front_len = cpu_to_le32(msg->front.iov_len); 1919 msg->hdr.front_len = cpu_to_le32(msg->front.iov_len);
1918 1920
1919 if (req->r_data_len) { 1921 if (req->r_pagelist) {
1920 /* outbound data set only by ceph_sync_setxattr() */ 1922 struct ceph_pagelist *pagelist = req->r_pagelist;
1921 BUG_ON(!req->r_pages); 1923 atomic_inc(&pagelist->refcnt);
1922 ceph_msg_data_add_pages(msg, req->r_pages, req->r_data_len, 0); 1924 ceph_msg_data_add_pagelist(msg, pagelist);
1925 msg->hdr.data_len = cpu_to_le32(pagelist->length);
1926 } else {
1927 msg->hdr.data_len = 0;
1923 } 1928 }
1924 1929
1925 msg->hdr.data_len = cpu_to_le32(req->r_data_len);
1926 msg->hdr.data_off = cpu_to_le16(0); 1930 msg->hdr.data_off = cpu_to_le16(0);
1927 1931
1928out_free2: 1932out_free2:
diff --git a/fs/ceph/mds_client.h b/fs/ceph/mds_client.h
index e00737cf523c..23015f747061 100644
--- a/fs/ceph/mds_client.h
+++ b/fs/ceph/mds_client.h
@@ -202,9 +202,7 @@ struct ceph_mds_request {
202 bool r_direct_is_hash; /* true if r_direct_hash is valid */ 202 bool r_direct_is_hash; /* true if r_direct_hash is valid */
203 203
204 /* data payload is used for xattr ops */ 204 /* data payload is used for xattr ops */
205 struct page **r_pages; 205 struct ceph_pagelist *r_pagelist;
206 int r_num_pages;
207 int r_data_len;
208 206
209 /* what caps shall we drop? */ 207 /* what caps shall we drop? */
210 int r_inode_drop, r_inode_unless; 208 int r_inode_drop, r_inode_unless;
diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c
index 19da5026c38f..678b0d2bbbc4 100644
--- a/fs/ceph/xattr.c
+++ b/fs/ceph/xattr.c
@@ -1,4 +1,5 @@
1#include <linux/ceph/ceph_debug.h> 1#include <linux/ceph/ceph_debug.h>
2#include <linux/ceph/pagelist.h>
2 3
3#include "super.h" 4#include "super.h"
4#include "mds_client.h" 5#include "mds_client.h"
@@ -850,35 +851,25 @@ static int ceph_sync_setxattr(struct dentry *dentry, const char *name,
850 struct ceph_inode_info *ci = ceph_inode(inode); 851 struct ceph_inode_info *ci = ceph_inode(inode);
851 struct ceph_mds_request *req; 852 struct ceph_mds_request *req;
852 struct ceph_mds_client *mdsc = fsc->mdsc; 853 struct ceph_mds_client *mdsc = fsc->mdsc;
854 struct ceph_pagelist *pagelist = NULL;
853 int err; 855 int err;
854 int i, nr_pages; 856
855 struct page **pages = NULL; 857 if (value) {
856 void *kaddr; 858 /* copy value into pagelist */
857 859 pagelist = kmalloc(sizeof(*pagelist), GFP_NOFS);
858 /* copy value into some pages */ 860 if (!pagelist)
859 nr_pages = calc_pages_for(0, size);
860 if (nr_pages) {
861 pages = kmalloc(sizeof(pages[0])*nr_pages, GFP_NOFS);
862 if (!pages)
863 return -ENOMEM; 861 return -ENOMEM;
864 err = -ENOMEM; 862
865 for (i = 0; i < nr_pages; i++) { 863 ceph_pagelist_init(pagelist);
866 pages[i] = __page_cache_alloc(GFP_NOFS); 864 err = ceph_pagelist_append(pagelist, value, size);
867 if (!pages[i]) { 865 if (err)
868 nr_pages = i; 866 goto out;
869 goto out; 867 } else {
870 } 868 flags |= CEPH_XATTR_REMOVE;
871 kaddr = kmap(pages[i]);
872 memcpy(kaddr, value + i*PAGE_CACHE_SIZE,
873 min(PAGE_CACHE_SIZE, size-i*PAGE_CACHE_SIZE));
874 }
875 } 869 }
876 870
877 dout("setxattr value=%.*s\n", (int)size, value); 871 dout("setxattr value=%.*s\n", (int)size, value);
878 872
879 if (!value)
880 flags |= CEPH_XATTR_REMOVE;
881
882 /* do request */ 873 /* do request */
883 req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETXATTR, 874 req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETXATTR,
884 USE_AUTH_MDS); 875 USE_AUTH_MDS);
@@ -893,9 +884,8 @@ static int ceph_sync_setxattr(struct dentry *dentry, const char *name,
893 req->r_args.setxattr.flags = cpu_to_le32(flags); 884 req->r_args.setxattr.flags = cpu_to_le32(flags);
894 req->r_path2 = kstrdup(name, GFP_NOFS); 885 req->r_path2 = kstrdup(name, GFP_NOFS);
895 886
896 req->r_pages = pages; 887 req->r_pagelist = pagelist;
897 req->r_num_pages = nr_pages; 888 pagelist = NULL;
898 req->r_data_len = size;
899 889
900 dout("xattr.ver (before): %lld\n", ci->i_xattrs.version); 890 dout("xattr.ver (before): %lld\n", ci->i_xattrs.version);
901 err = ceph_mdsc_do_request(mdsc, NULL, req); 891 err = ceph_mdsc_do_request(mdsc, NULL, req);
@@ -903,11 +893,8 @@ static int ceph_sync_setxattr(struct dentry *dentry, const char *name,
903 dout("xattr.ver (after): %lld\n", ci->i_xattrs.version); 893 dout("xattr.ver (after): %lld\n", ci->i_xattrs.version);
904 894
905out: 895out:
906 if (pages) { 896 if (pagelist)
907 for (i = 0; i < nr_pages; i++) 897 ceph_pagelist_release(pagelist);
908 __free_page(pages[i]);
909 kfree(pages);
910 }
911 return err; 898 return err;
912} 899}
913 900