Whamcloud - gitweb
LU-16210 llite: replace selinux_is_enabled()
[fs/lustre-release.git] / lustre / llite / xattr_cache.c
index 835c737..0a75174 100644 (file)
@@ -139,6 +139,13 @@ 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) ||
+                   !strcmp(xattr_name, LL_XATTR_NAME_ENCRYPTION_CONTEXT_OLD))
+                       /* 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 +257,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 +268,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 +295,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);
@@ -297,12 +316,48 @@ int ll_xattr_cache_destroy(struct inode *inode)
 }
 
 /**
+ * ll_xattr_cache_empty - empty xattr cache for @ino
+ *
+ * Similar to ll_xattr_cache_destroy(), but preserves encryption context.
+ * So only LLIF_XATTR_CACHE_FILLED flag is cleared, but not LLIF_XATTR_CACHE.
+ */
+int ll_xattr_cache_empty(struct inode *inode)
+{
+       struct ll_inode_info *lli = ll_i2info(inode);
+       struct ll_xattr_entry *entry, *n;
+
+       ENTRY;
+
+       down_write(&lli->lli_xattrs_list_rwsem);
+       if (!ll_xattr_cache_valid(lli) ||
+           !ll_xattr_cache_filled(lli))
+               GOTO(out_empty, 0);
+
+       list_for_each_entry_safe(entry, n, &lli->lli_xattrs, xe_list) {
+               if (strcmp(entry->xe_name, xattr_for_enc(inode)) == 0)
+                       continue;
+
+               CDEBUG(D_CACHE, "delete: %s\n", entry->xe_name);
+               list_del(&entry->xe_list);
+               OBD_FREE(entry->xe_name, entry->xe_namelen);
+               OBD_FREE(entry->xe_value, entry->xe_vallen);
+               OBD_SLAB_FREE_PTR(entry, xattr_kmem);
+       }
+       clear_bit(LLIF_XATTR_CACHE_FILLED, &lli->lli_flags);
+
+out_empty:
+       up_write(&lli->lli_xattrs_list_rwsem);
+       RETURN(0);
+}
+
+/**
  * Match or enqueue a PR lock.
  *
  * 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 +379,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 +422,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
@@ -386,12 +443,14 @@ static int ll_xattr_cache_refill(struct inode *inode)
 
        ENTRY;
 
+       CFS_FAIL_TIMEOUT(OBD_FAIL_LLITE_XATTR_PAUSE, cfs_fail_val ?: 2);
+
        rc = ll_xattr_find_get_lock(inode, &oit, &req);
        if (rc)
                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 +486,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);
@@ -445,9 +505,13 @@ static int ll_xattr_cache_refill(struct inode *inode)
                        CDEBUG(D_CACHE, "not caching %s\n",
                               XATTR_NAME_ACL_ACCESS);
                        rc = 0;
-               } else if (!strcmp(xdata, "security.selinux")) {
-                       /* Filter out security.selinux, it is cached in slab */
-                       CDEBUG(D_CACHE, "not caching security.selinux\n");
+               } else if (ll_xattr_is_seclabel(xdata)) {
+                       /* Filter out security label, it is cached in slab */
+                       CDEBUG(D_CACHE, "not caching %s\n", xdata);
+                       rc = 0;
+               } else if (!strcmp(xdata, XATTR_NAME_SOM)) {
+                       /* Filter out trusted.som, it is not cached on client */
+                       CDEBUG(D_CACHE, "not caching trusted.som\n");
                        rc = 0;
                } else {
                        rc = ll_xattr_cache_add(&lli->lli_xattrs, xdata, xval,
@@ -464,6 +528,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 +579,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, xattr_for_enc(inode)) != 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;
 
@@ -537,6 +614,21 @@ int ll_xattr_cache_get(struct inode *inode,
                                else
                                        rc = -ERANGE;
                        }
+               /* Return the project id when the virtual project id xattr
+                * is explicitly asked.
+                */
+               } else if (strcmp(name, XATTR_NAME_PROJID) == 0) {
+                       /* 10 chars to hold u32 in decimal, plus ending \0 */
+                       char projid[11];
+
+                       rc = snprintf(projid, sizeof(projid),
+                                     "%u", lli->lli_projid);
+                       if (size != 0) {
+                               if (rc <= size)
+                                       memcpy(buffer, projid, rc);
+                               else
+                                       rc = -ERANGE;
+                       }
                }
        } else if (valid & OBD_MD_FLXATTRLS) {
                rc = ll_xattr_cache_list(&lli->lli_xattrs,
@@ -570,18 +662,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);
 }