@@ -21,9 +21,9 @@ package mount
21
21
22
22
import (
23
23
"fmt"
24
+ "strconv"
24
25
"strings"
25
26
26
- "k8s.io/apimachinery/pkg/util/sets"
27
27
"k8s.io/klog/v2"
28
28
utilexec "k8s.io/utils/exec"
29
29
)
@@ -129,18 +129,93 @@ func (resizefs *ResizeFs) NeedResize(devicePath string, deviceMountPath string)
129
129
return false , nil
130
130
}
131
131
132
- supportedFormats := sets .New ("ext3" , "ext4" , "xfs" , "btrfs" )
133
- if ! supportedFormats .Has (format ) {
132
+ switch format {
133
+ case "ext3" , "ext4" , "xfs" :
134
+ // For ext3/ext4/xfs, recommendation received from linux filesystem folks is to let
135
+ // resize2fs/xfs_growfs do the check for us. So we will not do any check here.
136
+ return true , nil
137
+ case "btrfs" :
138
+ deviceSize , err := resizefs .getDeviceSize (devicePath )
139
+ if err != nil {
140
+ return false , err
141
+ }
142
+ blockSize , fsSize , err := resizefs .getBtrfsSize (devicePath )
143
+ klog .V (5 ).Infof ("Btrfs size: filesystem size=%d, block size=%d, err=%v" , fsSize , blockSize , err )
144
+ if err != nil {
145
+ return false , err
146
+ }
147
+ if deviceSize <= fsSize + blockSize {
148
+ return false , nil
149
+ }
150
+ return true , nil
151
+ default :
134
152
return false , fmt .Errorf ("could not parse fs info of given filesystem format: %s. Supported fs types are: xfs, ext3, ext4" , format )
135
153
}
136
- return true , nil
154
+ }
155
+
156
+ func (resizefs * ResizeFs ) getDeviceSize (devicePath string ) (uint64 , error ) {
157
+ output , err := resizefs .exec .Command (blockDev , "--getsize64" , devicePath ).CombinedOutput ()
158
+ outStr := strings .TrimSpace (string (output ))
159
+ if err != nil {
160
+ return 0 , fmt .Errorf ("failed to read size of device %s: %s: %s" , devicePath , err , outStr )
161
+ }
162
+ size , err := strconv .ParseUint (outStr , 10 , 64 )
163
+ if err != nil {
164
+ return 0 , fmt .Errorf ("failed to parse size of device %s %s: %s" , devicePath , outStr , err )
165
+ }
166
+ return size , nil
167
+ }
168
+
169
+ func (resizefs * ResizeFs ) getBtrfsSize (devicePath string ) (uint64 , uint64 , error ) {
170
+ output , err := resizefs .exec .Command ("btrfs" , "inspect-internal" , "dump-super" , "-f" , devicePath ).CombinedOutput ()
171
+ if err != nil {
172
+ return 0 , 0 , fmt .Errorf ("failed to read size of filesystem on %s: %s: %s" , devicePath , err , string (output ))
173
+ }
174
+
175
+ blockSize , totalBytes , _ := resizefs .parseBtrfsInfoOutput (string (output ), "sectorsize" , "total_bytes" )
176
+
177
+ if blockSize == 0 {
178
+ return 0 , 0 , fmt .Errorf ("could not find block size of device %s" , devicePath )
179
+ }
180
+ if totalBytes == 0 {
181
+ return 0 , 0 , fmt .Errorf ("could not find total size of device %s" , devicePath )
182
+ }
183
+ return blockSize , totalBytes , nil
184
+ }
185
+
186
+ func (resizefs * ResizeFs ) parseBtrfsInfoOutput (cmdOutput string , blockSizeKey string , totalBytesKey string ) (uint64 , uint64 , error ) {
187
+ lines := strings .Split (cmdOutput , "\n " )
188
+ var blockSize , blockCount uint64
189
+ var err error
190
+
191
+ for _ , line := range lines {
192
+ tokens := strings .Fields (line )
193
+ if len (tokens ) != 2 {
194
+ continue
195
+ }
196
+ key , value := strings .ToLower (strings .TrimSpace (tokens [0 ])), strings .ToLower (strings .TrimSpace (tokens [1 ]))
197
+
198
+ if key == blockSizeKey {
199
+ blockSize , err = strconv .ParseUint (value , 10 , 64 )
200
+ if err != nil {
201
+ return 0 , 0 , fmt .Errorf ("failed to parse block size %s: %s" , value , err )
202
+ }
203
+ }
204
+ if key == totalBytesKey {
205
+ blockCount , err = strconv .ParseUint (value , 10 , 64 )
206
+ if err != nil {
207
+ return 0 , 0 , fmt .Errorf ("failed to parse total size %s: %s" , value , err )
208
+ }
209
+ }
210
+ }
211
+ return blockSize , blockCount , err
137
212
}
138
213
139
214
func (resizefs * ResizeFs ) getDeviceRO (devicePath string ) (bool , error ) {
140
215
output , err := resizefs .exec .Command (blockDev , "--getro" , devicePath ).CombinedOutput ()
141
216
outStr := strings .TrimSpace (string (output ))
142
217
if err != nil {
143
- return false , fmt .Errorf ("failed to get readonly bit from device %s: %s : %s" , devicePath , err , outStr )
218
+ return false , fmt .Errorf ("failed to get readonly bit from device %s: %w : %s" , devicePath , err , outStr )
144
219
}
145
220
switch outStr {
146
221
case "0" :
0 commit comments