| 
									
										
										
										
											2021-04-19 03:41:13 +08:00
										 |  |  | // Copyright (c) 2015-2021 MinIO, Inc.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This file is part of MinIO Object Storage stack
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This program is free software: you can redistribute it and/or modify
 | 
					
						
							|  |  |  | // it under the terms of the GNU Affero General Public License as published by
 | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or
 | 
					
						
							|  |  |  | // (at your option) any later version.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This program is distributed in the hope that it will be useful
 | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					
						
							|  |  |  | // GNU Affero General Public License for more details.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // You should have received a copy of the GNU Affero General Public License
 | 
					
						
							|  |  |  | // along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							| 
									
										
										
										
											2016-10-10 14:03:10 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | package cmd | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2020-03-19 07:19:29 +08:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2016-10-10 14:03:10 +08:00
										 |  |  | 	"os" | 
					
						
							|  |  |  | 	"os/exec" | 
					
						
							| 
									
										
										
										
											2019-03-21 13:20:30 +08:00
										 |  |  | 	"syscall" | 
					
						
							| 
									
										
										
										
											2016-10-10 14:03:10 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Type of service signals currently supported.
 | 
					
						
							| 
									
										
										
										
											2019-08-28 02:37:47 +08:00
										 |  |  | type serviceSignal int | 
					
						
							| 
									
										
										
										
											2016-10-10 14:03:10 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							| 
									
										
										
										
											2020-12-05 01:32:35 +08:00
										 |  |  | 	serviceRestart       serviceSignal = iota // Restarts the server.
 | 
					
						
							|  |  |  | 	serviceStop                               // Stops the server.
 | 
					
						
							|  |  |  | 	serviceReloadDynamic                      // Reload dynamic config values.
 | 
					
						
							| 
									
										
										
										
											2021-11-24 04:02:16 +08:00
										 |  |  | 	serviceFreeze                             // Freeze all S3 API calls.
 | 
					
						
							|  |  |  | 	serviceUnFreeze                           // Un-Freeze previously frozen S3 API calls.
 | 
					
						
							| 
									
										
										
										
											2016-10-10 14:03:10 +08:00
										 |  |  | 	// Add new service requests here.
 | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Global service signal channel.
 | 
					
						
							|  |  |  | var globalServiceSignalCh chan serviceSignal | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-19 07:19:29 +08:00
										 |  |  | // GlobalContext context that is canceled when server is requested to shut down.
 | 
					
						
							|  |  |  | var GlobalContext context.Context | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // cancelGlobalContext can be used to indicate server shutdown.
 | 
					
						
							|  |  |  | var cancelGlobalContext context.CancelFunc | 
					
						
							| 
									
										
										
										
											2016-10-10 14:03:10 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-03-19 07:19:29 +08:00
										 |  |  | func initGlobalContext() { | 
					
						
							|  |  |  | 	GlobalContext, cancelGlobalContext = context.WithCancel(context.Background()) | 
					
						
							| 
									
										
										
										
											2016-12-16 14:26:15 +08:00
										 |  |  | 	globalServiceSignalCh = make(chan serviceSignal) | 
					
						
							| 
									
										
										
										
											2016-10-10 14:03:10 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // restartProcess starts a new process passing it the active fd's. It
 | 
					
						
							|  |  |  | // doesn't fork, but starts a new process using the same environment and
 | 
					
						
							|  |  |  | // arguments as when it was originally started. This allows for a newly
 | 
					
						
							|  |  |  | // deployed binary to be started. It returns the pid of the newly started
 | 
					
						
							|  |  |  | // process when successful.
 | 
					
						
							|  |  |  | func restartProcess() error { | 
					
						
							|  |  |  | 	// Use the original binary location. This works with symlinks such that if
 | 
					
						
							|  |  |  | 	// the file it points to has been changed we will use the updated symlink.
 | 
					
						
							|  |  |  | 	argv0, err := exec.LookPath(os.Args[0]) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-03-21 13:20:30 +08:00
										 |  |  | 	// Invokes the execve system call.
 | 
					
						
							|  |  |  | 	// Re-uses the same pid. This preserves the pid over multiple server-respawns.
 | 
					
						
							|  |  |  | 	return syscall.Exec(argv0, os.Args, os.Environ()) | 
					
						
							| 
									
										
										
										
											2016-10-10 14:03:10 +08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2021-11-24 04:02:16 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | // freezeServices will freeze all incoming S3 API calls.
 | 
					
						
							|  |  |  | // For each call, unfreezeServices must be called once.
 | 
					
						
							|  |  |  | func freezeServices() { | 
					
						
							|  |  |  | 	// Use atomics for globalServiceFreeze, so we can read without locking.
 | 
					
						
							| 
									
										
										
										
											2021-11-24 08:09:28 +08:00
										 |  |  | 	// We need a lock since we are need the 2 atomic values to remain in sync.
 | 
					
						
							|  |  |  | 	globalServiceFreezeMu.Lock() | 
					
						
							|  |  |  | 	// If multiple calls, first one creates channel.
 | 
					
						
							|  |  |  | 	globalServiceFreezeCnt++ | 
					
						
							|  |  |  | 	if globalServiceFreezeCnt == 1 { | 
					
						
							|  |  |  | 		globalServiceFreeze.Store(make(chan struct{})) | 
					
						
							| 
									
										
										
										
											2021-11-24 04:02:16 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-11-24 08:09:28 +08:00
										 |  |  | 	globalServiceFreezeMu.Unlock() | 
					
						
							| 
									
										
										
										
											2021-11-24 04:02:16 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // unfreezeServices will unfreeze all incoming S3 API calls.
 | 
					
						
							|  |  |  | // For each call, unfreezeServices must be called once.
 | 
					
						
							|  |  |  | func unfreezeServices() { | 
					
						
							| 
									
										
										
										
											2021-11-24 08:09:28 +08:00
										 |  |  | 	// We need a lock since we need the 2 atomic values to remain in sync.
 | 
					
						
							|  |  |  | 	globalServiceFreezeMu.Lock() | 
					
						
							|  |  |  | 	// Close when we reach 0
 | 
					
						
							|  |  |  | 	globalServiceFreezeCnt-- | 
					
						
							|  |  |  | 	if globalServiceFreezeCnt <= 0 { | 
					
						
							|  |  |  | 		// Ensure we only close once.
 | 
					
						
							| 
									
										
										
										
											2021-11-24 04:02:16 +08:00
										 |  |  | 		if val := globalServiceFreeze.Load(); val != nil { | 
					
						
							| 
									
										
										
										
											2021-11-24 08:09:28 +08:00
										 |  |  | 			var _ch chan struct{} | 
					
						
							| 
									
										
										
										
											2021-11-24 04:02:16 +08:00
										 |  |  | 			if ch, ok := val.(chan struct{}); ok { | 
					
						
							| 
									
										
										
										
											2021-11-24 08:09:28 +08:00
										 |  |  | 				globalServiceFreeze.Store(_ch) | 
					
						
							|  |  |  | 				close(ch) | 
					
						
							| 
									
										
										
										
											2021-11-24 04:02:16 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-11-24 08:09:28 +08:00
										 |  |  | 		globalServiceFreezeCnt = 0 // Don't risk going negative.
 | 
					
						
							| 
									
										
										
										
											2021-11-24 04:02:16 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-11-24 08:09:28 +08:00
										 |  |  | 	globalServiceFreezeMu.Unlock() | 
					
						
							| 
									
										
										
										
											2021-11-24 04:02:16 +08:00
										 |  |  | } |