Whamcloud - gitweb
LU-14989 sec: access to enc file's xattrs
[fs/lustre-release.git] / lustre / llite / xattr_cache.c
index 835c737..d572f73 100644 (file)
@@ -139,6 +139,12 @@ static int ll_xattr_cache_add(struct list_head *cache,
        ENTRY;
 
        if (ll_xattr_cache_find(cache, xattr_name, &xattr) == 0) {
+               if (!strcmp(xattr_name, LL_XATTR_NAME_ENCRYPTION_CONTEXT))
+                       /* it means enc ctx was already in cache,
+                        * ignore error as it cannot be modified
+                        */
+                       RETURN(0);
+
                CDEBUG(D_CACHE, "duplicate xattr: [%s]\n", xattr_name);
                RETURN(-EPROTO);
        }
@@ -250,7 +256,7 @@ static int ll_xattr_cache_list(struct list_head *cache,
 }
 
 /**
- * Check if the xattr cache is initialized (filled).
+ * Check if the xattr cache is initialized.
  *
  * \retval 0 @cache is not initialized
  * \retval 1 @cache is initialized
@@ -261,6 +267,17 @@ static int ll_xattr_cache_valid(struct ll_inode_info *lli)
 }
 
 /**
+ * Check if the xattr cache is filled.
+ *
+ * \retval 0 @cache is not filled
+ * \retval 1 @cache is filled
+ */
+static int ll_xattr_cache_filled(struct ll_inode_info *lli)
+{
+       return test_bit(LLIF_XATTR_CACHE_FILLED, &lli->lli_flags);
+}
+
+/**
  * This finalizes the xattr cache.
  *
  * Free all xattr memory. @lli is the inode info pointer.
@@ -277,6 +294,7 @@ static int ll_xattr_cache_destroy_locked(struct ll_inode_info *lli)
        while (ll_xattr_cache_del(&lli->lli_xattrs, NULL) == 0)
                /* empty loop */ ;
 
+       clear_bit(LLIF_XATTR_CACHE_FILLED, &lli->lli_flags);
        clear_bit(LLIF_XATTR_CACHE, &lli->lli_flags);
 
        RETURN(0);
@@ -302,7 +320,8 @@ int ll_xattr_cache_destroy(struct inode *inode)
  * Find or request an LDLM lock with xattr data.
  * Since LDLM does not provide API for atomic match_or_enqueue,
  * the function handles it with a separate enq lock.
- * If successful, the function exits with the list lock held.
+ * If successful, the function exits with a write lock held
+ * on lli_xattrs_list_rwsem.
  *
  * \retval 0       no error occured
  * \retval -ENOMEM not enough memory
@@ -324,7 +343,7 @@ static int ll_xattr_find_get_lock(struct inode *inode,
        mutex_lock(&lli->lli_xattrs_enq_lock);
        /* inode may have been shrunk and recreated, so data is gone, match lock
         * only when data exists. */
-       if (ll_xattr_cache_valid(lli)) {
+       if (ll_xattr_cache_filled(lli)) {
                /* Try matching first. */
                mode = ll_take_md_lock(inode, MDS_INODELOCK_XATTR, &lockh, 0,
                                        LCK_PR);
@@ -367,7 +386,9 @@ out:
 /**
  * Refill the xattr cache.
  *
- * Fetch and cache the whole of xattrs for @inode, acquiring a read lock.
+ * Fetch and cache the whole of xattrs for @inode, thanks to the write lock
+ * on lli_xattrs_list_rwsem obtained from ll_xattr_find_get_lock().
+ * If successful, this write lock is kept.
  *
  * \retval 0       no error occured
  * \retval -EPROTO network protocol error
@@ -391,7 +412,7 @@ static int ll_xattr_cache_refill(struct inode *inode)
                GOTO(err_req, rc);
 
        /* Do we have the data at this point? */
-       if (ll_xattr_cache_valid(lli)) {
+       if (ll_xattr_cache_filled(lli)) {
                ll_stats_ops_tally(sbi, LPROC_LL_GETXATTR_HITS, 1);
                ll_intent_drop_lock(&oit);
                GOTO(err_req, rc = 0);
@@ -427,7 +448,8 @@ static int ll_xattr_cache_refill(struct inode *inode)
 
        CDEBUG(D_CACHE, "caching: xdata=%p xtail=%p\n", xdata, xtail);
 
-       ll_xattr_cache_init(lli);
+       if (!ll_xattr_cache_valid(lli))
+               ll_xattr_cache_init(lli);
 
        for (i = 0; i < body->mbo_max_mdsize; i++) {
                CDEBUG(D_CACHE, "caching [%s]=%.*s\n", xdata, *xsizes, xval);
@@ -464,6 +486,8 @@ static int ll_xattr_cache_refill(struct inode *inode)
 
        if (xdata != xtail || xval != xvtail)
                CERROR("a hole in xattr data\n");
+       else
+               set_bit(LLIF_XATTR_CACHE_FILLED, &lli->lli_flags);
 
        ll_set_lock_data(sbi->ll_md_exp, inode, &oit, NULL);
        ll_intent_drop_lock(&oit);
@@ -513,16 +537,27 @@ int ll_xattr_cache_get(struct inode *inode,
        LASSERT(!!(valid & OBD_MD_FLXATTR) ^ !!(valid & OBD_MD_FLXATTRLS));
 
        down_read(&lli->lli_xattrs_list_rwsem);
-       if (!ll_xattr_cache_valid(lli)) {
+       /* For performance reasons, we do not want to refill complete xattr
+        * cache if we are just interested in encryption context.
+        */
+       if ((valid & OBD_MD_FLXATTRLS ||
+            strcmp(name, LL_XATTR_NAME_ENCRYPTION_CONTEXT) != 0) &&
+           !ll_xattr_cache_filled(lli)) {
                up_read(&lli->lli_xattrs_list_rwsem);
                rc = ll_xattr_cache_refill(inode);
                if (rc)
                        RETURN(rc);
+               /* Turn the write lock obtained in ll_xattr_cache_refill()
+                * into a read lock.
+                */
                downgrade_write(&lli->lli_xattrs_list_rwsem);
        } else {
                ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_GETXATTR_HITS, 1);
        }
 
+       if (!ll_xattr_cache_valid(lli))
+               GOTO(out, rc = -ENODATA);
+
        if (valid & OBD_MD_FLXATTR) {
                struct ll_xattr_entry *xattr;
 
@@ -570,18 +605,10 @@ int ll_xattr_cache_insert(struct inode *inode,
 
        ENTRY;
 
-       down_read(&lli->lli_xattrs_list_rwsem);
+       down_write(&lli->lli_xattrs_list_rwsem);
        if (!ll_xattr_cache_valid(lli))
                ll_xattr_cache_init(lli);
-       rc = ll_xattr_cache_add(&lli->lli_xattrs, name, buffer,
-                               size);
-       up_read(&lli->lli_xattrs_list_rwsem);
-
-       if (rc == -EPROTO &&
-           strcmp(name, LL_XATTR_NAME_ENCRYPTION_CONTEXT) == 0)
-               /* it means enc ctx was already in cache,
-                * ignore error as it cannot be modified
-                */
-               rc = 0;
+       rc = ll_xattr_cache_add(&lli->lli_xattrs, name, buffer, size);
+       up_write(&lli->lli_xattrs_list_rwsem);
        RETURN(rc);
 }