Skip to content

Commit

Permalink
support root squash (#3575)
Browse files Browse the repository at this point in the history
* support root squash

Signed-off-by: xixi <[email protected]>
  • Loading branch information
Hexilee authored May 10, 2023
1 parent 83258be commit 1770458
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 35 deletions.
43 changes: 42 additions & 1 deletion cmd/mount_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,12 @@ import (
"bytes"
"io"
"os"
"os/user"
"path"
"path/filepath"
"runtime"
"strconv"
"strings"
"syscall"
"time"

Expand Down Expand Up @@ -128,6 +131,10 @@ func mount_flags() []cli.Flag {
Value: path.Join(defaultLogDir, "juicefs.log"),
Usage: "path of log file when running in background",
},
&cli.StringFlag{
Name: "root-squash",
Usage: "map local root user (uid = 0) to another one in filesystem",
},
&cli.StringFlag{
Name: "o",
Usage: "other FUSE options",
Expand Down Expand Up @@ -207,11 +214,45 @@ func mount_main(v *vfs.VFS, c *cli.Context) {
if os.Getuid() == 0 {
disableUpdatedb()
}

conf := v.Conf
conf.AttrTimeout = time.Millisecond * time.Duration(c.Float64("attr-cache")*1000)
conf.EntryTimeout = time.Millisecond * time.Duration(c.Float64("entry-cache")*1000)
conf.DirEntryTimeout = time.Millisecond * time.Duration(c.Float64("dir-entry-cache")*1000)
rootSquash := c.String("root-squash")
if rootSquash != "" {
var uid, gid uint32 = 65534, 65534
if u, err := user.Lookup("nobody"); err == nil {
nobody, err := strconv.ParseUint(u.Uid, 10, 32)
if err != nil {
logger.Fatalf("invalid uid: %s", u.Uid)
}
uid = uint32(nobody)
}
if g, err := user.LookupGroup("nogroup"); err == nil {
nogroup, err := strconv.ParseUint(g.Gid, 10, 32)
if err != nil {
logger.Fatalf("invalid gid: %s", g.Gid)
}
gid = uint32(nogroup)
}

ss := strings.SplitN(strings.TrimSpace(rootSquash), ":", 2)
if ss[0] != "" {
u, err := strconv.ParseUint(ss[0], 10, 32)
if err != nil {
logger.Fatalf("invalid uid: %s", ss[0])
}
uid = uint32(u)
}
if len(ss) == 2 && ss[1] != "" {
g, err := strconv.ParseUint(ss[1], 10, 32)
if err != nil {
logger.Fatalf("invalid gid: %s", ss[1])
}
gid = uint32(g)
}
conf.RootSquash = &vfs.RootSquash{Uid: uid, Gid: gid}
}
logger.Infof("Mounting volume %s at %s ...", conf.Format.Name, conf.Meta.MountPoint)
err := fuse.Serve(v, c.String("o"), c.Bool("enable-xattr"), c.Bool("enable-ioctl"))
if err != nil {
Expand Down
6 changes: 5 additions & 1 deletion pkg/fuse/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,17 @@ var contextPool = sync.Pool{
},
}

func newContext(cancel <-chan struct{}, header *fuse.InHeader) *fuseContext {
func (fs *fileSystem) newContext(cancel <-chan struct{}, header *fuse.InHeader) *fuseContext {
ctx := contextPool.Get().(*fuseContext)
ctx.Context = context.Background()
ctx.start = time.Now()
ctx.canceled = false
ctx.cancel = cancel
ctx.header = header
if header.Uid == 0 && fs.conf.RootSquash != nil {
ctx.header.Uid = fs.conf.RootSquash.Uid
ctx.header.Gid = fs.conf.RootSquash.Gid
}
return ctx
}

Expand Down
66 changes: 33 additions & 33 deletions pkg/fuse/fuse.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ func (fs *fileSystem) replyEntry(ctx *fuseContext, out *fuse.EntryOut, e *meta.E
}

func (fs *fileSystem) Lookup(cancel <-chan struct{}, header *fuse.InHeader, name string, out *fuse.EntryOut) (status fuse.Status) {
ctx := newContext(cancel, header)
ctx := fs.newContext(cancel, header)
defer releaseContext(ctx)
entry, err := fs.v.Lookup(ctx, Ino(header.NodeId), name)
if err != 0 {
Expand All @@ -91,7 +91,7 @@ func (fs *fileSystem) Lookup(cancel <-chan struct{}, header *fuse.InHeader, name
}

func (fs *fileSystem) GetAttr(cancel <-chan struct{}, in *fuse.GetAttrIn, out *fuse.AttrOut) (code fuse.Status) {
ctx := newContext(cancel, &in.InHeader)
ctx := fs.newContext(cancel, &in.InHeader)
defer releaseContext(ctx)
var opened uint8
if in.Fh() != 0 {
Expand All @@ -106,7 +106,7 @@ func (fs *fileSystem) GetAttr(cancel <-chan struct{}, in *fuse.GetAttrIn, out *f
}

func (fs *fileSystem) SetAttr(cancel <-chan struct{}, in *fuse.SetAttrIn, out *fuse.AttrOut) (code fuse.Status) {
ctx := newContext(cancel, &in.InHeader)
ctx := fs.newContext(cancel, &in.InHeader)
defer releaseContext(ctx)
var opened uint8
if in.Fh != 0 {
Expand All @@ -121,7 +121,7 @@ func (fs *fileSystem) SetAttr(cancel <-chan struct{}, in *fuse.SetAttrIn, out *f
}

func (fs *fileSystem) Mknod(cancel <-chan struct{}, in *fuse.MknodIn, name string, out *fuse.EntryOut) (code fuse.Status) {
ctx := newContext(cancel, &in.InHeader)
ctx := fs.newContext(cancel, &in.InHeader)
defer releaseContext(ctx)
entry, err := fs.v.Mknod(ctx, Ino(in.NodeId), name, uint16(in.Mode), getUmask(in), in.Rdev)
if err != 0 {
Expand All @@ -131,7 +131,7 @@ func (fs *fileSystem) Mknod(cancel <-chan struct{}, in *fuse.MknodIn, name strin
}

func (fs *fileSystem) Mkdir(cancel <-chan struct{}, in *fuse.MkdirIn, name string, out *fuse.EntryOut) (code fuse.Status) {
ctx := newContext(cancel, &in.InHeader)
ctx := fs.newContext(cancel, &in.InHeader)
defer releaseContext(ctx)
entry, err := fs.v.Mkdir(ctx, Ino(in.NodeId), name, uint16(in.Mode), uint16(in.Umask))
if err != 0 {
Expand All @@ -141,28 +141,28 @@ func (fs *fileSystem) Mkdir(cancel <-chan struct{}, in *fuse.MkdirIn, name strin
}

func (fs *fileSystem) Unlink(cancel <-chan struct{}, header *fuse.InHeader, name string) (code fuse.Status) {
ctx := newContext(cancel, header)
ctx := fs.newContext(cancel, header)
defer releaseContext(ctx)
err := fs.v.Unlink(ctx, Ino(header.NodeId), name)
return fuse.Status(err)
}

func (fs *fileSystem) Rmdir(cancel <-chan struct{}, header *fuse.InHeader, name string) (code fuse.Status) {
ctx := newContext(cancel, header)
ctx := fs.newContext(cancel, header)
defer releaseContext(ctx)
err := fs.v.Rmdir(ctx, Ino(header.NodeId), name)
return fuse.Status(err)
}

func (fs *fileSystem) Rename(cancel <-chan struct{}, in *fuse.RenameIn, oldName string, newName string) (code fuse.Status) {
ctx := newContext(cancel, &in.InHeader)
ctx := fs.newContext(cancel, &in.InHeader)
defer releaseContext(ctx)
err := fs.v.Rename(ctx, Ino(in.NodeId), oldName, Ino(in.Newdir), newName, in.Flags)
return fuse.Status(err)
}

func (fs *fileSystem) Link(cancel <-chan struct{}, in *fuse.LinkIn, name string, out *fuse.EntryOut) (code fuse.Status) {
ctx := newContext(cancel, &in.InHeader)
ctx := fs.newContext(cancel, &in.InHeader)
defer releaseContext(ctx)
entry, err := fs.v.Link(ctx, Ino(in.Oldnodeid), Ino(in.NodeId), name)
if err != 0 {
Expand All @@ -172,7 +172,7 @@ func (fs *fileSystem) Link(cancel <-chan struct{}, in *fuse.LinkIn, name string,
}

func (fs *fileSystem) Symlink(cancel <-chan struct{}, header *fuse.InHeader, target string, name string, out *fuse.EntryOut) (code fuse.Status) {
ctx := newContext(cancel, header)
ctx := fs.newContext(cancel, header)
defer releaseContext(ctx)
entry, err := fs.v.Symlink(ctx, target, Ino(header.NodeId), name)
if err != 0 {
Expand All @@ -182,14 +182,14 @@ func (fs *fileSystem) Symlink(cancel <-chan struct{}, header *fuse.InHeader, tar
}

func (fs *fileSystem) Readlink(cancel <-chan struct{}, header *fuse.InHeader) (out []byte, code fuse.Status) {
ctx := newContext(cancel, header)
ctx := fs.newContext(cancel, header)
defer releaseContext(ctx)
path, err := fs.v.Readlink(ctx, Ino(header.NodeId))
return path, fuse.Status(err)
}

func (fs *fileSystem) GetXAttr(cancel <-chan struct{}, header *fuse.InHeader, attr string, dest []byte) (sz uint32, code fuse.Status) {
ctx := newContext(cancel, header)
ctx := fs.newContext(cancel, header)
defer releaseContext(ctx)
value, err := fs.v.GetXattr(ctx, Ino(header.NodeId), attr, uint32(len(dest)))
if err != 0 {
Expand All @@ -200,7 +200,7 @@ func (fs *fileSystem) GetXAttr(cancel <-chan struct{}, header *fuse.InHeader, at
}

func (fs *fileSystem) ListXAttr(cancel <-chan struct{}, header *fuse.InHeader, dest []byte) (uint32, fuse.Status) {
ctx := newContext(cancel, header)
ctx := fs.newContext(cancel, header)
defer releaseContext(ctx)
data, err := fs.v.ListXattr(ctx, Ino(header.NodeId), len(dest))
if err != 0 {
Expand All @@ -211,21 +211,21 @@ func (fs *fileSystem) ListXAttr(cancel <-chan struct{}, header *fuse.InHeader, d
}

func (fs *fileSystem) SetXAttr(cancel <-chan struct{}, in *fuse.SetXAttrIn, attr string, data []byte) fuse.Status {
ctx := newContext(cancel, &in.InHeader)
ctx := fs.newContext(cancel, &in.InHeader)
defer releaseContext(ctx)
err := fs.v.SetXattr(ctx, Ino(in.NodeId), attr, data, in.Flags)
return fuse.Status(err)
}

func (fs *fileSystem) RemoveXAttr(cancel <-chan struct{}, header *fuse.InHeader, attr string) (code fuse.Status) {
ctx := newContext(cancel, header)
ctx := fs.newContext(cancel, header)
defer releaseContext(ctx)
err := fs.v.RemoveXattr(ctx, Ino(header.NodeId), attr)
return fuse.Status(err)
}

func (fs *fileSystem) Create(cancel <-chan struct{}, in *fuse.CreateIn, name string, out *fuse.CreateOut) (code fuse.Status) {
ctx := newContext(cancel, &in.InHeader)
ctx := fs.newContext(cancel, &in.InHeader)
defer releaseContext(ctx)
entry, fh, err := fs.v.Create(ctx, Ino(in.NodeId), name, uint16(in.Mode), 0, in.Flags)
if err != 0 {
Expand All @@ -236,7 +236,7 @@ func (fs *fileSystem) Create(cancel <-chan struct{}, in *fuse.CreateIn, name str
}

func (fs *fileSystem) Open(cancel <-chan struct{}, in *fuse.OpenIn, out *fuse.OpenOut) (status fuse.Status) {
ctx := newContext(cancel, &in.InHeader)
ctx := fs.newContext(cancel, &in.InHeader)
defer releaseContext(ctx)
entry, fh, err := fs.v.Open(ctx, Ino(in.NodeId), in.Flags)
if err != 0 {
Expand All @@ -252,7 +252,7 @@ func (fs *fileSystem) Open(cancel <-chan struct{}, in *fuse.OpenIn, out *fuse.Op
}

func (fs *fileSystem) Read(cancel <-chan struct{}, in *fuse.ReadIn, buf []byte) (fuse.ReadResult, fuse.Status) {
ctx := newContext(cancel, &in.InHeader)
ctx := fs.newContext(cancel, &in.InHeader)
defer releaseContext(ctx)
n, err := fs.v.Read(ctx, Ino(in.NodeId), buf, in.Offset, in.Fh)
if err != 0 {
Expand All @@ -262,13 +262,13 @@ func (fs *fileSystem) Read(cancel <-chan struct{}, in *fuse.ReadIn, buf []byte)
}

func (fs *fileSystem) Release(cancel <-chan struct{}, in *fuse.ReleaseIn) {
ctx := newContext(cancel, &in.InHeader)
ctx := fs.newContext(cancel, &in.InHeader)
defer releaseContext(ctx)
fs.v.Release(ctx, Ino(in.NodeId), in.Fh)
}

func (fs *fileSystem) Write(cancel <-chan struct{}, in *fuse.WriteIn, data []byte) (written uint32, code fuse.Status) {
ctx := newContext(cancel, &in.InHeader)
ctx := fs.newContext(cancel, &in.InHeader)
defer releaseContext(ctx)
err := fs.v.Write(ctx, Ino(in.NodeId), data, in.Offset, in.Fh)
if err != 0 {
Expand All @@ -278,28 +278,28 @@ func (fs *fileSystem) Write(cancel <-chan struct{}, in *fuse.WriteIn, data []byt
}

func (fs *fileSystem) Flush(cancel <-chan struct{}, in *fuse.FlushIn) fuse.Status {
ctx := newContext(cancel, &in.InHeader)
ctx := fs.newContext(cancel, &in.InHeader)
defer releaseContext(ctx)
err := fs.v.Flush(ctx, Ino(in.NodeId), in.Fh, in.LockOwner)
return fuse.Status(err)
}

func (fs *fileSystem) Fsync(cancel <-chan struct{}, in *fuse.FsyncIn) (code fuse.Status) {
ctx := newContext(cancel, &in.InHeader)
ctx := fs.newContext(cancel, &in.InHeader)
defer releaseContext(ctx)
err := fs.v.Fsync(ctx, Ino(in.NodeId), int(in.FsyncFlags), in.Fh)
return fuse.Status(err)
}

func (fs *fileSystem) Fallocate(cancel <-chan struct{}, in *fuse.FallocateIn) (code fuse.Status) {
ctx := newContext(cancel, &in.InHeader)
ctx := fs.newContext(cancel, &in.InHeader)
defer releaseContext(ctx)
err := fs.v.Fallocate(ctx, Ino(in.NodeId), uint8(in.Mode), int64(in.Offset), int64(in.Length), in.Fh)
return fuse.Status(err)
}

func (fs *fileSystem) CopyFileRange(cancel <-chan struct{}, in *fuse.CopyFileRangeIn) (written uint32, code fuse.Status) {
ctx := newContext(cancel, &in.InHeader)
ctx := fs.newContext(cancel, &in.InHeader)
defer releaseContext(ctx)
copied, err := fs.v.CopyFileRange(ctx, Ino(in.NodeId), in.FhIn, in.OffIn, Ino(in.NodeIdOut), in.FhOut, in.OffOut, in.Len, uint32(in.Flags))
if err != 0 {
Expand All @@ -309,7 +309,7 @@ func (fs *fileSystem) CopyFileRange(cancel <-chan struct{}, in *fuse.CopyFileRan
}

func (fs *fileSystem) GetLk(cancel <-chan struct{}, in *fuse.LkIn, out *fuse.LkOut) (code fuse.Status) {
ctx := newContext(cancel, &in.InHeader)
ctx := fs.newContext(cancel, &in.InHeader)
defer releaseContext(ctx)
l := in.Lk
err := fs.v.Getlk(ctx, Ino(in.NodeId), in.Fh, in.Owner, &l.Start, &l.End, &l.Typ, &l.Pid)
Expand All @@ -331,30 +331,30 @@ func (fs *fileSystem) setLk(cancel <-chan struct{}, in *fuse.LkIn, block bool) (
if in.LkFlags&fuse.FUSE_LK_FLOCK != 0 {
return fs.Flock(cancel, in, block)
}
ctx := newContext(cancel, &in.InHeader)
ctx := fs.newContext(cancel, &in.InHeader)
defer releaseContext(ctx)
l := in.Lk
err := fs.v.Setlk(ctx, Ino(in.NodeId), in.Fh, in.Owner, l.Start, l.End, l.Typ, l.Pid, block)
return fuse.Status(err)
}

func (fs *fileSystem) Flock(cancel <-chan struct{}, in *fuse.LkIn, block bool) (code fuse.Status) {
ctx := newContext(cancel, &in.InHeader)
ctx := fs.newContext(cancel, &in.InHeader)
defer releaseContext(ctx)
err := fs.v.Flock(ctx, Ino(in.NodeId), in.Fh, in.Owner, in.Lk.Typ, block)
return fuse.Status(err)
}

func (fs *fileSystem) OpenDir(cancel <-chan struct{}, in *fuse.OpenIn, out *fuse.OpenOut) (status fuse.Status) {
ctx := newContext(cancel, &in.InHeader)
ctx := fs.newContext(cancel, &in.InHeader)
defer releaseContext(ctx)
fh, err := fs.v.Opendir(ctx, Ino(in.NodeId))
out.Fh = fh
return fuse.Status(err)
}

func (fs *fileSystem) ReadDir(cancel <-chan struct{}, in *fuse.ReadIn, out *fuse.DirEntryList) fuse.Status {
ctx := newContext(cancel, &in.InHeader)
ctx := fs.newContext(cancel, &in.InHeader)
defer releaseContext(ctx)
entries, _, err := fs.v.Readdir(ctx, Ino(in.NodeId), in.Size, int(in.Offset), in.Fh, false)
var de fuse.DirEntry
Expand All @@ -370,7 +370,7 @@ func (fs *fileSystem) ReadDir(cancel <-chan struct{}, in *fuse.ReadIn, out *fuse
}

func (fs *fileSystem) ReadDirPlus(cancel <-chan struct{}, in *fuse.ReadIn, out *fuse.DirEntryList) fuse.Status {
ctx := newContext(cancel, &in.InHeader)
ctx := fs.newContext(cancel, &in.InHeader)
defer releaseContext(ctx)
entries, readAt, err := fs.v.Readdir(ctx, Ino(in.NodeId), in.Size, int(in.Offset), in.Fh, true)
ctx.start = readAt
Expand All @@ -396,13 +396,13 @@ func (fs *fileSystem) ReadDirPlus(cancel <-chan struct{}, in *fuse.ReadIn, out *
var cancelReleaseDir = make(chan struct{})

func (fs *fileSystem) ReleaseDir(in *fuse.ReleaseIn) {
ctx := newContext(cancelReleaseDir, &in.InHeader)
ctx := fs.newContext(cancelReleaseDir, &in.InHeader)
defer releaseContext(ctx)
fs.v.Releasedir(ctx, Ino(in.NodeId), in.Fh)
}

func (fs *fileSystem) StatFs(cancel <-chan struct{}, in *fuse.InHeader, out *fuse.StatfsOut) (code fuse.Status) {
ctx := newContext(cancel, in)
ctx := fs.newContext(cancel, in)
defer releaseContext(ctx)
st, err := fs.v.StatFS(ctx, Ino(in.NodeId))
if err != 0 {
Expand All @@ -423,7 +423,7 @@ func (fs *fileSystem) StatFs(cancel <-chan struct{}, in *fuse.InHeader, out *fus
}

func (fs *fileSystem) Ioctl(cancel <-chan struct{}, in *fuse.IoctlIn, out *fuse.IoctlOut, bufIn, bufOut []byte) (status fuse.Status) {
ctx := newContext(cancel, &in.InHeader)
ctx := fs.newContext(cancel, &in.InHeader)
defer releaseContext(ctx)
out.Result = int32(fs.v.Ioctl(ctx, Ino(in.NodeId), in.Cmd, in.Arg, bufIn, bufOut))
return 0
Expand Down
6 changes: 6 additions & 0 deletions pkg/vfs/vfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ type Config struct {
AccessLog string `json:",omitempty"`
PrefixInternal bool
HideInternal bool
RootSquash *RootSquash `json:",omitempty"`
}

type RootSquash struct {
Uid uint32
Gid uint32
}

var (
Expand Down

0 comments on commit 1770458

Please sign in to comment.