Repository: minio/minio (language: go)

Issue:
Found crash while uploading files to Minio
### Discussed in https://github.com/minio/minio/discussions/17628

<div type='discussions-op-text'>

<sup>Originally posted by **adeesh-vunet** July 11, 2023</sup>
We were uploading lots of small sized files to Minio bucket, suddenly we encountered timeout error on uploading any file.  
We uploaded around 50,000 files, of total size around 500 MB. 

Now we can't upload any files to any of the bucket, but we can access and delete, 
```

panic: "PUT /vustreams/log4j2.xml": runtime error: integer divide by zero
goroutine 193510 [running]:
runtime/debug.Stack()
        runtime/debug/stack.go:24 +0x65
github.com/minio/minio/cmd.setCriticalErrorHandler.func1.1()
        github.com/minio/minio/cmd/generic-handlers.go:529 +0x8e
panic({0x2750c00, 0x62fc4e0})
        runtime/panic.go:884 +0x212
github.com/minio/minio/cmd.hasSpaceFor({0xc01033a4c0?, 0xc011dcac60?, 0xc0097add70?}, 0x1?)
        github.com/minio/minio/cmd/object-api-utils.go:1182 +0x1ec
github.com/minio/minio/cmd.(*erasureServerPools).PutObject(_, {_, _}, {_, _}, {_, _}, _, {{0x0, 0x0}, ...})
        github.com/minio/minio/cmd/erasure-server-pool.go:944 +0x2c8
github.com/minio/minio/cmd.objectAPIHandlers.PutObjectHandler({0x498da00?, 0x498d9e8?}, {0x4e06420, 0xc010b17800}, 0xc000347800)
        github.com/minio/minio/cmd/object-handlers.go:1870 +0x3f17
net/http.HandlerFunc.ServeHTTP(...)
        net/http/server.go:2109
github.com/minio/minio/cmd.httpTrace.func1({0x4e06420, 0xc010b17800}, 0xc000347800)
        github.com/minio/minio/cmd/http-tracer.go:188 +0x195
net/http.HandlerFunc.ServeHTTP(0x2622680?, {0x4e06420?, 0xc010b17800?}, 0x4?)
        net/http/server.go:2109 +0x2f
github.com/klauspost/compress/gzhttp.NewWrapper.func1.1({0x4e06a50, 0xc0039fdef0}, 0x4de8100?)
        github.com/klauspost/compress@v1.16.5/gzhttp/compress.go:484 +0x534
net/http.HandlerFunc.ServeHTTP(...)
        net/http/server.go:2109
github.com/minio/minio/cmd.maxClients.func1({0x4e06a50, 0xc0039fdef0}, 0xc000347800)
        github.com/minio/minio/cmd/handler-api.go:296 +0x55a
net/http.HandlerFunc.ServeHTTP(...)
        net/http/server.go:2109
github.com/minio/minio/cmd.collectAPIStats.func1({0x4e06a50, 0xc0039fdef0}, 0xc000347800)
        github.com/minio/minio/cmd/handler-utils.go:275 +0x114
net/http.HandlerFunc.ServeHTTP(0x0?, {0x4e06a50?, 0xc0039fdef0?}, 0x1?)
        net/http/server.go:2109 +0x2f
github.com/minio/minio/cmd.setBucketForwardingHandler.func1({0x4e06a50, 0xc0039fdef0}, 0xc000347800)
        github.com/minio/minio/cmd/generic-handlers.go:433 +0x237
net/http.HandlerFunc.ServeHTTP(0x40d93f?, {0x4e06a50?, 0xc0039fdef0?}, 0xc00ab261e0?)
        net/http/server.go:2109 +0x2f
github.com/minio/minio/cmd.setUploadForwardingHandler.func1({0x4e06a50, 0xc0039fdef0}, 0xc000347800)
        github.com/minio/minio/cmd/generic-handlers.go:547 +0x18e
net/http.HandlerFunc.ServeHTTP(0x2929840?, {0x4e06a50?, 0xc0039fdef0?}, 0xa?)
        net/http/server.go:2109 +0x2f
github.com/minio/minio/cmd.addCustomHeaders.func1({0x4e06a50, 0xc0039fdef0}, 0xc008d14f20?)
        github.com/minio/minio/cmd/generic-handlers.go:512 +0x4b7
net/http.HandlerFunc.ServeHTTP(0x2a62440?, {0x4e06a50?, 0xc0039fdef0?}, 0x39?)
        net/http/server.go:2109 +0x2f
github.com/minio/minio/cmd.setRequestValidityHandler.func1({0x4e06a50?, 0xc0039fdef0}, 0xc000347800)
        github.com/minio/minio/cmd/generic-handlers.go:421 +0x14b2
net/http.HandlerFunc.ServeHTTP(0xc011dcab10?, {0x4e06a50?, 0xc0039fdef0?}, 0x10000000071414f?)
        net/http/server.go:2109 +0x2f
github.com/minio/minio/cmd.setRequestLimitHandler.func1({0x4e06a50?, 0xc0039fdef0}, 0xc000347800)
        github.com/minio/minio/cmd/generic-handlers.go:132 +0x6a5
net/http.HandlerFunc.ServeHTTP(0x2b63b11?, {0x4e06a50?, 0xc0039fdef0?}, 0x2218ab6?)
        net/http/server.go:2109 +0x2f
github.com/minio/minio/cmd.setCrossDomainPolicy.func1({0x4e06a50?, 0xc0039fdef0?}, 0x6?)
        github.com/minio/minio/cmd/crossdomain-xml-handler.go:42 +0xef
net/http.HandlerFunc.ServeHTTP(0xc000347800?, {0x4e06a50?, 0xc0039fdef0?}, 0x1?)
        net/http/server.go:2109 +0x2f
github.com/minio/minio/cmd.setBrowserRedirectHandler.func1({0x4e06a50, 0xc0039fdef0}, 0xc000347800)
        github.com/minio/minio/cmd/generic-handlers.go:162 +0x183
net/http.HandlerFunc.ServeHTTP(0x0?, {0x4e06a50?, 0xc0039fdef0?}, 0x1008196f?)
        net/http/server.go:2109 +0x2f
github.com/minio/minio/cmd.setAuthHandler.func1({0x4e06a50, 0xc0039fdef0}, 0xc000347800)
        github.com/minio/minio/cmd/auth-handler.go:637 +0x6ca
net/http.HandlerFunc.ServeHTTP(0x4e0c488?, {0x4e06a50?, 0xc0039fdef0?}, 0x4de8100?)
        net/http/server.go:2109 +0x2f
github.com/minio/minio/cmd.httpTracer.func1({0x4e0a950?, 0xc009a4fce0?}, 0xc000347700)
        github.com/minio/minio/cmd/http-tracer.go:88 +0x3d1
net/http.HandlerFunc.ServeHTTP(0xc000347600?, {0x4e0a950?, 0xc009a4fce0?}, 0x2622680?)
        net/http/server.go:2109 +0x2f
github.com/minio/mux.(*Router).ServeHTTP(0xc003a3a000, {0x4e0a950, 0xc009a4fce0}, 0xc000347600)
        github.com/minio/mux@v1.9.0/mux.go:214 +0x204
github.com/rs/cors.(*Cors).Handler.func1({0x4e0a950, 0xc009a4fce0}, 0xc000347600)
        github.com/rs/cors@v1.8.3/cors.go:236 +0x1c4
net/http.HandlerFunc.ServeHTTP(0x0?, {0x4e0a950?, 0xc009a4fce0?}, 0x40dc87?)
        net/http/server.go:2109 +0x2f
github.com/minio/minio/cmd.setCriticalErrorHandler.func1({0x4e0a950?, 0xc009a4fce0?}, 0x0?)
        github.com/minio/minio/cmd/generic-handlers.go:536 +0x83
net/http.HandlerFunc.ServeHTTP(0x0?, {0x4e0a950?, 0xc009a4fce0?}, 0x0?)
        net/http/server.go:2109 +0x2f
github.com/minio/minio/internal/http.(*Server).Start.func1({0x4e0a950?, 0xc009a4fce0?}, 0xc011dca9f0?)
        github.com/minio/minio/internal/http/server.go:113 +0x19c
net/http.HandlerFunc.ServeHTTP(0x0?, {0x4e0a950?, 0xc009a4fce0?}, 0x722c54?)
        net/http/server.go:2109 +0x2f
net/http.serverHandler.ServeHTTP({0x4e01fa0?}, {0x4e0a950, 0xc009a4fce0}, 0xc000347600)
        net/http/server.go:2947 +0x30c
net/http.(*conn).serve(0xc003bacf00, {0x4e0c488, 0xc003336300})
        net/http/server.go:1991 +0x607
created by net/http.(*Server).Serve
        net/http/server.go:3102 +0x4db


```
This is the trace for a single upload. 

