From: Sage Weil Date: Fri, 9 Jan 2009 00:45:53 +0000 (-0800) Subject: kclient: only update xattr blob when defined and newer (caps|reply) X-Git-Tag: v0.6~1^2~121 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=c7fa14dc61f0c8e8d250b06da8c08fa257e5f006;p=ceph.git kclient: only update xattr blob when defined and newer (caps|reply) --- diff --git a/src/kernel/caps.c b/src/kernel/caps.c index 3b2d0142191a..82a530920b07 100644 --- a/src/kernel/caps.c +++ b/src/kernel/caps.c @@ -1095,7 +1095,8 @@ void ceph_put_wrbuffer_cap_refs(struct ceph_inode_info *ci, int nr, */ static int handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant, struct ceph_mds_session *session, - struct ceph_cap *cap) + struct ceph_cap *cap, + void **xattr_data) __releases(inode->i_lock) { @@ -1188,7 +1189,19 @@ start: } if ((issued & CEPH_CAP_XATTR_EXCL) == 0 && grant->xattr_len) { -#warning fix xattr cap update + int len = le32_to_cpu(grant->xattr_len); + u64 version = le64_to_cpu(grant->xattr_version); + + if (!(len > 4 && *xattr_data == 0) && /* ENOMEM in caller */ + version > ci->i_xattr_version) { + dout(20, " got new xattrs v%llu on %p len %d\n", + version, inode, len); + kfree(ci->i_xattr_data); + ci->i_xattr_len = len; + ci->i_xattr_version = version; + ci->i_xattr_data = *xattr_data; + *xattr_data = 0; + } } /* size/ctime/mtime/atime? */ @@ -1540,6 +1553,7 @@ void ceph_handle_caps(struct ceph_mds_client *mdsc, struct ceph_vino vino; u64 size, max_size; int check_caps = 0; + void *xattr_data = 0; dout(10, "handle_caps from mds%d\n", mds); @@ -1602,6 +1616,10 @@ void ceph_handle_caps(struct ceph_mds_client *mdsc, } + /* preallocate space for xattrs? */ + if (le32_to_cpu(h->xattr_len) > 4) + xattr_data = kmalloc(le32_to_cpu(h->xattr_len), GFP_NOFS); + /* the rest require a cap */ spin_lock(&inode->i_lock); cap = __get_cap_for_mds(inode, mds); @@ -1616,7 +1634,7 @@ void ceph_handle_caps(struct ceph_mds_client *mdsc, switch (op) { case CEPH_CAP_OP_GRANT: up_write(&mdsc->snap_rwsem); - if (handle_cap_grant(inode, h, session, cap) == 1) { + if (handle_cap_grant(inode, h, session, cap,&xattr_data) == 1) { dout(10, " sending reply back to mds%d\n", mds); ceph_msg_get(msg); ceph_send_msg_mds(mdsc, msg, mds); @@ -1645,6 +1663,7 @@ done: mutex_unlock(&session->s_mutex); ceph_put_mds_session(session); + kfree(xattr_data); if (check_caps) ceph_check_caps(ceph_inode(inode), 1, 0); if (inode) diff --git a/src/kernel/inode.c b/src/kernel/inode.c index 5d6c8345370a..55b6c692d2da 100644 --- a/src/kernel/inode.c +++ b/src/kernel/inode.c @@ -405,8 +405,12 @@ static int fill_inode(struct inode *inode, inode, ceph_vinop(inode), le64_to_cpu(info->version), ci->i_version); - /* prealloc xattr data, if it looks like we'll need it */ - if (iinfo->xattr_len && iinfo->xattr_len != ci->i_xattr_len) { + /* + * prealloc xattr data, if it looks like we'll need it. only + * if len > 4 (meaning there are actually xattrs; the first 4 + * bytes are the xattr count). + */ + if (iinfo->xattr_len > 4 && iinfo->xattr_len != ci->i_xattr_len) { xattr_data = kmalloc(iinfo->xattr_len, GFP_NOFS); if (!xattr_data) derr(10, "ENOMEM on xattr blob %d bytes\n", @@ -451,14 +455,17 @@ static int fill_inode(struct inode *inode, inode->i_blkbits = fls(le32_to_cpu(info->layout.fl_stripe_unit)) - 1; /* xattrs */ - if (iinfo->xattr_len && (issued & CEPH_CAP_XATTR_EXCL) == 0) { + /* note that if i_xattr_len <= 4, i_xattr_data will still be NULL. */ + if (iinfo->xattr_len && (issued & CEPH_CAP_XATTR_EXCL) == 0 && + le64_to_cpu(info->xattr_version) > ci->i_xattr_version) { if (ci->i_xattr_len != iinfo->xattr_len) { kfree(ci->i_xattr_data); ci->i_xattr_len = iinfo->xattr_len; + ci->i_xattr_version = le64_to_cpu(info->xattr_version); ci->i_xattr_data = xattr_data; xattr_data = NULL; } - if (ci->i_xattr_len) + if (ci->i_xattr_len > 4) memcpy(ci->i_xattr_data, iinfo->xattr_data, ci->i_xattr_len); } @@ -1802,7 +1809,7 @@ ssize_t ceph_getxattr(struct dentry *dentry, const char *name, void *value, spin_lock(&inode->i_lock); err = -ENODATA; /* == ENOATTR */ - if (!ci->i_xattr_len) + if (ci->i_xattr_len <= 4) goto out; /* find attr name */ @@ -1858,7 +1865,7 @@ ssize_t ceph_listxattr(struct dentry *dentry, char *names, size_t size) spin_lock(&inode->i_lock); /* measure len of names */ - if (ci->i_xattr_len) { + if (ci->i_xattr_len > 4) { p = ci->i_xattr_data; end = p + ci->i_xattr_len; ceph_decode_32_safe(&p, end, numattr, bad); @@ -1886,7 +1893,7 @@ ssize_t ceph_listxattr(struct dentry *dentry, char *names, size_t size) goto out; /* copy names */ - if (ci->i_xattr_len) { + if (ci->i_xattr_len> 4) { p = ci->i_xattr_data; ceph_decode_32(&p, numattr); while (numattr--) { diff --git a/src/kernel/super.h b/src/kernel/super.h index 0c75cc793a51..b4a8ca505d06 100644 --- a/src/kernel/super.h +++ b/src/kernel/super.h @@ -160,7 +160,8 @@ struct ceph_cap_snap { gid_t gid; void *xattr_blob; - int xattr_len; + int xattr_len; + u64 xattr_version; u64 size; struct timespec mtime, atime, ctime; @@ -220,10 +221,17 @@ struct ceph_inode_info { struct rb_root i_fragtree; struct mutex i_fragtree_mutex; - /* (still encoded) xattr blob. we avoid the overhead of parsing - * this until someone actually called getxattr, etc. */ + /* + * (still encoded) xattr blob. we avoid the overhead of parsing + * this until someone actually calls getxattr, etc. + * + * if i_xattr_len == 0 or 4, i_xattr_data == NULL. + * i_xattr_len == 4 implies there are no xattrs; 0 means we + * don't know. + */ int i_xattr_len; char *i_xattr_data; + u64 i_xattr_version; /* capabilities. protected _both_ by i_lock and cap->session's * s_mutex. */