Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support root squash #3575

Merged
merged 2 commits into from
May 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Usage: "map local root user (uid = 0) to another one in filesystem",
Usage: "map local root user (uid = 0) to another one specified as <uid>:<gid>",

},
&cli.StringFlag{
Name: "o",
Usage: "other FUSE options",
Expand Down Expand Up @@ -203,11 +210,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 @@ -61,6 +61,12 @@ type Config struct {
FastResolve bool `json:",omitempty"`
AccessLog string `json:",omitempty"`
HideInternal bool
RootSquash *RootSquash `json:",omitempty"`
}

type RootSquash struct {
Uid uint32
Gid uint32
}

var (
Expand Down