diff options
author | Zyad A. Ali <zyad.ali.me@gmail.com> | 2021-05-31 21:07:47 +0200 |
---|---|---|
committer | Zyad A. Ali <zyad.ali.me@gmail.com> | 2021-07-13 22:12:02 +0200 |
commit | 7eae6402c111323cd6e92e0499dfa12cf2554d1a (patch) | |
tree | 8fc3aa361048a4f681764e929f8506c9fd10a68a /pkg/sentry/kernel/msgqueue/msgqueue.go | |
parent | 7c488fcfe8a5fd17f99f1c88c29ce97f5851f786 (diff) |
Implement Registry.FindOrCreate.
FindOrCreate implements the behaviour of msgget(2).
Updates #135
Diffstat (limited to 'pkg/sentry/kernel/msgqueue/msgqueue.go')
-rw-r--r-- | pkg/sentry/kernel/msgqueue/msgqueue.go | 93 |
1 files changed, 87 insertions, 6 deletions
diff --git a/pkg/sentry/kernel/msgqueue/msgqueue.go b/pkg/sentry/kernel/msgqueue/msgqueue.go index 51db8b12c..0e2d996a8 100644 --- a/pkg/sentry/kernel/msgqueue/msgqueue.go +++ b/pkg/sentry/kernel/msgqueue/msgqueue.go @@ -16,14 +16,28 @@ package msgqueue import ( - "sync" - + "gvisor.dev/gvisor/pkg/abi/linux" + "gvisor.dev/gvisor/pkg/context" + "gvisor.dev/gvisor/pkg/errors/linuxerr" + "gvisor.dev/gvisor/pkg/sentry/fs" "gvisor.dev/gvisor/pkg/sentry/kernel/auth" "gvisor.dev/gvisor/pkg/sentry/kernel/ipc" ktime "gvisor.dev/gvisor/pkg/sentry/kernel/time" + "gvisor.dev/gvisor/pkg/sync" "gvisor.dev/gvisor/pkg/waiter" ) +const ( + // System-wide limit for maximum number of queues. + maxQueues = linux.MSGMNI + + // Maximum size of a queue in bytes. + maxQueueBytes = linux.MSGMNB + + // Maximum size of a message in bytes. + maxMessageBytes = linux.MSGMAX +) + // Registry contains a set of message queues that can be referenced using keys // or IDs. // @@ -36,6 +50,13 @@ type Registry struct { reg *ipc.Registry } +// NewRegistry returns a new Registry ready to be used. +func NewRegistry(userNS *auth.UserNamespace) *Registry { + return &Registry{ + reg: ipc.NewRegistry(userNS), + } +} + // Queue represents a SysV message queue, described by sysvipc(7). // // +stateify savable @@ -103,9 +124,69 @@ type Message struct { mSize uint64 } -// NewRegistry returns a new Registry ready to be used. -func NewRegistry(userNS *auth.UserNamespace) *Registry { - return &Registry{ - reg: ipc.NewRegistry(userNS), +// FindOrCreate creates a new message queue or returns an existing one. See +// msgget(2). +func (r *Registry) FindOrCreate(ctx context.Context, key ipc.Key, mode linux.FileMode, private, create, exclusive bool) (*Queue, error) { + r.mu.Lock() + defer r.mu.Unlock() + + if !private { + queue, err := r.reg.Find(ctx, key, mode, create, exclusive) + if err != nil { + return nil, err + } + + if queue != nil { + return queue.(*Queue), nil + } + } + + // Check system-wide limits. + if r.reg.ObjectCount() >= maxQueues { + return nil, linuxerr.ENOSPC } + + return r.newQueueLocked(ctx, key, fs.FileOwnerFromContext(ctx), fs.FilePermsFromMode(mode)) +} + +// newQueueLocked creates a new queue using the given fields. An error is +// returned if there're no more available identifiers. +// +// Precondition: r.mu must be held. +func (r *Registry) newQueueLocked(ctx context.Context, key ipc.Key, creator fs.FileOwner, perms fs.FilePermissions) (*Queue, error) { + q := &Queue{ + registry: r, + obj: ipc.NewObject(r.reg.UserNS, key, creator, creator, perms), + sendTime: ktime.ZeroTime, + receiveTime: ktime.ZeroTime, + changeTime: ktime.NowFromContext(ctx), + maxBytes: maxQueueBytes, + } + + err := r.reg.Register(q) + if err != nil { + return nil, err + } + return q, nil +} + +// Lock implements ipc.Mechanism.Lock. +func (q *Queue) Lock() { + q.mu.Lock() +} + +// Unlock implements ipc.mechanism.Unlock. +// +// +checklocksignore +func (q *Queue) Unlock() { + q.mu.Unlock() +} + +// Object implements ipc.Mechanism.Object. +func (q *Queue) Object() *ipc.Object { + return q.obj +} + +// Destroy implements ipc.Mechanism.Destroy. It's yet to be implemented. +func (q *Queue) Destroy() { } |