LinuxCIFS Multisession Mount

Revision as of 09:40, 30 March 2018 by Fraz (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Introduction

This page is a design document for adding multisession capability to the Linux CIFS client.

Current State

Currently each mount with the Linux CIFS client is a single-user affair. That is, each mount uses a single set of credentials. Any user does operations within that mount uses the same set of credentials.

The exception to this rule is the "MultiuserMount" switch. When that is enabled, the client will try to match the uid of the current process with an existing mount to the same server and then will use that session's credentials instead. The upshot here is that if you mount the same share multiple times with different uid= and different credentials then you can allow different users to use different credentials.

There are problems with this approach though:

  • it's extremely cumbersome to implement
  • when a matching session isn't found, it uses the "default" session for the mount anyway
  • multiple mounts means that caches aren't properly shared

...as well as other issues. We'd like to see this fixed

Overview of the Goal

Allow a single mountpoint to spawn SMB sessions on the fly. When a "new" user walks into a mount, CIFS will establish a new SMB session on the fly. It will get credentials out of the keyring and then spawn a new SMB session and perform a tree connect for that user. The operations will then be done using the correct smb session and tcon for that uid.

Eventually, the list of sessions will be pruned (probably by cifsd closing out unused sessions after a timeout).

Design Details

CIFS already has a hierarchy of structures to track server state:

  • TCP_Server_Info: contains info pertaining to the connection to the server. Holds info on the socket, for instance.
    • cifsSesInfo: authentication generally happens here (unless share-level auth is used). Identified on server by VUID.
      • cifsTconInfo: info on a particular connection to the server's tree. Identified on the server by the TID.
        • filehandles: open file descriptors. Identified on server by netfid.

Currently, things are not organized quite so cleanly. For instance, when multiuser mounts are used, the TID used is not necessarily one that was established using the same VUID. This is fine in CIFS, but apparently SMB2 ties the TID to the VUID used to establish it. Also filehandles are currently somewhat "free-floating", and aren't cleanly tied to a cifsTconInfo. This info is also too closely mashed together with the superblock currently.

To do multisession mounts properly, we'll need a much more rigid heirarchy. I propose something like this:

  • server struct: holds info on the socket and results of a NEGOTIATE_PROTOCOL op
    • session: tracked on a per-fsid basis and holds info pertaining to SESSION_SETUP
      • tcon: holds info pertaining to TREE_CONNECT operation
        • filehandles: info on an open filehandle. Generally a new one will be spawned on an open and destroyed on close.

Now, all of this has nothing so far to do with the filesystem on linux. These structs just track information about the state on the server. I believe a clean separation of the server state tracking and filesystem is an essential part of the design. This allows us to have a filesystem layer with a SMB state layer below it, and (probably) a transport layer below that.

For this to be useful, we need a way for new on the wire calls to pick out a tcon/ses combo to use. I propose using a radix tree with the fsuid of the user as the key and pointers to tcon structs as the value. We'll probably need to consider using bumping the refcount of the tcon to ensure that they don't vanish out from under us.