github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/vfs/file_description_impl_util.go (about)

     1  // Copyright 2019 The gVisor Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package vfs
    16  
    17  import (
    18  	"bytes"
    19  	"io"
    20  
    21  	"github.com/SagerNet/gvisor/pkg/abi/linux"
    22  	"github.com/SagerNet/gvisor/pkg/context"
    23  	"github.com/SagerNet/gvisor/pkg/errors/linuxerr"
    24  	"github.com/SagerNet/gvisor/pkg/sentry/arch"
    25  	fslock "github.com/SagerNet/gvisor/pkg/sentry/fs/lock"
    26  	"github.com/SagerNet/gvisor/pkg/sentry/memmap"
    27  	"github.com/SagerNet/gvisor/pkg/sync"
    28  	"github.com/SagerNet/gvisor/pkg/syserror"
    29  	"github.com/SagerNet/gvisor/pkg/usermem"
    30  	"github.com/SagerNet/gvisor/pkg/waiter"
    31  )
    32  
    33  // The following design pattern is strongly recommended for filesystem
    34  // implementations to adapt:
    35  //   - Have a local fileDescription struct (containing FileDescription) which
    36  //     embeds FileDescriptionDefaultImpl and overrides the default methods
    37  //     which are common to all fd implementations for that filesystem like
    38  //     StatusFlags, SetStatusFlags, Stat, SetStat, StatFS, etc.
    39  //   - This should be embedded in all file description implementations as the
    40  //     first field by value.
    41  //   - Directory FDs would also embed DirectoryFileDescriptionDefaultImpl.
    42  
    43  // FileDescriptionDefaultImpl may be embedded by implementations of
    44  // FileDescriptionImpl to obtain implementations of many FileDescriptionImpl
    45  // methods with default behavior analogous to Linux's.
    46  //
    47  // +stateify savable
    48  type FileDescriptionDefaultImpl struct{}
    49  
    50  // OnClose implements FileDescriptionImpl.OnClose analogously to
    51  // file_operations::flush == NULL in Linux.
    52  func (FileDescriptionDefaultImpl) OnClose(ctx context.Context) error {
    53  	return nil
    54  }
    55  
    56  // StatFS implements FileDescriptionImpl.StatFS analogously to
    57  // super_operations::statfs == NULL in Linux.
    58  func (FileDescriptionDefaultImpl) StatFS(ctx context.Context) (linux.Statfs, error) {
    59  	return linux.Statfs{}, syserror.ENOSYS
    60  }
    61  
    62  // Allocate implements FileDescriptionImpl.Allocate analogously to
    63  // fallocate called on an invalid type of file in Linux.
    64  //
    65  // Note that directories can rely on this implementation even though they
    66  // should technically return EISDIR. Allocate should never be called for a
    67  // directory, because it requires a writable fd.
    68  func (FileDescriptionDefaultImpl) Allocate(ctx context.Context, mode, offset, length uint64) error {
    69  	return linuxerr.ENODEV
    70  }
    71  
    72  // Readiness implements waiter.Waitable.Readiness analogously to
    73  // file_operations::poll == NULL in Linux.
    74  func (FileDescriptionDefaultImpl) Readiness(mask waiter.EventMask) waiter.EventMask {
    75  	// include/linux/poll.h:vfs_poll() => DEFAULT_POLLMASK
    76  	return waiter.ReadableEvents | waiter.WritableEvents
    77  }
    78  
    79  // EventRegister implements waiter.Waitable.EventRegister analogously to
    80  // file_operations::poll == NULL in Linux.
    81  func (FileDescriptionDefaultImpl) EventRegister(e *waiter.Entry, mask waiter.EventMask) {
    82  }
    83  
    84  // EventUnregister implements waiter.Waitable.EventUnregister analogously to
    85  // file_operations::poll == NULL in Linux.
    86  func (FileDescriptionDefaultImpl) EventUnregister(e *waiter.Entry) {
    87  }
    88  
    89  // PRead implements FileDescriptionImpl.PRead analogously to
    90  // file_operations::read == file_operations::read_iter == NULL in Linux.
    91  func (FileDescriptionDefaultImpl) PRead(ctx context.Context, dst usermem.IOSequence, offset int64, opts ReadOptions) (int64, error) {
    92  	return 0, linuxerr.EINVAL
    93  }
    94  
    95  // Read implements FileDescriptionImpl.Read analogously to
    96  // file_operations::read == file_operations::read_iter == NULL in Linux.
    97  func (FileDescriptionDefaultImpl) Read(ctx context.Context, dst usermem.IOSequence, opts ReadOptions) (int64, error) {
    98  	return 0, linuxerr.EINVAL
    99  }
   100  
   101  // PWrite implements FileDescriptionImpl.PWrite analogously to
   102  // file_operations::write == file_operations::write_iter == NULL in Linux.
   103  func (FileDescriptionDefaultImpl) PWrite(ctx context.Context, src usermem.IOSequence, offset int64, opts WriteOptions) (int64, error) {
   104  	return 0, linuxerr.EINVAL
   105  }
   106  
   107  // Write implements FileDescriptionImpl.Write analogously to
   108  // file_operations::write == file_operations::write_iter == NULL in Linux.
   109  func (FileDescriptionDefaultImpl) Write(ctx context.Context, src usermem.IOSequence, opts WriteOptions) (int64, error) {
   110  	return 0, linuxerr.EINVAL
   111  }
   112  
   113  // IterDirents implements FileDescriptionImpl.IterDirents analogously to
   114  // file_operations::iterate == file_operations::iterate_shared == NULL in
   115  // Linux.
   116  func (FileDescriptionDefaultImpl) IterDirents(ctx context.Context, cb IterDirentsCallback) error {
   117  	return syserror.ENOTDIR
   118  }
   119  
   120  // Seek implements FileDescriptionImpl.Seek analogously to
   121  // file_operations::llseek == NULL in Linux.
   122  func (FileDescriptionDefaultImpl) Seek(ctx context.Context, offset int64, whence int32) (int64, error) {
   123  	return 0, linuxerr.ESPIPE
   124  }
   125  
   126  // Sync implements FileDescriptionImpl.Sync analogously to
   127  // file_operations::fsync == NULL in Linux.
   128  func (FileDescriptionDefaultImpl) Sync(ctx context.Context) error {
   129  	return linuxerr.EINVAL
   130  }
   131  
   132  // ConfigureMMap implements FileDescriptionImpl.ConfigureMMap analogously to
   133  // file_operations::mmap == NULL in Linux.
   134  func (FileDescriptionDefaultImpl) ConfigureMMap(ctx context.Context, opts *memmap.MMapOpts) error {
   135  	return linuxerr.ENODEV
   136  }
   137  
   138  // Ioctl implements FileDescriptionImpl.Ioctl analogously to
   139  // file_operations::unlocked_ioctl == NULL in Linux.
   140  func (FileDescriptionDefaultImpl) Ioctl(ctx context.Context, uio usermem.IO, args arch.SyscallArguments) (uintptr, error) {
   141  	return 0, syserror.ENOTTY
   142  }
   143  
   144  // ListXattr implements FileDescriptionImpl.ListXattr analogously to
   145  // inode_operations::listxattr == NULL in Linux.
   146  func (FileDescriptionDefaultImpl) ListXattr(ctx context.Context, size uint64) ([]string, error) {
   147  	// This isn't exactly accurate; see FileDescription.ListXattr.
   148  	return nil, linuxerr.ENOTSUP
   149  }
   150  
   151  // GetXattr implements FileDescriptionImpl.GetXattr analogously to
   152  // inode::i_opflags & IOP_XATTR == 0 in Linux.
   153  func (FileDescriptionDefaultImpl) GetXattr(ctx context.Context, opts GetXattrOptions) (string, error) {
   154  	return "", linuxerr.ENOTSUP
   155  }
   156  
   157  // SetXattr implements FileDescriptionImpl.SetXattr analogously to
   158  // inode::i_opflags & IOP_XATTR == 0 in Linux.
   159  func (FileDescriptionDefaultImpl) SetXattr(ctx context.Context, opts SetXattrOptions) error {
   160  	return linuxerr.ENOTSUP
   161  }
   162  
   163  // RemoveXattr implements FileDescriptionImpl.RemoveXattr analogously to
   164  // inode::i_opflags & IOP_XATTR == 0 in Linux.
   165  func (FileDescriptionDefaultImpl) RemoveXattr(ctx context.Context, name string) error {
   166  	return linuxerr.ENOTSUP
   167  }
   168  
   169  // DirectoryFileDescriptionDefaultImpl may be embedded by implementations of
   170  // FileDescriptionImpl that always represent directories to obtain
   171  // implementations of non-directory I/O methods that return EISDIR.
   172  //
   173  // +stateify savable
   174  type DirectoryFileDescriptionDefaultImpl struct{}
   175  
   176  // Allocate implements DirectoryFileDescriptionDefaultImpl.Allocate.
   177  func (DirectoryFileDescriptionDefaultImpl) Allocate(ctx context.Context, mode, offset, length uint64) error {
   178  	return syserror.EISDIR
   179  }
   180  
   181  // PRead implements FileDescriptionImpl.PRead.
   182  func (DirectoryFileDescriptionDefaultImpl) PRead(ctx context.Context, dst usermem.IOSequence, offset int64, opts ReadOptions) (int64, error) {
   183  	return 0, syserror.EISDIR
   184  }
   185  
   186  // Read implements FileDescriptionImpl.Read.
   187  func (DirectoryFileDescriptionDefaultImpl) Read(ctx context.Context, dst usermem.IOSequence, opts ReadOptions) (int64, error) {
   188  	return 0, syserror.EISDIR
   189  }
   190  
   191  // PWrite implements FileDescriptionImpl.PWrite.
   192  func (DirectoryFileDescriptionDefaultImpl) PWrite(ctx context.Context, src usermem.IOSequence, offset int64, opts WriteOptions) (int64, error) {
   193  	return 0, syserror.EISDIR
   194  }
   195  
   196  // Write implements FileDescriptionImpl.Write.
   197  func (DirectoryFileDescriptionDefaultImpl) Write(ctx context.Context, src usermem.IOSequence, opts WriteOptions) (int64, error) {
   198  	return 0, syserror.EISDIR
   199  }
   200  
   201  // DentryMetadataFileDescriptionImpl may be embedded by implementations of
   202  // FileDescriptionImpl for which FileDescriptionOptions.UseDentryMetadata is
   203  // true to obtain implementations of Stat and SetStat that panic.
   204  //
   205  // +stateify savable
   206  type DentryMetadataFileDescriptionImpl struct{}
   207  
   208  // Stat implements FileDescriptionImpl.Stat.
   209  func (DentryMetadataFileDescriptionImpl) Stat(ctx context.Context, opts StatOptions) (linux.Statx, error) {
   210  	panic("illegal call to DentryMetadataFileDescriptionImpl.Stat")
   211  }
   212  
   213  // SetStat implements FileDescriptionImpl.SetStat.
   214  func (DentryMetadataFileDescriptionImpl) SetStat(ctx context.Context, opts SetStatOptions) error {
   215  	panic("illegal call to DentryMetadataFileDescriptionImpl.SetStat")
   216  }
   217  
   218  // DynamicBytesSource represents a data source for a
   219  // DynamicBytesFileDescriptionImpl.
   220  //
   221  // +stateify savable
   222  type DynamicBytesSource interface {
   223  	// Generate writes the file's contents to buf.
   224  	Generate(ctx context.Context, buf *bytes.Buffer) error
   225  }
   226  
   227  // StaticData implements DynamicBytesSource over a static string.
   228  //
   229  // +stateify savable
   230  type StaticData struct {
   231  	Data string
   232  }
   233  
   234  // Generate implements DynamicBytesSource.
   235  func (s *StaticData) Generate(ctx context.Context, buf *bytes.Buffer) error {
   236  	buf.WriteString(s.Data)
   237  	return nil
   238  }
   239  
   240  // WritableDynamicBytesSource extends DynamicBytesSource to allow writes to the
   241  // underlying source.
   242  //
   243  // TODO(b/179825241): Make utility for integer-based writable files.
   244  type WritableDynamicBytesSource interface {
   245  	DynamicBytesSource
   246  
   247  	// Write sends writes to the source.
   248  	Write(ctx context.Context, src usermem.IOSequence, offset int64) (int64, error)
   249  }
   250  
   251  // DynamicBytesFileDescriptionImpl may be embedded by implementations of
   252  // FileDescriptionImpl that represent read-only regular files whose contents
   253  // are backed by a bytes.Buffer that is regenerated when necessary, consistent
   254  // with Linux's fs/seq_file.c:single_open().
   255  //
   256  // If data additionally implements WritableDynamicBytesSource, writes are
   257  // dispatched to the implementer. The source data is not automatically modified.
   258  //
   259  // DynamicBytesFileDescriptionImpl.SetDataSource() must be called before first
   260  // use.
   261  //
   262  // +stateify savable
   263  type DynamicBytesFileDescriptionImpl struct {
   264  	data     DynamicBytesSource // immutable
   265  	mu       sync.Mutex         `state:"nosave"` // protects the following fields
   266  	buf      bytes.Buffer       `state:".([]byte)"`
   267  	off      int64
   268  	lastRead int64 // offset at which the last Read, PRead, or Seek ended
   269  }
   270  
   271  func (fd *DynamicBytesFileDescriptionImpl) saveBuf() []byte {
   272  	return fd.buf.Bytes()
   273  }
   274  
   275  func (fd *DynamicBytesFileDescriptionImpl) loadBuf(p []byte) {
   276  	fd.buf.Write(p)
   277  }
   278  
   279  // SetDataSource must be called exactly once on fd before first use.
   280  func (fd *DynamicBytesFileDescriptionImpl) SetDataSource(data DynamicBytesSource) {
   281  	fd.data = data
   282  }
   283  
   284  // Preconditions: fd.mu must be locked.
   285  func (fd *DynamicBytesFileDescriptionImpl) preadLocked(ctx context.Context, dst usermem.IOSequence, offset int64, opts *ReadOptions) (int64, error) {
   286  	// Regenerate the buffer if it's empty, or before pread() at a new offset.
   287  	// Compare fs/seq_file.c:seq_read() => traverse().
   288  	switch {
   289  	case offset != fd.lastRead:
   290  		fd.buf.Reset()
   291  		fallthrough
   292  	case fd.buf.Len() == 0:
   293  		if err := fd.data.Generate(ctx, &fd.buf); err != nil {
   294  			fd.buf.Reset()
   295  			// fd.off is not updated in this case.
   296  			fd.lastRead = 0
   297  			return 0, err
   298  		}
   299  	}
   300  	bs := fd.buf.Bytes()
   301  	if offset >= int64(len(bs)) {
   302  		return 0, io.EOF
   303  	}
   304  	n, err := dst.CopyOut(ctx, bs[offset:])
   305  	fd.lastRead = offset + int64(n)
   306  	return int64(n), err
   307  }
   308  
   309  // PRead implements FileDescriptionImpl.PRead.
   310  func (fd *DynamicBytesFileDescriptionImpl) PRead(ctx context.Context, dst usermem.IOSequence, offset int64, opts ReadOptions) (int64, error) {
   311  	fd.mu.Lock()
   312  	n, err := fd.preadLocked(ctx, dst, offset, &opts)
   313  	fd.mu.Unlock()
   314  	return n, err
   315  }
   316  
   317  // Read implements FileDescriptionImpl.Read.
   318  func (fd *DynamicBytesFileDescriptionImpl) Read(ctx context.Context, dst usermem.IOSequence, opts ReadOptions) (int64, error) {
   319  	fd.mu.Lock()
   320  	n, err := fd.preadLocked(ctx, dst, fd.off, &opts)
   321  	fd.off += n
   322  	fd.mu.Unlock()
   323  	return n, err
   324  }
   325  
   326  // Seek implements FileDescriptionImpl.Seek.
   327  func (fd *DynamicBytesFileDescriptionImpl) Seek(ctx context.Context, offset int64, whence int32) (int64, error) {
   328  	fd.mu.Lock()
   329  	defer fd.mu.Unlock()
   330  	switch whence {
   331  	case linux.SEEK_SET:
   332  		// Use offset as given.
   333  	case linux.SEEK_CUR:
   334  		offset += fd.off
   335  	default:
   336  		// fs/seq_file:seq_lseek() rejects SEEK_END etc.
   337  		return 0, linuxerr.EINVAL
   338  	}
   339  	if offset < 0 {
   340  		return 0, linuxerr.EINVAL
   341  	}
   342  	if offset != fd.lastRead {
   343  		// Regenerate the file's contents immediately. Compare
   344  		// fs/seq_file.c:seq_lseek() => traverse().
   345  		fd.buf.Reset()
   346  		if err := fd.data.Generate(ctx, &fd.buf); err != nil {
   347  			fd.buf.Reset()
   348  			fd.off = 0
   349  			fd.lastRead = 0
   350  			return 0, err
   351  		}
   352  		fd.lastRead = offset
   353  	}
   354  	fd.off = offset
   355  	return offset, nil
   356  }
   357  
   358  // Preconditions: fd.mu must be locked.
   359  func (fd *DynamicBytesFileDescriptionImpl) pwriteLocked(ctx context.Context, src usermem.IOSequence, offset int64, opts WriteOptions) (int64, error) {
   360  	if opts.Flags&^(linux.RWF_HIPRI|linux.RWF_DSYNC|linux.RWF_SYNC) != 0 {
   361  		return 0, syserror.EOPNOTSUPP
   362  	}
   363  	limit, err := CheckLimit(ctx, offset, src.NumBytes())
   364  	if err != nil {
   365  		return 0, err
   366  	}
   367  	src = src.TakeFirst64(limit)
   368  
   369  	writable, ok := fd.data.(WritableDynamicBytesSource)
   370  	if !ok {
   371  		return 0, syserror.EIO
   372  	}
   373  	n, err := writable.Write(ctx, src, offset)
   374  	if err != nil {
   375  		return 0, err
   376  	}
   377  
   378  	// Invalidate cached data that might exist prior to this call.
   379  	fd.buf.Reset()
   380  	return n, nil
   381  }
   382  
   383  // PWrite implements FileDescriptionImpl.PWrite.
   384  func (fd *DynamicBytesFileDescriptionImpl) PWrite(ctx context.Context, src usermem.IOSequence, offset int64, opts WriteOptions) (int64, error) {
   385  	fd.mu.Lock()
   386  	n, err := fd.pwriteLocked(ctx, src, offset, opts)
   387  	fd.mu.Unlock()
   388  	return n, err
   389  }
   390  
   391  // Write implements FileDescriptionImpl.Write.
   392  func (fd *DynamicBytesFileDescriptionImpl) Write(ctx context.Context, src usermem.IOSequence, opts WriteOptions) (int64, error) {
   393  	fd.mu.Lock()
   394  	n, err := fd.pwriteLocked(ctx, src, fd.off, opts)
   395  	fd.off += n
   396  	fd.mu.Unlock()
   397  	return n, err
   398  }
   399  
   400  // GenericConfigureMMap may be used by most implementations of
   401  // FileDescriptionImpl.ConfigureMMap.
   402  func GenericConfigureMMap(fd *FileDescription, m memmap.Mappable, opts *memmap.MMapOpts) error {
   403  	opts.Mappable = m
   404  	opts.MappingIdentity = fd
   405  	fd.IncRef()
   406  	return nil
   407  }
   408  
   409  // LockFD may be used by most implementations of FileDescriptionImpl.Lock*
   410  // functions. Caller must call Init().
   411  //
   412  // +stateify savable
   413  type LockFD struct {
   414  	locks *FileLocks
   415  }
   416  
   417  // SupportsLocks implements FileDescriptionImpl.SupportsLocks.
   418  func (LockFD) SupportsLocks() bool {
   419  	return true
   420  }
   421  
   422  // Init initializes fd with FileLocks to use.
   423  func (fd *LockFD) Init(locks *FileLocks) {
   424  	fd.locks = locks
   425  }
   426  
   427  // Locks returns the locks associated with this file.
   428  func (fd *LockFD) Locks() *FileLocks {
   429  	return fd.locks
   430  }
   431  
   432  // LockBSD implements FileDescriptionImpl.LockBSD.
   433  func (fd *LockFD) LockBSD(ctx context.Context, uid fslock.UniqueID, ownerPID int32, t fslock.LockType, block fslock.Blocker) error {
   434  	return fd.locks.LockBSD(ctx, uid, ownerPID, t, block)
   435  }
   436  
   437  // UnlockBSD implements FileDescriptionImpl.UnlockBSD.
   438  func (fd *LockFD) UnlockBSD(ctx context.Context, uid fslock.UniqueID) error {
   439  	fd.locks.UnlockBSD(uid)
   440  	return nil
   441  }
   442  
   443  // LockPOSIX implements FileDescriptionImpl.LockPOSIX.
   444  func (fd *LockFD) LockPOSIX(ctx context.Context, uid fslock.UniqueID, ownerPID int32, t fslock.LockType, r fslock.LockRange, block fslock.Blocker) error {
   445  	return fd.locks.LockPOSIX(ctx, uid, ownerPID, t, r, block)
   446  }
   447  
   448  // UnlockPOSIX implements FileDescriptionImpl.UnlockPOSIX.
   449  func (fd *LockFD) UnlockPOSIX(ctx context.Context, uid fslock.UniqueID, r fslock.LockRange) error {
   450  	return fd.locks.UnlockPOSIX(ctx, uid, r)
   451  }
   452  
   453  // TestPOSIX implements FileDescriptionImpl.TestPOSIX.
   454  func (fd *LockFD) TestPOSIX(ctx context.Context, uid fslock.UniqueID, t fslock.LockType, r fslock.LockRange) (linux.Flock, error) {
   455  	return fd.locks.TestPOSIX(ctx, uid, t, r)
   456  }
   457  
   458  // NoLockFD implements Lock*/Unlock* portion of FileDescriptionImpl interface
   459  // returning ENOLCK.
   460  //
   461  // +stateify savable
   462  type NoLockFD struct{}
   463  
   464  // SupportsLocks implements FileDescriptionImpl.SupportsLocks.
   465  func (NoLockFD) SupportsLocks() bool {
   466  	return false
   467  }
   468  
   469  // LockBSD implements FileDescriptionImpl.LockBSD.
   470  func (NoLockFD) LockBSD(ctx context.Context, uid fslock.UniqueID, ownerPID int32, t fslock.LockType, block fslock.Blocker) error {
   471  	return linuxerr.ENOLCK
   472  }
   473  
   474  // UnlockBSD implements FileDescriptionImpl.UnlockBSD.
   475  func (NoLockFD) UnlockBSD(ctx context.Context, uid fslock.UniqueID) error {
   476  	return linuxerr.ENOLCK
   477  }
   478  
   479  // LockPOSIX implements FileDescriptionImpl.LockPOSIX.
   480  func (NoLockFD) LockPOSIX(ctx context.Context, uid fslock.UniqueID, ownerPID int32, t fslock.LockType, r fslock.LockRange, block fslock.Blocker) error {
   481  	return linuxerr.ENOLCK
   482  }
   483  
   484  // UnlockPOSIX implements FileDescriptionImpl.UnlockPOSIX.
   485  func (NoLockFD) UnlockPOSIX(ctx context.Context, uid fslock.UniqueID, r fslock.LockRange) error {
   486  	return linuxerr.ENOLCK
   487  }
   488  
   489  // TestPOSIX implements FileDescriptionImpl.TestPOSIX.
   490  func (NoLockFD) TestPOSIX(ctx context.Context, uid fslock.UniqueID, t fslock.LockType, r fslock.LockRange) (linux.Flock, error) {
   491  	return linux.Flock{}, linuxerr.ENOLCK
   492  }
   493  
   494  // BadLockFD implements Lock*/Unlock* portion of FileDescriptionImpl interface
   495  // returning EBADF.
   496  //
   497  // +stateify savable
   498  type BadLockFD struct{}
   499  
   500  // SupportsLocks implements FileDescriptionImpl.SupportsLocks.
   501  func (BadLockFD) SupportsLocks() bool {
   502  	return false
   503  }
   504  
   505  // LockBSD implements FileDescriptionImpl.LockBSD.
   506  func (BadLockFD) LockBSD(ctx context.Context, uid fslock.UniqueID, ownerPID int32, t fslock.LockType, block fslock.Blocker) error {
   507  	return linuxerr.EBADF
   508  }
   509  
   510  // UnlockBSD implements FileDescriptionImpl.UnlockBSD.
   511  func (BadLockFD) UnlockBSD(ctx context.Context, uid fslock.UniqueID) error {
   512  	return linuxerr.EBADF
   513  }
   514  
   515  // LockPOSIX implements FileDescriptionImpl.LockPOSIX.
   516  func (BadLockFD) LockPOSIX(ctx context.Context, uid fslock.UniqueID, ownerPID int32, t fslock.LockType, r fslock.LockRange, block fslock.Blocker) error {
   517  	return linuxerr.EBADF
   518  }
   519  
   520  // UnlockPOSIX implements FileDescriptionImpl.UnlockPOSIX.
   521  func (BadLockFD) UnlockPOSIX(ctx context.Context, uid fslock.UniqueID, r fslock.LockRange) error {
   522  	return linuxerr.EBADF
   523  }
   524  
   525  // TestPOSIX implements FileDescriptionImpl.TestPOSIX.
   526  func (BadLockFD) TestPOSIX(ctx context.Context, uid fslock.UniqueID, t fslock.LockType, r fslock.LockRange) (linux.Flock, error) {
   527  	return linux.Flock{}, linuxerr.EBADF
   528  }