mirror of
https://gitee.com/juicedata/JuiceFS.git
synced 2025-12-06 09:39:14 +08:00
windows: add attr, entry and dir-entry cache; (#6053)
This commit is contained in:
2
.github/workflows/wintest.yml
vendored
2
.github/workflows/wintest.yml
vendored
@@ -132,7 +132,7 @@ jobs:
|
||||
- name: Juicefs Mount
|
||||
run: |
|
||||
$env:PATH+=";C:\Program Files (x86)\WinFsp\bin"
|
||||
./juicefs.exe mount -d redis://127.0.0.1:6379/1 z:
|
||||
./juicefs.exe mount -d redis://127.0.0.1:6379/1 z: --fuse-trace-log c:/fuse.log
|
||||
|
||||
- name: Run Winfsp Tests
|
||||
run: |
|
||||
|
||||
10
cmd/bench.go
10
cmd/bench.go
@@ -428,8 +428,14 @@ func bench(ctx *cli.Context) error {
|
||||
progress.Done()
|
||||
|
||||
/* --- Clean-up --- */
|
||||
if err := exec.Command("rm", "-rf", bm.tmpdir).Run(); err != nil {
|
||||
logger.Warnf("Failed to cleanup %s: %s", bm.tmpdir, err)
|
||||
if runtime.GOOS == "windows" {
|
||||
if err := exec.Command("cmd", "/C", "rd", "/s", "/q", bm.tmpdir).Run(); err != nil {
|
||||
logger.Warnf("Failed to cleanup %s: %s", bm.tmpdir, err)
|
||||
}
|
||||
} else {
|
||||
if err := exec.Command("rm", "-rf", bm.tmpdir).Run(); err != nil {
|
||||
logger.Warnf("Failed to cleanup %s: %s", bm.tmpdir, err)
|
||||
}
|
||||
}
|
||||
|
||||
/* --- Report --- */
|
||||
|
||||
@@ -104,9 +104,10 @@ func getDaemonStage() int {
|
||||
|
||||
func mountMain(v *vfs.VFS, c *cli.Context) {
|
||||
v.Conf.AccessLog = c.String("access-log")
|
||||
v.Conf.AttrTimeout = utils.Duration(c.String("attr-cache"))
|
||||
v.Conf.EntryTimeout = utils.Duration(c.String("entry-cache"))
|
||||
v.Conf.DirEntryTimeout = utils.Duration(c.String("dir-entry-cache"))
|
||||
|
||||
fileCacheTimeout := utils.Duration(c.String("entry-cache"))
|
||||
dirCacheTimeout := utils.Duration(c.String("dir-entry-cache"))
|
||||
delayCloseTime := utils.Duration(c.String("delay-close"))
|
||||
|
||||
traceLog := c.String("fuse-trace-log")
|
||||
@@ -114,7 +115,7 @@ func mountMain(v *vfs.VFS, c *cli.Context) {
|
||||
winfsp.SetTraceOutput(traceLog)
|
||||
}
|
||||
|
||||
winfsp.Serve(v, c.String("o"), fileCacheTimeout.Seconds(), dirCacheTimeout.Seconds(),
|
||||
winfsp.Serve(v, c.String("o"),
|
||||
c.Bool("as-root"), int(delayCloseTime.Seconds()), c.Bool("show-dot-files"),
|
||||
c.Int("winfsp-threads"), c.Bool("case-sensitive"), c.Bool("report-case"))
|
||||
}
|
||||
|
||||
44
pkg/fs/fs.go
44
pkg/fs/fs.go
@@ -113,6 +113,8 @@ func (fs *FileStat) Gid() int { return int(fs.attr.Gid) }
|
||||
func (fs *FileStat) Atime() int64 { return fs.attr.Atime*1000 + int64(fs.attr.Atimensec/1e6) }
|
||||
func (fs *FileStat) Mtime() int64 { return fs.attr.Mtime*1000 + int64(fs.attr.Mtimensec/1e6) }
|
||||
|
||||
func (fs *FileStat) Attr() *Attr { return fs.attr }
|
||||
|
||||
func AttrToFileInfo(inode Ino, attr *Attr) *FileStat {
|
||||
return &FileStat{inode: inode, attr: attr}
|
||||
}
|
||||
@@ -252,7 +254,7 @@ func (fs *FileSystem) cleanupCache() {
|
||||
}
|
||||
}
|
||||
|
||||
func (fs *FileSystem) invalidateEntry(parent Ino, name string) {
|
||||
func (fs *FileSystem) InvalidateEntry(parent Ino, name string) {
|
||||
fs.cacheM.Lock()
|
||||
defer fs.cacheM.Unlock()
|
||||
es, ok := fs.entries[parent]
|
||||
@@ -264,7 +266,7 @@ func (fs *FileSystem) invalidateEntry(parent Ino, name string) {
|
||||
}
|
||||
}
|
||||
|
||||
func (fs *FileSystem) invalidateAttr(ino Ino) {
|
||||
func (fs *FileSystem) InvalidateAttr(ino Ino) {
|
||||
fs.cacheM.Lock()
|
||||
defer fs.cacheM.Unlock()
|
||||
delete(fs.attrs, ino)
|
||||
@@ -453,7 +455,7 @@ func (fs *FileSystem) Mkdir(ctx meta.Context, p string, mode uint16, umask uint1
|
||||
if fs.conf.DirEntryTimeout > 0 {
|
||||
parent := parentDir(p)
|
||||
if fi, err := fs.resolve(ctx, parentDir(parent), true); err == 0 {
|
||||
fs.invalidateEntry(fi.inode, path.Base(parent))
|
||||
fs.InvalidateEntry(fi.inode, path.Base(parent))
|
||||
}
|
||||
}
|
||||
if fi2, e := fs.resolve(ctx, parentDir(p), true); e != 0 {
|
||||
@@ -462,7 +464,7 @@ func (fs *FileSystem) Mkdir(ctx meta.Context, p string, mode uint16, umask uint1
|
||||
err = fs.m.Mkdir(ctx, fi2.inode, path.Base(p), mode, umask, 0, &inode, nil)
|
||||
}
|
||||
}
|
||||
fs.invalidateEntry(fi.inode, path.Base(p))
|
||||
fs.InvalidateEntry(fi.inode, path.Base(p))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -516,7 +518,7 @@ func (fs *FileSystem) Delete0(ctx meta.Context, p string, callByUnlink bool) (er
|
||||
} else {
|
||||
err = fs.m.Unlink(ctx, parent.inode, path.Base(p))
|
||||
}
|
||||
fs.invalidateEntry(parent.inode, path.Base(p))
|
||||
fs.InvalidateEntry(parent.inode, path.Base(p))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -529,7 +531,7 @@ func (fs *FileSystem) Rmdir(ctx meta.Context, p string) (err syscall.Errno) {
|
||||
return
|
||||
}
|
||||
err = fs.m.Rmdir(ctx, parent.inode, path.Base(p))
|
||||
fs.invalidateEntry(parent.inode, path.Base(p))
|
||||
fs.InvalidateEntry(parent.inode, path.Base(p))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -542,7 +544,7 @@ func (fs *FileSystem) Rmr(ctx meta.Context, p string, skipTrash bool, numthreads
|
||||
return
|
||||
}
|
||||
err = fs.m.Remove(ctx, parent.inode, path.Base(p), skipTrash, numthreads, nil)
|
||||
fs.invalidateEntry(parent.inode, path.Base(p))
|
||||
fs.InvalidateEntry(parent.inode, path.Base(p))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -601,8 +603,8 @@ func (fs *FileSystem) Rename(ctx meta.Context, oldpath string, newpath string, f
|
||||
return err0
|
||||
}
|
||||
err = fs.m.Rename(ctx, oldfi.inode, path.Base(oldpath), newfi.inode, path.Base(newpath), flags, nil, nil)
|
||||
fs.invalidateEntry(oldfi.inode, path.Base(oldpath))
|
||||
fs.invalidateEntry(newfi.inode, path.Base(newpath))
|
||||
fs.InvalidateEntry(oldfi.inode, path.Base(oldpath))
|
||||
fs.InvalidateEntry(newfi.inode, path.Base(newpath))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -620,7 +622,7 @@ func (fs *FileSystem) Link(ctx meta.Context, src string, dst string) (err syscal
|
||||
return
|
||||
}
|
||||
err = fs.m.Link(ctx, fi.inode, pi.inode, path.Base(dst), nil)
|
||||
fs.invalidateEntry(pi.inode, path.Base(dst))
|
||||
fs.InvalidateEntry(pi.inode, path.Base(dst))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -636,7 +638,7 @@ func (fs *FileSystem) Symlink(ctx meta.Context, target string, link string) (err
|
||||
return
|
||||
}
|
||||
err = fs.m.Symlink(ctx, fi.inode, path.Base(link), target, nil, nil)
|
||||
fs.invalidateEntry(fi.inode, path.Base(link))
|
||||
fs.InvalidateEntry(fi.inode, path.Base(link))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -949,7 +951,7 @@ func (fs *FileSystem) Create(ctx meta.Context, p string, mode uint16, umask uint
|
||||
if fs.conf.DirEntryTimeout > 0 {
|
||||
parent := parentDir(p)
|
||||
if fi, err := fs.resolve(ctx, parentDir(parent), true); err == 0 {
|
||||
fs.invalidateEntry(fi.inode, path.Base(parent))
|
||||
fs.InvalidateEntry(fi.inode, path.Base(parent))
|
||||
}
|
||||
}
|
||||
if fi2, e := fs.resolve(ctx, parentDir(p), true); e != 0 {
|
||||
@@ -968,7 +970,7 @@ func (fs *FileSystem) Create(ctx meta.Context, p string, mode uint16, umask uint
|
||||
f.info = fi
|
||||
f.fs = fs
|
||||
}
|
||||
fs.invalidateEntry(fi.inode, path.Base(p))
|
||||
fs.InvalidateEntry(fi.inode, path.Base(p))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1089,7 +1091,7 @@ func (f *File) Chmod(ctx meta.Context, mode uint16) (err syscall.Errno) {
|
||||
defer func() { f.fs.log(l, "Chmod (%s,%o): %s", f.path, mode, errstr(err)) }()
|
||||
var attr = Attr{Mode: mode}
|
||||
err = f.fs.m.SetAttr(ctx, f.inode, meta.SetAttrMode, 0, &attr)
|
||||
f.fs.invalidateAttr(f.inode)
|
||||
f.fs.InvalidateAttr(f.inode)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1106,7 +1108,7 @@ func (f *File) Chown(ctx meta.Context, uid uint32, gid uint32) (err syscall.Errn
|
||||
}
|
||||
var attr = Attr{Uid: uid, Gid: gid}
|
||||
err = f.fs.m.SetAttr(ctx, f.inode, flag, 0, &attr)
|
||||
f.fs.invalidateAttr(f.inode)
|
||||
f.fs.InvalidateAttr(f.inode)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1130,7 +1132,7 @@ func (f *File) Utime(ctx meta.Context, atime, mtime int64) (err syscall.Errno) {
|
||||
attr.Mtime = mtime / 1000
|
||||
attr.Mtimensec = uint32(mtime%1000) * 1e6
|
||||
err = f.fs.m.SetAttr(ctx, f.inode, flag, 0, &attr)
|
||||
f.fs.invalidateAttr(f.inode)
|
||||
f.fs.InvalidateAttr(f.inode)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1156,7 +1158,7 @@ func (f *File) Utime2(ctx meta.Context, atimeSec, atimeNSec, mtimeSec, mtimeNsec
|
||||
attr.Mtime = mtimeSec
|
||||
attr.Mtimensec = uint32(mtimeNsec)
|
||||
err = f.fs.m.SetAttr(ctx, f.inode, flag, 0, &attr)
|
||||
f.fs.invalidateAttr(f.inode)
|
||||
f.fs.InvalidateAttr(f.inode)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1289,7 +1291,7 @@ func (f *File) Truncate(ctx meta.Context, length uint64) (err syscall.Errno) {
|
||||
f.fs.writer.Truncate(f.inode, length)
|
||||
f.fs.reader.Truncate(f.inode, length)
|
||||
f.info.attr.Length = length
|
||||
f.fs.invalidateAttr(f.inode)
|
||||
f.fs.InvalidateAttr(f.inode)
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1304,7 +1306,7 @@ func (f *File) Flush(ctx meta.Context) (err syscall.Errno) {
|
||||
l := vfs.NewLogContext(ctx)
|
||||
defer func() { f.fs.log(l, "Flush (%s): %s", f.path, errstr(err)) }()
|
||||
err = f.wdata.Flush(ctx)
|
||||
f.fs.invalidateAttr(f.inode)
|
||||
f.fs.InvalidateAttr(f.inode)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1318,7 +1320,7 @@ func (f *File) Fsync(ctx meta.Context) (err syscall.Errno) {
|
||||
l := vfs.NewLogContext(ctx)
|
||||
defer func() { f.fs.log(l, "Fsync (%s): %s", f.path, errstr(err)) }()
|
||||
err = f.wdata.Flush(ctx)
|
||||
f.fs.invalidateAttr(f.inode)
|
||||
f.fs.InvalidateAttr(f.inode)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1338,7 +1340,7 @@ func (f *File) Close(ctx meta.Context) (err syscall.Errno) {
|
||||
}
|
||||
if f.wdata != nil {
|
||||
err = f.wdata.Close(meta.Background())
|
||||
f.fs.invalidateAttr(f.inode)
|
||||
f.fs.InvalidateAttr(f.inode)
|
||||
f.wdata = nil
|
||||
}
|
||||
_ = f.fs.m.Close(ctx, f.inode)
|
||||
|
||||
@@ -40,8 +40,16 @@ import (
|
||||
|
||||
var logger = utils.GetLogger("juicefs")
|
||||
|
||||
const invalidFileHandle = uint64(0xffffffffffffffff)
|
||||
|
||||
type Ino = meta.Ino
|
||||
|
||||
type handleInfo struct {
|
||||
ino meta.Ino
|
||||
cacheAttr *meta.Attr
|
||||
attrExpiredAt time.Time
|
||||
}
|
||||
|
||||
func trace(vals ...interface{}) func(vals ...interface{}) {
|
||||
uid, gid, pid := fuse.Getcontext()
|
||||
return Trace(1, fmt.Sprintf("[uid=%v,gid=%v,pid=%d]", uid, gid, pid), vals...)
|
||||
@@ -49,24 +57,28 @@ func trace(vals ...interface{}) func(vals ...interface{}) {
|
||||
|
||||
type juice struct {
|
||||
fuse.FileSystemBase
|
||||
sync.Mutex
|
||||
conf *vfs.Config
|
||||
vfs *vfs.VFS
|
||||
fs *fs.FileSystem
|
||||
host *fuse.FileSystemHost
|
||||
handlers map[uint64]meta.Ino
|
||||
badfd map[uint64]uint64
|
||||
sync.RWMutex
|
||||
conf *vfs.Config
|
||||
vfs *vfs.VFS
|
||||
fs *fs.FileSystem
|
||||
host *fuse.FileSystemHost
|
||||
handlers map[uint64]handleInfo
|
||||
badfd map[uint64]uint64
|
||||
inoHandleMap map[meta.Ino][]uint64
|
||||
|
||||
asRoot bool
|
||||
delayClose int
|
||||
enabledGetPath bool
|
||||
disableSymlink bool
|
||||
|
||||
attrCacheTimeout time.Duration
|
||||
}
|
||||
|
||||
// Init is called when the file system is created.
|
||||
func (j *juice) Init() {
|
||||
j.handlers = make(map[uint64]meta.Ino)
|
||||
j.handlers = make(map[uint64]handleInfo)
|
||||
j.badfd = make(map[uint64]uint64)
|
||||
j.inoHandleMap = make(map[meta.Ino][]uint64)
|
||||
}
|
||||
|
||||
func (j *juice) newContext() vfs.LogContext {
|
||||
@@ -74,10 +86,10 @@ func (j *juice) newContext() vfs.LogContext {
|
||||
return vfs.NewLogContext(meta.Background())
|
||||
}
|
||||
uid, gid, pid := fuse.Getcontext()
|
||||
if uid == 0xffffffff {
|
||||
if uid == 0xffffffff || uid == 18 {
|
||||
uid = 0
|
||||
}
|
||||
if gid == 0xffffffff {
|
||||
if gid == 0xffffffff || gid == 18 {
|
||||
gid = 0
|
||||
}
|
||||
if pid == -1 {
|
||||
@@ -179,6 +191,9 @@ func (j *juice) Mknod(p string, mode uint32, dev uint64) (e int) {
|
||||
}
|
||||
_, errno := j.vfs.Mknod(ctx, parent.Inode(), path.Base(p), uint16(mode), 0, uint32(dev))
|
||||
e = errorconv(errno)
|
||||
if e == 0 {
|
||||
j.fs.InvalidateEntry(parent.Inode(), path.Base(p))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -261,6 +276,9 @@ func (j *juice) Chmod(path string, mode uint32) (e int) {
|
||||
return
|
||||
}
|
||||
e = errorconv(f.Chmod(ctx, uint16(mode)))
|
||||
if e == 0 {
|
||||
j.invalidateAttrCache(f.Inode())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -297,6 +315,9 @@ func (j *juice) Utimens(path string, tmsp []fuse.Timespec) (e int) {
|
||||
e = errorconv(err)
|
||||
} else {
|
||||
e = errorconv(f.Utime2(ctx, tmsp[0].Sec, tmsp[0].Nsec, tmsp[1].Sec, tmsp[1].Nsec))
|
||||
if e == 0 {
|
||||
j.invalidateAttrCache(f.Inode())
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -315,10 +336,18 @@ func (j *juice) Create(p string, flags int, mode uint32) (e int, fh uint64) {
|
||||
entry, fh, errno := j.vfs.Create(ctx, parent.Inode(), path.Base(p), uint16(mode), 0, uint32(fuseFlagToSyscall(flags)))
|
||||
if errno == 0 {
|
||||
j.Lock()
|
||||
j.handlers[fh] = entry.Inode
|
||||
j.handlers[fh] = handleInfo{
|
||||
ino: entry.Inode,
|
||||
cacheAttr: entry.Attr,
|
||||
attrExpiredAt: time.Now().Add(j.conf.AttrTimeout),
|
||||
}
|
||||
j.inoHandleMap[entry.Inode] = append(j.inoHandleMap[entry.Inode], fh)
|
||||
j.Unlock()
|
||||
}
|
||||
e = errorconv(errno)
|
||||
if e == 0 {
|
||||
j.fs.InvalidateEntry(parent.Inode(), path.Base(p))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -336,7 +365,7 @@ func (j *juice) Open(path string, flags int) (e int, fh uint64) {
|
||||
// The flags are a combination of the fuse.O_* constants.
|
||||
func (j *juice) OpenEx(p string, fi *fuse.FileInfo_t) (e int) {
|
||||
ctx := j.newContext()
|
||||
defer trace(p, fi.Flags)(&e)
|
||||
defer trace(p, fi.Flags)(&e, &fi.Fh)
|
||||
ino := meta.Ino(0)
|
||||
if strings.HasSuffix(p, "/.control") {
|
||||
ino, _ = vfs.GetInternalNodeByName(".control")
|
||||
@@ -368,7 +397,12 @@ func (j *juice) OpenEx(p string, fi *fuse.FileInfo_t) (e int) {
|
||||
fi.KeepCache = entry.Attr.KeepCache
|
||||
}
|
||||
j.Lock()
|
||||
j.handlers[fh] = ino
|
||||
j.handlers[fh] = handleInfo{
|
||||
ino: ino,
|
||||
cacheAttr: entry.Attr,
|
||||
attrExpiredAt: time.Now().Add(j.conf.AttrTimeout),
|
||||
}
|
||||
j.inoHandleMap[ino] = append(j.inoHandleMap[ino], fh)
|
||||
j.Unlock()
|
||||
}
|
||||
e = errorconv(errno)
|
||||
@@ -429,19 +463,20 @@ func attrToStat(inode Ino, attr *meta.Attr, stat *fuse.Stat_t) {
|
||||
}
|
||||
|
||||
func (j *juice) h2i(fh *uint64) meta.Ino {
|
||||
defer j.Unlock()
|
||||
j.Lock()
|
||||
ino := j.handlers[*fh]
|
||||
if ino == 0 {
|
||||
defer j.RUnlock()
|
||||
j.RLock()
|
||||
|
||||
entry := j.handlers[*fh]
|
||||
if entry.ino == 0 {
|
||||
newfh := j.badfd[*fh]
|
||||
if newfh != 0 {
|
||||
ino = j.handlers[newfh]
|
||||
if ino > 0 {
|
||||
entry = j.handlers[newfh]
|
||||
if entry.ino > 0 {
|
||||
*fh = newfh
|
||||
}
|
||||
}
|
||||
}
|
||||
return ino
|
||||
return entry.ino
|
||||
}
|
||||
|
||||
func (j *juice) reopen(p string, fh *uint64) meta.Ino {
|
||||
@@ -453,7 +488,7 @@ func (j *juice) reopen(p string, fh *uint64) meta.Ino {
|
||||
defer j.Unlock()
|
||||
j.badfd[*fh] = newfh
|
||||
*fh = newfh
|
||||
return j.handlers[newfh]
|
||||
return j.handlers[newfh].ino
|
||||
}
|
||||
|
||||
// Getattr gets file attributes.
|
||||
@@ -481,11 +516,77 @@ func (j *juice) getAttrForSpFile(ctx vfs.LogContext, p string, stat *fuse.Stat_t
|
||||
return
|
||||
}
|
||||
|
||||
func (j *juice) invalidateAttrCache(ino meta.Ino) {
|
||||
if j.attrCacheTimeout == 0 || ino == 0 {
|
||||
return
|
||||
}
|
||||
j.fs.InvalidateAttr(ino) // invalidate the attrcache in fs layer
|
||||
j.Lock()
|
||||
defer j.Unlock()
|
||||
|
||||
handlers := j.inoHandleMap[ino]
|
||||
for _, fh := range handlers {
|
||||
if cache, ok := j.handlers[fh]; ok {
|
||||
cache.cacheAttr = nil
|
||||
cache.attrExpiredAt = time.Time{}
|
||||
j.handlers[fh] = cache
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (j *juice) getAttrFromCache(fh uint64) (entry *meta.Entry) {
|
||||
if j.attrCacheTimeout == 0 || fh == invalidFileHandle {
|
||||
return nil
|
||||
}
|
||||
j.RLock()
|
||||
defer j.RUnlock()
|
||||
if cache, ok := j.handlers[fh]; ok && cache.cacheAttr != nil {
|
||||
if time.Now().Before(cache.attrExpiredAt) {
|
||||
entry = &meta.Entry{
|
||||
Inode: cache.ino,
|
||||
Attr: cache.cacheAttr,
|
||||
}
|
||||
return entry
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (j *juice) setAttrCache(fh uint64, attr *meta.Attr) {
|
||||
if j.attrCacheTimeout == 0 || fh == invalidFileHandle {
|
||||
return
|
||||
}
|
||||
|
||||
j.Lock()
|
||||
defer j.Unlock()
|
||||
|
||||
if cache, ok := j.handlers[fh]; ok {
|
||||
cache.cacheAttr = attr
|
||||
cache.attrExpiredAt = time.Now().Add(j.attrCacheTimeout)
|
||||
j.handlers[fh] = cache
|
||||
}
|
||||
}
|
||||
|
||||
func (j *juice) getAttr(ctx vfs.Context, fh uint64, ino Ino, opened uint8) (entry *meta.Entry, err syscall.Errno) {
|
||||
if entry := j.getAttrFromCache(fh); entry != nil {
|
||||
return entry, 0
|
||||
}
|
||||
|
||||
if entry, err = j.vfs.GetAttr(ctx, ino, opened); err != 0 {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
j.setAttrCache(fh, entry.Attr)
|
||||
|
||||
return entry, 0
|
||||
}
|
||||
|
||||
// Getattr gets file attributes.
|
||||
func (j *juice) Getattr(p string, stat *fuse.Stat_t, fh uint64) (e int) {
|
||||
ctx := j.newContext()
|
||||
defer trace(p, fh)(stat, &e)
|
||||
ino := j.h2i(&fh)
|
||||
|
||||
if ino == 0 {
|
||||
// special case for .control file
|
||||
if strings.HasSuffix(p, "/.control") {
|
||||
@@ -505,8 +606,15 @@ func (j *juice) Getattr(p string, stat *fuse.Stat_t, fh uint64) (e int) {
|
||||
return
|
||||
}
|
||||
ino = fi.Inode()
|
||||
entry := fi.Attr()
|
||||
if entry != nil {
|
||||
j.vfs.UpdateLength(ino, entry)
|
||||
attrToStat(ino, entry, stat)
|
||||
return
|
||||
}
|
||||
}
|
||||
entry, errrno := j.vfs.GetAttr(ctx, ino, 0)
|
||||
|
||||
entry, errrno := j.getAttr(ctx, fh, ino, 0)
|
||||
if errrno != 0 {
|
||||
e = errorconv(errrno)
|
||||
return
|
||||
@@ -526,6 +634,9 @@ func (j *juice) Truncate(path string, size int64, fh uint64) (e int) {
|
||||
return
|
||||
}
|
||||
e = errorconv(j.vfs.Truncate(ctx, ino, size, 0, nil))
|
||||
if e == 0 {
|
||||
j.invalidateAttrCache(ino)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -569,6 +680,7 @@ func (j *juice) Write(path string, buff []byte, off int64, fh uint64) (e int) {
|
||||
} else {
|
||||
e = len(buff)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -585,6 +697,19 @@ func (j *juice) Flush(path string, fh uint64) (e int) {
|
||||
return
|
||||
}
|
||||
|
||||
func (j *juice) cleanInoHandlerMap(ino meta.Ino, fh uint64) {
|
||||
handles := j.inoHandleMap[ino]
|
||||
for i, handle := range handles {
|
||||
if handle == fh {
|
||||
j.inoHandleMap[ino] = append(handles[:i], handles[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
if len(j.inoHandleMap[ino]) == 0 {
|
||||
delete(j.inoHandleMap, ino)
|
||||
}
|
||||
}
|
||||
|
||||
// Release closes an open file.
|
||||
func (j *juice) Release(path string, fh uint64) int {
|
||||
defer trace(path, fh)()
|
||||
@@ -598,8 +723,10 @@ func (j *juice) Release(path string, fh uint64) int {
|
||||
time.Sleep(time.Second * time.Duration(j.delayClose))
|
||||
j.Lock()
|
||||
delete(j.handlers, fh)
|
||||
j.cleanInoHandlerMap(ino, fh)
|
||||
if orig != fh {
|
||||
delete(j.badfd, orig)
|
||||
j.cleanInoHandlerMap(ino, orig)
|
||||
}
|
||||
j.Unlock()
|
||||
j.vfs.Release(j.newContext(), ino, fh)
|
||||
@@ -632,7 +759,11 @@ func (j *juice) Opendir(path string) (e int, fh uint64) {
|
||||
fh, errno := j.vfs.Opendir(ctx, f.Inode(), 0)
|
||||
if errno == 0 {
|
||||
j.Lock()
|
||||
j.handlers[fh] = f.Inode()
|
||||
j.handlers[fh] = handleInfo{
|
||||
ino: f.Inode(),
|
||||
}
|
||||
j.inoHandleMap[f.Inode()] = append(j.inoHandleMap[f.Inode()], fh)
|
||||
|
||||
j.Unlock()
|
||||
}
|
||||
e = errorconv(errno)
|
||||
@@ -696,6 +827,7 @@ func (j *juice) Releasedir(path string, fh uint64) (e int) {
|
||||
}
|
||||
j.Lock()
|
||||
delete(j.handlers, fh)
|
||||
j.cleanInoHandlerMap(ino, fh)
|
||||
j.Unlock()
|
||||
e = -int(j.vfs.Releasedir(j.newContext(), ino, fh))
|
||||
return
|
||||
@@ -729,6 +861,8 @@ func (j *juice) Chflags(path string, flags uint32) (e int) {
|
||||
err = j.vfs.ChFlags(ctx, ino, flagSet)
|
||||
if err != 0 {
|
||||
e = errorconv(err)
|
||||
} else {
|
||||
j.invalidateAttrCache(ino)
|
||||
}
|
||||
|
||||
return
|
||||
@@ -786,10 +920,10 @@ func (j *juice) Getpath(p string, fh uint64) (e int, ret string) {
|
||||
return
|
||||
}
|
||||
|
||||
func Serve(v *vfs.VFS, fuseOpt string, fileCacheTimeoutSec float64, dirCacheTimeoutSec float64,
|
||||
asRoot bool, delayCloseSec int, showDotFiles bool, threadsCount int, caseSensitive bool, enabledGetPath bool) {
|
||||
func Serve(v *vfs.VFS, fuseOpt string, asRoot bool, delayCloseSec int, showDotFiles bool, threadsCount int, caseSensitive bool, enabledGetPath bool) {
|
||||
var jfs juice
|
||||
conf := v.Conf
|
||||
jfs.attrCacheTimeout = v.Conf.AttrTimeout
|
||||
jfs.conf = conf
|
||||
jfs.vfs = v
|
||||
jfs.enabledGetPath = enabledGetPath
|
||||
@@ -805,8 +939,8 @@ func Serve(v *vfs.VFS, fuseOpt string, fileCacheTimeoutSec float64, dirCacheTime
|
||||
jfs.host = host
|
||||
var options = "volname=" + conf.Format.Name
|
||||
options += fmt.Sprintf(",ExactFileSystemName=JuiceFS,ThreadCount=%d", threadsCount)
|
||||
options += fmt.Sprintf(",DirInfoTimeout=%d,VolumeInfoTimeout=1000,KeepFileCache", int(dirCacheTimeoutSec*1000))
|
||||
options += fmt.Sprintf(",FileInfoTimeout=%d", int(fileCacheTimeoutSec*1000))
|
||||
options += fmt.Sprintf(",DirInfoTimeout=%d,VolumeInfoTimeout=1000,KeepFileCache", int(conf.DirEntryTimeout.Seconds()*1000))
|
||||
options += fmt.Sprintf(",FileInfoTimeout=%d", int(conf.EntryTimeout.Seconds()*1000))
|
||||
options += ",VolumePrefix=/juicefs/" + conf.Format.Name
|
||||
if asRoot {
|
||||
options += ",uid=-1,gid=-1"
|
||||
|
||||
Reference in New Issue
Block a user