Mercurial > illumos > illumos-gate
changeset 3978:2dd668007b7a
6533813 recursive snapshotting resulted in a bad stack overflow
author | mmusante |
---|---|
date | Thu, 05 Apr 2007 20:34:28 -0700 |
parents | 4d8c8b4553a3 |
children | 4fa53442c9a8 |
files | usr/src/lib/libzfs/common/libzfs.h usr/src/lib/libzfs/common/libzfs_util.c usr/src/uts/common/fs/zfs/dmu_objset.c usr/src/uts/common/fs/zfs/dsl_dataset.c usr/src/uts/common/fs/zfs/dsl_dir.c usr/src/uts/common/fs/zfs/sys/dsl_dir.h |
diffstat | 6 files changed, 79 insertions(+), 11 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/lib/libzfs/common/libzfs.h Thu Apr 05 15:35:55 2007 -0700 +++ b/usr/src/lib/libzfs/common/libzfs.h Thu Apr 05 20:34:28 2007 -0700 @@ -97,6 +97,7 @@ EZFS_POOLPROPS, /* couldn't retrieve pool props */ EZFS_POOL_NOTSUP, /* ops not supported for this type of pool */ EZFS_POOL_INVALARG, /* invalid argument for this pool operation */ + EZFS_NAMETOOLONG, /* dataset name is too long */ EZFS_UNKNOWN };
--- a/usr/src/lib/libzfs/common/libzfs_util.c Thu Apr 05 15:35:55 2007 -0700 +++ b/usr/src/lib/libzfs/common/libzfs_util.c Thu Apr 05 20:34:28 2007 -0700 @@ -167,6 +167,8 @@ case EZFS_POOL_INVALARG: return (dgettext(TEXT_DOMAIN, "invalid argument for " "this pool operation")); + case EZFS_NAMETOOLONG: + return (dgettext(TEXT_DOMAIN, "dataset name is too long")); case EZFS_UNKNOWN: return (dgettext(TEXT_DOMAIN, "unknown error")); default: @@ -306,6 +308,11 @@ "dataset is busy")); zfs_verror(hdl, EZFS_BUSY, fmt, ap); break; + + case ENAMETOOLONG: + zfs_verror(hdl, EZFS_NAMETOOLONG, fmt, ap); + break; + default: zfs_error_aux(hdl, strerror(errno)); zfs_verror(hdl, EZFS_UNKNOWN, fmt, ap);
--- a/usr/src/uts/common/fs/zfs/dmu_objset.c Thu Apr 05 15:35:55 2007 -0700 +++ b/usr/src/uts/common/fs/zfs/dmu_objset.c Thu Apr 05 20:34:28 2007 -0700 @@ -948,7 +948,7 @@ objset_t *os; uint64_t snapobj; zap_cursor_t zc; - zap_attribute_t attr; + zap_attribute_t *attr; char *child; int do_self, err; @@ -958,6 +958,7 @@ /* NB: the $MOS dir doesn't have a head dataset */ do_self = (dd->dd_phys->dd_head_dataset_obj != 0); + attr = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP); /* * Iterate over all children. @@ -965,10 +966,10 @@ if (flags & DS_FIND_CHILDREN) { for (zap_cursor_init(&zc, dd->dd_pool->dp_meta_objset, dd->dd_phys->dd_child_dir_zapobj); - zap_cursor_retrieve(&zc, &attr) == 0; + zap_cursor_retrieve(&zc, attr) == 0; (void) zap_cursor_advance(&zc)) { - ASSERT(attr.za_integer_length == sizeof (uint64_t)); - ASSERT(attr.za_num_integers == 1); + ASSERT(attr->za_integer_length == sizeof (uint64_t)); + ASSERT(attr->za_num_integers == 1); /* * No separating '/' because parent's name ends in /. @@ -977,7 +978,7 @@ /* XXX could probably just use name here */ dsl_dir_name(dd, child); (void) strcat(child, "/"); - (void) strcat(child, attr.za_name); + (void) strcat(child, attr->za_name); err = dmu_objset_find(child, func, arg, flags); kmem_free(child, MAXPATHLEN); if (err) @@ -987,6 +988,7 @@ if (err) { dsl_dir_close(dd, FTAG); + kmem_free(attr, sizeof (zap_attribute_t)); return (err); } } @@ -1002,16 +1004,16 @@ dmu_objset_close(os); for (zap_cursor_init(&zc, dd->dd_pool->dp_meta_objset, snapobj); - zap_cursor_retrieve(&zc, &attr) == 0; + zap_cursor_retrieve(&zc, attr) == 0; (void) zap_cursor_advance(&zc)) { - ASSERT(attr.za_integer_length == sizeof (uint64_t)); - ASSERT(attr.za_num_integers == 1); + ASSERT(attr->za_integer_length == sizeof (uint64_t)); + ASSERT(attr->za_num_integers == 1); child = kmem_alloc(MAXPATHLEN, KM_SLEEP); /* XXX could probably just use name here */ dsl_dir_name(dd, child); (void) strcat(child, "@"); - (void) strcat(child, attr.za_name); + (void) strcat(child, attr->za_name); err = func(child, arg); kmem_free(child, MAXPATHLEN); if (err) @@ -1021,6 +1023,7 @@ } dsl_dir_close(dd, FTAG); + kmem_free(attr, sizeof (zap_attribute_t)); if (err) return (err);
--- a/usr/src/uts/common/fs/zfs/dsl_dataset.c Thu Apr 05 15:35:55 2007 -0700 +++ b/usr/src/uts/common/fs/zfs/dsl_dataset.c Thu Apr 05 20:34:28 2007 -0700 @@ -491,6 +491,32 @@ } } +static int +dsl_dataset_namelen(dsl_dataset_t *ds) +{ + int result; + + if (ds == NULL) { + result = 3; /* "mos" */ + } else { + result = dsl_dir_namelen(ds->ds_dir); + VERIFY(0 == dsl_dataset_get_snapname(ds)); + if (ds->ds_snapname[0]) { + ++result; /* adding one for the @-sign */ + if (!MUTEX_HELD(&ds->ds_lock)) { + /* see dsl_datset_name */ + mutex_enter(&ds->ds_lock); + result += strlen(ds->ds_snapname); + mutex_exit(&ds->ds_lock); + } else { + result += strlen(ds->ds_snapname); + } + } + } + + return (result); +} + void dsl_dataset_close(dsl_dataset_t *ds, int mode, void *tag) { @@ -1328,6 +1354,13 @@ if (err != ENOENT) return (err); + /* + * Check that the dataset's name is not too long. Name consists + * of the dataset's length + 1 for the @-sign + snapshot name's length + */ + if (dsl_dataset_namelen(ds) + 1 + strlen(snapname) >= MAXNAMELEN) + return (ENAMETOOLONG); + ds->ds_trysnap_txg = tx->tx_txg; return (0); }
--- a/usr/src/uts/common/fs/zfs/dsl_dir.c Thu Apr 05 15:35:55 2007 -0700 +++ b/usr/src/uts/common/fs/zfs/dsl_dir.c Thu Apr 05 20:34:28 2007 -0700 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -207,6 +207,29 @@ } } +/* Calculate name legnth, avoiding all the strcat calls of dsl_dir_name */ +int +dsl_dir_namelen(dsl_dir_t *dd) +{ + int result = 0; + + if (dd->dd_parent) { + /* parent's name + 1 for the "/" */ + result = dsl_dir_namelen(dd->dd_parent) + 1; + } + + if (!MUTEX_HELD(&dd->dd_lock)) { + /* see dsl_dir_name */ + mutex_enter(&dd->dd_lock); + result += strlen(dd->dd_myname); + mutex_exit(&dd->dd_lock); + } else { + result += strlen(dd->dd_myname); + } + + return (result); +} + int dsl_dir_is_private(dsl_dir_t *dd) {
--- a/usr/src/uts/common/fs/zfs/sys/dsl_dir.h Thu Apr 05 15:35:55 2007 -0700 +++ b/usr/src/uts/common/fs/zfs/sys/dsl_dir.h Thu Apr 05 20:34:28 2007 -0700 @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -97,6 +97,7 @@ int dsl_dir_open_obj(dsl_pool_t *dp, uint64_t ddobj, const char *tail, void *tag, dsl_dir_t **); void dsl_dir_name(dsl_dir_t *dd, char *buf); +int dsl_dir_namelen(dsl_dir_t *dd); int dsl_dir_is_private(dsl_dir_t *dd); uint64_t dsl_dir_create_sync(dsl_dir_t *pds, const char *name, dmu_tx_t *tx); void dsl_dir_create_root(objset_t *mos, uint64_t *ddobjp, dmu_tx_t *tx);