void init_exception_processing (void) { tree tmp; /* void std::terminate (); */ push_namespace (std_identifier); tmp = build_function_type (void_type_node, void_list_node); terminate_node = build_cp_library_fn_ptr ("terminate", tmp); TREE_THIS_VOLATILE (terminate_node) = 1; TREE_NOTHROW (terminate_node) = 1; pop_namespace (); /* void __cxa_call_unexpected(void *); */ tmp = tree_cons (NULL_TREE, ptr_type_node, void_list_node); tmp = build_function_type (void_type_node, tmp); call_unexpected_node = push_throw_library_fn (get_identifier ("__cxa_call_unexpected"), tmp); eh_personality_libfunc = init_one_libfunc (USING_SJLJ_EXCEPTIONS ? "__gxx_personality_sj0" : "__gxx_personality_v0"); lang_eh_runtime_type = build_eh_type_type; lang_protect_cleanup_actions = &cp_protect_cleanup_actions; }
void init_rtti_processing () { push_namespace (std_identifier); type_info_type_node = xref_tag (class_type_node, get_identifier ("type_info"), 1); pop_namespace (); tinfo_decl_type = build_qualified_type (type_info_type_node, TYPE_QUAL_CONST); }
void init_rtti_processing () { push_namespace (std_identifier); type_info_type_node = xref_tag (class_type, get_identifier ("type_info"), /*attributes=*/NULL_TREE, 1); pop_namespace (); type_info_ptr_type = build_pointer_type (build_qualified_type (type_info_type_node, TYPE_QUAL_CONST)); create_tinfo_types (); }
void init_rtti_processing () { if (flag_honor_std) push_namespace (get_identifier ("std")); type_info_type_node = xref_tag (class_type_node, get_identifier ("type_info"), 1); if (flag_honor_std) pop_namespace (); tinfo_fn_id = get_identifier ("__tf"); tinfo_fn_type = build_function_type (build_reference_type (build_qualified_type (type_info_type_node, TYPE_QUAL_CONST)), void_list_node); }
void init_rtti_processing (void) { tree type_info_type; push_namespace (std_identifier); type_info_type = xref_tag (class_type, get_identifier ("type_info"), /*tag_scope=*/ts_current, false); pop_namespace (); const_type_info_type_node = build_qualified_type (type_info_type, TYPE_QUAL_CONST); type_info_ptr_type = build_pointer_type (const_type_info_type_node); unemitted_tinfo_decls = VEC_alloc (tree, 124); create_tinfo_types (); }
void init_exception_processing (void) { tree tmp; /* void std::terminate (); */ push_namespace (std_identifier); tmp = build_function_type_list (void_type_node, NULL_TREE); terminate_node = build_cp_library_fn_ptr ("terminate", tmp); TREE_THIS_VOLATILE (terminate_node) = 1; TREE_NOTHROW (terminate_node) = 1; pop_namespace (); /* void __cxa_call_unexpected(void *); */ tmp = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE); call_unexpected_node = push_throw_library_fn (get_identifier ("__cxa_call_unexpected"), tmp); }
void init_exception_processing (void) { tree tmp; /* void std::terminate (); */ push_namespace (std_identifier); tmp = build_function_type_list (void_type_node, NULL_TREE); terminate_fn = build_cp_library_fn_ptr ("terminate", tmp, ECF_NOTHROW | ECF_NORETURN | ECF_COLD); gcc_checking_assert (TREE_THIS_VOLATILE (terminate_fn) && TREE_NOTHROW (terminate_fn)); pop_namespace (); /* void __cxa_call_unexpected(void *); */ tmp = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE); call_unexpected_fn = push_throw_library_fn (get_identifier ("__cxa_call_unexpected"), tmp); }
void init_exception_processing () { /* void vtype () */ tree vtype = build_function_type (void_type_node, void_list_node); if (flag_honor_std) push_namespace (get_identifier ("std")); terminate_node = build_cp_library_fn_ptr ("terminate", vtype); TREE_THIS_VOLATILE (terminate_node) = 1; TREE_NOTHROW (terminate_node) = 1; if (flag_honor_std) pop_namespace (); set_exception_lang_code (EH_LANG_C_plus_plus); set_exception_version_code (1); /* If we use setjmp/longjmp EH, arrange for all cleanup actions to be protected with __terminate. */ protect_cleanup_actions_with_terminate = 1; }
/* called from the GMarkupParser */ static void start_element_handler (GMarkupParseContext *markup_context, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, gpointer user_data, GError **error) { XMPParseContext *context = user_data; gint attr; #ifdef DEBUG_XMP_PARSER g_print ("[%25s/%17s] %d <%s>\n", state_names[context->state], (context->saved_state == STATE_ERROR ? "-" : state_names[context->saved_state]), context->depth, element_name); #endif context->depth++; for (attr = 0; attribute_names[attr] != NULL; ++attr) if (g_str_has_prefix (attribute_names[attr], "xmlns:")) push_namespace (context, attribute_values[attr], attribute_names[attr] + sizeof ("xmlns:") - 1, error); switch (context->state) { case STATE_INSIDE_XPACKET: if (! strcmp (element_name, "x:xmpmeta") || ! strcmp (element_name, "x:xapmeta") || matches_with_prefix (element_name, context->xmp_prefix, context->xmp_prefix_len, "xmpmeta")) context->state = STATE_INSIDE_XMPMETA; else if (matches_rdf (element_name, context, "RDF")) { /* the x:xmpmeta element is missing, but this is allowed */ context->depth++; context->state = STATE_INSIDE_RDF; } else parse_error_element (context, error, "x:xmpmeta", FALSE, element_name); break; case STATE_INSIDE_XMPMETA: if (matches_rdf (element_name, context, "RDF")) context->state = STATE_INSIDE_RDF; else parse_error_element (context, error, "rdf:RDF", FALSE, element_name); break; case STATE_INSIDE_RDF: if (matches_rdf (element_name, context, "Description")) { XMLNameSpace *ns; gboolean about_seen = FALSE; context->state = STATE_INSIDE_TOPLEVEL_DESC; for (attr = 0; attribute_names[attr] != NULL; ++attr) { if (matches_rdf (attribute_names[attr], context, "about") || ! strcmp (attribute_names[attr], "about") /* old style */) about_seen = TRUE; else if (g_str_has_prefix (attribute_names[attr], "xmlns")) ; /* the namespace has already been pushed on the stack */ else { ns = new_property_in_ns (context, attribute_names[attr]); if (ns != NULL) { /* RDF shorthand notation */ add_property_value (context, XMP_PTYPE_TEXT, NULL, g_strdup (attribute_values[attr])); propagate_property (context, error); } else unknown_attribute (context, error, element_name, attribute_names[attr], attribute_values[attr]); } } if ((about_seen == FALSE) && (context->flags & XMP_FLAG_NO_MISSING_ABOUT)) parse_error (context, error, XMP_ERROR_MISSING_ABOUT, _("Required attribute rdf:about missing in <%s>"), element_name); } else parse_error_element (context, error, "rdf:Description", FALSE, element_name); break; case STATE_INSIDE_TOPLEVEL_DESC: { XMLNameSpace *ns; ns = new_property_in_ns (context, element_name); if (ns != NULL) { context->state = STATE_INSIDE_PROPERTY; for (attr = 0; attribute_names[attr] != NULL; ++attr) { if (matches_rdf (attribute_names[attr], context, "resource")) add_property_value (context, XMP_PTYPE_RESOURCE, NULL, g_strdup (attribute_values[attr])); else if (matches_rdf (attribute_names[attr], context, "parseType") && ! strcmp (attribute_values[attr], "Resource")) { context->saved_state = STATE_INSIDE_TOPLEVEL_DESC; context->state = STATE_INSIDE_STRUCT_ADD_NS; } else unknown_attribute (context, error, element_name, attribute_names[attr], attribute_values[attr]); } } else unknown_element (context, error, element_name); } break; case STATE_INSIDE_PROPERTY: if (matches_rdf (element_name, context, "Description")) { context->saved_state = context->state; context->state = STATE_INSIDE_QDESC; for (attr = 0; attribute_names[attr] != NULL; ++attr) { if (g_str_has_prefix (attribute_names[attr], "xmlns")) { /* this desc. is a structure, not a property qualifier */ context->state = STATE_INSIDE_STRUCT_ADD_NS; } else unknown_attribute (context, error, element_name, attribute_names[attr], attribute_values[attr]); } } else if (matches_rdf (element_name, context, "Alt")) context->state = STATE_INSIDE_ALT; else if (matches_rdf (element_name, context, "Bag")) context->state = STATE_INSIDE_BAG; else if (matches_rdf (element_name, context, "Seq")) context->state = STATE_INSIDE_SEQ; else unknown_element (context, error, element_name); break; case STATE_INSIDE_QDESC: if (matches_rdf (element_name, context, "value")) context->state = STATE_INSIDE_QDESC_VALUE; else context->state = STATE_INSIDE_QDESC_QUAL; break; case STATE_INSIDE_STRUCT_ADD_NS: case STATE_INSIDE_STRUCT: { GSList *ns_list; XMLNameSpace *ns; gboolean found; /* compare with namespaces in scope of current rdf:Description */ found = FALSE; ns_list = context->namespaces; while (ns_list != NULL) { ns = ns_list->data; if (ns->depth < context->depth - 2) break; if (has_ns_prefix (element_name, ns)) { if (context->state == STATE_INSIDE_STRUCT_ADD_NS) { /* first element - save the namespace prefix and uri */ add_property_value (context, XMP_PTYPE_STRUCTURE, g_strdup (ns->prefix), g_strdup (ns->uri)); } context->state = STATE_INSIDE_STRUCT_ELEMENT; add_property_value (context, XMP_PTYPE_STRUCTURE, g_strdup (element_name + ns->prefix_len + 1), NULL); found = TRUE; break; } ns_list = ns_list->next; } if (found == FALSE) unknown_element (context, error, element_name); } break; case STATE_INSIDE_ALT: if (matches_rdf (element_name, context, "li")) { context->state = STATE_INSIDE_ALT_LI; for (attr = 0; attribute_names[attr] != NULL; ++attr) { if (matches_rdf (attribute_names[attr], context, "parseType") && ! strcmp (attribute_values[attr], "Resource")) context->state = STATE_INSIDE_ALT_LI_RSC; else if (! strcmp (attribute_names[attr], "xml:lang")) add_property_value (context, XMP_PTYPE_ALT_LANG, g_strdup (attribute_values[attr]), NULL); else unknown_attribute (context, error, element_name, attribute_names[attr], attribute_values[attr]); } /* rdf:Alt is not an ordered list, but some broken XMP files use */ /* it instead of rdf:Seq. Workaround: if we did not find some */ /* attributes for the valid cases ALT_LANG or ALT_LI_RSC, then */ /* we pretend that we are parsing a real list (bug #343315). */ if ((context->property_type != XMP_PTYPE_ALT_LANG) && (context->state != STATE_INSIDE_ALT_LI_RSC)) add_property_value (context, XMP_PTYPE_ORDERED_LIST, NULL, NULL); } else parse_error_element (context, error, "rdf:li", FALSE, element_name); break; case STATE_INSIDE_BAG: if (matches_rdf (element_name, context, "li")) { context->state = STATE_INSIDE_BAG_LI; for (attr = 0; attribute_names[attr] != NULL; ++attr) { if (matches_rdf (attribute_names[attr], context, "parseType") && ! strcmp (attribute_values[attr], "Resource")) context->state = STATE_INSIDE_BAG_LI_RSC; else unknown_attribute (context, error, element_name, attribute_names[attr], attribute_values[attr]); } if (context->state != STATE_INSIDE_BAG_LI_RSC) add_property_value (context, XMP_PTYPE_UNORDERED_LIST, NULL, NULL); } else parse_error_element (context, error, "rdf:li", FALSE, element_name); break; case STATE_INSIDE_SEQ: if (matches_rdf (element_name, context, "li")) { context->state = STATE_INSIDE_SEQ_LI; for (attr = 0; attribute_names[attr] != NULL; ++attr) { if (matches_rdf (attribute_names[attr], context, "parseType") && ! strcmp (attribute_values[attr], "Resource")) context->state = STATE_INSIDE_SEQ_LI_RSC; else unknown_attribute (context, error, element_name, attribute_names[attr], attribute_values[attr]); } if (context->state != STATE_INSIDE_SEQ_LI_RSC) add_property_value (context, XMP_PTYPE_ORDERED_LIST, NULL, NULL); } else parse_error_element (context, error, "rdf:li", FALSE, element_name); break; case STATE_INSIDE_BAG_LI: case STATE_INSIDE_SEQ_LI: if (matches_rdf (element_name, context, "Description")) { context->saved_state = context->state; context->state = STATE_INSIDE_QDESC; } else parse_error_element (context, error, "rdf:Description", TRUE, element_name); break; case STATE_INSIDE_ALT_LI_RSC: /* store the thumbnail image and ignore the other elements */ if (! strcmp (element_name, "xapGImg:image")) /* FIXME */ context->state = STATE_INSIDE_ALT_LI_RSC_IMG; else if (! strcmp (element_name, "xapGImg:format") || ! strcmp (element_name, "xapGImg:width") || ! strcmp (element_name, "xapGImg:height")) ignore_element (context); else unknown_element (context, error, element_name); break; case STATE_INSIDE_BAG_LI_RSC: case STATE_INSIDE_SEQ_LI_RSC: unknown_element (context, error, element_name); break; case STATE_SKIPPING_UNKNOWN_ELEMENTS: case STATE_SKIPPING_IGNORED_ELEMENTS: break; default: parse_error (context, error, XMP_ERROR_PARSE, _("Nested elements (<%s>) are not allowed in this context"), element_name); break; } }
MarFS_Namespace* push_namespace(MarFS_Namespace* dummy, MarFS_Repo* repo) { if (! dummy) { LOG(LOG_ERR, "NULL namespace\n"); exit(1); } if (!IS_ROOT_NS(dummy) && !repo) { LOG(LOG_ERR, "NULL repo\n"); exit(1); } MarFS_Namespace* ns = (MarFS_Namespace*)malloc(sizeof(MarFS_Namespace)); if (! ns) { LOG(LOG_ERR, "alloc failed for '%s'\n", dummy->name); exit(1); } if (_ns_count >= _ns_max) { LOG(LOG_ERR, "No room for namespqace '%s'\n", dummy->name); exit(1); } LOG(LOG_INFO, "namespace: %-16s (repo: %s)\n", dummy->name, repo->name); *ns = *dummy; // use <repo> for everything. RangeList* ranges = (RangeList*) malloc(sizeof(RangeList)); *ranges = (RangeList) { .min = 0, .max = -1, .repo = repo }; ns->range_list = ranges; ns->iwrite_repo = repo; // these make it quicker to parse parts of the paths ns->name_len = strlen(ns->name); ns->mnt_path_len = strlen(ns->mnt_path); ns->md_path_len = strlen(ns->md_path); _ns[_ns_count++] = ns; return ns; } int validate_config(); // fwd-decl int read_config(const char* config_fname) { /// // config_fname is ignored, for now, but will eventually hold everythying /// if (! config_fname) /// config_fname = CONFIG_DEFAULT; /// /// MarFS_mnt_top = "/marfs"; /// MarFS_mnt_top_len = strlen(MarFS_mnt_top); _marfs_config.version_major = 0; _marfs_config.version_minor = 1; _marfs_config.mnt_top = "/marfs"; _marfs_config.mnt_top_len = strlen(_marfs_config.mnt_top); _marfs_config.name = "static"; _marfs_config.name_len = strlen(_marfs_config.name); // ........................................................................... // hard-coded repositories // // For sproxyd, repo.name must match an existing fast-cgi path // For S3, repo.name must match an existing bucket // // ........................................................................... _repo_max = 64; /* the number we're about to allocate */ _repo = (MarFS_Repo**) malloc(_repo_max * sizeof(MarFS_Repo*)); MarFS_Repo r_dummy; r_dummy = (MarFS_Repo) { .name = "proxy", // repo is sproxyd: this must match fastcgi-path .host = "10.135.0.%d:81", .host_offset = 30, .host_count = 4, .access_method = ACCESSMETHOD_SPROXYD, .chunk_size = (1024 * 1024 * 1028), /* max MarFS object (tune to match storage) */ .is_online = 1, .auth = AUTH_S3_AWS_MASTER, .compression = COMPRESS_NONE, .correction = CORRECT_NONE, .encryption = ENCRYPT_NONE, .latency_ms = (10 * 1000) }; push_repo(&r_dummy); // tiny, so detailed debugging (where we watch every char go over the line) // won't be overwhelming at the scale needed for Multi. r_dummy = (MarFS_Repo) { .name = "sproxyd_2k", // repo is sproxyd: this must match fastcgi-path .host = "10.135.0.21:81", .access_method = ACCESSMETHOD_SPROXYD, .chunk_size = (2048), /* i.e. max MarFS object (small for debugging) */ .is_online = 1, .auth = AUTH_S3_AWS_MASTER, .compression = COMPRESS_NONE, .correction = CORRECT_NONE, .encryption = ENCRYPT_NONE, .latency_ms = (10 * 1000), }; push_repo(&r_dummy); // For Brett, unit-testing, small enough to make it easy to create MULTIs r_dummy = (MarFS_Repo) { .name = "sproxyd_1M", // repo is sproxyd: this must match fastcgi-path .host = "10.135.0.22:81", .access_method = ACCESSMETHOD_SPROXYD, .chunk_size = (1024 * 1024 * 1), /* max MarFS object (tune to match storage) */ .is_online = 1, .auth = AUTH_S3_AWS_MASTER, .compression = COMPRESS_NONE, .correction = CORRECT_NONE, .encryption = ENCRYPT_NONE, .latency_ms = (10 * 1000) }; push_repo(&r_dummy); // @@@-HTTPS: For Brett, unit-testing, small enough to make it easy to create MULTIs r_dummy = (MarFS_Repo) { .name = "sproxyd_1M_https", // repo is sproxyd: this must match fastcgi-path .host = "10.135.0.22:444", .access_method = ACCESSMETHOD_SPROXYD, .chunk_size = (1024 * 1024 * 1), /* max MarFS object (tune to match storage) */ .is_online = 1, .auth = AUTH_S3_AWS_MASTER, .compression = COMPRESS_NONE, .correction = CORRECT_NONE, .encryption = ENCRYPT_NONE, .latency_ms = (10 * 1000) }; push_repo(&r_dummy); // S3 on EMC ECS r_dummy = (MarFS_Repo) { .name = "emc_s3", // repo is s3: this must match existing bucket .host = "10.140.0.15:9020", //"10.143.0.1:80", .access_method = ACCESSMETHOD_S3_EMC, .chunk_size = (1024 * 1024 * 256), /* max MarFS object (tune to match storage) */ .is_online = 1, .auth = AUTH_S3_AWS_MASTER, .compression = COMPRESS_NONE, .correction = CORRECT_NONE, .encryption = ENCRYPT_NONE, .latency_ms = (10 * 1000), }; push_repo(&r_dummy); #if TBD // semi-direct experiment r_dummy = (MarFS_Repo) { .name = "semi", .host = "/gpfs/marfs-gpfs/fuse/semi", //"10.143.0.1:443", .access_method = ACCESSMETHOD_SEMI_DIRECT, .chunk_size = (1024 * 1024 * 1), /* max MarFS object (tune to match storage) */ .is_online = 1, .auth = AUTH_NONE, .compression = COMPRESS_NONE, .correction = CORRECT_NONE, .encryption = ENCRYPT_NONE, .latency_ms = (10 * 1000), }; push_repo(&r_dummy); #endif // ........................................................................... // hard-coded namespaces // // For sproxyd, namespace.name must match an existing sproxyd driver-alias // For S3, namespace.name is just part of the object-id // // NOTE: Two namespaces should not have the same mount-suffix, because // Fuse will use this to look-up namespaces. Two NSes also // shouldn't have the same name, in case someone wants to lookup // by-name. // ........................................................................... _ns_max = 64; /* the number we're about to allocate */ _ns = (MarFS_Namespace**) malloc(_ns_max * sizeof(MarFS_Namespace*)); MarFS_Namespace ns_dummy; // Brett, unit ns_dummy = (MarFS_Namespace) { .name = "brettk", .mnt_path = "/brettk", // "<mnt_top>/brettk" comes here .md_path = "/gpfs/marfs-gpfs/brettk/mdfs", .fsinfo_path = "/gpfs/marfs-gpfs/brettk/fsinfo", /* a file */ .trash_md_path = "/gpfs/marfs-gpfs/trash", // NOT NEC IN THE SAME FILESET! .iperms = ( R_META | W_META | R_DATA | W_DATA | T_DATA | U_DATA ), .bperms = ( R_META | W_META | R_DATA | W_DATA | T_DATA | U_DATA ), .dirty_pack_percent = 0, .dirty_pack_threshold = 75, .quota_space = -1, /* no limit */ .quota_names = -1, /* no limit */ .shard_path = NULL, .shard_count = 0, }; push_namespace(&ns_dummy, find_repo_by_name("sproxyd_1M")); // @@@-HTTPS: Brett, unit ns_dummy = (MarFS_Namespace) { .name = "brettk_https", .mnt_path = "/brettk_https", // "<mnt_top>/brettk_https" comes here .md_path = "/gpfs/marfs-gpfs/brettk_https/mdfs", .fsinfo_path = "/gpfs/marfs-gpfs/brettk_https/fsinfo", /* a file */ .trash_md_path = "/gpfs/marfs-gpfs/trash", // NOT NEC IN THE SAME FILESET! .iperms = ( R_META | W_META | R_DATA | W_DATA | T_DATA | U_DATA ), .bperms = ( R_META | W_META | R_DATA | W_DATA | T_DATA | U_DATA ), .dirty_pack_percent = 0, .dirty_pack_threshold = 75, .quota_space = -1, /* no limit */ .quota_names = -1, /* no limit */ .shard_path = NULL, .shard_count = 0, }; push_namespace(&ns_dummy, find_repo_by_name("sproxyd_1M_https")); // jti testing ns_dummy = (MarFS_Namespace) { .name = "jti", .mnt_path = "/jti", // "<mnt_top>/jti" comes here .md_path = "/gpfs/marfs-gpfs/jti/mdfs", .fsinfo_path = "/gpfs/marfs-gpfs/jti/fsinfo", /* a file */ .trash_md_path = "/gpfs/marfs-gpfs/trash", // NOT NEC IN THE SAME FILESET! .iperms = ( R_META | W_META | R_DATA | W_DATA | T_DATA | U_DATA ), .bperms = ( R_META | W_META | R_DATA | W_DATA | T_DATA | U_DATA ), .dirty_pack_percent = 0, .dirty_pack_threshold = 75, .quota_space = (1024L * 1024 * 1024), /* 1 GB of data */ .quota_names = 32, /* 32 names */ .shard_path = NULL, .shard_count = 0, }; push_namespace(&ns_dummy, find_repo_by_name("proxy")); // EMC ECS install (with S3) ns_dummy = (MarFS_Namespace) { .name = "s3", .mnt_path = "/s3", // "<mnt_top>/s3" comes here .md_path = "/gpfs/fs2/s3/mdfs", .fsinfo_path = "/gpfs/fs2/s3/fsinfo", /* a file */ .trash_md_path = "/gpfs/fs2/trash", // NOT NEC IN THE SAME FILESET! .iperms = ( R_META | W_META | R_DATA | W_DATA | T_DATA | U_DATA ), .bperms = ( R_META | W_META | R_DATA | W_DATA | T_DATA | U_DATA ), .dirty_pack_percent = 0, .dirty_pack_threshold = 75, .quota_space = (1024L * 1024 * 1024), /* 1GB of data */ .quota_names = 32, /* 32 names */ .shard_path = NULL, .shard_count = 0, }; push_namespace(&ns_dummy, find_repo_by_name("emc_s3")); // jti testing on machine without GPFS ns_dummy = (MarFS_Namespace) { .name = "ext4", .mnt_path = "/ext4", // "<mnt_top>/ext4" comes here .md_path = "/non_gpfs/mdfs", .trash_md_path = "/non_gpfs/trash", .fsinfo_path = "/non_gpfs/fsinfo", .iperms = ( R_META | W_META | R_DATA | W_DATA | T_DATA | U_DATA ), .bperms = ( R_META | W_META | R_DATA | W_DATA | T_DATA | U_DATA ), .dirty_pack_percent = 0, .dirty_pack_threshold = 75, .quota_space = (1024L * 1024 * 1024), /* 1 GB of data */ .quota_names = 32, /* 32 names */ .shard_path = NULL, .shard_count = 0, }; push_namespace(&ns_dummy, find_repo_by_name("proxy")); #ifdef TBD // jti testing semi-direct ns_dummy = (MarFS_Namespace) { .name = "semi", .mnt_path = "/semi", .md_path = "/gpfs/marfs-gpfs/semi/mdfs", .trash_md_path = "/gpfs/marfs-gpfs/semi/trash", .fsinfo_path = "/gpfs/marfs-gpfs/semi/fsinfo", .iperms = ( R_META | W_META | R_DATA | W_DATA | T_DATA | U_DATA ), .bperms = ( R_META | W_META | R_DATA | W_DATA | T_DATA | U_DATA ), .dirty_pack_percent = 0, .dirty_pack_threshold = 75, .quota_space = (1024L * 1024 * 1024), /* 1 GB of data */ .quota_names = 32, /* 32 names */ .shard_path = NULL, .shard_count = 0, }; push_namespace(&ns_dummy, find_repo_by_name("semi")); #endif // "root" is a special path // // NOTE: find_namespace_by_path() will only return this namespace if its // <path> matches our <mnt_path> exactly. That's because our // mnt_path is (necessarily) a suffix of all paths. ns_dummy = (MarFS_Namespace) { .name = "root", .mnt_path = "/", .md_path = "should_never_be_used", .trash_md_path = "should_never_be_used", .fsinfo_path = "should_never_be_used", .iperms = ( R_META ), /* marfs_getattr() does manual stuff */ .bperms = 0, .dirty_pack_percent = 0, .dirty_pack_threshold = 75, .quota_space = -1, /* no limit */ .quota_names = -1, /* no limit */ .shard_path = NULL, .shard_count = 0, }; push_namespace(&ns_dummy, find_repo_by_name("sproxyd_1M")); return 0; /* success */ } // ........................................................................... // NAMESPACES // ........................................................................... // Find the namespace corresponding to the mnt_suffx in a Namespace struct, // which corresponds with a "namespace" managed by fuse. We might // pontentially have many namespaces (should be cheap to have as many as // you want), and this lookup is done for every fuse call (and in parallel // from pftool). Also done every time we parse an object-ID xattr! Thus, // this should eventually be made efficient. // // One way to make this fast would be to look through all the namespaces // and identify the places where a path diverges for different namespaces. // This becomes a series of hardcoded substring-ops, on the path. Each one // identifies the next suffix in a suffix tree. (Attractive Chaos has an // open source suffix-array impl). The leaves would be pointers to // Namespaces. // // NOTE: If the fuse mount-point is "/A/B", and you provide a path like // "/A/B/C", then the "path" seen by fuse callbacks is "/C". In // otherwords, we should never see MarFS_mnt_top, as part of the // incoming path. // // For a quick first-cut, there's only one namespace. Your path is either // in it or fails. MarFS_Namespace* find_namespace_by_name(const char* name) { int i; size_t name_len = strlen( name ); for (i=0; i<_ns_count; ++i) { MarFS_Namespace* ns = _ns[i]; // We want to compare the whole name to ns->name, not just the first // name length characters. That will match names that are substrings // of name to name incorrectly. // // if (! strncmp(ns->name, name, ns->name_len)) if (( ns->name_len == name_len ) && ( ! strcmp( ns->name, name ))) { return ns; } } return NULL; } /* * @@@-HTTPS: * The path that is passed into this function always starts with the * "/" character. That character and any others up to the next "/" * character are the namespace's mnt_path. A namespace's mnt_path * must begin with the "/" character and not contain any other "/" * characters after the initial one by definition. It is the FUSE * mount point and we'll always use a one-level mount point. */ MarFS_Namespace* find_namespace_by_mnt_path(const char* path) { int i; char *path_dup; char *path_dup_token; size_t path_dup_len; path_dup = strdup( path ); path_dup_token = strtok( path_dup, "/" ); path_dup_len = strlen( path_dup ); /* * At this point path_dup will include the leading "/" and any other * characters up to, but not including, the next "/" character in * path. This includes path_dup being able to be "/" (the root * namespace. */ for (i=0; i<_ns_count; ++i) { MarFS_Namespace* ns = _ns[i]; if (( ns->mnt_path_len == path_dup_len ) && ( !strcmp( ns->mnt_path, path_dup ))) { free( path_dup ); return ns; } } free( path_dup ); return NULL; } // Let others traverse namespaces, without knowing how they are stored NSIterator namespace_iterator() { return (NSIterator){ .pos = 0 }; } MarFS_Namespace* namespace_next(NSIterator* it) { if (it->pos >= _ns_count) return NULL; else return _ns[it->pos++]; } // ........................................................................... // REPOS // ........................................................................... MarFS_Repo* find_repo(MarFS_Namespace* ns, size_t file_size, int interactive_write) { // bool if (interactive_write) return ns->iwrite_repo; else return find_in_range(ns->range_list, file_size); } // later, _repo will be a B-tree, or something, associating repo-names with // repos. MarFS_Repo* find_repo_by_name(const char* repo_name) { int i; for (i=0; i<_repo_count; ++i) { MarFS_Repo* repo = _repo[i]; if (!strcmp(repo_name, repo->name)) return repo; } return NULL; } MarFS_Repo* find_repo_by_range (MarFS_Namespace* ns, size_t file_size) { RangeList* range_list; if (ns) { for (range_list=ns->range_list; range_list; range_list=range_list->next) { if ( (file_size >= range_list->min) && ((file_size <= range_list->max) || (range_list->max == -1))) { return range_list->repo; } } } return NULL; } // Let others traverse repos, without knowing how they are stored RepoIterator repo_iterator() { return (RepoIterator){ .pos = 0 }; } MarFS_Repo* repo_next(RepoIterator* it) { if (it->pos >= _repo_count) return NULL; else return _repo[it->pos++]; } // Give us a pointer to your list-pointer. Your list-pointer should start // out having a value of NULL. We maintain the list of repos ASCCENDING by // min file-size handled. Return false in case of conflicts. Conflicts // include overlapping ranges, or gaps in ranges. Call with <max>==-1, to // make range from <min> to infinity. int insert_in_range(RangeList** list, size_t min, size_t max, MarFS_Repo* repo) { RangeList** insert = list; // ptr to place to store ptr to new element // leave <ptr> pointing to the inserted element RangeList* this; for (this=*list; this; this=this->next) { if (min < this->min) { // insert before <this> if (max == -1) { LOG(LOG_ERR, "range [%ld, -1] includes range [%ld, %ld]\n", min, this->min, this->max); return -1; } if (max < this->min) { LOG(LOG_ERR, "gap between range [%ld, %ld] and [%ld, %ld]\n", min, max, this->min, this->max); return -1; } if (max > this->min) { LOG(LOG_ERR, "overlap in range [%ld, %ld] and [%ld, %ld]\n", min, max, this->min, this->max); return -1; } // do the insert break; } insert = &this->next; } RangeList* elt = (RangeList*)malloc(sizeof(RangeList)); elt->min = min; elt->max = max; elt->repo = repo; elt->next = *insert; *insert = elt; return 0; /* success */ } // given a file-size, find the corresponding element in a RangeList, and // return the corresponding repo. insert_range() maintains repos in // descending order of the block-sizes they handle, to make this as quick // as possible. MarFS_Repo* find_in_range(RangeList* list, size_t block_size) { while (list) { if (block_size >= list->min) return list->repo; list = list->next; } return NULL; }