diff --git a/pkg/fuse/fuse.go b/pkg/fuse/fuse.go index 1e3b61c26347..81ea12a78220 100644 --- a/pkg/fuse/fuse.go +++ b/pkg/fuse/fuse.go @@ -46,19 +46,19 @@ func NewJFS() *JFS { } } -func (fs *JFS) replyEntry(out *fuse.EntryOut, entry *meta.Entry) fuse.Status { - out.NodeId = uint64(entry.Inode) +func (fs *JFS) replyEntry(out *fuse.EntryOut, e *meta.Entry) fuse.Status { + out.NodeId = uint64(e.Inode) out.Generation = 1 out.SetAttrTimeout(fs.attrTimeout) - if entry.Attr.Typ == meta.TypeDirectory { + if e.Attr.Typ == meta.TypeDirectory { out.SetEntryTimeout(fs.direntryTimeout) } else { out.SetEntryTimeout(fs.entryTimeout) } - if vfs.IsSpecialNode(entry.Inode) { + if vfs.IsSpecialNode(e.Inode) { out.SetAttrTimeout(time.Hour) } - attrToStat(entry.Inode, entry.Attr, &out.Attr) + attrToStat(e.Inode, e.Attr, &out.Attr) return 0 } @@ -368,7 +368,7 @@ func (fs *JFS) ReadDirPlus(cancel <-chan struct{}, in *fuse.ReadIn, out *fuse.Di break } if e.Attr.Full { - vfs.UpdateEntry(e) + vfs.UpdateLength(e.Inode, e.Attr) fs.replyEntry(eo, e) } else { eo.Ino = uint64(e.Inode) diff --git a/pkg/vfs/handle.go b/pkg/vfs/handle.go index 6a56f4e02e92..651f46332463 100644 --- a/pkg/vfs/handle.go +++ b/pkg/vfs/handle.go @@ -32,8 +32,6 @@ type handle struct { children []*meta.Entry // for file - length uint64 - mode uint8 locks uint8 flockOwner uint64 // kernel 3.1- does not pass lock_owner in release() reader FileReader @@ -51,11 +49,14 @@ type handle struct { } func (h *handle) addOp(ctx Context) { + h.Lock() + defer h.Unlock() h.ops = append(h.ops, ctx) } func (h *handle) removeOp(ctx Context) { h.Lock() + defer h.Unlock() for i, c := range h.ops { if c == ctx { h.ops[i] = h.ops[len(h.ops)-1] @@ -63,13 +64,14 @@ func (h *handle) removeOp(ctx Context) { break } } - h.Unlock() } func (h *handle) cancelOp(pid uint32) { if pid == 0 { return } + h.Lock() + defer h.Unlock() for _, c := range h.ops { if c.Pid() == pid || c.Pid() > 0 && c.Duration() > time.Second { c.Cancel() @@ -86,11 +88,8 @@ func (h *handle) Rlock(ctx Context) bool { } } h.readers++ - if h.reader == nil { - h.reader = reader.Open(h.inode, h.length) - } - h.addOp(ctx) h.Unlock() + h.addOp(ctx) return true } @@ -115,11 +114,8 @@ func (h *handle) Wlock(ctx Context) bool { } h.writers-- h.writing = 1 - if h.writer == nil { - h.writer = writer.Open(h.inode, h.length) - } - h.addOp(ctx) h.Unlock() + h.addOp(ctx) return true } @@ -186,25 +182,14 @@ func releaseHandle(inode Ino, fh uint64) { } } -func updateHandleLength(inode Ino, length uint64) { - hanleLock.Lock() - for _, h := range handles[inode] { - h.Lock() - h.length = length - h.Unlock() - } - hanleLock.Unlock() -} - func newFileHandle(mode uint8, inode Ino, length uint64) uint64 { h := newHandle(inode) h.Lock() defer h.Unlock() - h.length = length - h.mode = mode - if mode == modeRead { + if mode&modeRead != 0 { h.reader = reader.Open(inode, length) - } else if mode == modeWrite { + } + if mode&modeWrite != 0 { h.writer = writer.Open(inode, length) } return h.fh diff --git a/pkg/vfs/reader.go b/pkg/vfs/reader.go index 643d5b52736f..53ea8156ba6e 100644 --- a/pkg/vfs/reader.go +++ b/pkg/vfs/reader.go @@ -71,7 +71,8 @@ type FileReader interface { } type DataReader interface { - Open(inode Ino, fleng uint64) FileReader + Open(inode Ino, length uint64) FileReader + Truncate(inode Ino, length uint64) } type frange struct { @@ -298,6 +299,7 @@ type fileReader struct { r *dataReader } +// protected by f func (f *fileReader) newSlice(block *frange) *sliceReader { s := &sliceReader{} s.file = f @@ -498,6 +500,7 @@ func (f *fileReader) splitRange(block *frange) []uint64 { return ranges } +// protected by f func (f *fileReader) readAhead(block *frange) { f.visit(func(r *sliceReader) { if r.state.valid() && r.block.off <= block.off && r.block.end() > block.off { @@ -639,6 +642,12 @@ func (f *fileReader) Read(ctx meta.Context, offset uint64, buf []byte) (int, sys return f.waitForIO(ctx, reqs, buf) } +func (f *fileReader) Truncate(length uint64) { + f.Lock() + f.length = length + f.Unlock() +} + func (f *fileReader) visit(fn func(s *sliceReader)) { var next *sliceReader for s := f.slices; s != nil; s = next { @@ -690,11 +699,11 @@ func NewDataReader(conf *Config, m meta.Meta, store chunk.ChunkStore) DataReader } } -func (r *dataReader) Open(inode Ino, len uint64) FileReader { +func (r *dataReader) Open(inode Ino, length uint64) FileReader { f := &fileReader{ r: r, inode: inode, - length: len, + length: length, } f.last = &(f.slices) @@ -706,6 +715,23 @@ func (r *dataReader) Open(inode Ino, len uint64) FileReader { return f } +func (r *dataReader) Truncate(inode Ino, length uint64) { + // r could be hold inside f, so Unlock r first to avoid deadlock + r.Lock() + var fs []*fileReader + f := r.files[inode] + for f != nil { + fs = append(fs, f) + f = f.next + } + r.Unlock() + for _, f := range fs { + f.Lock() + f.length = length + f.Unlock() + } +} + func (r *dataReader) readSlice(ctx context.Context, s *meta.Slice, page *chunk.Page, off int) error { buf := page.Data read := 0 diff --git a/pkg/vfs/vfs.go b/pkg/vfs/vfs.go index 2b762490ddf9..b4389baea12a 100644 --- a/pkg/vfs/vfs.go +++ b/pkg/vfs/vfs.go @@ -92,13 +92,7 @@ func Lookup(ctx Context, parent Ino, name string) (entry *meta.Entry, err syscal if err != 0 { return } - if attr.Typ == meta.TypeFile { - maxfleng := writer.GetLength(inode) - if maxfleng > attr.Length { - attr.Length = maxfleng - } - updateHandleLength(inode, attr.Length) - } + UpdateLength(inode, attr) entry = &meta.Entry{Inode: inode, Attr: attr} return } @@ -115,13 +109,7 @@ func GetAttr(ctx Context, ino Ino, opened uint8) (entry *meta.Entry, err syscall if err != 0 { return } - if attr.Typ == meta.TypeFile { - maxfleng := writer.GetLength(ino) - if maxfleng > attr.Length { - attr.Length = maxfleng - } - updateHandleLength(ino, attr.Length) - } + UpdateLength(ino, attr) entry = &meta.Entry{Inode: ino, Attr: attr} return } @@ -295,6 +283,7 @@ func Link(ctx Context, ino Ino, newparent Ino, newname string) (entry *meta.Entr var attr = &Attr{} err = m.Link(ctx, ino, newparent, newname, attr) if err == 0 { + UpdateLength(ino, attr) entry = &meta.Entry{Inode: ino, Attr: attr} } return @@ -310,14 +299,12 @@ func Opendir(ctx Context, ino Ino) (fh uint64, err syscall.Errno) { return } -func UpdateEntry(e *meta.Entry) { - attr := e.Attr +func UpdateLength(inode Ino, attr *meta.Attr) { if attr.Full && attr.Typ == meta.TypeFile { - maxfleng := writer.GetLength(e.Inode) - if maxfleng > attr.Length { - attr.Length = maxfleng + length := writer.GetLength(inode) + if length > attr.Length { + attr.Length = length } - updateHandleLength(e.Inode, attr.Length) } } @@ -447,10 +434,7 @@ func Open(ctx Context, ino Ino, flags uint32) (entry *meta.Entry, fh uint64, err return } - maxfleng := writer.GetLength(ino) - if maxfleng > attr.Length { - attr.Length = maxfleng - } + UpdateLength(ino, attr) fh = newFileHandle(oflags, ino, attr.Length) entry = &meta.Entry{Inode: ino, Attr: attr} return @@ -471,61 +455,12 @@ func Truncate(ctx Context, ino Ino, size int64, opened uint8, attr *Attr) (err s return } writer.Flush(ctx, ino) - var flags uint8 - trycnt := 0 - if attr == nil { - attr = &Attr{} - } - for { - err = m.Truncate(ctx, ino, flags, uint64(size), attr) - if err == syscall.ENOTSUP { - err = m.GetAttr(ctx, ino, attr) - if err == 0 { - fleng := attr.Length - logger.Debugf("fill zero %d-%d", fleng, size) - w := writer.Open(ino, fleng) - block := make([]byte, 1<<17) - for fleng < uint64(size) { - n := uint64(len(block)) - if fleng+n > uint64(size) { - n = uint64(size) - fleng - } - err = w.Write(ctx, fleng, block[:n]) - if err != 0 { - err = syscall.EIO - break - } - fleng += n - } - if fleng == uint64(size) { - err = w.Close(ctx) - } else { - w.Close(ctx) - } - } - if err != 0 { - err = syscall.EINTR // retry - } - } - if err == 0 || err == syscall.EROFS || err == syscall.EACCES || err == syscall.EPERM || err == syscall.ENOENT || err == syscall.ENOSPC || err == syscall.EINTR { - break - } else { - trycnt++ - if trycnt >= 30 { - break - } - t := 1 + (trycnt-1)*300 - if trycnt > 30 { - t = 10000 - } - time.Sleep(time.Millisecond * time.Duration(t)) - } - } + err = m.Truncate(ctx, ino, 0, uint64(size), attr) if err != 0 { return } - updateHandleLength(ino, uint64(size)) writer.Truncate(ino, uint64(size)) + reader.Truncate(ino, uint64(size)) return 0 } @@ -606,7 +541,7 @@ func Read(ctx Context, ino Ino, buf []byte, off uint64, fh uint64) (n int, err s err = syscall.EFBIG return } - if h.mode == modeWrite { + if h.reader == nil { err = syscall.EACCES return } @@ -641,7 +576,7 @@ func Write(ctx Context, ino Ino, buf []byte, off, fh uint64) (err syscall.Errno) err = syscall.EFBIG return } - if h.mode == modeRead { + if h.writer == nil { err = syscall.EACCES return } @@ -661,18 +596,7 @@ func Write(ctx Context, ino Ino, buf []byte, off, fh uint64) (err syscall.Errno) if err != 0 { return } - - h.Lock() - var newfleng uint64 - if off+size > h.length { - newfleng = off + size - h.length = newfleng - } - h.Unlock() - if newfleng > 0 { - writer.Truncate(ino, newfleng) - updateHandleLength(ino, newfleng) - } + reader.Truncate(ino, writer.GetLength(ino)) return } @@ -695,7 +619,7 @@ func Fallocate(ctx Context, ino Ino, mode uint8, off, length int64, fh uint64) ( err = syscall.EFBIG return } - if h.mode == modeRead { + if h.writer == nil { err = syscall.EACCES return } @@ -711,9 +635,7 @@ func Fallocate(ctx Context, ino Ino, mode uint8, off, length int64, fh uint64) ( } func doFsync(ctx Context, h *handle) (err syscall.Errno) { - h.Lock() - if h.writer != nil && (h.mode != modeRead) { - h.Unlock() + if h.writer != nil { if !h.Wlock(ctx) { return syscall.EINTR } @@ -724,8 +646,6 @@ func doFsync(ctx Context, h *handle) (err syscall.Errno) { if err == syscall.ENOENT || err == syscall.EPERM || err == syscall.EINVAL { err = syscall.EBADF } - } else { - h.Unlock() } return err } @@ -741,10 +661,7 @@ func Flush(ctx Context, ino Ino, fh uint64, lockOwner uint64) (err syscall.Errno return } - h.Lock() - locks := h.locks - if h.writer != nil && (h.mode != modeRead) { - h.Unlock() + if h.writer != nil { if !h.Wlock(ctx) { h.cancelOp(ctx.Pid()) err = syscall.EINTR @@ -757,10 +674,12 @@ func Flush(ctx Context, ino Ino, fh uint64, lockOwner uint64) (err syscall.Errno } h.removeOp(ctx) h.Wunlock() - h.Lock() } else if h.reader != nil { h.cancelOp(ctx.Pid()) } + + h.Lock() + locks := h.locks h.Unlock() if locks&2 != 0 { m.Setlk(ctx, ino, lockOwner, false, syscall.F_UNLCK, 0, 0x7FFFFFFFFFFFFFFF, 0) diff --git a/pkg/vfs/writer.go b/pkg/vfs/writer.go index 94c8405e8ebd..13adf6875c7e 100644 --- a/pkg/vfs/writer.go +++ b/pkg/vfs/writer.go @@ -35,14 +35,14 @@ type FileWriter interface { Flush(ctx meta.Context) syscall.Errno Close(ctx meta.Context) syscall.Errno GetLength() uint64 - Truncate(maxfleng uint64) + Truncate(length uint64) } type DataWriter interface { Open(inode Ino, fleng uint64) FileWriter Flush(ctx meta.Context, inode Ino) syscall.Errno GetLength(inode Ino) uint64 - Truncate(inode Ino, maxfleng uint64) + Truncate(inode Ino, length uint64) } type sliceWriter struct {