Use open fids when fstat()ing gofer files.

PiperOrigin-RevId: 243018347
Change-Id: I1e5b80607c1df0747482abea61db7fcf24536d37
This commit is contained in:
Jamie Liu
2019-04-11 00:43:04 -07:00
committed by Shentubot
parent cc48969bb7
commit 4209edafb6
43 changed files with 422 additions and 293 deletions
+5 -4
View File
@@ -42,10 +42,11 @@ const (
//
// +stateify savable
type Area struct {
waiter.AlwaysReady `state:"nosave"`
fsutil.FileNoFsync `state:"nosave"`
fsutil.FileNoopFlush `state:"nosave"`
fsutil.FileNotDirReaddir `state:"nosave"`
waiter.AlwaysReady `state:"nosave"`
fsutil.FileNoFsync `state:"nosave"`
fsutil.FileNoopFlush `state:"nosave"`
fsutil.FileNotDirReaddir `state:"nosave"`
fsutil.FileUseInodeUnstableAttr `state:"nosave"`
ad *Device
+4 -3
View File
@@ -85,9 +85,10 @@ func (bd *Device) GetFile(ctx context.Context, d *fs.Dirent, flags fs.FileFlags)
//
// +stateify savable
type Proc struct {
waiter.AlwaysReady `state:"nosave"`
fsutil.FileNoFsync `state:"nosave"`
fsutil.FileNotDirReaddir `state:"nosave"`
waiter.AlwaysReady `state:"nosave"`
fsutil.FileNoFsync `state:"nosave"`
fsutil.FileNotDirReaddir `state:"nosave"`
fsutil.FileUseInodeUnstableAttr `state:"nosave"`
bd *Device
task *kernel.Task
+10 -9
View File
@@ -59,15 +59,16 @@ func (f *fullDevice) GetFile(ctx context.Context, dirent *fs.Dirent, flags fs.Fi
// +stateify savable
type fullFileOperations struct {
waiter.AlwaysReady `state:"nosave"`
fsutil.FileGenericSeek `state:"nosave"`
fsutil.FileNoIoctl `state:"nosave"`
fsutil.FileNoMMap `state:"nosave"`
fsutil.FileNoopFlush `state:"nosave"`
fsutil.FileNoopFsync `state:"nosave"`
fsutil.FileNoopRelease `state:"nosave"`
fsutil.FileNotDirReaddir `state:"nosave"`
readZeros `state:"nosave"`
waiter.AlwaysReady `state:"nosave"`
fsutil.FileGenericSeek `state:"nosave"`
fsutil.FileNoIoctl `state:"nosave"`
fsutil.FileNoMMap `state:"nosave"`
fsutil.FileNoopFlush `state:"nosave"`
fsutil.FileNoopFsync `state:"nosave"`
fsutil.FileNoopRelease `state:"nosave"`
fsutil.FileNotDirReaddir `state:"nosave"`
fsutil.FileUseInodeUnstableAttr `state:"nosave"`
readZeros `state:"nosave"`
}
var _ fs.FileOperations = (*fullFileOperations)(nil)
+21 -19
View File
@@ -60,16 +60,17 @@ func (n *nullDevice) GetFile(ctx context.Context, dirent *fs.Dirent, flags fs.Fi
// +stateify savable
type nullFileOperations struct {
waiter.AlwaysReady `state:"nosave"`
fsutil.FileGenericSeek `state:"nosave"`
fsutil.FileNoIoctl `state:"nosave"`
fsutil.FileNoMMap `state:"nosave"`
fsutil.FileNoopFlush `state:"nosave"`
fsutil.FileNoopFsync `state:"nosave"`
fsutil.FileNoopRead `state:"nosave"`
fsutil.FileNoopWrite `state:"nosave"`
fsutil.FileNoopRelease `state:"nosave"`
fsutil.FileNotDirReaddir `state:"nosave"`
waiter.AlwaysReady `state:"nosave"`
fsutil.FileGenericSeek `state:"nosave"`
fsutil.FileNoIoctl `state:"nosave"`
fsutil.FileNoMMap `state:"nosave"`
fsutil.FileNoopFlush `state:"nosave"`
fsutil.FileNoopFsync `state:"nosave"`
fsutil.FileNoopRead `state:"nosave"`
fsutil.FileNoopWrite `state:"nosave"`
fsutil.FileNoopRelease `state:"nosave"`
fsutil.FileNotDirReaddir `state:"nosave"`
fsutil.FileUseInodeUnstableAttr `state:"nosave"`
}
var _ fs.FileOperations = (*nullFileOperations)(nil)
@@ -100,15 +101,16 @@ func (zd *zeroDevice) GetFile(ctx context.Context, dirent *fs.Dirent, flags fs.F
// +stateify savable
type zeroFileOperations struct {
waiter.AlwaysReady `state:"nosave"`
fsutil.FileGenericSeek `state:"nosave"`
fsutil.FileNoopFlush `state:"nosave"`
fsutil.FileNoopFsync `state:"nosave"`
fsutil.FileNoopRelease `state:"nosave"`
fsutil.FileNoopWrite `state:"nosave"`
fsutil.FileNotDirReaddir `state:"nosave"`
fsutil.FileNoIoctl `state:"nosave"`
readZeros `state:"nosave"`
waiter.AlwaysReady `state:"nosave"`
fsutil.FileGenericSeek `state:"nosave"`
fsutil.FileNoopFlush `state:"nosave"`
fsutil.FileNoopFsync `state:"nosave"`
fsutil.FileNoopRelease `state:"nosave"`
fsutil.FileNoopWrite `state:"nosave"`
fsutil.FileNotDirReaddir `state:"nosave"`
fsutil.FileNoIoctl `state:"nosave"`
fsutil.FileUseInodeUnstableAttr `state:"nosave"`
readZeros `state:"nosave"`
}
var _ fs.FileOperations = (*zeroFileOperations)(nil)
+10 -9
View File
@@ -57,15 +57,16 @@ func (*randomDevice) GetFile(ctx context.Context, dirent *fs.Dirent, flags fs.Fi
// +stateify savable
type randomFileOperations struct {
waiter.AlwaysReady `state:"nosave"`
fsutil.FileGenericSeek `state:"nosave"`
fsutil.FileNotDirReaddir `state:"nosave"`
fsutil.FileNoMMap `state:"nosave"`
fsutil.FileNoopFsync `state:"nosave"`
fsutil.FileNoopFlush `state:"nosave"`
fsutil.FileNoIoctl `state:"nosave"`
fsutil.FileNoopRelease `state:"nosave"`
fsutil.FileNoopWrite `state:"nosave"`
waiter.AlwaysReady `state:"nosave"`
fsutil.FileGenericSeek `state:"nosave"`
fsutil.FileNotDirReaddir `state:"nosave"`
fsutil.FileNoMMap `state:"nosave"`
fsutil.FileNoopFsync `state:"nosave"`
fsutil.FileNoopFlush `state:"nosave"`
fsutil.FileNoIoctl `state:"nosave"`
fsutil.FileNoopRelease `state:"nosave"`
fsutil.FileNoopWrite `state:"nosave"`
fsutil.FileUseInodeUnstableAttr `state:"nosave"`
}
var _ fs.FileOperations = (*randomFileOperations)(nil)
+8 -7
View File
@@ -37,13 +37,14 @@ import (
//
// +stateify savable
type pipeOperations struct {
fsutil.FilePipeSeek `state:"nosave"`
fsutil.FileNotDirReaddir `state:"nosave"`
fsutil.FileNoFsync `state:"nosave"`
fsutil.FileNoopFlush `state:"nosave"`
fsutil.FileNoMMap `state:"nosave"`
fsutil.FileNoIoctl `state:"nosave"`
waiter.Queue `state:"nosave"`
fsutil.FilePipeSeek `state:"nosave"`
fsutil.FileNotDirReaddir `state:"nosave"`
fsutil.FileNoFsync `state:"nosave"`
fsutil.FileNoopFlush `state:"nosave"`
fsutil.FileNoMMap `state:"nosave"`
fsutil.FileNoIoctl `state:"nosave"`
fsutil.FileUseInodeUnstableAttr `state:"nosave"`
waiter.Queue `state:"nosave"`
// flags are the flags used to open the pipe.
flags fs.FileFlags `state:".(fs.FileFlags)"`
+12
View File
@@ -408,6 +408,18 @@ func (f *File) ConfigureMMap(ctx context.Context, opts *memmap.MMapOpts) error {
return f.FileOperations.ConfigureMMap(ctx, f, opts)
}
// UnstableAttr calls f.FileOperations.UnstableAttr with f as the File.
//
// Returns syserror.ErrInterrupted if interrupted.
func (f *File) UnstableAttr(ctx context.Context) (UnstableAttr, error) {
if !f.mu.Lock(ctx) {
return UnstableAttr{}, syserror.ErrInterrupted
}
defer f.mu.Unlock()
return f.FileOperations.UnstableAttr(ctx, f)
}
// MappedName implements memmap.MappingIdentity.MappedName.
func (f *File) MappedName(ctx context.Context) string {
root := RootFromContext(ctx)
+6
View File
@@ -96,6 +96,12 @@ type FileOperations interface {
// memmap.Mappable.
ConfigureMMap(ctx context.Context, file *File, opts *memmap.MMapOpts) error
// UnstableAttr returns the "unstable" attributes of the inode represented
// by the file. Most implementations can embed
// fsutil.FileUseInodeUnstableAttr, which delegates to
// InodeOperations.UnstableAttr.
UnstableAttr(ctx context.Context, file *File) (UnstableAttr, error)
// Ioctl implements the ioctl(2) linux syscall.
//
// io provides access to the virtual memory space to which pointers in args
+26
View File
@@ -339,6 +339,32 @@ func (*overlayFileOperations) ConfigureMMap(ctx context.Context, file *File, opt
return nil
}
// UnstableAttr implements fs.FileOperations.UnstableAttr.
func (f *overlayFileOperations) UnstableAttr(ctx context.Context, file *File) (UnstableAttr, error) {
// Hot path. Avoid defers.
f.upperMu.Lock()
if f.upper != nil {
attr, err := f.upper.UnstableAttr(ctx)
f.upperMu.Unlock()
return attr, err
}
f.upperMu.Unlock()
// It's possible that copy-up has occurred, but we haven't opened a upper
// file yet. If this is the case, just use the upper inode's UnstableAttr
// rather than opening a file.
o := file.Dirent.Inode.overlay
o.copyMu.RLock()
if o.upper != nil {
attr, err := o.upper.UnstableAttr(ctx)
o.copyMu.RUnlock()
return attr, err
}
o.copyMu.RUnlock()
return f.lower.UnstableAttr(ctx)
}
// Ioctl implements fs.FileOperations.Ioctl and always returns ENOTTY.
func (*overlayFileOperations) Ioctl(ctx context.Context, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
return 0, syserror.ENOTTY
+9 -8
View File
@@ -31,14 +31,15 @@ import (
// TestFileOperations is an implementation of the File interface. It provides all
// required methods.
type TestFileOperations struct {
fsutil.FileNoopRelease `state:"nosave"`
fsutil.FilePipeSeek `state:"nosave"`
fsutil.FileNotDirReaddir `state:"nosave"`
fsutil.FileNoFsync `state:"nosave"`
fsutil.FileNoopFlush `state:"nosave"`
fsutil.FileNoMMap `state:"nosave"`
fsutil.FileNoIoctl `state:"nosave"`
waiter.AlwaysReady `state:"nosave"`
fsutil.FileNoopRelease `state:"nosave"`
fsutil.FilePipeSeek `state:"nosave"`
fsutil.FileNotDirReaddir `state:"nosave"`
fsutil.FileNoFsync `state:"nosave"`
fsutil.FileNoopFlush `state:"nosave"`
fsutil.FileNoMMap `state:"nosave"`
fsutil.FileNoIoctl `state:"nosave"`
fsutil.FileUseInodeUnstableAttr `state:"nosave"`
waiter.AlwaysReady `state:"nosave"`
}
// NewTestFile creates and initializes a new test file.
+23 -12
View File
@@ -224,7 +224,7 @@ func (FileNoIoctl) Ioctl(ctx context.Context, io usermem.IO, args arch.SyscallAr
}
// DirFileOperations implements most of fs.FileOperations for directories,
// except for Readdir which the embedding type must implement.
// except for Readdir and UnstableAttr which the embedding type must implement.
type DirFileOperations struct {
waiter.AlwaysReady
FileGenericSeek
@@ -250,7 +250,8 @@ func (*DirFileOperations) Write(context.Context, *fs.File, usermem.IOSequence, i
//
// +stateify savable
type StaticDirFileOperations struct {
DirFileOperations
DirFileOperations `state:"nosave"`
FileUseInodeUnstableAttr `state:"nosave"`
// dentryMap is a SortedDentryMap used to implement Readdir.
dentryMap *fs.SortedDentryMap
@@ -291,16 +292,17 @@ func (sdfo *StaticDirFileOperations) Readdir(ctx context.Context, file *fs.File,
//
// +stateify savable
type NoReadWriteFile struct {
waiter.AlwaysReady `state:"nosave"`
FileGenericSeek `state:"nosave"`
FileNoIoctl `state:"nosave"`
FileNoMMap `state:"nosave"`
FileNoopFsync `state:"nosave"`
FileNoopFlush `state:"nosave"`
FileNoopRelease `state:"nosave"`
FileNoRead `state:"nosave"`
FileNoWrite `state:"nosave"`
FileNotDirReaddir `state:"nosave"`
waiter.AlwaysReady `state:"nosave"`
FileGenericSeek `state:"nosave"`
FileNoIoctl `state:"nosave"`
FileNoMMap `state:"nosave"`
FileNoopFsync `state:"nosave"`
FileNoopFlush `state:"nosave"`
FileNoopRelease `state:"nosave"`
FileNoRead `state:"nosave"`
FileNoWrite `state:"nosave"`
FileNotDirReaddir `state:"nosave"`
FileUseInodeUnstableAttr `state:"nosave"`
}
var _ fs.FileOperations = (*NoReadWriteFile)(nil)
@@ -365,3 +367,12 @@ type FileNoopRead struct{}
func (FileNoopRead) Read(context.Context, *fs.File, usermem.IOSequence, int64) (int64, error) {
return 0, nil
}
// FileUseInodeUnstableAttr implements fs.FileOperations.UnstableAttr by calling
// InodeOperations.UnstableAttr.
type FileUseInodeUnstableAttr struct{}
// UnstableAttr implements fs.FileOperations.UnstableAttr.
func (FileUseInodeUnstableAttr) UnstableAttr(ctx context.Context, file *fs.File) (fs.UnstableAttr, error) {
return file.Dirent.Inode.UnstableAttr(ctx)
}
+10 -9
View File
@@ -238,15 +238,16 @@ func (i *InodeSimpleExtendedAttributes) Listxattr(_ *fs.Inode) (map[string]struc
//
// +stateify savable
type staticFile struct {
waiter.AlwaysReady `state:"nosave"`
FileGenericSeek `state:"nosave"`
FileNoIoctl `state:"nosave"`
FileNoMMap `state:"nosave"`
FileNoopFsync `state:"nosave"`
FileNoopFlush `state:"nosave"`
FileNoopRelease `state:"nosave"`
FileNoopWrite `state:"nosave"`
FileNotDirReaddir `state:"nosave"`
waiter.AlwaysReady `state:"nosave"`
FileGenericSeek `state:"nosave"`
FileNoIoctl `state:"nosave"`
FileNoMMap `state:"nosave"`
FileNoopFsync `state:"nosave"`
FileNoopFlush `state:"nosave"`
FileNoopRelease `state:"nosave"`
FileNoopWrite `state:"nosave"`
FileNotDirReaddir `state:"nosave"`
FileUseInodeUnstableAttr `state:"nosave"`
FileStaticContentReader
}
+16
View File
@@ -310,6 +310,22 @@ func (f *fileOperations) ConfigureMMap(ctx context.Context, file *fs.File, opts
return f.inodeOperations.configureMMap(file, opts)
}
// UnstableAttr implements fs.FileOperations.UnstableAttr.
func (f *fileOperations) UnstableAttr(ctx context.Context, file *fs.File) (fs.UnstableAttr, error) {
s := f.inodeOperations.session()
if s.cachePolicy.cacheUAttrs(file.Dirent.Inode) {
return f.inodeOperations.cachingInodeOps.UnstableAttr(ctx, file.Dirent.Inode)
}
// Use f.handles.File, which represents 9P fids that have been opened,
// instead of inodeFileState.file, which represents 9P fids that have not.
// This may be significantly more efficient in some implementations.
_, valid, pattr, err := getattr(ctx, f.handles.File)
if err != nil {
return fs.UnstableAttr{}, err
}
return unstable(ctx, valid, pattr, s.mounter, s.client), nil
}
// Seek implements fs.FileOperations.Seek.
func (f *fileOperations) Seek(ctx context.Context, file *fs.File, whence fs.SeekWhence, offset int64) (int64, error) {
return fsutil.SeekWithDirCursor(ctx, file, whence, offset, &f.dirCursor)
+3 -2
View File
@@ -36,8 +36,9 @@ import (
//
// +stateify savable
type fileOperations struct {
fsutil.FileNoIoctl `state:"nosave"`
fsutil.FileNoopRelease `state:"nosave"`
fsutil.FileNoIoctl `state:"nosave"`
fsutil.FileNoopRelease `state:"nosave"`
fsutil.FileUseInodeUnstableAttr `state:"nosave"`
// iops are the Inode operations for this file.
iops *inodeOperations `state:"wait"`
+5
View File
@@ -186,6 +186,11 @@ func (*Inotify) ConfigureMMap(context.Context, *File, *memmap.MMapOpts) error {
return syserror.ENODEV
}
// UnstableAttr implements FileOperations.UnstableAttr.
func (i *Inotify) UnstableAttr(ctx context.Context, file *File) (UnstableAttr, error) {
return file.Dirent.Inode.UnstableAttr(ctx)
}
// Ioctl implements fs.FileOperations.Ioctl.
func (i *Inotify) Ioctl(ctx context.Context, io usermem.IO, args arch.SyscallArguments) (uintptr, error) {
switch args[1].Int() {
+10 -9
View File
@@ -77,15 +77,16 @@ func (i *execArgInode) GetFile(ctx context.Context, dirent *fs.Dirent, flags fs.
// +stateify savable
type execArgFile struct {
waiter.AlwaysReady `state:"nosave"`
fsutil.FileGenericSeek `state:"nosave"`
fsutil.FileNoIoctl `state:"nosave"`
fsutil.FileNoMMap `state:"nosave"`
fsutil.FileNotDirReaddir `state:"nosave"`
fsutil.FileNoopRelease `state:"nosave"`
fsutil.FileNoopFlush `state:"nosave"`
fsutil.FileNoopFsync `state:"nosave"`
fsutil.FileNoopWrite `state:"nosave"`
waiter.AlwaysReady `state:"nosave"`
fsutil.FileGenericSeek `state:"nosave"`
fsutil.FileNoIoctl `state:"nosave"`
fsutil.FileNoMMap `state:"nosave"`
fsutil.FileNotDirReaddir `state:"nosave"`
fsutil.FileNoopRelease `state:"nosave"`
fsutil.FileNoopFlush `state:"nosave"`
fsutil.FileNoopFsync `state:"nosave"`
fsutil.FileNoopWrite `state:"nosave"`
fsutil.FileUseInodeUnstableAttr `state:"nosave"`
// arg is the type of exec argument this file contains.
arg execArgType
+11 -10
View File
@@ -91,7 +91,7 @@ func readDescriptors(t *kernel.Task, c *fs.DirCtx, offset int64, toDentAttr func
// fd implements fs.InodeOperations for a file in /proc/TID/fd/.
type fd struct {
ramfs.Symlink
*fs.File
file *fs.File
}
var _ fs.InodeOperations = (*fd)(nil)
@@ -103,7 +103,7 @@ func newFd(t *kernel.Task, f *fs.File, msrc *fs.MountSource) *fs.Inode {
fd := &fd{
// RootOwner overridden by taskOwnedInodeOps.UnstableAttrs().
Symlink: *ramfs.NewSymlink(t, fs.RootOwner, ""),
File: f,
file: f,
}
return newProcInode(fd, msrc, fs.Symlink, t)
}
@@ -112,8 +112,8 @@ func newFd(t *kernel.Task, f *fs.File, msrc *fs.MountSource) *fs.Inode {
// arguments are ignored.
func (f *fd) GetFile(context.Context, *fs.Dirent, fs.FileFlags) (*fs.File, error) {
// Take a reference on the fs.File.
f.File.IncRef()
return f.File, nil
f.file.IncRef()
return f.file, nil
}
// Readlink returns the current target.
@@ -122,14 +122,14 @@ func (f *fd) Readlink(ctx context.Context, _ *fs.Inode) (string, error) {
if root != nil {
defer root.DecRef()
}
n, _ := f.Dirent.FullName(root)
n, _ := f.file.Dirent.FullName(root)
return n, nil
}
// Getlink implements fs.InodeOperations.Getlink.
func (f *fd) Getlink(context.Context, *fs.Inode) (*fs.Dirent, error) {
f.Dirent.IncRef()
return f.Dirent, nil
f.file.Dirent.IncRef()
return f.file.Dirent, nil
}
// Truncate is ignored.
@@ -139,12 +139,12 @@ func (f *fd) Truncate(context.Context, *fs.Inode, int64) error {
func (f *fd) Release(ctx context.Context) {
f.Symlink.Release(ctx)
f.File.DecRef()
f.file.DecRef()
}
// Close releases the reference on the file.
func (f *fd) Close() error {
f.DecRef()
f.file.DecRef()
return nil
}
@@ -212,7 +212,8 @@ func (f *fdDir) GetFile(ctx context.Context, dirent *fs.Dirent, flags fs.FileFla
// +stateify savable
type fdDirFile struct {
fsutil.DirFileOperations `state:"nosave"`
fsutil.DirFileOperations `state:"nosave"`
fsutil.FileUseInodeUnstableAttr `state:"nosave"`
isInfoFile bool
+2 -1
View File
@@ -191,7 +191,8 @@ func (p *proc) GetFile(ctx context.Context, dirent *fs.Dirent, flags fs.FileFlag
//
// +stateify savable
type rootProcFile struct {
fsutil.DirFileOperations `state:"nosave"`
fsutil.DirFileOperations `state:"nosave"`
fsutil.FileUseInodeUnstableAttr `state:"nosave"`
iops *proc
}
+9 -8
View File
@@ -60,14 +60,15 @@ func (i *rpcInetInode) GetFile(ctx context.Context, dirent *fs.Dirent, flags fs.
// rpcInetFile implements fs.FileOperations as RPCs.
type rpcInetFile struct {
waiter.AlwaysReady `state:"nosave"`
fsutil.FileGenericSeek `state:"nosave"`
fsutil.FileNoIoctl `state:"nosave"`
fsutil.FileNoMMap `state:"nosave"`
fsutil.FileNoopFlush `state:"nosave"`
fsutil.FileNoopFsync `state:"nosave"`
fsutil.FileNoopRelease `state:"nosave"`
fsutil.FileNotDirReaddir `state:"nosave"`
waiter.AlwaysReady `state:"nosave"`
fsutil.FileGenericSeek `state:"nosave"`
fsutil.FileNoIoctl `state:"nosave"`
fsutil.FileNoMMap `state:"nosave"`
fsutil.FileNoopFlush `state:"nosave"`
fsutil.FileNoopFsync `state:"nosave"`
fsutil.FileNoopRelease `state:"nosave"`
fsutil.FileNotDirReaddir `state:"nosave"`
fsutil.FileUseInodeUnstableAttr `state:"nosave"`
inode *rpcInetInode
}
+9 -8
View File
@@ -183,14 +183,15 @@ func (s *SeqFile) updateSourceLocked(ctx context.Context, record int) {
//
// +stateify savable
type seqFileOperations struct {
waiter.AlwaysReady `state:"nosave"`
fsutil.FileGenericSeek `state:"nosave"`
fsutil.FileNoIoctl `state:"nosave"`
fsutil.FileNoMMap `state:"nosave"`
fsutil.FileNoopFlush `state:"nosave"`
fsutil.FileNoopFsync `state:"nosave"`
fsutil.FileNoopRelease `state:"nosave"`
fsutil.FileNotDirReaddir `state:"nosave"`
waiter.AlwaysReady `state:"nosave"`
fsutil.FileGenericSeek `state:"nosave"`
fsutil.FileNoIoctl `state:"nosave"`
fsutil.FileNoMMap `state:"nosave"`
fsutil.FileNoopFlush `state:"nosave"`
fsutil.FileNoopFsync `state:"nosave"`
fsutil.FileNoopRelease `state:"nosave"`
fsutil.FileNotDirReaddir `state:"nosave"`
fsutil.FileUseInodeUnstableAttr `state:"nosave"`
seqFile *SeqFile
}

Some files were not shown because too many files have changed in this diff Show More