struct cachefiles_object *object,
                                          struct dentry *dentry);
 extern void cachefiles_prepare_to_write(struct fscache_cookie *cookie);
+extern bool cachefiles_set_volume_xattr(struct cachefiles_volume *volume);
+extern int cachefiles_check_volume_xattr(struct cachefiles_volume *volume);
 
 /*
  * Error handling
 
        struct dentry *vdentry, *fan;
        size_t len;
        char *name;
-       int n_accesses, i;
+       bool is_new = false;
+       int ret, n_accesses, i;
 
        _enter("");
 
        memcpy(name + 1, vcookie->key + 1, len);
        name[len + 1] = 0;
 
-       vdentry = cachefiles_get_directory(cache, cache->store, name, NULL);
+retry:
+       vdentry = cachefiles_get_directory(cache, cache->store, name, &is_new);
        if (IS_ERR(vdentry))
                goto error_name;
        volume->dentry = vdentry;
 
+       if (is_new) {
+               if (!cachefiles_set_volume_xattr(volume))
+                       goto error_dir;
+       } else {
+               ret = cachefiles_check_volume_xattr(volume);
+               if (ret < 0) {
+                       if (ret != -ESTALE)
+                               goto error_dir;
+                       inode_lock_nested(d_inode(cache->store), I_MUTEX_PARENT);
+                       cachefiles_bury_object(cache, NULL, cache->store, vdentry,
+                                              FSCACHE_VOLUME_IS_WEIRD);
+                       cachefiles_put_directory(volume->dentry);
+                       cond_resched();
+                       goto retry;
+               }
+       }
+       
        for (i = 0; i < 256; i++) {
                sprintf(name, "@%02x", i);
                fan = cachefiles_get_directory(cache, vdentry, name, NULL);
 error_fan:
        for (i = 0; i < 256; i++)
                cachefiles_put_directory(volume->fanout[i]);
+error_dir:
        cachefiles_put_directory(volume->dentry);
 error_name:
        kfree(name);
 void cachefiles_withdraw_volume(struct cachefiles_volume *volume)
 {
        fscache_withdraw_volume(volume->vcookie);
+       cachefiles_set_volume_xattr(volume);
        __cachefiles_free_volume(volume);
 }
 
                cachefiles_end_secure(cache, saved_cred);
        }
 }
+
+/*
+ * Set the state xattr on a volume directory.
+ */
+bool cachefiles_set_volume_xattr(struct cachefiles_volume *volume)
+{
+       unsigned int len = volume->vcookie->coherency_len;
+       const void *p = volume->vcookie->coherency;
+       struct dentry *dentry = volume->dentry;
+       int ret;
+
+       _enter("%x,#%d", volume->vcookie->debug_id, len);
+
+       ret = cachefiles_inject_write_error();
+       if (ret == 0)
+               ret = vfs_setxattr(&init_user_ns, dentry, cachefiles_xattr_cache,
+                                  p, len, 0);
+       if (ret < 0) {
+               trace_cachefiles_vfs_error(NULL, d_inode(dentry), ret,
+                                          cachefiles_trace_setxattr_error);
+               trace_cachefiles_vol_coherency(volume, d_inode(dentry)->i_ino,
+                                              cachefiles_coherency_vol_set_fail);
+               if (ret != -ENOMEM)
+                       cachefiles_io_error(
+                               volume->cache, "Failed to set xattr with error %d", ret);
+       } else {
+               trace_cachefiles_vol_coherency(volume, d_inode(dentry)->i_ino,
+                                              cachefiles_coherency_vol_set_ok);
+       }
+
+       _leave(" = %d", ret);
+       return ret == 0;
+}
+
+/*
+ * Check the consistency between the backing cache and the volume cookie.
+ */
+int cachefiles_check_volume_xattr(struct cachefiles_volume *volume)
+{
+       struct cachefiles_xattr *buf;
+       struct dentry *dentry = volume->dentry;
+       unsigned int len = volume->vcookie->coherency_len;
+       const void *p = volume->vcookie->coherency;
+       enum cachefiles_coherency_trace why;
+       ssize_t xlen;
+       int ret = -ESTALE;
+
+       _enter("");
+
+       buf = kmalloc(len, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
+       xlen = cachefiles_inject_read_error();
+       if (xlen == 0)
+               xlen = vfs_getxattr(&init_user_ns, dentry, cachefiles_xattr_cache, buf, len);
+       if (xlen != len) {
+               if (xlen < 0) {
+                       trace_cachefiles_vfs_error(NULL, d_inode(dentry), xlen,
+                                                  cachefiles_trace_getxattr_error);
+                       if (xlen == -EIO)
+                               cachefiles_io_error(
+                                       volume->cache,
+                                       "Failed to read xattr with error %zd", xlen);
+               }
+               why = cachefiles_coherency_vol_check_xattr;
+       } else if (memcmp(buf->data, p, len) != 0) {
+               why = cachefiles_coherency_vol_check_cmp;
+       } else {
+               why = cachefiles_coherency_vol_check_ok;
+               ret = 0;
+       }
+
+       trace_cachefiles_vol_coherency(volume, d_inode(dentry)->i_ino, why);
+       kfree(buf);
+       _leave(" = %d", ret);
+       return ret;
+}
 
        size_t klen, hlen;
        char *key;
 
+       if (!coherency_data)
+               coherency_len = 0;
+
        cache = fscache_lookup_cache(cache_name, false);
        if (IS_ERR(cache))
                return NULL;
 
-       volume = kzalloc(sizeof(*volume), GFP_KERNEL);
+       volume = kzalloc(struct_size(volume, coherency, coherency_len),
+                        GFP_KERNEL);
        if (!volume)
                goto err_cache;
 
        volume->cache = cache;
+       volume->coherency_len = coherency_len;
+       if (coherency_data)
+               memcpy(volume->coherency, coherency_data, coherency_len);
        INIT_LIST_HEAD(&volume->proc_link);
        INIT_WORK(&volume->work, fscache_create_volume_work);
        refcount_set(&volume->ref, 1);
        if (WARN_ON(test_and_set_bit(FSCACHE_VOLUME_RELINQUISHED, &volume->flags)))
                return;
 
-       if (invalidate)
+       if (invalidate) {
                set_bit(FSCACHE_VOLUME_INVALIDATE, &volume->flags);
+       } else if (coherency_data) {
+               memcpy(volume->coherency, coherency_data, volume->coherency_len);
+       }
 
        fscache_put_volume(volume, fscache_volume_put_relinquish);
 }
 
 #define FSCACHE_VOLUME_COLLIDED_WITH   2       /* Volume was collided with */
 #define FSCACHE_VOLUME_ACQUIRE_PENDING 3       /* Volume is waiting to complete acquisition */
 #define FSCACHE_VOLUME_CREATING                4       /* Volume is being created on disk */
