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 + -
显示快捷键?