aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ceph/xattr.c
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 /fs/ceph/xattr.c
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>
Diffstat (limited to 'fs/ceph/xattr.c')
-rw-r--r--fs/ceph/xattr.c49
1 files changed, 18 insertions, 31 deletions
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