X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Fobdclass%2Fcapa.c;h=3943d55c3f66b351841febaf2c5e529532a1ae0f;hb=b11d0d89b22e8409cac12129a80044f84df0023c;hp=18d431156f505b40f77b832a43c70e7bd45bef4c;hpb=56a32318ff0509aaddb69466b4f17069c3f207b6;p=fs%2Flustre-release.git diff --git a/lustre/obdclass/capa.c b/lustre/obdclass/capa.c index 18d4311..3943d55 100644 --- a/lustre/obdclass/capa.c +++ b/lustre/obdclass/capa.c @@ -2,9 +2,9 @@ * vim:expandtab:shiftwidth=8:tabstop=8: * * lustre/obdclass/capa.c - * Lustre Capability Cache Management + * Lustre Capability Hash Management * - * Copyright (c) 2001-2003 Cluster File Systems, Inc. + * Copyright (c) 2005 Cluster File Systems, Inc. * Author: Lai Siyao * * This file is part of Lustre, http://www.lustre.org. @@ -36,393 +36,255 @@ #include #include -#include -#include -#include -#include +#include +#include +#include #else #include #endif #include -#include +#include -kmem_cache_t *capa_cachep = NULL; +#define NR_CAPAHASH 32 +#define CAPA_HASH_SIZE 3000 /* for MDS & OSS */ -/* capa_lock protect capa hash, list and content. */ +cfs_mem_cache_t *capa_cachep = NULL; + +#ifdef __KERNEL__ +/* lock for capa hash/capa_list/fo_capa_keys */ spinlock_t capa_lock = SPIN_LOCK_UNLOCKED; -struct hlist_head *capa_hash; -struct list_head capa_list[3]; -static int capa_count[3] = { 0 }; -/* TODO: mdc and llite all need this, so define it here. - * in the future it will be moved to ll_sb_info to support multi- - * mount point */ -struct timer_list ll_capa_timer; +struct list_head capa_list[CAPA_SITE_MAX]; -EXPORT_SYMBOL(capa_lock); -EXPORT_SYMBOL(capa_hash); +static struct capa_hmac_alg capa_hmac_algs[] = { + DEF_CAPA_HMAC_ALG("sha1", SHA1, 20, 20), +}; +#endif +/* capa count */ +int capa_count[CAPA_SITE_MAX] = { 0, }; + +EXPORT_SYMBOL(capa_cachep); EXPORT_SYMBOL(capa_list); -EXPORT_SYMBOL(ll_capa_timer); +EXPORT_SYMBOL(capa_lock); +EXPORT_SYMBOL(capa_count); -static inline int const -capa_hashfn(unsigned int uid, int capa_op, __u64 mdsid, unsigned long ino) +struct hlist_head *init_capa_hash(void) { - return (ino ^ uid) * (unsigned long)capa_op * (unsigned long)mdsid % - NR_CAPAHASH; -} + struct hlist_head *hash; + int nr_hash, i; -int capa_op(int flags) -{ - if (flags & (FMODE_WRITE|MDS_OPEN_TRUNC)) - return MAY_WRITE; - else if (flags & FMODE_READ) - return MAY_READ; + OBD_ALLOC(hash, PAGE_SIZE); + if (!hash) + return NULL; - LBUG(); /* should be either MAY_READ or MAY_WRITE */ - return 0; + nr_hash = PAGE_SIZE / sizeof(struct hlist_head); + LASSERT(nr_hash > NR_CAPAHASH); + + for (i = 0; i < NR_CAPAHASH; i++) + INIT_HLIST_HEAD(hash + i); + return hash; } -static struct obd_capa * -find_capa(struct hlist_head *head, uid_t uid, int capa_op, __u64 mdsid, - unsigned long ino, int type) +#ifdef __KERNEL__ +static inline int capa_on_server(struct obd_capa *ocapa) { - struct hlist_node *pos; - struct obd_capa *ocapa; - ENTRY; - - CDEBUG(D_CACHE, "find_capa uid %u op %u mdsid "LPU64" ino %lu " - "type %d\n", uid, capa_op, mdsid, ino, type); - - hlist_for_each_entry(ocapa, pos, head, c_hash) { - if (ocapa->c_capa.lc_uid != uid) - continue; - if (ocapa->c_capa.lc_op != capa_op) - continue; - if (ocapa->c_capa.lc_mdsid != mdsid) - continue; - if (ocapa->c_capa.lc_ino != ino) - continue; - if (ocapa->c_type != type) - continue; - RETURN(ocapa); - } - - RETURN(NULL); + return ocapa->c_site == CAPA_SITE_SERVER; } -inline void __capa_get(struct obd_capa *ocapa) +static inline void capa_delete(struct obd_capa *ocapa) { - atomic_inc(&ocapa->c_refc); + LASSERT(capa_on_server(ocapa)); + hlist_del(&ocapa->u.tgt.c_hash); + list_del(&ocapa->c_list); + capa_count[ocapa->c_site]--; + free_capa(ocapa); } -static struct obd_capa * -find_capa_locked(struct hlist_head *head, uid_t uid, int capa_op, __u64 mdsid, - unsigned long ino, int type) +void cleanup_capa_hash(struct hlist_head *hash) { - struct obd_capa *ocapa; - ENTRY; + int i; + struct hlist_node *pos, *next; + struct obd_capa *oc; spin_lock(&capa_lock); - ocapa = find_capa(head, uid, capa_op, mdsid, ino, type); - if (ocapa) - __capa_get(ocapa); + for (i = 0; i < NR_CAPAHASH; i++) { + hlist_for_each_entry_safe(oc, pos, next, hash + i, u.tgt.c_hash) + capa_delete(oc); + } spin_unlock(&capa_lock); - RETURN(ocapa); + OBD_FREE(hash, PAGE_SIZE); } -static struct obd_capa *alloc_capa(void) +static inline int const capa_hashfn(struct lu_fid *fid) { - struct obd_capa *ocapa; - ENTRY; - - OBD_SLAB_ALLOC(ocapa, capa_cachep, SLAB_NOFS, sizeof(*ocapa)); - if (ocapa) { - INIT_HLIST_NODE(&ocapa->c_hash); - INIT_LIST_HEAD(&ocapa->c_list); - } - - RETURN(ocapa); + return (fid_oid(fid) ^ fid_ver(fid)) * + (unsigned long)(fid_seq(fid) + 1) % NR_CAPAHASH; } -static void destroy_capa(struct obd_capa *ocapa) +/* capa renewal time check is earlier than that on client, which is to prevent + * client renew right after obtaining it. */ +static inline int capa_is_to_expire(struct obd_capa *oc) { - OBD_SLAB_FREE(ocapa, capa_cachep, sizeof(*ocapa)); + return cfs_time_before(cfs_time_sub(oc->c_expiry, + cfs_time_seconds(oc->c_capa.lc_timeout)*2/3), + cfs_time_current()); } -int capa_cache_init(void) +static struct obd_capa *find_capa(struct lustre_capa *capa, + struct hlist_head *head, int alive) { - int nr_hash, i; - - OBD_ALLOC(capa_hash, PAGE_SIZE); - if (!capa_hash) - return -ENOMEM; + struct hlist_node *pos; + struct obd_capa *ocapa; + int len = alive ? offsetof(struct lustre_capa, lc_keyid):sizeof(*capa); - nr_hash = PAGE_SIZE / sizeof(struct hlist_head); - LASSERT(nr_hash > NR_CAPAHASH); + hlist_for_each_entry(ocapa, pos, head, u.tgt.c_hash) { + if (memcmp(&ocapa->c_capa, capa, len)) + continue; + /* don't return one that will expire soon in this case */ + if (alive && capa_is_to_expire(ocapa)) + continue; - for (i = 0; i < NR_CAPAHASH; i++) - INIT_HLIST_HEAD(capa_hash + i); + LASSERT(capa_on_server(ocapa)); - for (i = 0; i < 3; i++) - INIT_LIST_HEAD(&capa_list[i]); + DEBUG_CAPA(D_SEC, &ocapa->c_capa, "found"); + return ocapa; + } - return 0; + return NULL; } -void capa_cache_cleanup(void) +#define LRU_CAPA_DELETE_COUNT 12 +static inline void capa_delete_lru(struct list_head *head) { struct obd_capa *ocapa; - struct hlist_node *pos, *n; - - hlist_for_each_entry_safe(ocapa, pos, n, capa_hash, c_hash) { - hlist_del(&ocapa->c_hash); - list_del(&ocapa->c_list); - OBD_FREE(ocapa, sizeof(*ocapa)); - } -} - + struct list_head *node = head->next; + int count = 0; + + /* free LRU_CAPA_DELETE_COUNT unused capa from head */ + while (count++ < LRU_CAPA_DELETE_COUNT) { + ocapa = list_entry(node, struct obd_capa, c_list); + node = node->next; + if (atomic_read(&ocapa->c_refc)) + continue; -static inline void list_add_capa(struct obd_capa *ocapa, struct list_head *head) -{ - struct obd_capa *tmp; - - /* XXX: capa is sorted in client, this could be optimized */ - if (ocapa->c_type == CLIENT_CAPA) { - list_for_each_entry_reverse(tmp, head, c_list) { - if (ocapa->c_capa.lc_expiry > tmp->c_capa.lc_expiry) { - list_add(&ocapa->c_list, &tmp->c_list); - return; - } - } + DEBUG_CAPA(D_SEC, &ocapa->c_capa, "free lru"); + capa_delete(ocapa); } - - list_add_tail(&ocapa->c_list, head); } -#define DEBUG_CAPA(level, ocapa, fmt, args...) \ -do { \ -CDEBUG(level, fmt " capa@%p uid %u op %u ino "LPU64" mdsid %d keyid %d " \ - "expiry "LPU64" flags %u type %d\n", \ - ##args, ocapa, ocapa->c_capa.lc_uid, ocapa->c_capa.lc_op, \ - ocapa->c_capa.lc_ino, ocapa->c_capa.lc_mdsid, ocapa->c_capa.lc_keyid, \ - ocapa->c_capa.lc_expiry, ocapa->c_capa.lc_flags, ocapa->c_type); \ -} while (0) - -static struct obd_capa * -get_new_capa_locked(struct hlist_head *head, uid_t uid, int capa_op,__u64 mdsid, - unsigned long ino, int type, struct lustre_capa *capa, - struct inode *inode, struct lustre_handle *handle) +/* add or update */ +struct obd_capa *capa_add(struct hlist_head *hash, struct lustre_capa *capa) { - struct obd_capa *ocapa, *old; - ENTRY; + struct hlist_head *head = hash + capa_hashfn(&capa->lc_fid); + struct obd_capa *ocapa, *old = NULL; + struct list_head *list = &capa_list[CAPA_SITE_SERVER]; - ocapa = alloc_capa(); + ocapa = alloc_capa(CAPA_SITE_SERVER); if (!ocapa) - RETURN(NULL); + return NULL; spin_lock(&capa_lock); - old = find_capa(head, uid, capa_op, mdsid, ino, type); + old = find_capa(capa, head, 0); if (!old) { - memcpy(&ocapa->c_capa, capa, sizeof(*capa)); - ocapa->c_type = type; - if (type == CLIENT_CAPA) { - LASSERT(inode); -#ifdef __KERNEL__ - igrab(inode); -#endif - ocapa->c_inode = inode; - memcpy(&ocapa->c_handle, handle, sizeof(*handle)); - } - list_add_capa(ocapa, &capa_list[type]); - hlist_add_head(&ocapa->c_hash, capa_hash); - capa_count[type]++; - DEBUG_CAPA(D_CACHE, ocapa, "get_new_capa_locked"); - __capa_get(ocapa); - if (type != CLIENT_CAPA && capa_count[type] > CAPA_CACHE_SIZE) { - struct list_head *node = capa_list[type].next; - struct obd_capa *tcapa; - int count = 0; - - /* free 12 unused capa from head */ - while (node->next != &capa_list[type] && count < 12) { - tcapa = list_entry(node, struct obd_capa, c_list); - node = node->next; - if (atomic_read(&tcapa->c_refc) > 0) - continue; - list_del(&tcapa->c_list); - destroy_capa(tcapa); - count++; - } - } + ocapa->c_capa = *capa; + set_capa_expiry(ocapa); + hlist_add_head(&ocapa->u.tgt.c_hash, head); + list_add_tail(&ocapa->c_list, list); + capa_count[CAPA_SITE_SERVER]++; + capa_get(ocapa); + + if (capa_count[CAPA_SITE_SERVER] > CAPA_HASH_SIZE) + capa_delete_lru(list); + + DEBUG_CAPA(D_SEC, &ocapa->c_capa, "new"); spin_unlock(&capa_lock); - RETURN(ocapa); + return ocapa; } - __capa_get(old); + capa_get(old); spin_unlock(&capa_lock); - destroy_capa(ocapa); - ocapa = old; - RETURN(ocapa); -} - -static struct obd_capa * -capa_get_locked(uid_t uid, int capa_op,__u64 mdsid, unsigned long ino, - int type, struct lustre_capa *capa, struct inode *inode, - struct lustre_handle *handle) -{ - struct hlist_head *head = capa_hash + - capa_hashfn(uid, capa_op, mdsid, ino); - struct obd_capa *ocapa; - ENTRY; - - ocapa = find_capa_locked(head, uid, capa_op, mdsid, ino, type); - if (ocapa) - RETURN(ocapa); - - if (capa) - ocapa = get_new_capa_locked(head, uid, capa_op, mdsid, ino, - type, capa, inode, handle); - RETURN(ocapa); -} - -struct obd_capa * -capa_get(uid_t uid, int capa_op, __u64 mdsid, unsigned long ino, int type, - struct lustre_capa *capa, struct inode *inode, - struct lustre_handle *handle) -{ - return capa_get_locked(uid, capa_op, mdsid, ino, type, capa, inode, - handle); -} - -static void __capa_put(struct obd_capa *ocapa, int type) -{ - hlist_del_init(&ocapa->c_hash); - list_del_init(&ocapa->c_list); - capa_count[type]--; -} -void capa_put(struct obd_capa *ocapa, int type) -{ - ENTRY; + DEBUG_CAPA(D_SEC, &old->c_capa, "update"); - if (ocapa) { - if (atomic_dec_and_lock(&ocapa->c_refc, &capa_lock)) { - if (type == CLIENT_CAPA) { -#ifdef __KERNEL__ - iput(ocapa->c_inode); -#endif - __capa_put(ocapa, type); - destroy_capa(ocapa); - } - spin_unlock(&capa_lock); - } - } - - EXIT; -} - -static inline void __update_capa(struct obd_capa *ocapa, struct lustre_capa *capa) -{ - memcpy(&ocapa->c_capa, capa, sizeof(*capa)); + free_capa(ocapa); + return old; } -static int update_capa_locked(struct lustre_capa *capa, int type) +struct obd_capa *capa_lookup(struct hlist_head *hash, struct lustre_capa *capa, + int alive) { - uid_t uid = capa->lc_uid; - int capa_op = capa->lc_op; - __u64 mdsid = capa->lc_mdsid; - unsigned long ino = capa->lc_ino; - struct hlist_head *head = capa_hash + - capa_hashfn(uid, capa_op, mdsid, ino); struct obd_capa *ocapa; - ENTRY; spin_lock(&capa_lock); - ocapa = find_capa(head, uid, capa_op, mdsid, ino, type); - if (ocapa) - __update_capa(ocapa, capa); + ocapa = find_capa(capa, hash + capa_hashfn(&capa->lc_fid), alive); + if (ocapa) { + list_move_tail(&ocapa->c_list, &capa_list[CAPA_SITE_SERVER]); + capa_get(ocapa); + } spin_unlock(&capa_lock); - if (ocapa == NULL && type == MDS_CAPA) - ocapa = get_new_capa_locked(head, uid, capa_op, mdsid, ino, type, - capa, NULL, NULL); - - RETURN(ocapa ? 0 : -ENOENT); -} - -int capa_renew(struct lustre_capa *capa, int type) -{ - return update_capa_locked(capa, type); + return ocapa; } -void capa_hmac(struct crypto_tfm *tfm, __u8 *key, struct lustre_capa *capa) +int capa_hmac(__u8 *hmac, struct lustre_capa *capa, __u8 *key) { - int keylen = CAPA_KEY_LEN; + struct crypto_tfm *tfm; + struct capa_hmac_alg *alg; + int keylen; struct scatterlist sl = { .page = virt_to_page(capa), .offset = (unsigned long)(capa) % PAGE_SIZE, - .length = sizeof(struct lustre_capa_data), + .length = offsetof(struct lustre_capa, lc_hmac), }; - ENTRY; - LASSERT(tfm); - crypto_hmac(tfm, key, &keylen, &sl, 1, capa->lc_hmac); - EXIT; -} + if (capa_alg(capa) != CAPA_HMAC_ALG_SHA1) { + CERROR("unknown capability hmac algorithm!\n"); + return -EFAULT; + } -void capa_dup(void *dst, struct obd_capa *ocapa) -{ - spin_lock(&capa_lock); - memcpy(dst, &ocapa->c_capa, sizeof(ocapa->c_capa)); - spin_unlock(&capa_lock); -} + alg = &capa_hmac_algs[capa_alg(capa)]; -void capa_dup2(void *dst, struct lustre_capa *capa) -{ - spin_lock(&capa_lock); - memcpy(dst, capa, sizeof(*capa)); - spin_unlock(&capa_lock); -} + tfm = crypto_alloc_tfm(alg->ha_name, 0); + if (!tfm) { + CERROR("crypto_alloc_tfm failed, check whether your kernel" + "has crypto support!\n"); + return -ENOMEM; + } + keylen = alg->ha_keylen; -int capa_expired(struct lustre_capa *capa) -{ - struct timeval tv; + crypto_hmac(tfm, key, &keylen, &sl, 1, hmac); + crypto_free_tfm(tfm); - do_gettimeofday(&tv); - return (capa->lc_expiry < tv.tv_sec) ? 1 : 0; + return 0; } +#endif -int __capa_is_to_expire(struct obd_capa *ocapa) +void capa_cpy(void *capa, struct obd_capa *ocapa) { - struct timeval tv; - int pre_expiry = capa_pre_expiry(&ocapa->c_capa); - - do_gettimeofday(&tv); - return (ocapa->c_capa.lc_expiry - pre_expiry < tv.tv_sec)? 1 : 0; + spin_lock(&ocapa->c_lock); + *(struct lustre_capa *)capa = ocapa->c_capa; + spin_unlock(&ocapa->c_lock); } -int capa_is_to_expire(struct obd_capa *ocapa) +char *dump_capa_content(char *buf, char *key, int len) { - int rc; + int i, n = 0; - spin_lock(&capa_lock); - rc = __capa_is_to_expire(ocapa); - spin_unlock(&capa_lock); - - return rc; + for (i = 0; i < len; i++) + n += sprintf(buf + n, "%02x", (unsigned char) key[i]); + return buf; } -EXPORT_SYMBOL(capa_op); -EXPORT_SYMBOL(capa_get); -EXPORT_SYMBOL(capa_put); -EXPORT_SYMBOL(capa_renew); -EXPORT_SYMBOL(__capa_get); +EXPORT_SYMBOL(init_capa_hash); +EXPORT_SYMBOL(cleanup_capa_hash); + +EXPORT_SYMBOL(capa_add); +EXPORT_SYMBOL(capa_lookup); + EXPORT_SYMBOL(capa_hmac); -EXPORT_SYMBOL(capa_dup); -EXPORT_SYMBOL(capa_dup2); -EXPORT_SYMBOL(capa_expired); -EXPORT_SYMBOL(__capa_is_to_expire); -EXPORT_SYMBOL(capa_is_to_expire); +EXPORT_SYMBOL(capa_cpy); + +EXPORT_SYMBOL(dump_capa_content);