]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
kclient: only update xattr blob when defined and newer (caps|reply)
authorSage Weil <sage@newdream.net>
Fri, 9 Jan 2009 00:45:53 +0000 (16:45 -0800)
committerSage Weil <sage@newdream.net>
Fri, 9 Jan 2009 00:45:53 +0000 (16:45 -0800)
src/kernel/caps.c
src/kernel/inode.c
src/kernel/super.h

index 3b2d0142191a8641b25bc3ede848ea3ba2941f13..82a530920b07436aa7a67b436bdd3aebfcc71da4 100644 (file)
@@ -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)
index 5d6c8345370ac6cc28a09fe428a95be079baea3e..55b6c692d2daa31aac6da7d77a88146460a96d95 100644 (file)
@@ -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--) {
index 0c75cc793a5169870da501ca4087d6bd86142cc5..b4a8ca505d068f9a5dbb27145545176f51dff523 100644 (file)
@@ -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. */