@@ -25,8 +25,10 @@ import (
25
25
"gvisor.dev/gvisor/pkg/errors/linuxerr"
26
26
"gvisor.dev/gvisor/pkg/fdnotifier"
27
27
"gvisor.dev/gvisor/pkg/hostarch"
28
+ "gvisor.dev/gvisor/pkg/log"
28
29
"gvisor.dev/gvisor/pkg/refs"
29
30
"gvisor.dev/gvisor/pkg/safemem"
31
+ "gvisor.dev/gvisor/pkg/sentry/kernel/auth"
30
32
"gvisor.dev/gvisor/pkg/sentry/pgalloc"
31
33
"gvisor.dev/gvisor/pkg/sentry/vfs"
32
34
)
@@ -48,6 +50,7 @@ func (fs *filesystem) PrepareSave(ctx context.Context) error {
48
50
fs .renameMu .Lock ()
49
51
fs .evictAllCachedDentriesLocked (ctx )
50
52
fs .renameMu .Unlock ()
53
+ fs .savedDentryRW = make (map [* dentry ]savedDentryRW )
51
54
52
55
// Buffer pipe data so that it's available for reading after restore. (This
53
56
// is a legacy VFS1 feature.)
@@ -60,14 +63,23 @@ func (fs *filesystem) PrepareSave(ctx context.Context) error {
60
63
}
61
64
}
62
65
}
66
+ // Save file data for deleted regular files which are still accessible via
67
+ // open application FDs.
68
+ for sd := fs .syncableDentries .Front (); sd != nil ; sd = sd .Next () {
69
+ if sd .d .vfsd .IsDead () {
70
+ if err := sd .d .prepareSaveDead (ctx ); err != nil {
71
+ fs .syncMu .Unlock ()
72
+ return err
73
+ }
74
+ }
75
+ }
63
76
fs .syncMu .Unlock ()
64
77
65
78
// Flush local state to the remote filesystem.
66
79
if err := fs .Sync (ctx ); err != nil {
67
80
return err
68
81
}
69
82
70
- fs .savedDentryRW = make (map [* dentry ]savedDentryRW )
71
83
return fs .root .prepareSaveRecursive (ctx )
72
84
}
73
85
@@ -96,6 +108,55 @@ func (fd *specialFileFD) savePipeData(ctx context.Context) error {
96
108
return nil
97
109
}
98
110
111
+ func (d * dentry ) prepareSaveDead (ctx context.Context ) error {
112
+ if ! d .isRegularFile () {
113
+ return fmt .Errorf ("gofer.dentry(%q).prepareSaveDead: only regular deleted dentries can be saved, got %s" , genericDebugPathname (d .fs , d ), linux .FileMode (d .mode .Load ()))
114
+ }
115
+ if ! d .isDeleted () {
116
+ return fmt .Errorf ("gofer.dentry(%q).prepareSaveDead: invalidated dentries can't be saved" , genericDebugPathname (d .fs , d ))
117
+ }
118
+ if ! d .cachedMetadataAuthoritative () {
119
+ if err := d .updateMetadata (ctx ); err != nil {
120
+ return err
121
+ }
122
+ }
123
+ if d .isReadHandleOk () || d .isWriteHandleOk () {
124
+ d .fs .savedDentryRW [d ] = savedDentryRW {
125
+ read : d .isReadHandleOk (),
126
+ write : d .isWriteHandleOk (),
127
+ }
128
+ }
129
+ d .handleMu .RLock ()
130
+ defer d .handleMu .RUnlock ()
131
+ var h handle
132
+ if d .isReadHandleOk () {
133
+ h = d .readHandle ()
134
+ } else {
135
+ var err error
136
+ h , err = d .openHandle (ctx , true /* read */ , false /* write */ , false /* trunc */ )
137
+ if err != nil {
138
+ return fmt .Errorf ("failed to open read handle for deleted file %q: %w" , genericDebugPathname (d .fs , d ), err )
139
+ }
140
+ defer h .close (ctx )
141
+ }
142
+ d .dataMu .RLock ()
143
+ defer d .dataMu .RUnlock ()
144
+ d .deletedDataSR = make ([]byte , d .size .Load ())
145
+ done := uint64 (0 )
146
+ for done < uint64 (len (d .deletedDataSR )) {
147
+ n , err := h .readToBlocksAt (ctx , safemem .BlockSeqOf (safemem .BlockFromSafeSlice (d .deletedDataSR [done :])), done )
148
+ done += n
149
+ if err != nil {
150
+ if err == io .EOF {
151
+ break
152
+ }
153
+ return fmt .Errorf ("failed to read deleted file %q: %w" , genericDebugPathname (d .fs , d ), err )
154
+ }
155
+ }
156
+ d .deletedDataSR = d .deletedDataSR [:done ]
157
+ return nil
158
+ }
159
+
99
160
func (d * dentry ) prepareSaveRecursive (ctx context.Context ) error {
100
161
if d .isRegularFile () && ! d .cachedMetadataAuthoritative () {
101
162
// Get updated metadata for d in case we need to perform metadata
@@ -129,7 +190,7 @@ func (d *dentry) prepareSaveRecursive(ctx context.Context) error {
129
190
130
191
// beforeSave is invoked by stateify.
131
192
func (d * dentry ) beforeSave () {
132
- if d .vfsd .IsDead () {
193
+ if d .vfsd .IsDead () && d . deletedDataSR == nil {
133
194
panic (fmt .Sprintf ("gofer.dentry(%q).beforeSave: deleted and invalidated dentries can't be restored" , genericDebugPathname (d .fs , d )))
134
195
}
135
196
}
@@ -204,6 +265,7 @@ func (fs *filesystem) CompleteRestore(ctx context.Context, opts vfs.CompleteRest
204
265
return err
205
266
}
206
267
268
+ fs .syncMu .Lock ()
207
269
// Re-open handles for specialFileFDs. Unlike the initial open
208
270
// (dentry.openSpecialFile()), pipes are always opened without blocking;
209
271
// non-readable pipe FDs are opened last to ensure that they don't get
@@ -216,18 +278,30 @@ func (fs *filesystem) CompleteRestore(ctx context.Context, opts vfs.CompleteRest
216
278
continue
217
279
}
218
280
if err := fd .completeRestore (ctx ); err != nil {
281
+ fs .syncMu .Unlock ()
219
282
return err
220
283
}
221
284
}
222
285
if haveWriteOnlyPipes {
223
286
for fd := fs .specialFileFDs .Front (); fd != nil ; fd = fd .Next () {
224
287
if fd .dentry ().fileType () == linux .S_IFIFO && ! fd .vfsfd .IsReadable () {
225
288
if err := fd .completeRestore (ctx ); err != nil {
289
+ fs .syncMu .Unlock ()
226
290
return err
227
291
}
228
292
}
229
293
}
230
294
}
295
+ // Restore deleted files which are still accessible via open application FDs.
296
+ for sd := fs .syncableDentries .Front (); sd != nil ; sd = sd .Next () {
297
+ if sd .d .deletedDataSR != nil {
298
+ if err := sd .d .restoreDead (ctx , & opts ); err != nil {
299
+ fs .syncMu .Unlock ()
300
+ return err
301
+ }
302
+ }
303
+ }
304
+ fs .syncMu .Unlock ()
231
305
232
306
// Discard state only required during restore.
233
307
fs .savedDentryRW = nil
@@ -256,6 +330,37 @@ func (d *dentry) restoreDescendantsRecursive(ctx context.Context, opts *vfs.Comp
256
330
return nil
257
331
}
258
332
333
+ // Preconditions: d.deletedDataSR != nil.
334
+ func (d * dentry ) restoreDead (ctx context.Context , opts * vfs.CompleteRestoreOptions ) error {
335
+ parent := d .parent .Load ()
336
+ // This is a deleted regular file. Recreate it on the host filesystem
337
+ // temporarily, fill it with data and then proceed with the restore.
338
+ _ , h , err := parent .openCreate (ctx , d .name , linux .O_WRONLY , linux .FileMode (d .mode .Load ()), auth .KUID (d .uid .Load ()), auth .KGID (d .gid .Load ()), false /* createDentry */ )
339
+ if err != nil {
340
+ return fmt .Errorf ("failed to re-create deleted file %q: %w" , genericDebugPathname (d .fs , d ), err )
341
+ }
342
+ defer h .close (ctx )
343
+ n , err := h .writeFromBlocksAt (ctx , safemem .BlockSeqOf (safemem .BlockFromSafeSlice (d .deletedDataSR )), 0 )
344
+ if err != nil {
345
+ return fmt .Errorf ("failed to write deleted file %q: %w" , genericDebugPathname (d .fs , d ), err )
346
+ }
347
+ if n != uint64 (len (d .deletedDataSR )) {
348
+ return fmt .Errorf ("failed to write all of deleted file %q: wrote %d bytes, expected %d" , genericDebugPathname (d .fs , d ), n , len (d .deletedDataSR ))
349
+ }
350
+ d .deletedDataSR = nil
351
+ if err := d .restoreFile (ctx , opts ); err != nil {
352
+ if err := parent .unlink (ctx , d .name , 0 /* flags */ ); err != nil {
353
+ // Log warning, give preference to the restore error.
354
+ log .Warningf ("failed to clean up recreated deleted file %q: %v" , genericDebugPathname (d .fs , d ), err )
355
+ }
356
+ return err
357
+ }
358
+ if err := parent .unlink (ctx , d .name , 0 /* flags */ ); err != nil {
359
+ return fmt .Errorf ("failed to clean up recreated deleted file %q: %v" , genericDebugPathname (d .fs , d ), err )
360
+ }
361
+ return nil
362
+ }
363
+
259
364
func (fd * specialFileFD ) completeRestore (ctx context.Context ) error {
260
365
d := fd .dentry ()
261
366
h , err := d .openHandle (ctx , fd .vfsfd .IsReadable (), fd .vfsfd .IsWritable (), false /* trunc */ )
0 commit comments