*/
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)
{
}
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? */
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);
}
+ /* 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);
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);
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)
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",
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);
}
spin_lock(&inode->i_lock);
err = -ENODATA; /* == ENOATTR */
- if (!ci->i_xattr_len)
+ if (ci->i_xattr_len <= 4)
goto out;
/* find attr name */
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);
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--) {
gid_t gid;
void *xattr_blob;
- int xattr_len;
+ int xattr_len;
+ u64 xattr_version;
u64 size;
struct timespec mtime, atime, ctime;
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. */