genops.c

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

C
1,319
字号
        CDEBUG(D_IOCTL, "connect: client %s, cookie "LPX64"\n",               cluuid->uuid, conn->cookie);        RETURN(0);}EXPORT_SYMBOL(class_connect);/* This function removes two references from the export: one for the * hash entry and one for the export pointer passed in.  The export * pointer passed to this function is destroyed should not be used * again. */int class_disconnect(struct obd_export *export){        int already_disconnected;        ENTRY;        if (export == NULL) {                fixme();                CDEBUG(D_IOCTL, "attempting to free NULL export %p\n", export);                RETURN(-EINVAL);        }        spin_lock(&export->exp_lock);        already_disconnected = export->exp_disconnected;        export->exp_disconnected = 1;        if (!hlist_unhashed(&export->exp_nid_hash)) {                lustre_hash_delitem(export->exp_obd->obd_nid_hash_body,                                    &export->exp_connection->c_peer.nid, &export->exp_nid_hash);        }        spin_unlock(&export->exp_lock);        /* class_cleanup(), abort_recovery(), and class_fail_export()         * all end up in here, and if any of them race we shouldn't         * call extra class_export_puts(). */        if (already_disconnected)                RETURN(0);        CDEBUG(D_IOCTL, "disconnect: cookie "LPX64"\n",               export->exp_handle.h_cookie);        class_unlink_export(export);        class_export_put(export);        RETURN(0);}static void class_disconnect_export_list(struct list_head *list, int flags){        int rc;        struct lustre_handle fake_conn;        struct obd_export *fake_exp, *exp;        ENTRY;        /* It's possible that an export may disconnect itself, but         * nothing else will be added to this list. */        while (!list_empty(list)) {                exp = list_entry(list->next, struct obd_export, exp_obd_chain);                class_export_get(exp);                spin_lock(&exp->exp_lock);                exp->exp_flags = flags;                spin_unlock(&exp->exp_lock);                if (obd_uuid_equals(&exp->exp_client_uuid,                                    &exp->exp_obd->obd_uuid)) {                        CDEBUG(D_HA,                               "exp %p export uuid == obd uuid, don't discon\n",                               exp);                        /* Need to delete this now so we don't end up pointing                         * to work_list later when this export is cleaned up. */                        list_del_init(&exp->exp_obd_chain);                        class_export_put(exp);                        continue;                }                fake_conn.cookie = exp->exp_handle.h_cookie;                fake_exp = class_conn2export(&fake_conn);                if (!fake_exp) {                        class_export_put(exp);                        continue;                }                spin_lock(&fake_exp->exp_lock);                fake_exp->exp_flags = flags;                spin_unlock(&fake_exp->exp_lock);                CDEBUG(D_HA, "%s: disconnecting export at %s (%p), "                       "last request at %ld\n",                       exp->exp_obd->obd_name, obd_export_nid2str(exp),                       exp, exp->exp_last_request_time);                rc = obd_disconnect(fake_exp);                class_export_put(exp);        }        EXIT;}static inline int get_exp_flags_from_obd(struct obd_device *obd){        return ((obd->obd_fail ? OBD_OPT_FAILOVER : 0) |                (obd->obd_force ? OBD_OPT_FORCE : 0));}void class_disconnect_exports(struct obd_device *obd){        struct list_head work_list;        ENTRY;        /* Move all of the exports from obd_exports to a work list, en masse. */        spin_lock(&obd->obd_dev_lock);        list_add(&work_list, &obd->obd_exports);        list_del_init(&obd->obd_exports);        spin_unlock(&obd->obd_dev_lock);        CDEBUG(D_HA, "OBD device %d (%p) has exports, "               "disconnecting them\n", obd->obd_minor, obd);        class_disconnect_export_list(&work_list, get_exp_flags_from_obd(obd));        EXIT;}EXPORT_SYMBOL(class_disconnect_exports);/* Remove exports that have not completed recovery. */void class_disconnect_stale_exports(struct obd_device *obd){        struct list_head work_list;        struct list_head *pos, *n;        struct obd_export *exp;        int cnt = 0;        ENTRY;        CFS_INIT_LIST_HEAD(&work_list);        spin_lock(&obd->obd_dev_lock);        list_for_each_safe(pos, n, &obd->obd_exports) {                exp = list_entry(pos, struct obd_export, exp_obd_chain);                if (exp->exp_replay_needed) {                        list_del(&exp->exp_obd_chain);                        list_add(&exp->exp_obd_chain, &work_list);                        cnt++;                }        }        spin_unlock(&obd->obd_dev_lock);        CDEBUG(D_ERROR, "%s: disconnecting %d stale clients\n",               obd->obd_name, cnt);        class_disconnect_export_list(&work_list, get_exp_flags_from_obd(obd));        EXIT;}EXPORT_SYMBOL(class_disconnect_stale_exports);int oig_init(struct obd_io_group **oig_out){        struct obd_io_group *oig;        ENTRY;        OBD_ALLOC(oig, sizeof(*oig));        if (oig == NULL)                RETURN(-ENOMEM);        spin_lock_init(&oig->oig_lock);        oig->oig_rc = 0;        oig->oig_pending = 0;        atomic_set(&oig->oig_refcount, 1);        cfs_waitq_init(&oig->oig_waitq);        CFS_INIT_LIST_HEAD(&oig->oig_occ_list);        *oig_out = oig;        RETURN(0);};EXPORT_SYMBOL(oig_init);static inline void oig_grab(struct obd_io_group *oig){        atomic_inc(&oig->oig_refcount);}void oig_release(struct obd_io_group *oig){        if (atomic_dec_and_test(&oig->oig_refcount))                OBD_FREE(oig, sizeof(*oig));}EXPORT_SYMBOL(oig_release);int oig_add_one(struct obd_io_group *oig, struct oig_callback_context *occ){        int rc = 0;        CDEBUG(D_CACHE, "oig %p ready to roll\n", oig);        spin_lock(&oig->oig_lock);        if (oig->oig_rc) {                rc = oig->oig_rc;        } else {                oig->oig_pending++;                if (occ != NULL)                        list_add_tail(&occ->occ_oig_item, &oig->oig_occ_list);        }        spin_unlock(&oig->oig_lock);        oig_grab(oig);        return rc;}EXPORT_SYMBOL(oig_add_one);void oig_complete_one(struct obd_io_group *oig,                      struct oig_callback_context *occ, int rc){        cfs_waitq_t *wake = NULL;        int old_rc;        spin_lock(&oig->oig_lock);        if (occ != NULL)                list_del_init(&occ->occ_oig_item);        old_rc = oig->oig_rc;        if (oig->oig_rc == 0 && rc != 0)                oig->oig_rc = rc;        if (--oig->oig_pending <= 0)                wake = &oig->oig_waitq;        spin_unlock(&oig->oig_lock);        CDEBUG(D_CACHE, "oig %p completed, rc %d -> %d via %d, %d now "                        "pending (racey)\n", oig, old_rc, oig->oig_rc, rc,                        oig->oig_pending);        if (wake)                cfs_waitq_signal(wake);        oig_release(oig);}EXPORT_SYMBOL(oig_complete_one);static int oig_done(struct obd_io_group *oig){        int rc = 0;        spin_lock(&oig->oig_lock);        if (oig->oig_pending <= 0)                rc = 1;        spin_unlock(&oig->oig_lock);        return rc;}static void interrupted_oig(void *data){        struct obd_io_group *oig = data;        struct oig_callback_context *occ;        spin_lock(&oig->oig_lock);        /* We need to restart the processing each time we drop the lock, as         * it is possible other threads called oig_complete_one() to remove         * an entry elsewhere in the list while we dropped lock.  We need to         * drop the lock because osc_ap_completion() calls oig_complete_one()         * which re-gets this lock ;-) as well as a lock ordering issue. */restart:        list_for_each_entry(occ, &oig->oig_occ_list, occ_oig_item) {                if (occ->interrupted)                        continue;                occ->interrupted = 1;                spin_unlock(&oig->oig_lock);                occ->occ_interrupted(occ);                spin_lock(&oig->oig_lock);                goto restart;        }        spin_unlock(&oig->oig_lock);}int oig_wait(struct obd_io_group *oig){        struct l_wait_info lwi = LWI_INTR(interrupted_oig, oig);        int rc;        CDEBUG(D_CACHE, "waiting for oig %p\n", oig);        do {                rc = l_wait_event(oig->oig_waitq, oig_done(oig), &lwi);                LASSERTF(rc == 0 || rc == -EINTR, "rc: %d\n", rc);                /* we can't continue until the oig has emptied and stopped                 * referencing state that the caller will free upon return */                if (rc == -EINTR)                        lwi = (struct l_wait_info){ 0, };        } while (rc == -EINTR);        LASSERTF(oig->oig_pending == 0,                 "exiting oig_wait(oig = %p) with %d pending\n", oig,                 oig->oig_pending);        CDEBUG(D_CACHE, "done waiting on oig %p rc %d\n", oig, oig->oig_rc);        return oig->oig_rc;}EXPORT_SYMBOL(oig_wait);void class_fail_export(struct obd_export *exp){        int rc, already_failed;        spin_lock(&exp->exp_lock);        already_failed = exp->exp_failed;        exp->exp_failed = 1;        spin_unlock(&exp->exp_lock);        if (already_failed) {                CDEBUG(D_HA, "disconnecting dead export %p/%s; skipping\n",                       exp, exp->exp_client_uuid.uuid);                return;        }        CDEBUG(D_HA, "disconnecting export %p/%s\n",               exp, exp->exp_client_uuid.uuid);        if (obd_dump_on_timeout)                libcfs_debug_dumplog();        /* Most callers into obd_disconnect are removing their own reference         * (request, for example) in addition to the one from the hash table.         * We don't have such a reference here, so make one. */        class_export_get(exp);        rc = obd_disconnect(exp);        if (rc)                CERROR("disconnecting export %p failed: %d\n", exp, rc);        else                CDEBUG(D_HA, "disconnected export %p/%s\n",                       exp, exp->exp_client_uuid.uuid);}EXPORT_SYMBOL(class_fail_export);char *obd_export_nid2str(struct obd_export *exp){        if (exp->exp_connection != NULL)                return libcfs_nid2str(exp->exp_connection->c_peer.nid);                return "(no nid)";}EXPORT_SYMBOL(obd_export_nid2str);int obd_export_evict_by_nid(struct obd_device *obd, char *nid){        struct obd_export *doomed_exp = NULL;        int exports_evicted = 0;        lnet_nid_t nid_key = libcfs_str2nid(nid);        do {                doomed_exp = lustre_hash_get_object_by_key(obd->obd_nid_hash_body,                                                           &nid_key);                if (doomed_exp == NULL)                        break;                LASSERTF(doomed_exp->exp_connection->c_peer.nid == nid_key,                         "nid %s found, wanted nid %s, requested nid %s\n",                         obd_export_nid2str(doomed_exp),                         libcfs_nid2str(nid_key), nid);                        exports_evicted++;                CDEBUG(D_HA, "%s: evict NID '%s' (%s) #%d at adminstrative request\n",                       obd->obd_name, nid, doomed_exp->exp_client_uuid.uuid,                       exports_evicted);                class_fail_export(doomed_exp);                class_export_put(doomed_exp);        } while (1);        if (!exports_evicted)                CDEBUG(D_HA,"%s: can't disconnect NID '%s': no exports found\n",                       obd->obd_name, nid);        return exports_evicted;}EXPORT_SYMBOL(obd_export_evict_by_nid);int obd_export_evict_by_uuid(struct obd_device *obd, char *uuid){        struct obd_export *doomed_exp = NULL;        struct obd_uuid doomed;        int exports_evicted = 0;        obd_str2uuid(&doomed, uuid);        if(obd_uuid_equals(&doomed, &obd->obd_uuid)) {                CERROR("%s: can't evict myself\n", obd->obd_name);                return exports_evicted;        }        doomed_exp = lustre_hash_get_object_by_key(obd->obd_uuid_hash_body,                                                    &doomed);        if (doomed_exp == NULL) {                CERROR("%s: can't disconnect %s: no exports found\n",                       obd->obd_name, uuid);        } else {                CWARN("%s: evicting %s at adminstrative request\n",                       obd->obd_name, doomed_exp->exp_client_uuid.uuid);                class_fail_export(doomed_exp);                class_export_put(doomed_exp);                exports_evicted++;        }        return exports_evicted;}EXPORT_SYMBOL(obd_export_evict_by_uuid);void obd_zombie_impexp_cull(void) {        struct obd_import *import;        struct obd_export *export;                do {                spin_lock (&obd_zombie_impexp_lock);                import = NULL;                if (!list_empty(&obd_zombie_imports)) {                        import = list_entry(obd_zombie_imports.next,                                            struct obd_import,                                            imp_zombie_chain);                        list_del(&import->imp_zombie_chain);                }                                export = NULL;                if (!list_empty(&obd_zombie_exports)) {                        export = list_entry(obd_zombie_exports.next,                                            struct obd_export,                                            exp_obd_chain);                        list_del_init(&export->exp_obd_chain);                }                spin_unlock(&obd_zombie_impexp_lock);                                if (import != NULL)                        class_import_destroy(import);                if (export != NULL)                        class_export_destroy(export);        } while (import != NULL || export != NULL);}EXPORT_SYMBOL(obd_zombie_impexp_cull);void obd_zombie_impexp_init(void){        CFS_INIT_LIST_HEAD(&obd_zombie_imports);        CFS_INIT_LIST_HEAD(&obd_zombie_exports);        spin_lock_init(&obd_zombie_impexp_lock);}

⌨️ 快捷键说明

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