X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Fllite%2Fxattr_cache.c;h=9de6b6d9cd740a185d242d6f55f49dbede12bff7;hb=6bceb0030d15b70097d75f8da2d373310fe2c658;hp=1abd6ba7aefbdfb2b010aa519abff01b8185d319;hpb=cd8230c9beb72589ff6dc6456de8ca169b674dda;p=fs%2Flustre-release.git diff --git a/lustre/llite/xattr_cache.c b/lustre/llite/xattr_cache.c index 1abd6ba..9de6b6d 100644 --- a/lustre/llite/xattr_cache.c +++ b/lustre/llite/xattr_cache.c @@ -24,7 +24,7 @@ /* * Copyright 2012 Xyratex Technology Limited * - * Copyright (c) 2013, 2014, Intel Corporation. + * Copyright (c) 2013, 2017, Intel Corporation. * * Author: Andrew Perepechko * @@ -37,7 +37,6 @@ #include #include #include -#include #include "llite_internal.h" /* If we ever have hundreds of extended attributes, we might want to consider @@ -86,7 +85,7 @@ static void ll_xattr_cache_init(struct ll_inode_info *lli) LASSERT(lli != NULL); INIT_LIST_HEAD(&lli->lli_xattrs); - ll_file_set_flag(lli, LLIF_XATTR_CACHE); + set_bit(LLIF_XATTR_CACHE, &lli->lli_flags); } /** @@ -140,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); } @@ -251,14 +256,25 @@ 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 */ static int ll_xattr_cache_valid(struct ll_inode_info *lli) { - return ll_file_test_flag(lli, LLIF_XATTR_CACHE); + return test_bit(LLIF_XATTR_CACHE, &lli->lli_flags); +} + +/** + * 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); } /** @@ -278,7 +294,8 @@ static int ll_xattr_cache_destroy_locked(struct ll_inode_info *lli) while (ll_xattr_cache_del(&lli->lli_xattrs, NULL) == 0) /* empty loop */ ; - ll_file_clear_flag(lli, LLIF_XATTR_CACHE); + clear_bit(LLIF_XATTR_CACHE_FILLED, &lli->lli_flags); + clear_bit(LLIF_XATTR_CACHE, &lli->lli_flags); RETURN(0); } @@ -298,12 +315,49 @@ 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, + LL_XATTR_NAME_ENCRYPTION_CONTEXT) == 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 @@ -312,16 +366,10 @@ static int ll_xattr_find_get_lock(struct inode *inode, struct lookup_intent *oit, struct ptlrpc_request **req) { - ldlm_mode_t mode; + enum ldlm_mode mode; struct lustre_handle lockh = { 0 }; struct md_op_data *op_data; struct ll_inode_info *lli = ll_i2info(inode); - struct ldlm_enqueue_info einfo = { - .ei_type = LDLM_IBITS, - .ei_mode = it_to_lock_mode(oit), - .ei_cb_bl = &ll_md_blocking_ast, - .ei_cb_cp = &ldlm_completion_ast, - }; struct ll_sb_info *sbi = ll_i2sbi(inode); struct obd_export *exp = sbi->ll_md_exp; int rc; @@ -331,14 +379,14 @@ 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); if (mode != 0) { /* fake oit in mdc_revalidate_lock() manner */ - oit->d.lustre.it_lock_handle = lockh.cookie; - oit->d.lustre.it_lock_mode = mode; + oit->it_lock_handle = lockh.cookie; + oit->it_lock_mode = mode; goto out; } } @@ -353,8 +401,9 @@ static int ll_xattr_find_get_lock(struct inode *inode, op_data->op_valid = OBD_MD_FLXATTR | OBD_MD_FLXATTRLS; - rc = md_enqueue(exp, &einfo, NULL, oit, op_data, &lockh, 0); + rc = md_intent_lock(exp, op_data, oit, req, &ll_md_blocking_ast, 0); ll_finish_md_op_data(op_data); + *req = oit->it_request; if (rc < 0) { CDEBUG(D_CACHE, "md_intent_lock failed with %d for fid "DFID"\n", @@ -363,7 +412,6 @@ static int ll_xattr_find_get_lock(struct inode *inode, RETURN(rc); } - *req = (struct ptlrpc_request *)oit->d.lustre.it_data; out: down_write(&lli->lli_xattrs_list_rwsem); mutex_unlock(&lli->lli_xattrs_enq_lock); @@ -374,16 +422,17 @@ out: /** * Refill the xattr cache. * - * Fetch and cache the whole of xattrs for @inode, acquiring - * a read or a write xattr lock depending on operation in @oit. - * Intent is dropped on exit unless the operation is setxattr. + * 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 * \retval -ENOMEM not enough memory for the cache */ -static int ll_xattr_cache_refill(struct inode *inode, struct lookup_intent *oit) +static int ll_xattr_cache_refill(struct inode *inode) { + struct lookup_intent oit = { .it_op = IT_GETXATTR }; struct ll_sb_info *sbi = ll_i2sbi(inode); struct ptlrpc_request *req = NULL; const char *xdata, *xval, *xtail, *xvtail; @@ -394,36 +443,30 @@ static int ll_xattr_cache_refill(struct inode *inode, struct lookup_intent *oit) ENTRY; - rc = ll_xattr_find_get_lock(inode, oit, &req); + CFS_FAIL_TIMEOUT(OBD_FAIL_LLITE_XATTR_PAUSE, cfs_fail_val ?: 2); + + rc = ll_xattr_find_get_lock(inode, &oit, &req); if (rc) - GOTO(out_no_unlock, 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); - GOTO(out_maybe_drop, rc = 0); + ll_intent_drop_lock(&oit); + GOTO(err_req, rc = 0); } /* Matched but no cache? Cancelled on error by a parallel refill. */ if (unlikely(req == NULL)) { CDEBUG(D_CACHE, "cancelled by a parallel getxattr\n"); - GOTO(out_maybe_drop, rc = -EIO); - } - - if (oit->d.lustre.it_status < 0) { - CDEBUG(D_CACHE, "getxattr intent returned %d for fid "DFID"\n", - oit->d.lustre.it_status, PFID(ll_inode2fid(inode))); - rc = oit->d.lustre.it_status; - /* xattr data is so large that we don't want to cache it */ - if (rc == -ERANGE) - rc = -EAGAIN; - GOTO(out_destroy, rc); + ll_intent_drop_lock(&oit); + GOTO(err_unlock, rc = -EAGAIN); } body = req_capsule_server_get(&req->rq_pill, &RMF_MDT_BODY); if (body == NULL) { CERROR("no MDT BODY in the refill xattr reply\n"); - GOTO(out_destroy, rc = -EPROTO); + GOTO(err_cancel, rc = -EPROTO); } /* do not need swab xattr data */ xdata = req_capsule_server_sized_get(&req->rq_pill, &RMF_EADATA, @@ -435,7 +478,7 @@ static int ll_xattr_cache_refill(struct inode *inode, struct lookup_intent *oit) sizeof(__u32)); if (xdata == NULL || xval == NULL || xsizes == NULL) { CERROR("wrong setxattr reply\n"); - GOTO(out_destroy, rc = -EPROTO); + GOTO(err_cancel, rc = -EPROTO); } xtail = xdata + body->mbo_eadatasize; @@ -443,7 +486,8 @@ static int ll_xattr_cache_refill(struct inode *inode, struct lookup_intent *oit) 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); @@ -461,13 +505,21 @@ static int ll_xattr_cache_refill(struct inode *inode, struct lookup_intent *oit) 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"); + 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, *xsizes); } if (rc < 0) { ll_xattr_cache_destroy_locked(lli); - GOTO(out_destroy, rc); + GOTO(err_cancel, rc); } xdata += strlen(xdata) + 1; xval += *xsizes; @@ -476,29 +528,27 @@ static int ll_xattr_cache_refill(struct inode *inode, struct lookup_intent *oit) 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); - - GOTO(out_maybe_drop, rc); -out_maybe_drop: - - ll_intent_drop_lock(oit); + ll_set_lock_data(sbi->ll_md_exp, inode, &oit, NULL); + ll_intent_drop_lock(&oit); - if (rc != 0) - up_write(&lli->lli_xattrs_list_rwsem); -out_no_unlock: ptlrpc_req_finished(req); + RETURN(0); - return rc; - -out_destroy: - up_write(&lli->lli_xattrs_list_rwsem); - +err_cancel: ldlm_lock_decref_and_cancel((struct lustre_handle *) - &oit->d.lustre.it_lock_handle, - oit->d.lustre.it_lock_mode); + &oit.it_lock_handle, + oit.it_lock_mode); +err_unlock: + up_write(&lli->lli_xattrs_list_rwsem); +err_req: + if (rc == -ERANGE) + rc = -EAGAIN; - goto out_no_unlock; + ptlrpc_req_finished(req); + RETURN(rc); } /** @@ -521,7 +571,6 @@ int ll_xattr_cache_get(struct inode *inode, size_t size, __u64 valid) { - struct lookup_intent oit = { .it_op = IT_GETXATTR }; struct ll_inode_info *lli = ll_i2info(inode); int rc = 0; @@ -530,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, LL_XATTR_NAME_ENCRYPTION_CONTEXT) != 0) && + !ll_xattr_cache_filled(lli)) { up_read(&lli->lli_xattrs_list_rwsem); - rc = ll_xattr_cache_refill(inode, &oit); + 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; @@ -554,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, @@ -564,6 +639,33 @@ int ll_xattr_cache_get(struct inode *inode, out: up_read(&lli->lli_xattrs_list_rwsem); - return rc; + RETURN(rc); } +/** + * Insert an xattr value into the cache. + * + * Add @name xattr with @buffer value and @size length for @inode. + * Init cache for @inode if necessary. + * + * \retval 0 success + * \retval < 0 from ll_xattr_cache_add(), except -EPROTO is ignored for + * LL_XATTR_NAME_ENCRYPTION_CONTEXT xattr + */ +int ll_xattr_cache_insert(struct inode *inode, + const char *name, + char *buffer, + size_t size) +{ + struct ll_inode_info *lli = ll_i2info(inode); + int rc; + + ENTRY; + + 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_write(&lli->lli_xattrs_list_rwsem); + RETURN(rc); +}