Index: src/wp-includes/functions.php
===================================================================
--- src/wp-includes/functions.php	(revision 35559)
+++ src/wp-includes/functions.php	(working copy)
@@ -1805,94 +1805,118 @@
  * @return array See above for description.
  */
 function wp_upload_dir( $time = null ) {
-	$siteurl = get_option( 'siteurl' );
-	$upload_path = trim( get_option( 'upload_path' ) );
-
-	if ( empty( $upload_path ) || 'wp-content/uploads' == $upload_path ) {
-		$dir = WP_CONTENT_DIR . '/uploads';
-	} elseif ( 0 !== strpos( $upload_path, ABSPATH ) ) {
-		// $dir is absolute, $upload_path is (maybe) relative to ABSPATH
-		$dir = path_join( ABSPATH, $upload_path );
-	} else {
-		$dir = $upload_path;
+	if ( ! $time ) {
+		$time = current_time( 'mysql' );
 	}
 
-	if ( !$url = get_option( 'upload_url_path' ) ) {
-		if ( empty($upload_path) || ( 'wp-content/uploads' == $upload_path ) || ( $upload_path == $dir ) )
-			$url = WP_CONTENT_URL . '/uploads';
-		else
-			$url = trailingslashit( $siteurl ) . $upload_path;
-	}
+	// Generate cache key with yeatr_month suffix
+	$year = substr( $time, 0, 4 );
+	$month = substr( $time, 5, 2 );
+	$cache_key = "upload_dir_{$year}_{$month}";
 
-	/*
-	 * Honor the value of UPLOADS. This happens as long as ms-files rewriting is disabled.
-	 * We also sometimes obey UPLOADS when rewriting is enabled -- see the next block.
-	 */
-	if ( defined( 'UPLOADS' ) && ! ( is_multisite() && get_site_option( 'ms_files_rewriting' ) ) ) {
-		$dir = ABSPATH . UPLOADS;
-		$url = trailingslashit( $siteurl ) . UPLOADS;
-	}
+	$uploads = wp_cache_get( $cache_key );
 
-	// If multisite (and if not the main site in a post-MU network)
-	if ( is_multisite() && ! ( is_main_network() && is_main_site() && defined( 'MULTISITE' ) ) ) {
+	if ( ! $uploads ) {
+		$siteurl = get_option( 'siteurl' );
+		$upload_path = trim( get_option( 'upload_path' ) );
 
-		if ( ! get_site_option( 'ms_files_rewriting' ) ) {
-			/*
-			 * If ms-files rewriting is disabled (networks created post-3.5), it is fairly
-			 * straightforward: Append sites/%d if we're not on the main site (for post-MU
-			 * networks). (The extra directory prevents a four-digit ID from conflicting with
-			 * a year-based directory for the main site. But if a MU-era network has disabled
-			 * ms-files rewriting manually, they don't need the extra directory, as they never
-			 * had wp-content/uploads for the main site.)
-			 */
+		if ( empty( $upload_path ) || 'wp-content/uploads' == $upload_path ) {
+			$dir = WP_CONTENT_DIR . '/uploads';
+		} elseif ( 0 !== strpos( $upload_path, ABSPATH ) ) {
+			// $dir is absolute, $upload_path is (maybe) relative to ABSPATH
+			$dir = path_join( ABSPATH, $upload_path );
+		} else {
+			$dir = $upload_path;
+		}
 
-			if ( defined( 'MULTISITE' ) )
-				$ms_dir = '/sites/' . get_current_blog_id();
-			else
-				$ms_dir = '/' . get_current_blog_id();
+		if ( !$url = get_option( 'upload_url_path' ) ) {
+			if ( empty($upload_path) || ( 'wp-content/uploads' == $upload_path ) || ( $upload_path == $dir ) ) {
+				$url = WP_CONTENT_URL . '/uploads';
+			} else {
+				$url = trailingslashit( $siteurl ) . $upload_path;
+			}
+		}
 
-			$dir .= $ms_dir;
-			$url .= $ms_dir;
+		/*
+		 * Honor the value of UPLOADS. This happens as long as ms-files rewriting is disabled.
+		 * We also sometimes obey UPLOADS when rewriting is enabled -- see the next block.
+		 */
+		if ( defined( 'UPLOADS' ) && ! ( is_multisite() && get_site_option( 'ms_files_rewriting' ) ) ) {
+			$dir = ABSPATH . UPLOADS;
+			$url = trailingslashit( $siteurl ) . UPLOADS;
+		}
 
-		} elseif ( defined( 'UPLOADS' ) && ! ms_is_switched() ) {
-			/*
-			 * Handle the old-form ms-files.php rewriting if the network still has that enabled.
-			 * When ms-files rewriting is enabled, then we only listen to UPLOADS when:
-			 * 1) We are not on the main site in a post-MU network, as wp-content/uploads is used
-			 *    there, and
-			 * 2) We are not switched, as ms_upload_constants() hardcodes these constants to reflect
-			 *    the original blog ID.
-			 *
-			 * Rather than UPLOADS, we actually use BLOGUPLOADDIR if it is set, as it is absolute.
-			 * (And it will be set, see ms_upload_constants().) Otherwise, UPLOADS can be used, as
-			 * as it is relative to ABSPATH. For the final piece: when UPLOADS is used with ms-files
-			 * rewriting in multisite, the resulting URL is /files. (#WP22702 for background.)
-			 */
+		// If multisite (and if not the main site in a post-MU network)
+		if ( is_multisite() && ! ( is_main_network() && is_main_site() && defined( 'MULTISITE' ) ) ) {
 
-			if ( defined( 'BLOGUPLOADDIR' ) )
-				$dir = untrailingslashit( BLOGUPLOADDIR );
-			else
-				$dir = ABSPATH . UPLOADS;
-			$url = trailingslashit( $siteurl ) . 'files';
+			if ( ! get_site_option( 'ms_files_rewriting' ) ) {
+				/*
+				 * If ms-files rewriting is disabled (networks created post-3.5), it is fairly
+				 * straightforward: Append sites/%d if we're not on the main site (for post-MU
+				 * networks). (The extra directory prevents a four-digit ID from conflicting with
+				 * a year-based directory for the main site. But if a MU-era network has disabled
+				 * ms-files rewriting manually, they don't need the extra directory, as they never
+				 * had wp-content/uploads for the main site.)
+				 */
+
+				if ( defined( 'MULTISITE' ) ) {
+					$ms_dir = '/sites/' . get_current_blog_id();
+				} else {
+					$ms_dir = '/' . get_current_blog_id();
+				}
+
+				$dir .= $ms_dir;
+				$url .= $ms_dir;
+
+			} elseif ( defined( 'UPLOADS' ) && ! ms_is_switched() ) {
+				/*
+				 * Handle the old-form ms-files.php rewriting if the network still has that enabled.
+				 * When ms-files rewriting is enabled, then we only listen to UPLOADS when:
+				 * 1) We are not on the main site in a post-MU network, as wp-content/uploads is used
+				 *    there, and
+				 * 2) We are not switched, as ms_upload_constants() hardcodes these constants to reflect
+				 *    the original blog ID.
+				 *
+				 * Rather than UPLOADS, we actually use BLOGUPLOADDIR if it is set, as it is absolute.
+				 * (And it will be set, see ms_upload_constants().) Otherwise, UPLOADS can be used, as
+				 * as it is relative to ABSPATH. For the final piece: when UPLOADS is used with ms-files
+				 * rewriting in multisite, the resulting URL is /files. (#WP22702 for background.)
+				 */
+
+				if ( defined( 'BLOGUPLOADDIR' ) ) {
+					$dir = untrailingslashit( BLOGUPLOADDIR );
+				} else {
+					$dir = ABSPATH . UPLOADS;
+				}
+
+				$url = trailingslashit( $siteurl ) . 'files';
+			}
 		}
-	}
 
-	$basedir = $dir;
-	$baseurl = $url;
+		$basedir = $dir;
+		$baseurl = $url;
 
-	$subdir = '';
-	if ( get_option( 'uploads_use_yearmonth_folders' ) ) {
-		// Generate the yearly and monthly dirs
-		if ( !$time )
-			$time = current_time( 'mysql' );
-		$y = substr( $time, 0, 4 );
-		$m = substr( $time, 5, 2 );
-		$subdir = "/$y/$m";
+		$subdir = '';
+		if ( get_option( 'uploads_use_yearmonth_folders' ) ) {
+			$subdir = "/{$year}/{$month}";
+		}
+
+		$dir .= $subdir;
+		$url .= $subdir;
+
+		$uploads = array(
+			'path'    => $dir,
+			'url'     => $url,
+			'subdir'  => $subdir,
+			'basedir' => $basedir,
+			'baseurl' => $baseurl,
+			'error'   => false,
+		);
+
+		// Cache the $uploads array before filtering.
+		wp_cache_set( $cache_key, $uploads );
 	}
 
-	$dir .= $subdir;
-	$url .= $subdir;
-
 	/**
 	 * Filter the uploads directory data.
 	 *
@@ -1901,28 +1925,36 @@
 	 * @param array $uploads Array of upload directory data with keys of 'path',
 	 *                       'url', 'subdir, 'basedir', and 'error'.
 	 */
-	$uploads = apply_filters( 'upload_dir',
-		array(
-			'path'    => $dir,
-			'url'     => $url,
-			'subdir'  => $subdir,
-			'basedir' => $basedir,
-			'baseurl' => $baseurl,
-			'error'   => false,
-		) );
+	$filtered_uploads = apply_filters( 'upload_dir', $uploads );
 
-	// Make sure we have an uploads directory.
-	if ( ! wp_mkdir_p( $uploads['path'] ) ) {
-		if ( 0 === strpos( $uploads['basedir'], ABSPATH ) )
-			$error_path = str_replace( ABSPATH, '', $uploads['basedir'] ) . $uploads['subdir'];
-		else
-			$error_path = basename( $uploads['basedir'] ) . $uploads['subdir'];
+	$filtered_path = $filtered_uploads['path'];
+	$tested_paths = wp_cache_get( 'upload_dir_paths' );
 
-		$message = sprintf( __( 'Unable to create directory %s. Is its parent directory writable by the server?' ), $error_path );
-		$uploads['error'] = $message;
+	if ( ! is_array( $tested_paths ) ) {
+		$tested_paths = array();
 	}
 
-	return $uploads;
+	if ( ! array_key_exists( $filtered_path, $tested_paths ) ) {
+		// Make sure we have an uploads directory.
+		if ( ! wp_mkdir_p( $filtered_path ) ) {
+			if ( 0 === strpos( $filtered_uploads['basedir'], ABSPATH ) ) {
+				$error_path = str_replace( ABSPATH, '', $filtered_uploads['basedir'] ) . $filtered_uploads['subdir'];
+			} else {
+				$error_path = basename( $filtered_uploads['basedir'] ) . $filtered_uploads['subdir'];
+			}
+
+			$message = sprintf( __( 'Unable to create directory %s. Is its parent directory writable by the server?' ), $error_path );
+			$filtered_uploads['error'] = $message;
+		}
+
+		$tested_paths[ $filtered_path ] = $filtered_uploads['error'];
+		wp_cache_set( 'upload_dir_paths', $tested_paths );
+	}
+
+	// Set the proper error for this path.
+	$filtered_uploads['error'] = $tested_paths[ $filtered_path ];
+
+	return $filtered_uploads;
 }
 
 /**