+       u8                              coherency_len;  /* Length of the coherency data */
+       u8                              coherency[];    /* Coherency data */
 };
 
 /*
 
        FSCACHE_OBJECT_NO_SPACE,
        FSCACHE_OBJECT_WAS_RETIRED,
        FSCACHE_OBJECT_WAS_CULLED,
+       FSCACHE_VOLUME_IS_WEIRD,
 };
 
 enum cachefiles_coherency_trace {
        cachefiles_coherency_check_xattr,
        cachefiles_coherency_set_fail,
        cachefiles_coherency_set_ok,
+       cachefiles_coherency_vol_check_cmp,
+       cachefiles_coherency_vol_check_ok,
+       cachefiles_coherency_vol_check_xattr,
+       cachefiles_coherency_vol_set_fail,
+       cachefiles_coherency_vol_set_ok,
 };
 
 enum cachefiles_trunc_trace {
        EM(FSCACHE_OBJECT_INVALIDATED,  "inval")                \
        EM(FSCACHE_OBJECT_NO_SPACE,     "no_space")             \
        EM(FSCACHE_OBJECT_WAS_RETIRED,  "was_retired")          \
-       E_(FSCACHE_OBJECT_WAS_CULLED,   "was_culled")
+       EM(FSCACHE_OBJECT_WAS_CULLED,   "was_culled")           \
+       E_(FSCACHE_VOLUME_IS_WEIRD,     "volume_weird")
 
 #define cachefiles_obj_ref_traces                                      \
        EM(cachefiles_obj_get_ioreq,            "GET ioreq")            \
        EM(cachefiles_coherency_check_type,     "BAD type")             \
        EM(cachefiles_coherency_check_xattr,    "BAD xatt")             \
        EM(cachefiles_coherency_set_fail,       "SET fail")             \
-       E_(cachefiles_coherency_set_ok,         "SET ok  ")
+       EM(cachefiles_coherency_set_ok,         "SET ok  ")             \
+       EM(cachefiles_coherency_vol_check_cmp,  "VOL BAD cmp ")         \
+       EM(cachefiles_coherency_vol_check_ok,   "VOL OK      ")         \
+       EM(cachefiles_coherency_vol_check_xattr,"VOL BAD xatt")         \
+       EM(cachefiles_coherency_vol_set_fail,   "VOL SET fail")         \
+       E_(cachefiles_coherency_vol_set_ok,     "VOL SET ok  ")
 
 #define cachefiles_trunc_traces                                                \
        EM(cachefiles_trunc_dio_adjust,         "DIOADJ")               \
                      __entry->content)
            );
 
+TRACE_EVENT(cachefiles_vol_coherency,
+           TP_PROTO(struct cachefiles_volume *volume,
+                    ino_t ino,
+                    enum cachefiles_coherency_trace why),
+
+           TP_ARGS(volume, ino, why),
+
+           /* Note that obj may be NULL */
+           TP_STRUCT__entry(
+                   __field(unsigned int,                       vol     )
+                   __field(enum cachefiles_coherency_trace,    why     )
+                   __field(u64,                                ino     )
+                            ),
+
+           TP_fast_assign(
+                   __entry->vol        = volume->vcookie->debug_id;
+                   __entry->why        = why;
+                   __entry->ino        = ino;
+                          ),
+
+           TP_printk("V=%08x %s i=%llx",
+                     __entry->vol,
+                     __print_symbolic(__entry->why, cachefiles_coherency_traces),
+                     __entry->ino)
+           );
+
 TRACE_EVENT(cachefiles_prep_read,
            TP_PROTO(struct netfs_read_subrequest *sreq,
                     enum netfs_read_source source,