[Pvfs2-cvs] commit by kunkel in pvfs2/src/common/misc: fsck-utils.h
fsck-utils.c pvfs2-debug.c module.mk.in pint-util.c
pint-perf-counter.c
CVS commit program
cvs at parl.clemson.edu
Sat Jan 13 05:16:43 EST 2007
Update of /projects/cvsroot/pvfs2/src/common/misc
In directory parlweb1:/tmp/cvs-serv19417/src/common/misc
Modified Files:
Tag: kunkel-hint-branch
pvfs2-debug.c module.mk.in pint-util.c pint-perf-counter.c
Added Files:
Tag: kunkel-hint-branch
fsck-utils.h fsck-utils.c
Log Message:
Synchronization with HEAD
--- /dev/null 2004-06-24 14:04:38.000000000 -0400
+++ fsck-utils.h 2007-01-13 05:16:43.000000000 -0500
@@ -0,0 +1,151 @@
+/*
+ * Copyright © Acxiom Corporation, 2005
+ *
+ * See COPYING in top-level directory.
+ */
+
+#ifndef __FSCK_UTILS_H
+#define __FSCK_UTILS_H
+
+#include "pvfs2.h"
+#include "pvfs2-mgmt.h"
+#include "pvfs2-internal.h"
+#include "pint-cached-config.h"
+#include "pint-sysint-utils.h"
+
+#include <stdlib.h>
+
+/** \defgroup fsckutils FSCK Utilities
+ *
+ * The fsck-utils implements a API for checking validity of different PVFS_objects.
+ *
+ * List of PVFS_Object types with API's allowing validity checks:
+ * - PVFS_TYPE_METAFILE
+ * - PVFS_TYPE_DIRECTORY
+ * - PVFS_TYPE_DATAFILE
+ * - PVFS_TYPE_DIRDATA
+ * - PVFS_TYPE_SYMLINK
+ * .
+ * The API is broken up into two sections. The first section simply validates
+ * whether an object is valid. The second section will perform some action
+ * in attempt to either fix or remove the problem.
+ *
+ * @see PINT_fsck_options for optional file system checks
+ *
+ * Any driver program calling this will need to initialize the PVFS system
+ * interface first.
+ * @{
+ */
+
+/** \file
+ * Declarations for the fsck utility component.
+ */
+
+/** FSCK options */
+struct PINT_fsck_options
+{
+ unsigned int fix_errors; /**< fix errors found */
+ unsigned int check_stranded_objects; /**< check for stranded objects */
+ unsigned int check_symlink_target; /**< checks symlink target for bad practice */
+ unsigned int check_dir_entry_names; /**< checks dirent names for bad practice */
+ unsigned int verbose; /**< enable verbose output */
+ unsigned int check_fs_configs; /**< verify fs config files */
+ char* start_path; /**< PVFS2 path to begin check */
+};
+
+int PVFS_fsck_initialize(
+ const struct PINT_fsck_options* options,
+ const PVFS_credentials* creds,
+ const PVFS_fs_id* cur_fs);
+
+int PVFS_fsck_validate_dfile(
+ const struct PINT_fsck_options* fsck_options,
+ const PVFS_handle* handle,
+ const PVFS_fs_id* cur_fs,
+ const PVFS_credentials* creds,
+ PVFS_size* dfile_total_size);
+
+int PVFS_fsck_validate_dfile_attr(
+ const struct PINT_fsck_options* fsck_options,
+ const PVFS_sysresp_getattr* attributes);
+
+int PVFS_fsck_validate_metafile(
+ const struct PINT_fsck_options* fsck_options,
+ const PVFS_object_ref* obj_ref,
+ const PVFS_sysresp_getattr* attributes,
+ const PVFS_credentials* creds);
+
+int PVFS_fsck_validate_metafile_attr(
+ const struct PINT_fsck_options* fsck_options,
+ const PVFS_sysresp_getattr* attributes);
+
+int PVFS_fsck_validate_symlink(
+ const struct PINT_fsck_options* fsck_options,
+ const PVFS_object_ref* obj_ref,
+ const PVFS_sysresp_getattr* attributes);
+
+int PVFS_fsck_validate_symlink_attr(
+ const struct PINT_fsck_options* fsck_options,
+ const PVFS_sysresp_getattr* attributes);
+
+int PVFS_fsck_validate_symlink_target(
+ const struct PINT_fsck_options* fsck_options,
+ const PVFS_sysresp_getattr* attributes);
+
+int PVFS_fsck_validate_dirdata(
+ const struct PINT_fsck_options* fsck_options,
+ const PVFS_handle* handle,
+ const PVFS_fs_id* cur_fs,
+ const PVFS_credentials* creds);
+
+int PVFS_fsck_validate_dirdata_attr(
+ const struct PINT_fsck_options* fsck_options,
+ const PVFS_sysresp_getattr* attributes);
+
+int PVFS_fsck_validate_dir(
+ const struct PINT_fsck_options* fsck_options,
+ const PVFS_object_ref* obj_ref,
+ const PVFS_sysresp_getattr* attributes,
+ const PVFS_credentials* creds,
+ PVFS_dirent* directory_entries);
+
+int PVFS_fsck_validate_dir_attr(
+ const struct PINT_fsck_options* fsck_options,
+ const PVFS_sysresp_getattr* attributes);
+
+int PVFS_fsck_validate_dir_ent(
+ const struct PINT_fsck_options* fsck_options,
+ const char* filename);
+
+int PVFS_fsck_finalize(
+ const struct PINT_fsck_options* fsck_options,
+ const PVFS_fs_id* cur_fs,
+ const PVFS_credentials*);
+
+int PVFS_fsck_get_attributes(
+ const struct PINT_fsck_options*,
+ const PVFS_object_ref*,
+ const PVFS_credentials*,
+ PVFS_sysresp_getattr* );
+
+int PVFS_fsck_check_server_configs(
+ const struct PINT_fsck_options*,
+ const PVFS_credentials*,
+ const PVFS_fs_id*);
+
+/** TODO:
+ * Need to add functions to repair problems. (PVFS2_fsck_fix_XXXX() ?)
+ */
+
+#endif
+
+/* @} */
+
+/*
+ * Local variables:
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * End:
+ *
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
--- /dev/null 2004-06-24 14:04:38.000000000 -0400
+++ fsck-utils.c 2007-01-13 05:16:43.000000000 -0500
@@ -0,0 +1,1633 @@
+/*
+ * Copyright © Acxiom Corporation, 2005
+ *
+ * See COPYING in top-level directory.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "fsck-utils.h"
+
+#define HANDLE_BATCH 1000
+#define MAX_DIR_ENTS 64
+
+#define SERVER_CONFIG_BUFFER_SIZE 5000
+#define FS_CONFIG_BUFFER_SIZE 10000
+
+/** \file
+ * \ingroup fsckutils
+ * Implementation of the fsck-utils component.
+ *
+ * TODO's:
+ * - What action should be taken to recover broken on missing PVFS2 objects? Can
+ * we recover pieces and zero out unknown? Can we create missing metadata
+ * for data files that are orphaned? Do we automatically move to lost+found
+ * directory, and/or allow option to simply remove and delete?
+ * - What needs to be done for extended attributes
+ * - What needs to be done for access control lists (extended attributes &
+ * accounts)
+ * .
+ *
+ * Terminology:
+ * - Orphaned bstreams: bstreams with no dfiles/attributes
+ * - Stranded Object: An object exists with no way to get to it
+ * - Datafile missing metadata
+ * - Metadata missing directory entry
+ * - Dirdata missing directory object
+ * - Dangling directory entry: directory entry exists, but object/attributes don't
+ * .
+ */
+
+static void set_return_code(
+ int *ret,
+ const int retval);
+
+static int compare_handles(
+ const void *handle1,
+ const void *handle2);
+
+/** The following declarations deal with the option to check for stranded objects */
+struct PINT_handle_wrangler_handlelist
+{
+ int num_servers;
+ PVFS_handle **list_array;
+ char **list_array_seen;
+ int *size_array;
+ int *used_array;
+ int *stranded_array;
+ PVFS_BMI_addr_t *addr_array;
+} PINT_handle_wrangler_handlelist;
+
+#if 0
+/* not used yet */
+static int PINT_handle_wrangler_get_stranded_handles(
+ const PVFS_fs_id * cur_fs,
+ int *num_stranded_handles,
+ PVFS_handle ** stranded_handles);
+#endif
+
+static int PINT_handle_wrangler_display_stranded_handles(
+ const struct PINT_fsck_options *fsck_options,
+ const PVFS_fs_id * cur_fs,
+ const PVFS_credentials * creds);
+
+static int PINT_handle_wrangler_load_handles(
+ const struct PINT_fsck_options *fsck_options,
+ const PVFS_fs_id * cur_fs,
+ const PVFS_credentials * creds);
+
+static int PINT_handle_wrangler_remove_handle(
+ const PVFS_handle * handle,
+ const PVFS_fs_id * cur_fs);
+
+/**
+ * Initializes API and checks options for correctness
+ *
+ * \retval 0 on success
+ * \retval -PVFS_error on failure
+ */
+int PVFS_fsck_initialize(
+ const struct PINT_fsck_options *fsck_options, /**< Populated options */
+ const PVFS_credentials * creds, /**< Populated creditials structure */
+ const PVFS_fs_id * cur_fs) /**< filesystem id */
+{
+ int ret = 0;
+
+ if(fsck_options->fix_errors)
+ {
+ return(-PVFS_ENOSYS);
+ }
+
+ /* If check stranded objects... Setup handle stuff */
+ if (fsck_options->check_stranded_objects)
+ {
+ /* get all handles from all servers */
+ ret = PINT_handle_wrangler_load_handles(fsck_options, cur_fs, creds);
+ }
+
+ return ret;
+}
+
+/**
+ * Verifies the same fs config is present on each pvfs2 server.
+ * Ignores extraneous whitespace and comments begining with #. Does not stop
+ * on the first problem- will show any config differences, using the first
+ * server as the golden standard.
+ *
+ * \retval 0 on success
+ * \retval -PVFS_error on failure
+ */
+int PVFS_fsck_check_server_configs(
+ const struct PINT_fsck_options *fsck_options, /**< Populated options */
+ const PVFS_credentials * creds, /**< pvfs2 credentials structure */
+ const PVFS_fs_id * cur_fs) /**< the current fs */
+{
+ int ret = 0;
+ int num_servers = 0;
+ int i = 0;
+ int server_type = 0;
+ PVFS_BMI_addr_t *addresses = NULL;
+ char *fs_config = NULL;
+ char *fs_config_diff = NULL;
+ char *server_config = NULL;
+ char *reference_config_server = NULL;
+ const char *server_name = NULL;
+ struct server_configuration_s *server_config_struct = NULL;
+ FILE *pin = NULL;
+ char line[130] = { 0 };
+ char *cmd = NULL;
+ /* temp file name and file descriptor to store our reference config */
+ char reference_fs_config_tmp_file[] = "/tmp/pvfs2-fsck.XXXXXX";
+ int fout = 0;
+ int final_ret = 0;
+
+ /* count how many servers we have */
+ ret = PVFS_mgmt_count_servers(*cur_fs,
+ (PVFS_credentials *) creds,
+ PVFS_MGMT_IO_SERVER | PVFS_MGMT_META_SERVER,
+ &num_servers);
+ if(ret < 0)
+ {
+ PVFS_perror_gossip("PVFS_mgmt_count_servers", ret);
+ return ret;
+ }
+
+ addresses =
+ (PVFS_BMI_addr_t *) calloc(num_servers, sizeof(PVFS_BMI_addr_t));
+ if (addresses == NULL)
+ {
+ return -PVFS_ENOMEM;
+ }
+
+ /* get a list of the pvfs2 servers */
+ ret = PVFS_mgmt_get_server_array(
+ *cur_fs,
+ (PVFS_credentials *) creds,
+ PVFS_MGMT_IO_SERVER | PVFS_MGMT_META_SERVER,
+ addresses, &num_servers);
+ if(ret < 0)
+ {
+ free(addresses);
+ PVFS_perror_gossip("PVFS_mgmt_get_server_array", ret);
+ return ret;
+ }
+
+ for (i = 0; i < num_servers; i++)
+ {
+ server_type = 0;
+ server_name = NULL;
+
+ /* get the pretty server name */
+ server_config_struct = PINT_get_server_config_struct(*cur_fs);
+ server_name = PINT_cached_config_map_addr(
+ server_config_struct,
+ *cur_fs,
+ addresses[i], &server_type);
+ assert(server_name);
+
+ PINT_put_server_config_struct(server_config_struct);
+
+ fs_config = calloc(FS_CONFIG_BUFFER_SIZE, sizeof(char));
+ if (fs_config == NULL)
+ {
+ free(addresses);
+ return -PVFS_ENOMEM;
+ }
+
+ server_config = calloc(SERVER_CONFIG_BUFFER_SIZE, sizeof(char));
+ if (server_config == NULL)
+ {
+ free(addresses);
+ free(fs_config);
+ return -PVFS_ENOMEM;
+ }
+
+ ret = PVFS_mgmt_get_config(cur_fs,
+ &addresses[i],
+ fs_config,
+ FS_CONFIG_BUFFER_SIZE,
+ server_config, SERVER_CONFIG_BUFFER_SIZE);
+ if (ret < 0)
+ {
+ PVFS_perror_gossip("PVFS_mgmt_get_config", ret);
+ gossip_err("Error: failed to retrieve configuration on server %d of %d.\n",
+ i, num_servers);
+ free(addresses);
+ free(fs_config);
+ free(server_config);
+ return(ret);
+ }
+
+ /* don't need this guy */
+ free(server_config);
+
+ if (i == 0)
+ {
+ /* store the "reference" server name for nice output later */
+ reference_config_server = calloc(1, strlen(server_name) + 1);
+ if (reference_config_server == NULL)
+ {
+ free(addresses);
+ free(fs_config);
+ return -PVFS_ENOMEM;
+ }
+ strcpy(reference_config_server, server_name);
+
+ /* store the first server config as the reference */
+ fout = mkstemp(reference_fs_config_tmp_file);
+ if (fout < 0)
+ {
+ ret = -errno;
+ gossip_err("Error opening temp file [%s]\n",
+ reference_fs_config_tmp_file);
+ free(addresses);
+ free(fs_config);
+ free(reference_config_server);
+ return ret;
+ }
+
+ ret = write(fout, fs_config, strlen(fs_config));
+ if (ret < 0)
+ {
+ ret = -errno;
+ gossip_err("Error: could not write reference configuration.\n");
+ free(addresses);
+ free(fs_config);
+ free(reference_config_server);
+ return(ret);
+ }
+
+ close(fout);
+ }
+ else
+ {
+ /* allocate enough space to hold our diff command */
+ cmd = calloc(1,
+ strlen(fs_config) + strlen(reference_config_server) +
+ strlen(server_name) + 1000);
+ if (cmd == NULL)
+ {
+ free(addresses);
+ free(fs_config);
+ free(reference_config_server);
+ return -PVFS_ENOMEM;
+ }
+
+ /* build the diff command */
+ sprintf(cmd,
+ "echo \"%s\"| diff -EbBu -I '^#.*' -L %s -L %s %s -",
+ fs_config,
+ reference_config_server,
+ server_name, reference_fs_config_tmp_file);
+
+ pin = popen(cmd, "r");
+ if (pin == NULL)
+ {
+ ret = -errno;
+ gossip_err("Error: failed popen() for command: %s\n", cmd);
+ free(addresses);
+ free(fs_config);
+ free(reference_config_server);
+ free(cmd);
+ return ret;
+ }
+
+ fs_config_diff = calloc(1, strlen(fs_config) + 100);
+ if (fs_config_diff == NULL)
+ {
+ free(addresses);
+ free(fs_config);
+ free(reference_config_server);
+ free(cmd);
+ return -PVFS_ENOMEM;
+ }
+
+ /* get the output from diff */
+ while (fgets(line, sizeof line, pin))
+ {
+ strcat(fs_config_diff, line);
+ }
+
+ ret = pclose(pin);
+ if(ret != 0)
+ {
+ gossip_err("Error: failed popen() for command: %s\n", cmd);
+ free(addresses);
+ free(fs_config);
+ free(reference_config_server);
+ free(cmd);
+ free(fs_config_diff);
+ return(-PVFS_EINVAL);
+ }
+
+ /* if diff shows any problems, display it but keep going (we want
+ * to see all config file problems if there is more than one)
+ */
+ if (strlen(fs_config_diff) > 0)
+ {
+ gossip_err("Error: File system config on [%s] doesn't\n",
+ server_name);
+ gossip_err(" match reference config from [%s]:\n\n%s\n",
+ reference_config_server, fs_config_diff);
+
+ final_ret = -PVFS_EINVAL;
+ }
+
+ free(fs_config_diff);
+ free(cmd);
+ }
+
+ free(fs_config);
+ }
+
+ unlink(reference_fs_config_tmp_file);
+ free(reference_config_server);
+ free(addresses);
+
+ return final_ret;
+}
+
+/**
+ * Performs sanity checking on the PVFS_TYPE_DATAFILE PVFS_Object type
+ * Checks the following:
+ * - Existence of attributes
+ * .
+ *
+ * \retval 0 on success
+ * \retval -PVFS_error on failure
+ */
+int PVFS_fsck_validate_dfile(
+ const struct PINT_fsck_options *fsck_options, /**< generic fsck options */
+ const PVFS_handle * handle, /**< The dfile handle */
+ const PVFS_fs_id * cur_fs, /**< The fsid the handle belongs to */
+ const PVFS_credentials * creds, /**< Populated creditials structure */
+ PVFS_size * dfiles_total_size) /**< Total size of all dfiles */
+{
+ int ret = 0;
+ PVFS_object_ref obj_ref;
+ PVFS_sysresp_getattr dfile_attributes;
+ int err = 0;
+
+ memset(&dfile_attributes, 0, sizeof(dfile_attributes));
+
+ if (fsck_options->check_stranded_objects)
+ {
+ if (PINT_handle_wrangler_remove_handle(handle, cur_fs))
+ {
+ gossip_err("WARNING: unable to remove handle [%llu] from handle list while verifying stranded objects\n",
+ llu(*handle));
+ }
+ }
+
+ /* Build the needed PVFS_Object reference needed for API calls */
+ obj_ref.handle = *handle;
+ obj_ref.fs_id = *cur_fs;
+
+ /* Check for existence of attributes */
+ err = PVFS_fsck_get_attributes(fsck_options, &obj_ref, creds,
+ &dfile_attributes);
+ if(err < 0)
+ {
+ gossip_err("Error: unable to get dfile attributes\n");
+ return(err);
+ }
+ set_return_code(&ret, err);
+
+ /* total up the dfile sizes. */
+ *dfiles_total_size += dfile_attributes.attr.size;
+
+ /* Do attributes contain valid data */
+ err = PVFS_fsck_validate_dfile_attr(fsck_options, &dfile_attributes);
+ if(err < 0)
+ {
+ gossip_err("Error: dfile has invalid attributes\n");
+ return(err);
+ }
+ set_return_code(&ret, err);
+
+ return ret;
+}
+
+/**
+ * Performs validity checking for the attributes for PVFS_TYPE_DATAFILE
+ * Checks the following:
+ * - Object Type must be PVFS_TYPE_DFILE
+ * - size >= 0
+ * .
+ * \retval 0 on success
+ * \retval -PVFS_error on failure
+ */
+int PVFS_fsck_validate_dfile_attr(
+ const struct PINT_fsck_options *fsck_options, /**< generic fsck options */
+ const PVFS_sysresp_getattr * getattr_resp) /**< DFILE attributes */
+{
+ int ret = 0;
+
+ if (getattr_resp->attr.objtype != PVFS_TYPE_DATAFILE)
+ {
+ gossip_err(
+ "dfile object type [%d] does not match expected type PVFS_TYPE_DATAFILE %d\n",
+ getattr_resp->attr.objtype, PVFS_TYPE_DATAFILE);
+
+ set_return_code(&ret, -PVFS_EINVAL);
+ }
+
+ if (getattr_resp->attr.size < 0)
+ {
+ /* invalid size attribute */
+ gossip_err("Error: dfile size [%lld] is invalid.\n",
+ lld(getattr_resp->attr.size));
+
+ set_return_code(&ret, -PVFS_EINVAL);
+ }
+
+ return ret;
+}
+
+/**
+ * Performs sanity checking on the PVFS_TYPE_METAFILE PVFS_Object type
+ *
+ * \retval 0 on success
+ * \retval -PVFS_error on failure
+ */
+int PVFS_fsck_validate_metafile(
+ const struct PINT_fsck_options *fsck_options, /**< generic fsck options */
+ const PVFS_object_ref * obj_ref, /**< PVFS_Object reference */
+ const PVFS_sysresp_getattr * attributes, /**< METAFILE attributes */
+ const PVFS_credentials * creds) /**< Populated creditials structure */
+{
+ int ret = 0;
+ int i = 0;
+ PVFS_handle *df_handles;
+ PVFS_size dfiles_total_size = 0;
+ int err = 0;
+
+ if (fsck_options->check_stranded_objects)
+ {
+ if (PINT_handle_wrangler_remove_handle
+ (&obj_ref->handle, &obj_ref->fs_id))
+ {
+ gossip_err("WARNING: unable to remove handle [%llu] from \
+ handle list while verifying stranded objects\n", llu(obj_ref->handle));
+ }
+ }
+
+ /* Check for validity of attributes */
+ err = PVFS_fsck_validate_metafile_attr(fsck_options, attributes);
+ if(err < 0)
+ {
+ gossip_err("Error: metafile has invalid attributes\n");
+ return(err);
+ }
+ set_return_code(&ret, err);
+
+ df_handles = (PVFS_handle *) calloc(attributes->attr.dfile_count,
+ sizeof(PVFS_handle));
+ if (df_handles == NULL)
+ {
+ return -PVFS_ENOMEM;
+ }
+
+ err = PVFS_mgmt_get_dfile_array(*obj_ref,
+ (PVFS_credentials *) creds,
+ df_handles, attributes->attr.dfile_count, NULL);
+ if(err < 0)
+ {
+ PVFS_perror("PVFS_mgmt_get_dfile_array", err);
+ free(df_handles);
+ return(err);
+ }
+
+ /* verify dfiles */
+ for (i = 0; i < attributes->attr.dfile_count; i++)
+ {
+ err = PVFS_fsck_validate_dfile(fsck_options,
+ &df_handles[i],
+ &obj_ref->fs_id,
+ creds, &dfiles_total_size);
+ if(err < 0)
+ {
+ gossip_err("Error: metafile dfile [%d] is invalid\n", i);
+ free(df_handles);
+ return(err);
+ }
+ set_return_code(&ret, err);
+ }
+
+ if (dfiles_total_size > attributes->attr.size)
+ {
+ gossip_err(
+ "Error: sum size of dfiles [%lld] is greater than expected size of [%lld]\n",
+ lld(dfiles_total_size), lld(attributes->attr.size));
+
+ free(df_handles);
+ return(-PVFS_EINVAL);
+ }
+
+ free(df_handles);
+ return ret;
+}
+
+/**
+ * Performs validity checking for the attributes for PVFS_TYPE_METAFILE
+ * Checks the following:
+ * - Object type must be PVFS_TYPE_METAFILE
+ * - Existence of dfiles
+ * - Existence of distribution
+ * - size >= 0
+ * .
+ * \retval 0 on success
+ * \retval -PVFS_error on failure
+ */
+int PVFS_fsck_validate_metafile_attr(
+ const struct PINT_fsck_options *fsck_options, /**< generic fsck options */
+ const PVFS_sysresp_getattr * attributes) /**< METAFILE attributes */
+{
+ int ret = 0;
+
+ /* check attributes */
+ if (attributes->attr.objtype != PVFS_TYPE_METAFILE)
+ {
+ gossip_err(
+ "Error: metafile type [%d] does not match expected type PVFS_TYPE_METAFILE %d\n",
+ attributes->attr.objtype, PVFS_TYPE_METAFILE);
+
+ set_return_code(&ret, -PVFS_EINVAL);
+ }
+
+ /* verify we have dfiles */
+ if (attributes->attr.dfile_count <= 0)
+ {
+ gossip_err("Error: metafile has an invalid number of dfiles [%d]\n",
+ attributes->attr.dfile_count);
+
+ set_return_code(&ret, -PVFS_EINVAL);
+ }
+
+ /* TODO: check to make sure that dfile array and dist is present. */
+
+ return ret;
+}
+
+/**
+ * Performs sanity checking on the PVFS_TYPE_SYMLINK PVFS_Object type
+ *
+ * \retval 0 on success
+ * \retval -PVFS_error on failure
+ */
+int PVFS_fsck_validate_symlink(
+ const struct PINT_fsck_options *fsck_options, /**< generic fsck options */
+ const PVFS_object_ref * obj_ref, /**< PVFS_Object reference */
+ const PVFS_sysresp_getattr * attributes) /**< SYMLINK attributes */
+{
+ int ret = 0;
+
+ if (fsck_options->check_stranded_objects)
+ {
+ if (PINT_handle_wrangler_remove_handle
+ (&obj_ref->handle, &obj_ref->fs_id))
+ {
+ gossip_err("WARNING: unable to remove handle [%llu] from handle \
+ list while verifying stranded objects\n", llu(obj_ref->handle));
+ }
+ }
+
+ ret = PVFS_fsck_validate_symlink_attr(fsck_options, attributes);
+
+ return ret;
+}
+
+/**
+ * Performs validity checking for the attributes for PVFS_TYPE_SYMLINK
+ * Checks the following:
+ * - Object type must be PVFS_TYPE_SYMLINK
+ * - Target must be non-null
+ * .
+ * \retval 0 on success
+ * \retval -PVFS_error on failure
+ */
+int PVFS_fsck_validate_symlink_attr(
+ const struct PINT_fsck_options *fsck_options, /**< generic fsck options */
+ const PVFS_sysresp_getattr * attributes) /**< SYMLINK attributes */
+{
+ int ret = 0;
+ int err = 0;
+
+ /* check attributes */
+ if (attributes->attr.objtype != PVFS_TYPE_SYMLINK)
+ {
+ gossip_err(
+ "Error: symlink type [%d] does not match expected type PVFS_TYPE_SYMLINK [%d]\n",
+ attributes->attr.objtype, PVFS_TYPE_SYMLINK);
+
+ set_return_code(&ret, -PVFS_EINVAL);
+ }
+
+ if (attributes->attr.link_target)
+ {
+ if (fsck_options->check_symlink_target)
+ {
+ /* we do have a target, make sure it's valid */
+ err = PVFS_fsck_validate_symlink_target(fsck_options, attributes);
+ if (err < 0)
+ {
+ gossip_err("Error: symlink target [%s] is invalid\n",
+ attributes->attr.link_target);
+ return(err);
+ }
+ set_return_code(&ret, err);
+ }
+ }
+ else
+ {
+ gossip_err("Error: symlink missing target attribute\n");
+ set_return_code(&ret, -PVFS_EINVAL);
+ }
+
+ return ret;
+}
+
+/**
+ * Performs "bad practice" warning checks for the target attributes for
+ * PVFS_TYPE_SYMLINK. Checks the following:
+ * - Does target exist
+ * - Does target back out of PVFS2 filesystem
+ * - Does target use absolute path
+ * .
+ * \retval 0 on success
+ * \retval -PVFS_error on failure
+ */
+int PVFS_fsck_validate_symlink_target(
+ const struct PINT_fsck_options *fsck_options, /**< generic fsck options */
+ const PVFS_sysresp_getattr * attributes) /**< SYMLINK attributes */
+{
+ int ret = 0;
+
+ /* TODO: finish other tests */
+
+ if (attributes->attr.link_target[0] == '/')
+ {
+ gossip_err("WARNING: symlink target [%s] uses absolute path\n",
+ attributes->attr.link_target);
+ }
+
+ return ret;
+}
+
+/**
+ * Performs sanity checking on the PVFS_TYPE_DIRDATA PVFS_Object type.
+ * Checks the following:
+ * - Do attributes exist
+ * .
+ * \retval 0 on success
+ * \retval -PVFS_error on failure
+ */
+int PVFS_fsck_validate_dirdata(
+ const struct PINT_fsck_options *fsck_options, /**< generic fsck options */
+ const PVFS_handle * handle, /**< The dirdata handle */
+ const PVFS_fs_id * cur_fs, /**< The fsid the handle belongs to */
+ const PVFS_credentials * creds) /**< Populated creditials structure */
+{
+ int ret = 0;
+ int err = 0;
+ PVFS_sysresp_getattr dirdata_attributes;
+ PVFS_object_ref obj_ref;
+
+ memset(&dirdata_attributes, 0, sizeof(dirdata_attributes));
+
+ obj_ref.handle = *handle;
+ obj_ref.fs_id = *cur_fs;
+
+ if (fsck_options->check_stranded_objects)
+ {
+ if (PINT_handle_wrangler_remove_handle(handle, cur_fs))
+ {
+ gossip_err("WARNING: unable to remove handle [%llu] from handle \
+ list while verifying stranded objects\n", llu(*handle));
+ }
+ }
+
+ err = PVFS_fsck_get_attributes
+ (fsck_options, &obj_ref, creds, &dirdata_attributes);
+ if(err < 0)
+ {
+ gossip_err("Error: failed to get attributes for dirdata object\n");
+ return(err);
+ }
+ set_return_code(&ret, err);
+
+ err = PVFS_fsck_validate_dirdata_attr(fsck_options, &dirdata_attributes);
+ if(err < 0)
+ {
+ gossip_err("Error: dirdata entry has invalid attributes\n");
+ return(err);
+ }
+ set_return_code(&ret, err);
+
+ return ret;
+}
+
+/**
+ * Performs validity checking for the attributes for PVFS_TYPE_DIRDATA.
+ * Checks the following:
+ * - Object type must be PVFS_TYPE_DIRDATA
+ * .
+ * \retval 0 on success
+ * \retval -PVFS_error on failure
+ */
+int PVFS_fsck_validate_dirdata_attr(
+ const struct PINT_fsck_options *fsck_options, /**< generic fsck options */
+ const PVFS_sysresp_getattr * attributes) /**< DIRDATA attributes */
+{
+ int ret = 0;
+
+ if (attributes->attr.objtype != PVFS_TYPE_DIRDATA)
+ {
+ gossip_err(
+ "Error: dirdata type [%d] does not match expected type PVFS_TYPE_DIRDATA %d\n",
+ attributes->attr.objtype, PVFS_TYPE_DIRDATA);
+
+ set_return_code(&ret, -PVFS_EINVAL);
+ }
+
+ return ret;
+}
+
+/**
+ * Performs sanity checking on the PVFS_TYPE_DIRECTORY PVFS_Object type.
+ * Checks the following:
+ * - gets and validates directory entry filenames
+ * .
+ * \retval 0 on success
+ * \retval -PVFS_error on failure
+ */
+int PVFS_fsck_validate_dir(
+ const struct PINT_fsck_options *fsck_options, /**< generic fsck options */
+ const PVFS_object_ref * obj_ref, /**< DIRECTORY object reference */
+ const PVFS_sysresp_getattr * attributes, /**< DIRECTORY attributes */
+ const PVFS_credentials * creds, /**< populated creditials structure */
+ PVFS_dirent * directory_entries) /**< \return readdir response */
+{
+ int ret = 0;
+ int i = 0;
+ int err = 0;
+ int current_dir_entry = 0;
+ PVFS_ds_position token = PVFS_READDIR_START;
+ PVFS_sysresp_readdir readdir_resp;
+ PVFS_handle dirdata_handle;
+
+ if (fsck_options->check_stranded_objects)
+ {
+ if (PINT_handle_wrangler_remove_handle
+ (&obj_ref->handle, &obj_ref->fs_id))
+ {
+ gossip_err("WARNING: unable to remove handle [%llu] from \
+ handle list while verifying stranded objects\n", llu(obj_ref->handle));
+ }
+ }
+
+ err = PVFS_fsck_validate_dir_attr(fsck_options, attributes);
+ if(err < 0)
+ {
+ gossip_err("Error: directory has invalid attributes\n");
+ return(err);
+ }
+ set_return_code(&ret, err);
+
+ /* get the dirdata handle and validate */
+ err = PVFS_mgmt_get_dirdata_handle
+ (*obj_ref, &dirdata_handle, (PVFS_credentials *) creds, NULL);
+ if(err < 0)
+ {
+ gossip_err("Error: unable to get dirdata handle\n");
+ return(err);
+ }
+
+ err = PVFS_fsck_validate_dirdata
+ (fsck_options, &dirdata_handle, &obj_ref->fs_id, creds);
+ if(err < 0)
+ {
+ gossip_err("Error: directory dirdata is invalid\n");
+ return(err);
+ }
+ set_return_code(&ret, err);
+
+ /* get and validate all directory entries */
+ do
+ {
+ memset(&readdir_resp, 0, sizeof(PVFS_sysresp_readdir));
+
+ err = PVFS_sys_readdir(*obj_ref,
+ token,
+ MAX_DIR_ENTS,
+ (PVFS_credentials *) creds, &readdir_resp, NULL);
+ if(err < 0)
+ {
+ gossip_err("Error: could not read directory entries\n");
+ return(err);
+ }
+
+ for (i = 0; i < readdir_resp.pvfs_dirent_outcount; i++)
+ {
+ strncpy(directory_entries[current_dir_entry].d_name,
+ readdir_resp.dirent_array[i].d_name, PVFS_NAME_MAX + 1);
+
+ directory_entries[current_dir_entry].handle =
+ readdir_resp.dirent_array[i].handle;
+ current_dir_entry++;
+
+ if (fsck_options->check_dir_entry_names)
+ {
+ err = PVFS_fsck_validate_dir_ent(fsck_options,
+ readdir_resp.
+ dirent_array[i].d_name);
+ /* continue even if we hit errors; we want to see all entries */
+ if (err < 0)
+ {
+ gossip_err("Error: directory entry [%s] is invalid\n",
+ readdir_resp.dirent_array[i].d_name);
+ }
+ set_return_code(&ret, err);
+ }
+ }
+
+ free(readdir_resp.dirent_array);
+ token = readdir_resp.token;
+
+ } while (readdir_resp.pvfs_dirent_outcount == MAX_DIR_ENTS);
+
+ return ret;
+}
+
+/**
+ * Performs validity checking for the attributes for PVFS_TYPE_DIRECTORY.
+ * Checks the following:
+ * - Object type must be PVFS_TYPE_DIRECTORY
+ * - dirent_count must be >= 0
+ * .
+ * \retval 0 on success
+ * \retval -PVFS_error on failure
+ */
+int PVFS_fsck_validate_dir_attr(
+ const struct PINT_fsck_options *fsck_options, /**< generic fsck options */
+ const PVFS_sysresp_getattr * attributes) /**< DIRECTORY attributes */
+{
+ int ret = 0;
+
+ if (attributes->attr.objtype != PVFS_TYPE_DIRECTORY)
+ {
+ gossip_err("Error: directory type [%d] does not \
+ match expected type PVFS_TYPE_DIRECTORY %d\n", attributes->attr.objtype, PVFS_TYPE_DIRECTORY);
+
+ set_return_code(&ret, -PVFS_EINVAL);
+ }
+
+ if (attributes->attr.dirent_count < 0)
+ {
+ gossip_err("Error: directory entry count [%lld] is invalid\n",
+ lld(attributes->attr.dirent_count));
+
+ set_return_code(&ret, -PVFS_EINVAL);
+ }
+
+ return ret;
+}
+
+/**
+ * Performs validity checking for the PVFS_TYPE_DIRECTORY directory entries
+ * Checks the following:
+ * - invalid characters in entry names
+ * - entry_names <= PVFS2_SEGMENT_MAX
+ * - warnings for characters that tend to confuse shells
+ * .
+ * \retval 0 on success
+ * \retval -PVFS_error on failure
+ */
+int PVFS_fsck_validate_dir_ent(
+ const struct PINT_fsck_options *fsck_options, /**< generic fsck options */
+ const char *filename) /**< Filename associated with handle */
+{
+ const char *cp;
+ int ret = 0;
+
+ if (strlen(filename) > PVFS_SEGMENT_MAX)
+ {
+ gossip_err(
+ "Error: directory entry [%s] length is > PVFS_SEGMENT_MAX [%d]\n",
+ filename, PVFS_SEGMENT_MAX);
+ set_return_code(&ret, -PVFS_EINVAL);
+ }
+
+ if (strspn(filename, "/") > 0)
+ {
+ gossip_err("Error: directory entry [%s] contains invalid / character \n",
+ filename);
+ set_return_code(&ret, -PVFS_EINVAL);
+ }
+
+ cp = filename;
+ while (*cp)
+ {
+ /* isprint is ' ' through ~ in ASCII; no tabs or newlines */
+ if (!isprint(*cp))
+ {
+ gossip_err("WARNING: directory entry [%s] contains odd character\n",
+ filename);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/**
+ * Get a pvfs2 objects attributes.
+ *
+ * \retval 0 on success
+ * \retval -PVFS_error on failure
+ */
+int PVFS_fsck_get_attributes(
+ const struct PINT_fsck_options *fsck_options, /**< generic fsck options */
+ const PVFS_object_ref * pref, /**< object reference requesting attributes */
+ const PVFS_credentials * creds, /**< populated credentials structure */
+ PVFS_sysresp_getattr * getattr_resp) /**< attribute structure to populate */
+{
+ time_t r_atime, r_mtime, r_ctime;
+ int ret = 0;
+
+ ret = PVFS_sys_getattr
+ (*pref, PVFS_ATTR_SYS_ALL, (PVFS_credentials *) creds, getattr_resp, NULL);
+ if(ret < 0)
+ {
+ gossip_err("Error: unable to retrieve attributes\n");
+ return(ret);
+ }
+
+ r_atime = (time_t) getattr_resp->attr.atime;
+ r_mtime = (time_t) getattr_resp->attr.mtime;
+ r_ctime = (time_t) getattr_resp->attr.ctime;
+
+ /* if the gossip fsck debug mask is enabled, then print detailed
+ * information about the attributes
+ */
+ gossip_debug(GOSSIP_FSCK_DEBUG, "\tFSID : %d\n", (int) pref->fs_id);
+ gossip_debug(GOSSIP_FSCK_DEBUG, "\tHandle : %llu\n", llu(pref->handle));
+
+ if (getattr_resp->attr.mask & PVFS_ATTR_SYS_COMMON_ALL)
+ {
+ gossip_debug(GOSSIP_FSCK_DEBUG,
+ "\tuid : %d\n", getattr_resp->attr.owner);
+ gossip_debug(GOSSIP_FSCK_DEBUG,
+ "\tgid : %d\n", getattr_resp->attr.group);
+ gossip_debug(GOSSIP_FSCK_DEBUG,
+ "\tperms : %o\n", getattr_resp->attr.perms);
+ gossip_debug(GOSSIP_FSCK_DEBUG,
+ "\tatime : %s", ctime(&r_atime));
+ gossip_debug(GOSSIP_FSCK_DEBUG,
+ "\tmtime : %s", ctime(&r_mtime));
+ gossip_debug(GOSSIP_FSCK_DEBUG,
+ "\tctime : %s", ctime(&r_ctime));
+
+ }
+
+ if (getattr_resp->attr.objtype == PVFS_TYPE_SYMLINK)
+ {
+ gossip_debug(GOSSIP_FSCK_DEBUG,
+ "\ttarget: : %s\n", getattr_resp->attr.link_target);
+ }
+
+ if (getattr_resp->attr.mask & PVFS_ATTR_SYS_SIZE)
+ {
+ gossip_debug(GOSSIP_FSCK_DEBUG,
+ "\tfile size : %lld\n", lld(getattr_resp->attr.size));
+ }
+
+ if (getattr_resp->attr.mask & PVFS_ATTR_SYS_DFILE_COUNT)
+ {
+ gossip_debug(GOSSIP_FSCK_DEBUG,
+ "\tdfile count : %d\n", getattr_resp->attr.dfile_count);
+ }
+
+ gossip_debug(GOSSIP_FSCK_DEBUG, "\tobject type : ");
+
+ switch (getattr_resp->attr.objtype)
+ {
+ case PVFS_TYPE_NONE:
+ gossip_debug(GOSSIP_FSCK_DEBUG, "none\n");
+ break;
+ case PVFS_TYPE_METAFILE:
+ gossip_debug(GOSSIP_FSCK_DEBUG, "meta file\n");
+ break;
+ case PVFS_TYPE_DATAFILE:
+ gossip_debug(GOSSIP_FSCK_DEBUG, "data file\n");
+ break;
+ case PVFS_TYPE_DIRECTORY:
+ gossip_debug(GOSSIP_FSCK_DEBUG, "directory\n");
+ break;
+ case PVFS_TYPE_SYMLINK:
+ gossip_debug(GOSSIP_FSCK_DEBUG, "symlink\n");
+ break;
+ case PVFS_TYPE_DIRDATA:
+ gossip_debug(GOSSIP_FSCK_DEBUG, "dirdata\n");
+ break;
+ }
+ gossip_debug(GOSSIP_FSCK_DEBUG, "\n");
+
+ return ret;
+}
+
+/**
+ * Performs final steps of fsck. If option was enabled to check for stranded
+ * objects, then it will print any leftover objects.
+ *
+ * \retval 0 on success
+ * \retval -PVFS_error on failure
+ */
+int PVFS_fsck_finalize(
+ const struct PINT_fsck_options *fsck_options, /**< Populated options */
+ const PVFS_fs_id * cur_fs, /**< The fsid the handle belongs to */
+ const PVFS_credentials * creds) /**< populated credentials structure */
+{
+ /* display leftover handles */
+ if (fsck_options->check_stranded_objects)
+ {
+ PINT_handle_wrangler_display_stranded_handles(fsck_options, cur_fs,
+ creds);
+ }
+
+ return(0);
+}
+
+/**
+ * Gets a list of all the handles used from the PVFS2 servers. The PVFS2 system
+ * interface must have already been initialized.
+ *
+ * \retval 0 on success
+ * \retval -PVFS_error on failure
+ */
+static int PINT_handle_wrangler_load_handles(
+ const struct PINT_fsck_options *fsck_options, /**< Populated options */
+ const PVFS_fs_id * cur_fs, /**< fs_id */
+ const PVFS_credentials * creds) /**< populdated credentials structure */
+{
+ int ret = 0;
+ int server_count;
+ struct PVFS_mgmt_server_stat *stat_array = NULL;
+ PVFS_handle **handle_matrix = NULL;
+ int i = 0;
+ int *handle_count_array = NULL;
+ int *position_array = NULL;
+ int more_handles = 0;
+ int err = 0;
+
+ gossip_debug(GOSSIP_FSCK_DEBUG,
+ "getting all file handles from filesystem\n");
+
+ memset(&PINT_handle_wrangler_handlelist, 0,
+ sizeof(PINT_handle_wrangler_handlelist));
+
+ /* count how many servers we have */
+ err = PVFS_mgmt_count_servers(*cur_fs,
+ (PVFS_credentials *) creds,
+ PVFS_MGMT_IO_SERVER | PVFS_MGMT_META_SERVER,
+ &server_count);
+ if(err < 0)
+ {
+ PVFS_perror_gossip("PVFS_mgmt_count_servers", err);
+ return err;
+ }
+
+ PINT_handle_wrangler_handlelist.num_servers = server_count;
+
+ PINT_handle_wrangler_handlelist.addr_array =
+ (PVFS_BMI_addr_t *) calloc(server_count, sizeof(PVFS_BMI_addr_t));
+ if (PINT_handle_wrangler_handlelist.addr_array == NULL)
+ {
+ ret = -PVFS_ENOMEM;
+ goto load_handles_error;
+ }
+
+ /* get a list of the pvfs2 servers */
+ err = PVFS_mgmt_get_server_array(*cur_fs,
+ (PVFS_credentials *) creds,
+ PVFS_MGMT_IO_SERVER | PVFS_MGMT_META_SERVER,
+ PINT_handle_wrangler_handlelist.addr_array,
+ &server_count);
+ if(err < 0)
+ {
+ PVFS_perror_gossip("PVFS_mgmt_get_server_array", err);
+ ret = err;
+ goto load_handles_error;
+ }
+
+ stat_array = (struct PVFS_mgmt_server_stat *)
+ calloc(server_count, sizeof(struct PVFS_mgmt_server_stat));
+ if (stat_array == NULL)
+ {
+ ret = -PVFS_ENOMEM;
+ goto load_handles_error;
+ }
+
+ /* this gives us a count of the handles on each server */
+ err = PVFS_mgmt_statfs_list(*cur_fs,
+ (PVFS_credentials *) creds,
+ stat_array,
+ PINT_handle_wrangler_handlelist.addr_array,
+ server_count, NULL, NULL);
+ if(err < 0)
+ {
+ ret = -PVFS_ENOMEM;
+ goto load_handles_error;
+ }
+
+ /* allocate big chunks of memory to keep up with handles */
+ handle_count_array = (int *) calloc(server_count, sizeof(int));
+ if (handle_count_array == NULL)
+ {
+ ret = -PVFS_ENOMEM;
+ goto load_handles_error;
+ }
+
+ position_array = (int *) calloc(server_count, sizeof(int));
+ if (position_array == NULL)
+ {
+ ret = -PVFS_ENOMEM;
+ goto load_handles_error;
+ }
+
+ PINT_handle_wrangler_handlelist.list_array =
+ (PVFS_handle **) calloc(server_count, sizeof(PVFS_handle *));
+ if (PINT_handle_wrangler_handlelist.list_array == NULL)
+ {
+ ret = -PVFS_ENOMEM;
+ goto load_handles_error;
+ }
+ memset(PINT_handle_wrangler_handlelist.list_array, 0,
+ server_count*sizeof(PVFS_handle*));
+
+ PINT_handle_wrangler_handlelist.list_array_seen =
+ (char **) calloc(server_count, sizeof(char *));
+ if (PINT_handle_wrangler_handlelist.list_array_seen == NULL)
+ {
+ ret = -PVFS_ENOMEM;
+ goto load_handles_error;
+ }
+ memset(PINT_handle_wrangler_handlelist.list_array_seen, 0,
+ server_count*sizeof(char*));
+
+ PINT_handle_wrangler_handlelist.size_array =
+ (int *) calloc(server_count, sizeof(int));
+ if (PINT_handle_wrangler_handlelist.size_array == NULL)
+ {
+ ret = -PVFS_ENOMEM;
+ goto load_handles_error;
+ }
+
+ PINT_handle_wrangler_handlelist.used_array =
+ (int *) calloc(server_count, sizeof(int));
+ if (PINT_handle_wrangler_handlelist.used_array == NULL)
+ {
+ ret = -PVFS_ENOMEM;
+ goto load_handles_error;
+ }
+
+ PINT_handle_wrangler_handlelist.stranded_array =
+ (int *) calloc(server_count, sizeof(int));
+ if (PINT_handle_wrangler_handlelist.stranded_array == NULL)
+ {
+ ret = -PVFS_ENOMEM;
+ goto load_handles_error;
+ }
+
+ /* temporary array to keep state while fetching handles */
+ handle_matrix =
+ (PVFS_handle **) calloc(server_count, sizeof(PVFS_handle *));
+ if (handle_matrix == NULL)
+ {
+ ret = -PVFS_ENOMEM;
+ goto load_handles_error;
+ }
+ memset(handle_matrix, 0, server_count*sizeof(PVFS_handle*));
+
+ /* populating a nice "handlelist" struct with all this various handle data */
+ for (i = 0; i < server_count; i++)
+ {
+ PINT_handle_wrangler_handlelist.size_array[i] =
+ stat_array[i].handles_total_count -
+ stat_array[i].handles_available_count;
+
+ PINT_handle_wrangler_handlelist.used_array[i] = 0;
+
+ PINT_handle_wrangler_handlelist.list_array[i] =
+ (PVFS_handle *) calloc(PINT_handle_wrangler_handlelist.size_array[i],
+ sizeof(PVFS_handle));
+ if (PINT_handle_wrangler_handlelist.list_array[i] == NULL)
+ {
+ ret = -PVFS_ENOMEM;
+ goto load_handles_error;
+ }
+
+ PINT_handle_wrangler_handlelist.list_array_seen[i] =
+ (char *) calloc(PINT_handle_wrangler_handlelist.size_array[i],
+ sizeof(char));
+ if (PINT_handle_wrangler_handlelist.list_array_seen[i] == NULL)
+ {
+ ret = -PVFS_ENOMEM;
+ goto load_handles_error;
+ }
+
+ handle_matrix[i] =
+ (PVFS_handle *) calloc(PINT_handle_wrangler_handlelist.size_array[i],
+ sizeof(PVFS_handle));
+ if (handle_matrix[i] == NULL)
+ {
+ ret = -PVFS_ENOMEM;
+ goto load_handles_error;
+ }
+
+ position_array[i] = PVFS_ITERATE_START;
+ handle_count_array[i] = HANDLE_BATCH;
+ }
+
+ /* repeatedly grab handles until we get them all */
+ do
+ {
+ /* mgmt call to get block of handles */
+ err = PVFS_mgmt_iterate_handles_list(*cur_fs,
+ (PVFS_credentials *) creds,
+ handle_matrix,
+ handle_count_array,
+ position_array,
+ PINT_handle_wrangler_handlelist.
+ addr_array, server_count, NULL, NULL);
+ if(err < 0)
+ {
+ PVFS_perror_gossip("PVFS_mgmt_iterate_handles", err);
+ ret = err;
+ goto load_handles_error;
+ }
+
+ more_handles = 0;
+
+ for (i = 0; i < server_count; i++)
+ {
+ /* add this block of handles to the full list */
+ int j = 0;
+ for (j = 0; j < handle_count_array[i]; j++)
+ {
+ PINT_handle_wrangler_handlelist.list_array[i]
+ [PINT_handle_wrangler_handlelist.used_array[i] + j] =
+ handle_matrix[i][j];
+ }
+
+ PINT_handle_wrangler_handlelist.used_array[i] +=
+ handle_count_array[i];
+
+ /* are there more handles? */
+ if (position_array[i] != PVFS_ITERATE_END)
+ {
+ more_handles = 1;
+ }
+ }
+ } while (more_handles != 0);
+
+ for (i = 0; i < server_count; i++)
+ {
+ /* sort the list of handles */
+ qsort(PINT_handle_wrangler_handlelist.list_array[i],
+ PINT_handle_wrangler_handlelist.used_array[i],
+ sizeof(PVFS_size), compare_handles);
+
+ /* we will decrement this during the actual fsck as we check each handle */
+ PINT_handle_wrangler_handlelist.stranded_array[i] =
+ PINT_handle_wrangler_handlelist.used_array[i];
+ }
+ ret = 0;
+ goto load_handles_success;
+
+load_handles_error:
+ if(PINT_handle_wrangler_handlelist.stranded_array)
+ free(PINT_handle_wrangler_handlelist.stranded_array);
+ if(PINT_handle_wrangler_handlelist.used_array)
+ free(PINT_handle_wrangler_handlelist.used_array);
+ if(PINT_handle_wrangler_handlelist.size_array)
+ free(PINT_handle_wrangler_handlelist.size_array);
+ if(PINT_handle_wrangler_handlelist.addr_array)
+ free(PINT_handle_wrangler_handlelist.addr_array);
+ if(PINT_handle_wrangler_handlelist.list_array)
+ {
+ for(i=0; i<server_count; i++)
+ {
+ if(PINT_handle_wrangler_handlelist.list_array[i])
+ free(PINT_handle_wrangler_handlelist.list_array[i]);
+ }
+ free(PINT_handle_wrangler_handlelist.list_array);
+ }
+ if(PINT_handle_wrangler_handlelist.list_array_seen)
+ {
+ for(i=0; i<server_count; i++)
+ {
+ if(PINT_handle_wrangler_handlelist.list_array_seen[i])
+ free(PINT_handle_wrangler_handlelist.list_array_seen[i]);
+ }
+ free(PINT_handle_wrangler_handlelist.list_array_seen);
+ }
+
+ /* fall through on purpose */
+
+load_handles_success:
+ if(handle_matrix)
+ {
+ for(i=0; i<server_count; i++)
+ {
+ if(handle_matrix[i])
+ free(handle_matrix[i]);
+ }
+ free(handle_matrix);
+ }
+ if(position_array)
+ free(position_array);
+ if(handle_count_array)
+ free(handle_count_array);
+ if(stat_array)
+ free(stat_array);
+
+ return ret;
+}
+
+/**
+ * Removes the given handle from the list of handles stored. Each check in
+ * the fsck calls this function as it sees a handle. The end result is a
+ * list of left over "stranded" handles.
+ *
+ * \retval 0 on success
+ * \retval -PVFS_error on failure
+ */
+static int PINT_handle_wrangler_remove_handle(
+ const PVFS_handle * handle, /**< handle to remove */
+ const PVFS_fs_id * cur_fs) /**< fs_id */
+{
+ int ret = 0;
+ int i = 0;
+ int j = 0;
+ PVFS_BMI_addr_t server_addr;
+ int found = 0;
+
+ /* find which server the handle is on */
+ ret = PINT_cached_config_map_to_server(&server_addr, *handle, *cur_fs);
+ if(ret < 0)
+ {
+ PVFS_perror_gossip("PINT_cached_config_map_to_server", ret);
+ gossip_err("Error: could not resolve handle [%llu] to server\n",
+ llu(*handle));
+ return(ret);
+ }
+
+ /* get the index of the server this handle is located on */
+ for (i = 0; i < PINT_handle_wrangler_handlelist.num_servers; i++)
+ {
+ if (PINT_handle_wrangler_handlelist.addr_array[i] == server_addr)
+ {
+ found = 1;
+ break;
+ }
+ }
+ if(!found)
+ {
+ gossip_err("Error: could not find matching server for handle [%llu]\n",
+ llu(*handle));
+ return(-PVFS_EINVAL);
+ }
+
+ /* keep up with which handles have been "seen" */
+ found = 0;
+ for (j = 0; j < PINT_handle_wrangler_handlelist.used_array[i]; j++)
+ {
+ if (PINT_handle_wrangler_handlelist.list_array[i][j] == *handle)
+ {
+ PINT_handle_wrangler_handlelist.list_array_seen[i][j] = 'x';
+ PINT_handle_wrangler_handlelist.stranded_array[i]--;
+ found = 1;
+ break;
+ }
+ }
+ if(!found)
+ {
+ gossip_err("Error: could not find handle [%llu]\n",
+ llu(*handle));
+ return(-PVFS_EINVAL);
+ }
+
+ return ret;
+}
+
+#if 0
+/**
+ * Returns the handles left over from the fsck
+ */
+static int PINT_handle_wrangler_get_stranded_handles(
+ const PVFS_fs_id * cur_fs, /**< filesystem id */
+ int *num_stranded_handles, /**< number of handles in array of handles returned */
+ PVFS_handle ** stranded_handles) /**< array of stranded handles on fs cur_fs */
+{
+ int ret = 0;
+ int i = 0;
+ int j = 0;
+ int position = 0;
+
+ *num_stranded_handles = 0;
+
+ for (i = 0; i < PINT_handle_wrangler_handlelist.num_servers; i++)
+ {
+ (*num_stranded_handles) +=
+ PINT_handle_wrangler_handlelist.stranded_array[i];
+ }
+
+ *stranded_handles = (PVFS_handle *) calloc((*num_stranded_handles), sizeof(PVFS_handle));
+ if (*stranded_handles == NULL)
+ {
+ return -PVFS_ENOMEM;
+ }
+
+ for (i = 0; i < PINT_handle_wrangler_handlelist.num_servers; i++)
+ {
+ for (j = 0; j < PINT_handle_wrangler_handlelist.used_array[i]; j++)
+ {
+ if (!PINT_handle_wrangler_handlelist.list_array_seen[i][j])
+ {
+ (*stranded_handles)[position] =
+ PINT_handle_wrangler_handlelist.list_array[i][j];
+ position++;
+ }
+ }
+ }
+
+ return ret;
+}
+#endif
+
+/**
+ * Displays the handles left over from the fsck
+ *
+ * \retval 0 on success
+ * \retval -PVFS_error on failure
+ */
+static int PINT_handle_wrangler_display_stranded_handles(
+ const struct PINT_fsck_options *fsck_options, /**< populated fsck options */
+ const PVFS_fs_id * cur_fs, /**< filesystem id */
+ const PVFS_credentials * creds) /**< populated credentials structure */
+{
+ int ret = 0;
+ int i = 0;
+ int j = 0;
+ int server_type = 0;
+ PVFS_sysresp_getattr attributes;
+ PVFS_object_ref pref;
+ struct server_configuration_s *config;
+ const char *server_name = NULL;
+ int header = 0;
+
+ for (i = 0; i < PINT_handle_wrangler_handlelist.num_servers; i++)
+ {
+ /* get the pretty server name */
+ config = PINT_get_server_config_struct(*cur_fs);
+ server_name = PINT_cached_config_map_addr(config,
+ *cur_fs,
+ PINT_handle_wrangler_handlelist.
+ addr_array[i], &server_type);
+
+ /* release mutex on server config */
+ PINT_put_server_config_struct(config);
+
+ for (j = 0; j < PINT_handle_wrangler_handlelist.size_array[i]; j++)
+ {
+ if (!PINT_handle_wrangler_handlelist.list_array_seen[i][j])
+ {
+ pref.handle = PINT_handle_wrangler_handlelist.list_array[i][j];
+ pref.fs_id = *cur_fs;
+
+ if(!header)
+ {
+ printf("\n");
+ printf("Stranded Objects:\n");
+ printf
+ ("[ Handle ] [ FSID ] [ Size ] [File Type] [ PVFS2 Server ]\n");
+ header = 1;
+ }
+
+ /* get this objects attributes */
+ ret = PVFS_fsck_get_attributes(fsck_options, &pref, creds,
+ &attributes);
+ if(ret < 0)
+ {
+ PVFS_perror_gossip("PVFS_fsck_get_attributes", ret);
+ gossip_err("Error: unable to retrieve attributes for handle [%llu]\n",
+ llu(pref.handle));
+ return(ret);
+ }
+
+ printf(" %llu %d ",
+ llu(PINT_handle_wrangler_handlelist.list_array[i][j]),
+ *cur_fs);
+
+ if (attributes.attr.mask & PVFS_ATTR_SYS_SIZE)
+ {
+ printf("%13lld ", lld(attributes.attr.size));
+ }
+
+ switch (attributes.attr.objtype)
+ {
+ case PVFS_TYPE_NONE:
+ printf("none ");
+ break;
+ case PVFS_TYPE_METAFILE:
+ printf("meta file");
+ break;
+ case PVFS_TYPE_DATAFILE:
+ printf("data file");
+ break;
+ case PVFS_TYPE_DIRECTORY:
+ printf("directory");
+ break;
+ case PVFS_TYPE_SYMLINK:
+ printf("symlink ");
+ free(attributes.attr.link_target);
+ break;
+ case PVFS_TYPE_DIRDATA:
+ printf("dirdata ");
+ break;
+ }
+ printf(" %s\n", server_name);
+ }
+ }
+ }
+
+ if(!header)
+ {
+ printf("No stranded objects found.\n");
+ }
+
+ return ret;
+}
+
+/**
+ * Compares two handles, for qsort()
+ *
+ * \retval 0 if equal
+ * \retval <0 if handle1 less than handle2
+ * \retval >0 if handle1 greater than handle2
+ */
+static int compare_handles(
+ const void *handle1, /**< handle 1*/
+ const void *handle2) /**< handle 2*/
+{
+ PVFS_size temp_handle =
+ *((PVFS_handle *) handle1) - *((PVFS_handle *) handle2);
+
+ if (temp_handle > 0)
+ {
+ return 1;
+ }
+ else if (temp_handle < 0)
+ {
+ return -1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+/**
+ * Set the return code for a function, taking previous return values into
+ * account. The purpose of this is to make sure when we are propigating
+ * errors that warnings do not take precident over standard error codes.
+ */
+static void set_return_code(
+ int *ret, /**< error code to populate */
+ const int retval) /**< the value we are proposing to set the error code to */
+{
+ if (*ret >= 0)
+ {
+ *ret = retval;
+ }
+ else if (retval != 0)
+ {
+ *ret = retval;
+ }
+}
+
+/* @} */
+
+/*
+ * Local variables:
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * End:
+ *
+ * vim: ts=8 sts=4 sw=4 expandtab
+ */
Index: pvfs2-debug.c
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/common/misc/pvfs2-debug.c,v
diff -p -u -r1.43.2.3 -r1.43.2.4
--- pvfs2-debug.c 2 Dec 2006 11:20:33 -0000 1.43.2.3
+++ pvfs2-debug.c 13 Jan 2007 10:16:42 -0000 1.43.2.4
@@ -108,6 +108,8 @@ static __keyword_mask_t s_keyword_mask_m
{ "access_hostnames", GOSSIP_ACCESS_HOSTNAMES },
/* Show the client device events */
{ "dev", GOSSIP_DEV_DEBUG },
+ /* Debug the fsck tool */
+ { "fsck", GOSSIP_FSCK_DEBUG },
/* Everything except the periodic events. Useful for debugging */
{ "verbose",
(__DEBUG_ALL & ~(GOSSIP_PERFCOUNTER_DEBUG | GOSSIP_STATE_MACHINE_DEBUG))
Index: module.mk.in
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/common/misc/module.mk.in,v
diff -p -u -r1.26.14.3 -r1.26.14.4
--- module.mk.in 27 Sep 2006 08:57:26 -0000 1.26.14.3
+++ module.mk.in 13 Jan 2007 10:16:42 -0000 1.26.14.4
@@ -16,7 +16,8 @@ LIBSRC += $(DIR)/server-config.c \
$(DIR)/msgpairarray.c \
$(DIR)/pint-util.c \
$(DIR)/realpath.c \
- $(DIR)/tcache.c
+ $(DIR)/tcache.c \
+ $(DIR)/fsck-utils.c
SERVERSRC += $(DIR)/server-config.c \
$(DIR)/server-config-mgr.c \
$(DIR)/str-utils.c \
Index: pint-util.c
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/common/misc/pint-util.c,v
diff -p -u -r1.13.2.2 -r1.13.2.3
--- pint-util.c 2 Dec 2006 11:20:33 -0000 1.13.2.2
+++ pint-util.c 13 Jan 2007 10:16:42 -0000 1.13.2.3
@@ -526,7 +526,7 @@ static int PINT_check_group(uid_t uid, g
if(ret != 0)
{
gen_mutex_unlock(&check_group_mutex);
- return(-PVFS_ENOENT);
+ return(-PVFS_EINVAL);
}
/* check primary group */
@@ -539,7 +539,15 @@ static int PINT_check_group(uid_t uid, g
if(ret != 0)
{
gen_mutex_unlock(&check_group_mutex);
- return(-PVFS_ENOENT);
+ return(-PVFS_EINVAL);
+ }
+
+ if(grp_p == NULL)
+ {
+ gen_mutex_unlock(&check_group_mutex);
+ gossip_err("User (uid=%d) isn't in group %d on storage node.\n",
+ uid, gid);
+ return(-PVFS_EACCES);
}
gen_mutex_unlock(&check_group_mutex);
Index: pint-perf-counter.c
===================================================================
RCS file: /projects/cvsroot/pvfs2/src/common/misc/pint-perf-counter.c,v
diff -p -u -r1.11.8.1 -r1.11.8.2
--- pint-perf-counter.c 27 Sep 2006 08:57:26 -0000 1.11.8.1
+++ pint-perf-counter.c 13 Jan 2007 10:16:42 -0000 1.11.8.2
@@ -9,6 +9,7 @@
#include <sys/time.h>
#include <assert.h>
#include <stdio.h>
+#include <time.h>
#include "pvfs2-types.h"
#include "pvfs2-util.h"
More information about the Pvfs2-cvs
mailing list