From d0c6e97fa53ae26dec458087e96dcbb0ed0d469a Mon Sep 17 00:00:00 2001 From: Fan Yong Date: Fri, 4 Nov 2016 20:28:31 +0800 Subject: [PATCH] LU-8900 snapshot: rename filesysetem fsname Introuduce new tunefs options "--rename" for renaming the existing Lustre filesystem fsname with configuration/parameters preserved. Usage: tunefs.lustre --fsname $NEW_FSNAME --rename $OLD_FSNAME ... NEW_FSNAME is the new fsname, must be specified. OLD_FSNAME is the old fsname, it is optional if the MGS and the MDT are combined together. It shares the functionality of fork/erase Lustre configuration logs in kernel. Signed-off-by: Fan Yong Change-Id: Ic9aaf6ed6209c7580bfabd4b660a6a7667576484 Reviewed-on: https://review.whamcloud.com/24268 Reviewed-by: Niu Yawei Reviewed-by: Lai Siyao Reviewed-by: Oleg Drokin Tested-by: Oleg Drokin --- lustre/include/dt_object.h | 4 + lustre/include/lustre_disk.h | 15 +-- lustre/mgs/mgs_handler.c | 4 + lustre/mgs/mgs_internal.h | 1 + lustre/mgs/mgs_llog.c | 135 ++++++++++++++++++++++++ lustre/obdclass/local_storage.c | 59 +++++++---- lustre/tests/conf-sanity.sh | 125 ++++++++++++++++++++++ lustre/tests/test-framework.sh | 17 ++- lustre/utils/mkfs_lustre.c | 100 +++++++++++++++--- lustre/utils/mount_utils.c | 211 +++++++++++++++++++++++++++++++++++++ lustre/utils/mount_utils.h | 5 + lustre/utils/mount_utils_ldiskfs.c | 63 +++++++++++ lustre/utils/mount_utils_zfs.c | 64 +++++++++++ 13 files changed, 756 insertions(+), 47 deletions(-) diff --git a/lustre/include/dt_object.h b/lustre/include/dt_object.h index 537ee16..5c568ee 100644 --- a/lustre/include/dt_object.h +++ b/lustre/include/dt_object.h @@ -1975,6 +1975,10 @@ int local_object_create(const struct lu_env *env, struct dt_object *o, struct lu_attr *attr, struct dt_object_format *dof, struct thandle *th); +struct dt_object *local_file_find(const struct lu_env *env, + struct local_oid_storage *los, + struct dt_object *parent, + const char *name); struct dt_object *local_file_find_or_create(const struct lu_env *env, struct local_oid_storage *los, struct dt_object *parent, diff --git a/lustre/include/lustre_disk.h b/lustre/include/lustre_disk.h index 2841f6a..90e6629 100644 --- a/lustre/include/lustre_disk.h +++ b/lustre/include/lustre_disk.h @@ -119,6 +119,8 @@ #define LDD_F_MASK 0xFFFF +#define XATTR_TARGET_RENAME "trusted.rename_tgt" + enum ldd_mount_type { LDD_MT_EXT3 = 0, LDD_MT_LDISKFS, @@ -184,12 +186,13 @@ struct lustre_disk_data { }; -#define IS_MDT(data) ((data)->lsi_flags & LDD_F_SV_TYPE_MDT) -#define IS_OST(data) ((data)->lsi_flags & LDD_F_SV_TYPE_OST) -#define IS_MGS(data) ((data)->lsi_flags & LDD_F_SV_TYPE_MGS) -#define IS_SERVER(data) ((data)->lsi_flags & (LDD_F_SV_TYPE_MGS | \ - LDD_F_SV_TYPE_MDT | LDD_F_SV_TYPE_OST)) -#define MT_STR(data) mt_str((data)->ldd_mount_type) +#define IS_MDT(data) ((data)->lsi_flags & LDD_F_SV_TYPE_MDT) +#define IS_OST(data) ((data)->lsi_flags & LDD_F_SV_TYPE_OST) +#define IS_MGS(data) ((data)->lsi_flags & LDD_F_SV_TYPE_MGS) +#define IS_SEPARATED_MGS(data) ((data)->ldd_flags == LDD_F_SV_TYPE_MGS) +#define IS_SERVER(data) ((data)->lsi_flags & (LDD_F_SV_TYPE_MGS | \ + LDD_F_SV_TYPE_MDT | LDD_F_SV_TYPE_OST)) +#define MT_STR(data) mt_str((data)->ldd_mount_type) /* Make the mdt/ost server obd name based on the filesystem name */ static inline bool server_make_name(__u32 flags, __u16 index, char *fs, diff --git a/lustre/mgs/mgs_handler.c b/lustre/mgs/mgs_handler.c index 36ed177..a21acf3 100644 --- a/lustre/mgs/mgs_handler.c +++ b/lustre/mgs/mgs_handler.c @@ -1294,6 +1294,10 @@ static int mgs_init0(const struct lu_env *env, struct mgs_device *mgs, mutex_init(&mgs->mgs_health_mutex); init_rwsem(&mgs->mgs_barrier_rwsem); + rc = mgs_lcfg_rename(env, mgs); + if (rc) + GOTO(err_llog, rc); + rc = lproc_mgs_setup(mgs, lustre_cfg_string(lcfg, 3)); if (rc != 0) { CERROR("%s: cannot initialize proc entry: rc = %d\n", diff --git a/lustre/mgs/mgs_internal.h b/lustre/mgs/mgs_internal.h index 88cf7e8..634a9fe 100644 --- a/lustre/mgs/mgs_internal.h +++ b/lustre/mgs/mgs_internal.h @@ -426,5 +426,6 @@ int mgs_lcfg_fork(const struct lu_env *env, struct mgs_device *mgs, const char *oldname, const char *newname); int mgs_lcfg_erase(const struct lu_env *env, struct mgs_device *mgs, const char *fsname); +int mgs_lcfg_rename(const struct lu_env *env, struct mgs_device *mgs); #endif /* _MGS_INTERNAL_H */ diff --git a/lustre/mgs/mgs_llog.c b/lustre/mgs/mgs_llog.c index 15102e0..407667d 100644 --- a/lustre/mgs/mgs_llog.c +++ b/lustre/mgs/mgs_llog.c @@ -4517,6 +4517,141 @@ int mgs_lcfg_erase(const struct lu_env *env, struct mgs_device *mgs, RETURN(rc); } +static int mgs_xattr_del(const struct lu_env *env, struct dt_object *obj) +{ + struct dt_device *dev; + struct thandle *th = NULL; + int rc = 0; + + ENTRY; + + dev = container_of0(obj->do_lu.lo_dev, struct dt_device, dd_lu_dev); + th = dt_trans_create(env, dev); + if (IS_ERR(th)) + RETURN(PTR_ERR(th)); + + rc = dt_declare_xattr_del(env, obj, XATTR_TARGET_RENAME, th); + if (rc) + GOTO(stop, rc); + + rc = dt_trans_start_local(env, dev, th); + if (rc) + GOTO(stop, rc); + + dt_write_lock(env, obj, 0); + rc = dt_xattr_del(env, obj, XATTR_TARGET_RENAME, th); + + GOTO(unlock, rc); + +unlock: + dt_write_unlock(env, obj); + +stop: + dt_trans_stop(env, dev, th); + + return rc; +} + +int mgs_lcfg_rename(const struct lu_env *env, struct mgs_device *mgs) +{ + struct list_head log_list; + struct mgs_direntry *dirent, *n; + char fsname[16]; + struct lu_buf buf = { + .lb_buf = fsname, + .lb_len = sizeof(fsname) + }; + int rc = 0; + + ENTRY; + + rc = class_dentry_readdir(env, mgs, &log_list); + if (rc) + RETURN(rc); + + if (list_empty(&log_list)) + RETURN(0); + + list_for_each_entry_safe(dirent, n, &log_list, mde_list) { + struct dt_object *o = NULL; + char oldname[16]; + char *ptr; + int len; + + list_del_init(&dirent->mde_list); + ptr = strrchr(dirent->mde_name, '-'); + if (!ptr) + goto next; + + len = ptr - dirent->mde_name; + if (unlikely(len >= sizeof(oldname))) { + CDEBUG(D_MGS, "Skip invalid configuration file %s\n", + dirent->mde_name); + goto next; + } + + o = local_file_find(env, mgs->mgs_los, mgs->mgs_configs_dir, + dirent->mde_name); + if (IS_ERR(o)) { + rc = PTR_ERR(o); + CDEBUG(D_MGS, "Fail to locate file %s: rc = %d\n", + dirent->mde_name, rc); + goto next; + } + + rc = dt_xattr_get(env, o, &buf, XATTR_TARGET_RENAME); + if (rc < 0) { + if (rc == -ENODATA) + rc = 0; + else + CDEBUG(D_MGS, + "Fail to get EA for %s: rc = %d\n", + dirent->mde_name, rc); + goto next; + } + + if (unlikely(rc == len && + memcmp(fsname, dirent->mde_name, len) == 0)) { + /* The new fsname is the same as the old one. */ + rc = mgs_xattr_del(env, o); + goto next; + } + + memcpy(oldname, dirent->mde_name, len); + oldname[len] = '\0'; + fsname[rc] = '\0'; + rc = mgs_lcfg_fork_one(env, mgs, dirent, oldname, fsname); + if (rc && rc != -EEXIST) { + CDEBUG(D_MGS, "Fail to fork %s: rc = %d\n", + dirent->mde_name, rc); + goto next; + } + + rc = mgs_erase_log(env, mgs, dirent->mde_name); + if (rc) { + CDEBUG(D_MGS, "Fail to erase old %s: rc = %d\n", + dirent->mde_name, rc); + /* keep it there if failed to remove it. */ + rc = 0; + } + +next: + if (o && !IS_ERR(o)) + lu_object_put(env, &o->do_lu); + + mgs_direntry_free(dirent); + if (rc) + break; + } + + list_for_each_entry_safe(dirent, n, &log_list, mde_list) { + list_del_init(&dirent->mde_list); + mgs_direntry_free(dirent); + } + + RETURN(rc); +} + /* from llog_swab */ static void print_lustre_cfg(struct lustre_cfg *lcfg) { diff --git a/lustre/obdclass/local_storage.c b/lustre/obdclass/local_storage.c index ffcf104..c15624e 100644 --- a/lustre/obdclass/local_storage.c +++ b/lustre/obdclass/local_storage.c @@ -425,6 +425,28 @@ out: RETURN(dto); } +struct dt_object *local_file_find(const struct lu_env *env, + struct local_oid_storage *los, + struct dt_object *parent, + const char *name) +{ + struct dt_thread_info *dti = dt_info(env); + struct dt_object *dto; + int rc; + + LASSERT(parent); + + rc = dt_lookup_dir(env, parent, name, &dti->dti_fid); + if (!rc) + dto = ls_locate(env, dt2ls_dev(los->los_dev), + &dti->dti_fid, NULL); + else + dto = ERR_PTR(rc); + + return dto; +} +EXPORT_SYMBOL(local_file_find); + /* * Look up and create (if it does not exist) a local named file or directory in * parent directory. @@ -438,30 +460,21 @@ struct dt_object *local_file_find_or_create(const struct lu_env *env, struct dt_object *dto; int rc; - LASSERT(parent); + dto = local_file_find(env, los, parent, name); + if (!IS_ERR(dto) || PTR_ERR(dto) != -ENOENT) + return dto; - rc = dt_lookup_dir(env, parent, name, &dti->dti_fid); - if (rc == 0) - /* name is found, get the object */ - dto = ls_locate(env, dt2ls_dev(los->los_dev), - &dti->dti_fid, NULL); - else if (rc != -ENOENT) - dto = ERR_PTR(rc); - else { - rc = local_object_fid_generate(env, los, &dti->dti_fid); - if (rc < 0) { - dto = ERR_PTR(rc); - } else { - /* create the object */ - dti->dti_attr.la_valid = LA_MODE; - dti->dti_attr.la_mode = mode; - dti->dti_dof.dof_type = dt_mode_to_dft(mode & S_IFMT); - dto = __local_file_create(env, &dti->dti_fid, los, - dt2ls_dev(los->los_dev), - parent, name, &dti->dti_attr, - &dti->dti_dof); - } - } + rc = local_object_fid_generate(env, los, &dti->dti_fid); + if (rc) + return ERR_PTR(rc); + + /* create the object */ + dti->dti_attr.la_valid = LA_MODE; + dti->dti_attr.la_mode = mode; + dti->dti_dof.dof_type = dt_mode_to_dft(mode & S_IFMT); + dto = __local_file_create(env, &dti->dti_fid, los, + dt2ls_dev(los->los_dev), parent, name, + &dti->dti_attr, &dti->dti_dof); return dto; } EXPORT_SYMBOL(local_file_find_or_create); diff --git a/lustre/tests/conf-sanity.sh b/lustre/tests/conf-sanity.sh index 5ee57af..6d95b78 100755 --- a/lustre/tests/conf-sanity.sh +++ b/lustre/tests/conf-sanity.sh @@ -7076,6 +7076,131 @@ test_102() { } run_test 102 "obdclass module cleanup upon error" +test_renamefs() { + local newname=$1 + + echo "rename $FSNAME to $newname" + + if [ ! combined_mgs_mds ]; then + local facet=$(mgsdevname) + + do_facet mgs \ + "$TUNEFS --fsname=$newname --rename=$FSNAME -v $facet"|| + error "(7) Fail to rename MGS" + if [ "$(facet_fstype $facet)" = "zfs" ]; then + reimport_zpool mgs $newname-mgs + fi + fi + + for num in $(seq $MDSCOUNT); do + local facet=$(mdsdevname $num) + + do_facet mds${num} \ + "$TUNEFS --fsname=$newname --rename=$FSNAME -v $facet"|| + error "(8) Fail to rename MDT $num" + if [ "$(facet_fstype $facet)" = "zfs" ]; then + reimport_zpool mds${num} $newname-mdt${num} + fi + done + + for num in $(seq $OSTCOUNT); do + local facet=$(ostdevname $num) + + do_facet ost${num} \ + "$TUNEFS --fsname=$newname --rename=$FSNAME -v $facet"|| + error "(9) Fail to rename OST $num" + if [ "$(facet_fstype $facet)" = "zfs" ]; then + reimport_zpool ost${num} $newname-ost${num} + fi + done +} + +test_103_set_pool() { + local pname=$1 + local ost_x=$2 + + do_facet mgs $LCTL pool_add $FSNAME.$pname ${FSNAME}-$ost_x || + error "Fail to add $ost_x to $FSNAME.$pname" + wait_update $HOSTNAME \ + "lctl get_param -n lov.$FSNAME-clilov-*.pools.$pname | + grep $ost_x" "$FSNAME-${ost_x}_UUID" || + error "$ost_x is NOT in pool $FSNAME.$pname" +} + +test_103_check_pool() { + local save_fsname=$1 + local errno=$2 + + stat $DIR/$tdir/test-framework.sh || + error "($errno) Fail to stat" + do_facet mgs $LCTL pool_list $FSNAME.pool1 || + error "($errno) Fail to list $FSNAME.pool1" + do_facet mgs $LCTL pool_list $FSNAME.$save_fsname || + error "($errno) Fail to list $FSNAME.$save_fsname" + do_facet mgs $LCTL pool_list $FSNAME.$save_fsname | + grep ${FSNAME}-OST0000 || + error "($errno) List $FSNAME.$save_fsname is invalid" + + local pname=$($LFS getstripe --pool $DIR/$tdir/d0) + [ "$pname" = "$save_fsname" ] || + error "($errno) Unexpected pool name $pname" +} + +test_103() { + check_mount_and_prep + rm -rf $DIR/$tdir + mkdir $DIR/$tdir || error "(1) Fail to mkdir $DIR/$tdir" + cp $LUSTRE/tests/test-framework.sh $DIR/$tdir || + error "(2) Fail to copy test-framework.sh" + + do_facet mgs $LCTL pool_new $FSNAME.pool1 || + error "(3) Fail to create $FSNAME.pool1" + # name the pool name as the fsname + do_facet mgs $LCTL pool_new $FSNAME.$FSNAME || + error "(4) Fail to create $FSNAME.$FSNAME" + + test_103_set_pool $FSNAME OST0000 + + $SETSTRIPE -p $FSNAME $DIR/$tdir/d0 || + error "(6) Fail to setstripe on $DIR/$tdir/d0" + + KEEP_ZPOOL=true + stopall + + test_renamefs mylustre + + local save_fsname=$FSNAME + FSNAME="mylustre" + setupall + + test_103_check_pool $save_fsname 7 + + if [ $OSTCOUNT -ge 2 ]; then + test_103_set_pool $save_fsname OST0001 + fi + + $SETSTRIPE -p $save_fsname $DIR/$tdir/f0 || + error "(16) Fail to setstripe on $DIR/$tdir/f0" + + stopall + + test_renamefs tfs + + FSNAME="tfs" + setupall + + test_103_check_pool $save_fsname 17 + + stopall + + test_renamefs $save_fsname + + FSNAME=$save_fsname + setupall + KEEP_ZPOOL=false +} +run_test 103 "rename filesystem name" + if ! combined_mgs_mds ; then stop mgs fi diff --git a/lustre/tests/test-framework.sh b/lustre/tests/test-framework.sh index 623caca..1a1ad31 100755 --- a/lustre/tests/test-framework.sh +++ b/lustre/tests/test-framework.sh @@ -139,6 +139,7 @@ init_test_env() { export FAIL_ON_SKIP_ENV=${FAIL_ON_SKIP_ENV:-false} export RPC_MODE=${RPC_MODE:-false} export DO_CLEANUP=${DO_CLEANUP:-true} + export KEEP_ZPOOL=${KEEP_ZPOOL:-false} export MKE2FS=$MKE2FS if [ -z "$MKE2FS" ]; then @@ -1110,6 +1111,20 @@ import_zpool() { } # +# Reimport ZFS storage pool with new name +# +reimport_zpool() { + local facet=$1 + local newpool=$2 + local opts="-o cachefile=none" + local poolname=$(zpool_name $facet) + + opts+=" -d $(dirname $(facet_vdevice $facet))" + do_facet $facet "$ZPOOL export $poolname; + $ZPOOL import $opts $poolname $newpool" +} + +# # Set the "cachefile=none" property on ZFS storage pool so that the pool # is not automatically imported on system startup. # @@ -1398,7 +1413,7 @@ stop() { if [[ $(facet_fstype $facet) == zfs ]]; then # export ZFS storage pool - export_zpool $facet + [ "$KEEP_ZPOOL" = "true" ] || export_zpool $facet fi } diff --git a/lustre/utils/mkfs_lustre.c b/lustre/utils/mkfs_lustre.c index e426f64..ab813fa 100644 --- a/lustre/utils/mkfs_lustre.c +++ b/lustre/utils/mkfs_lustre.c @@ -119,9 +119,10 @@ void usage(FILE *out) "cache, log)\n" #endif "\n" -#ifndef TUNEFS "\ttarget types:\n" "\t\t--mgs: configuration management service\n" + "\t\t--nomgs: turn off MGS service on this MDT\n" +#ifndef TUNEFS "\t\t--mdt: metadata storage, mutually exclusive with ost\n" "\t\t--ost: object storage, mutually exclusive with mdt, mgs\n" #endif @@ -154,9 +155,9 @@ void usage(FILE *out) "\t\t--stripe-count-hint=#N: for optimizing MDT inode size\n" #else "\t\t--erase-params: erase all old parameter settings\n" - "\t\t--nomgs: turn off MGS service on this MDT\n" "\t\t--writeconf: erase all config logs for this fs.\n" "\t\t--quota: enable space accounting on old 2.x device.\n" + "\t\t--rename: rename the filesystem name\n" #endif "\t\t--comment=: arbitrary string (%d bytes)\n" "\t\t--dryrun: report what we would do; don't write to disk\n" @@ -274,18 +275,20 @@ static char *convert_hostnames(char *s1) } int parse_opts(int argc, char *const argv[], struct mkfs_opts *mop, - char **mountopts) + char **mountopts, char *old_fsname) { static struct option long_opt[] = { { "backfs-mount-opts", required_argument, NULL, 'B' }, { "failnode", required_argument, NULL, 'f' }, { "failover", required_argument, NULL, 'f' }, + { "mgs", no_argument, NULL, 'G' }, { "help", no_argument, NULL, 'h' }, { "index", required_argument, NULL, 'i' }, { "fsname", required_argument, NULL, 'L' }, { "mgsnode", required_argument, NULL, 'm' }, { "mgsnid", required_argument, NULL, 'm' }, { "dryrun", no_argument, NULL, 'n' }, + { "nomgs", no_argument, NULL, 'N' }, { "mountfsoptions", required_argument, NULL, 'o' }, { "param", required_argument, NULL, 'p' }, { "quiet", no_argument, NULL, 'q' }, @@ -299,25 +302,24 @@ int parse_opts(int argc, char *const argv[], struct mkfs_opts *mop, { "backfstype", required_argument, NULL, 'b' }, { "stripe-count-hint", required_argument, NULL, 'c' }, { "device-size", required_argument, NULL, 'd' }, - { "mgs", no_argument, NULL, 'G' }, { "mkfsoptions", required_argument, NULL, 'k' }, { "mdt", no_argument, NULL, 'M' }, - { "nomgs", no_argument, NULL, 'N' }, { "ost", no_argument, NULL, 'O' }, { "reformat", no_argument, NULL, 'r' }, { "replace", no_argument, NULL, 'R' }, #else { "erase-params", no_argument, NULL, 'e' }, { "quota", no_argument, NULL, 'Q' }, + { "rename", optional_argument, NULL, 'R' }, { "writeconf", no_argument, NULL, 'w' }, #endif { 0, 0, NULL, 0 } }; - char *optstring = "B:f:hi:L:m:no:p:qs:t:u:vV" + char *optstring = "B:f:Ghi:L:m:nNo:p:qs:t:u:vV" #ifndef TUNEFS - "b:c:d:Gk:MNOrR"; + "b:c:d:k:MOrR"; #else - "eQw"; + "eQR::w"; #endif struct lustre_disk_data *ldd = &mop->mo_ldd; char new_fsname[16] = { 0 }; @@ -368,6 +370,9 @@ int parse_opts(int argc, char *const argv[], struct mkfs_opts *mop, mop->mo_flags |= MO_FAILOVER; break; } + case 'G': + ldd->ldd_flags |= LDD_F_SV_TYPE_MGS; + break; case 'h': usage(stdout); return 1; @@ -434,6 +439,9 @@ int parse_opts(int argc, char *const argv[], struct mkfs_opts *mop, case 'n': print_only++; break; + case 'N': + ldd->ldd_flags &= ~LDD_F_SV_TYPE_MGS; + break; case 'o': *mountopts = optarg; break; @@ -515,9 +523,6 @@ int parse_opts(int argc, char *const argv[], struct mkfs_opts *mop, case 'd': mop->mo_device_kb = atol(optarg); break; - case 'G': - ldd->ldd_flags |= LDD_F_SV_TYPE_MGS; - break; case 'k': strscpy(mop->mo_mkfsopts, optarg, sizeof(mop->mo_mkfsopts)); @@ -525,9 +530,6 @@ int parse_opts(int argc, char *const argv[], struct mkfs_opts *mop, case 'M': ldd->ldd_flags |= LDD_F_SV_TYPE_MDT; break; - case 'N': - ldd->ldd_flags &= ~LDD_F_SV_TYPE_MGS; - break; case 'O': ldd->ldd_flags |= LDD_F_SV_TYPE_OST; break; @@ -546,6 +548,45 @@ int parse_opts(int argc, char *const argv[], struct mkfs_opts *mop, case 'Q': mop->mo_flags |= MO_QUOTA; break; + case 'R': { + char *tmp; + + mop->mo_flags |= MO_RENAME; + if (!optarg) { + if (IS_SEPARATED_MGS(ldd)) { + fprintf(stderr, "%s: must specify the " + "old fsname to be renamed for " + "separated MGS\n", progname); + return 1; + } + break; + } + + if ((strlen(optarg) < 1) || (strlen(optarg) > 8)) { + fprintf(stderr, "%s: filesystem name must be " + "1-8 chars\n", progname); + return 1; + } + + tmp = strpbrk(optarg, "/:"); + if (tmp) { + fprintf(stderr, "%s: char '%c' not allowed in " + "filesystem name\n", progname, *tmp); + return 1; + } + + if (IS_SEPARATED_MGS(ldd)) { + strscpy(old_fsname, optarg, + sizeof(ldd->ldd_fsname)); + } else if (strlen(old_fsname) != strlen(optarg) || + strcmp(old_fsname, optarg) != 0) { + fprintf(stderr, "%s: the given fsname '%s' " + "to be renamed does not exist\n", + progname, optarg); + return 1; + } + break; + } case 'w': ldd->ldd_flags |= LDD_F_WRITECONF; break; @@ -560,7 +601,7 @@ int parse_opts(int argc, char *const argv[], struct mkfs_opts *mop, } if (strlen(new_fsname) > 0) { - if (!(mop->mo_flags & MO_FORCEFORMAT) && + if (!(mop->mo_flags & (MO_FORCEFORMAT | MO_RENAME)) && (!(ldd->ldd_flags & (LDD_F_UPGRADE14 | LDD_F_VIRGIN | LDD_F_WRITECONF)))) { fprintf(stderr, "%s: cannot change the name " @@ -579,6 +620,22 @@ int parse_opts(int argc, char *const argv[], struct mkfs_opts *mop, return 1; } +#ifdef TUNEFS + if (mop->mo_flags & MO_RENAME) { + if (new_fsname[0] == '\0') { + fprintf(stderr, "%s: need to specify new fsname for " + "renaming case\n", progname); + return 1; + } + + if (strcmp(old_fsname, new_fsname) == 0) { + fprintf(stderr, "%s: cannot rename fsname '%s' to " + "the same name\n", progname, old_fsname); + return 1; + } + } +#endif + /* Need to clear this flag after parsing 'L' and 'i' options. */ if (replace) ldd->ldd_flags &= ~LDD_F_VIRGIN; @@ -607,6 +664,7 @@ int main(int argc, char *const argv[]) struct lustre_disk_data *ldd = &mop.mo_ldd; char *mountopts = NULL; char wanted_mountopts[512] = ""; + char old_fsname[16] = ""; unsigned mount_type; int ret = 0; int ret2 = 0; @@ -655,6 +713,7 @@ int main(int argc, char *const argv[]) goto out; } + strscpy(old_fsname, ldd->ldd_fsname, sizeof(ldd->ldd_fsname)); ldd->ldd_flags &= ~(LDD_F_WRITECONF | LDD_F_VIRGIN); /* svname of the form lustre:OST1234 means never registered */ @@ -674,7 +733,7 @@ int main(int argc, char *const argv[]) print_ldd("Read previous values", ldd); #endif /* TUNEFS */ - ret = parse_opts(argc, argv, &mop, &mountopts); + ret = parse_opts(argc, argv, &mop, &mountopts, old_fsname); if (ret != 0 || version) goto out; @@ -839,7 +898,7 @@ int main(int argc, char *const argv[]) fprintf(stderr, "mkfs failed %d\n", ret); goto out; } -#else /* !TUNEFS */ +#else /* TUNEFS */ /* update svname with '=' to refresh config */ if (ldd->ldd_flags & LDD_F_WRITECONF) { struct mount_opts opts; @@ -848,6 +907,13 @@ int main(int argc, char *const argv[]) (void) osd_label_lustre(&opts); } + /* Rename filesystem fsname */ + if (mop.mo_flags & MO_RENAME) { + ret = osd_rename_fsname(&mop, old_fsname); + if (ret) + goto out; + } + /* Enable quota accounting */ if (mop.mo_flags & MO_QUOTA) { ret = osd_enable_quota(&mop); diff --git a/lustre/utils/mount_utils.c b/lustre/utils/mount_utils.c index 2027b28..db05359 100644 --- a/lustre/utils/mount_utils.c +++ b/lustre/utils/mount_utils.c @@ -51,6 +51,11 @@ #include #include #include +#include +#include +#include +#include +#include #ifdef HAVE_GSS #include @@ -586,6 +591,7 @@ struct module_backfs_ops *load_backfs_module(enum ldd_mount_type mount_type) DLSYM(name, ops, prepare_lustre); DLSYM(name, ops, tune_lustre); DLSYM(name, ops, label_lustre); + DLSYM(name, ops, rename_fsname); DLSYM(name, ops, enable_quota); error = dlerror(); @@ -748,6 +754,21 @@ int osd_label_lustre(struct mount_opts *mop) return ret; } +/* Rename filesystem fsname */ +int osd_rename_fsname(struct mkfs_opts *mop, const char *oldname) +{ + struct lustre_disk_data *ldd = &mop->mo_ldd; + int ret; + + if (backfs_mount_type_okay(ldd->ldd_mount_type)) + ret = backfs_ops[ldd->ldd_mount_type]->rename_fsname(mop, + oldname); + else + ret = EINVAL; + + return ret; +} + /* Enable quota accounting */ int osd_enable_quota(struct mkfs_opts *mop) { @@ -875,6 +896,196 @@ int file_create(char *path, __u64 size) return 0; } + +struct lustre_cfg_entry { + struct list_head lce_list; + char lce_name[0]; +}; + +static struct lustre_cfg_entry *lustre_cfg_entry_init(const char *name) +{ + struct lustre_cfg_entry *lce; + int len = strlen(name) + 1; + + lce = malloc(sizeof(*lce) + len); + if (lce) { + INIT_LIST_HEAD(&lce->lce_list); + memcpy(lce->lce_name, name, len); + } + + return lce; +} + +static void lustre_cfg_entry_fini(struct lustre_cfg_entry *lce) +{ + free(lce); +} + +int lustre_rename_fsname(struct mkfs_opts *mop, const char *mntpt, + const char *oldname) +{ + struct lustre_disk_data *ldd = &mop->mo_ldd; + struct lr_server_data lsd; + char filepnm[128]; + char cfg_dir[128]; + DIR *dir = NULL; + struct dirent64 *dirent; + struct lustre_cfg_entry *lce; + struct list_head cfg_list; + int old_namelen = strlen(oldname); + int new_namelen = strlen(ldd->ldd_fsname); + int ret; + int fd; + + INIT_LIST_HEAD(&cfg_list); + + snprintf(filepnm, sizeof(filepnm), "%s/%s", mntpt, LAST_RCVD); + fd = open(filepnm, O_RDWR); + if (fd < 0) { + if (errno == ENOENT) + goto config; + + if (errno != 0) + ret = errno; + else + ret = fd; + fprintf(stderr, "Unable to open %s: %s\n", + filepnm, strerror(ret)); + return ret; + } + + ret = read(fd, &lsd, sizeof(lsd)); + if (ret != sizeof(lsd)) { + if (errno != 0) + ret = errno; + fprintf(stderr, "Unable to read %s: %s\n", + filepnm, strerror(ret)); + close(fd); + return ret; + } + + ret = lseek(fd, 0, SEEK_SET); + if (ret) { + if (errno != 0) + ret = errno; + fprintf(stderr, "Unable to lseek %s: %s\n", + filepnm, strerror(ret)); + close(fd); + return ret; + } + + /* replace fsname in lr_server_data::lsd_uuid. */ + if (old_namelen > new_namelen) + memmove(lsd.lsd_uuid + new_namelen, + lsd.lsd_uuid + old_namelen, + sizeof(lsd.lsd_uuid) - old_namelen); + else if (old_namelen < new_namelen) + memmove(lsd.lsd_uuid + new_namelen, + lsd.lsd_uuid + old_namelen, + sizeof(lsd.lsd_uuid) - new_namelen); + memcpy(lsd.lsd_uuid, ldd->ldd_fsname, new_namelen); + ret = write(fd, &lsd, sizeof(lsd)); + if (ret != sizeof(lsd)) { + if (errno != 0) + ret = errno; + fprintf(stderr, "Unable to write %s: %s\n", + filepnm, strerror(ret)); + close(fd); + return ret; + } + + close(fd); + +config: + snprintf(cfg_dir, sizeof(cfg_dir), "%s/%s", mntpt, MOUNT_CONFIGS_DIR); + dir = opendir(cfg_dir); + if (!dir) { + if (errno != 0) + ret = errno; + else + ret = EINVAL; + fprintf(stderr, "Unable to opendir %s: %s\n", + cfg_dir, strerror(ret)); + return ret; + } + + while ((dirent = readdir64(dir)) != NULL) { + char *ptr; + + if (strlen(dirent->d_name) <= old_namelen) + continue; + + ptr = strrchr(dirent->d_name, '-'); + if (!ptr || (ptr - dirent->d_name) != old_namelen) + continue; + + if (strncmp(dirent->d_name, oldname, old_namelen) != 0) + continue; + + lce = lustre_cfg_entry_init(dirent->d_name); + if (!lce) { + if (errno != 0) + ret = errno; + else + ret = EINVAL; + + fprintf(stderr, "Fail to init item for %s: %s\n", + dirent->d_name, strerror(ret)); + goto out; + } + + list_add(&lce->lce_list, &cfg_list); + } + + closedir(dir); + dir = NULL; + ret = 0; + + while (!list_empty(&cfg_list) && ret == 0) { + lce = list_entry(cfg_list.next, struct lustre_cfg_entry, + lce_list); + list_del(&lce->lce_list); + snprintf(filepnm, sizeof(filepnm), "%s/%s", cfg_dir, + lce->lce_name); + if (IS_MGS(ldd)) + /* Store the new fsname in the XATTR_TARGET_RENAME EA. + * When the MGS start, it will scan config logs, and + * for the ones which have the XATTR_TARGET_RENAME EA, + * it will replace old fsname with the new fsname in + * the config log by some shared kernel level config + * logs {fork,erase} functionalities automatically. */ + ret = setxattr(filepnm, XATTR_TARGET_RENAME, + ldd->ldd_fsname, + strlen(ldd->ldd_fsname), 0); + else + ret = unlink(filepnm); + + if (ret) { + if (errno != 0) + ret = errno; + + fprintf(stderr, "Fail to %s %s: %s\n", + IS_MGS(ldd) ? "setxattr" : "unlink", + filepnm, strerror(ret)); + } + + lustre_cfg_entry_fini(lce); + } + +out: + if (dir) + closedir(dir); + + while (!list_empty(&cfg_list)) { + lce = list_entry(cfg_list.next, struct lustre_cfg_entry, + lce_list); + list_del(&lce->lce_list); + lustre_cfg_entry_fini(lce); + } + + return ret; +} + #ifdef HAVE_GSS #ifdef HAVE_OPENSSL_SSK int load_shared_keys(struct mount_opts *mop) diff --git a/lustre/utils/mount_utils.h b/lustre/utils/mount_utils.h index 16206a0..2b1ac8f 100644 --- a/lustre/utils/mount_utils.h +++ b/lustre/utils/mount_utils.h @@ -72,6 +72,7 @@ extern int failover; #define MO_DRYRUN 0x08 #define MO_QUOTA 0x10 #define MO_NOHOSTID_CHECK 0x20 +#define MO_RENAME 0x40 #define MAX_LOOP_DEVICES 16 #define INDEX_UNASSIGNED 0xFFFF @@ -141,6 +142,8 @@ int update_utab_entry(struct mount_opts *mop); int check_mountfsoptions(char *mountopts, char *wanted_mountopts); void trim_mountfsoptions(char *s); __u64 get_device_size(char* device); +int lustre_rename_fsname(struct mkfs_opts *mop, const char *mntpt, + const char *oldname); /* loopback helper functions */ int file_create(char *path, __u64 size); @@ -158,6 +161,7 @@ int osd_prepare_lustre(struct mkfs_opts *mop, int osd_fix_mountopts(struct mkfs_opts *mop, char *mountopts, size_t len); int osd_tune_lustre(char *dev, struct mount_opts *mop); int osd_label_lustre(struct mount_opts *mop); +int osd_rename_fsname(struct mkfs_opts *mop, const char *oldname); int osd_enable_quota(struct mkfs_opts *mop); int osd_init(void); void osd_fini(void); @@ -176,6 +180,7 @@ struct module_backfs_ops { int (*tune_lustre)(char *dev, struct mount_opts *mop); int (*label_lustre)(struct mount_opts *mop); int (*enable_quota)(struct mkfs_opts *mop); + int (*rename_fsname)(struct mkfs_opts *mop, const char *oldname); void *dl_handle; }; diff --git a/lustre/utils/mount_utils_ldiskfs.c b/lustre/utils/mount_utils_ldiskfs.c index d93a483..b1edf54 100644 --- a/lustre/utils/mount_utils_ldiskfs.c +++ b/lustre/utils/mount_utils_ldiskfs.c @@ -1314,6 +1314,69 @@ int ldiskfs_label_lustre(struct mount_opts *mop) return rc; } +int ldiskfs_rename_fsname(struct mkfs_opts *mop, const char *oldname) +{ + struct mount_opts opts; + struct lustre_disk_data *ldd = &mop->mo_ldd; + char mntpt[] = "/tmp/mntXXXXXX"; + char *dev; + int ret; + + /* Change the filesystem label. */ + opts.mo_ldd = *ldd; + opts.mo_source = mop->mo_device; + ret = ldiskfs_label_lustre(&opts); + if (ret) { + if (errno != 0) + ret = errno; + fprintf(stderr, "Can't change filesystem label: %s\n", + strerror(ret)); + return ret; + } + + /* Mount this device temporarily in order to write these files */ + if (mkdtemp(mntpt) == NULL) { + if (errno != 0) + ret = errno; + else + ret = EINVAL; + fprintf(stderr, "Can't create temp mount point %s: %s\n", + mntpt, strerror(ret)); + return ret; + } + +#ifdef HAVE_SELINUX + /* + * Append file context to mount options if SE Linux is enabled + */ + if (is_selinux_enabled() > 0) + append_context_for_mount(mntpt, mop); +#endif + + if (mop->mo_flags & MO_IS_LOOP) + dev = mop->mo_loopdev; + else + dev = mop->mo_device; + ret = mount(dev, mntpt, MT_STR(ldd), 0, ldd->ldd_mount_opts); + if (ret) { + if (errno != 0) + ret = errno; + fprintf(stderr, "Unable to mount %s: %s\n", + dev, strerror(ret)); + if (ret == ENODEV) + fprintf(stderr, "Is the %s module available?\n", + MT_STR(ldd)); + goto out_rmdir; + } + + ret = lustre_rename_fsname(mop, mntpt, oldname); + umount(mntpt); + +out_rmdir: + rmdir(mntpt); + return ret; +} + /* Enable quota accounting */ int ldiskfs_enable_quota(struct mkfs_opts *mop) { diff --git a/lustre/utils/mount_utils_zfs.c b/lustre/utils/mount_utils_zfs.c index be29c3f..72dbb69 100644 --- a/lustre/utils/mount_utils_zfs.c +++ b/lustre/utils/mount_utils_zfs.c @@ -680,6 +680,70 @@ int zfs_label_lustre(struct mount_opts *mop) return ret; } +int zfs_rename_fsname(struct mkfs_opts *mop, const char *oldname) +{ + struct mount_opts opts; + char mntpt[] = "/tmp/mntXXXXXX"; + char *cmd_buf; + int ret; + + /* Change the filesystem label. */ + opts.mo_ldd = mop->mo_ldd; + opts.mo_source = mop->mo_device; + ret = zfs_label_lustre(&opts); + if (ret) { + if (errno != 0) + ret = errno; + fprintf(stderr, "Can't change filesystem label: %s\n", + strerror(ret)); + return ret; + } + + /* Mount this device temporarily in order to write these files */ + if (mkdtemp(mntpt) == NULL) { + if (errno != 0) + ret = errno; + fprintf(stderr, "Can't create temp mount point %s: %s\n", + mntpt, strerror(ret)); + return ret; + } + + cmd_buf = malloc(PATH_MAX); + if (!cmd_buf) { + ret = ENOMEM; + goto out_rmdir; + } + + memset(cmd_buf, 0, PATH_MAX); + snprintf(cmd_buf, PATH_MAX - 1, "zfs set mountpoint=%s %s && " + "zfs set canmount=on %s && zfs mount %s", + mntpt, mop->mo_device, mop->mo_device, mop->mo_device); + ret = run_command(cmd_buf, PATH_MAX); + if (ret) { + if (errno != 0) + ret = errno; + fprintf(stderr, "Unable to mount %s (%s)\n", + mop->mo_device, strerror(ret)); + if (ret == ENODEV) + fprintf(stderr, "Is the %s module available?\n", + MT_STR(&mop->mo_ldd)); + goto out_free; + } + + ret = lustre_rename_fsname(mop, mntpt, oldname); + memset(cmd_buf, 0, PATH_MAX); + snprintf(cmd_buf, PATH_MAX - 1, "zfs umount %s && " + "zfs set canmount=off %s && zfs set mountpoint=none %s", + mop->mo_device, mop->mo_device, mop->mo_device); + run_command(cmd_buf, PATH_MAX); + +out_free: + free(cmd_buf); +out_rmdir: + rmdir(mntpt); + return ret; +} + int zfs_init(void) { int ret = 0; -- 1.8.3.1