upcall_cache.c

来自「lustre 1.6.5 source code」· C语言 代码 · 共 519 行 · 第 1/2 页

C
519
字号
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- * vim:expandtab:shiftwidth=8:tabstop=8: * *  Supplementary groups cache. * *  Copyright (c) 2004 Cluster File Systems, Inc. * *   This file is part of Lustre, http://www.lustre.org. * *   Lustre is free software; you can redistribute it and/or *   modify it under the terms of version 2 of the GNU General Public *   License as published by the Free Software Foundation. * *   Lustre is distributed in the hope that it will be useful, *   but WITHOUT ANY WARRANTY; without even the implied warranty of *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *   GNU General Public License for more details. * *   You should have received a copy of the GNU General Public License *   along with Lustre; if not, write to the Free Software *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#define DEBUG_SUBSYSTEM S_SEC#ifndef AUTOCONF_INCLUDED#include <linux/config.h>#endif#include <linux/module.h>#include <linux/kernel.h>#include <linux/mm.h>#include <linux/kmod.h>#include <linux/string.h>#include <linux/stat.h>#include <linux/errno.h>#include <linux/version.h>#include <linux/unistd.h>#include <asm/system.h>#include <asm/uaccess.h>#include <linux/fs.h>#include <linux/stat.h>#include <asm/uaccess.h>#include <linux/slab.h>#include <obd_support.h>#include <lustre_lib.h>#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,4)struct group_info *groups_alloc(int ngroups){        struct group_info *ginfo;        LASSERT(ngroups <= NGROUPS_SMALL);        OBD_ALLOC(ginfo, sizeof(*ginfo) + 1 * sizeof(gid_t *));        if (!ginfo)                return NULL;        ginfo->ngroups = ngroups;        ginfo->nblocks = 1;        ginfo->blocks[0] = ginfo->small_block;        atomic_set(&ginfo->usage, 1);        return ginfo;}void groups_free(struct group_info *ginfo){        LASSERT(ginfo->ngroups <= NGROUPS_SMALL);        LASSERT(ginfo->nblocks == 1);        LASSERT(ginfo->blocks[0] == ginfo->small_block);        OBD_FREE(ginfo, sizeof(*ginfo) + 1 * sizeof(gid_t *));}#endifstatic struct upcall_cache_entry *alloc_entry(__u64 key){        struct upcall_cache_entry *entry;        OBD_ALLOC(entry, sizeof(*entry));        if (!entry)                return NULL;        UC_CACHE_SET_NEW(entry);        INIT_LIST_HEAD(&entry->ue_hash);        entry->ue_key = key;        atomic_set(&entry->ue_refcount, 0);        init_waitqueue_head(&entry->ue_waitq);        return entry;}/* protected by hash lock */static void free_entry(struct upcall_cache_entry *entry){        if (entry->ue_group_info)                groups_free(entry->ue_group_info);        list_del(&entry->ue_hash);        CDEBUG(D_OTHER, "destroy cache entry %p for key "LPU64"\n",               entry, entry->ue_key);        OBD_FREE(entry, sizeof(*entry));}static void get_entry(struct upcall_cache_entry *entry){        atomic_inc(&entry->ue_refcount);}static void put_entry(struct upcall_cache_entry *entry){        if (atomic_dec_and_test(&entry->ue_refcount) &&            (UC_CACHE_IS_INVALID(entry) || UC_CACHE_IS_EXPIRED(entry))) {                free_entry(entry);        }}static int check_unlink_entry(struct upcall_cache_entry *entry){        if (UC_CACHE_IS_VALID(entry) &&            time_before(jiffies, entry->ue_expire))                return 0;        if (UC_CACHE_IS_ACQUIRING(entry)) {                if (time_before(jiffies, entry->ue_acquire_expire))                        return 0;                UC_CACHE_SET_EXPIRED(entry);                wake_up_all(&entry->ue_waitq);        } else if (!UC_CACHE_IS_INVALID(entry)) {                UC_CACHE_SET_EXPIRED(entry);        }        list_del_init(&entry->ue_hash);        if (!atomic_read(&entry->ue_refcount))                free_entry(entry);        return 1;}static int refresh_entry(struct upcall_cache *hash,                         struct upcall_cache_entry *entry){        char *argv[4];        char *envp[3];        char keystr[16];        int rc;        ENTRY;        snprintf(keystr, 16, LPU64, entry->ue_key);        CDEBUG(D_INFO, "The groups upcall is: %s \n", hash->uc_upcall);        argv[0] = hash->uc_upcall;        argv[1] = hash->uc_name;        argv[2] = keystr;        argv[3] = NULL;        envp[0] = "HOME=/";        envp[1] = "PATH=/sbin:/usr/sbin";        envp[2] = NULL;        rc = USERMODEHELPER(argv[0], argv, envp);        if (rc < 0) {                CERROR("%s: error invoking getgroups upcall %s %s %s: rc %d; "                       "check /proc/fs/lustre/mds/%s/group_upcall\n",                       hash->uc_name, argv[0], argv[1], argv[2], rc, argv[1]);        } else {                CDEBUG(D_HA, "%s: invoked upcall %s %s %s\n", hash->uc_name,                       argv[0], argv[1], argv[2]);                rc = 0;        }        RETURN(rc);}static int entry_set_group_info(struct upcall_cache_entry *entry, __u32 primary,                                __u32 ngroups, __u32 *groups){        struct group_info *ginfo;        int i, j;        ENTRY;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,4)        if (ngroups > NGROUPS)                ngroups = NGROUPS;#endif        if (ngroups > NGROUPS_MAX) {                CERROR("using first %d supplementary groups for uid "LPU64"\n",                       NGROUPS_MAX, entry->ue_key);                ngroups = NGROUPS_MAX;        }        ginfo = groups_alloc(ngroups);        if (!ginfo) {                CERROR("uid "LPU64" update can't alloc ginfo for %d groups\n",                       entry->ue_key, ngroups);                RETURN(-ENOMEM);        }        entry->ue_group_info = ginfo;        entry->ue_primary = primary;        for (i = 0; i < ginfo->nblocks; i++) {                int cp_count = min(NGROUPS_PER_BLOCK, (int)ngroups);                int off = i * NGROUPS_PER_BLOCK;                for (j = 0; j < cp_count; j++)                        ginfo->blocks[i][j] = groups[off + j];                ngroups -= cp_count;        }        RETURN(0);}struct upcall_cache_entry *upcall_cache_get_entry(struct upcall_cache *hash,                                                  __u64 key, __u32 primary,                                                  __u32 ngroups, __u32 *groups){        struct upcall_cache_entry *entry = NULL, *new = NULL, *next;        struct list_head *head;        wait_queue_t wait;        int rc, found;        ENTRY;        LASSERT(hash);        if (strcmp(hash->uc_upcall, "NONE") == 0) {                new = alloc_entry(key);                if (!new) {                        CERROR("fail to alloc entry\n");                        RETURN(NULL);                }                get_entry(new);                /* We have to sort the groups for 2.6 kernels */                LASSERT(ngroups <= 2);                if (ngroups == 2 && groups[1] == -1)                        ngroups--;#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,4)                /* 2.6 needs groups array sorted */                if (ngroups == 2 && groups[0] > groups[1]) {                        __u32 tmp = groups[1];                        groups[1] = groups[0];                        groups[0] = tmp;                }#endif                if (ngroups > 0 && groups[0] == -1) {                        groups[0] = groups[1];                        ngroups--;                }                rc = entry_set_group_info(new, primary, ngroups, groups);                /* We can't cache this entry as it only has a subset of                 * the user's groups, as sent in suppgid1, suppgid2. */                UC_CACHE_SET_EXPIRED(new);                RETURN(new);        }        head = &hash->uc_hashtable[UC_CACHE_HASH_INDEX(key)];find_again:        found = 0;        spin_lock(&hash->uc_lock);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?