Can you let me know what went wrong, that we observed this behaviour. ? Also please ask if you require any other information. 
</div>


Discussion / hints:

Fix patch:
diff --git a/cmd/object-api-utils.go b/cmd/object-api-utils.go
index eeddf15730c4f..f224498181319 100644
--- a/cmd/object-api-utils.go
+++ b/cmd/object-api-utils.go
@@ -1166,7 +1166,7 @@ func hasSpaceFor(di []*DiskInfo, size int64) (bool, error) {
 	var total uint64
 	var nDisks int
 	for _, disk := range di {
-		if disk == nil || disk.Total == 0 || (disk.FreeInodes < diskMinInodes && disk.UsedInodes > 0) {
+		if disk == nil || disk.Total == 0 {
 			// Disk offline, no inodes or something else is wrong.
 			continue
 		}
@@ -1175,16 +1175,20 @@ func hasSpaceFor(di []*DiskInfo, size int64) (bool, error) {
 		available += disk.Total - disk.Used
 	}
 
-	if nDisks < len(di)/2 {
+	if nDisks < len(di)/2 || nDisks <= 0 {
 		return false, fmt.Errorf("not enough online disks to calculate the available space, expected (%d)/(%d)", (len(di)/2)+1, nDisks)
 	}
 
 	// Check we have enough on each disk, ignoring diskFillFraction.
 	perDisk := size / int64(nDisks)
 	for _, disk := range di {
-		if disk == nil || disk.Total == 0 || (disk.FreeInodes < diskMinInodes && disk.UsedInodes > 0) {
+		if disk == nil || disk.Total == 0 {
 			continue
 		}
+		if disk.FreeInodes < diskMinInodes && disk.UsedInodes > 0 {
+			// We have an inode count, but not enough inodes.
+			return false, nil
+		}
 		if int64(disk.Free) <= perDisk {
 			return false, nil
 		}


Test patch: