usr/src/uts/common/fs/zfs/dsl_dir.c
changeset 13980 d7059eb1884c
parent 13975 ef6409bc370f
child 14031 e4eb37f33d60
equal deleted inserted replaced
13979:b01a4832cdf9 13980:d7059eb1884c
    18  *
    18  *
    19  * CDDL HEADER END
    19  * CDDL HEADER END
    20  */
    20  */
    21 /*
    21 /*
    22  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
    22  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
    23  * Copyright (c) 2012 by Delphix. All rights reserved.
    23  * Copyright (c) 2013 by Delphix. All rights reserved.
    24  */
    24  */
    25 
    25 
    26 #include <sys/dmu.h>
    26 #include <sys/dmu.h>
    27 #include <sys/dmu_objset.h>
    27 #include <sys/dmu_objset.h>
    28 #include <sys/dmu_tx.h>
    28 #include <sys/dmu_tx.h>
   247 getcomponent(const char *path, char *component, const char **nextp)
   247 getcomponent(const char *path, char *component, const char **nextp)
   248 {
   248 {
   249 	char *p;
   249 	char *p;
   250 
   250 
   251 	if ((path == NULL) || (path[0] == '\0'))
   251 	if ((path == NULL) || (path[0] == '\0'))
   252 		return (ENOENT);
   252 		return (SET_ERROR(ENOENT));
   253 	/* This would be a good place to reserve some namespace... */
   253 	/* This would be a good place to reserve some namespace... */
   254 	p = strpbrk(path, "/@");
   254 	p = strpbrk(path, "/@");
   255 	if (p && (p[1] == '/' || p[1] == '@')) {
   255 	if (p && (p[1] == '/' || p[1] == '@')) {
   256 		/* two separators in a row */
   256 		/* two separators in a row */
   257 		return (EINVAL);
   257 		return (SET_ERROR(EINVAL));
   258 	}
   258 	}
   259 	if (p == NULL || p == path) {
   259 	if (p == NULL || p == path) {
   260 		/*
   260 		/*
   261 		 * if the first thing is an @ or /, it had better be an
   261 		 * if the first thing is an @ or /, it had better be an
   262 		 * @ and it had better not have any more ats or slashes,
   262 		 * @ and it had better not have any more ats or slashes,
   263 		 * and it had better have something after the @.
   263 		 * and it had better have something after the @.
   264 		 */
   264 		 */
   265 		if (p != NULL &&
   265 		if (p != NULL &&
   266 		    (p[0] != '@' || strpbrk(path+1, "/@") || p[1] == '\0'))
   266 		    (p[0] != '@' || strpbrk(path+1, "/@") || p[1] == '\0'))
   267 			return (EINVAL);
   267 			return (SET_ERROR(EINVAL));
   268 		if (strlen(path) >= MAXNAMELEN)
   268 		if (strlen(path) >= MAXNAMELEN)
   269 			return (ENAMETOOLONG);
   269 			return (SET_ERROR(ENAMETOOLONG));
   270 		(void) strcpy(component, path);
   270 		(void) strcpy(component, path);
   271 		p = NULL;
   271 		p = NULL;
   272 	} else if (p[0] == '/') {
   272 	} else if (p[0] == '/') {
   273 		if (p - path >= MAXNAMELEN)
   273 		if (p - path >= MAXNAMELEN)
   274 			return (ENAMETOOLONG);
   274 			return (SET_ERROR(ENAMETOOLONG));
   275 		(void) strncpy(component, path, p - path);
   275 		(void) strncpy(component, path, p - path);
   276 		component[p - path] = '\0';
   276 		component[p - path] = '\0';
   277 		p++;
   277 		p++;
   278 	} else if (p[0] == '@') {
   278 	} else if (p[0] == '@') {
   279 		/*
   279 		/*
   280 		 * if the next separator is an @, there better not be
   280 		 * if the next separator is an @, there better not be
   281 		 * any more slashes.
   281 		 * any more slashes.
   282 		 */
   282 		 */
   283 		if (strchr(path, '/'))
   283 		if (strchr(path, '/'))
   284 			return (EINVAL);
   284 			return (SET_ERROR(EINVAL));
   285 		if (p - path >= MAXNAMELEN)
   285 		if (p - path >= MAXNAMELEN)
   286 			return (ENAMETOOLONG);
   286 			return (SET_ERROR(ENAMETOOLONG));
   287 		(void) strncpy(component, path, p - path);
   287 		(void) strncpy(component, path, p - path);
   288 		component[p - path] = '\0';
   288 		component[p - path] = '\0';
   289 	} else {
   289 	} else {
   290 		panic("invalid p=%p", (void *)p);
   290 		panic("invalid p=%p", (void *)p);
   291 	}
   291 	}
   315 		return (err);
   315 		return (err);
   316 
   316 
   317 	/* Make sure the name is in the specified pool. */
   317 	/* Make sure the name is in the specified pool. */
   318 	spaname = spa_name(dp->dp_spa);
   318 	spaname = spa_name(dp->dp_spa);
   319 	if (strcmp(buf, spaname) != 0)
   319 	if (strcmp(buf, spaname) != 0)
   320 		return (EINVAL);
   320 		return (SET_ERROR(EINVAL));
   321 
   321 
   322 	ASSERT(dsl_pool_config_held(dp));
   322 	ASSERT(dsl_pool_config_held(dp));
   323 
   323 
   324 	err = dsl_dir_hold_obj(dp, dp->dp_root_dir_obj, NULL, tag, &dd);
   324 	err = dsl_dir_hold_obj(dp, dp->dp_root_dir_obj, NULL, tag, &dd);
   325 	if (err != 0) {
   325 	if (err != 0) {
   366 	if (next != NULL &&
   366 	if (next != NULL &&
   367 	    (tailp == NULL || (nextnext && nextnext[0] != '\0'))) {
   367 	    (tailp == NULL || (nextnext && nextnext[0] != '\0'))) {
   368 		/* bad path name */
   368 		/* bad path name */
   369 		dsl_dir_rele(dd, tag);
   369 		dsl_dir_rele(dd, tag);
   370 		dprintf("next=%p (%s) tail=%p\n", next, next?next:"", tailp);
   370 		dprintf("next=%p (%s) tail=%p\n", next, next?next:"", tailp);
   371 		err = ENOENT;
   371 		err = SET_ERROR(ENOENT);
   372 	}
   372 	}
   373 	if (tailp != NULL)
   373 	if (tailp != NULL)
   374 		*tailp = next;
   374 		*tailp = next;
   375 	*ddp = dd;
   375 	*ddp = dd;
   376 	return (err);
   376 	return (err);
   675 		dprintf_dd(dd, "failing: used=%lluK inflight = %lluK "
   675 		dprintf_dd(dd, "failing: used=%lluK inflight = %lluK "
   676 		    "quota=%lluK tr=%lluK err=%d\n",
   676 		    "quota=%lluK tr=%lluK err=%d\n",
   677 		    used_on_disk>>10, est_inflight>>10,
   677 		    used_on_disk>>10, est_inflight>>10,
   678 		    quota>>10, asize>>10, retval);
   678 		    quota>>10, asize>>10, retval);
   679 		mutex_exit(&dd->dd_lock);
   679 		mutex_exit(&dd->dd_lock);
   680 		return (retval);
   680 		return (SET_ERROR(retval));
   681 	}
   681 	}
   682 
   682 
   683 	/* We need to up our estimated delta before dropping dd_lock */
   683 	/* We need to up our estimated delta before dropping dd_lock */
   684 	dd->dd_tempreserved[txgidx] += asize;
   684 	dd->dd_tempreserved[txgidx] += asize;
   685 
   685 
   738 		err = dsl_pool_tempreserve_space(dd->dd_pool, asize, tx);
   738 		err = dsl_pool_tempreserve_space(dd->dd_pool, asize, tx);
   739 	} else {
   739 	} else {
   740 		if (err == EAGAIN) {
   740 		if (err == EAGAIN) {
   741 			txg_delay(dd->dd_pool, tx->tx_txg,
   741 			txg_delay(dd->dd_pool, tx->tx_txg,
   742 			    MSEC2NSEC(10), MSEC2NSEC(10));
   742 			    MSEC2NSEC(10), MSEC2NSEC(10));
   743 			err = ERESTART;
   743 			err = SET_ERROR(ERESTART);
   744 		}
   744 		}
   745 		dsl_pool_memory_pressure(dd->dd_pool);
   745 		dsl_pool_memory_pressure(dd->dd_pool);
   746 	}
   746 	}
   747 
   747 
   748 	if (err == 0) {
   748 	if (err == 0) {
   948 	 */
   948 	 */
   949 	towrite = dsl_dir_space_towrite(ds->ds_dir);
   949 	towrite = dsl_dir_space_towrite(ds->ds_dir);
   950 	if ((dmu_tx_is_syncing(tx) || towrite == 0) &&
   950 	if ((dmu_tx_is_syncing(tx) || towrite == 0) &&
   951 	    (newval < ds->ds_dir->dd_phys->dd_reserved ||
   951 	    (newval < ds->ds_dir->dd_phys->dd_reserved ||
   952 	    newval < ds->ds_dir->dd_phys->dd_used_bytes + towrite)) {
   952 	    newval < ds->ds_dir->dd_phys->dd_used_bytes + towrite)) {
   953 		error = ENOSPC;
   953 		error = SET_ERROR(ENOSPC);
   954 	}
   954 	}
   955 	mutex_exit(&ds->ds_dir->dd_lock);
   955 	mutex_exit(&ds->ds_dir->dd_lock);
   956 	dsl_dataset_rele(ds, FTAG);
   956 	dsl_dataset_rele(ds, FTAG);
   957 	return (error);
   957 	return (error);
   958 }
   958 }
  1042 		    MAX(used, dd->dd_phys->dd_reserved);
  1042 		    MAX(used, dd->dd_phys->dd_reserved);
  1043 
  1043 
  1044 		if (delta > avail ||
  1044 		if (delta > avail ||
  1045 		    (dd->dd_phys->dd_quota > 0 &&
  1045 		    (dd->dd_phys->dd_quota > 0 &&
  1046 		    newval > dd->dd_phys->dd_quota))
  1046 		    newval > dd->dd_phys->dd_quota))
  1047 			error = ENOSPC;
  1047 			error = SET_ERROR(ENOSPC);
  1048 	}
  1048 	}
  1049 
  1049 
  1050 	dsl_dataset_rele(ds, FTAG);
  1050 	dsl_dataset_rele(ds, FTAG);
  1051 	return (error);
  1051 	return (error);
  1052 }
  1052 }
  1150 	char namebuf[MAXNAMELEN];
  1150 	char namebuf[MAXNAMELEN];
  1151 
  1151 
  1152 	dsl_dataset_name(ds, namebuf);
  1152 	dsl_dataset_name(ds, namebuf);
  1153 
  1153 
  1154 	if (strlen(namebuf) + *deltap >= MAXNAMELEN)
  1154 	if (strlen(namebuf) + *deltap >= MAXNAMELEN)
  1155 		return (ENAMETOOLONG);
  1155 		return (SET_ERROR(ENAMETOOLONG));
  1156 	return (0);
  1156 	return (0);
  1157 }
  1157 }
  1158 
  1158 
  1159 static int
  1159 static int
  1160 dsl_dir_rename_check(void *arg, dmu_tx_t *tx)
  1160 dsl_dir_rename_check(void *arg, dmu_tx_t *tx)
  1181 
  1181 
  1182 	/* can't rename to different pool */
  1182 	/* can't rename to different pool */
  1183 	if (dd->dd_pool != newparent->dd_pool) {
  1183 	if (dd->dd_pool != newparent->dd_pool) {
  1184 		dsl_dir_rele(newparent, FTAG);
  1184 		dsl_dir_rele(newparent, FTAG);
  1185 		dsl_dir_rele(dd, FTAG);
  1185 		dsl_dir_rele(dd, FTAG);
  1186 		return (ENXIO);
  1186 		return (SET_ERROR(ENXIO));
  1187 	}
  1187 	}
  1188 
  1188 
  1189 	/* new name should not already exist */
  1189 	/* new name should not already exist */
  1190 	if (mynewname == NULL) {
  1190 	if (mynewname == NULL) {
  1191 		dsl_dir_rele(newparent, FTAG);
  1191 		dsl_dir_rele(newparent, FTAG);
  1192 		dsl_dir_rele(dd, FTAG);
  1192 		dsl_dir_rele(dd, FTAG);
  1193 		return (EEXIST);
  1193 		return (SET_ERROR(EEXIST));
  1194 	}
  1194 	}
  1195 
  1195 
  1196 	/* if the name length is growing, validate child name lengths */
  1196 	/* if the name length is growing, validate child name lengths */
  1197 	if (delta > 0) {
  1197 	if (delta > 0) {
  1198 		error = dmu_objset_find_dp(dp, dd->dd_object, dsl_valid_rename,
  1198 		error = dmu_objset_find_dp(dp, dd->dd_object, dsl_valid_rename,
  1211 
  1211 
  1212 		/* no rename into our descendant */
  1212 		/* no rename into our descendant */
  1213 		if (closest_common_ancestor(dd, newparent) == dd) {
  1213 		if (closest_common_ancestor(dd, newparent) == dd) {
  1214 			dsl_dir_rele(newparent, FTAG);
  1214 			dsl_dir_rele(newparent, FTAG);
  1215 			dsl_dir_rele(dd, FTAG);
  1215 			dsl_dir_rele(dd, FTAG);
  1216 			return (EINVAL);
  1216 			return (SET_ERROR(EINVAL));
  1217 		}
  1217 		}
  1218 
  1218 
  1219 		error = dsl_dir_transfer_possible(dd->dd_parent,
  1219 		error = dsl_dir_transfer_possible(dd->dd_parent,
  1220 		    newparent, myspace);
  1220 		    newparent, myspace);
  1221 		if (error != 0) {
  1221 		if (error != 0) {
  1313 
  1313 
  1314 	ancestor = closest_common_ancestor(sdd, tdd);
  1314 	ancestor = closest_common_ancestor(sdd, tdd);
  1315 	adelta = would_change(sdd, -space, ancestor);
  1315 	adelta = would_change(sdd, -space, ancestor);
  1316 	avail = dsl_dir_space_available(tdd, ancestor, adelta, FALSE);
  1316 	avail = dsl_dir_space_available(tdd, ancestor, adelta, FALSE);
  1317 	if (avail < space)
  1317 	if (avail < space)
  1318 		return (ENOSPC);
  1318 		return (SET_ERROR(ENOSPC));
  1319 
  1319 
  1320 	return (0);
  1320 	return (0);
  1321 }
  1321 }
  1322 
  1322 
  1323 timestruc_t
  1323 timestruc_t