diff options
author | Gordon Ross <Gordon.Ross@Sun.COM> | 2009-12-16 15:03:38 -0500 |
---|---|---|
committer | Gordon Ross <Gordon.Ross@Sun.COM> | 2009-12-16 15:03:38 -0500 |
commit | 02d09e03eb27f3a2dc299de704e45dae5173f43f (patch) | |
tree | d01a29c58a8a455627b355abb83addad11802bd6 | |
parent | aab2fe4104e428e5213f84aee65b9905ec97cf9a (diff) | |
download | illumos-gate-02d09e03eb27f3a2dc299de704e45dae5173f43f.tar.gz |
6650611 Attribute cache logic needs improvement
6876185 common I/F for net message build/parse in kernel vs user code
6891728 syslog shows: smbfs_close: error 9 closing /dirname
6906037 smbfs_mount() doesn't ASSERT the return value of smbfs_make_node()
6607536 the size of a dir on smbfs is not correct
6648146 smbfs should implement reclaim from node cache
--HG--
rename : usr/src/lib/libsmbfs/smb/acl_conv.c => usr/src/common/smbclnt/smbfs_ntacl.c
rename : usr/src/lib/libsmbfs/smb/acl_nt.h => usr/src/common/smbclnt/smbfs_ntacl.h
67 files changed, 3990 insertions, 3826 deletions
diff --git a/usr/src/cmd/fs.d/smbclnt/lsacl/lsacl.c b/usr/src/cmd/fs.d/smbclnt/lsacl/lsacl.c index 1285251898..afce3a64fd 100644 --- a/usr/src/cmd/fs.d/smbclnt/lsacl/lsacl.c +++ b/usr/src/cmd/fs.d/smbclnt/lsacl/lsacl.c @@ -61,7 +61,7 @@ main(int argc, char **argv) uid_t uid; gid_t gid; int error, fd; - i_ntsd_t *sd; + struct i_ntsd *sd; progname = argv[0]; diff --git a/usr/src/cmd/fs.d/smbclnt/mount/mntopts.h b/usr/src/cmd/fs.d/smbclnt/mount/mntopts.h deleted file mode 100644 index 6b908f3c7f..0000000000 --- a/usr/src/cmd/fs.d/smbclnt/mount/mntopts.h +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (c) 1994 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * @(#)mntopts.h 8.7 (Berkeley) 3/29/95 - * $Id: mntopts.h,v 1.4 2004/03/19 01:49:47 lindak Exp $ - */ - -/* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -#ifndef _CIFS_MNTOPTS_H -#define _CIFS_MNTOPTS_H - -#pragma ident "%Z%%M% %I% %E% SMI" - -#ifdef __cplusplus -extern "C" { -#endif - -#include <sys/vfs.h> -#ifdef UNPORTED -/* In solaris this is defined in proto/root_i386/usr/include/sys/vfs.h */ -struct mntopt { - const char *m_option; /* option name */ - int m_inverse; /* if a negative option, e.g. "dev" */ - int m_flag; /* bit to set, e.g. MNT_RDONLY */ - int m_altloc; /* 1 => set bit in altflags */ -}; -#endif /* UNPORTED */ - -/* User-visible MNT_ flags. */ -#define MOPT_ASYNC { "async", 0, MNT_ASYNC, 0 } -#define MOPT_NODEV { "dev", 1, MNT_NODEV, 0 } -#define MOPT_NOEXEC { "exec", 1, MNT_NOEXEC, 0 } -#define MOPT_NOSUID { "suid", 1, MNT_NOSUID, 0 } -#define MOPT_RDONLY { "rdonly", 0, MNT_RDONLY, 0 } -#define MOPT_SYNC { "sync", 0, MNT_SYNCHRONOUS, 0 } -#define MOPT_UNION { "union", 0, MNT_UNION, 0 } -#define MOPT_USERQUOTA { "userquota", 0, 0, 0 } -#define MOPT_GROUPQUOTA { "groupquota", 0, 0, 0 } -#define MOPT_BROWSE { "browse", 1, MNT_DONTBROWSE, 0 } -#define MOPT_AUTOMOUNTED { "automounted", 0, MNT_AUTOMOUNTED, 0 } - -/* Control flags. */ -#define MOPT_FORCE { "force", 0, MNT_FORCE, 0 } -#define MOPT_UPDATE { "update", 0, MNT_UPDATE, 0 } -#define MOPT_RO { "ro", 0, MNT_RDONLY, 0 } -#define MOPT_RW { "rw", 1, MNT_RDONLY, 0 } - -/* This is parsed by mount(1m), but is ignored by specific mount_*(1m)s. */ -#define MOPT_AUTO { "auto", 0, 0, 0 } - -#define MOPT_FSTAB_COMPAT \ - MOPT_RO, \ - MOPT_RW, \ - MOPT_AUTO - -/* Standard options which all mounts can understand. */ -#define MOPT_STDOPTS \ - MOPT_USERQUOTA, \ - MOPT_GROUPQUOTA, \ - MOPT_FSTAB_COMPAT, \ - MOPT_NODEV, \ - MOPT_NOEXEC, \ - MOPT_NOSUID, \ - MOPT_RDONLY, \ - MOPT_UNION, \ - MOPT_BROWSE, \ - MOPT_AUTOMOUNTED - -void getmntopts(const char *, const mntopt_t *, int *, int *); - -extern int getmnt_silent; - -#ifdef __cplusplus -} -#endif - -#endif /* _CIFS_MNTOPTS_H */ diff --git a/usr/src/cmd/fs.d/smbclnt/mount/mount.c b/usr/src/cmd/fs.d/smbclnt/mount/mount.c index 9068d093b6..5b2cac4ee7 100644 --- a/usr/src/cmd/fs.d/smbclnt/mount/mount.c +++ b/usr/src/cmd/fs.d/smbclnt/mount/mount.c @@ -47,7 +47,6 @@ #include <stdlib.h> #include <errno.h> #include <err.h> -#include <sysexits.h> #include <libintl.h> #include <locale.h> #include <libscf.h> @@ -59,93 +58,110 @@ #include <sys/mntent.h> #include <sys/mnttab.h> -/* This needs to know ctx->ct_dev_fd, etc. */ -#include <netsmb/smb_lib.h> - #include <sys/fs/smbfs_mount.h> -#include "mntopts.h" +/* This needs to know ctx->ct_dev_fd, etc. */ +#include <netsmb/smb_lib.h> extern char *optarg; extern int optind; static char mount_point[MAXPATHLEN + 1]; static void usage(void); -static int setsubopt(smb_ctx_t *, struct smbfs_args *, int, char *); - -/* smbfs options */ -#define MNTOPT_DOMAIN "domain" -#define MNTOPT_USER "user" -#define MNTOPT_DIRPERMS "dirperms" -#define MNTOPT_FILEPERMS "fileperms" -#define MNTOPT_GID "gid" -#define MNTOPT_UID "uid" -#define MNTOPT_NOPROMPT "noprompt" - -#define OPT_DOMAIN 1 -#define OPT_USER 2 -#define OPT_DIRPERMS 3 -#define OPT_FILEPERMS 4 -#define OPT_GID 5 -#define OPT_UID 6 -#define OPT_NOPROMPT 7 - -/* generic VFS options */ -#define OPT_RO 10 -#define OPT_RW 11 -#define OPT_SUID 12 -#define OPT_NOSUID 13 -#define OPT_DEVICES 14 -#define OPT_NODEVICES 15 -#define OPT_SETUID 16 -#define OPT_NOSETUID 17 -#define OPT_EXEC 18 -#define OPT_NOEXEC 19 - -struct smbfsopts { - char *name; - int index; -}; - -struct smbfsopts opts[] = { - {MNTOPT_DOMAIN, OPT_DOMAIN}, - {MNTOPT_USER, OPT_USER}, - {MNTOPT_DIRPERMS, OPT_DIRPERMS}, - {MNTOPT_FILEPERMS, OPT_FILEPERMS}, - {MNTOPT_GID, OPT_GID}, - {MNTOPT_UID, OPT_UID}, - {MNTOPT_NOPROMPT, OPT_NOPROMPT}, - {MNTOPT_RO, OPT_RO}, - {MNTOPT_RW, OPT_RW}, - {MNTOPT_SUID, OPT_SUID}, - {MNTOPT_NOSUID, OPT_NOSUID}, - {MNTOPT_DEVICES, OPT_DEVICES}, - {MNTOPT_NODEVICES, OPT_NODEVICES}, - {MNTOPT_SETUID, OPT_SETUID}, - {MNTOPT_NOSETUID, OPT_NOSETUID}, - {MNTOPT_EXEC, OPT_EXEC}, - {MNTOPT_NOEXEC, OPT_NOEXEC}, - {NULL, 0} +static int setsubopt(smb_ctx_t *, struct smbfs_args *, char *); + +const char * const optlist[] = { + + /* Generic VFS options. */ +#define OPT_RO 0 + MNTOPT_RO, +#define OPT_RW 1 + MNTOPT_RW, +#define OPT_SUID 2 + MNTOPT_SUID, +#define OPT_NOSUID 3 + MNTOPT_NOSUID, +#define OPT_DEVICES 4 + MNTOPT_DEVICES, +#define OPT_NODEVICES 5 + MNTOPT_NODEVICES, +#define OPT_SETUID 6 + MNTOPT_SETUID, +#define OPT_NOSETUID 7 + MNTOPT_NOSETUID, +#define OPT_EXEC 8 + MNTOPT_EXEC, +#define OPT_NOEXEC 9 + MNTOPT_NOEXEC, +#define OPT_XATTR 10 + MNTOPT_XATTR, +#define OPT_NOXATTR 11 + MNTOPT_NOXATTR, + + /* Sort of generic (from NFS) */ +#define OPT_NOAC 12 + MNTOPT_NOAC, +#define OPT_ACTIMEO 13 + MNTOPT_ACTIMEO, +#define OPT_ACREGMIN 14 + MNTOPT_ACREGMIN, +#define OPT_ACREGMAX 15 + MNTOPT_ACREGMAX, +#define OPT_ACDIRMIN 16 + MNTOPT_ACDIRMIN, +#define OPT_ACDIRMAX 17 + MNTOPT_ACDIRMAX, + + /* smbfs-specifis options */ +#define OPT_DOMAIN 18 + "domain", +#define OPT_USER 19 + "user", +#define OPT_UID 20 + "uid", +#define OPT_GID 21 + "gid", +#define OPT_DIRPERMS 22 + "dirperms", +#define OPT_FILEPERMS 23 + "fileperms", +#define OPT_NOPROMPT 24 + "noprompt", + + NULL }; static int Oflg = 0; /* Overlay mounts */ static int qflg = 0; /* quiet - don't print warnings on bad options */ -static int ro = 0; /* read-only mount */ static int noprompt = 0; /* don't prompt for password */ -#define RET_ERR 33 +/* Note: smbfs uses _both_ kinds of options. */ +static int mntflags = MS_DATA | MS_OPTIONSTR; + +#define EX_OK 0 /* normal */ +#define EX_OPT 1 /* bad options, usage, etc */ +#define EX_MNT 2 /* mount point problems, etc */ +#define RET_ERR 3 /* later errors */ + #define SERVICE "svc:/network/smb/client:default" struct smbfs_args mdata; struct mnttab mnt; -char optbuf[MAX_MNTOPT_STR]; + +/* + * Initialize this with "rw" just to have something there, + * so we don't have to decide whether to add a comma when + * we strcat another option. Note the "rw" may be changed + * to an "ro" by option processing. + */ +char optbuf[MAX_MNTOPT_STR] = "rw"; int main(int argc, char *argv[]) { struct smb_ctx *ctx = NULL; struct stat st; - int opt, error, err2, mntflags; + int opt, error, err2; static char *fstype = MNTTYPE_SMBFS; char *env, *state; @@ -188,13 +204,11 @@ main(int argc, char *argv[]) exit(RET_ERR); mnt.mnt_mntopts = optbuf; - mntflags = MS_DATA; bzero(&mdata, sizeof (mdata)); mdata.version = SMBFS_VERSION; /* smbfs mount version */ mdata.uid = (uid_t)-1; mdata.gid = (gid_t)-1; - mdata.caseopt = SMB_CS_NONE; error = smb_ctx_alloc(&ctx); if (error) @@ -209,11 +223,11 @@ main(int argc, char *argv[]) error = smb_ctx_parseunc(ctx, argv[argc - 2], SMBL_SHARE, SMBL_SHARE, USE_DISKDEV, NULL); if (error) - exit(RET_ERR); + exit(EX_OPT); error = smb_ctx_readrc(ctx); if (error) - exit(RET_ERR); + exit(EX_OPT); while ((opt = getopt(argc, argv, "ro:Oq")) != -1) { switch (opt) { @@ -226,19 +240,13 @@ main(int argc, char *argv[]) break; case 'r': - ro++; + mntflags |= MS_RDONLY; break; case 'o': { - char *nextopt, *comma, *equals, *sopt, *soptval; - int i, ret; - - if (strlen(optarg) >= MAX_MNTOPT_STR) { - if (!qflg) - warnx(gettext( - "option string too long")); - exit(RET_ERR); - } + char *nextopt, *comma, *sopt; + int ret; + for (sopt = optarg; sopt != NULL; sopt = nextopt) { comma = strchr(sopt, ','); if (comma) { @@ -246,33 +254,10 @@ main(int argc, char *argv[]) *comma = '\0'; } else nextopt = NULL; - equals = strchr(sopt, '='); - if (equals) { - soptval = equals + 1; - *equals = '\0'; - } else - soptval = NULL; - for (i = 0; opts[i].name != NULL; i++) { - if (strcmp(sopt, opts[i].name) == 0) - break; - } - if (opts[i].name == NULL) { - if (equals) - *equals = '='; - if (!qflg) - errx(RET_ERR, gettext( - "Bad option '%s'"), sopt); - if (comma) - *comma = ','; - continue; - } - ret = setsubopt(ctx, &mdata, - opts[i].index, soptval); + ret = setsubopt(ctx, &mdata, sopt); if (ret != 0) - exit(RET_ERR); - if (equals) - *equals = '='; - (void) strcat(mnt.mnt_mntopts, sopt); + exit(EX_OPT); + /* undo changes to optarg */ if (comma) *comma = ','; } @@ -288,12 +273,10 @@ main(int argc, char *argv[]) if (Oflg) mntflags |= MS_OVERLAY; - if (ro) { + if (mntflags & MS_RDONLY) { char *p; - - mntflags |= MS_RDONLY; /* convert "rw"->"ro" */ - if (p = strstr(mnt.mnt_mntopts, "rw")) { + if (p = strstr(optbuf, "rw")) { if (*(p+2) == ',' || *(p+2) == '\0') *(p+1) = 'o'; } @@ -307,11 +290,11 @@ main(int argc, char *argv[]) realpath(argv[optind+1], mount_point); if (stat(mount_point, &st) == -1) - err(EX_OSERR, gettext("could not find mount point %s"), + err(EX_MNT, gettext("could not find mount point %s"), mount_point); if (!S_ISDIR(st.st_mode)) { errno = ENOTDIR; - err(EX_OSERR, gettext("can't mount on %s"), mount_point); + err(EX_MNT, gettext("can't mount on %s"), mount_point); } /* @@ -379,40 +362,57 @@ again: mntflags, fstype, &mdata, sizeof (mdata), mnt.mnt_mntopts, MAX_MNTOPT_STR) < 0) { if (errno != ENOENT) { - err(EX_OSERR, gettext("mount_smbfs: %s"), + err(EX_MNT, gettext("mount_smbfs: %s"), mnt.mnt_mountp); } else { struct stat sb; if (stat(mnt.mnt_mountp, &sb) < 0 && errno == ENOENT) - err(EX_OSERR, gettext("mount_smbfs: %s"), + err(EX_MNT, gettext("mount_smbfs: %s"), mnt.mnt_mountp); else - err(EX_OSERR, gettext("mount_smbfs: %s"), + err(EX_MNT, gettext("mount_smbfs: %s"), mnt.mnt_special); } } smb_ctx_free(ctx); - if (error) { - smb_error(gettext("mount error: %s"), error, mount_point); - exit(RET_ERR); - } return (0); } +#define bad(val) (val == NULL || !isdigit(*val)) + int -setsubopt(smb_ctx_t *ctx, struct smbfs_args *mdatap, int index, char *optarg) +setsubopt(smb_ctx_t *ctx, struct smbfs_args *mdatap, char *subopt) { + char *equals, *optarg; struct passwd *pwd; struct group *grp; - long l; - int err = 0; - char *next; + long val; + int rc = EX_OK; + int index; + char *p; + + equals = strchr(subopt, '='); + if (equals) { + *equals = '\0'; + optarg = equals + 1; + } else + optarg = NULL; + + for (index = 0; optlist[index] != NULL; index++) { + if (strcmp(subopt, optlist[index]) == 0) + break; + } + + /* + * Note: if the option was unknown, index will + * point to the NULL at the end of optlist[], + * and we'll take the switch default. + */ switch (index) { - case OPT_RO: - case OPT_RW: + case OPT_SUID: case OPT_NOSUID: case OPT_DEVICES: @@ -421,15 +421,106 @@ setsubopt(smb_ctx_t *ctx, struct smbfs_args *mdatap, int index, char *optarg) case OPT_NOSETUID: case OPT_EXEC: case OPT_NOEXEC: - /* We don't have to handle generic options here */ - return (0); + case OPT_XATTR: + case OPT_NOXATTR: + /* + * These options are handled via the + * generic option string mechanism. + * None of these take an optarg. + */ + if (optarg != NULL) + goto badval; + (void) strlcat(optbuf, ",", sizeof (optbuf)); + if (strlcat(optbuf, subopt, sizeof (optbuf)) >= + sizeof (optbuf)) { + if (!qflg) + warnx(gettext("option string too long")); + rc = EX_OPT; + } + break; + + /* + * OPT_RO, OPT_RW, are actually generic too, + * but we use the mntflags for these, and + * then update the options string later. + */ + case OPT_RO: + mntflags |= MS_RDONLY; + break; + case OPT_RW: + mntflags &= ~MS_RDONLY; + break; + + /* + * NFS-derived options for attribute cache + * handling (disable, set min/max timeouts) + */ + case OPT_NOAC: + mdatap->flags |= SMBFS_MF_NOAC; + break; + + case OPT_ACTIMEO: + errno = 0; + val = strtol(optarg, &p, 10); + if (errno || *p != 0) + goto badval; + mdatap->acdirmin = mdatap->acregmin = val; + mdatap->acdirmax = mdatap->acregmax = val; + mdatap->flags |= SMBFS_MF_ACDIRMAX; + mdatap->flags |= SMBFS_MF_ACREGMAX; + mdatap->flags |= SMBFS_MF_ACDIRMIN; + mdatap->flags |= SMBFS_MF_ACREGMIN; + break; + + case OPT_ACREGMIN: + errno = 0; + val = strtol(optarg, &p, 10); + if (errno || *p != 0) + goto badval; + mdatap->acregmin = val; + mdatap->flags |= SMBFS_MF_ACREGMIN; + break; + + case OPT_ACREGMAX: + errno = 0; + val = strtol(optarg, &p, 10); + if (errno || *p != 0) + goto badval; + mdatap->acregmax = val; + mdatap->flags |= SMBFS_MF_ACREGMAX; + break; + + case OPT_ACDIRMIN: + errno = 0; + val = strtol(optarg, &p, 10); + if (errno || *p != 0) + goto badval; + mdatap->acdirmin = val; + mdatap->flags |= SMBFS_MF_ACDIRMIN; + break; + + case OPT_ACDIRMAX: + errno = 0; + val = strtol(optarg, &p, 10); + if (errno || *p != 0) + goto badval; + mdatap->acdirmax = val; + mdatap->flags |= SMBFS_MF_ACDIRMAX; + break; + /* + * SMBFS-specific options. Some of these + * don't go through the mount system call, + * but just set libsmbfs options. + */ case OPT_DOMAIN: - err = smb_ctx_setdomain(ctx, optarg, B_TRUE); + if (smb_ctx_setdomain(ctx, optarg, B_TRUE) != 0) + rc = EX_OPT; break; case OPT_USER: - err = smb_ctx_setuser(ctx, optarg, B_TRUE); + if (smb_ctx_setuser(ctx, optarg, B_TRUE) != 0) + rc = EX_OPT; break; case OPT_UID: @@ -438,49 +529,62 @@ setsubopt(smb_ctx_t *ctx, struct smbfs_args *mdatap, int index, char *optarg) if (pwd == NULL) { if (!qflg) warnx(gettext("unknown user '%s'"), optarg); - err = -1; + rc = EX_OPT; } else { mdatap->uid = pwd->pw_uid; } break; + case OPT_GID: grp = isdigit(optarg[0]) ? getgrgid(atoi(optarg)) : getgrnam(optarg); if (grp == NULL) { if (!qflg) warnx(gettext("unknown group '%s'"), optarg); - err = -1; + rc = EX_OPT; } else { mdatap->gid = grp->gr_gid; } break; + case OPT_DIRPERMS: errno = 0; - l = strtol(optarg, &next, 8); - if (errno || *next != 0) { - if (!qflg) - warnx(gettext( - "invalid value for directory mode")); - err = -1; - } else { - mdatap->dir_mode = l; - } + val = strtol(optarg, &p, 8); + if (errno || *p != 0) + goto badval; + mdatap->dir_mode = val; break; + case OPT_FILEPERMS: errno = 0; - l = strtol(optarg, &next, 8); - if (errno || *next != 0) { - if (!qflg) - warnx(gettext("invalid value for file mode")); - err = -1; - } else { - mdatap->file_mode = l; - } + val = strtol(optarg, &p, 8); + if (errno || *p != 0) + goto badval; + mdatap->file_mode = val; break; + case OPT_NOPROMPT: noprompt++; + break; + + default: + if (!qflg) + warnx(gettext("unknown option %s"), subopt); + rc = EX_OPT; + break; + + badval: + if (!qflg) + warnx(gettext("invalid value for %s"), subopt); + rc = EX_OPT; + break; } - return (err); + + /* Undo changes made to subopt */ + if (equals) + *equals = '='; + + return (rc); } static void @@ -490,5 +594,5 @@ usage(void) gettext("usage: mount -F smbfs [-Orq] [-o option[,option]]" " //[workgroup;][user[:password]@]server[/share] path")); - exit(EX_USAGE); + exit(EX_OPT); } diff --git a/usr/src/cmd/mdb/common/modules/smbfs/smbfs.c b/usr/src/cmd/mdb/common/modules/smbfs/smbfs.c index 11aeb9f081..4841a41cd8 100644 --- a/usr/src/cmd/mdb/common/modules/smbfs/smbfs.c +++ b/usr/src/cmd/mdb/common/modules/smbfs/smbfs.c @@ -20,13 +20,10 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ - -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/mdb_modapi.h> #include <sys/types.h> #include <sys/refstr_impl.h> @@ -176,138 +173,29 @@ smbfs_vfs_help(void) } /* - * Walker for the smbnode hash table. - */ - -typedef struct smbnode_walk_data { - rhashq_t *smbtab; /* (our copy of) the smbtable */ - int tabsize; /* size of table */ - int nextidx; /* next bucket index */ - uintptr_t buckptr; /* target addr of current bucket */ - uintptr_t nodeptr; /* target addr of current smbnode */ - smbnode_t node; /* scratch space for _step */ -} smbnode_walk_data_t; - -int -smbnode_walk_init(mdb_walk_state_t *wsp) -{ - size_t tabsz_bytes; - int tabsize; - uintptr_t smbtab; - smbnode_walk_data_t *smbw; - - if (wsp->walk_addr != NULL) { - mdb_warn("smbnode only supports global walks\n"); - return (WALK_ERR); - } - - if (mdb_readvar(&tabsize, "smbtablesize") == -1) { - mdb_warn("failed to read `smbtablesize'\n"); - return (WALK_ERR); - } - - if (tabsize == 0) { - return (WALK_DONE); - } - - if (mdb_readvar(&smbtab, "smbtable") == -1) { - mdb_warn("failed to read `smbtable'\n"); - return (WALK_ERR); - } - - smbw = mdb_alloc(sizeof (*smbw), UM_SLEEP | UM_GC); - - tabsz_bytes = tabsize * sizeof (rhashq_t); - smbw->smbtab = mdb_alloc(tabsz_bytes, UM_SLEEP | UM_GC); - if (mdb_vread(smbw->smbtab, tabsz_bytes, smbtab) != tabsz_bytes) { - mdb_warn("failed to read in smbtable from %p", smbtab); - return (WALK_ERR); - } - smbw->tabsize = tabsize; - smbw->nextidx = 1; - smbw->buckptr = smbtab; - smbw->nodeptr = (uintptr_t)smbw->smbtab[0].r_hashf; - wsp->walk_data = smbw; - - return (WALK_NEXT); -} - -int -smbnode_walk_step(mdb_walk_state_t *wsp) -{ - smbnode_walk_data_t *smbw = wsp->walk_data; - int status; - -next_bucket: - while (smbw->nodeptr == smbw->buckptr && - smbw->nextidx < smbw->tabsize) { - - /* Skip an empty bucket */ - rhashq_t *h = &smbw->smbtab[smbw->nextidx]; - smbw->nodeptr = (uintptr_t)h->r_hashf; - smbw->nextidx++; - smbw->buckptr += sizeof (rhashq_t); - } - - if (smbw->nodeptr == smbw->buckptr) - return (WALK_DONE); - - if (mdb_vread(&smbw->node, sizeof (smbw->node), - smbw->nodeptr) != sizeof (smbw->node)) { - mdb_warn("failed to read smbnode at %p in bucket %p\n", - smbw->nodeptr, smbw->buckptr); - /* Proceed with next bucket. */ - smbw->nodeptr = smbw->buckptr; - goto next_bucket; - } - - status = wsp->walk_callback(smbw->nodeptr, - &smbw->node, wsp->walk_cbdata); - - /* Move to next node in this bucket */ - smbw->nodeptr = (uintptr_t)smbw->node.r_hashf; - - return (status); -} - -/*ARGSUSED*/ -void -smbnode_walk_fini(mdb_walk_state_t *wsp) -{ - /* UM_GC takes care of it all. */ -} - -/* * Dcmd (and callback function) to print a summary of - * all smbnodes in the node hash table. + * all smbnodes in the node "hash" (cache) AVL tree. */ -typedef struct smbnode_cbdata { +typedef struct smbfs_node_cbdata { int flags; int printed_header; - uintptr_t smi; /* optional filtering by VFS */ - /* TODO: only nodes with a given [-h]ash */ - vnode_t vn; /* scratch space for smbnode_cb */ -} smbnode_cbdata_t; + vnode_t vn; +} smbfs_node_cbdata_t; int -smbnode_cb(uintptr_t addr, const void *data, void *arg) +smbfs_node_cb(uintptr_t addr, const void *data, void *arg) { const smbnode_t *np = data; - smbnode_cbdata_t *cbd = arg; - - /* Optional filtering by mount point. */ - if (cbd->smi && cbd->smi != (uintptr_t)np->n_mount) { - return (WALK_NEXT); - } + smbfs_node_cbdata_t *cbd = arg; if (cbd->printed_header == 0) { cbd->printed_header = 1; - mdb_printf("// smbnode vnode rpath\n"); + mdb_printf("// vnode smbnode rpath\n"); } - mdb_printf(" %-p", addr); /* smbnode */ mdb_printf(" %-p", (uintptr_t)np->r_vnode); + mdb_printf(" %-p", addr); /* smbnode */ print_str((uintptr_t)np->n_rpath); mdb_printf("\n"); @@ -320,9 +208,8 @@ smbnode_cb(uintptr_t addr, const void *data, void *arg) (uintptr_t)np->r_vnode); } else { /* Interesting parts of vnode_t */ - mdb_printf("v_type: %d v_path:", - cbd->vn.v_type); - print_str((uintptr_t)cbd->vn.v_path); + mdb_printf("v_type=%d v_count=%d", + cbd->vn.v_type, cbd->vn.v_count); mdb_printf("\n"); } mdb_dec_indent(2); @@ -332,55 +219,54 @@ smbnode_cb(uintptr_t addr, const void *data, void *arg) } int -smbnode_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) +smbfs_node_dcmd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv) { - smbnode_cbdata_t *cbd; - smbnode_t *np; + smbfs_node_cbdata_t *cbd; cbd = mdb_zalloc(sizeof (*cbd), UM_SLEEP | UM_GC); if (mdb_getopts(argc, argv, 'v', MDB_OPT_SETBITS, OPT_VERBOSE, &cbd->flags, - 'm', MDB_OPT_UINTPTR, &cbd->smi, NULL) != argc) { + NULL) != argc) { return (DCMD_USAGE); } if (!(flags & DCMD_ADDRSPEC)) { - if (mdb_walk("smbnode", smbnode_cb, cbd) - == -1) { - mdb_warn("cannot walk smbnodes"); - return (DCMD_ERR); - } - return (DCMD_OK); + mdb_warn("expect an smbmntinfo_t addr"); + return (DCMD_USAGE); } + addr += OFFSETOF(smbmntinfo_t, smi_hash_avl); - np = mdb_alloc(sizeof (*np), UM_SLEEP | UM_GC); - SMBFS_OBJ_FETCH(addr, smbnode_t, np, DCMD_ERR); - smbnode_cb(addr, np, cbd); + if (mdb_pwalk("genunix`avl", smbfs_node_cb, cbd, addr) == -1) { + mdb_warn("cannot walk smbfs nodes"); + return (DCMD_ERR); + } return (DCMD_OK); } void -smbnode_help(void) +smbfs_node_help(void) { mdb_printf("Options:\n" - " -m mntinfo only show smbnodes belonging to mntinfo\n" " -v be verbose when displaying smbnodes\n"); } static const mdb_dcmd_t dcmds[] = { - { "smbfs_vfs", "?[-v]", + { + "smbfs_vfs", "?[-v]", "show smbfs-mounted vfs structs", - smbfs_vfs_dcmd, smbfs_vfs_help }, - { "smbnode", "?[-v] [-m mntinfo]", - "show smbnodes", smbnode_dcmd, smbnode_help }, + smbfs_vfs_dcmd, smbfs_vfs_help + }, + { + "smbfs_node", "?[-v]", + "given an smbmntinfo_t, list smbnodes", + smbfs_node_dcmd, smbfs_node_help + }, {NULL} }; static const mdb_walker_t walkers[] = { - { "smbnode", "walk smbnode hash table", - smbnode_walk_init, smbnode_walk_step, smbnode_walk_fini }, {NULL} }; diff --git a/usr/src/lib/libsmbfs/smb/acl_conv.c b/usr/src/common/smbclnt/smbfs_ntacl.c index d19b323dfe..79d307f6ca 100644 --- a/usr/src/lib/libsmbfs/smb/acl_conv.c +++ b/usr/src/common/smbclnt/smbfs_ntacl.c @@ -25,43 +25,39 @@ */ /* - * ACL support for smbfs - * - * May want to move some of this to usr/src/common - * and compile with the smbfs kmod too, once we - * implement VOP_GETSECATTR, VOP_SETSECATTR. + * ACL conversion support for smbfs + * (To/from NT/ZFS-style ACLs.) */ #include <sys/types.h> #include <sys/errno.h> +#include <sys/acl.h> +#include <sys/byteorder.h> + +#ifdef _KERNEL + #include <sys/cred.h> #include <sys/cmn_err.h> #include <sys/kmem.h> #include <sys/sunddi.h> -#include <sys/acl.h> #include <sys/vnode.h> #include <sys/vfs.h> -#include <sys/byteorder.h> -#include <errno.h> +#include <sys/kidmap.h> + +#else /* _KERNEL */ + #include <stdio.h> -#include <string.h> +#include <stdlib.h> #include <strings.h> -#include <unistd.h> -#include <umem.h> #include <idmap.h> -#include <sys/fs/smbfs_ioctl.h> +#endif /* _KERNEL */ #include <netsmb/mchain.h> #include <netsmb/smb.h> - -#include <netsmb/smb_lib.h> -#include <netsmb/smbfs_acl.h> - -#include "acl_nt.h" -#include "private.h" +#include "smbfs_ntacl.h" #ifdef _KERNEL #define MALLOC(size) kmem_alloc(size, KM_SLEEP) @@ -80,7 +76,6 @@ FREESZ(void *p, size_t sz) #endif /* lint */ #endif /* _KERNEL */ - #define ERRCHK(expr) if ((error = expr) != 0) goto errout /* @@ -99,7 +94,7 @@ ifree_sid(i_ntsid_t *sid) } static int -mb_get_sid(mbdata_t *mbp, i_ntsid_t **sidp) +md_get_sid(mdchain_t *mdp, i_ntsid_t **sidp) { i_ntsid_t *sid = NULL; uint8_t revision, subauthcount; @@ -107,9 +102,9 @@ mb_get_sid(mbdata_t *mbp, i_ntsid_t **sidp) size_t sidsz; int error, i; - if ((error = mb_get_uint8(mbp, &revision)) != 0) + if ((error = md_get_uint8(mdp, &revision)) != 0) return (error); - if ((error = mb_get_uint8(mbp, &subauthcount)) != 0) + if ((error = md_get_uint8(mdp, &subauthcount)) != 0) return (error); sidsz = I_SID_SIZE(subauthcount); @@ -120,11 +115,11 @@ mb_get_sid(mbdata_t *mbp, i_ntsid_t **sidp) bzero(sid, sidsz); sid->sid_revision = revision; sid->sid_subauthcount = subauthcount; - ERRCHK(mb_get_mem(mbp, (char *)sid->sid_authority, 6)); + ERRCHK(md_get_mem(mdp, sid->sid_authority, 6, MB_MSYSTEM)); subauthp = &sid->sid_subauthvec[0]; for (i = 0; i < subauthcount; i++) { - ERRCHK(mb_get_uint32le(mbp, subauthp)); + ERRCHK(md_get_uint32le(mdp, subauthp)); subauthp++; } @@ -138,7 +133,7 @@ errout: } static int -mb_put_sid(mbdata_t *mbp, i_ntsid_t *sid) +mb_put_sid(mbchain_t *mbp, i_ntsid_t *sid) { uint32_t *subauthp; int error, i; @@ -148,7 +143,7 @@ mb_put_sid(mbdata_t *mbp, i_ntsid_t *sid) ERRCHK(mb_put_uint8(mbp, sid->sid_revision)); ERRCHK(mb_put_uint8(mbp, sid->sid_subauthcount)); - ERRCHK(mb_put_mem(mbp, (char *)sid->sid_authority, 6)); + ERRCHK(mb_put_mem(mbp, sid->sid_authority, 6, MB_MSYSTEM)); subauthp = &sid->sid_subauthvec[0]; for (i = 0; i < sid->sid_subauthcount; i++) { @@ -179,9 +174,9 @@ ifree_ace(i_ntace_t *ace) } static int -mb_get_ace(mbdata_t *mbp, i_ntace_t **acep) +md_get_ace(mdchain_t *mdp, i_ntace_t **acep) { - mbdata_t tmp_mb; + mdchain_t tmp_md; i_ntace_t *ace = NULL; uint16_t ace_len; int error; @@ -196,22 +191,22 @@ mb_get_ace(mbdata_t *mbp, i_ntace_t **acep) * XXX: This only decodes types 0-7 * * There may also be padding after it, so - * decode the using a copy of the mbdata, + * decode the using a copy of the mdchain, * and then consume the specified length. */ - tmp_mb = *mbp; + tmp_md = *mdp; /* Fixed-size header */ - ERRCHK(mb_get_uint8(&tmp_mb, &ace->ace_type)); - ERRCHK(mb_get_uint8(&tmp_mb, &ace->ace_flags)); - ERRCHK(mb_get_uint16le(&tmp_mb, &ace_len)); + ERRCHK(md_get_uint8(&tmp_md, &ace->ace_type)); + ERRCHK(md_get_uint8(&tmp_md, &ace->ace_flags)); + ERRCHK(md_get_uint16le(&tmp_md, &ace_len)); /* Variable-size body */ - ERRCHK(mb_get_uint32le(&tmp_mb, &ace->ace_rights)); - ERRCHK(mb_get_sid(&tmp_mb, &ace->ace_sid)); + ERRCHK(md_get_uint32le(&tmp_md, &ace->ace_rights)); + ERRCHK(md_get_sid(&tmp_md, &ace->ace_sid)); /* Now actually consume ace_len */ - ERRCHK(mb_get_mem(mbp, NULL, ace_len)); + ERRCHK(md_get_mem(mdp, NULL, ace_len, MB_MSYSTEM)); /* Success! */ *acep = ace; @@ -223,7 +218,7 @@ errout: } static int -mb_put_ace(mbdata_t *mbp, i_ntace_t *ace) +mb_put_ace(mbchain_t *mbp, i_ntace_t *ace) { int cnt0, error; uint16_t ace_len, *ace_len_p; @@ -235,7 +230,11 @@ mb_put_ace(mbdata_t *mbp, i_ntace_t *ace) ERRCHK(mb_put_uint8(mbp, ace->ace_type)); ERRCHK(mb_put_uint8(mbp, ace->ace_flags)); - ERRCHK(mb_fit(mbp, 2, (char **)&ace_len_p)); + ace_len_p = mb_reserve(mbp, sizeof (*ace_len_p)); + if (ace_len_p == NULL) { + error = ENOMEM; + goto errout; + } ERRCHK(mb_put_uint32le(mbp, ace->ace_rights)); ERRCHK(mb_put_sid(mbp, ace->ace_sid)); @@ -278,7 +277,7 @@ ifree_acl(i_ntacl_t *acl) } static int -mb_get_acl(mbdata_t *mbp, i_ntacl_t **aclp) +md_get_acl(mdchain_t *mdp, i_ntacl_t **aclp) { i_ntacl_t *acl = NULL; i_ntace_t **acep; @@ -287,15 +286,15 @@ mb_get_acl(mbdata_t *mbp, i_ntacl_t **aclp) size_t aclsz; int i, error; - if ((error = mb_get_uint8(mbp, &revision)) != 0) + if ((error = md_get_uint8(mdp, &revision)) != 0) return (error); - if ((error = mb_get_uint8(mbp, NULL)) != 0) + if ((error = md_get_uint8(mdp, NULL)) != 0) return (error); - if ((error = mb_get_uint16le(mbp, &acl_len)) != 0) + if ((error = md_get_uint16le(mdp, &acl_len)) != 0) return (error); - if ((error = mb_get_uint16le(mbp, &acecount)) != 0) + if ((error = md_get_uint16le(mdp, &acecount)) != 0) return (error); - if ((error = mb_get_uint16(mbp, NULL)) != 0) + if ((error = md_get_uint16le(mdp, NULL)) != 0) return (error); aclsz = I_ACL_SIZE(acecount); @@ -307,7 +306,7 @@ mb_get_acl(mbdata_t *mbp, i_ntacl_t **aclp) acep = &acl->acl_acevec[0]; for (i = 0; i < acl->acl_acecount; i++) { - ERRCHK(mb_get_ace(mbp, acep)); + ERRCHK(md_get_ace(mdp, acep)); acep++; } /* @@ -325,7 +324,7 @@ errout: } static int -mb_put_acl(mbdata_t *mbp, i_ntacl_t *acl) +mb_put_acl(mbchain_t *mbp, i_ntacl_t *acl) { i_ntace_t **acep; uint16_t acl_len, *acl_len_p; @@ -335,7 +334,11 @@ mb_put_acl(mbdata_t *mbp, i_ntacl_t *acl) ERRCHK(mb_put_uint8(mbp, acl->acl_revision)); ERRCHK(mb_put_uint8(mbp, 0)); /* pad1 */ - ERRCHK(mb_fit(mbp, 2, (char **)&acl_len_p)); + acl_len_p = mb_reserve(mbp, sizeof (*acl_len_p)); + if (acl_len_p == NULL) { + error = ENOMEM; + goto errout; + } ERRCHK(mb_put_uint16le(mbp, acl->acl_acecount)); ERRCHK(mb_put_uint16le(mbp, 0)); /* pad2 */ @@ -380,14 +383,14 @@ smbfs_acl_free_sd(i_ntsd_t *sd) * (like "absolute" form per. NT docs) * Returns allocated data in sdp * - * Note: does NOT consume all the mbp data, so the + * Note: does NOT consume all the mdp data, so the * caller has to take care of that if necessary. */ int -mb_get_ntsd(mbdata_t *mbp, i_ntsd_t **sdp) +md_get_ntsd(mdchain_t *mdp, i_ntsd_t **sdp) { i_ntsd_t *sd = NULL; - mbdata_t top_mb, tmp_mb; + mdchain_t top_md, tmp_md; uint32_t owneroff, groupoff, sacloff, dacloff; int error; @@ -397,44 +400,44 @@ mb_get_ntsd(mbdata_t *mbp, i_ntsd_t **sdp) /* * Offsets below are relative to this point, - * so save the mbp state for use below. + * so save the mdp state for use below. */ - top_mb = *mbp; + top_md = *mdp; - ERRCHK(mb_get_uint8(mbp, &sd->sd_revision)); - ERRCHK(mb_get_uint8(mbp, NULL)); - ERRCHK(mb_get_uint16le(mbp, &sd->sd_flags)); - ERRCHK(mb_get_uint32le(mbp, &owneroff)); - ERRCHK(mb_get_uint32le(mbp, &groupoff)); - ERRCHK(mb_get_uint32le(mbp, &sacloff)); - ERRCHK(mb_get_uint32le(mbp, &dacloff)); + ERRCHK(md_get_uint8(mdp, &sd->sd_revision)); + ERRCHK(md_get_uint8(mdp, &sd->sd_rmctl)); + ERRCHK(md_get_uint16le(mdp, &sd->sd_flags)); + ERRCHK(md_get_uint32le(mdp, &owneroff)); + ERRCHK(md_get_uint32le(mdp, &groupoff)); + ERRCHK(md_get_uint32le(mdp, &sacloff)); + ERRCHK(md_get_uint32le(mdp, &dacloff)); /* * For each section make a temporary copy of the - * top_mb state, advance to the given offset, and - * pass that to the lower mb_get_xxx functions. + * top_md state, advance to the given offset, and + * pass that to the lower md_get_xxx functions. * These could be marshalled in any order, but * are normally found in the order shown here. */ if (sacloff) { - tmp_mb = top_mb; - mb_get_mem(&tmp_mb, NULL, sacloff); - ERRCHK(mb_get_acl(&tmp_mb, &sd->sd_sacl)); + tmp_md = top_md; + md_get_mem(&tmp_md, NULL, sacloff, MB_MSYSTEM); + ERRCHK(md_get_acl(&tmp_md, &sd->sd_sacl)); } if (dacloff) { - tmp_mb = top_mb; - mb_get_mem(&tmp_mb, NULL, dacloff); - ERRCHK(mb_get_acl(&tmp_mb, &sd->sd_dacl)); + tmp_md = top_md; + md_get_mem(&tmp_md, NULL, dacloff, MB_MSYSTEM); + ERRCHK(md_get_acl(&tmp_md, &sd->sd_dacl)); } if (owneroff) { - tmp_mb = top_mb; - mb_get_mem(&tmp_mb, NULL, owneroff); - ERRCHK(mb_get_sid(&tmp_mb, &sd->sd_owner)); + tmp_md = top_md; + md_get_mem(&tmp_md, NULL, owneroff, MB_MSYSTEM); + ERRCHK(md_get_sid(&tmp_md, &sd->sd_owner)); } if (groupoff) { - tmp_mb = top_mb; - mb_get_mem(&tmp_mb, NULL, groupoff); - ERRCHK(mb_get_sid(&tmp_mb, &sd->sd_group)); + tmp_md = top_md; + md_get_mem(&tmp_md, NULL, groupoff, MB_MSYSTEM); + ERRCHK(md_get_sid(&tmp_md, &sd->sd_group)); } /* Success! */ @@ -452,7 +455,7 @@ errout: * Returns allocated mbchain in mbp. */ int -mb_put_ntsd(mbdata_t *mbp, i_ntsd_t *sd) +mb_put_ntsd(mbchain_t *mbp, i_ntsd_t *sd) { uint32_t *owneroffp, *groupoffp, *sacloffp, *dacloffp; uint32_t owneroff, groupoff, sacloff, dacloff; @@ -462,12 +465,18 @@ mb_put_ntsd(mbdata_t *mbp, i_ntsd_t *sd) owneroff = groupoff = sacloff = dacloff = 0; ERRCHK(mb_put_uint8(mbp, sd->sd_revision)); - ERRCHK(mb_put_uint8(mbp, 0)); /* pad1 */ + ERRCHK(mb_put_uint8(mbp, sd->sd_rmctl)); ERRCHK(mb_put_uint16le(mbp, sd->sd_flags)); - ERRCHK(mb_fit(mbp, 4, (char **)&owneroffp)); - ERRCHK(mb_fit(mbp, 4, (char **)&groupoffp)); - ERRCHK(mb_fit(mbp, 4, (char **)&sacloffp)); - ERRCHK(mb_fit(mbp, 4, (char **)&dacloffp)); + + owneroffp = mb_reserve(mbp, sizeof (*owneroffp)); + groupoffp = mb_reserve(mbp, sizeof (*groupoffp)); + sacloffp = mb_reserve(mbp, sizeof (*sacloffp)); + dacloffp = mb_reserve(mbp, sizeof (*dacloffp)); + if (owneroffp == NULL || groupoffp == NULL || + sacloffp == NULL || dacloffp == NULL) { + error = ENOMEM; + goto errout; + } /* * These could be marshalled in any order, but @@ -535,7 +544,7 @@ smbfs_sid2str(i_ntsid_t *sid, for (i = 0; i < 6; i++) auth = (auth << 8) | sid->sid_authority[i]; - n = snprintf(s, osz, "-%llu", auth); + n = snprintf(s, osz, "-%llu", (u_longlong_t)auth); if (n > osz) return (-1); s += n; osz -= n; @@ -556,19 +565,29 @@ smbfs_sid2str(i_ntsid_t *sid, if (ridp) *ridp = *ip; + /* LINTED E_PTRDIFF_OVERFLOW */ return (s - obuf); } /* * Our interface to the idmap service. + * + * The idmap API is _almost_ the same between + * kernel and user-level. But not quite... + * Hope this improves readability below. */ - #ifdef _KERNEL -#define I_GetPidBySid kidmap_batch_getpidbysid + +#define I_GetPidBySid(GH, SPP, RID, PIDP, ISUP, SP) \ + kidmap_batch_getpidbysid(GH, SPP, RID, PIDP, ISUP, SP) #define I_GetMappings kidmap_get_mappings + #else /* _KERNEL */ -#define I_GetPidBySid idmap_get_pidbysid + +#define I_GetPidBySid(GH, SPP, RID, PIDP, ISUP, SP) \ + idmap_get_pidbysid(GH, SPP, RID, 0, PIDP, ISUP, SP) #define I_GetMappings idmap_get_mappings + #endif /* _KERNEL */ struct mapinfo { @@ -615,7 +634,7 @@ mkrq_idmap_sid2ux( return (0); } - idms = I_GetPidBySid(idmap_gh, sid_prefix, rid, 0, + idms = I_GetPidBySid(idmap_gh, sid_prefix, rid, &mip->mi_uid, &mip->mi_isuser, &mip->mi_status); if (idms != IDMAP_SUCCESS) return (EINVAL); @@ -824,9 +843,6 @@ smbfs_acl_sd2zfs( idms = I_GetMappings(idmap_gh); if (idms != IDMAP_SUCCESS) { -#ifdef DEBUG - printf("idmap_get_mappings: rc=%d\n", idms); -#endif /* creative error choice */ error = EIDRM; goto errout; diff --git a/usr/src/lib/libsmbfs/smb/acl_nt.h b/usr/src/common/smbclnt/smbfs_ntacl.h index 844a7e6543..cf6788f491 100644 --- a/usr/src/lib/libsmbfs/smb/acl_nt.h +++ b/usr/src/common/smbclnt/smbfs_ntacl.h @@ -24,15 +24,15 @@ * Use is subject to license terms. */ -#ifndef _ACL_NT_H -#define _ACL_NT_H +#ifndef _SMBFS_NTACL_H +#define _SMBFS_NTACL_H /* * Internal functions for dealing with * NT Security data structures. */ -#include <netsmb/smbfs_acl.h> +#include <netsmb/mchain.h> /* * Internal form of an NT SID @@ -68,46 +68,60 @@ typedef struct i_ntacl { /* * Internal form of an NT Security Descriptor (SD) */ -struct i_ntsd { +typedef struct i_ntsd { uint8_t sd_revision; /* 0x01 observed between W2K */ + uint8_t sd_rmctl; /* resource mgr control (MBZ) */ uint16_t sd_flags; i_ntsid_t *sd_owner; i_ntsid_t *sd_group; i_ntacl_t *sd_sacl; i_ntacl_t *sd_dacl; -}; - -struct mbdata; +} i_ntsd_t; /* * Import a raw SD (mb chain) into "internal" form. * (like "absolute" form per. NT docs) * Returns allocated data in sdp */ -int mb_get_ntsd(struct mbdata *mbp, i_ntsd_t **sdp); +int md_get_ntsd(mdchain_t *mbp, i_ntsd_t **sdp); /* * Export an "internal" SD into an raw SD (mb chain). * (a.k.a "self-relative" form per. NT docs) * Returns allocated mbchain in mbp. */ -int mb_put_ntsd(struct mbdata *mbp, i_ntsd_t *sd); - +int mb_put_ntsd(mbchain_t *mbp, i_ntsd_t *sd); /* - * Get an SD via ioctl on FD (with "selector" bits), - * stroing the raw Windows SD in the mb chain mbp. + * Convert an internal SD to a ZFS-style ACL. + * Get uid/gid too if pointers != NULL. */ -int smbfs_acl_iocget(int fd, uint32_t selector, struct mbdata *mbp); +#ifdef _KERNEL +int smbfs_acl_sd2zfs(i_ntsd_t *, vsecattr_t *, uid_t *, gid_t *); +#else /* _KERNEL */ +int smbfs_acl_sd2zfs(i_ntsd_t *, acl_t *, uid_t *, gid_t *); +#endif /* _KERNEL */ /* - * Set an SD via ioctl on FD (with "selector" bits), - * with a raw Windows SD from the chain mbp. + * Convert an internal SD to a ZFS-style ACL. + * Include owner/group too if uid/gid != -1. */ -int smbfs_acl_iocset(int fd, uint32_t selector, struct mbdata *mbp); +#ifdef _KERNEL +int smbfs_acl_zfs2sd(vsecattr_t *, uid_t, gid_t, i_ntsd_t **); +#else /* _KERNEL */ +int smbfs_acl_zfs2sd(acl_t *, uid_t, gid_t, i_ntsd_t **); +#endif /* _KERNEL */ +/* + * Free an i_ntsd_t, as returned by md_get_ntsd() + * or smbfs_acl_zfs2sd(). + */ +void smbfs_acl_free_sd(struct i_ntsd *); +/* + * Convert an NT SID to string format. + */ int smbfs_sid2str(i_ntsid_t *sid, char *obuf, size_t olen, uint32_t *ridp); -#endif /* _ACL_NT_H */ +#endif /* _SMBFS_NTACL_H */ diff --git a/usr/src/lib/libsmbfs/Makefile.com b/usr/src/lib/libsmbfs/Makefile.com index 656ba731b3..f7a6c06790 100644 --- a/usr/src/lib/libsmbfs/Makefile.com +++ b/usr/src/lib/libsmbfs/Makefile.com @@ -33,9 +33,8 @@ VERS= .1 # leaving out: kiconv.o -OBJECTS=\ +OBJ_LIB=\ acl_api.o \ - acl_conv.o \ acl_print.o \ charsets.o \ cfopt.o \ @@ -75,13 +74,19 @@ OBJECTS=\ ui-sun.o \ utf_str.o +OBJ_CMN= smbfs_ntacl.o + +OBJECTS= $(OBJ_LIB) $(OBJ_CMN) + include $(SRC)/lib/Makefile.lib LIBS = $(DYNLIB) $(LINTLIB) SRCDIR= ../smb +CMNDIR= $(SRC)/common/smbclnt -SRCS= $(OBJECTS:%.o=../smb/%.c) +SRCS= $(OBJ_LIB:%.o=$(SRCDIR)/%.c) \ + $(OBJ_CMN:%.o=$(CMNDIR)/%.c) $(LINTLIB) := SRCS = $(SRCDIR)/$(LINTSRC) @@ -93,7 +98,9 @@ LDLIBS += -lsocket -lnsl -lc -lmd -lpkcs11 -lkrb5 -lsec -lidmap CFLAGS += $(CCVERBOSE) CPPFLAGS += -D__EXTENSIONS__ -D_REENTRANT -DMIA \ - -I$(SRCDIR) -I.. -I$(SRC)/uts/common + -I$(SRCDIR) -I.. \ + -I$(SRC)/uts/common \ + -I$(SRC)/common/smbclnt # Debugging ${NOT_RELEASE_BUILD} CPPFLAGS += -DDEBUG @@ -104,15 +111,22 @@ ${NOT_RELEASE_BUILD} CPPFLAGS += -DDEBUG #CTFCONVERT_O= #CTFMERGE_LIB= -# disable some of the less important lint -LINTCHECKFLAGS += -erroff=E_FUNC_RET_ALWAYS_IGNOR2 -LINTCHECKFLAGS += -erroff=E_FUNC_RET_MAYBE_IGNORED2 -LINTCHECKFLAGS += -DDEBUG +# Filter out the less important lint. +# See lgrep.awk +LGREP = nawk -f $(SRCDIR)/lgrep.awk +LTAIL += 2>&1 | $(LGREP) all: $(LIBS) -lint: lintcheck +lint: lintcheck_t include ../../Makefile.targ +lintcheck_t: $$(SRCS) + $(LINT.c) $(LINTCHECKFLAGS) $(SRCS) $(LDLIBS) $(LTAIL) + +objs/%.o pics/%.o: $(CMNDIR)/%.c + $(COMPILE.c) -o $@ $< + $(POST_PROCESS_O) + .KEEP_STATE: diff --git a/usr/src/lib/libsmbfs/netsmb/smbfs_acl.h b/usr/src/lib/libsmbfs/netsmb/smbfs_acl.h index d1da5bda22..b8cf6a8036 100644 --- a/usr/src/lib/libsmbfs/netsmb/smbfs_acl.h +++ b/usr/src/lib/libsmbfs/netsmb/smbfs_acl.h @@ -61,37 +61,26 @@ int smbfs_acl_set(int fd, acl_t *, uid_t, gid_t); /* * Slightly lower-level functions, allowing access to * the raw Windows Security Descriptor (SD) + * + * The struct i_ntsid is opaque in this I/F. + * Real decl. in: common/smbclnt/smbfs_ntacl.h */ -typedef struct i_ntsd i_ntsd_t; +struct i_ntsd; /* * Get an "internal form" SD from the FD (opened in smbfs). * Allocates a hierarchy in isdp. Caller must free it via * smbfs_acl_free_isd() */ -int smbfs_acl_getsd(int fd, uint32_t, i_ntsd_t **); +int smbfs_acl_getsd(int fd, uint32_t, struct i_ntsd **); /* * Set an "internal form" SD onto the FD (opened in smbfs). */ -int smbfs_acl_setsd(int fd, uint32_t, i_ntsd_t *); - -/* - * Convert an internal SD to a ZFS-style ACL. - * Get uid/gid too if pointers != NULL. - */ -int smbfs_acl_sd2zfs(i_ntsd_t *, acl_t *, uid_t *, gid_t *); - -/* - * Convert an internal SD to a ZFS-style ACL. - * Include owner/group too if uid/gid != -1. - */ -int smbfs_acl_zfs2sd(acl_t *, uid_t, gid_t, i_ntsd_t **); - -void smbfs_acl_free_sd(i_ntsd_t *); +int smbfs_acl_setsd(int fd, uint32_t, struct i_ntsd *); struct __FILE; -void smbfs_acl_print_sd(struct __FILE *, i_ntsd_t *); +void smbfs_acl_print_sd(struct __FILE *, struct i_ntsd *); #ifdef __cplusplus } diff --git a/usr/src/lib/libsmbfs/smb/acl_api.c b/usr/src/lib/libsmbfs/smb/acl_api.c index 3e9d703c99..b5b6123063 100644 --- a/usr/src/lib/libsmbfs/smb/acl_api.c +++ b/usr/src/lib/libsmbfs/smb/acl_api.c @@ -53,7 +53,7 @@ #include <netsmb/smb_lib.h> #include <netsmb/smbfs_acl.h> -#include "acl_nt.h" +#include "smbfs_ntacl.h" #include "private.h" /* Sanity check SD sizes */ @@ -78,7 +78,7 @@ smbfs_acl_iocget(int fd, uint32_t selector, mbdata_t *mbp) struct mbuf *m; int error; - error = mb_init(mbp, MAX_RAW_SD_SIZE); + error = mb_init_sz(mbp, MAX_RAW_SD_SIZE); if (error) return (error); @@ -157,7 +157,7 @@ smbfs_acl_getsd(int fd, uint32_t selector, i_ntsd_t **sdp) * (like "absolute" form per. NT docs) * Returns allocated data in sdp */ - error = mb_get_ntsd(mbp, sdp); + error = md_get_ntsd(mbp, sdp); } mb_done(mbp); @@ -174,7 +174,9 @@ smbfs_acl_setsd(int fd, uint32_t selector, i_ntsd_t *sd) int error; mbp = &mb_store; - mb_init(mbp, M_MINSIZE); + error = mb_init_sz(mbp, MAX_RAW_SD_SIZE); + if (error) + return (error); /* * Export the "internal" SD into an mb chain. diff --git a/usr/src/lib/libsmbfs/smb/acl_print.c b/usr/src/lib/libsmbfs/smb/acl_print.c index 259258a9f1..6d399e32aa 100644 --- a/usr/src/lib/libsmbfs/smb/acl_print.c +++ b/usr/src/lib/libsmbfs/smb/acl_print.c @@ -53,7 +53,7 @@ #include <netsmb/smb_lib.h> #include <netsmb/smbfs_acl.h> -#include "acl_nt.h" +#include "smbfs_ntacl.h" static void fprint_sid(FILE *fp, i_ntsid_t *sid) diff --git a/usr/src/lib/libsmbfs/smb/ctx.c b/usr/src/lib/libsmbfs/smb/ctx.c index 04057ac334..40a62a3853 100644 --- a/usr/src/lib/libsmbfs/smb/ctx.c +++ b/usr/src/lib/libsmbfs/smb/ctx.c @@ -253,22 +253,30 @@ smb_ctx_init(struct smb_ctx *ctx) ctx->ct_authflags = SMB_AT_DEFAULT; ctx->ct_minauth = SMB_AT_DEFAULT; - nb_ctx_setscope(ctx->ct_nb, ""); + error = nb_ctx_setscope(ctx->ct_nb, ""); + if (error) + return (error); /* * if the user name is not specified some other way, * use the current user name (built-in default) */ if (getpwuid_r(getuid(), &pw, pwbuf, sizeof (pwbuf)) != NULL) { - smb_ctx_setuser(ctx, pw.pw_name, 0); + error = smb_ctx_setuser(ctx, pw.pw_name, 0); + if (error) + return (error); ctx->ct_home = strdup(pw.pw_name); + if (ctx->ct_home == NULL) + return (ENOMEM); } /* * Set a built-in default domain (workgroup). * Using the Windows/NT default for now. */ - smb_ctx_setdomain(ctx, "WORKGROUP", 0); + error = smb_ctx_setdomain(ctx, "WORKGROUP", 0); + if (error) + return (error); return (error); } @@ -571,7 +579,7 @@ smb_ctx_parseunc(struct smb_ctx *ctx, const char *unc, */ if (strchr(tmp, '%')) (void) unpercent(tmp); - smb_ctx_setfullserver(ctx, tmp); + error = smb_ctx_setfullserver(ctx, tmp); if (error) goto out; @@ -771,7 +779,7 @@ smb_ctx_setpassword(struct smb_ctx *ctx, const char *passwd, int from_cmd) memset(ctx->ct_password, 0, sizeof (ctx->ct_password)); if (strncmp(passwd, "$$1", 3) == 0) - smb_simpledecrypt(ctx->ct_password, passwd); + (void) smb_simpledecrypt(ctx->ct_password, passwd); else strlcpy(ctx->ct_password, passwd, sizeof (ctx->ct_password)); @@ -1387,14 +1395,15 @@ smb_ctx_readrcsection(struct smb_ctx *ctx, const char *sname, int level) if (p) { /* * "signing" was set in this section; override - * the current signing settings. + * the current signing settings. Note: + * setsigning flags are: enable, require */ if (strcmp(p, "disabled") == 0) { - smb_ctx_setsigning(ctx, FALSE, FALSE); + (void) smb_ctx_setsigning(ctx, FALSE, FALSE); } else if (strcmp(p, "enabled") == 0) { - smb_ctx_setsigning(ctx, TRUE, FALSE); + (void) smb_ctx_setsigning(ctx, TRUE, FALSE); } else if (strcmp(p, "required") == 0) { - smb_ctx_setsigning(ctx, TRUE, TRUE); + (void) smb_ctx_setsigning(ctx, TRUE, TRUE); } else { /* * Unknown "signing" value. diff --git a/usr/src/lib/libsmbfs/smb/file.c b/usr/src/lib/libsmbfs/smb/file.c index 74630fdd91..3c8184e8a1 100644 --- a/usr/src/lib/libsmbfs/smb/file.c +++ b/usr/src/lib/libsmbfs/smb/file.c @@ -114,7 +114,7 @@ smb_fh_ntcreate( mb_put_uint16le(mbp, 0xff); /* secondary command */ mb_put_uint16le(mbp, 0); /* offset to next command (none) */ mb_put_uint8(mbp, 0); /* MBZ (pad?) */ - mb_fit(mbp, 2, &pathsizep); /* path size - fill in below */ + (void) mb_fit(mbp, 2, &pathsizep); /* path size - fill in below */ mb_put_uint32le(mbp, flags); /* create flags (oplock) */ mb_put_uint32le(mbp, 0); /* FID - basis for path if not root */ mb_put_uint32le(mbp, req_acc); @@ -138,7 +138,7 @@ smb_fh_ntcreate( mb_put_uint8(mbp, 0); } pathstart = mbp->mb_count; - mb_put_dstring(mbp, path, uc); + mb_put_string(mbp, path, uc); smb_rq_bend(rqp); /* Now go back and fill in pathsizep */ @@ -155,30 +155,30 @@ smb_fh_ntcreate( * spec says 26 for word count, but 34 words are defined * and observed from win2000 */ - error = mb_get_uint8(mbp, &wc); + error = md_get_uint8(mbp, &wc); if (error || wc < 26) { smb_error(dgettext(TEXT_DOMAIN, "%s: open failed, bad word count"), 0, path); error = EBADRPC; goto out; } - mb_get_uint8(mbp, NULL); /* secondary cmd */ - mb_get_uint8(mbp, NULL); /* mbz */ - mb_get_uint16le(mbp, NULL); /* andxoffset */ - mb_get_uint8(mbp, NULL); /* oplock lvl granted */ - mb_get_uint16le(mbp, &fh); /* FID */ - mb_get_uint32le(mbp, action_taken); + md_get_uint8(mbp, NULL); /* secondary cmd */ + md_get_uint8(mbp, NULL); /* mbz */ + md_get_uint16le(mbp, NULL); /* andxoffset */ + md_get_uint8(mbp, NULL); /* oplock lvl granted */ + md_get_uint16le(mbp, &fh); /* FID */ + md_get_uint32le(mbp, action_taken); #if 0 /* skip decoding the rest */ - mb_get_uint64le(mbp, NULL); /* creation time */ - mb_get_uint64le(mbp, NULL); /* access time */ - mb_get_uint64le(mbp, NULL); /* write time */ - mb_get_uint64le(mbp, NULL); /* change time */ - mb_get_uint32le(mbp, NULL); /* attributes */ - mb_get_uint64le(mbp, NULL); /* allocation size */ - mb_get_uint64le(mbp, NULL); /* EOF */ - mb_get_uint16le(mbp, NULL); /* file type */ - mb_get_uint16le(mbp, NULL); /* device state */ - mb_get_uint8(mbp, NULL); /* directory (boolean) */ + md_get_uint64le(mbp, NULL); /* creation time */ + md_get_uint64le(mbp, NULL); /* access time */ + md_get_uint64le(mbp, NULL); /* write time */ + md_get_uint64le(mbp, NULL); /* change time */ + md_get_uint32le(mbp, NULL); /* attributes */ + md_get_uint64le(mbp, NULL); /* allocation size */ + md_get_uint64le(mbp, NULL); /* EOF */ + md_get_uint16le(mbp, NULL); /* file type */ + md_get_uint16le(mbp, NULL); /* device state */ + md_get_uint8(mbp, NULL); /* directory (boolean) */ #endif /* success! */ diff --git a/usr/src/lib/libsmbfs/smb/iod_cl.c b/usr/src/lib/libsmbfs/smb/iod_cl.c index 074b2ad848..7449d68ed5 100644 --- a/usr/src/lib/libsmbfs/smb/iod_cl.c +++ b/usr/src/lib/libsmbfs/smb/iod_cl.c @@ -151,7 +151,7 @@ smb_iod_start(smb_ctx_t *ctx) char *argv[2]; argv[0] = "smbiod"; argv[1] = NULL; - execv(smbiod_path, argv); + (void) execv(smbiod_path, argv); _exit(1); } @@ -160,7 +160,7 @@ smb_iod_start(smb_ctx_t *ctx) */ tmo = iod_start_timeout; while (--tmo >= 0) { - sleep(1); + (void) sleep(1); err = smb_iod_open_door(&fd); if (err == 0) goto OK; diff --git a/usr/src/lib/libsmbfs/smb/keychain.c b/usr/src/lib/libsmbfs/smb/keychain.c index da19fd4d0b..c5cf319c21 100644 --- a/usr/src/lib/libsmbfs/smb/keychain.c +++ b/usr/src/lib/libsmbfs/smb/keychain.c @@ -290,8 +290,11 @@ smbfs_default_dom_usr(const char *home, const char *server, if (err) return (err); - if (server) - smb_ctx_setfullserver(ctx, server); + if (server) { + err = smb_ctx_setfullserver(ctx, server); + if (err != 0) + goto out; + } if (home && *home) { if (ctx->ct_home) diff --git a/usr/src/lib/libsmbfs/smb/krb5ssp.c b/usr/src/lib/libsmbfs/smb/krb5ssp.c index fbbd08398b..d473c07c79 100644 --- a/usr/src/lib/libsmbfs/smb/krb5ssp.c +++ b/usr/src/lib/libsmbfs/smb/krb5ssp.c @@ -236,9 +236,9 @@ krb5ssp_put_request(struct ssp_ctx *sp, struct mbdata *out_mb) if ((err = krb5ssp_tkt2gtok(tkt, tktlen, >ok, >oklen)) != 0) goto out; - if ((err = mb_init(out_mb, gtoklen)) != 0) + if ((err = mb_init_sz(out_mb, gtoklen)) != 0) goto out; - if ((err = mb_put_mem(out_mb, gtok, gtoklen)) != 0) + if ((err = mb_put_mem(out_mb, gtok, gtoklen, MB_MSYSTEM)) != 0) goto out; if (ctx->ct_vcflags & SMBV_WILL_SIGN) diff --git a/usr/src/lib/libsmbfs/smb/lgrep.awk b/usr/src/lib/libsmbfs/smb/lgrep.awk new file mode 100644 index 0000000000..8f36708df8 --- /dev/null +++ b/usr/src/lib/libsmbfs/smb/lgrep.awk @@ -0,0 +1,54 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# + +# +# Copyright 2009 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# + +# This is a "lint tail" that removes all the +# uninteresting lines from our lint output. +# It's nawk because sed doesn't do (a|b). +# Also comments are easier here. + +# The mb_put/md_get functions are intentionally used both +# with and without return value checks. Not a concern. +/: mb_put_.* .E_FUNC_RET_[A-Z]*_IGNOR/ { next; } +/: md_get_.* .E_FUNC_RET_[A-Z]*_IGNOR/ { next; } + +# The rc_get* functions clear the out arg even on failure, +# so most callers don't need to check the return value. +/: rc_get[a-z]* .E_FUNC_RET_[A-Z]*_IGNOR/ { next; } + +# These have uninteresting return values, usually ignored. +/: (n|sm)b_ctx_readrcsection .E_FUNC_RET_[A-Z]*_IGNOR/ { next; } +/: nls_str_(lower|upper) .E_FUNC_RET_[A-Z]*_IGNOR/ { next; } +/: rc_(close|freesect) .E_FUNC_RET_[A-Z]*_IGNOR/ { next; } + +# Other functions for which we often ignore return values. +/: [a-z]*close .E_FUNC_RET_[A-Z]*_IGNOR/ { next; } +/: [a-z]*flush .E_FUNC_RET_[A-Z]*_IGNOR/ { next; } +/: [a-z]*printf .E_FUNC_RET_[A-Z]*_IGNOR/ { next; } +/: mem(cpy|move|set) .E_FUNC_RET_[A-Z]*_IGNOR/ { next; } +/: mutex_.* .E_FUNC_RET_[A-Z]*_IGNOR/ { next; } +/: str[ln]?(cat|cpy) .E_FUNC_RET_[A-Z]*_IGNOR/ { next; } + +{ print; } diff --git a/usr/src/lib/libsmbfs/smb/mbuf.c b/usr/src/lib/libsmbfs/smb/mbuf.c index 9380ec12e9..86710f3f94 100644 --- a/usr/src/lib/libsmbfs/smb/mbuf.c +++ b/usr/src/lib/libsmbfs/smb/mbuf.c @@ -53,8 +53,20 @@ #include "private.h" #include "charsets.h" -static int -m_get(size_t len, struct mbuf **mpp) +/* + * Note: Leaving a little space (8 bytes) between the + * mbuf header and the start of the data so we can + * prepend a NetBIOS header in that space. + */ +#define M_ALIGNFACTOR (sizeof (long)) +#define M_ALIGN(len) (((len) + M_ALIGNFACTOR - 1) & ~(M_ALIGNFACTOR - 1)) +#define M_BASESIZE (sizeof (struct mbuf) + 8) +#define M_MINSIZE (1024 - M_BASESIZE) +#define M_TOP(m) ((char *)(m) + M_BASESIZE) +#define M_TRAILINGSPACE(m) ((m)->m_maxlen - (m)->m_len) + +int +m_get(int len, struct mbuf **mpp) { struct mbuf *m; @@ -132,37 +144,42 @@ m_lineup(struct mbuf *m0, struct mbuf **mpp) } int -mb_init(struct mbdata *mbp, size_t size) +mb_init(struct mbdata *mbp) +{ + return (mb_init_sz(mbp, M_MINSIZE)); +} + +int +mb_init_sz(struct mbdata *mbp, int size) { struct mbuf *m; int error; if ((error = m_get(size, &m)) != 0) return (error); - return (mb_initm(mbp, m)); + mb_initm(mbp, m); + return (0); } -int +void mb_initm(struct mbdata *mbp, struct mbuf *m) { bzero(mbp, sizeof (*mbp)); mbp->mb_top = mbp->mb_cur = m; mbp->mb_pos = mtod(m, char *); - return (0); } -int +void mb_done(struct mbdata *mbp) { if (mbp->mb_top) { m_freem(mbp->mb_top); mbp->mb_top = NULL; } - return (0); } int -m_getm(struct mbuf *top, size_t len, struct mbuf **mpp) +m_getm(struct mbuf *top, int len, struct mbuf **mpp) { struct mbuf *m, *mp; int error, ts; @@ -190,13 +207,24 @@ out: * Routines to put data in a buffer */ +void * +mb_reserve(mbchain_t *mbp, int size) +{ + char *p; + + if (mb_fit(mbp, size, &p) != 0) + return (NULL); + + return (p); +} + /* * Check if object of size 'size' fit to the current position and * allocate new mbuf if not. Advance pointers and increase length of mbuf(s). * Return pointer to the object placeholder or NULL if any error occured. */ int -mb_fit(struct mbdata *mbp, size_t size, char **pp) +mb_fit(mbchain_t *mbp, int size, char **pp) { struct mbuf *m, *mn; int error; @@ -217,56 +245,57 @@ mb_fit(struct mbdata *mbp, size_t size, char **pp) } int -mb_put_uint8(struct mbdata *mbp, uint8_t x) +mb_put_uint8(mbchain_t *mbp, uint8_t x) { uint8_t y = x; - return (mb_put_mem(mbp, &y, sizeof (y))); + return (mb_put_mem(mbp, &y, sizeof (y), MB_MINLINE)); } int -mb_put_uint16be(struct mbdata *mbp, uint16_t x) +mb_put_uint16be(mbchain_t *mbp, uint16_t x) { uint16_t y = htobes(x); - return (mb_put_mem(mbp, &y, sizeof (y))); + return (mb_put_mem(mbp, &y, sizeof (y), MB_MINLINE)); } int -mb_put_uint16le(struct mbdata *mbp, uint16_t x) +mb_put_uint16le(mbchain_t *mbp, uint16_t x) { uint16_t y = htoles(x); - return (mb_put_mem(mbp, &y, sizeof (y))); + return (mb_put_mem(mbp, &y, sizeof (y), MB_MINLINE)); } int -mb_put_uint32be(struct mbdata *mbp, uint32_t x) +mb_put_uint32be(mbchain_t *mbp, uint32_t x) { uint32_t y = htobel(x); - return (mb_put_mem(mbp, &y, sizeof (y))); + return (mb_put_mem(mbp, &y, sizeof (y), MB_MINLINE)); } int -mb_put_uint32le(struct mbdata *mbp, uint32_t x) +mb_put_uint32le(mbchain_t *mbp, uint32_t x) { uint32_t y = htolel(x); - return (mb_put_mem(mbp, &y, sizeof (y))); + return (mb_put_mem(mbp, &y, sizeof (y), MB_MINLINE)); } int -mb_put_uint64be(struct mbdata *mbp, uint64_t x) +mb_put_uint64be(mbchain_t *mbp, uint64_t x) { uint64_t y = htobeq(x); - return (mb_put_mem(mbp, &y, sizeof (y))); + return (mb_put_mem(mbp, &y, sizeof (y), MB_MINLINE)); } int -mb_put_uint64le(struct mbdata *mbp, uint64_t x) +mb_put_uint64le(mbchain_t *mbp, uint64_t x) { uint64_t y = htoleq(x); - return (mb_put_mem(mbp, &y, sizeof (y))); + return (mb_put_mem(mbp, &y, sizeof (y), MB_MINLINE)); } +/* ARGSUSED */ int -mb_put_mem(struct mbdata *mbp, const void *vmem, size_t size) +mb_put_mem(mbchain_t *mbp, const void *vmem, int size, int type) { struct mbuf *m; const char *src; @@ -311,14 +340,14 @@ mb_put_mem(struct mbdata *mbp, const void *vmem, size_t size) * This always consumes the passed mbuf. */ int -mb_put_mbuf(struct mbdata *mbp, struct mbuf *m) +mb_put_mbuf(mbchain_t *mbp, struct mbuf *m) { struct mbuf *cm = mbp->mb_cur; int ts = M_TRAILINGSPACE(cm); if (m->m_next == NULL && m->m_len <= ts) { /* just copy */ - mb_put_mem(mbp, m->m_data, m->m_len); + mb_put_mem(mbp, m->m_data, m->m_len, MB_MSYSTEM); m_freem(m); return (0); } @@ -340,7 +369,7 @@ mb_put_mbuf(struct mbdata *mbp, struct mbuf *m) * null terminated, and aligned if necessary. */ int -mb_put_dstring(struct mbdata *mbp, const char *s, int uc) +mb_put_string(mbchain_t *mbp, const char *s, int uc) { int err; @@ -361,7 +390,7 @@ mb_put_dstring(struct mbdata *mbp, const char *s, int uc) * Put an ASCII string (really OEM), given a UTF-8 string. */ int -mb_put_astring(struct mbdata *mbp, const char *s) +mb_put_astring(mbchain_t *mbp, const char *s) { char *abuf; int err, len; @@ -370,7 +399,7 @@ mb_put_astring(struct mbdata *mbp, const char *s) if (abuf == NULL) return (ENOMEM); len = strlen(abuf) + 1; - err = mb_put_mem(mbp, abuf, len); + err = mb_put_mem(mbp, abuf, len, MB_MSYSTEM); free(abuf); return (err); } @@ -379,7 +408,7 @@ mb_put_astring(struct mbdata *mbp, const char *s) * Put UCS-2LE, given a UTF-8 string. */ int -mb_put_ustring(struct mbdata *mbp, const char *s) +mb_put_ustring(mbchain_t *mbp, const char *s) { uint16_t *ubuf; int err, len; @@ -387,8 +416,8 @@ mb_put_ustring(struct mbdata *mbp, const char *s) ubuf = convert_utf8_to_leunicode(s); if (ubuf == NULL) return (ENOMEM); - len = unicode_strlen(ubuf) + 1; - err = mb_put_mem(mbp, ubuf, (len << 1)); + len = 2 * (unicode_strlen(ubuf) + 1); + err = mb_put_mem(mbp, ubuf, len, MB_MSYSTEM); free(ubuf); return (err); } @@ -399,24 +428,18 @@ mb_put_ustring(struct mbdata *mbp, const char *s) #define mb_left(m, p) (mtod(m, char *) + (m)->m_len - (p)) int -mb_get_uint8(struct mbdata *mbp, uint8_t *x) -{ - return (mb_get_mem(mbp, x, 1)); -} - -int -mb_get_uint16(struct mbdata *mbp, uint16_t *x) +md_get_uint8(mdchain_t *mbp, uint8_t *x) { - return (mb_get_mem(mbp, x, 2)); + return (md_get_mem(mbp, x, 1, MB_MINLINE)); } int -mb_get_uint16le(struct mbdata *mbp, uint16_t *x) +md_get_uint16le(mdchain_t *mbp, uint16_t *x) { uint16_t v; int err; - if ((err = mb_get_mem(mbp, &v, 2)) != 0) + if ((err = md_get_mem(mbp, &v, sizeof (v), MB_MINLINE)) != 0) return (err); if (x != NULL) *x = letohs(v); @@ -424,11 +447,11 @@ mb_get_uint16le(struct mbdata *mbp, uint16_t *x) } int -mb_get_uint16be(struct mbdata *mbp, uint16_t *x) { +md_get_uint16be(mdchain_t *mbp, uint16_t *x) { uint16_t v; int err; - if ((err = mb_get_mem(mbp, &v, 2)) != 0) + if ((err = md_get_mem(mbp, &v, sizeof (v), MB_MINLINE)) != 0) return (err); if (x != NULL) *x = betohs(v); @@ -436,18 +459,12 @@ mb_get_uint16be(struct mbdata *mbp, uint16_t *x) { } int -mb_get_uint32(struct mbdata *mbp, uint32_t *x) -{ - return (mb_get_mem(mbp, x, 4)); -} - -int -mb_get_uint32be(struct mbdata *mbp, uint32_t *x) +md_get_uint32be(mdchain_t *mbp, uint32_t *x) { uint32_t v; int err; - if ((err = mb_get_mem(mbp, &v, 4)) != 0) + if ((err = md_get_mem(mbp, &v, sizeof (v), MB_MINLINE)) != 0) return (err); if (x != NULL) *x = betohl(v); @@ -455,12 +472,12 @@ mb_get_uint32be(struct mbdata *mbp, uint32_t *x) } int -mb_get_uint32le(struct mbdata *mbp, uint32_t *x) +md_get_uint32le(mdchain_t *mbp, uint32_t *x) { uint32_t v; int err; - if ((err = mb_get_mem(mbp, &v, 4)) != 0) + if ((err = md_get_mem(mbp, &v, sizeof (v), MB_MINLINE)) != 0) return (err); if (x != NULL) *x = letohl(v); @@ -468,18 +485,12 @@ mb_get_uint32le(struct mbdata *mbp, uint32_t *x) } int -mb_get_uint64(struct mbdata *mbp, uint64_t *x) -{ - return (mb_get_mem(mbp, x, 8)); -} - -int -mb_get_uint64be(struct mbdata *mbp, uint64_t *x) +md_get_uint64be(mdchain_t *mbp, uint64_t *x) { uint64_t v; int err; - if ((err = mb_get_mem(mbp, &v, 8)) != 0) + if ((err = md_get_mem(mbp, &v, sizeof (v), MB_MINLINE)) != 0) return (err); if (x != NULL) *x = betohq(v); @@ -487,20 +498,21 @@ mb_get_uint64be(struct mbdata *mbp, uint64_t *x) } int -mb_get_uint64le(struct mbdata *mbp, uint64_t *x) +md_get_uint64le(mdchain_t *mbp, uint64_t *x) { uint64_t v; int err; - if ((err = mb_get_mem(mbp, &v, 8)) != 0) + if ((err = md_get_mem(mbp, &v, sizeof (v), MB_MINLINE)) != 0) return (err); if (x != NULL) *x = letohq(v); return (0); } +/* ARGSUSED */ int -mb_get_mem(struct mbdata *mbp, void *vmem, size_t size) +md_get_mem(mdchain_t *mbp, void *vmem, int size, int type) { struct mbuf *m = mbp->mb_cur; char *dst = vmem; @@ -539,7 +551,7 @@ mb_get_mem(struct mbdata *mbp, void *vmem, size_t size) * Nothing fancy here - just copy. */ int -mb_get_mbuf(struct mbdata *mbp, int size, struct mbuf **ret) +md_get_mbuf(mdchain_t *mbp, int size, mbuf_t **ret) { mbuf_t *m; int err; @@ -548,7 +560,7 @@ mb_get_mbuf(struct mbdata *mbp, int size, struct mbuf **ret) if (err) return (err); - err = mb_get_mem(mbp, m->m_data, size); + err = md_get_mem(mbp, m->m_data, size, MB_MSYSTEM); if (err) { m_freem(m); return (err); @@ -564,26 +576,27 @@ mb_get_mbuf(struct mbdata *mbp, int size, struct mbuf **ret) * either Unicode or OEM chars. */ int -mb_get_string(struct mbdata *mbp, char **str_pp, int uc) +md_get_string(mdchain_t *mbp, char **str_pp, int uc) { int err; if (uc) - err = mb_get_ustring(mbp, str_pp); + err = md_get_ustring(mbp, str_pp); else - err = mb_get_astring(mbp, str_pp); + err = md_get_astring(mbp, str_pp); return (err); } /* * Get an ASCII (really OEM) string from the mbuf chain * and convert it to UTF-8 - * Similar to mb_get_ustring below. + * + * Similar to md_get_ustring below. */ int -mb_get_astring(struct mbdata *real_mbp, char **str_pp) +md_get_astring(mdchain_t *real_mbp, char **str_pp) { - struct mbdata tmp_mb, *mbp; + mdchain_t tmp_mb, *mbp; char *tstr, *ostr; int err, i, slen; uint8_t ch; @@ -598,7 +611,7 @@ mb_get_astring(struct mbdata *real_mbp, char **str_pp) mbp = &tmp_mb; slen = 0; for (;;) { - err = mb_get_uint8(mbp, &ch); + err = md_get_uint8(mbp, &ch); if (err) break; if (ch == 0) @@ -615,11 +628,11 @@ mb_get_astring(struct mbdata *real_mbp, char **str_pp) return (ENOMEM); mbp = real_mbp; for (i = 0; i < slen; i++) { - mb_get_uint8(mbp, &ch); + md_get_uint8(mbp, &ch); tstr[i] = ch; } tstr[i] = 0; - mb_get_uint8(mbp, NULL); + md_get_uint8(mbp, NULL); /* * Convert OEM to UTF-8 @@ -637,12 +650,12 @@ mb_get_astring(struct mbdata *real_mbp, char **str_pp) * Get a UCS-2LE string from the mbuf chain, and * convert it to UTF-8. * - * Similar to mb_get_astring below. + * Similar to md_get_astring above. */ int -mb_get_ustring(struct mbdata *real_mbp, char **str_pp) +md_get_ustring(mdchain_t *real_mbp, char **str_pp) { - struct mbdata tmp_mb, *mbp; + mdchain_t tmp_mb, *mbp; uint16_t *tstr; char *ostr; int err, i, slen; @@ -652,7 +665,7 @@ mb_get_ustring(struct mbdata *real_mbp, char **str_pp) * First, align(2) on the real_mbp */ if (((uintptr_t)real_mbp->mb_pos) & 1) - mb_get_uint8(real_mbp, NULL); + md_get_uint8(real_mbp, NULL); /* * Next, figure out the string length. @@ -664,7 +677,7 @@ mb_get_ustring(struct mbdata *real_mbp, char **str_pp) mbp = &tmp_mb; slen = 0; for (;;) { - err = mb_get_uint16le(mbp, &ch); + err = md_get_uint16le(mbp, &ch); if (err) break; if (ch == 0) @@ -682,11 +695,11 @@ mb_get_ustring(struct mbdata *real_mbp, char **str_pp) return (ENOMEM); mbp = real_mbp; for (i = 0; i < slen; i++) { - mb_get_uint16le(mbp, &ch); + md_get_uint16le(mbp, &ch); tstr[i] = ch; } tstr[i] = 0; - mb_get_uint16le(mbp, NULL); + md_get_uint16le(mbp, NULL); /* * Convert UCS-2 (native!) to UTF-8 diff --git a/usr/src/lib/libsmbfs/smb/nb_name.c b/usr/src/lib/libsmbfs/smb/nb_name.c index 604d9142cd..812900aca9 100644 --- a/usr/src/lib/libsmbfs/smb/nb_name.c +++ b/usr/src/lib/libsmbfs/smb/nb_name.c @@ -206,7 +206,7 @@ nb_name_encode(struct mbdata *mbp, struct nb_name *nn) return (0); } - mb_fit(mbp, 1, &plen); + (void) mb_fit(mbp, 1, &plen); *plen = 0; /* will update below */ lblen = 0; for (p = nn->nn_scope; ; p++) { @@ -218,7 +218,7 @@ nb_name_encode(struct mbdata *mbp, struct nb_name *nn) } if (*p == '.') { *plen = lblen; - mb_fit(mbp, 1, &plen); + (void) mb_fit(mbp, 1, &plen); *plen = 0; lblen = 0; } else { diff --git a/usr/src/lib/libsmbfs/smb/nb_ssn.c b/usr/src/lib/libsmbfs/smb/nb_ssn.c index bd53ce6fce..44d5a48120 100644 --- a/usr/src/lib/libsmbfs/smb/nb_ssn.c +++ b/usr/src/lib/libsmbfs/smb/nb_ssn.c @@ -178,7 +178,7 @@ nb_ssn_recv(struct smb_ctx *ctx, struct mbdata *mb, /* * Get a message buffer, read the payload */ - if ((err = mb_init(mb, *mlen)) != 0) + if ((err = mb_init_sz(mb, *mlen)) != 0) return (err); buf = mb->mb_top->m_data; len = *mlen; @@ -274,7 +274,7 @@ nb_ssn_request(struct smb_ctx *ctx, char *srvname) bzero(&req, sizeof (req)); bzero(&res, sizeof (res)); - if ((err = mb_init(&req, M_MINSIZE)) != 0) + if ((err = mb_init(&req)) != 0) goto errout; ucwks = utf8_str_toupper(ctx->ct_locname); diff --git a/usr/src/lib/libsmbfs/smb/nbns_rq.c b/usr/src/lib/libsmbfs/smb/nbns_rq.c index d0e85209e7..7dc46f3983 100644 --- a/usr/src/lib/libsmbfs/smb/nbns_rq.c +++ b/usr/src/lib/libsmbfs/smb/nbns_rq.c @@ -373,7 +373,7 @@ nbns_rq_create(int opcode, struct nb_ctx *ctx, struct nbns_rq **rqpp) if (rqp == NULL) return (ENOMEM); bzero(rqp, sizeof (*rqp)); - error = mb_init(&rqp->nr_rq, NBDG_MAXSIZE); + error = mb_init_sz(&rqp->nr_rq, NBDG_MAXSIZE); if (error) { free(rqp); return (error); @@ -416,15 +416,15 @@ nbns_rq_getrr(struct nbns_rq *rqp, struct nbns_rr *rrp) if (len < 1) return (NBERROR(NBERR_INVALIDRESPONSE)); rrp->rr_name = cp; - error = mb_get_mem(mbp, NULL, len); + error = md_get_mem(mbp, NULL, len, MB_MSYSTEM); if (error) return (error); - mb_get_uint16be(mbp, &rrp->rr_type); - mb_get_uint16be(mbp, &rrp->rr_class); - mb_get_uint32be(mbp, &rrp->rr_ttl); - mb_get_uint16be(mbp, &rrp->rr_rdlength); + md_get_uint16be(mbp, &rrp->rr_type); + md_get_uint16be(mbp, &rrp->rr_class); + md_get_uint32be(mbp, &rrp->rr_ttl); + md_get_uint16be(mbp, &rrp->rr_rdlength); rrp->rr_data = (uchar_t *)mbp->mb_pos; - error = mb_get_mem(mbp, NULL, rrp->rr_rdlength); + error = md_get_mem(mbp, NULL, rrp->rr_rdlength, MB_MSYSTEM); return (error); } @@ -436,11 +436,7 @@ nbns_rq_prepare(struct nbns_rq *rqp) uint16_t ofr; /* opcode, flags, rcode */ int error; - /* - * Replacing with one argument. - * error = mb_init(&rqp->nr_rp, NBDG_MAXSIZE); - */ - error = mb_init(&rqp->nr_rp, NBDG_MAXSIZE); + error = mb_init_sz(&rqp->nr_rp, NBDG_MAXSIZE); if (error) return (error); @@ -455,15 +451,19 @@ nbns_rq_prepare(struct nbns_rq *rqp) mb_put_uint16be(mbp, rqp->nr_qdcount); mb_put_uint16be(mbp, rqp->nr_ancount); mb_put_uint16be(mbp, rqp->nr_nscount); - mb_put_uint16be(mbp, rqp->nr_arcount); + error = mb_put_uint16be(mbp, rqp->nr_arcount); if (rqp->nr_qdcount) { if (rqp->nr_qdcount > 1) return (EINVAL); - nb_name_encode(mbp, rqp->nr_qdname); + (void) nb_name_encode(mbp, rqp->nr_qdname); mb_put_uint16be(mbp, rqp->nr_qdtype); - mb_put_uint16be(mbp, rqp->nr_qdclass); + error = mb_put_uint16be(mbp, rqp->nr_qdclass); } - m_lineup(mbp->mb_top, &mbp->mb_top); + if (error) + return (error); + error = m_lineup(mbp->mb_top, &mbp->mb_top); + if (error) + return (error); if (ctx->nb_timo == 0) ctx->nb_timo = 1; /* by default 1 second */ return (0); @@ -652,7 +652,7 @@ do_recv: mbp = &rqp->nr_rp; if (mbp->mb_count < 12) return (NBERROR(NBERR_INVALIDRESPONSE)); - mb_get_uint16be(mbp, &rpid); + md_get_uint16be(mbp, &rpid); if (rpid != rqp->nr_trnid) return (NBERROR(NBERR_INVALIDRESPONSE)); break; @@ -660,14 +660,14 @@ do_recv: if (tries == maxretry) return (NBERROR(NBERR_HOSTNOTFOUND)); - mb_get_uint16be(mbp, &ofr); + md_get_uint16be(mbp, &ofr); rqp->nr_rpnmflags = (ofr >> 4) & 0x7F; rqp->nr_rprcode = ofr & 0xf; if (rqp->nr_rprcode) return (NBERROR(rqp->nr_rprcode)); - mb_get_uint16be(mbp, &rpid); /* QDCOUNT */ - mb_get_uint16be(mbp, &rqp->nr_rpancount); - mb_get_uint16be(mbp, &rqp->nr_rpnscount); - mb_get_uint16be(mbp, &rqp->nr_rparcount); + md_get_uint16be(mbp, &rpid); /* QDCOUNT */ + md_get_uint16be(mbp, &rqp->nr_rpancount); + md_get_uint16be(mbp, &rqp->nr_rpnscount); + md_get_uint16be(mbp, &rqp->nr_rparcount); return (0); } diff --git a/usr/src/lib/libsmbfs/smb/negprot.c b/usr/src/lib/libsmbfs/smb/negprot.c index 6c1649f1bb..cd6e2866df 100644 --- a/usr/src/lib/libsmbfs/smb/negprot.c +++ b/usr/src/lib/libsmbfs/smb/negprot.c @@ -104,7 +104,7 @@ smb_negprot(struct smb_ctx *ctx, struct mbdata *oblob) struct mbdata *mbp; struct smb_dialect *dp; int err, len; - uint8_t wc, stime[8], eklen; + uint8_t wc, eklen; uint16_t dindex, bc; int will_sign = 0; @@ -188,8 +188,8 @@ smb_negprot(struct smb_ctx *ctx, struct mbdata *oblob) * section 2.2.3 */ mbp = &rqp->rq_rp; - (void) mb_get_uint8(mbp, &wc); - err = mb_get_uint16le(mbp, &dindex); + (void) md_get_uint8(mbp, &wc); + err = md_get_uint16le(mbp, &dindex); if (err || dindex > SMB_DIALECT_MAX) { DPRINT("err %d dindex %d", err, (int)dindex); goto errout; @@ -206,17 +206,17 @@ smb_negprot(struct smb_ctx *ctx, struct mbdata *oblob) DPRINT("bad wc %d", (int)wc); goto errout; } - mb_get_uint8(mbp, &sv->sv_sm); /* SecurityMode */ - mb_get_uint16le(mbp, &sv->sv_maxmux); /* MaxMpxCount */ - mb_get_uint16le(mbp, &sv->sv_maxvcs); /* MaxCountVCs */ - mb_get_uint32le(mbp, &sv->sv_maxtx); /* MaxBufferSize */ - mb_get_uint32le(mbp, &sv->sv_maxraw); /* MaxRawSize */ - mb_get_uint32le(mbp, &sv->sv_skey); /* SessionKey */ - mb_get_uint32le(mbp, &sv->sv_caps); /* Capabilities */ - mb_get_mem(mbp, (char *)stime, 8); /* SystemTime(s) */ - mb_get_uint16le(mbp, (uint16_t *)&sv->sv_tz); - mb_get_uint8(mbp, &eklen); /* EncryptionKeyLength */ - err = mb_get_uint16le(mbp, &bc); /* ByteCount */ + md_get_uint8(mbp, &sv->sv_sm); /* SecurityMode */ + md_get_uint16le(mbp, &sv->sv_maxmux); /* MaxMpxCount */ + md_get_uint16le(mbp, &sv->sv_maxvcs); /* MaxCountVCs */ + md_get_uint32le(mbp, &sv->sv_maxtx); /* MaxBufferSize */ + md_get_uint32le(mbp, &sv->sv_maxraw); /* MaxRawSize */ + md_get_uint32le(mbp, &sv->sv_skey); /* SessionKey */ + md_get_uint32le(mbp, &sv->sv_caps); /* Capabilities */ + md_get_mem(mbp, NULL, 8, MB_MSYSTEM); /* SystemTime(s) */ + md_get_uint16le(mbp, (uint16_t *)&sv->sv_tz); + md_get_uint8(mbp, &eklen); /* EncryptionKeyLength */ + err = md_get_uint16le(mbp, &bc); /* ByteCount */ if (err) goto errout; @@ -325,7 +325,7 @@ smb_negprot(struct smb_ctx *ctx, struct mbdata *oblob) /* * Skip the server GUID. */ - err = mb_get_mem(mbp, NULL, SMB_GUIDLEN); + err = md_get_mem(mbp, NULL, SMB_GUIDLEN, MB_MSYSTEM); if (err) goto errout; /* @@ -339,7 +339,7 @@ smb_negprot(struct smb_ctx *ctx, struct mbdata *oblob) /* * Get the (optional) SPNEGO "hint". */ - err = mb_get_mbuf(mbp, len, &m); + err = md_get_mbuf(mbp, len, &m); if (err) goto errout; mb_initm(oblob, m); @@ -358,7 +358,8 @@ smb_negprot(struct smb_ctx *ctx, struct mbdata *oblob) err = EBADRPC; goto errout; } - err = mb_get_mem(mbp, (char *)ctx->ct_ntlm_chal, NTLM_CHAL_SZ); + err = md_get_mem(mbp, ctx->ct_ntlm_chal, + NTLM_CHAL_SZ, MB_MSYSTEM); /* * Server domain follows (ignored) * Note: NOT aligned(2) - unusual! diff --git a/usr/src/lib/libsmbfs/smb/netshareenum.c b/usr/src/lib/libsmbfs/smb/netshareenum.c index 2ee1fd7792..bd2c24caec 100644 --- a/usr/src/lib/libsmbfs/smb/netshareenum.c +++ b/usr/src/lib/libsmbfs/smb/netshareenum.c @@ -280,9 +280,9 @@ smb_rap_NetShareEnum(struct smb_ctx *ctx, int sLevel, void *pbBuffer, error = smb_rap_create(0, "WrLeh", "B13BWz", &rap); if (error) return (error); - smb_rap_setNparam(rap, sLevel); /* W - sLevel */ - smb_rap_setPparam(rap, pbBuffer); /* r - pbBuffer */ - smb_rap_setNparam(rap, *cbBuffer); /* L - cbBuffer */ + (void) smb_rap_setNparam(rap, sLevel); /* W - sLevel */ + (void) smb_rap_setPparam(rap, pbBuffer); /* r - pbBuffer */ + (void) smb_rap_setNparam(rap, *cbBuffer); /* L - cbBuffer */ error = smb_rap_request(rap, ctx); if (error == 0) { *pcEntriesRead = rap->r_entries; diff --git a/usr/src/lib/libsmbfs/smb/ntlm.c b/usr/src/lib/libsmbfs/smb/ntlm.c index 8119e62b65..ffd9ff3d41 100644 --- a/usr/src/lib/libsmbfs/smb/ntlm.c +++ b/usr/src/lib/libsmbfs/smb/ntlm.c @@ -187,11 +187,11 @@ ntlm_put_v1_responses(struct smb_ctx *ctx, int err; /* Get mbuf chain for the LM response. */ - if ((err = mb_init(lm_mbp, NTLM_V1_RESP_SZ)) != 0) + if ((err = mb_init_sz(lm_mbp, NTLM_V1_RESP_SZ)) != 0) return (err); /* Get mbuf chain for the NT response. */ - if ((err = mb_init(nt_mbp, NTLM_V1_RESP_SZ)) != 0) + if ((err = mb_init_sz(nt_mbp, NTLM_V1_RESP_SZ)) != 0) return (err); /* @@ -199,7 +199,9 @@ ntlm_put_v1_responses(struct smb_ctx *ctx, * from the challenge and the ASCII * password (if authflags allow). */ - mb_fit(lm_mbp, NTLM_V1_RESP_SZ, (char **)&lmresp); + err = mb_fit(lm_mbp, NTLM_V1_RESP_SZ, (char **)&lmresp); + if (err) + return (err); bzero(lmresp, NTLM_V1_RESP_SZ); if (ctx->ct_authflags & SMB_AT_LM1) { /* They asked to send the LM hash too. */ @@ -213,7 +215,9 @@ ntlm_put_v1_responses(struct smb_ctx *ctx, * Compute the NTLM response, derived from * the challenge and the NT hash. */ - mb_fit(nt_mbp, NTLM_V1_RESP_SZ, (char **)&ntresp); + err = mb_fit(nt_mbp, NTLM_V1_RESP_SZ, (char **)&ntresp); + if (err) + return (err); bzero(ntresp, NTLM_V1_RESP_SZ); err = ntlm_v1_response(ntresp, ctx->ct_nthash, ctx->ct_ntlm_chal, NTLM_CHAL_SZ); @@ -408,9 +412,9 @@ ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp, uchar_t v2hash[NTLM_HASH_SZ]; struct mbuf *tim = ti_mbp->mb_top; - if ((err = mb_init(lm_mbp, M_MINSIZE)) != 0) + if ((err = mb_init(lm_mbp)) != 0) return (err); - if ((err = mb_init(nt_mbp, M_MINSIZE)) != 0) + if ((err = mb_init(nt_mbp)) != 0) return (err); /* @@ -443,13 +447,13 @@ ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp, * 2: Client nonce */ lmresp = (uchar_t *)lm_mbp->mb_pos; - mb_put_mem(lm_mbp, NULL, NTLM_HASH_SZ); + mb_put_mem(lm_mbp, NULL, NTLM_HASH_SZ, MB_MSYSTEM); err = ntlm_v2_resp_hash(lmresp, v2hash, ctx->ct_ntlm_chal, ctx->ct_clnonce, NTLM_CHAL_SZ); if (err) goto out; - mb_put_mem(lm_mbp, ctx->ct_clnonce, NTLM_CHAL_SZ); + mb_put_mem(lm_mbp, ctx->ct_clnonce, NTLM_CHAL_SZ, MB_MSYSTEM); /* * Compute the NTLMv2 response, derived @@ -461,13 +465,13 @@ ntlm_put_v2_responses(struct smb_ctx *ctx, struct mbdata *ti_mbp, * 2: "target info." blob */ ntresp = (uchar_t *)nt_mbp->mb_pos; - mb_put_mem(nt_mbp, NULL, NTLM_HASH_SZ); + mb_put_mem(nt_mbp, NULL, NTLM_HASH_SZ, MB_MSYSTEM); err = ntlm_v2_resp_hash(ntresp, v2hash, ctx->ct_ntlm_chal, (uchar_t *)tim->m_data, tim->m_len); if (err) goto out; - mb_put_mem(nt_mbp, tim->m_data, tim->m_len); + mb_put_mem(nt_mbp, tim->m_data, tim->m_len, MB_MSYSTEM); /* * Compute the session key @@ -506,7 +510,7 @@ smb_put_blob_name(struct mbdata *mbp, char *name, int type) mb_put_uint16le(mbp, type); mb_put_uint16le(mbp, nlen); - mb_put_mem(mbp, (char *)ucs, nlen); + mb_put_mem(mbp, (char *)ucs, nlen, MB_MSYSTEM); if (ucs) free(ucs); @@ -528,7 +532,7 @@ ntlm_build_target_info(struct smb_ctx *ctx, struct mbuf *names, int err; /* Get mbuf chain for the "target info". */ - if ((err = mb_init(mbp, M_MINSIZE)) != 0) + if ((err = mb_init(mbp)) != 0) return (err); /* @@ -556,7 +560,7 @@ ntlm_build_target_info(struct smb_ctx *ctx, struct mbuf *names, mb_put_uint32le(mbp, 0x101); /* Blob signature */ mb_put_uint32le(mbp, 0); /* reserved */ mb_put_uint64le(mbp, nt_time); /* NT time stamp */ - mb_put_mem(mbp, ctx->ct_clnonce, NTLM_CHAL_SZ); + mb_put_mem(mbp, ctx->ct_clnonce, NTLM_CHAL_SZ, MB_MSYSTEM); mb_put_uint32le(mbp, 0); /* unknown */ /* @@ -564,7 +568,7 @@ ntlm_build_target_info(struct smb_ctx *ctx, struct mbuf *names, * NTLMSSP Type 2 message or composed here. */ if (names) { - err = mb_put_mem(mbp, names->m_data, names->m_len); + err = mb_put_mem(mbp, names->m_data, names->m_len, MB_MSYSTEM); } else { /* Get upper-case names. */ ucdom = utf8_str_toupper(ctx->ct_domain); diff --git a/usr/src/lib/libsmbfs/smb/ntlmssp.c b/usr/src/lib/libsmbfs/smb/ntlmssp.c index 3428fbca36..535777b187 100644 --- a/usr/src/lib/libsmbfs/smb/ntlmssp.c +++ b/usr/src/lib/libsmbfs/smb/ntlmssp.c @@ -87,13 +87,13 @@ static const char ntlmssp_id[ID_SZ] = "NTLMSSP"; * Get a "security buffer" (header part) */ static int -mb_get_sb_hdr(struct mbdata *mbp, struct sec_buf *sb) +md_get_sb_hdr(struct mbdata *mbp, struct sec_buf *sb) { int err; - (void) mb_get_uint16le(mbp, &sb->sb_length); - (void) mb_get_uint16le(mbp, &sb->sb_maxlen); - err = mb_get_uint32le(mbp, &sb->sb_offset); + (void) md_get_uint16le(mbp, &sb->sb_length); + (void) md_get_uint16le(mbp, &sb->sb_maxlen); + err = md_get_uint32le(mbp, &sb->sb_offset); return (err); } @@ -103,7 +103,7 @@ mb_get_sb_hdr(struct mbdata *mbp, struct sec_buf *sb) * the data is delivered as an mbuf. */ static int -mb_get_sb_data(struct mbdata *mbp, struct sec_buf *sb, struct mbuf **mp) +md_get_sb_data(struct mbdata *mbp, struct sec_buf *sb, struct mbuf **mp) { struct mbdata tmp_mb; int err; @@ -115,12 +115,12 @@ mb_get_sb_data(struct mbdata *mbp, struct sec_buf *sb, struct mbuf **mp) mb_initm(&tmp_mb, mbp->mb_top); /* Skip data up to the offset. */ - err = mb_get_mem(&tmp_mb, NULL, sb->sb_offset); + err = md_get_mem(&tmp_mb, NULL, sb->sb_offset, MB_MSYSTEM); if (err) return (err); /* Get the data (as an mbuf). */ - err = mb_get_mbuf(&tmp_mb, sb->sb_maxlen, mp); + err = md_get_mbuf(&tmp_mb, sb->sb_maxlen, mp); return (err); } @@ -174,10 +174,10 @@ mb_put_sb_string(struct mbdata *mbp, struct sec_buf *sb, * then chop off the null terminator * before appending to caller's mbp. */ - err = mb_init(&tmp_mb, M_MINSIZE); + err = mb_init(&tmp_mb); if (err) return (err); - err = mb_put_dstring(&tmp_mb, s, unicode); + err = mb_put_string(&tmp_mb, s, unicode); if (err) return (err); @@ -218,7 +218,7 @@ ntlmssp_put_type1(struct ssp_ctx *sp, struct mbdata *out_mb) char *ucdom = NULL; char *ucwks = NULL; - if ((err = mb_init(&mb2, M_MINSIZE)) != 0) + if ((err = mb_init(&mb2)) != 0) return (err); mb2.mb_count = sizeof (hdr); @@ -269,7 +269,7 @@ ntlmssp_put_type1(struct ssp_ctx *sp, struct mbdata *out_mb) * Marshal the header (in LE order) * then concatenate the 2nd part. */ - (void) mb_put_mem(out_mb, &hdr.h_id, ID_SZ); + (void) mb_put_mem(out_mb, &hdr.h_id, ID_SZ, MB_MSYSTEM); (void) mb_put_uint32le(out_mb, hdr.h_type); (void) mb_put_uint32le(out_mb, hdr.h_flags); (void) mb_put_sb_hdr(out_mb, &hdr.h_cldom); @@ -322,15 +322,15 @@ ntlmssp_get_type2(struct ssp_ctx *sp, struct mbdata *in_mb) /* Parse the fixed size header stuff. */ bzero(&hdr, sizeof (hdr)); - (void) mb_get_mem(in_mb, &hdr.h_id, ID_SZ); - (void) mb_get_uint32le(in_mb, &hdr.h_type); + (void) md_get_mem(in_mb, &hdr.h_id, ID_SZ, MB_MSYSTEM); + (void) md_get_uint32le(in_mb, &hdr.h_type); if (hdr.h_type != 2) { err = EPROTO; goto out; } - (void) mb_get_sb_hdr(in_mb, &hdr.h_target_name); - (void) mb_get_uint32le(in_mb, &hdr.h_flags); - (void) mb_get_mem(in_mb, &hdr.h_challenge, NTLM_CHAL_SZ); + (void) md_get_sb_hdr(in_mb, &hdr.h_target_name); + (void) md_get_uint32le(in_mb, &hdr.h_flags); + (void) md_get_mem(in_mb, &hdr.h_challenge, NTLM_CHAL_SZ, MB_MSYSTEM); /* * Save flags, challenge for later. @@ -344,9 +344,9 @@ ntlmssp_get_type2(struct ssp_ctx *sp, struct mbdata *in_mb) */ if ((m_totlen(top_mb.mb_top) > sizeof (hdr)) && (hdr.h_target_name.sb_offset >= sizeof (hdr))) { - (void) mb_get_uint32le(in_mb, &hdr.h_context[0]); - (void) mb_get_uint32le(in_mb, &hdr.h_context[1]); - (void) mb_get_sb_hdr(in_mb, &hdr.h_target_info); + (void) md_get_uint32le(in_mb, &hdr.h_context[0]); + (void) md_get_uint32le(in_mb, &hdr.h_context[1]); + (void) md_get_sb_hdr(in_mb, &hdr.h_target_info); } /* @@ -354,18 +354,18 @@ ntlmssp_get_type2(struct ssp_ctx *sp, struct mbdata *in_mb) * the data from the offset/length indicated in the * security buffer header; then parse the string. */ - err = mb_get_sb_data(&top_mb, &hdr.h_target_name, &m); + err = md_get_sb_data(&top_mb, &hdr.h_target_name, &m); if (err) goto out; mb_initm(&tmp_mb, m); - err = mb_get_string(&tmp_mb, &ssp_st->ss_target_name, uc); + err = md_get_string(&tmp_mb, &ssp_st->ss_target_name, uc); mb_done(&tmp_mb); /* * Get the target info blob, if present. */ if (hdr.h_target_info.sb_offset >= sizeof (hdr)) { - err = mb_get_sb_data(&top_mb, &hdr.h_target_info, + err = md_get_sb_data(&top_mb, &hdr.h_target_info, &ssp_st->ss_target_info); } @@ -422,7 +422,7 @@ ntlmssp_put_type3(struct ssp_ctx *sp, struct mbdata *out_mb) goto out; } - if ((err = mb_init(&mb2, M_MINSIZE)) != 0) + if ((err = mb_init(&mb2)) != 0) goto out; mb2.mb_count = sizeof (hdr); uc = ssp_st->ss_flags & NTLMSSP_NEGOTIATE_UNICODE; @@ -475,7 +475,7 @@ ntlmssp_put_type3(struct ssp_ctx *sp, struct mbdata *out_mb) * Marshal the header (in LE order) * then concatenate the 2nd part. */ - (void) mb_put_mem(out_mb, &hdr.h_id, ID_SZ); + (void) mb_put_mem(out_mb, &hdr.h_id, ID_SZ, MB_MSYSTEM); (void) mb_put_uint32le(out_mb, hdr.h_type); (void) mb_put_sb_hdr(out_mb, &hdr.h_lm_resp); @@ -555,7 +555,7 @@ ntlmssp_next_token(struct ssp_ctx *sp, struct mbdata *in_mb, } /* Will build an ouptut token. */ - err = mb_init(out_mb, M_MINSIZE); + err = mb_init(out_mb); if (err) goto out; diff --git a/usr/src/lib/libsmbfs/smb/print.c b/usr/src/lib/libsmbfs/smb/print.c index 263cafaa93..268c330a0b 100644 --- a/usr/src/lib/libsmbfs/smb/print.c +++ b/usr/src/lib/libsmbfs/smb/print.c @@ -75,19 +75,19 @@ smb_printer_open(struct smb_ctx *ctx, int setuplen, int mode, smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_uint8(mbp, SMB_DT_ASCII); - mb_put_dstring(mbp, ident, uc); + mb_put_string(mbp, ident, uc); smb_rq_bend(rqp); error = smb_rq_simple(rqp); if (error) goto out; mbp = smb_rq_getreply(rqp); - error = mb_get_uint8(mbp, &wc); + error = md_get_uint8(mbp, &wc); if (error || wc < 1) { error = EBADRPC; goto out; } - mb_get_uint16(mbp, &fh); + md_get_uint16le(mbp, &fh); *fhp = fh; error = 0; diff --git a/usr/src/lib/libsmbfs/smb/private.h b/usr/src/lib/libsmbfs/smb/private.h index b95ec1f7f4..e6124f2e57 100644 --- a/usr/src/lib/libsmbfs/smb/private.h +++ b/usr/src/lib/libsmbfs/smb/private.h @@ -47,6 +47,7 @@ #include <sys/byteorder.h> #include <sys/ccompile.h> +#include <netsmb/mchain.h> #include <netsmb/netbios.h> extern void dprint(const char *, const char *, ...) @@ -71,39 +72,6 @@ extern void dprint(const char *, const char *, ...) #define SMBV_EXT_SEC 0x0080 /* conn to use extended security */ #define SMBV_WILL_SIGN 0x0100 /* negotiated signing */ - -/* - * BSD-style mbuf simulation - */ -struct mbuf { - int m_len; - int m_maxlen; - char *m_data; - struct mbuf *m_next; -}; -typedef struct mbuf mbuf_t; - -struct mbdata { - struct mbuf *mb_top; - struct mbuf *mb_cur; - char *mb_pos; - int mb_count; -}; -typedef struct mbdata mbdata_t; - -/* - * Note: Leaving a little space (8 bytes) between the - * mbuf header and the start of the data so we can - * prepend a NetBIOS header in that space. - */ -#define M_ALIGNFACTOR (sizeof (long)) -#define M_ALIGN(len) (((len) + M_ALIGNFACTOR - 1) & ~(M_ALIGNFACTOR - 1)) -#define M_BASESIZE (sizeof (struct mbuf) + 8) -#define M_MINSIZE (1024 - M_BASESIZE) -#define M_TOP(m) ((char *)(m) + M_BASESIZE) -#define M_TRAILINGSPACE(m) ((m)->m_maxlen - (m)->m_len) -#define mtod(m, t) ((t)(m)->m_data) - /* * request handling structures */ @@ -140,52 +108,26 @@ void smb_rq_wend(struct smb_rq *); int smb_rq_simple(struct smb_rq *); int smb_rq_dmem(struct mbdata *, const char *, size_t); int smb_rq_internal(struct smb_ctx *, struct smb_rq *); -int smb_rq_sign(struct smb_rq *); +void smb_rq_sign(struct smb_rq *); int smb_rq_verify(struct smb_rq *); - /* - * Message compose/parse + * This library extends the mchain.h function set a little. */ - -void m_freem(struct mbuf *); -int m_getm(struct mbuf *, size_t, struct mbuf **); +int m_getm(struct mbuf *, int, struct mbuf **); int m_lineup(struct mbuf *, struct mbuf **); size_t m_totlen(struct mbuf *); -int mb_init(struct mbdata *, size_t); -int mb_initm(struct mbdata *, struct mbuf *); -int mb_done(struct mbdata *); -int mb_fit(struct mbdata *mbp, size_t size, char **pp); -int mb_put_uint8(struct mbdata *, uint8_t); -int mb_put_uint16be(struct mbdata *, uint16_t); -int mb_put_uint16le(struct mbdata *, uint16_t); -int mb_put_uint32be(struct mbdata *, uint32_t); -int mb_put_uint32le(struct mbdata *, uint32_t); -int mb_put_uint64be(struct mbdata *, uint64_t); -int mb_put_uint64le(struct mbdata *, uint64_t); -int mb_put_mem(struct mbdata *, const void *, size_t); -int mb_put_mbuf(struct mbdata *, struct mbuf *); +int mb_init_sz(struct mbdata *, int); +int mb_fit(struct mbdata *mbp, int size, char **pp); + +int mb_put_string(struct mbdata *mbp, const char *s, int); int mb_put_astring(struct mbdata *mbp, const char *s); -int mb_put_dstring(struct mbdata *mbp, const char *s, int); int mb_put_ustring(struct mbdata *mbp, const char *s); -int mb_get_uint8(struct mbdata *, uint8_t *); -int mb_get_uint16(struct mbdata *, uint16_t *); -int mb_get_uint16le(struct mbdata *, uint16_t *); -int mb_get_uint16be(struct mbdata *, uint16_t *); -int mb_get_uint32(struct mbdata *, uint32_t *); -int mb_get_uint32be(struct mbdata *, uint32_t *); -int mb_get_uint32le(struct mbdata *, uint32_t *); -int mb_get_uint64(struct mbdata *, uint64_t *); -int mb_get_uint64be(struct mbdata *, uint64_t *); -int mb_get_uint64le(struct mbdata *, uint64_t *); -int mb_get_mem(struct mbdata *, void *, size_t); -int mb_get_mbuf(struct mbdata *, int, struct mbuf **); -int mb_get_string(struct mbdata *, char **, int); -int mb_get_astring(struct mbdata *, char **); -int mb_get_ustring(struct mbdata *, char **); - +int md_get_string(struct mbdata *, char **, int); +int md_get_astring(struct mbdata *, char **); +int md_get_ustring(struct mbdata *, char **); /* * Network stuff (NetBIOS and otherwise) diff --git a/usr/src/lib/libsmbfs/smb/rap.c b/usr/src/lib/libsmbfs/smb/rap.c index 8260e2639c..98f35af5ff 100644 --- a/usr/src/lib/libsmbfs/smb/rap.c +++ b/usr/src/lib/libsmbfs/smb/rap.c @@ -222,9 +222,11 @@ smb_rap_create(int fn, const char *param, const char *data, len += plen; } rap->r_pbuf = rap->r_npbuf = malloc(len); - smb_rap_rqparam(rap, 'W', 1, fn); - smb_rap_rqparam_z(rap, rap->r_sparam); - smb_rap_rqparam_z(rap, rap->r_sdata); + if (rap->r_pbuf == NULL) + return (ENOMEM); + (void) smb_rap_rqparam(rap, 'W', 1, fn); + (void) smb_rap_rqparam_z(rap, rap->r_sparam); + (void) smb_rap_rqparam_z(rap, rap->r_sdata); *rapp = rap; return (0); } diff --git a/usr/src/lib/libsmbfs/smb/rq.c b/usr/src/lib/libsmbfs/smb/rq.c index 7b21708428..6045237393 100644 --- a/usr/src/lib/libsmbfs/smb/rq.c +++ b/usr/src/lib/libsmbfs/smb/rq.c @@ -51,6 +51,8 @@ #include <netsmb/smb_lib.h> #include "private.h" +#define MIN_REPLY_SIZE 4096 + static uint32_t smb_map_doserr(uint8_t, uint16_t); /* @@ -85,11 +87,11 @@ smb_rq_init(struct smb_ctx *ctx, uchar_t cmd, struct smb_rq **rqpp) * Setup the request buffer. * Do the reply buffer later. */ - if (mb_init(&rqp->rq_rq, M_MINSIZE)) + if (mb_init(&rqp->rq_rq)) goto errout; /* Space for the SMB header. (filled in later) */ - mb_put_mem(&rqp->rq_rq, NULL, SMB_HDRLEN); + mb_put_mem(&rqp->rq_rq, NULL, SMB_HDRLEN, MB_MSYSTEM); /* * Copy the ctx flags here, so the caller can @@ -130,7 +132,7 @@ smb_rq_wstart(struct smb_rq *rqp) { struct mbdata *mbp = &rqp->rq_rq; - mb_fit(mbp, 1, &rqp->rq_wcntp); + (void) mb_fit(mbp, 1, &rqp->rq_wcntp); rqp->rq_wcbase = mbp->mb_count; } @@ -176,7 +178,7 @@ smb_rq_bstart(struct smb_rq *rqp) { struct mbdata *mbp = &rqp->rq_rq; - mb_fit(mbp, 2, &rqp->rq_bcntp); + (void) mb_fit(mbp, 2, &rqp->rq_bcntp); rqp->rq_bcbase = mbp->mb_count; } @@ -209,19 +211,16 @@ smb_rq_bend(struct smb_rq *rqp) rqp->rq_bcntp[1] = (bcnt >> 8); } -/* - * Removed: smb_rq_dmem - * which was mostly like: mb_put_mem - */ - int smb_rq_simple(struct smb_rq *rqp) { struct smbioc_rq krq; struct mbdata *mbp; + mbuf_t *m; char *data; uint32_t len; size_t rpbufsz; + int error; bzero(&krq, sizeof (krq)); krq.ioc_cmd = rqp->rq_cmd; @@ -231,7 +230,10 @@ smb_rq_simple(struct smb_rq *rqp) * and fill in the ioctl request. */ mbp = smb_rq_getrequest(rqp); - m_lineup(mbp->mb_top, &mbp->mb_top); + error = m_lineup(mbp->mb_top, &mbp->mb_top); + if (error) + return (error); + data = mtod(mbp->mb_top, char *); len = m_totlen(mbp->mb_top); @@ -246,20 +248,19 @@ smb_rq_simple(struct smb_rq *rqp) krq.ioc_tbuf = data + SMB_HDRLEN; /* - * Setup a buffer to hold the reply. - * - * Default size is M_MINSIZE, but the - * caller may increase rq_rpbufsz - * before calling this. + * Setup a buffer to hold the reply, + * at least MIN_REPLY_SIZE, or larger + * if the caller increased rq_rpbufsz. */ mbp = smb_rq_getreply(rqp); rpbufsz = rqp->rq_rpbufsz; - if (rpbufsz < M_MINSIZE) - rpbufsz = M_MINSIZE; - if (mb_init(mbp, rpbufsz)) - return (ENOMEM); + if (rpbufsz < MIN_REPLY_SIZE) + rpbufsz = MIN_REPLY_SIZE; + if ((error = m_get(rpbufsz, &m)) != 0) + return (error); + mb_initm(mbp, m); krq.ioc_rbufsz = rpbufsz; - krq.ioc_rbuf = mtod(mbp->mb_top, char *); + krq.ioc_rbuf = mtod(m, char *); /* * Call the driver @@ -271,7 +272,7 @@ smb_rq_simple(struct smb_rq *rqp) * Initialize returned mbdata. * SMB header already parsed. */ - mbp->mb_top->m_len = krq.ioc_rbufsz; + m->m_len = krq.ioc_rbufsz; return (0); } @@ -360,14 +361,13 @@ smb_rq_internal(struct smb_ctx *ctx, struct smb_rq *rqp) /* * rewind done; fill it in */ - mb_put_mem(mbp, (char *)SMB_SIGNATURE, SMB_SIGLEN); + mb_put_mem(mbp, ffsmb, SMB_SIGLEN, MB_MSYSTEM); mb_put_uint8(mbp, rqp->rq_cmd); - mb_put_mem(mbp, NULL, 4); /* status */ + mb_put_uint32le(mbp, 0); /* status */ mb_put_uint8(mbp, rqp->rq_hflags); mb_put_uint16le(mbp, rqp->rq_hflags2); - mb_put_uint16le(mbp, 0); /* pid_hi */ - mb_put_mem(mbp, NULL, 8); /* signature */ - mb_put_uint16le(mbp, 0); /* reserved */ + /* pid_hi(2), signature(8), reserved(2) */ + mb_put_mem(mbp, NULL, 12, MB_MZERO); mb_put_uint16le(mbp, rqp->rq_tid); mb_put_uint16le(mbp, 0); /* pid_lo */ mb_put_uint16le(mbp, rqp->rq_uid); @@ -416,22 +416,21 @@ smb_rq_internal(struct smb_ctx *ctx, struct smb_rq *rqp) /* * Decode the SMB header. */ - mb_get_mem(mbp, (char *)sigbuf, 4); + md_get_mem(mbp, (char *)sigbuf, 4, MB_MSYSTEM); if (0 != bcmp(sigbuf, ffsmb, 4)) { DPRINT("not SMB"); return (EBADRPC); } - mb_get_uint8(mbp, &ctmp); /* SMB cmd */ - mb_get_uint32le(mbp, &rqp->rq_status); - mb_get_uint8(mbp, &rqp->rq_hflags); - mb_get_uint16le(mbp, &rqp->rq_hflags2); - mb_get_uint16le(mbp, NULL); /* pid_hi */ - mb_get_mem(mbp, NULL, 8); /* signature */ - mb_get_uint16le(mbp, NULL); /* reserved */ - mb_get_uint16le(mbp, &rqp->rq_tid); - mb_get_uint16le(mbp, NULL); /* pid_lo */ - mb_get_uint16le(mbp, &rqp->rq_uid); - mb_get_uint16le(mbp, &rqp->rq_mid); + md_get_uint8(mbp, &ctmp); /* SMB cmd */ + md_get_uint32le(mbp, &rqp->rq_status); + md_get_uint8(mbp, &rqp->rq_hflags); + md_get_uint16le(mbp, &rqp->rq_hflags2); + /* pid_hi(2), signature(8), reserved(2) */ + md_get_mem(mbp, NULL, 12, MB_MSYSTEM); + md_get_uint16le(mbp, &rqp->rq_tid); + md_get_uint16le(mbp, NULL); /* pid_lo */ + md_get_uint16le(mbp, &rqp->rq_uid); + md_get_uint16le(mbp, &rqp->rq_mid); /* * Figure out the status return. diff --git a/usr/src/lib/libsmbfs/smb/signing.c b/usr/src/lib/libsmbfs/smb/signing.c index ef9a32e2e0..0e9c826bbd 100644 --- a/usr/src/lib/libsmbfs/smb/signing.c +++ b/usr/src/lib/libsmbfs/smb/signing.c @@ -142,7 +142,7 @@ smb_compute_MAC(struct smb_ctx *ctx, mbuf_t *m, /* * Sign a request with HMAC-MD5. */ -int +void smb_rq_sign(struct smb_rq *rqp) { struct smb_ctx *ctx = rqp->rq_ctx; @@ -155,7 +155,7 @@ smb_rq_sign(struct smb_rq *rqp) * but just in case... */ if (m->m_len < SMB_HDRLEN) - return (EIO); + return; sigloc = (uchar_t *)m->m_data + SMBSIGOFF; if (ctx->ct_mackey == NULL) { @@ -165,7 +165,7 @@ smb_rq_sign(struct smb_rq *rqp) * This happens with SPNEGO, NTLMSSP, ... */ bcopy("BSRSPLY", sigloc, 8); - return (0); + return; } /* @@ -178,9 +178,7 @@ smb_rq_sign(struct smb_rq *rqp) if (err) { DPRINT("compute MAC, err %d", err); bzero(sigloc, SMBSIGLEN); - return (ENOTSUP); } - return (0); } /* @@ -247,10 +245,10 @@ smb_rq_verify(struct smb_rq *rqp) * of the sequence # has gotten a bit out of sync. */ for (fudge = 1; fudge <= nsmb_signing_fudge; fudge++) { - smb_compute_MAC(ctx, m, rseqno + fudge, sigbuf); + (void) smb_compute_MAC(ctx, m, rseqno + fudge, sigbuf); if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0) break; - smb_compute_MAC(ctx, m, rseqno - fudge, sigbuf); + (void) smb_compute_MAC(ctx, m, rseqno - fudge, sigbuf); if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0) { fudge = -fudge; break; diff --git a/usr/src/lib/libsmbfs/smb/ssnsetup.c b/usr/src/lib/libsmbfs/smb/ssnsetup.c index e4b5ec4f20..712a71f34c 100644 --- a/usr/src/lib/libsmbfs/smb/ssnsetup.c +++ b/usr/src/lib/libsmbfs/smb/ssnsetup.c @@ -405,11 +405,11 @@ smb__ssnsetup(struct smb_ctx *ctx, mb_put_mbuf(mbp, mbc2->mb_top); /* NT password */ mbc2->mb_top = NULL; /* consumed */ } - mb_put_dstring(mbp, ctx->ct_user, uc); - mb_put_dstring(mbp, ctx->ct_domain, uc); + mb_put_string(mbp, ctx->ct_user, uc); + mb_put_string(mbp, ctx->ct_domain, uc); } - mb_put_dstring(mbp, NativeOS, uc); - mb_put_dstring(mbp, LanMan, uc); + mb_put_string(mbp, NativeOS, uc); + mb_put_string(mbp, LanMan, uc); smb_rq_bend(rqp); err = smb_rq_internal(ctx, rqp); @@ -436,7 +436,7 @@ smb__ssnsetup(struct smb_ctx *ctx, is->is_smbuid = rqp->rq_uid; mbp = &rqp->rq_rp; - err = mb_get_uint8(mbp, &wc); + err = md_get_uint8(mbp, &wc); if (err) goto out; @@ -444,18 +444,18 @@ smb__ssnsetup(struct smb_ctx *ctx, if (caps & SMB_CAP_EXT_SECURITY) { if (wc != 4) goto out; - mb_get_uint16le(mbp, NULL); /* secondary cmd */ - mb_get_uint16le(mbp, NULL); /* andxoffset */ - mb_get_uint16le(mbp, actionp); /* action */ - mb_get_uint16le(mbp, &sblen); /* sec. blob len */ - mb_get_uint16le(mbp, &bc); /* byte count */ + md_get_uint16le(mbp, NULL); /* secondary cmd */ + md_get_uint16le(mbp, NULL); /* andxoffset */ + md_get_uint16le(mbp, actionp); /* action */ + md_get_uint16le(mbp, &sblen); /* sec. blob len */ + md_get_uint16le(mbp, &bc); /* byte count */ /* * Get the security blob, after * sanity-checking the length. */ if (sblen == 0 || bc < sblen) goto out; - err = mb_get_mbuf(mbp, sblen, &m); + err = md_get_mbuf(mbp, sblen, &m); if (err) goto out; mb_initm(mbc2, m); @@ -463,10 +463,10 @@ smb__ssnsetup(struct smb_ctx *ctx, } else { if (wc != 3) goto out; - mb_get_uint16le(mbp, NULL); /* secondary cmd */ - mb_get_uint16le(mbp, NULL); /* andxoffset */ - mb_get_uint16le(mbp, actionp); /* action */ - err = mb_get_uint16le(mbp, &bc); /* byte count */ + md_get_uint16le(mbp, NULL); /* secondary cmd */ + md_get_uint16le(mbp, NULL); /* andxoffset */ + md_get_uint16le(mbp, actionp); /* action */ + err = md_get_uint16le(mbp, &bc); /* byte count */ if (err) goto out; } @@ -485,9 +485,9 @@ smb__ssnsetup(struct smb_ctx *ctx, goto out; /* Ignore any parsing errors for these strings. */ - err = mb_get_string(mbp, &ctx->ct_srv_OS, uc); + err = md_get_string(mbp, &ctx->ct_srv_OS, uc); DPRINT("server OS: %s", err ? "?" : ctx->ct_srv_OS); - err = mb_get_string(mbp, &ctx->ct_srv_LM, uc); + err = md_get_string(mbp, &ctx->ct_srv_LM, uc); DPRINT("server LM: %s", err ? "?" : ctx->ct_srv_LM); /* * There's sometimes a server domain folloing diff --git a/usr/src/lib/libsmbfs/smb/ssp.c b/usr/src/lib/libsmbfs/smb/ssp.c index f8433ba8e5..d0b0d86d4f 100644 --- a/usr/src/lib/libsmbfs/smb/ssp.c +++ b/usr/src/lib/libsmbfs/smb/ssp.c @@ -277,7 +277,7 @@ ssp_ctx_next_token(struct smb_ctx *ctx, err = EBADRPC; goto out; } - err = mb_init(&body_in, (size_t)toklen); + err = mb_init_sz(&body_in, (size_t)toklen); if (err) goto out; m = body_in.mb_top; @@ -354,7 +354,7 @@ ssp_ctx_next_token(struct smb_ctx *ctx, err = EBADRPC; goto out; } - err = mb_init(caller_out, (size_t)toklen); + err = mb_init_sz(caller_out, (size_t)toklen); if (err) goto out; m = caller_out->mb_top; diff --git a/usr/src/pkgdefs/SUNWsmbfsu/prototype_com b/usr/src/pkgdefs/SUNWsmbfsu/prototype_com index e1a79c3742..bf892511dc 100644 --- a/usr/src/pkgdefs/SUNWsmbfsu/prototype_com +++ b/usr/src/pkgdefs/SUNWsmbfsu/prototype_com @@ -58,7 +58,6 @@ d none usr/lib/fs 755 root sys d none usr/lib/fs/smbfs 755 root sys f none usr/lib/fs/smbfs/mount 555 root bin f none usr/lib/fs/smbfs/umount 555 root bin -d none usr/lib/fs/smb 755 root sys f none usr/lib/fs/smbfs/libshare_smbfs.so.1 755 root bin f none usr/lib/libsmbfs.so.1 755 root bin d none usr/lib/mdb 755 root sys diff --git a/usr/src/uts/common/Makefile.files b/usr/src/uts/common/Makefile.files index 1feed57654..8681c65e96 100644 --- a/usr/src/uts/common/Makefile.files +++ b/usr/src/uts/common/Makefile.files @@ -1262,15 +1262,17 @@ UFS_OBJS += ufs_alloc.o ufs_bmap.o ufs_dir.o ufs_xattr.o \ lufs_log.o lufs_map.o lufs_top.o lufs_debug.o VSCAN_OBJS += vscan_drv.o vscan_svc.o vscan_door.o -NSMB_OBJS += smb_conn.o smb_dev.o smb_iod.o smb_rq.o \ - smb_sign.o smb_smb.o smb_tran.o smb_trantcp.o \ - smb_usr.o smb_subrs.o subr_mchain.o smb_pass.o +NSMB_OBJS += smb_conn.o smb_dev.o smb_iod.o smb_pass.o \ + smb_rq.o smb_sign.o smb_smb.o smb_subrs.o \ + smb_time.o smb_tran.o smb_trantcp.o smb_usr.o \ + subr_mchain.o +SMBFS_COMMON_OBJS += smbfs_ntacl.o SMBFS_OBJS += smbfs_vfsops.o smbfs_vnops.o smbfs_node.o \ smbfs_acl.o smbfs_client.o smbfs_smb.o \ smbfs_subr.o smbfs_subr2.o \ - smbfs_rwlock.o smbfs_xattr.o - + smbfs_rwlock.o smbfs_xattr.o \ + $(SMBFS_COMMON_OBJS) # # LVM modules diff --git a/usr/src/uts/common/Makefile.rules b/usr/src/uts/common/Makefile.rules index d87dd585e2..e1a301b569 100644 --- a/usr/src/uts/common/Makefile.rules +++ b/usr/src/uts/common/Makefile.rules @@ -284,6 +284,10 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/common/fs/sharefs/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) +$(OBJS_DIR)/%.o: $(COMMONBASE)/smbclnt/%.c + $(COMPILE.c) -o $@ $< + $(CTFCONVERT_O) + $(OBJS_DIR)/%.o: $(UTSBASE)/common/fs/smbclnt/netsmb/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) @@ -1707,6 +1711,9 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/common/fs/proc/%.c $(LINTS_DIR)/%.ln: $(UTSBASE)/common/fs/sharefs/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL)) +$(LINTS_DIR)/%.ln: $(COMMONBASE)/smbclnt/%.c + @($(LHEAD) $(LINT.c) $< $(LTAIL)) + $(LINTS_DIR)/%.ln: $(UTSBASE)/common/fs/smbclnt/netsmb/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL)) diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c index f1dcd57ea3..d1e7efd60a 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.c @@ -58,12 +58,7 @@ #include <sys/atomic.h> #include <sys/u8_textprep.h> -#ifdef APPLE -#include <sys/smb_apple.h> -#include <sys/smb_iconv.h> -#else #include <netsmb/smb_osdep.h> -#endif #include <netsmb/smb.h> #include <netsmb/smb_conn.h> @@ -620,7 +615,7 @@ smb_share_gone(struct smb_connobj *cp) smb_credinit(&scred, NULL); smb_iod_shutdown_share(ssp); - smb_smb_treedisconnect(ssp, &scred); + (void) smb_smb_treedisconnect(ssp, &scred); smb_credrele(&scred); } diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h index df85a77d11..83138776e4 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_conn.h @@ -81,13 +81,7 @@ typedef struct smb_cred { #define SMBS_RECONNECTING 0x0002 #define SMBS_CONNECTED 0x0004 #define SMBS_TCON_WAIT 0x0008 -#define SMBS_1980 0x0010 -/* - * ^ This partition can't handle dates before 1980. It's probably a FAT - * partition but could be some other ancient FS type - */ -#define SMBS_RESUMEKEYS 0x0020 /* must use resume keys */ -#define SMBS_LONGNAMES 0x0040 /* share can use long names */ +#define SMBS_FST_FAT 0x0010 /* share FS Type is FAT */ /* * Note: the common "obj" level uses this GONE flag by * the name SMBO_GONE. Keep this alias as a reminder. @@ -274,7 +268,7 @@ typedef struct smb_fscb { void (*fscb_up)(smb_share_t *); } smb_fscb_t; /* Install the above vector, or pass NULL to clear it. */ -int smb_fscb_set(smb_fscb_t *); +void smb_fscb_set(smb_fscb_t *); /* * The driver per open instance object. @@ -331,11 +325,11 @@ int smb_usr_iod_ioctl(smb_dev_t *sdp, int cmd, intptr_t arg, int flags); int smb_iod_create(smb_vc_t *vcp); int smb_iod_destroy(smb_vc_t *vcp); int smb_iod_connect(smb_vc_t *vcp); -int smb_iod_disconnect(smb_vc_t *vcp); +void smb_iod_disconnect(smb_vc_t *vcp); int smb_iod_addrq(struct smb_rq *rqp); int smb_iod_multirq(struct smb_rq *rqp); int smb_iod_waitrq(struct smb_rq *rqp); -int smb_iod_removerq(struct smb_rq *rqp); +void smb_iod_removerq(struct smb_rq *rqp); void smb_iod_shutdown_share(smb_share_t *ssp); void smb_iod_sendall(smb_vc_t *); diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c index 8ec7daef1c..61b4088927 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_dev.c @@ -66,12 +66,7 @@ #include <sys/types.h> #include <sys/zone.h> -#ifdef APPLE -#include <sys/smb_apple.h> -#else #include <netsmb/smb_osdep.h> -#endif - #include <netsmb/mchain.h> /* for "htoles()" */ #include <netsmb/smb.h> @@ -182,7 +177,7 @@ _init(void) { int error; - ddi_soft_state_init(&statep, sizeof (smb_dev_t), 1); + (void) ddi_soft_state_init(&statep, sizeof (smb_dev_t), 1); /* Can initialize some mutexes also. */ mutex_init(&dev_lck, NULL, MUTEX_DRIVER, NULL); @@ -198,6 +193,9 @@ _init(void) /* Initialize password Key chain DB. */ smb_pkey_init(); + /* Time conversion stuff. */ + smb_time_init(); + /* Initialize crypto mechanisms. */ smb_crypto_mech_init(); @@ -247,6 +245,9 @@ _fini(void) (void) zone_key_delete(nsmb_zone_key); + /* Time conversion stuff. */ + smb_time_fini(); + /* Destroy password Key chain DB. */ smb_pkey_fini(); @@ -384,7 +385,7 @@ nsmb_ioctl(dev_t dev, int cmd, intptr_t arg, int flags, /* model.h */ err = 0; switch (cmd) { case SMBIOC_GETVERS: - ddi_copyout(&nsmb_version, (void *)arg, + (void) ddi_copyout(&nsmb_version, (void *)arg, sizeof (nsmb_version), flags); break; diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c index f6bba8380a..e7cac1aa75 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_iod.c @@ -64,11 +64,7 @@ #include <sys/zone.h> #include <sys/sdt.h> -#ifdef APPLE -#include <sys/smb_apple.h> -#else #include <netsmb/smb_osdep.h> -#endif #include <netsmb/smb.h> #include <netsmb/smb_conn.h> @@ -85,11 +81,10 @@ int smb_iod_send_echo(smb_vc_t *); * can't unload until all the mounts are gone. */ static smb_fscb_t *fscb; -int +void smb_fscb_set(smb_fscb_t *cb) { fscb = cb; - return (0); } static void @@ -161,7 +156,7 @@ smb_iod_invrq(struct smb_vc *vcp) * * Forcibly kill the connection and IOD. */ -int +void smb_iod_disconnect(struct smb_vc *vcp) { @@ -194,8 +189,6 @@ smb_iod_disconnect(struct smb_vc *vcp) vcp->iod_thr != curthread) { tsignal(vcp->iod_thr, SIGKILL); } - - return (0); } /* @@ -700,7 +693,7 @@ smb_iod_multirq(struct smb_rq *rqp) } -int +void smb_iod_removerq(struct smb_rq *rqp) { struct smb_vc *vcp = rqp->sr_vc; @@ -716,8 +709,6 @@ smb_iod_removerq(struct smb_rq *rqp) #endif TAILQ_REMOVE(&vcp->iod_rqlist, rqp, sr_link); rw_exit(&vcp->iod_rqlock); - - return (0); } @@ -789,7 +780,6 @@ smb_iod_waitrq(struct smb_rq *rqp) tmo1 = SEC_TO_TICK(smb_timo_notice); else tmo1 = 0; - tmo2 = ddi_get_lbolt() + SEC_TO_TICK(rqp->sr_timo); /* @@ -914,14 +904,13 @@ void smb_iod_sendall(smb_vc_t *vcp) { struct smb_rq *rqp; - int error, save_newrq, muxcnt; + int error, muxcnt; /* * Clear "newrq" to make sure threads adding * new requests will run this function again. */ rw_enter(&vcp->iod_rqlock, RW_WRITER); - save_newrq = vcp->iod_newrq; vcp->iod_newrq = 0; /* @@ -931,9 +920,6 @@ smb_iod_sendall(smb_vc_t *vcp) */ rw_downgrade(&vcp->iod_rqlock); - /* Expect to find about this many requests. */ - SMBIODEBUG("top, save_newrq=%d\n", save_newrq); - /* * Serialize to prevent multiple senders. * Note lock order: iod_rqlock, vc_sendlock diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.c index 4079482538..c26d80e48c 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.c +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_pass.c @@ -166,7 +166,7 @@ smb_pkey_init() void smb_pkey_fini() { - smb_pkey_deluid((uid_t)-1, kcred); + (void) smb_pkey_deluid((uid_t)-1, kcred); avl_destroy(&smb_ptd); mutex_destroy(&smb_ptd_lock); } @@ -187,15 +187,14 @@ smb_pkey_idle() return ((n) ? EBUSY : 0); } -int -smb_node_delete(smb_passid_t *tmp) +static void +smb_pkey_delete(smb_passid_t *tmp) { ASSERT(MUTEX_HELD(&smb_ptd_lock)); avl_remove(&smb_ptd, tmp); strfree(tmp->srvdom); strfree(tmp->username); kmem_free(tmp, sizeof (*tmp)); - return (0); } @@ -225,7 +224,7 @@ smb_pkey_del(smbioc_pk_t *pk, cred_t *cr) mutex_enter(&smb_ptd_lock); if ((cpid = (smb_passid_t *)avl_find(&smb_ptd, tmp, &where)) != NULL) { - smb_node_delete(cpid); + smb_pkey_delete(cpid); } mutex_exit(&smb_ptd_lock); @@ -259,7 +258,7 @@ smb_pkey_deluid(uid_t ioc_uid, cred_t *cr) /* * Delete the node. */ - smb_node_delete(tmp); + smb_pkey_delete(tmp); } } mutex_exit(&smb_ptd_lock); @@ -306,7 +305,7 @@ smb_pkey_add(smbioc_pk_t *pk, cred_t *cr) /* If it already exists, delete it. */ ret = smb_pkey_check(pk, cr); if (ret == 0) { - smb_pkey_del(pk, cr); + (void) smb_pkey_del(pk, cr); } mutex_enter(&smb_ptd_lock); diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c index 0985d58ff4..0ce241b0ce 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_rq.c @@ -39,6 +39,7 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/time.h> #include <sys/kmem.h> #include <sys/proc.h> #include <sys/lock.h> @@ -261,17 +262,14 @@ smb_rq_simple_timed(struct smb_rq *rqp, int timeout) break; SMBRQ_LOCK(rqp); if (rqp->sr_share) { - cv_reltimedwait(&rqp->sr_cond, &(rqp)->sr_lock, - (hz * SMB_RCNDELAY), TR_CLOCK_TICK); + (void) cv_reltimedwait(&rqp->sr_cond, &(rqp)->sr_lock, + SEC_TO_TICK(SMB_RCNDELAY), TR_CLOCK_TICK); } else { - delay(ddi_get_lbolt() + (hz * SMB_RCNDELAY)); + delay(SEC_TO_TICK(SMB_RCNDELAY)); } SMBRQ_UNLOCK(rqp); rqp->sr_rexmit--; -#ifdef XXX - timeout *= 2; -#endif } return (error); } @@ -469,8 +467,10 @@ smb_rq_reply(struct smb_rq *rqp) u_int8_t tb; int error, rperror = 0; - if (rqp->sr_timo == SMBNOREPLYWAIT) - return (smb_iod_removerq(rqp)); + if (rqp->sr_timo == SMBNOREPLYWAIT) { + smb_iod_removerq(rqp); + return (0); + } error = smb_iod_waitrq(rqp); if (error) @@ -534,10 +534,6 @@ smb_rq_reply(struct smb_rq *rqp) error = md_get_uint16le(mdp, &rqp->sr_rpuid); error = md_get_uint16le(mdp, &rqp->sr_rpmid); - SMBSDEBUG("M:%04x, P:%04x, U:%04x, T:%04x, E: %d:%d\n", - rqp->sr_rpmid, rqp->sr_rppid, rqp->sr_rpuid, rqp->sr_rptid, - rqp->sr_errclass, rqp->sr_serror); - return ((error) ? error : rperror); } @@ -969,7 +965,7 @@ smb_t2_request_int(struct smb_t2rq *t2p) m = t2p->t2_tdata.mb_top; if (m) { md_initm(&mbdata, m); /* do not free it! */ - totdcount = m_fixhdr(m); + totdcount = m_fixhdr(m); if (totdcount > 0xffff) return (EINVAL); } else @@ -1045,12 +1041,14 @@ smb_t2_request_int(struct smb_t2rq *t2p) smb_rq_bstart(rqp); if (t2p->t_name) { /* Put the string and terminating null. */ - smb_put_dmem(mbp, vcp, t2p->t_name, nmlen + 1, + error = smb_put_dmem(mbp, vcp, t2p->t_name, nmlen + 1, SMB_CS_NONE, NULL); } else { /* nmsize accounts for padding, char size. */ - mb_put_mem(mbp, NULL, nmsize, MB_MZERO); + error = mb_put_mem(mbp, NULL, nmsize, MB_MZERO); } + if (error) + goto freerq; len = mb_fixhdr(mbp); if (txpcount) { mb_put_mem(mbp, NULL, ALIGN4(len) - len, MB_MZERO); @@ -1153,12 +1151,10 @@ smb_t2_request_int(struct smb_t2rq *t2p) goto bad; mdp = &t2p->t2_rdata; if (mdp->md_top) { - m_fixhdr(mdp->md_top); md_initm(mdp, mdp->md_top); } mdp = &t2p->t2_rparam; if (mdp->md_top) { - m_fixhdr(mdp->md_top); md_initm(mdp, mdp->md_top); } bad: @@ -1366,12 +1362,10 @@ smb_nt_request_int(struct smb_ntrq *ntp) goto bad; mdp = &ntp->nt_rdata; if (mdp->md_top) { - m_fixhdr(mdp->md_top); md_initm(mdp, mdp->md_top); } mdp = &ntp->nt_rparam; if (mdp->md_top) { - m_fixhdr(mdp->md_top); md_initm(mdp, mdp->md_top); } bad: @@ -1409,10 +1403,10 @@ smb_t2_request(struct smb_t2rq *t2p) break; mutex_enter(&(t2p)->t2_lock); if (t2p->t2_share) { - cv_reltimedwait(&t2p->t2_cond, &(t2p)->t2_lock, - (hz * SMB_RCNDELAY), TR_CLOCK_TICK); + (void) cv_reltimedwait(&t2p->t2_cond, &(t2p)->t2_lock, + SEC_TO_TICK(SMB_RCNDELAY), TR_CLOCK_TICK); } else { - delay(ddi_get_lbolt() + (hz * SMB_RCNDELAY)); + delay(SEC_TO_TICK(SMB_RCNDELAY)); } mutex_exit(&(t2p)->t2_lock); } @@ -1442,11 +1436,11 @@ smb_nt_request(struct smb_ntrq *ntp) break; mutex_enter(&(ntp)->nt_lock); if (ntp->nt_share) { - cv_reltimedwait(&ntp->nt_cond, &(ntp)->nt_lock, - (hz * SMB_RCNDELAY), TR_CLOCK_TICK); + (void) cv_reltimedwait(&ntp->nt_cond, &(ntp)->nt_lock, + SEC_TO_TICK(SMB_RCNDELAY), TR_CLOCK_TICK); } else { - delay(ddi_get_lbolt() + (hz * SMB_RCNDELAY)); + delay(SEC_TO_TICK(SMB_RCNDELAY)); } mutex_exit(&(ntp)->nt_lock); } diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c index 91c450bb23..140d390670 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_sign.c @@ -189,7 +189,7 @@ smb_compute_MAC(struct smb_vc *vcp, mblk_t *mp, /* * Sign a request with HMAC-MD5. */ -int +void smb_rq_sign(struct smb_rq *rqp) { struct smb_vc *vcp = rqp->sr_vc; @@ -203,7 +203,7 @@ smb_rq_sign(struct smb_rq *rqp) */ if (MBLKL(mp) < SMB_HDRLEN) { if (!pullupmsg(mp, SMB_HDRLEN)) - return (0); + return; } sigloc = mp->b_rptr + SMBSIGOFF; @@ -214,7 +214,7 @@ smb_rq_sign(struct smb_rq *rqp) * This happens with SPNEGO, NTLMSSP, ... */ bcopy("BSRSPLY", sigloc, 8); - return (0); + return; } /* @@ -225,9 +225,7 @@ smb_rq_sign(struct smb_rq *rqp) if (status != CRYPTO_SUCCESS) { SMBSDEBUG("Crypto error %d", status); bzero(sigloc, SMBSIGLEN); - return (ENOTSUP); } - return (0); } /* @@ -240,8 +238,7 @@ smb_rq_verify(struct smb_rq *rqp) mblk_t *mp = rqp->sr_rp.md_top; uint8_t sigbuf[SMBSIGLEN]; uint8_t *sigloc; - int status; - int fudge; + int fudge, rsn, status; /* * Note vc_mackey and vc_mackeylen gets filled in by @@ -266,9 +263,11 @@ smb_rq_verify(struct smb_rq *rqp) } sigloc = mp->b_rptr + SMBSIGOFF; - SMBSDEBUG("sr_rseqno = 0x%x\n", rqp->sr_rseqno); - - status = smb_compute_MAC(vcp, mp, rqp->sr_rseqno, sigbuf); + /* + * Compute the expected signature in sigbuf. + */ + rsn = rqp->sr_rseqno; + status = smb_compute_MAC(vcp, mp, rsn, sigbuf); if (status != CRYPTO_SUCCESS) { SMBSDEBUG("Crypto error %d", status); /* @@ -293,10 +292,10 @@ smb_rq_verify(struct smb_rq *rqp) * of the sequence # has gotten a bit out of sync. */ for (fudge = 1; fudge <= nsmb_signing_fudge; fudge++) { - smb_compute_MAC(vcp, mp, rqp->sr_rseqno + fudge, sigbuf); + (void) smb_compute_MAC(vcp, mp, rsn + fudge, sigbuf); if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0) break; - smb_compute_MAC(vcp, mp, rqp->sr_rseqno - fudge, sigbuf); + (void) smb_compute_MAC(vcp, mp, rsn - fudge, sigbuf); if (bcmp(sigbuf, sigloc, SMBSIGLEN) == 0) { fudge = -fudge; break; @@ -304,7 +303,7 @@ smb_rq_verify(struct smb_rq *rqp) } if (fudge <= nsmb_signing_fudge) { SMBSDEBUG("sr_rseqno=%d, but %d would have worked\n", - rqp->sr_rseqno, rqp->sr_rseqno + fudge); + rsn, rsn + fudge); } #endif return (EBADRPC); diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c index fce18f74ff..5fa43ece4b 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_smb.c @@ -51,12 +51,7 @@ #include <sys/note.h> #include <sys/cmn_err.h> -#ifdef APPLE -#include <sys/smb_apple.h> -#include <sys/utfconv.h> -#else #include <netsmb/smb_osdep.h> -#endif #include <netsmb/smb.h> #include <netsmb/smb_conn.h> @@ -84,95 +79,16 @@ int smb_timo_read = 45; int smb_timo_write = 60; /* was SMBWRTTIMO */ int smb_timo_append = 90; -/* - * Debug/test feature to disable NTMLv2. - * Set this to zero to skip NTLMv2 - */ -int nsmb_enable_ntlmv2 = 1; - -static int smb_smb_read(struct smb_share *ssp, u_int16_t fid, +static int smb_smb_read(struct smb_share *ssp, uint16_t fid, uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo); -static int smb_smb_write(struct smb_share *ssp, u_int16_t fid, +static int smb_smb_write(struct smb_share *ssp, uint16_t fid, uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo); -static int smb_smb_readx(struct smb_share *ssp, u_int16_t fid, +static int smb_smb_readx(struct smb_share *ssp, uint16_t fid, uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo); -static int smb_smb_writex(struct smb_share *ssp, u_int16_t fid, +static int smb_smb_writex(struct smb_share *ssp, uint16_t fid, uint32_t *lenp, uio_t *uiop, smb_cred_t *scred, int timo); -struct smb_dialect { - int d_id; - const char *d_name; -}; - - -/* - * Number of seconds between 1970 and 1601 year - */ -const u_int64_t DIFF1970TO1601 = 11644473600ULL; - -void -smb_time_local2server(struct timespec *tsp, int tzoff, long *seconds) -{ - /* - * XXX - what if we connected to the server when it was in - * daylight savings/summer time and we've subsequently switched - * to standard time, or vice versa, so that the time zone - * offset we got from the server is now wrong? - */ - *seconds = tsp->tv_sec - tzoff * 60; - /* - tz.tz_minuteswest * 60 - (wall_cmos_clock ? adjkerntz : 0) */ -} - -void -smb_time_server2local(ulong_t seconds, int tzoff, struct timespec *tsp) -{ - /* - * XXX - what if we connected to the server when it was in - * daylight savings/summer time and we've subsequently switched - * to standard time, or vice versa, so that the time zone - * offset we got from the server is now wrong? - */ - tsp->tv_sec = seconds + tzoff * 60; - /* + tz.tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0); */ - tsp->tv_nsec = 0; -} - -/* - * Time from server comes as UTC, so no need to use tz - */ -/*ARGSUSED*/ -void -smb_time_NT2local(u_int64_t nsec, int tzoff, struct timespec *tsp) -{ - smb_time_server2local(nsec / 10000000 - DIFF1970TO1601, 0, tsp); -} - -/*ARGSUSED*/ -void -smb_time_local2NT(struct timespec *tsp, int tzoff, u_int64_t *nsec) -{ - long seconds; - - smb_time_local2server(tsp, 0, &seconds); - *nsec = (((u_int64_t)(seconds) & ~1) + DIFF1970TO1601) * - (u_int64_t)10000000; -} - -#if defined(NOICONVSUPPORT) || defined(lint) -extern int iconv_open(const char *to, const char *from, void **handle); -extern int iconv_close(void *handle); -#endif - -/* - * Moved to user space helper: - * smb_smb_negotiate() - * smb_smb_ssnsetup() - * smb_smb_ssnclose() - * smb_share_typename() - */ - - int smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred) { @@ -208,7 +124,7 @@ smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred) */ unc_len = 4 + strlen(vcp->vc_srvname) + strlen(ssp->ss_name); unc_name = kmem_alloc(unc_len, KM_SLEEP); - snprintf(unc_name, unc_len, "\\\\%s\\%s", + (void) snprintf(unc_name, unc_len, "\\\\%s\\%s", vcp->vc_srvname, ssp->ss_name); /* @@ -274,14 +190,17 @@ smb_smb_treeconnect(struct smb_share *ssp, struct smb_cred *scred) error = EBADRPC; goto out; } - md_get_uint16le(mdp, NULL); /* AndX cmd */ - md_get_uint16le(mdp, NULL); /* AndX off */ - md_get_uint16le(mdp, &options); /* option bits (DFS, search) */ - md_get_uint16le(mdp, &bcnt); /* byte count */ + md_get_uint16le(mdp, NULL); /* AndX cmd */ + md_get_uint16le(mdp, NULL); /* AndX off */ + md_get_uint16le(mdp, &options); /* option bits (DFS, search) */ + error = md_get_uint16le(mdp, &bcnt); /* byte count */ + if (error) + goto out; /* * Get the returned share type string, - * i.e. "IPC" or whatever. + * i.e. "IPC" or whatever. Don't care + * if we get an error reading the type. */ tlen = sizeof (ssp->ss_type_ret); bzero(ssp->ss_type_ret, tlen--); @@ -476,53 +395,61 @@ smb_smb_readx(struct smb_share *ssp, uint16_t fid, uint32_t *lenp, smb_rq_wend(rqp); smb_rq_bstart(rqp); smb_rq_bend(rqp); - do { - if (timo == 0) - timo = smb_timo_read; - error = smb_rq_simple_timed(rqp, timo); - if (error) - break; - smb_rq_getreply(rqp, &mdp); - md_get_uint8(mdp, &wc); - if (wc != 12) { - error = EBADRPC; - break; - } - md_get_uint8(mdp, NULL); - md_get_uint8(mdp, NULL); - md_get_uint16le(mdp, NULL); - md_get_uint16le(mdp, NULL); - md_get_uint16le(mdp, NULL); /* data compaction mode */ - md_get_uint16le(mdp, NULL); - md_get_uint16le(mdp, &lenlo); /* data len ret. */ - md_get_uint16le(mdp, &doff); /* data offset */ - md_get_uint16le(mdp, &lenhi); - rlen = (lenhi << 16) | lenlo; - md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM); - md_get_uint16le(mdp, NULL); /* ByteCount */ - /* - * Does the data offset indicate padding? - * Add up the gets above, we have: - */ - off = SMB_HDRLEN + 3 + (12 * 2); /* =59 */ - if (doff > off) /* pad byte(s)? */ - md_get_mem(mdp, NULL, doff - off, MB_MSYSTEM); - if (rlen == 0) { - *lenp = rlen; - break; - } - /* paranoid */ - if (rlen > *lenp) { - SMBSDEBUG("bad server! rlen %d, len %d\n", - rlen, *lenp); - rlen = *lenp; - } - error = md_get_uio(mdp, uiop, rlen); - if (error) - break; + + if (timo == 0) + timo = smb_timo_read; + error = smb_rq_simple_timed(rqp, timo); + if (error) + goto out; + + smb_rq_getreply(rqp, &mdp); + error = md_get_uint8(mdp, &wc); + if (error) + goto out; + if (wc != 12) { + error = EBADRPC; + goto out; + } + md_get_uint8(mdp, NULL); + md_get_uint8(mdp, NULL); + md_get_uint16le(mdp, NULL); + md_get_uint16le(mdp, NULL); + md_get_uint16le(mdp, NULL); /* data compaction mode */ + md_get_uint16le(mdp, NULL); + md_get_uint16le(mdp, &lenlo); /* data len ret. */ + md_get_uint16le(mdp, &doff); /* data offset */ + md_get_uint16le(mdp, &lenhi); + rlen = (lenhi << 16) | lenlo; + md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM); + error = md_get_uint16le(mdp, NULL); /* ByteCount */ + if (error) + goto out; + /* + * Does the data offset indicate padding? + * The current offset is a constant, found + * by counting the md_get_ calls above. + */ + off = SMB_HDRLEN + 3 + (12 * 2); /* =59 */ + if (doff > off) /* pad byte(s)? */ + md_get_mem(mdp, NULL, doff - off, MB_MSYSTEM); + if (rlen == 0) { *lenp = rlen; - /*LINTED*/ - } while (0); + goto out; + } + /* paranoid */ + if (rlen > *lenp) { + SMBSDEBUG("bad server! rlen %d, len %d\n", + rlen, *lenp); + rlen = *lenp; + } + error = md_get_uio(mdp, uiop, rlen); + if (error) + goto out; + + /* Success */ + *lenp = rlen; + +out: smb_rq_done(rqp); return (error); } @@ -563,34 +490,39 @@ smb_smb_writex(struct smb_share *ssp, uint16_t fid, uint32_t *lenp, mb_put_uint32le(mbp, offhi); /* offset (high part) */ smb_rq_wend(rqp); smb_rq_bstart(rqp); - do { - mb_put_uint8(mbp, 0); /* pad byte */ - error = mb_put_uio(mbp, uiop, *lenp); - if (error) - break; - smb_rq_bend(rqp); - if (timo == 0) - timo = smb_timo_write; - error = smb_rq_simple_timed(rqp, timo); - if (error) - break; - smb_rq_getreply(rqp, &mdp); - md_get_uint8(mdp, &wc); - if (wc != 6) { - error = EBADRPC; - break; - } - md_get_uint8(mdp, NULL); /* andx cmd */ - md_get_uint8(mdp, NULL); /* reserved */ - md_get_uint16le(mdp, NULL); /* andx offset */ - md_get_uint16le(mdp, &lenlo); /* data len ret. */ - md_get_uint16le(mdp, NULL); /* remaining */ - md_get_uint16le(mdp, &lenhi); - rlen = (lenhi << 16) | lenlo; - *lenp = rlen; - /*LINTED*/ - } while (0); + mb_put_uint8(mbp, 0); /* pad byte */ + error = mb_put_uio(mbp, uiop, *lenp); + if (error) + goto out; + smb_rq_bend(rqp); + if (timo == 0) + timo = smb_timo_write; + error = smb_rq_simple_timed(rqp, timo); + if (error) + goto out; + smb_rq_getreply(rqp, &mdp); + error = md_get_uint8(mdp, &wc); + if (error) + goto out; + if (wc != 6) { + error = EBADRPC; + goto out; + } + md_get_uint8(mdp, NULL); /* andx cmd */ + md_get_uint8(mdp, NULL); /* reserved */ + md_get_uint16le(mdp, NULL); /* andx offset */ + md_get_uint16le(mdp, &lenlo); /* data len ret. */ + md_get_uint16le(mdp, NULL); /* remaining */ + error = md_get_uint16le(mdp, &lenhi); + if (error) + goto out; + + /* Success */ + rlen = (lenhi << 16) | lenlo; + *lenp = rlen; + +out: smb_rq_done(rqp); return (error); } @@ -626,44 +558,50 @@ smb_smb_read(struct smb_share *ssp, uint16_t fid, uint32_t *lenp, smb_rq_wend(rqp); smb_rq_bstart(rqp); smb_rq_bend(rqp); - do { - if (timo == 0) - timo = smb_timo_read; - error = smb_rq_simple_timed(rqp, timo); - if (error) - break; - smb_rq_getreply(rqp, &mdp); - md_get_uint8(mdp, &wc); - if (wc != 5) { - error = EBADRPC; - break; - } - md_get_uint16le(mdp, &rcnt); /* ret. count */ - md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM); /* res. */ - md_get_uint16le(mdp, &bc); /* byte count */ - md_get_uint8(mdp, NULL); /* buffer format */ - md_get_uint16le(mdp, &dlen); /* data len */ - if (dlen < rcnt) { - SMBSDEBUG("oops: dlen=%d rcnt=%d\n", - (int)dlen, (int)rcnt); - rcnt = dlen; - } - if (rcnt == 0) { - *lenp = 0; - break; - } - /* paranoid */ - if (rcnt > cnt) { - SMBSDEBUG("bad server! rcnt %d, cnt %d\n", - (int)rcnt, (int)cnt); - rcnt = cnt; - } - error = md_get_uio(mdp, uiop, (int)rcnt); - if (error) - break; - *lenp = (int)rcnt; - /*LINTED*/ - } while (0); + + if (timo == 0) + timo = smb_timo_read; + error = smb_rq_simple_timed(rqp, timo); + if (error) + goto out; + smb_rq_getreply(rqp, &mdp); + error = md_get_uint8(mdp, &wc); + if (error) + goto out; + if (wc != 5) { + error = EBADRPC; + goto out; + } + md_get_uint16le(mdp, &rcnt); /* ret. count */ + md_get_mem(mdp, NULL, 4 * 2, MB_MSYSTEM); /* res. */ + md_get_uint16le(mdp, &bc); /* byte count */ + md_get_uint8(mdp, NULL); /* buffer format */ + error = md_get_uint16le(mdp, &dlen); /* data len */ + if (error) + goto out; + if (dlen < rcnt) { + SMBSDEBUG("oops: dlen=%d rcnt=%d\n", + (int)dlen, (int)rcnt); + rcnt = dlen; + } + if (rcnt == 0) { + *lenp = 0; + goto out; + } + /* paranoid */ + if (rcnt > cnt) { + SMBSDEBUG("bad server! rcnt %d, cnt %d\n", + (int)rcnt, (int)cnt); + rcnt = cnt; + } + error = md_get_uio(mdp, uiop, (int)rcnt); + if (error) + goto out; + + /* success */ + *lenp = (int)rcnt; + +out: smb_rq_done(rqp); return (error); } @@ -700,26 +638,30 @@ smb_smb_write(struct smb_share *ssp, uint16_t fid, uint32_t *lenp, smb_rq_bstart(rqp); mb_put_uint8(mbp, SMB_DT_DATA); mb_put_uint16le(mbp, cnt); - do { - error = mb_put_uio(mbp, uiop, *lenp); - if (error) - break; - smb_rq_bend(rqp); - if (timo == 0) - timo = smb_timo_write; - error = smb_rq_simple_timed(rqp, timo); - if (error) - break; - smb_rq_getreply(rqp, &mdp); - md_get_uint8(mdp, &wc); - if (wc != 1) { - error = EBADRPC; - break; - } - md_get_uint16le(mdp, &rcnt); - *lenp = rcnt; - /*LINTED*/ - } while (0); + + error = mb_put_uio(mbp, uiop, *lenp); + if (error) + goto out; + smb_rq_bend(rqp); + if (timo == 0) + timo = smb_timo_write; + error = smb_rq_simple_timed(rqp, timo); + if (error) + goto out; + smb_rq_getreply(rqp, &mdp); + error = md_get_uint8(mdp, &wc); + if (error) + goto out; + if (wc != 1) { + error = EBADRPC; + goto out; + } + error = md_get_uint16le(mdp, &rcnt); + if (error) + goto out; + *lenp = rcnt; + +out: smb_rq_done(rqp); return (error); } diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h index 3edf4c4d9d..675fa62b8d 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subr.h @@ -122,7 +122,7 @@ struct sockaddr *smb_dup_sockaddr(struct sockaddr *sa); void smb_free_sockaddr(struct sockaddr *sa); int smb_toupper(const char *, char *, size_t); -int smb_rq_sign(struct smb_rq *); +void smb_rq_sign(struct smb_rq *); int smb_rq_verify(struct smb_rq *); int smb_calcv2mackey(struct smb_vc *, const uchar_t *, const uchar_t *, size_t); @@ -130,4 +130,16 @@ int smb_calcmackey(struct smb_vc *, const uchar_t *, const uchar_t *, size_t); void smb_crypto_mech_init(void); +void smb_time_init(void); +void smb_time_fini(void); + +void smb_time_local2server(struct timespec *tsp, int tzoff, long *seconds); +void smb_time_server2local(ulong_t seconds, int tzoff, struct timespec *tsp); +void smb_time_NT2local(uint64_t nsec, struct timespec *tsp); +void smb_time_local2NT(struct timespec *tsp, uint64_t *nsec); +void smb_time_unix2dos(struct timespec *tsp, int tzoff, uint16_t *ddp, + uint16_t *dtp, uint8_t *dhp); +void smb_dos2unixtime(uint_t dd, uint_t dt, uint_t dh, int tzoff, + struct timespec *tsp); + #endif /* !_NETSMB_SMB_SUBR_H_ */ diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c index 98963b5583..bfacaaa55d 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_subrs.c @@ -134,7 +134,7 @@ smb_errmsg(int cel, const char *func_name, const char *fmt, ...) * Don't bother to log these, but just * fire a dtrace probe with the message. */ - vsnprintf(buf, sizeof (buf), fmt, adx); + (void) vsnprintf(buf, sizeof (buf), fmt, adx); DTRACE_PROBE2(debugmsg2, (char *), func_name, (char *), buf); @@ -144,7 +144,7 @@ smb_errmsg(int cel, const char *func_name, const char *fmt, ...) * Add a prefix to the fmt string, * then let vcmn_err do the args. */ - snprintf(buf, sizeof (buf), "?%s: %s", func_name, fmt); + (void) snprintf(buf, sizeof (buf), "?%s: %s", func_name, fmt); DTRACE_PROBE3(debugmsg3, (char *), func_name, (char *), buf, @@ -186,19 +186,22 @@ m_dumpm(mblk_t *m) #define ECOMM EIO #endif #ifndef ENOMEDIUM -#define ENOMEDIUM EIO +#define ENOMEDIUM ENXIO #endif #ifndef ETIME #define ETIME ETIMEDOUT #endif -static struct { - unsigned nterr; - unsigned errno; +static const struct { + unsigned int nterr; + unsigned int errno; } nt2errno[] = { + /* Alphabetical order. */ {NT_STATUS_ACCESS_DENIED, EACCES}, {NT_STATUS_ACCESS_VIOLATION, EACCES}, {NT_STATUS_ACCOUNT_DISABLED, EACCES}, + {NT_STATUS_ACCOUNT_EXPIRED, EACCES}, + {NT_STATUS_ACCOUNT_LOCKED_OUT, EACCES}, {NT_STATUS_ACCOUNT_RESTRICTION, EACCES}, {NT_STATUS_ADDRESS_ALREADY_EXISTS, EADDRINUSE}, {NT_STATUS_BAD_NETWORK_NAME, ENOENT}, @@ -209,6 +212,7 @@ static struct { {NT_STATUS_CONNECTION_DISCONNECTED, ECONNABORTED}, {NT_STATUS_CONNECTION_REFUSED, ECONNREFUSED}, {NT_STATUS_CONNECTION_RESET, ENETRESET}, + {NT_STATUS_DELETE_PENDING, EACCES}, {NT_STATUS_DEVICE_DOES_NOT_EXIST, ENODEV}, {NT_STATUS_DEVICE_PROTOCOL_ERROR, EPROTO}, {NT_STATUS_DIRECTORY_NOT_EMPTY, ENOTEMPTY}, @@ -216,13 +220,16 @@ static struct { {NT_STATUS_DLL_NOT_FOUND, ELIBACC}, {NT_STATUS_END_OF_FILE, ENODATA}, {NT_STATUS_FILE_IS_A_DIRECTORY, EISDIR}, + {NT_STATUS_FILE_LOCK_CONFLICT, EAGAIN}, {NT_STATUS_FLOAT_INEXACT_RESULT, ERANGE}, {NT_STATUS_FLOAT_OVERFLOW, ERANGE}, {NT_STATUS_FLOAT_UNDERFLOW, ERANGE}, {NT_STATUS_HOST_UNREACHABLE, EHOSTUNREACH}, {NT_STATUS_ILL_FORMED_PASSWORD, EACCES}, {NT_STATUS_INTEGER_OVERFLOW, ERANGE}, + {NT_STATUS_INVALID_ACCOUNT_NAME, EACCES}, {NT_STATUS_INVALID_HANDLE, EBADF}, + {NT_STATUS_INVALID_LEVEL, ENOTSUP}, {NT_STATUS_INVALID_LOGON_HOURS, EACCES}, {NT_STATUS_INVALID_PARAMETER, EINVAL}, {NT_STATUS_INVALID_PIPE_STATE, EPIPE}, @@ -232,6 +239,8 @@ static struct { {NT_STATUS_IP_ADDRESS_CONFLICT1, ENOTUNIQ}, {NT_STATUS_IP_ADDRESS_CONFLICT2, ENOTUNIQ}, {NT_STATUS_LICENSE_QUOTA_EXCEEDED, EDQUOT}, + {NT_STATUS_LOCK_NOT_GRANTED, EAGAIN}, + {NT_STATUS_LOGIN_TIME_RESTRICTION, EACCES}, {NT_STATUS_LOGON_FAILURE, EACCES}, {NT_STATUS_MEDIA_WRITE_PROTECTED, EROFS}, {NT_STATUS_MEMORY_NOT_ALLOCATED, EFAULT}, @@ -241,6 +250,7 @@ static struct { {NT_STATUS_NETWORK_UNREACHABLE, ENETUNREACH}, {NT_STATUS_NET_WRITE_FAULT, ECOMM}, {NT_STATUS_NONEXISTENT_SECTOR, ESPIPE}, + {NT_STATUS_NONE_MAPPED, EINVAL}, {NT_STATUS_NOT_A_DIRECTORY, ENOTDIR}, {NT_STATUS_NOT_IMPLEMENTED, ENOSYS}, {NT_STATUS_NOT_MAPPED_VIEW, EINVAL}, @@ -251,11 +261,13 @@ static struct { {NT_STATUS_NO_SUCH_DEVICE, ENODEV}, {NT_STATUS_NO_SUCH_FILE, ENOENT}, {NT_STATUS_OBJECT_NAME_COLLISION, EEXIST}, - {NT_STATUS_OBJECT_NAME_NOT_FOUND, ENOENT}, {NT_STATUS_OBJECT_NAME_INVALID, EINVAL}, + {NT_STATUS_OBJECT_NAME_NOT_FOUND, ENOENT}, {NT_STATUS_OBJECT_PATH_INVALID, ENOTDIR}, + {NT_STATUS_OBJECT_PATH_NOT_FOUND, ENOENT}, {NT_STATUS_PAGEFILE_QUOTA, EDQUOT}, {NT_STATUS_PASSWORD_EXPIRED, EACCES}, + {NT_STATUS_PASSWORD_MUST_CHANGE, EACCES}, {NT_STATUS_PASSWORD_RESTRICTION, EACCES}, {NT_STATUS_PATH_NOT_COVERED, ENOENT}, {NT_STATUS_PIPE_BROKEN, EPIPE}, @@ -268,6 +280,7 @@ static struct { {NT_STATUS_PORT_UNREACHABLE, EHOSTUNREACH}, {NT_STATUS_PROTOCOL_UNREACHABLE, ENOPROTOOPT}, {NT_STATUS_QUOTA_EXCEEDED, EDQUOT}, + {NT_STATUS_RANGE_NOT_LOCKED, EIO}, {NT_STATUS_REGISTRY_QUOTA_LIMIT, EDQUOT}, {NT_STATUS_REMOTE_DISCONNECT, ESHUTDOWN}, {NT_STATUS_REMOTE_NOT_LISTENING, ECONNREFUSED}, @@ -283,10 +296,10 @@ static struct { {0, 0} }; -static struct { - unsigned dclass; - unsigned derr; - unsigned nterr; +static const struct { + unsigned short dclass; + unsigned short derr; + unsigned int nterr; } nt2doserr[] = { {ERRDOS, ERRgeneral, NT_STATUS_UNSUCCESSFUL}, {ERRDOS, ERRbadfunc, NT_STATUS_NOT_IMPLEMENTED}, @@ -614,7 +627,7 @@ static struct { {ERRHRD, ERRgeneral, NT_STATUS_APP_INIT_FAILURE}, {ERRHRD, ERRgeneral, NT_STATUS_PAGEFILE_CREATE_FAILED}, {ERRHRD, ERRgeneral, NT_STATUS_NO_PAGEFILE}, - {ERRDOS, 124, NT_STATUS_INVALID_LEVEL}, + {ERRDOS, ERRunknownlevel, NT_STATUS_INVALID_LEVEL}, {ERRDOS, 86, NT_STATUS_WRONG_PASSWORD_CORE}, {ERRHRD, ERRgeneral, NT_STATUS_ILLEGAL_FLOAT_CONTEXT}, {ERRDOS, 109, NT_STATUS_PIPE_BROKEN}, @@ -652,7 +665,8 @@ static struct { {ERRHRD, ERRgeneral, NT_STATUS_DISK_RESET_FAILED}, {ERRHRD, ERRgeneral, NT_STATUS_SHARED_IRQ_BUSY}, {ERRHRD, ERRgeneral, NT_STATUS_FT_ORPHANING}, - {ERRHRD, ERRgeneral, NT_STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT}, + {ERRHRD, ERRgeneral, + NT_STATUS_BIOS_FAILED_TO_CONNECT_INTERRUPT}, {ERRHRD, ERRgeneral, NT_STATUS_16F}, {ERRHRD, ERRgeneral, NT_STATUS_170}, {ERRHRD, ERRgeneral, NT_STATUS_171}, @@ -695,7 +709,7 @@ static struct { {ERRHRD, ERRgeneral, NT_STATUS_REMOTE_SESSION_LIMIT}, {ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_FILE_CHANGED}, {ERRDOS, ERRnoaccess, - NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT}, + NT_STATUS_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT}, {ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_WORKSTATION_TRUST_ACCOUNT}, {ERRDOS, ERRnoaccess, NT_STATUS_NOLOGON_SERVER_TRUST_ACCOUNT}, @@ -853,12 +867,13 @@ smb_maperror(int eclass, int eno) switch (eclass) { case ERRDOS: switch (eno) { + case ERRunknownlevel: + return (ENOTSUP); case ERRbadfunc: case ERRbadenv: case ERRbadformat: case ERRremcd: case ERRrmuns: - case ERRunknownlevel: return (EINVAL); case ERRbadfile: case ERRbadpath: @@ -910,7 +925,7 @@ smb_maperror(int eclass, int eno) case ERRnofiles: return (0); /* eeof ? */ case ERRlock: - return (EDEADLK); + return (EAGAIN); case ERRfilexists: return (EEXIST); case ERRinvalidname: /* samba maps as noent */ @@ -937,9 +952,7 @@ smb_maperror(int eclass, int eno) case ERRinvnid: return (ENETRESET); case ERRinvnetname: - SMBERROR("NetBIOS name is invalid: %d\n", - ERRinvnetname); - return (EAUTH); + return (ENXIO); case ERRbadtype: /* reserved and returned */ return (EIO); case ERRacctexpired: /* NT: account exists but disabled */ @@ -957,7 +970,7 @@ smb_maperror(int eclass, int eno) case ERRbadshare: return (ETXTBSY); case ERRlock: - return (EDEADLK); + return (EAGAIN); case ERRdiskfull: return (EFBIG); case ERRnotready: diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_time.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_time.c new file mode 100644 index 0000000000..e984ded911 --- /dev/null +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_time.c @@ -0,0 +1,353 @@ +/* + * Copyright (c) 2000-2001, Boris Popov + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Boris Popov. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id: smbfs_subr.c,v 1.18 2005/02/02 00:22:23 lindak Exp $ + */ + +/* + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Time conversion functions (to/from DOS, NT times) + * From BSD/Darwin smbfs_subr.c + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/time.h> +#include <sys/vnode.h> +#include <sys/sunddi.h> + +#include <netsmb/smb_osdep.h> + +#include <netsmb/smb.h> +#include <netsmb/smb_conn.h> +#include <netsmb/smb_subr.h> + +/* + * Time & date conversion routines taken from msdosfs. Although leap + * year calculation is bogus, it's sufficient before 2100 :) + */ +/* + * This is the format of the contents of the deTime field in the direntry + * structure. + * We don't use bitfields because we don't know how compilers for + * arbitrary machines will lay them out. + */ +#define DT_2SECONDS_MASK 0x1F /* seconds divided by 2 */ +#define DT_2SECONDS_SHIFT 0 +#define DT_MINUTES_MASK 0x7E0 /* minutes */ +#define DT_MINUTES_SHIFT 5 +#define DT_HOURS_MASK 0xF800 /* hours */ +#define DT_HOURS_SHIFT 11 + +/* + * This is the format of the contents of the deDate field in the direntry + * structure. + */ +#define DD_DAY_MASK 0x1F /* day of month */ +#define DD_DAY_SHIFT 0 +#define DD_MONTH_MASK 0x1E0 /* month */ +#define DD_MONTH_SHIFT 5 +#define DD_YEAR_MASK 0xFE00 /* year - 1980 */ +#define DD_YEAR_SHIFT 9 +/* + * Total number of days that have passed for each month in a regular year. + */ +static ushort_t regyear[] = { + 31, 59, 90, 120, 151, 181, + 212, 243, 273, 304, 334, 365 +}; + +/* + * Total number of days that have passed for each month in a leap year. + */ +static ushort_t leapyear[] = { + 31, 60, 91, 121, 152, 182, + 213, 244, 274, 305, 335, 366 +}; + +/* + * Variables used to remember parts of the last time conversion. Maybe we + * can avoid a full conversion. + */ +static ulong_t lasttime; +static ulong_t lastday; +static ushort_t lastddate; +static ushort_t lastdtime; + +/* Lock for the lastxxx variables */ +static kmutex_t lastdt_lock; + +/* + * Number of seconds between 1970 and 1601 year + * (134774 days) + */ +const uint64_t DIFF1970TO1601 = 11644473600ULL; +const uint32_t TEN_MIL = 10000000UL; + +/* + * Convert NT time (tenths of microseconds since 1601) + * to Unix seconds+nanoseconds since 1970. Any time + * earlier than 1970 is converted to Unix time zero. + * Both are GMT-based (no time zone adjustments). + */ +void +smb_time_NT2local(uint64_t nt_time, struct timespec *tsp) +{ + uint64_t nt_sec; /* seconds */ + uint64_t nt_tus; /* tenths of uSec. */ + + /* Optimize time zero. */ + if (nt_time == 0) { + tsp->tv_sec = 0; + tsp->tv_nsec = 0; + return; + } + + nt_sec = nt_time / TEN_MIL; + nt_tus = nt_time % TEN_MIL; + + if (nt_sec <= DIFF1970TO1601) { + tsp->tv_sec = 0; + tsp->tv_nsec = 0; + return; + } + tsp->tv_sec = nt_sec - DIFF1970TO1601; + tsp->tv_nsec = nt_tus * 100; +} + +/* + * Convert Unix time (seconds+nanoseconds since 1970) + * to NT time (tenths of microseconds since 1601). + * Exception: Convert time zero (really any time in + * the first second of 1970) to NT time zero. + * Both are GMT-based (no time zone adjustments). + */ +void +smb_time_local2NT(struct timespec *tsp, uint64_t *nt_time) +{ + uint64_t nt_sec; /* seconds */ + uint64_t nt_tus; /* tenths of uSec. */ + + if (tsp->tv_sec == 0) { + *nt_time = 0; + return; + } + + nt_sec = tsp->tv_sec + DIFF1970TO1601; + nt_tus = tsp->tv_nsec / 100; + + *nt_time = (uint64_t)nt_sec * TEN_MIL + nt_tus; +} + +/* + * Time zone conversion stuff, only used in old dialects. + * Don't adjust time zero for either conversion. + */ +void +smb_time_local2server(struct timespec *tsp, int tzoff, long *seconds) +{ + if (tsp->tv_sec <= (tzoff * 60)) + *seconds = 0; + else + *seconds = tsp->tv_sec - (tzoff * 60); +} + +void +smb_time_server2local(ulong_t seconds, int tzoff, struct timespec *tsp) +{ + if (seconds == 0) + tsp->tv_sec = 0; + else + tsp->tv_sec = seconds + tzoff * 60; + tsp->tv_nsec = 0; +} + +/* + * Time conversions to/from DOS format, for old dialects. + */ + +void +smb_time_unix2dos(struct timespec *tsp, int tzoff, u_int16_t *ddp, + u_int16_t *dtp, u_int8_t *dhp) +{ + long t; + ulong_t days, year, month, inc; + ushort_t *months; + + mutex_enter(&lastdt_lock); + + /* + * If the time from the last conversion is the same as now, then + * skip the computations and use the saved result. + */ + smb_time_local2server(tsp, tzoff, &t); + t &= ~1; + if (lasttime != t) { + lasttime = t; + if (t < 0) { + /* + * This is before 1970, so it's before 1980, + * and can't be represented as a DOS time. + * Just represent it as the DOS epoch. + */ + lastdtime = 0; + lastddate = (1 << DD_DAY_SHIFT) + + (1 << DD_MONTH_SHIFT) + + ((1980 - 1980) << DD_YEAR_SHIFT); + } else { + lastdtime = (((t / 2) % 30) << DT_2SECONDS_SHIFT) + + (((t / 60) % 60) << DT_MINUTES_SHIFT) + + (((t / 3600) % 24) << DT_HOURS_SHIFT); + + /* + * If the number of days since 1970 is the same as + * the last time we did the computation then skip + * all this leap year and month stuff. + */ + days = t / (24 * 60 * 60); + if (days != lastday) { + lastday = days; + for (year = 1970; ; year++) { + /* + * XXX - works in 2000, but won't + * work in 2100. + */ + inc = year & 0x03 ? 365 : 366; + if (days < inc) + break; + days -= inc; + } + /* + * XXX - works in 2000, but won't work in 2100. + */ + months = year & 0x03 ? regyear : leapyear; + for (month = 0; days >= months[month]; month++) + ; + if (month > 0) + days -= months[month - 1]; + lastddate = ((days + 1) << DD_DAY_SHIFT) + + ((month + 1) << DD_MONTH_SHIFT); + /* + * Remember DOS's idea of time is relative + * to 1980, but UN*X's is relative to 1970. + * If somehow we get a time before 1980 then + * don't give totally crazy results. + */ + if (year > 1980) + lastddate += (year - 1980) << + DD_YEAR_SHIFT; + } + } + } + if (dhp) + *dhp = (tsp->tv_sec & 1) * 100 + tsp->tv_nsec / 10000000; + + *ddp = lastddate; + *dtp = lastdtime; + + mutex_exit(&lastdt_lock); +} + +/* + * The number of seconds between Jan 1, 1970 and Jan 1, 1980. In that + * interval there were 8 regular years and 2 leap years. + */ +#define SECONDSTO1980 (((8 * 365) + (2 * 366)) * (24 * 60 * 60)) + +static ushort_t lastdosdate; +static ulong_t lastseconds; + +void +smb_dos2unixtime(uint_t dd, uint_t dt, uint_t dh, int tzoff, + struct timespec *tsp) +{ + ulong_t seconds; + ulong_t month; + ulong_t year; + ulong_t days; + ushort_t *months; + + if (dd == 0) { + tsp->tv_sec = 0; + tsp->tv_nsec = 0; + return; + } + seconds = (((dt & DT_2SECONDS_MASK) >> DT_2SECONDS_SHIFT) << 1) + + ((dt & DT_MINUTES_MASK) >> DT_MINUTES_SHIFT) * 60 + + ((dt & DT_HOURS_MASK) >> DT_HOURS_SHIFT) * 3600 + + dh / 100; + + /* + * If the year, month, and day from the last conversion are the + * same then use the saved value. + */ + mutex_enter(&lastdt_lock); + if (lastdosdate != dd) { + lastdosdate = (ushort_t)dd; + days = 0; + year = (dd & DD_YEAR_MASK) >> DD_YEAR_SHIFT; + days = year * 365; + days += year / 4 + 1; /* add in leap days */ + /* + * XXX - works in 2000, but won't work in 2100. + */ + if ((year & 0x03) == 0) + days--; /* if year is a leap year */ + months = year & 0x03 ? regyear : leapyear; + month = (dd & DD_MONTH_MASK) >> DD_MONTH_SHIFT; + if (month < 1 || month > 12) { + month = 1; + } + if (month > 1) + days += months[month - 2]; + days += ((dd & DD_DAY_MASK) >> DD_DAY_SHIFT) - 1; + lastseconds = (days * 24 * 60 * 60) + SECONDSTO1980; + } + smb_time_server2local(seconds + lastseconds, tzoff, tsp); + tsp->tv_nsec = (dh % 100) * 10000000; + mutex_exit(&lastdt_lock); +} + +void +smb_time_init(void) +{ + mutex_init(&lastdt_lock, NULL, MUTEX_DEFAULT, NULL); +} + +void +smb_time_fini(void) +{ + mutex_destroy(&lastdt_lock); +} diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.c index 7a646b48c7..79163f4afe 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.c +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_tran.c @@ -32,7 +32,6 @@ * Selected code from smb_conn.c */ -#pragma ident "%Z%%M% %I% %E% SMI" /* * Helper functions for smb_trantcp.c * (and maybe future transports) @@ -46,14 +45,8 @@ #include <netinet/in.h> #include <netinet/tcp.h> -/* Like smb_dev.h, this knows about all our sockaddr formats. */ -#include <netsmb/netbios.h> - -#ifdef APPLE -#include <sys/smb_apple.h> -#else #include <netsmb/smb_osdep.h> -#endif +#include <netsmb/netbios.h> #include <netsmb/smb.h> #include <netsmb/smb_conn.h> diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c index 1cd73649c4..566bc27e46 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_trantcp.c @@ -62,12 +62,7 @@ #include <netinet/in.h> #include <netinet/tcp.h> -#ifdef APPLE -#include <sys/smb_apple.h> -#else #include <netsmb/smb_osdep.h> -#endif - #include <netsmb/mchain.h> #include <netsmb/netbios.h> @@ -201,7 +196,7 @@ discon: * cleanup and state change on any call. */ freemsg(tm); - nb_disconnect(nbp); + (void) nb_disconnect(nbp); return (ENOTCONN); } @@ -261,7 +256,7 @@ nb_snddis(TIUSER *tiptr) /* * Stuff the NetBIOS header into space already prepended. */ -static int +static void nb_sethdr(mblk_t *m, uint8_t type, uint32_t len) { uint32_t *p; @@ -272,7 +267,6 @@ nb_sethdr(mblk_t *m, uint8_t type, uint32_t len) /*LINTED*/ p = (uint32_t *)m->b_rptr; *p = htonl(len); - return (0); } /* @@ -517,9 +511,9 @@ smb_nbst_done(struct smb_vc *vcp) * But it's harmless. */ if (nbp->nbp_flags & NBF_CONNECTED) - nb_disconnect(nbp); + (void) nb_disconnect(nbp); if (nbp->nbp_tiptr) - t_kclose(nbp->nbp_tiptr, 0); + (void) t_kclose(nbp->nbp_tiptr, 0); if (nbp->nbp_laddr) smb_free_sockaddr((struct sockaddr *)nbp->nbp_laddr); if (nbp->nbp_paddr) @@ -542,7 +536,7 @@ smb_nbst_loan_fp(struct smb_vc *vcp, struct file *fp, cred_t *cr) * Un-loan the existing one, if any. */ if (nbp->nbp_tiptr != NULL) { - t_kclose(nbp->nbp_tiptr, 0); + (void) t_kclose(nbp->nbp_tiptr, 0); nbp->nbp_tiptr = NULL; nbp->nbp_flags &= ~NBF_CONNECTED; nbp->nbp_state = NBST_CLOSED; @@ -595,6 +589,7 @@ nb_disconnect(struct nbpcb *nbp) { TIUSER *tiptr; int save_flags; + int err = 0; tiptr = nbp->nbp_tiptr; if (tiptr == NULL) @@ -610,12 +605,13 @@ nb_disconnect(struct nbpcb *nbp) mutex_exit(&nbp->nbp_lock); if (save_flags & NBF_CONNECTED) - nb_snddis(tiptr); + err = nb_snddis(tiptr); if (nbp->nbp_state != NBST_RETARGET) { nbp->nbp_state = NBST_CLOSED; } - return (0); + + return (err); } /* diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c b/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c index 19ef7bdc97..c4843e8578 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c +++ b/usr/src/uts/common/fs/smbclnt/netsmb/smb_usr.c @@ -194,7 +194,7 @@ smb_usr_simplerq(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) ioc->ioc_errclass = rqp->sr_errclass; ioc->ioc_serror = rqp->sr_serror; ioc->ioc_error = rqp->sr_error; - ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags); + (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags); out: if (rqp != NULL) @@ -310,7 +310,7 @@ smb_usr_t2request(smb_dev_t *sdp, intptr_t arg, int flags, cred_t *cr) ioc->ioc_error = t2p->t2_sr_error; ioc->ioc_rpflags2 = t2p->t2_sr_rpflags2; - ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags); + (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags); out: @@ -404,7 +404,7 @@ smb_usr_rw(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr) */ ioc->ioc_cnt -= auio.uio_resid; - ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags); + (void) ddi_copyout(ioc, (void *)arg, sizeof (*ioc), flags); out: if (ioc != NULL) @@ -612,7 +612,7 @@ smb_usr_get_tree(smb_dev_t *sdp, int cmd, intptr_t arg, int flags, cred_t *cr) * the tree connect response, so they can * see if they got the requested type. */ - memcpy(tcon->tc_sh.sh_type_ret, + (void) memcpy(tcon->tc_sh.sh_type_ret, ssp->ss_type_ret, SMBIOC_STYPE_LEN); /* diff --git a/usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c b/usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c index 525beb671d..ecd2322da7 100644 --- a/usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c +++ b/usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c @@ -48,12 +48,7 @@ #include <sys/sunddi.h> #include <sys/cmn_err.h> -#ifdef APPLE -#include <sys/smb_apple.h> -#else #include <netsmb/smb_osdep.h> -#endif - #include <netsmb/mchain.h> #include <netsmb/smb.h> @@ -623,7 +618,7 @@ md_done(struct mdchain *mdp) * Append a new message (separate mbuf chain). * It is caller responsibility to prevent * multiple calls to fetch/record routines. - * XXX: Note (mis)use of mblk->b_next here. + * Note unusual use of mblk->b_next here. */ void md_append_record(struct mdchain *mdp, mblk_t *top) @@ -644,23 +639,31 @@ md_append_record(struct mdchain *mdp, mblk_t *top) /* * Advance mdp->md_top to the next message. - * XXX: Note (mis)use of mblk->b_next here. + * Note unusual use of mblk->b_next here. */ -int +void md_next_record(struct mdchain *mdp) { - mblk_t *m; + mblk_t *m, *top; + + if ((top = mdp->md_top) == NULL) + return; - if (mdp->md_top == NULL) - return (ENOENT); - /* Get to next message (not b_cont chain) */ - m = mdp->md_top->b_next; - mdp->md_top->b_next = NULL; + /* + * Get the next message, if any, + * stored by md_append_record. + * Note: NOT b_cont chain + */ + m = top->b_next; + top->b_next = NULL; + + /* Done with old "top". */ md_done(mdp); if (m == NULL) - return (ENOENT); + return; + + /* Setup new "top". */ md_initm(mdp, m); - return (0); } /* @@ -961,7 +964,7 @@ m_copym(mblk_t *m, int off, int len, int wait) if (len < dsz) { adj = (ssize_t)len - (ssize_t)dsz; ASSERT(adj < 0); - adjmsg(n, adj); + (void) adjmsg(n, adj); } } diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs.h b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs.h index 9eb6cdbed3..68c626094a 100644 --- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs.h +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs.h @@ -50,7 +50,9 @@ #include <sys/param.h> #include <sys/fstyp.h> +#include <sys/avl.h> #include <sys/list.h> +#include <sys/t_lock.h> #include <sys/vfs.h> #include <sys/fs/smbfs_mount.h> @@ -85,11 +87,14 @@ struct smbnode; struct smb_share; /* - * The values for smi_flags. + * The values for smi_flags (from nfs_clnt.h) */ -#define SMI_INT 0x01 /* interrupts allowed */ -#define SMI_DEAD 0x02 /* zone shutting down */ +#define SMI_INT 0x04 /* interrupts allowed */ +#define SMI_NOAC 0x10 /* don't cache attributes */ #define SMI_LLOCK 0x80 /* local locking only */ +#define SMI_ACL 0x2000 /* share supports ACLs */ +#define SMI_EXTATTR 0x80000 /* share supports ext. attrs */ +#define SMI_DEAD 0x200000 /* mount has been terminated */ /* * Stuff returned by smbfs_smb_qfsattr @@ -118,6 +123,14 @@ typedef struct smbmntinfo { #define smi_fsattr smi_fsa.fsa_aflags /* + * The smbfs node cache for this mount. + * Named "hash" for historical reasons. + * See smbfs_node.h for details. + */ + avl_tree_t smi_hash_avl; + krwlock_t smi_hash_lk; + + /* * Kstat statistics */ struct kstat *smi_io_kstats; @@ -131,20 +144,34 @@ typedef struct smbmntinfo { /* Lock for the list is: smi_globals_t -> smg_lock */ /* - * Copy of the args from mount. + * Stuff copied or derived from the mount args */ - struct smbfs_args smi_args; + uid_t smi_uid; /* user id */ + gid_t smi_gid; /* group id */ + mode_t smi_fmode; /* mode for files */ + mode_t smi_dmode; /* mode for dirs */ + + hrtime_t smi_acregmin; /* min time to hold cached file attr */ + hrtime_t smi_acregmax; /* max time to hold cached file attr */ + hrtime_t smi_acdirmin; /* min time to hold cached dir attr */ + hrtime_t smi_acdirmax; /* max time to hold cached dir attr */ } smbmntinfo_t; -typedef struct smbfattr { - int fa_attr; - len_t fa_size; - struct timespec fa_atime; - struct timespec fa_ctime; - struct timespec fa_mtime; - ino64_t fa_ino; - struct timespec fa_reqtime; -} smbfattr_t; +/* + * Attribute cache timeout defaults (in seconds). + */ +#define SMBFS_ACREGMIN 3 /* min secs to hold cached file attr */ +#define SMBFS_ACREGMAX 60 /* max secs to hold cached file attr */ +#define SMBFS_ACDIRMIN 30 /* min secs to hold cached dir attr */ +#define SMBFS_ACDIRMAX 60 /* max secs to hold cached dir attr */ +/* and limits for the mount options */ +#define SMBFS_ACMINMAX 600 /* 10 min. is longest min timeout */ +#define SMBFS_ACMAXMAX 3600 /* 1 hr is longest max timeout */ + +/* + * High-res time is nanoseconds. + */ +#define SEC2HR(sec) ((sec) * (hrtime_t)NANOSEC) /* * vnode pointer to mount info diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c index e50e3b2389..81493f5783 100644 --- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_acl.c @@ -39,11 +39,11 @@ #include <sys/vfs.h> #include <sys/byteorder.h> -#include <netsmb/smb_osdep.h> +#include <netsmb/mchain.h> #include <netsmb/smb.h> #include <netsmb/smb_conn.h> +#include <netsmb/smb_osdep.h> #include <netsmb/smb_subr.h> -#include <netsmb/mchain.h> #include <smbfs/smbfs.h> #include <smbfs/smbfs_node.h> @@ -51,17 +51,15 @@ #include <sys/fs/smbfs_ioctl.h> #include <fs/fs_subr.h> +#include "smbfs_ntacl.h" /* Sanity check SD sizes */ #define MAX_RAW_SD_SIZE 32768 #define SMALL_SD_SIZE 1024 -#undef ACL_SUPPORT /* not yet */ - - /* - * smbfs_getsd(), smbfs_setsd() are common functions used by - * both ioctl get/set ACL and VOP_GETSECATTR, VOP_SETSECATTR. + * smbfs_getsd() is a common function used by both + * smbfs_ioctl SMBFSIO_GETSD and VOP_GETSECATTR. * Handles required rights, tmpopen/tmpclose. * * Note: smbfs_getsd allocates and returns an mblk chain, @@ -119,7 +117,7 @@ again: cerror = smbfs_smb_tmpclose(np, fid, &scred); if (cerror) - SMBERROR("error %d closing file %s\n", + SMBVDEBUG("error %d closing file %s\n", cerror, np->n_rpath); out: @@ -174,7 +172,7 @@ smbfs_setsd(vnode_t *vp, uint32_t selector, mblk_t **mp, cred_t *cr) cerror = smbfs_smb_tmpclose(np, fid, &scred); if (cerror) - SMBERROR("error %d closing file %s\n", + SMBVDEBUG("error %d closing file %s\n", cerror, np->n_rpath); out: @@ -185,7 +183,7 @@ out: } /* - * Entry points from VOP_IOCTL + * Helper for VOP_IOCTL: SMBFSIO_GETSD */ int smbfs_ioc_getsd(vnode_t *vp, intptr_t arg, int flag, cred_t *cr) @@ -245,6 +243,9 @@ out: return (error); } +/* + * Helper for VOP_IOCTL: SMBFSIO_SETSD + */ int smbfs_ioc_setsd(vnode_t *vp, intptr_t arg, int flag, cred_t *cr) { @@ -285,62 +286,26 @@ out: } -#ifdef ACL_SUPPORT -/* - * Conversion functions for VOP_GETSECATTR, VOP_SETSECATTR - * - * XXX: We may or may not add conversion code here, or we - * may add that to usr/src/common (TBD). For now all the - * ACL conversion code is in libsmbfs. - */ - -/* - * Convert a Windows SD (in the mdchain mdp) into a - * ZFS-style vsecattr_t and possibly uid, gid. - */ -/* ARGSUSED */ -static int -smb_ntsd2vsec(mdchain_t *mdp, vsecattr_t *vsa, - int *uidp, int *gidp, cred_t *cr) -{ - /* XXX NOT_YET */ - return (ENOSYS); -} - -/* - * Convert a ZFS-style vsecattr_t (and possibly uid, gid) - * into a Windows SD (built in the mbchain mbp). - */ -/* ARGSUSED */ -static int -smb_vsec2ntsd(vsecattr_t *vsa, int uid, int gid, - mbchain_t *mbp, cred_t *cr) -{ - /* XXX NOT_YET */ - return (ENOSYS); -} -#endif /* ACL_SUPPORT */ /* - * Entry points from VOP_GETSECATTR, VOP_SETSECATTR - * - * Disabled the real _getacl functionality for now, - * because we have no way to return the owner and - * primary group until we replace our fake uid/gid - * in getattr with something derived from _getsd. + * Helper for VOP_GETSECATTR + * Call smbfs_getsd, convert NT to ZFS form. */ /* ARGSUSED */ int smbfs_getacl(vnode_t *vp, vsecattr_t *vsa, - int *uidp, int *gidp, int flag, cred_t *cr) + uid_t *uidp, gid_t *gidp, int flag, cred_t *cr) { -#ifdef ACL_SUPPORT mdchain_t *mdp, md_store; - mblk_t *m; + mblk_t *m = NULL; + i_ntsd_t *sd = NULL; uint32_t selector; int error; + bzero(&md_store, sizeof (md_store)); + mdp = &md_store; + /* * Which parts of the SD we request. * XXX: We need a way to let the caller specify @@ -365,41 +330,51 @@ smbfs_getacl(vnode_t *vp, vsecattr_t *vsa, */ error = smbfs_getsd(vp, selector, &m, cr); if (error) - return (error); + goto out; + /* Note: allocated *m */ + md_initm(mdp, m); /* - * Have m. Must free it before return. + * Parse the OtW security descriptor, + * storing in our internal form. */ - mdp = &md_store; - md_initm(mdp, m); + error = md_get_ntsd(mdp, &sd); + if (error) + goto out; /* * Convert the Windows security descriptor to a * ZFS ACL (and owner ID, primary group ID). - * This is the difficult part. (todo) */ - error = smb_ntsd2vsec(mdp, vsa, uidp, gidp, cr); + error = smbfs_acl_sd2zfs(sd, vsa, uidp, gidp); +out: + if (sd != NULL) + smbfs_acl_free_sd(sd); /* Note: m_freem(m) is done by... */ md_done(mdp); return (error); -#else /* ACL_SUPPORT */ - return (ENOSYS); -#endif /* ACL_SUPPORT */ } +/* + * Helper for VOP_SETSECATTR + * Convert ZFS to NT form, call smbfs_setsd. + */ /* ARGSUSED */ int smbfs_setacl(vnode_t *vp, vsecattr_t *vsa, - int uid, int gid, int flag, cred_t *cr) + uid_t uid, gid_t gid, int flag, cred_t *cr) { -#ifdef ACL_SUPPORT mbchain_t *mbp, mb_store; + i_ntsd_t *sd = NULL; uint32_t selector; int error; + bzero(&mb_store, sizeof (mb_store)); + mbp = &mb_store; + /* * Which parts of the SD we'll modify. * Ditto comments above re. SACL @@ -407,25 +382,27 @@ smbfs_setacl(vnode_t *vp, vsecattr_t *vsa, selector = 0; if (vsa) selector |= DACL_SECURITY_INFORMATION; - if (uid != -1) + if (uid != (uid_t)-1) selector |= OWNER_SECURITY_INFORMATION; - if (gid != -1) + if (gid != (gid_t)-1) selector |= GROUP_SECURITY_INFORMATION; if (selector == 0) return (0); /* - * Setup buffer for SD data. + * Convert a ZFS ACL (and owner ID, group ID) + * into an NT SD, internal form. */ - mbp = &mb_store; - mb_init(mbp); + error = smbfs_acl_zfs2sd(vsa, uid, gid, &sd); + if (error) + goto out; /* - * Convert a ZFS ACL (and owner ID, group ID) - * to a Windows security descriptor. - * This is the difficult part. (todo) + * Marshall the internal form SD into an + * OtW security descriptor. */ - error = smb_vsec2ntsd(vsa, uid, gid, mbp, cr); + mb_init(mbp); + error = mb_put_ntsd(mbp, sd); if (error) goto out; @@ -436,9 +413,8 @@ smbfs_setacl(vnode_t *vp, vsecattr_t *vsa, error = smbfs_setsd(vp, selector, &mbp->mb_top, cr); out: + if (sd != NULL) + smbfs_acl_free_sd(sd); mb_done(mbp); return (error); -#else /* ACL_SUPPORT */ - return (ENOSYS); -#endif /* ACL_SUPPORT */ } diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c index fc089d4c33..c6d23011fe 100644 --- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_client.c @@ -40,7 +40,6 @@ #include <sys/cred.h> #include <sys/kmem.h> #include <sys/debug.h> -#include <sys/dnlc.h> #include <sys/vmsystm.h> #include <sys/flock.h> #include <sys/share.h> @@ -54,7 +53,9 @@ #include <sys/list.h> #include <sys/zone.h> +#include <netsmb/smb.h> #include <netsmb/smb_conn.h> +#include <netsmb/smb_subr.h> #include <smbfs/smbfs.h> #include <smbfs/smbfs_node.h> @@ -68,6 +69,10 @@ #include <vm/seg_map.h> #include <vm/seg_vn.h> +static int smbfs_getattr_cache(vnode_t *, struct smbfattr *); +static int smbfattr_to_vattr(vnode_t *, struct smbfattr *, + struct vattr *); + /* * The following code provide zone support in order to perform an action * for each smbfs mount in a zone. This is also where we would add @@ -84,6 +89,437 @@ typedef struct smi_globals smi_globals_t; static zone_key_t smi_list_key; +/* + * Attributes caching: + * + * Attributes are cached in the smbnode in struct vattr form. + * There is a time associated with the cached attributes (r_attrtime) + * which tells whether the attributes are valid. The time is initialized + * to the difference between current time and the modify time of the vnode + * when new attributes are cached. This allows the attributes for + * files that have changed recently to be timed out sooner than for files + * that have not changed for a long time. There are minimum and maximum + * timeout values that can be set per mount point. + */ + +/* + * Validate caches by checking cached attributes. If they have timed out + * get the attributes from the server and compare mtimes. If mtimes are + * different purge all caches for this vnode. + */ +int +smbfs_validate_caches( + struct vnode *vp, + cred_t *cr) +{ + struct vattr va; + + va.va_mask = AT_SIZE; + return (smbfsgetattr(vp, &va, cr)); +} + +/* + * Purge all of the various data caches. + */ +/*ARGSUSED*/ +void +smbfs_purge_caches(struct vnode *vp) +{ +#if 0 /* not yet: mmap support */ + /* + * NFS: Purge the DNLC for this vp, + * Clear any readdir state bits, + * the readlink response cache, ... + */ + smbnode_t *np = VTOSMB(vp); + + /* + * Flush the page cache. + */ + if (vn_has_cached_data(vp)) { + (void) VOP_PUTPAGE(vp, (u_offset_t)0, 0, B_INVAL, cr, NULL); + } +#endif /* not yet */ +} + +/* + * Check the attribute cache to see if the new attributes match + * those cached. If they do, the various `data' caches are + * considered to be good. Otherwise, purge the cached data. + */ +void +smbfs_cache_check( + struct vnode *vp, + struct smbfattr *fap) +{ + smbnode_t *np; + int purge_data = 0; +#if 0 /* not yet: ACL support */ + int purge_acl = 0; + vsecattr_t *vsp = NULL; +#endif /* not yet */ + + np = VTOSMB(vp); + mutex_enter(&np->r_statelock); + + /* + * Compare with NFS macro: CACHE_VALID + * If the mtime or size has changed, + * purge cached data. + */ + if (np->r_attr.fa_mtime.tv_sec != fap->fa_mtime.tv_sec || + np->r_attr.fa_mtime.tv_nsec != fap->fa_mtime.tv_nsec) + purge_data = 1; + if (np->r_attr.fa_size != fap->fa_size) + purge_data = 1; + +#if 0 /* not yet: ACL support */ + if (np->r_attr.fa_ctime.tv_sec != fap->fa_ctime.tv_sec || + np->r_attr.fa_ctime.tv_nsec != fap->fa_ctime.tv_nsec) + purge_acl = 1; +#endif /* not yet */ + + mutex_exit(&np->r_statelock); + + if (purge_data) + smbfs_purge_caches(vp); + +#if 0 /* not yet: ACL support */ + if (purge_acl) { + vsecattr_t *vsp; + + if (np->r_secattr != NULL) { + mutex_enter(&np->r_statelock); + vsp = np->r_secattr; + np->r_secattr = NULL; + mutex_exit(&np->r_statelock); + if (vsp != NULL) + smbfs_acl_free(vsp); + } + } +#endif /* not yet */ +} + +/* + * Set attributes cache for given vnode using vnode attributes. + * From NFS: nfs_attrcache_va + */ +#if 0 /* not yet (not sure if we need this) */ +void +smbfs_attrcache_va(vnode_t *vp, struct vattr *vap) +{ + smbfattr_t fa; + smbnode_t *np; + + vattr_to_fattr(vp, vap, &fa); + smbfs_attrcache_fa(vp, &fa); +} +#endif /* not yet */ + +/* + * Set attributes cache for given vnode using SMB fattr + * and update the attribute cache timeout. + * + * From NFS: nfs_attrcache, nfs_attrcache_va + */ +void +smbfs_attrcache_fa(vnode_t *vp, struct smbfattr *fap) +{ + smbnode_t *np; + smbmntinfo_t *smi; + hrtime_t delta, now; + u_offset_t newsize; + vtype_t vtype, oldvt; + mode_t mode; + + np = VTOSMB(vp); + smi = VTOSMI(vp); + + /* + * We allow v_type to change, so set that here + * (and the mode, which is derived from it). + */ + if (fap->fa_attr & SMB_FA_DIR) { + vtype = VDIR; + mode = S_IFDIR | smi->smi_dmode; + } else { + vtype = VREG; + mode = S_IFREG | smi->smi_fmode; + } + + /* + * For now, n_uid/n_gid never change after they are + * set by: smbfs_node_findcreate / make_smbnode. + * Later, they will change in getsecattr. + */ + + mutex_enter(&np->r_statelock); + + now = gethrtime(); + + /* + * Delta is the number of nanoseconds that we will + * cache the attributes of the file. It is based on + * the number of nanoseconds since the last time that + * we detected a change. The assumption is that files + * that changed recently are likely to change again. + * There is a minimum and a maximum for regular files + * and for directories which is enforced though. + * + * Using the time since last change was detected + * eliminates direct comparison or calculation + * using mixed client and server times. SMBFS + * does not make any assumptions regarding the + * client and server clocks being synchronized. + */ + if (fap->fa_mtime.tv_sec != np->r_attr.fa_mtime.tv_sec || + fap->fa_mtime.tv_nsec != np->r_attr.fa_mtime.tv_nsec || + fap->fa_size != np->r_attr.fa_size) + np->r_mtime = now; + + if ((smi->smi_flags & SMI_NOAC) || (vp->v_flag & VNOCACHE)) + delta = 0; + else { + delta = now - np->r_mtime; + if (vtype == VDIR) { + if (delta < smi->smi_acdirmin) + delta = smi->smi_acdirmin; + else if (delta > smi->smi_acdirmax) + delta = smi->smi_acdirmax; + } else { + if (delta < smi->smi_acregmin) + delta = smi->smi_acregmin; + else if (delta > smi->smi_acregmax) + delta = smi->smi_acregmax; + } + } + + np->r_attrtime = now + delta; + np->r_attr = *fap; + np->n_mode = mode; + oldvt = vp->v_type; + vp->v_type = vtype; + + /* + * Shall we update r_size? (local notion of size) + * + * The real criteria for updating r_size should be: + * if the file has grown on the server, or if + * the client has not modified the file. + * + * Also deal with the fact that SMB presents + * directories as having size=0. Doing that + * here and leaving fa_size as returned OtW + * avoids fixing the size lots of places. + */ + newsize = fap->fa_size; + if (vtype == VDIR && newsize < DEV_BSIZE) + newsize = DEV_BSIZE; + + if (np->r_size != newsize) { +#if 0 /* not yet: mmap support */ + if (!vn_has_cached_data(vp) || ...) + /* XXX: See NFS page cache code. */ +#endif /* not yet */ + /* OK to set the size. */ + np->r_size = newsize; + } + + /* NFS: np->r_flags &= ~RWRITEATTR; */ + np->n_flag &= ~NATTRCHANGED; + + mutex_exit(&np->r_statelock); + + if (oldvt != vtype) { + SMBVDEBUG("vtype change %d to %d\n", oldvt, vtype); + } +} + +/* + * Fill in attribute from the cache. + * + * If valid, copy to *fap and return zero, + * otherwise return an error. + * + * From NFS: nfs_getattr_cache() + */ +int +smbfs_getattr_cache(vnode_t *vp, struct smbfattr *fap) +{ + smbnode_t *np; + int error; + + np = VTOSMB(vp); + + mutex_enter(&np->r_statelock); + if (gethrtime() >= np->r_attrtime) { + /* cache expired */ + error = ENOENT; + } else { + /* cache is valid */ + *fap = np->r_attr; + error = 0; + } + mutex_exit(&np->r_statelock); + + return (error); +} + +/* + * Get attributes over-the-wire and update attributes cache + * if no error occurred in the over-the-wire operation. + * Return 0 if successful, otherwise error. + * From NFS: nfs_getattr_otw + */ +int +smbfs_getattr_otw(vnode_t *vp, struct smbfattr *fap, cred_t *cr) +{ + struct smbnode *np; + struct smb_cred scred; + int error; + + np = VTOSMB(vp); + + /* + * NFS uses the ACL rpc here + * (if smi_flags & SMI_ACL) + */ + + /* Shared lock for (possible) n_fid use. */ + if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp))) + return (EINTR); + smb_credinit(&scred, cr); + + bzero(fap, sizeof (*fap)); + error = smbfs_smb_getfattr(np, fap, &scred); + + smb_credrele(&scred); + smbfs_rw_exit(&np->r_lkserlock); + + if (error) { + /* NFS had: PURGE_STALE_FH(error, vp, cr) */ + smbfs_attrcache_remove(np); + if (error == ENOENT || error == ENOTDIR) { + /* + * Getattr failed because the object was + * removed or renamed by another client. + * Remove any cached attributes under it. + */ + smbfs_attrcache_prune(np); + } + return (error); + } + + /* + * NFS: smbfs_cache_fattr(vap, fa, vap, t, cr); + * which did: fattr_to_vattr, nfs_attr_cache. + * We cache the fattr form, so just do the + * cache check and store the attributes. + */ + smbfs_cache_check(vp, fap); + smbfs_attrcache_fa(vp, fap); + + return (0); +} + +/* + * Return either cached or remote attributes. If get remote attr + * use them to check and invalidate caches, then cache the new attributes. + * + * From NFS: nfsgetattr() + */ +int +smbfsgetattr(vnode_t *vp, struct vattr *vap, cred_t *cr) +{ + struct smbfattr fa; + int error; + + ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone); + + /* + * If we've got cached attributes, just use them; + * otherwise go to the server to get attributes, + * which will update the cache in the process. + */ + error = smbfs_getattr_cache(vp, &fa); + if (error) + error = smbfs_getattr_otw(vp, &fa, cr); + if (error) + return (error); + + /* + * Re. client's view of the file size, see: + * smbfs_attrcache_fa, smbfs_getattr_otw + */ + + error = smbfattr_to_vattr(vp, &fa, vap); + return (error); +} + + +/* + * Convert SMB over the wire attributes to vnode form. + * Returns 0 for success, error if failed (overflow, etc). + * From NFS: nattr_to_vattr() + */ +int +smbfattr_to_vattr(vnode_t *vp, struct smbfattr *fa, struct vattr *vap) +{ + struct smbnode *np = VTOSMB(vp); + + vap->va_mask = AT_ALL; + + /* + * Take type, mode, uid, gid from the smbfs node, + * which has have been updated by _getattr_otw. + */ + vap->va_type = vp->v_type; + vap->va_mode = np->n_mode; + + vap->va_uid = np->n_uid; + vap->va_gid = np->n_gid; + + vap->va_fsid = vp->v_vfsp->vfs_dev; + vap->va_nodeid = np->n_ino; + vap->va_nlink = 1; + + /* + * Difference from NFS here: We cache attributes as + * reported by the server, so r_attr.fa_size is the + * server's idea of the file size. This is called + * for getattr, so we want to return the client's + * idea of the file size. NFS deals with that in + * nfsgetattr(), the equivalent of our caller. + */ + vap->va_size = np->r_size; + + /* + * Times. Note, already converted from NT to + * Unix form (in the unmarshalling code). + */ + vap->va_atime = fa->fa_atime; + vap->va_mtime = fa->fa_mtime; + vap->va_ctime = fa->fa_ctime; + + /* + * rdev, blksize, seq are made up. + * va_nblocks is 512 byte blocks. + */ + vap->va_rdev = vp->v_rdev; + vap->va_blksize = MAXBSIZE; + vap->va_nblocks = (fsblkcnt64_t)btod(np->r_attr.fa_allocsz); + vap->va_seq = 0; + + return (0); +} + + +/* + * SMB Client initialization and cleanup. + * Much of it is per-zone now. + */ + + /* ARGSUSED */ static void * smbfs_zone_init(zoneid_t zoneid) @@ -127,11 +563,6 @@ again: */ VFS_HOLD(smi->smi_vfsp); - /* - * purge the DNLC for this filesystem - */ - (void) dnlc_purge_vfsp(smi->smi_vfsp, 0); - mutex_enter(&smi->smi_lock); smi->smi_flags |= SMI_DEAD; mutex_exit(&smi->smi_lock); @@ -252,11 +683,7 @@ smb_fscb_t smbfs_cb = { int smbfs_clntinit(void) { - int error; - error = smbfs_subrinit(); - if (error) - return (error); zone_key_create(&smi_list_key, smbfs_zone_init, smbfs_zone_shutdown, smbfs_zone_destroy); #ifdef NEED_SMBFS_CALLBACKS @@ -276,5 +703,4 @@ smbfs_clntfini(void) smb_fscb_set(NULL); #endif /* NEED_SMBFS_CALLBACKS */ (void) zone_key_delete(smi_list_key); - smbfs_subrfini(); } diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.c index 594dedecc0..6c8eda5a87 100644 --- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.c +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.c @@ -33,15 +33,14 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#pragma ident "%Z%%M% %I% %E% SMI" - #include <sys/param.h> #include <sys/systm.h> #include <sys/cred.h> +#include <sys/time.h> #include <sys/vfs.h> #include <sys/vnode.h> #include <sys/kmem.h> @@ -51,11 +50,7 @@ #include <sys/sysmacros.h> #include <sys/bitmap.h> -#ifdef APPLE -#include <sys/smb_apple.h> -#else #include <netsmb/smb_osdep.h> -#endif #include <netsmb/smb.h> #include <netsmb/smb_conn.h> @@ -65,10 +60,6 @@ #include <smbfs/smbfs_node.h> #include <smbfs/smbfs_subr.h> -#if defined(DEBUG) || defined(lint) -#define SMBFS_NAME_DEBUG -#endif - /* * Lack of inode numbers leads us to the problem of generating them. * Partially this problem can be solved by having a dir/file cache @@ -83,8 +74,8 @@ #define FNV_32_PRIME ((uint32_t)0x01000193UL) #define FNV1_32_INIT ((uint32_t)33554467UL) -uint32_t -smbfs_hash3(uint32_t ival, const char *name, int nmlen) +static inline uint32_t +smbfs_hash(uint32_t ival, const char *name, int nmlen) { uint32_t v; @@ -95,166 +86,104 @@ smbfs_hash3(uint32_t ival, const char *name, int nmlen) return (v); } +/* + * Compute the hash of the full (remote) path name + * using the three parts supplied separately. + */ uint32_t -smbfs_hash(const char *name, int nmlen) +smbfs_gethash(const char *rpath, int rplen) { uint32_t v; - v = smbfs_hash3(FNV1_32_INIT, name, nmlen); + v = smbfs_hash(FNV1_32_INIT, rpath, rplen); return (v); } /* - * This is basically a hash of the full path name, but - * computed without having the full path contiguously. - * The path building logic needs to match what - * smbfs_fullpath does. - * - * Note that smbfs_make_node computes inode numbers by - * calling smbfs_hash on the full path name. This will - * compute the same result given the directory path and - * the last component separately. + * Like smbfs_gethash, but optimized a little by + * starting with the directory hash. */ uint32_t smbfs_getino(struct smbnode *dnp, const char *name, int nmlen) { uint32_t ino; + char sep; /* Start with directory hash */ ino = (uint32_t)dnp->n_ino; - /* - * If not the root, hash a slash. - */ - if (dnp->n_rplen > 1) - ino = smbfs_hash3(ino, "\\", 1); + /* separator (maybe) */ + sep = SMBFS_DNP_SEP(dnp); + if (sep) + ino = smbfs_hash(ino, &sep, 1); /* Now hash this component. */ - ino = smbfs_hash3(ino, name, nmlen); + ino = smbfs_hash(ino, name, nmlen); return (ino); } -#define CHAR_FC '\374' /* 0xFC */ -#define CHAR_FE '\376' /* 0xFE */ +/* + * Allocate and copy a string of passed length. + * The passed length does NOT include the null. + */ char * smbfs_name_alloc(const char *name, int nmlen) { char *cp; - size_t alen; -#ifdef SMBFS_NAME_DEBUG - /* - * Note: The passed length is strlen(name), - * and does NOT include the terminating nul. - * Allocated space holds: (in order) - * (int)strlen - * char 0xFC (1st marker) - * copy of string - * terminating null - * char 0xFE (2nd marker) - */ - alen = sizeof (int) + 1 + nmlen + 1 + 1; - cp = kmem_alloc(alen, KM_SLEEP); - /*LINTED*/ - *(int *)cp = nmlen; - cp += sizeof (int); - cp[0] = CHAR_FC; - cp++; - bcopy(name, cp, nmlen); - cp[nmlen] = 0; - cp[nmlen + 1] = CHAR_FE; -#else - alen = nmlen + 1; /* Passed length does NOT include the nul. */ - cp = kmem_alloc(alen, KM_SLEEP); + cp = kmem_alloc(nmlen + 1, KM_SLEEP); bcopy(name, cp, nmlen); cp[nmlen] = 0; -#endif + return (cp); } /* - * Note: Passed length does NOT include the nul, - * the same as with smbfs_name_alloc(). + * Free string from smbfs_name_alloc(). Again, + * the passed length does NOT include the null. */ void smbfs_name_free(const char *name, int nmlen) { - size_t alen; -#ifdef SMBFS_NAME_DEBUG - int lnmlen; - char *cp; - - /* - * See comment in smbfs_name_alloc - * about the layout of this memory. - */ - alen = sizeof (int) + 1 + nmlen + 1 + 1; - cp = (char *)name; - cp--; - if (*cp != CHAR_FC) { - debug_enter("smbfs_name_free: name[-1] != 0xFC"); - } - cp -= sizeof (int); - /*LINTED*/ - lnmlen = *(int *)cp; - if (lnmlen != nmlen) { - debug_enter("smbfs_name_free: name[-5] != nmlen"); - } - if (name[nmlen + 1] != CHAR_FE) { - debug_enter("smbfs_name_free: name[nmlen+1] != 0xFE"); - } - kmem_free(cp, alen); -#else - alen = nmlen + 1; - kmem_free((char *)name, alen); -#endif + kmem_free((char *)name, nmlen + 1); } /* * smbfs_nget() * - * NOTES: - * - * It would be nice to be able to pass in a flag when the caller is sure - * that the node does not exist and should just be allocated. + * Find or create a node under some directory node. */ int smbfs_nget(vnode_t *dvp, const char *name, int nmlen, - struct smbfattr *fap, vnode_t **vpp) + struct smbfattr *fap, vnode_t **vpp) { struct smbnode *dnp = VTOSMB(dvp); struct smbnode *np; vnode_t *vp; char sep; + ASSERT(fap != NULL); *vpp = NULL; - /* Don't expect "." or ".." here anymore. */ - if ((nmlen == 1 && name[0] == '.') || + /* Don't expect "" or "." or ".." here anymore. */ + if (nmlen == 0 || (nmlen == 1 && name[0] == '.') || (nmlen == 2 && name[0] == '.' && name[1] == '.')) { - DEBUG_ENTER("smbfs_nget: name is '.' or '..'"); return (EINVAL); } - - /* - * See the comment near the top of smbfs_xattr.c about - * the logic for what separators to use where. - */ - sep = (dnp->n_flag & N_XATTR) ? 0 : '\\'; + sep = SMBFS_DNP_SEP(dnp); /* Find or create the node. */ - vp = smbfs_make_node(dvp->v_vfsp, + np = smbfs_node_findcreate(dnp->n_mount, dnp->n_rpath, dnp->n_rplen, name, nmlen, sep, fap); /* - * We always have a vp now, because - * smbfs_make_node / make_smbnode - * calls kmem_alloc with KM_SLEEP. + * We should have np now, because we passed + * fap != NULL to smbfs_node_findcreate. */ - ASSERT(vp); - np = VTOSMB(vp); + ASSERT(np != NULL); + vp = SMBTOV(np); /* * Files in an XATTR dir are also XATTR. @@ -265,248 +194,57 @@ smbfs_nget(vnode_t *dvp, const char *name, int nmlen, mutex_exit(&np->r_statelock); } -#ifdef NOT_YET - /* update the attr_cache info if the file is clean */ - if (fap && !(VTOSMB(vp)->n_flag & NFLUSHWIRE)) - smbfs_attr_cacheenter(vp, fap); - if (dvp && makeentry) { - /* add entry to DNLC */ - cache_enter(dvp, vp, &cn); - } -#endif /* NOT_YET */ - /* BSD symlink hack removed (smb_symmagic) */ -#ifdef NOT_YET - smbfs_attr_cacheenter(vp, fap); /* update the attr_cache info */ -#endif /* NOT_YET */ - *vpp = vp; return (0); } /* - * routines to maintain vnode attributes cache - * smbfs_attr_cacheenter: unpack np.i to vnode_vattr structure - * - * Note that some SMB servers do not exhibit POSIX behaviour - * with regard to the mtime on directories. To work around - * this, we never allow the mtime on a directory to go backwards, - * and bump it forwards elsewhere to simulate the correct - * behaviour. + * smbfs_attrcache_enter, smbfs_attrcache_lookup replaced by + * code more closely resembling NFS. See smbfs_client.c */ -void -smbfs_attr_cacheenter(vnode_t *vp, struct smbfattr *fap) -{ - struct smbnode *np = VTOSMB(vp); - int vtype; - struct timespec ts; - - mutex_enter(&np->r_statelock); - - vtype = (fap->fa_attr & SMB_FA_DIR) ? VDIR : VREG; - if (vp->v_type != vtype) - SMBVDEBUG("vtype change %d to %d\n", - vp->v_type, vtype); - vp->v_type = vtype; - - if (vtype == VREG) { - if (np->n_size != fap->fa_size) { - /* - * Had Darwin ubc_sync_range call here, - * invalidating the truncated range. - * XXX: Solaris equivalent? - */ - SMBVDEBUG("Update size?\n"); - } - np->n_size = fap->fa_size; - } else if (vtype == VDIR) { - np->n_size = 16384; /* XXX should be a better way ... */ - /* - * Don't allow mtime to go backwards. - * Yes this has its flaws. Better ideas are welcome! - */ - /*CSTYLED*/ - if (timespeccmp(&fap->fa_mtime, &np->n_mtime, <)) - fap->fa_mtime = np->n_mtime; - } else if (vtype != VLNK) - goto out; - - np->n_atime = fap->fa_atime; - np->n_ctime = fap->fa_ctime; - np->n_mtime = fap->fa_mtime; - np->n_dosattr = fap->fa_attr; - - np->n_flag &= ~NATTRCHANGED; - gethrestime(&ts); - np->n_attrage = ts.tv_sec; - -out: - mutex_exit(&np->r_statelock); -} - -int -smbfs_attr_cachelookup(vnode_t *vp, struct vattr *vap) -{ - struct smbnode *np = VTOSMB(vp); - struct smbmntinfo *smi = VTOSMI(vp); - time_t attrtimeo; - struct timespec ts, *stime; - mode_t type; - - /* - * Determine attrtimeo. It will be something between SMB_MINATTRTIMO and - * SMB_MAXATTRTIMO where recently modified files have a short timeout - * and files that haven't been modified in a long time have a long - * timeout. This is the same algorithm used by NFS. - */ - gethrestime(&ts); - stime = &np->r_mtime; - attrtimeo = (ts.tv_sec - stime->tv_sec) / 10; - if (attrtimeo < SMB_MINATTRTIMO) { - attrtimeo = SMB_MINATTRTIMO; - } else if (attrtimeo > SMB_MAXATTRTIMO) - attrtimeo = SMB_MAXATTRTIMO; - /* has too much time passed? */ - stime = (struct timespec *)&np->r_attrtime; - if ((ts.tv_sec - stime->tv_sec) > attrtimeo) - return (ENOENT); - - if (!vap) - return (0); - - switch (vp->v_type) { - case VREG: - type = S_IFREG; - break; - case VLNK: - type = S_IFLNK; - break; - case VDIR: - type = S_IFDIR; - break; - default: - SMBSDEBUG("unknown vnode_vtype %d\n", vp->v_type); - return (EINVAL); - } - - mutex_enter(&np->r_statelock); - - if (!(np->n_flag & NGOTIDS)) { - np->n_mode = type; -#ifdef APPLE - if (smi->smi_fsattr & FILE_PERSISTENT_ACLS) { - /* XXX: Can this block? Drop r_statelock? */ - if (!smbfs_getids(np, scredp)) { - np->n_flag |= NGOTIDS; - np->n_mode |= ACCESSPERMS; /* 0777 */ - } - } -#endif /* APPLE */ - if (!(np->n_flag & NGOTIDS)) { - np->n_flag |= NGOTIDS; - np->n_uid = smi->smi_args.uid; - np->n_gid = smi->smi_args.gid; - } - } - - if (vap->va_mask & AT_TYPE) - vap->va_type = vp->v_type; - if (vap->va_mask & AT_MODE) { - np->n_mode = 0; - if (vp->v_type == VDIR) - np->n_mode |= smi->smi_args.dir_mode; - else /* symlink and regular file */ - np->n_mode |= smi->smi_args.file_mode; - vap->va_mode = np->n_mode; - } - if (vap->va_mask & AT_SIZE) - vap->va_size = np->n_size; - if (vap->va_mask & AT_NODEID) - vap->va_nodeid = np->n_ino; - if (vap->va_mask & AT_ATIME) - vap->va_atime = np->n_atime; - if (vap->va_mask & AT_CTIME) - vap->va_ctime = np->n_ctime; - if (vap->va_mask & AT_MTIME) - vap->va_mtime = np->n_mtime; - vap->va_nlink = 1; - vap->va_uid = np->n_uid; - vap->va_gid = np->n_gid; - vap->va_fsid = vp->v_vfsp->vfs_dev; - vap->va_rdev = 0; - vap->va_blksize = MAXBSIZE; - vap->va_nblocks = (fsblkcnt64_t)btod(np->n_size); - vap->va_seq = 0; - - mutex_exit(&np->r_statelock); - - return (0); -} /* - * Some SMB servers don't exhibit POSIX behaviour with regard to - * updating the directory mtime when the directory's contents - * change. - * - * We force the issue here by updating our cached copy of the mtime - * whenever we perform such an action ourselves, and then mark the - * cache invalid. Subsequently when the invalidated cache entry is - * updated, we disallow an update that would move the mtime backwards. - * - * This preserves correct or near-correct behaviour with a - * compliant server, and gives near-correct behaviour with - * a non-compliant server in the most common case (we are the - * only client changing the directory). - * - * There are also complications if a server's time is ahead - * of our own. We must 'touch' a directory when it is first - * created, to ensure that the timestamp starts out sane, - * however it may have a timestamp well ahead of the 'touch' - * point which will be returned and cached the first time the - * directory's attributes are fetched. Subsequently, the - * directory's mtime will not appear to us to change at all - * until our local time catches up to the server. - * - * Thus, any time a directory is 'touched', the saved timestamp - * must advance at least far enough forwards to be visible to - * the stat(2) interface. - * - * XXX note that better behaviour with non-compliant servers - * could be obtained by bumping the mtime forwards when - * an update for an invalidated entry returns a nonsensical - * mtime. + * Update the local notion of the mtime of some directory. + * See comments re. r_mtime in smbfs_node.h */ - void smbfs_attr_touchdir(struct smbnode *dnp) { - struct timespec ts, ta; mutex_enter(&dnp->r_statelock); /* - * XXX - not sure about this... - * Creep the saved time forwards far enough that - * layers above the kernel will notice. - */ - ta.tv_sec = 1; - ta.tv_nsec = 0; - timespecadd(&dnp->n_mtime, &ta); - /* - * If the current time is later than the updated - * saved time, apply it instead. + * Now that we keep the client's notion of mtime + * separately from the server, this is easy. */ - gethrestime(&ts); - /*CSTYLED*/ - if (timespeccmp(&dnp->n_mtime, &ts, <)) - dnp->n_mtime = ts; + dnp->r_mtime = gethrtime(); + /* * Invalidate the cache, so that we go to the wire * to check that the server doesn't have a better * timestamp next time we care. */ - smbfs_attr_cacheremove(dnp); + smbfs_attrcache_rm_locked(dnp); mutex_exit(&dnp->r_statelock); } + +void +smbfs_attrcache_remove(struct smbnode *np) +{ + mutex_enter(&np->r_statelock); + /* smbfs_attrcache_rm_locked(np); */ + np->r_attrtime = gethrtime(); + mutex_exit(&np->r_statelock); +} + +/* See smbfs_node.h */ +#undef smbfs_attrcache_rm_locked +void +smbfs_attrcache_rm_locked(struct smbnode *np) +{ + ASSERT(MUTEX_HELD(&np->r_statelock)); + np->r_attrtime = gethrtime(); +} diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h index 08e31e0d4d..a85ceb5f60 100644 --- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_node.h @@ -42,6 +42,7 @@ /* * Much code copied into here from Sun NFS. + * Compare with nfs_clnt.h */ #include <sys/avl.h> @@ -51,6 +52,32 @@ extern "C" { #endif +/* + * These are the attributes we can get from the server via + * SMB commands such as TRANS2_QUERY_FILE_INFORMATION + * with info level SMB_QFILEINFO_ALL_INFO, and directory + * FindFirst/FindNext info. levels FIND_DIRECTORY_INFO + * and FIND_BOTH_DIRECTORY_INFO, etc. + * + * Values in this struct are always native endian, + * and times are converted converted to Unix form. + * Note: zero in any of the times means "unknown". + * + * XXX: Later, move this to nsmb + */ +typedef struct smbfattr { + timespec_t fa_createtime; /* Note, != ctime */ + timespec_t fa_atime; /* these 3 are like unix */ + timespec_t fa_mtime; + timespec_t fa_ctime; + u_offset_t fa_size; /* EOF position */ + u_offset_t fa_allocsz; /* Allocated size. */ + uint32_t fa_attr; /* Ext. file (DOS) attr */ +} smbfattr_t; + +/* + * Cache whole directories (not yet) + */ typedef struct rddir_cache { lloff_t _cookie; /* cookie used to find this cache entry */ lloff_t _ncookie; /* cookie used to find the next cache entry */ @@ -93,32 +120,59 @@ typedef struct smbfs_rwlock { } smbfs_rwlock_t; /* - * The format of the hash bucket used to lookup smbnodes from a file handle. + * The format of the smbfs node header, which contains the + * fields used to link nodes in the AVL tree, and those + * fields needed by the AVL node comparison functions. + * It's a separate struct so we can call avl_find with + * this relatively small struct as a stack local. + * + * The AVL tree is mntinfo.smi_hash_avl, + * and its lock is mntinfo.smi_hash_lk. */ -typedef struct rhashq { - struct smbnode *r_hashf; - struct smbnode *r_hashb; - krwlock_t r_lock; -} rhashq_t; +typedef struct smbfs_node_hdr { + /* + * Our linkage in the node cache AVL tree. + */ + avl_node_t hdr_avl_node; + + /* + * Identity of this node: The full path name, + * in server form, relative to the share root. + */ + char *hdr_n_rpath; + int hdr_n_rplen; +} smbfs_node_hdr_t; /* - * Remote file information structure. + * Below is the SMBFS-specific representation of a "node". + * This struct is a mixture of Sun NFS and Darwin code. + * Fields starting with "r_" came from NFS struct "rnode" + * and fields starting with "n_" came from Darwin, or + * were added during the Solaris port. We have avoided + * renaming fields so we would not cause excessive + * changes in the code using this struct. + * + * Now using an AVL tree instead of hash lists, but kept the + * "hash" in some member names and functions to reduce churn. + * One AVL tree per mount replaces the global hash buckets. + * + * Notes carried over from the NFS code: * * The smbnode is the "inode" for remote files. It contains all the * information necessary to handle remote file on the client side. * * Note on file sizes: we keep two file sizes in the smbnode: the size * according to the client (r_size) and the size according to the server - * (r_attr.va_size). They can differ because we modify r_size during a + * (r_attr.fa_size). They can differ because we modify r_size during a * write system call (smbfs_rdwr), before the write request goes over the * wire (before the file is actually modified on the server). If an OTW * request occurs before the cached data is written to the server the file - * size returned from the server (r_attr.va_size) may not match r_size. - * r_size is the one we use, in general. r_attr.va_size is only used to + * size returned from the server (r_attr.fa_size) may not match r_size. + * r_size is the one we use, in general. r_attr.fa_size is only used to * determine whether or not our cached data is valid. * * Each smbnode has 3 locks associated with it (not including the smbnode - * hash table and free list locks): + * "hash" AVL tree and free list locks): * * r_rwlock: Serializes smbfs_write and smbfs_setattr requests * and allows smbfs_read requests to proceed in parallel. @@ -133,13 +187,12 @@ typedef struct rhashq { * time (not accross entire putpage operations, * for example). * - * The following members are protected by the mutex rpfreelist_lock: + * The following members are protected by the mutex smbfreelist_lock: * r_freef * r_freeb * - * The following members are protected by the hash bucket rwlock: - * r_hashf - * r_hashb + * The following members are protected by the AVL tree rwlock: + * r_avl_node (r__hdr.hdr_avl_node) * * Note: r_modaddr is only accessed when the r_statelock mutex is held. * Its value is also controlled via r_rwlock. It is assumed that @@ -156,99 +209,98 @@ typedef struct rhashq { * Lock ordering: * r_rwlock > r_lkserlock > r_statelock */ -struct exportinfo; /* defined in smbfs/export.h */ -struct failinfo; /* defined in smbfs/smbfs_clnt.h */ -struct mntinfo; /* defined in smbfs/smbfs_clnt.h */ - -#ifdef _KERNEL -/* Bits for smbnode.n_flag */ -#define NFLUSHINPROG 0x00001 -#define NFLUSHWANT 0x00002 /* they should gone ... */ -#define NMODIFIED 0x00004 /* bogus, until async IO implemented */ -#define NREFPARENT 0x00010 /* node holds parent from recycling */ -#define NGOTIDS 0x00020 -#define NRDIRSERIAL 0x00080 /* serialize readdir operation */ -#define NISMAPPED 0x00800 -#define NFLUSHWIRE 0x01000 -#define NATTRCHANGED 0x02000 /* use smbfs_attr_cacheremove at close */ -#define NALLOC 0x04000 /* being created */ -#define NWALLOC 0x08000 /* awaiting creation */ -#define N_XATTR 0x10000 /* extended attribute (dir or file) */ typedef struct smbnode { - /* from Sun NFS struct rnode (XXX: cleanup needed) */ - /* the hash fields must be first to match the rhashq_t */ - /* Lock for the hash queue is: np->r_hashq->r_lock */ - struct smbnode *r_hashf; /* hash queue forward pointer */ - struct smbnode *r_hashb; /* hash queue back pointer */ - /* Lock for the free list is: smbfreelist_lock */ + /* Our linkage in the node cache AVL tree (see above). */ + smbfs_node_hdr_t r__hdr; + + /* short-hand names for r__hdr members */ +#define r_avl_node r__hdr.hdr_avl_node +#define n_rpath r__hdr.hdr_n_rpath +#define n_rplen r__hdr.hdr_n_rplen + + smbmntinfo_t *n_mount; /* VFS data */ + vnode_t *r_vnode; /* associated vnode */ + + /* + * Linkage in smbfreelist, for reclaiming nodes. + * Lock for the free list is: smbfreelist_lock + */ struct smbnode *r_freef; /* free list forward pointer */ struct smbnode *r_freeb; /* free list back pointer */ - rhashq_t *r_hashq; /* pointer to the hash bucket */ - vnode_t *r_vnode; /* vnode for remote file */ - smbfs_rwlock_t r_rwlock; /* serializes write/setattr requests */ + + smbfs_rwlock_t r_rwlock; /* serialize write/setattr requests */ smbfs_rwlock_t r_lkserlock; /* serialize lock with other ops */ - kmutex_t r_statelock; /* protects (most of) smbnode fields */ - u_offset_t r_nextr; /* next byte read offset (read-ahead) */ + kmutex_t r_statelock; /* protect (most) smbnode fields */ + + /* + * File handle, directory search handle, + * and reference counts for them, etc. + * Lock for these is: r_lkserlock + */ + int n_dirrefs; + struct smbfs_fctx *n_dirseq; /* ff context */ + int n_dirofs; /* last ff offset */ + int n_fidrefs; + uint16_t n_fid; /* file handle */ + enum vtype n_ovtype; /* vnode type opened */ + uint32_t n_rights; /* granted rights */ + int n_vcgenid; /* gereration no. (reconnect) */ + + /* + * Misc. bookkeeping + */ cred_t *r_cred; /* current credentials */ - len_t r_size; /* client's view of file size */ - struct vattr r_attr; /* cached vnode attributes */ - hrtime_t r_attrtime; /* time attributes become invalid */ + u_offset_t r_nextr; /* next read offset (read-ahead) */ long r_mapcnt; /* count of mmapped pages */ uint_t r_count; /* # of refs not reflect in v_count */ uint_t r_awcount; /* # of outstanding async write */ uint_t r_gcount; /* getattrs waiting to flush pages */ - ushort_t r_flags; /* flags, see below */ - short r_error; /* async write error */ + uint_t r_flags; /* flags, see below */ + uint32_t n_flag; /* NXXX flags below */ + uint_t r_error; /* async write error */ kcondvar_t r_cv; /* condvar for blocked threads */ avl_tree_t r_dir; /* cache of readdir responses */ rddir_cache *r_direof; /* pointer to the EOF entry */ kthread_t *r_serial; /* id of purging thread */ list_t r_indelmap; /* list of delmap callers */ + /* - * Members derived from Darwin struct smbnode. - * Note: n_parent node pointer removed because it - * caused unwanted "holds" on nodes in our cache. - * Now keeping just the full remote path instead, - * in server form, relative to the share root. + * Attributes: local, and as last seen on the server. + * See notes above re: r_size vs r_attr.fa_size, etc. */ - char *n_rpath; - int n_rplen; - uint32_t n_flag; - smbmntinfo_t *n_mount; - ino64_t n_ino; - /* Lock for the next 7 is r_lkserlock */ - enum vtype n_ovtype; /* vnode type opened */ - int n_dirrefs; - struct smbfs_fctx *n_dirseq; /* ff context */ - int n_dirofs; /* last ff offset */ - int n_vcgenid; /* gereration no. (reconnect) */ - int n_fidrefs; - uint16_t n_fid; /* file handle */ - uint32_t n_rights; /* granted rights */ - /* Lock for the rest is r_statelock */ + smbfattr_t r_attr; /* attributes from the server */ + hrtime_t r_attrtime; /* time attributes become invalid */ + hrtime_t r_mtime; /* client time file last modified */ + len_t r_size; /* client's view of file size */ + + /* + * Other attributes, not carried in smbfattr_t + */ + u_longlong_t n_ino; uid_t n_uid; gid_t n_gid; mode_t n_mode; - timestruc_t r_atime; - timestruc_t r_ctime; - timestruc_t r_mtime; - int n_dosattr; - /* - * XXX: Maybe use this instead: - * #define n_atime r_attr.va_atime - * etc. - */ -#define n_size r_size -#define n_atime r_atime -#define n_ctime r_ctime -#define n_mtime r_mtime -#define n_attrage r_attrtime } smbnode_t; -#endif /* _KERNEL */ /* - * Flags + * Flag bits in: smbnode_t .n_flag + */ +#define NFLUSHINPROG 0x00001 +#define NFLUSHWANT 0x00002 /* they should gone ... */ +#define NMODIFIED 0x00004 /* bogus, until async IO implemented */ +#define NREFPARENT 0x00010 /* node holds parent from recycling */ +#define NGOTIDS 0x00020 +#define NRDIRSERIAL 0x00080 /* serialize readdir operation */ +#define NISMAPPED 0x00800 +#define NFLUSHWIRE 0x01000 +#define NATTRCHANGED 0x02000 /* kill cached attributes at close */ +#define NALLOC 0x04000 /* being created */ +#define NWALLOC 0x08000 /* awaiting creation */ +#define N_XATTR 0x10000 /* extended attribute (dir or file) */ + +/* + * Flag bits in: smbnode_t .r_flags */ #define RREADDIRPLUS 0x1 /* issue a READDIRPLUS instead of READDIR */ #define RDIRTY 0x2 /* dirty pages from write operation */ @@ -258,7 +310,7 @@ typedef struct smbnode { #define RHAVEVERF 0x20 /* have a write verifier to compare against */ #define RCOMMIT 0x40 /* commit in progress */ #define RCOMMITWAIT 0x80 /* someone is waiting to do a commit */ -#define RHASHED 0x100 /* smbnode is in hash queues */ +#define RHASHED 0x100 /* smbnode is in the "hash" AVL tree */ #define ROUTOFSPACE 0x200 /* an out of space error has happened */ #define RDIRECTIO 0x400 /* bypass the buffer cache */ #define RLOOKUP 0x800 /* a lookup has been performed */ @@ -272,27 +324,12 @@ typedef struct smbnode { #define VTOSMB(vp) ((smbnode_t *)((vp)->v_data)) #define SMBTOV(np) ((np)->r_vnode) -/* Attribute cache timeouts in seconds */ -#define SMB_MINATTRTIMO 2 -#define SMB_MAXATTRTIMO 30 - /* - * Function definitions. + * A macro to compute the separator that should be used for + * names under some directory. See smbfs_fullpath(). */ -struct smb_cred; -int smbfs_nget(vnode_t *dvp, const char *name, int nmlen, - struct smbfattr *fap, vnode_t **vpp); -void smbfs_attr_cacheenter(vnode_t *vp, struct smbfattr *fap); -int smbfs_attr_cachelookup(vnode_t *vp, struct vattr *va); -void smbfs_attr_touchdir(struct smbnode *dnp); -char *smbfs_name_alloc(const char *name, int nmlen); -void smbfs_name_free(const char *name, int nmlen); -uint32_t smbfs_hash(const char *name, int nmlen); -uint32_t smbfs_hash3(uint32_t ival, const char *name, int nmlen); -uint32_t smbfs_getino(struct smbnode *dnp, const char *name, int nmlen); -int smb_check_table(struct vfs *vfsp, smbnode_t *srp); - -#define smbfs_attr_cacheremove(np) (np)->n_attrage = 0 +#define SMBFS_DNP_SEP(dnp) \ + (((dnp->n_flag & N_XATTR) == 0 && dnp->n_rplen > 1) ? '\\' : '\0') #ifdef __cplusplus } diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c index 63c34c26d0..aa27feac67 100644 --- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_smb.c @@ -44,12 +44,7 @@ #include <sys/sunddi.h> #include <sys/cmn_err.h> -#ifdef APPLE -#include <sys/smb_apple.h> -#include <sys/utfconv.h> -#else #include <netsmb/smb_osdep.h> -#endif #include <netsmb/smb.h> #include <netsmb/smb_conn.h> @@ -61,38 +56,37 @@ #include <smbfs/smbfs_subr.h> /* + * Jan 1 1980 as 64 bit NT time. + * (tenths of microseconds since 1601) + */ +const uint64_t NT1980 = 11960035200ULL*10000000ULL; + +/* * Local functions. * Not static, to aid debugging. */ -int smbfs_smb_qfileinfo(struct smbnode *np, struct smbfattr *fap, - struct smb_cred *scrp, short infolevel); -int smbfs_smb_qpathinfo(struct smbnode *np, struct smbfattr *fap, - struct smb_cred *scrp, short infolevel); int smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen, struct smbfattr *fap, struct smb_cred *scrp); +int smbfs_smb_trans2_query(struct smbnode *np, struct smbfattr *fap, + struct smb_cred *scrp, uint16_t infolevel); int smbfs_smb_statfsLM1(struct smb_share *ssp, statvfs64_t *sbp, struct smb_cred *scrp); int smbfs_smb_statfsLM2(struct smb_share *ssp, statvfs64_t *sbp, struct smb_cred *scrp); +int smbfs_smb_setfattrNT(struct smbnode *np, int fid, + uint32_t attr, struct timespec *mtime, struct timespec *atime, + struct smb_cred *scrp); + int smbfs_smb_setftime1(struct smbnode *np, uint16_t fid, struct timespec *mtime, struct timespec *atime, struct smb_cred *scrp); -int smbfs_smb_setfattrNT(struct smbnode *np, uint16_t fid, - uint32_t attr, struct timespec *mtime, struct timespec *atime, - struct smb_cred *scrp); int smbfs_smb_setpattr1(struct smbnode *np, const char *name, int len, uint32_t attr, struct timespec *mtime, struct smb_cred *scrp); -int smbfs_smb_setpattr2(struct smbnode *np, uint32_t attr, - struct timespec *mtime, struct timespec *atime, - struct smb_cred *scrp); -int smbfs_smb_setpattrNT(struct smbnode *np, uint32_t attr, - struct timespec *mtime, struct timespec *atime, - struct smb_cred *scrp); /* @@ -120,6 +114,7 @@ smbfs_smb_lockandx(struct smbnode *np, int op, uint32_t pid, if (op == SMB_LOCK_SHARED) ltype |= SMB_LOCKING_ANDX_SHARED_LOCK; + /* XXX: if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)? */ if (largelock) ltype |= SMB_LOCKING_ANDX_LARGE_FILES; error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_LOCKING_ANDX, scrp); @@ -177,9 +172,13 @@ smbfs_smb_lock(struct smbnode *np, int op, caddr_t id, * TODO: use LOCK_BYTE_RANGE here. */ return (EINVAL); - else - return (smbfs_smb_lockandx(np, op, (uint32_t)id, start, len, - largelock, scrp, timeout)); + + /* + * XXX: compute largelock via: + * (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES)? + */ + return (smbfs_smb_lockandx(np, op, (uint32_t)id, start, len, + largelock, scrp, timeout)); } #endif /* APPLE */ @@ -197,8 +196,7 @@ smbfs_smb_getfattr( int error; /* - * This lock is really only necessary for qfileinfo, - * but hopefully we use that most of the time. + * This lock is necessary for FID-based calls. * Lock may be writer (via open) or reader. */ ASSERT(np->r_lkserlock.count != 0); @@ -211,35 +209,22 @@ smbfs_smb_getfattr( return (error); } - if (np->n_fidrefs) - error = smbfs_smb_qfileinfo(np, fap, scrp, 0); - else - error = smbfs_smb_qpathinfo(np, fap, scrp, 0); + error = smbfs_smb_trans2_query(np, fap, scrp, 0); + if (error != EINVAL) + return (error); - if (error == EINVAL) { - /* fallback */ - error = smbfs_smb_query_info(np, NULL, 0, fap, scrp); - } - - /* - * Note directory size is not provided by - * windows servers (they leave it as zero) - */ - if ((fap->fa_attr & SMB_FA_DIR) && - (fap->fa_size < DEV_BSIZE)) - fap->fa_size = DEV_BSIZE; + /* fallback */ + error = smbfs_smb_query_info(np, NULL, 0, fap, scrp); return (error); } - /* - * Nearly identical to smbfs_smb_qfileinfo (below). - * Please keep them in sync. + * Common function for QueryFileInfo, QueryPathInfo. */ int -smbfs_smb_qpathinfo(struct smbnode *np, struct smbfattr *fap, - struct smb_cred *scrp, short infolevel) +smbfs_smb_trans2_query(struct smbnode *np, struct smbfattr *fap, + struct smb_cred *scrp, uint16_t infolevel) { struct smb_share *ssp = np->n_mount->smi_share; struct smb_vc *vcp = SSTOVC(ssp); @@ -247,139 +232,7 @@ smbfs_smb_qpathinfo(struct smbnode *np, struct smbfattr *fap, int error, svtz, timesok = 1; struct mbchain *mbp; struct mdchain *mdp; - uint16_t date, time, wattr; - uint64_t llongint, lsize; - uint32_t size, dattr; - -top: - error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_PATH_INFORMATION, - scrp, &t2p); - if (error) - return (error); - mbp = &t2p->t2_tparam; - mb_init(mbp); - if (!infolevel) { - if (SMB_DIALECT(vcp) < SMB_DIALECT_NTLM0_12) - infolevel = SMB_QFILEINFO_STANDARD; - else - infolevel = SMB_QFILEINFO_ALL_INFO; - } - mb_put_uint16le(mbp, infolevel); - mb_put_uint32le(mbp, 0); - /* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */ - error = smbfs_fullpath(mbp, vcp, np, NULL, NULL, '\\'); - if (error) { - smb_t2_done(t2p); - return (error); - } - t2p->t2_maxpcount = 2; - t2p->t2_maxdcount = vcp->vc_txmax; - error = smb_t2_request(t2p); - if (error) { - smb_t2_done(t2p); - /* Invalid info level? Try fallback. */ - if (error == EINVAL && - infolevel == SMB_QFILEINFO_ALL_INFO) { - infolevel = SMB_QFILEINFO_STANDARD; - goto top; - } - return (error); - } - mdp = &t2p->t2_rdata; - svtz = vcp->vc_sopt.sv_tz; - switch (infolevel) { - case SMB_QFILEINFO_STANDARD: - timesok = 0; - md_get_uint16le(mdp, NULL); - md_get_uint16le(mdp, NULL); /* creation time */ - md_get_uint16le(mdp, &date); - md_get_uint16le(mdp, &time); /* access time */ - if (date || time) { - timesok++; - smb_dos2unixtime(date, time, 0, svtz, &fap->fa_atime); - } - md_get_uint16le(mdp, &date); - md_get_uint16le(mdp, &time); /* modify time */ - if (date || time) { - timesok++; - smb_dos2unixtime(date, time, 0, svtz, &fap->fa_mtime); - } - md_get_uint32le(mdp, &size); - fap->fa_size = size; - md_get_uint32le(mdp, NULL); /* allocation size */ - md_get_uint16le(mdp, &wattr); - fap->fa_attr = wattr; - break; - case SMB_QFILEINFO_ALL_INFO: - timesok = 0; - /* creation time (discard) */ - md_get_uint64le(mdp, NULL); - /* last access time */ - md_get_uint64le(mdp, &llongint); - if (llongint) { - timesok++; - smb_time_NT2local(llongint, svtz, &fap->fa_atime); - } - /* last write time */ - md_get_uint64le(mdp, &llongint); - if (llongint) { - timesok++; - smb_time_NT2local(llongint, svtz, &fap->fa_mtime); - } - /* last change time */ - md_get_uint64le(mdp, &llongint); - if (llongint) { - timesok++; - smb_time_NT2local(llongint, svtz, &fap->fa_ctime); - } - /* attributes */ - md_get_uint32le(mdp, &dattr); - fap->fa_attr = dattr; - /* - * 4-Byte alignment - discard - * Specs doesn't talk about this. - */ - md_get_uint32le(mdp, NULL); - /* allocation size (discard) */ - md_get_uint64le(mdp, NULL); - /* File size */ - md_get_uint64le(mdp, &lsize); - fap->fa_size = lsize; - break; - default: - SMBVDEBUG("unexpected info level %d\n", infolevel); - error = EINVAL; - } - smb_t2_done(t2p); - /* - * if all times are zero (observed with FAT on NT4SP6) - * then fall back to older info level - */ - if (!timesok) { - if (infolevel == SMB_QFILEINFO_ALL_INFO) { - infolevel = SMB_QFILEINFO_STANDARD; - goto top; - } - error = EINVAL; - } - return (error); -} - -/* - * Nearly identical to smbfs_smb_qpathinfo (above). - * Please keep them in sync. - */ -int -smbfs_smb_qfileinfo(struct smbnode *np, struct smbfattr *fap, - struct smb_cred *scrp, short infolevel) -{ - struct smb_share *ssp = np->n_mount->smi_share; - struct smb_vc *vcp = SSTOVC(ssp); - struct smb_t2rq *t2p; - int error, svtz, timesok = 1; - struct mbchain *mbp; - struct mdchain *mdp; - uint16_t date, time, wattr; + uint16_t cmd, date, time, wattr; uint64_t llongint, lsize; uint32_t size, dattr; @@ -389,16 +242,18 @@ smbfs_smb_qfileinfo(struct smbnode *np, struct smbfattr *fap, */ ASSERT(np->r_lkserlock.count != 0); - /* After reconnect, n_fid is invalid */ - if (np->n_vcgenid != ssp->ss_vcgenid) - return (ESTALE); - - if (np->n_fid == SMB_FID_UNUSED) - return (EBADF); + /* + * If we have a valid open FID, use it. + */ + if ((np->n_fidrefs > 0) && + (np->n_fid != SMB_FID_UNUSED) && + (np->n_vcgenid == ssp->ss_vcgenid)) + cmd = SMB_TRANS2_QUERY_FILE_INFORMATION; + else + cmd = SMB_TRANS2_QUERY_PATH_INFORMATION; top: - error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_QUERY_FILE_INFORMATION, - scrp, &t2p); + error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p); if (error) return (error); mbp = &t2p->t2_tparam; @@ -409,8 +264,22 @@ top: else infolevel = SMB_QFILEINFO_ALL_INFO; } - mb_put_uint16le(mbp, np->n_fid); + + if (cmd == SMB_TRANS2_QUERY_FILE_INFORMATION) + mb_put_uint16le(mbp, np->n_fid); + mb_put_uint16le(mbp, infolevel); + + if (cmd == SMB_TRANS2_QUERY_PATH_INFORMATION) { + mb_put_uint32le(mbp, 0); + /* mb_put_uint8(mbp, SMB_DT_ASCII); specs are wrong */ + error = smbfs_fullpath(mbp, vcp, np, NULL, NULL, '\\'); + if (error) { + smb_t2_done(t2p); + return (error); + } + } + t2p->t2_maxpcount = 2; t2p->t2_maxdcount = vcp->vc_txmax; error = smb_t2_request(t2p); @@ -428,61 +297,63 @@ top: svtz = vcp->vc_sopt.sv_tz; switch (infolevel) { case SMB_QFILEINFO_STANDARD: - timesok = 0; - md_get_uint16le(mdp, NULL); - md_get_uint16le(mdp, NULL); /* creation time */ + md_get_uint16le(mdp, &date); + md_get_uint16le(mdp, &time); /* creation time */ + smb_dos2unixtime(date, time, 0, svtz, &fap->fa_createtime); md_get_uint16le(mdp, &date); md_get_uint16le(mdp, &time); /* access time */ - if (date || time) { - timesok++; - smb_dos2unixtime(date, time, 0, svtz, &fap->fa_atime); - } + smb_dos2unixtime(date, time, 0, svtz, &fap->fa_atime); md_get_uint16le(mdp, &date); md_get_uint16le(mdp, &time); /* modify time */ - if (date || time) { - timesok++; - smb_dos2unixtime(date, time, 0, svtz, &fap->fa_mtime); - } - md_get_uint32le(mdp, &size); + smb_dos2unixtime(date, time, 0, svtz, &fap->fa_mtime); + md_get_uint32le(mdp, &size); /* EOF position */ fap->fa_size = size; - md_get_uint32le(mdp, NULL); /* allocation size */ - md_get_uint16le(mdp, &wattr); + md_get_uint32le(mdp, &size); /* allocation size */ + fap->fa_allocsz = size; + error = md_get_uint16le(mdp, &wattr); fap->fa_attr = wattr; + timesok = 1; break; case SMB_QFILEINFO_ALL_INFO: timesok = 0; - /* creation time (discard) */ - md_get_uint64le(mdp, NULL); + /* creation time */ + md_get_uint64le(mdp, &llongint); + if (llongint) + timesok++; + smb_time_NT2local(llongint, &fap->fa_createtime); + /* last access time */ md_get_uint64le(mdp, &llongint); - if (llongint) { + if (llongint) timesok++; - smb_time_NT2local(llongint, svtz, &fap->fa_atime); - } + smb_time_NT2local(llongint, &fap->fa_atime); + /* last write time */ md_get_uint64le(mdp, &llongint); - if (llongint) { + if (llongint) timesok++; - smb_time_NT2local(llongint, svtz, &fap->fa_mtime); - } + smb_time_NT2local(llongint, &fap->fa_mtime); + /* last change time */ md_get_uint64le(mdp, &llongint); - if (llongint) { + if (llongint) timesok++; - smb_time_NT2local(llongint, svtz, &fap->fa_ctime); - } + smb_time_NT2local(llongint, &fap->fa_ctime); + /* attributes */ md_get_uint32le(mdp, &dattr); fap->fa_attr = dattr; + /* * 4-Byte alignment - discard - * Specs doesn't talk about this. + * Specs don't talk about this. */ md_get_uint32le(mdp, NULL); - /* allocation size (discard) */ - md_get_uint64le(mdp, NULL); - /* File size */ + /* allocation size */ md_get_uint64le(mdp, &lsize); + fap->fa_allocsz = lsize; + /* File size */ + error = md_get_uint64le(mdp, &lsize); fap->fa_size = lsize; break; default: @@ -529,14 +400,15 @@ smbfs_smb_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *fsa, t2p->t2_maxpcount = 4; t2p->t2_maxdcount = 4 * 3 + 512; error = smb_t2_request(t2p); - if (error) { - smb_t2_done(t2p); - return (error); - } + if (error) + goto out; + mdp = &t2p->t2_rdata; md_get_uint32le(mdp, &fsa->fsa_aflags); md_get_uint32le(mdp, &fsa->fsa_maxname); - md_get_uint32le(mdp, &nlen); /* fs name length */ + error = md_get_uint32le(mdp, &nlen); /* fs name length */ + if (error) + goto out; /* * Get the FS type name. @@ -548,7 +420,7 @@ smbfs_smb_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *fsa, if (nlen > sizeof (tmpbuf)) nlen = sizeof (tmpbuf); - md_get_mem(mdp, tmpbuf, nlen, MB_MSYSTEM); + error = md_get_mem(mdp, tmpbuf, nlen, MB_MSYSTEM); tmplen = nlen / 2; /* UCS-2 chars */ outlen = FSTYPSZ - 1; (void) uconv_u16tou8(tmpbuf, &tmplen, @@ -557,9 +429,19 @@ smbfs_smb_qfsattr(struct smb_share *ssp, struct smb_fs_attr_info *fsa, } else { if (nlen > (FSTYPSZ - 1)) nlen = FSTYPSZ - 1; - md_get_mem(mdp, fsa->fsa_tname, nlen, MB_MSYSTEM); + error = md_get_mem(mdp, fsa->fsa_tname, nlen, MB_MSYSTEM); + } + + /* + * If fs_name starts with FAT, we can't set dates before 1980 + */ + if (0 == strncmp(fsa->fsa_tname, "FAT", 3)) { + SMB_SS_LOCK(ssp); + ssp->ss_flags |= SMBS_FST_FAT; + SMB_SS_UNLOCK(ssp); } +out: smb_t2_done(t2p); return (0); } @@ -600,16 +482,17 @@ smbfs_smb_statfsLM2(struct smb_share *ssp, statvfs64_t *sbp, t2p->t2_maxpcount = 4; t2p->t2_maxdcount = 4 * 4 + 2; error = smb_t2_request(t2p); - if (error) { - smb_t2_done(t2p); - return (error); - } + if (error) + goto out; + mdp = &t2p->t2_rdata; md_get_uint32le(mdp, NULL); /* fs id */ md_get_uint32le(mdp, &bpu); md_get_uint32le(mdp, &units); md_get_uint32le(mdp, &funits); - md_get_uint16le(mdp, &bsize); + error = md_get_uint16le(mdp, &bsize); + if (error) + goto out; s = bsize; s *= bpu; t = units; @@ -638,6 +521,8 @@ smbfs_smb_statfsLM2(struct smb_share *ssp, statvfs64_t *sbp, sbp->f_bavail = f; /* free blocks avail to non-superuser */ sbp->f_files = (-1); /* total file nodes in file system */ sbp->f_ffree = (-1); /* free file nodes in fs */ + +out: smb_t2_done(t2p); return (0); } @@ -661,15 +546,16 @@ smbfs_smb_statfsLM1(struct smb_share *ssp, statvfs64_t *sbp, smb_rq_bstart(rqp); smb_rq_bend(rqp); error = smb_rq_simple(rqp); - if (error) { - smb_rq_done(rqp); - return (error); - } + if (error) + goto out; + smb_rq_getreply(rqp, &mdp); md_get_uint16le(mdp, &units); md_get_uint16le(mdp, &bpu); md_get_uint16le(mdp, &bsize); - md_get_uint16le(mdp, &funits); + error = md_get_uint16le(mdp, &funits); + if (error) + goto out; s = bsize; s *= bpu; t = units; @@ -698,6 +584,8 @@ smbfs_smb_statfsLM1(struct smb_share *ssp, statvfs64_t *sbp, sbp->f_bavail = f; /* free blocks avail to non-superuser */ sbp->f_files = (-1); /* total file nodes in file system */ sbp->f_ffree = (-1); /* free file nodes in fs */ + +out: smb_rq_done(rqp); return (0); } @@ -722,12 +610,10 @@ smbfs_smb_seteof(struct smb_share *ssp, uint16_t fid, uint64_t newsize, mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFORMATION); else mb_put_uint16le(mbp, SMB_SFILEINFO_END_OF_FILE_INFO); - mb_put_uint32le(mbp, 0); /* XXX should be 16 not 32(?) */ + mb_put_uint16le(mbp, 0); /* pad */ mbp = &t2p->t2_tdata; mb_init(mbp); mb_put_uint64le(mbp, newsize); - mb_put_uint32le(mbp, 0); /* padding */ - mb_put_uint16le(mbp, 0); t2p->t2_maxpcount = 2; t2p->t2_maxdcount = 0; error = smb_t2_request(t2p); @@ -791,7 +677,8 @@ exit: if (fid) { cerror = smbfs_smb_tmpclose(tdnp, fid, scrp); if (cerror) - SMBERROR("error %d closing fid %d\n", cerror, fid); + SMBVDEBUG("error %d closing %s\n", + cerror, tdnp->n_rpath); } smb_t2_done(t2p); return (error); @@ -845,24 +732,17 @@ smbfs_smb_setfsize(struct smbnode *np, uint16_t fid, uint64_t newsize, struct mbchain *mbp; int error; - /* - * This call knows about 64-bit offsets. - */ - error = smbfs_smb_seteof(ssp, fid, newsize, scrp); - if (!error) { - mutex_enter(&np->r_statelock); - np->n_flag |= (NFLUSHWIRE | NATTRCHANGED); - mutex_exit(&np->r_statelock); - return (0); - } - - /* - * If we have SMB_CAP_LARGE_FILES, the above - * should have worked. XXX: Don't fallback? - * XXX: Or fallback on specific errors? - */ - if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_LARGE_FILES) { - SMBVDEBUG("Have CAP_LARGE but _seteof error=%d\n", error); + if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { + /* + * This call knows about 64-bit offsets. + */ + error = smbfs_smb_seteof(ssp, fid, newsize, scrp); + if (!error) { + mutex_enter(&np->r_statelock); + np->n_flag |= (NFLUSHWIRE | NATTRCHANGED); + mutex_exit(&np->r_statelock); + return (0); + } } /* @@ -894,6 +774,9 @@ smbfs_smb_setfsize(struct smbnode *np, uint16_t fid, uint64_t newsize, return (error); } +/* + * Old method for getting file attributes. + */ int smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen, struct smbfattr *fap, struct smb_cred *scrp) @@ -915,79 +798,39 @@ smbfs_smb_query_info(struct smbnode *np, const char *name, int nmlen, smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_uint8(mbp, SMB_DT_ASCII); - do { - error = smbfs_fullpath(mbp, SSTOVC(ssp), np, - name, &nmlen, '\\'); - if (error) - break; - smb_rq_bend(rqp); - error = smb_rq_simple(rqp); - if (error) - break; - smb_rq_getreply(rqp, &mdp); - if (md_get_uint8(mdp, &wc) != 0 || wc != 10) { - error = EBADRPC; - break; - } - md_get_uint16le(mdp, &wattr); - fap->fa_attr = wattr; - /* - * Be careful using the time returned here, as - * with FAT on NT4SP6, at least, the time returned is low - * 32 bits of 100s of nanoseconds (since 1601) so it rolls - * over about every seven minutes! - */ - md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */ - if (longint) /* avoid bogus zero returns */ - smb_time_server2local(longint, - SSTOVC(ssp)->vc_sopt.sv_tz, &fap->fa_mtime); - md_get_uint32le(mdp, &longint); - fap->fa_size = longint; - /*LINTED*/ - } while (0); - smb_rq_done(rqp); - return (error); -} - -int -smbfs_smb_setpattr(struct smbnode *np, uint32_t attr, - struct timespec *mtime, struct timespec *atime, - struct smb_cred *scrp) -{ - struct smb_share *ssp = np->n_mount->smi_share; - struct smb_vc *vcp = SSTOVC(ssp); - int error; + error = smbfs_fullpath(mbp, SSTOVC(ssp), np, + name, &nmlen, '\\'); + if (error) + goto out; + smb_rq_bend(rqp); + error = smb_rq_simple(rqp); + if (error) + goto out; + smb_rq_getreply(rqp, &mdp); + error = md_get_uint8(mdp, &wc); + if (error) + goto out; + if (wc != 10) { + error = EBADRPC; + goto out; + } + md_get_uint16le(mdp, &wattr); + fap->fa_attr = wattr; /* - * This is the logic that was in smbfs_vnops.c + * Be careful using the time returned here, as + * with FAT on NT4SP6, at least, the time returned is low + * 32 bits of 100s of nanoseconds (since 1601) so it rolls + * over about every seven minutes! */ - if ((vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) && - (vcp->vc_flags & SMBV_NT4) == 0) { - /* - * NT4 doesn't understand "NT" style SMBs; - * for NT4 we use the old SET_PATH_INFO - * XXX Actually, I think the issue is that - * NT requires an open handle for this. - */ - error = smbfs_smb_setpattrNT(np, - attr, mtime, atime, scrp); - if (error != EBADRPC) - return (error); - - /* NT4 response, remember */ - SMB_VC_LOCK(vcp); - vcp->vc_flags |= SMBV_NT4; - SMB_VC_UNLOCK(vcp); - } - - if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN2_0) { - error = smbfs_smb_setpattr2(np, - attr, mtime, atime, scrp); - } else { - error = smbfs_smb_setpattr1(np, NULL, 0, - attr, mtime, scrp); - } + md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */ + smb_time_server2local(longint, + SSTOVC(ssp)->vc_sopt.sv_tz, &fap->fa_mtime); + error = md_get_uint32le(mdp, &longint); + fap->fa_size = longint; +out: + smb_rq_done(rqp); return (error); } @@ -1021,22 +864,20 @@ smbfs_smb_setpattr1(struct smbnode *np, const char *name, int len, smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_uint8(mbp, SMB_DT_ASCII); - do { - error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, &len, '\\'); - if (error) - break; - mb_put_uint8(mbp, SMB_DT_ASCII); - if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) { - mb_put_padbyte(mbp); - mb_put_uint8(mbp, 0); /* 1st byte NULL Unicode char */ - } - mb_put_uint8(mbp, 0); - smb_rq_bend(rqp); - error = smb_rq_simple(rqp); - if (error) - break; - /*LINTED*/ - } while (0); + + error = smbfs_fullpath(mbp, SSTOVC(ssp), np, name, &len, '\\'); + if (error) + goto out; + mb_put_uint8(mbp, SMB_DT_ASCII); + if (SMB_UNICODE_STRINGS(SSTOVC(ssp))) { + mb_put_padbyte(mbp); + mb_put_uint8(mbp, 0); /* 1st byte NULL Unicode char */ + } + mb_put_uint8(mbp, 0); + smb_rq_bend(rqp); + error = smb_rq_simple(rqp); + +out: smb_rq_done(rqp); return (error); } @@ -1077,188 +918,41 @@ smbfs_smb_unhideit(struct smbnode *np, const char *name, int len, } /* - * Note, win95 doesn't support this call. + * Set file attributes (optionally: DOS attr, atime, mtime) + * either by open FID or by path name (FID == -1). */ int -smbfs_smb_setpattr2(struct smbnode *np, uint32_t attr, - struct timespec *mtime, struct timespec *atime, - struct smb_cred *scrp) -{ - struct smb_t2rq *t2p; - struct smb_share *ssp = np->n_mount->smi_share; - struct smb_vc *vcp = SSTOVC(ssp); - struct mbchain *mbp; - uint16_t date, time; - int error, tzoff; - - error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION, - scrp, &t2p); - if (error) - return (error); - mbp = &t2p->t2_tparam; - mb_init(mbp); - mb_put_uint16le(mbp, SMB_SFILEINFO_STANDARD); - mb_put_uint32le(mbp, 0); /* MBZ */ - /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */ - error = smbfs_fullpath(mbp, vcp, np, NULL, NULL, '\\'); - if (error) { - smb_t2_done(t2p); - return (error); - } - tzoff = vcp->vc_sopt.sv_tz; - mbp = &t2p->t2_tdata; - mb_init(mbp); - mb_put_uint32le(mbp, 0); /* creation time */ - if (atime) - smb_time_unix2dos(atime, tzoff, &date, &time, NULL); - else - time = date = 0; - mb_put_uint16le(mbp, date); - mb_put_uint16le(mbp, time); - if (mtime) - smb_time_unix2dos(mtime, tzoff, &date, &time, NULL); - else - time = date = 0; - mb_put_uint16le(mbp, date); - mb_put_uint16le(mbp, time); - mb_put_uint32le(mbp, 0); /* file size */ - mb_put_uint32le(mbp, 0); /* allocation unit size */ - mb_put_uint16le(mbp, attr); /* DOS attr */ - mb_put_uint32le(mbp, 0); /* EA size */ - t2p->t2_maxpcount = 5 * 2; - t2p->t2_maxdcount = vcp->vc_txmax; - error = smb_t2_request(t2p); - smb_t2_done(t2p); - return (error); -} - -/* - * *BASIC_INFO works with Samba, but Win2K servers say it is an - * invalid information level on a SET_PATH_INFO. Note Win2K does - * support *BASIC_INFO on a SET_FILE_INFO, and they support the - * equivalent *BASIC_INFORMATION on SET_PATH_INFO. Go figure. - */ -int -smbfs_smb_setpattrNT(struct smbnode *np, uint32_t attr, - struct timespec *mtime, struct timespec *atime, +smbfs_smb_setfattr( + struct smbnode *np, + int fid, + uint32_t attr, + struct timespec *mtime, + struct timespec *atime, struct smb_cred *scrp) { - struct smb_t2rq *t2p; struct smb_share *ssp = np->n_mount->smi_share; struct smb_vc *vcp = SSTOVC(ssp); - struct mbchain *mbp; - uint64_t tm; - int error, tzoff; - /* 64 bit value for Jan 1 1980 */ - PRIVSYM uint64_t DIFF1980TO1601 = 11960035200ULL*10000000ULL; - - error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_PATH_INFORMATION, - scrp, &t2p); - if (error) - return (error); - mbp = &t2p->t2_tparam; - mb_init(mbp); - if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU) - mb_put_uint16le(mbp, SMB_SFILEINFO_BASIC_INFORMATION); - else - mb_put_uint16le(mbp, SMB_SFILEINFO_BASIC_INFO); - mb_put_uint32le(mbp, 0); /* MBZ */ - /* mb_put_uint8(mbp, SMB_DT_ASCII); specs incorrect */ - error = smbfs_fullpath(mbp, vcp, np, NULL, NULL, '\\'); - if (error) { - smb_t2_done(t2p); - return (error); - } - tzoff = vcp->vc_sopt.sv_tz; + int error; - /* do we know it won't support dates < 1980? */ - if (!(ssp->ss_flags & SMBS_1980)) { - mbp = &t2p->t2_tdata; - mb_init(mbp); - mb_put_uint64le(mbp, 0); /* creation time */ - if (atime) { - smb_time_local2NT(atime, tzoff, &tm); - } else - tm = 0; - mb_put_uint64le(mbp, tm); /* access time */ - if (mtime) { - smb_time_local2NT(mtime, tzoff, &tm); - } else - tm = 0; - mb_put_uint64le(mbp, tm); /* last write time */ - mb_put_uint64le(mbp, tm); /* change time */ - mb_put_uint32le(mbp, attr); /* attr */ - mb_put_uint32le(mbp, 0); /* undocumented padding */ - t2p->t2_maxpcount = 24; - t2p->t2_maxdcount = 56; - error = smb_t2_request(t2p); - } /* - * "invalid argument" error probably means it's a - * FAT drive that doesn't accept dates earlier - * than 1980, so adjust dates and retry. If the - * 1980 flag is on we fell thru the if {} above + * Normally can use the trans2 call. */ - if ((ssp->ss_flags & SMBS_1980) || (error == EINVAL)) { - mbp = &t2p->t2_tdata; - mb_init(mbp); - mb_put_uint64le(mbp, 0); /* creation time */ - if (atime) { - smb_time_local2NT(atime, tzoff, &tm); - if (tm < DIFF1980TO1601) - tm = DIFF1980TO1601; - } else - tm = 0; - mb_put_uint64le(mbp, tm); /* access time */ - if (mtime) { - smb_time_local2NT(mtime, tzoff, &tm); - if (tm < DIFF1980TO1601) - tm = DIFF1980TO1601; - } else - tm = 0; - mb_put_uint64le(mbp, tm); /* last write time */ - mb_put_uint64le(mbp, tm); /* change time */ - mb_put_uint32le(mbp, attr); /* attr */ - mb_put_uint32le(mbp, 0); /* undocumented padding */ - t2p->t2_maxpcount = 24; - t2p->t2_maxdcount = 56; - error = smb_t2_request(t2p); - - /* if this worked set flag to do the right thing next time */ - if (!(error)) { - SMB_SS_LOCK(ssp); - ssp->ss_flags |= SMBS_1980; - SMB_SS_UNLOCK(ssp); - } + if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { + error = smbfs_smb_setfattrNT(np, fid, + attr, mtime, atime, scrp); + return (error); } - smb_t2_done(t2p); - return (error); -} - -int -smbfs_smb_setfattr(struct smbnode *np, uint16_t fid, - uint32_t attr, struct timespec *mtime, - struct timespec *atime, struct smb_cred *scrp) -{ - struct smb_share *ssp = np->n_mount->smi_share; - struct smb_vc *vcp = SSTOVC(ssp); - int error; /* - * This is the logic that was in smbfs_vnops.c - * Might not be quite right for older dialects. - * (XXX: What about the DOS attributes?) + * Fall-back for older protocols. */ - if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) - error = smbfs_smb_setfattrNT(np, fid, - np->n_dosattr, mtime, atime, scrp); - else if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0) + if (SMB_DIALECT(vcp) >= SMB_DIALECT_LANMAN1_0) { error = smbfs_smb_setftime1(np, fid, mtime, atime, scrp); - else - error = smbfs_smb_setpattr1(np, NULL, 0, - attr, mtime, scrp); - + return (error); + } + error = smbfs_smb_setpattr1(np, NULL, 0, + attr, mtime, scrp); return (error); } @@ -1282,6 +976,7 @@ smbfs_smb_setftime1( error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_SET_INFORMATION2, scrp); if (error) return (error); + tzoff = SSTOVC(ssp)->vc_sopt.sv_tz; smb_rq_getrequest(rqp, &mbp); smb_rq_wstart(rqp); @@ -1310,53 +1005,91 @@ smbfs_smb_setftime1( } /* - * Set DOS file attributes. + * Set DOS file attributes, either via open FID or by path name. * Looks like this call can be used only if CAP_NT_SMBS bit is on. + * + * When setting via path (fid == -1): + * *BASIC_INFO works with Samba, but Win2K servers say it is an + * invalid information level on a SET_PATH_INFO. Note Win2K does + * support *BASIC_INFO on a SET_FILE_INFO, and they support the + * equivalent *BASIC_INFORMATION on SET_PATH_INFO. Go figure. */ int -smbfs_smb_setfattrNT(struct smbnode *np, uint16_t fid, - uint32_t attr, struct timespec *mtime, - struct timespec *atime, struct smb_cred *scrp) +smbfs_smb_setfattrNT( + struct smbnode *np, + int fid, /* if fid == -1, set by path */ + uint32_t attr, + struct timespec *mtime, + struct timespec *atime, + struct smb_cred *scrp) { struct smb_t2rq *t2p; struct smb_share *ssp = np->n_mount->smi_share; struct smb_vc *vcp = SSTOVC(ssp); struct mbchain *mbp; uint64_t tm; - int error, svtz; + int error; + uint16_t cmd, level; - error = smb_t2_alloc(SSTOCP(ssp), SMB_TRANS2_SET_FILE_INFORMATION, - scrp, &t2p); + if (fid == -1) { + cmd = SMB_TRANS2_SET_PATH_INFORMATION; + } else { + if (fid > UINT16_MAX) + return (EINVAL); + cmd = SMB_TRANS2_SET_FILE_INFORMATION; + } + if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU) + level = SMB_SFILEINFO_BASIC_INFORMATION; + else + level = SMB_SFILEINFO_BASIC_INFO; + + error = smb_t2_alloc(SSTOCP(ssp), cmd, scrp, &t2p); if (error) return (error); - svtz = SSTOVC(ssp)->vc_sopt.sv_tz; + mbp = &t2p->t2_tparam; mb_init(mbp); - mb_put_uint16le(mbp, fid); - if (vcp->vc_sopt.sv_caps & SMB_CAP_INFOLEVEL_PASSTHRU) - mb_put_uint16le(mbp, SMB_SFILEINFO_BASIC_INFORMATION); - else - mb_put_uint16le(mbp, SMB_SFILEINFO_BASIC_INFO); - mb_put_uint32le(mbp, 0); /* XXX should be 16 not 32(?) */ + + if (cmd == SMB_TRANS2_SET_FILE_INFORMATION) + mb_put_uint16le(mbp, fid); + + mb_put_uint16le(mbp, level); + mb_put_uint32le(mbp, 0); /* MBZ */ + + if (cmd == SMB_TRANS2_SET_PATH_INFORMATION) { + error = smbfs_fullpath(mbp, vcp, np, NULL, NULL, '\\'); + if (error != 0) + goto out; + } + + /* FAT file systems don't support dates earlier than 1980. */ + mbp = &t2p->t2_tdata; mb_init(mbp); mb_put_uint64le(mbp, 0); /* creation time */ if (atime) { - smb_time_local2NT(atime, svtz, &tm); + smb_time_local2NT(atime, &tm); + if (tm != 0 && (ssp->ss_flags & SMBS_FST_FAT) && + tm < NT1980) + tm = NT1980; } else tm = 0; mb_put_uint64le(mbp, tm); /* access time */ if (mtime) { - smb_time_local2NT(mtime, svtz, &tm); + smb_time_local2NT(mtime, &tm); + if (tm != 0 && (ssp->ss_flags & SMBS_FST_FAT) && + tm < NT1980) + tm = NT1980; } else tm = 0; mb_put_uint64le(mbp, tm); /* last write time */ - mb_put_uint64le(mbp, tm); /* change time */ + mb_put_uint64le(mbp, 0); /* ctime (no change) */ mb_put_uint32le(mbp, attr); - mb_put_uint32le(mbp, 0); /* padding */ + mb_put_uint32le(mbp, 0); /* padding */ t2p->t2_maxpcount = 2; t2p->t2_maxdcount = 0; error = smb_t2_request(t2p); +out: smb_t2_done(t2p); return (error); } @@ -1380,38 +1113,34 @@ smbfs_smb_setfattrNT(struct smbnode *np, uint16_t fid, * now too, which may or may not create a new object. */ int -smbfs_smb_ntcreatex(struct smbnode *np, uint32_t rights, - struct smb_cred *scrp, enum vtype vt, - int *attrcacheupdated, uint16_t *fidp, - const char *name, int nmlen, uint32_t disp, int xattr, - len_t *sizep, uint32_t *rightsp) +smbfs_smb_ntcreatex( + struct smbnode *np, + const char *name, + int nmlen, + int xattr, /* is named stream? */ + uint32_t req_acc, /* requested access */ + uint32_t efa, /* ext. file attrs (DOS attr +) */ + uint32_t share_acc, + uint32_t disp, /* open disposition */ + uint32_t createopt, /* NTCREATEX_OPTIONS_ */ + struct smb_cred *scrp, + uint16_t *fidp, + uint32_t *cr_act_p, /* create action */ + struct smbfattr *fap) /* optional */ { struct smb_rq rq, *rqp = &rq; struct smb_share *ssp = np->n_mount->smi_share; struct smb_vc *vcp = SSTOVC(ssp); struct mbchain *mbp; struct mdchain *mdp; - struct smbfattr fap; + struct smbfattr fa; uint8_t wc; - uint32_t longint, createact, createopt, efa; + uint32_t longint, createact; uint64_t llongint; int error; uint16_t fid, *namelenp; - /* - * Set the File attributes and Create options. - * WinXP uses EFA_NORMAL in all of these cases. - */ - createopt = (vt == VDIR) ? - NTCREATEX_OPTIONS_DIRECTORY : - NTCREATEX_OPTIONS_NON_DIRECTORY_FILE; - efa = SMB_EFA_NORMAL; - if (disp != NTCREATEX_DISP_OPEN && !xattr) { - if (name && *name == '.') - efa = SMB_EFA_HIDDEN; - } - - gethrestime(&fap.fa_reqtime); + bzero(&fa, sizeof (fa)); error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_NT_CREATE_ANDX, scrp); if (error) return (error); @@ -1426,127 +1155,87 @@ smbfs_smb_ntcreatex(struct smbnode *np, uint32_t rights, * XP to a W2K Server does not use NTCREATEX_FLAGS_OPEN_DIRECTORY * for creating nor for opening a directory. Samba ignores the bit. */ -#if 0 /* causes sharing violation when making dir on W2K! */ - mb_put_uint32le(mbp, vt == VDIR ? NTCREATEX_FLAGS_OPEN_DIRECTORY : 0); -#else mb_put_uint32le(mbp, 0); /* NTCREATEX_FLAGS_* */ -#endif mb_put_uint32le(mbp, 0); /* FID - basis for path if not root */ - mb_put_uint32le(mbp, rights); + mb_put_uint32le(mbp, req_acc); mb_put_uint64le(mbp, 0); /* "initial allocation size" */ mb_put_uint32le(mbp, efa); - mb_put_uint32le(mbp, NTCREATEX_SHARE_ACCESS_ALL); + mb_put_uint32le(mbp, share_acc); mb_put_uint32le(mbp, disp); mb_put_uint32le(mbp, createopt); mb_put_uint32le(mbp, NTCREATEX_IMPERSONATION_IMPERSONATION); /* (?) */ mb_put_uint8(mbp, 0); /* security flags (?) */ smb_rq_wend(rqp); smb_rq_bstart(rqp); - do { - if (name == NULL) - nmlen = 0; - error = smbfs_fullpath(mbp, vcp, np, name, &nmlen, - xattr ? ':' : '\\'); - if (error) - break; - *namelenp = htoles(nmlen); /* includes null */ - smb_rq_bend(rqp); - /* - * Don't want to risk missing a successful - * open response, or we could "leak" FIDs. - */ - rqp->sr_flags |= SMBR_NOINTR_RECV; - error = smb_rq_simple_timed(rqp, smb_timo_open); - if (error) - break; - smb_rq_getreply(rqp, &mdp); - /* - * spec says 26 for word count, but 34 words are defined - * and observed from win2000 - */ - if (md_get_uint8(mdp, &wc) != 0 || - (wc != 26 && wc != 34 && wc != 42)) { - error = EBADRPC; - break; - } - md_get_uint8(mdp, NULL); /* secondary cmd */ - md_get_uint8(mdp, NULL); /* mbz */ - md_get_uint16le(mdp, NULL); /* andxoffset */ - md_get_uint8(mdp, NULL); /* oplock lvl granted */ - md_get_uint16le(mdp, &fid); /* file ID */ - md_get_uint32le(mdp, &createact); /* create_action */ - md_get_uint64le(mdp, &llongint); /* creation time */ - md_get_uint64le(mdp, &llongint); /* access time */ - if (llongint) /* avoid bogus 0 time (on FAT roots) */ - smb_time_NT2local(llongint, vcp->vc_sopt.sv_tz, - &fap.fa_atime); - md_get_uint64le(mdp, &llongint); /* write time */ - if (llongint) /* avoid bogus 0 time (on FAT roots) */ - smb_time_NT2local(llongint, vcp->vc_sopt.sv_tz, - &fap.fa_mtime); - md_get_uint64le(mdp, &llongint); /* change time */ - if (llongint) /* avoid bogus 0 time (on FAT roots) */ - smb_time_NT2local(llongint, vcp->vc_sopt.sv_tz, - &fap.fa_ctime); - md_get_uint32le(mdp, &longint); /* attributes */ - fap.fa_attr = longint; - md_get_uint64le(mdp, NULL); /* allocation size */ - md_get_uint64le(mdp, &llongint); /* EOF */ - fap.fa_size = llongint; - if (sizep) - *sizep = fap.fa_size; - md_get_uint16le(mdp, NULL); /* file type */ - md_get_uint16le(mdp, NULL); /* device state */ - md_get_uint8(mdp, NULL); /* directory (boolean) */ - /*LINTED*/ - } while (0); - smb_rq_done(rqp); + + if (name == NULL) + nmlen = 0; + error = smbfs_fullpath(mbp, vcp, np, name, &nmlen, + xattr ? ':' : '\\'); if (error) - return (error); - if (fidp) - *fidp = fid; - if (rightsp) - *rightsp = rights; + goto done; + *namelenp = htoles(nmlen); /* includes null */ + smb_rq_bend(rqp); /* - * Is it possible that we have cached attributes? - * Assume "not cached" if we created the object. + * Don't want to risk missing a successful + * open response, or we could "leak" FIDs. */ - if (createact == NTCREATEX_ACTION_CREATED || xattr) - goto uncached; - if (attrcacheupdated) - *attrcacheupdated = 0; + rqp->sr_flags |= SMBR_NOINTR_RECV; + error = smb_rq_simple_timed(rqp, smb_timo_open); + if (error) + goto done; + smb_rq_getreply(rqp, &mdp); /* - * Update the cached attributes if they are still valid - * in the cache and if nothing has changed. + * spec says 26 for word count, but 34 words are defined + * and observed from win2000 */ - if (np->r_vnode == NULL) - goto uncached; - if (smbfs_attr_cachelookup(np->r_vnode, NULL) != 0) - goto uncached; /* the cached attributes are not valid */ - if (fap.fa_size != np->n_size) - goto uncached; /* the size is different */ - if (fap.fa_attr != np->n_dosattr) - goto uncached; /* the attrs are different */ - /* - * fap.fa_mtime is in two second increments while np->n_mtime - * may be in one second increments, so comparing the times is - * somewhat sloppy. - * - * XXX: true fap.fa_mtime resolution must depend upon server's - * local filesystem and is thus indeterminate... XXX ...TBD how that - * affects this code... note wire resolution here is 100ns versus - * 1sec down in smbfs_smb_oldopen(SMB_COM_OPEN) - */ - if (fap.fa_mtime.tv_sec != np->n_mtime.tv_sec && - fap.fa_mtime.tv_sec != np->n_mtime.tv_sec - 1 && - fap.fa_mtime.tv_sec != np->n_mtime.tv_sec + 1) - goto uncached; /* the mod time is different */ - - fap.fa_mtime.tv_sec = np->n_mtime.tv_sec; /* keep higher res time */ - smbfs_attr_cacheenter(np->r_vnode, &fap); - if (attrcacheupdated) - *attrcacheupdated = 1; -uncached: + error = md_get_uint8(mdp, &wc); + if (error) + goto done; + if (wc != 26 && wc != 34 && wc != 42) { + error = EBADRPC; + goto done; + } + md_get_uint8(mdp, NULL); /* secondary cmd */ + md_get_uint8(mdp, NULL); /* mbz */ + md_get_uint16le(mdp, NULL); /* andxoffset */ + md_get_uint8(mdp, NULL); /* oplock lvl granted */ + md_get_uint16le(mdp, &fid); /* file ID */ + md_get_uint32le(mdp, &createact); /* create_action */ + + md_get_uint64le(mdp, &llongint); /* creation time */ + smb_time_NT2local(llongint, &fa.fa_createtime); + md_get_uint64le(mdp, &llongint); /* access time */ + smb_time_NT2local(llongint, &fa.fa_atime); + md_get_uint64le(mdp, &llongint); /* write time */ + smb_time_NT2local(llongint, &fa.fa_mtime); + md_get_uint64le(mdp, &llongint); /* change time */ + smb_time_NT2local(llongint, &fa.fa_ctime); + + md_get_uint32le(mdp, &longint); /* attributes */ + fa.fa_attr = longint; + + md_get_uint64le(mdp, &llongint); /* allocation size */ + fa.fa_allocsz = llongint; + + md_get_uint64le(mdp, &llongint); /* EOF position */ + fa.fa_size = llongint; + + error = md_get_uint16le(mdp, NULL); /* file type */ + /* other stuff we don't care about */ + +done: + smb_rq_done(rqp); + if (error) + return (error); + + if (fidp) + *fidp = fid; + if (cr_act_p) + *cr_act_p = createact; + if (fap) + *fap = fa; /* struct copy */ + return (0); } @@ -1554,18 +1243,32 @@ static uint32_t smb_mode2rights(int mode) { mode = mode & SMB_AM_OPENMODE; + uint32_t rights = + STD_RIGHT_SYNCHRONIZE_ACCESS | + STD_RIGHT_READ_CONTROL_ACCESS; - switch (mode) { - case SMB_AM_OPENREAD: - return (GENERIC_RIGHT_READ_ACCESS); - case SMB_AM_OPENWRITE: - return (GENERIC_RIGHT_WRITE_ACCESS); - case SMB_AM_OPENRW: - return (GENERIC_RIGHT_ALL_ACCESS); - case SMB_AM_OPENEXEC: - return (GENERIC_RIGHT_EXECUTE_ACCESS); + if ((mode == SMB_AM_OPENREAD) || + (mode == SMB_AM_OPENRW)) { + rights |= + SA_RIGHT_FILE_READ_ATTRIBUTES | + SA_RIGHT_FILE_READ_DATA; } - return (0); + + if ((mode == SMB_AM_OPENWRITE) || + (mode == SMB_AM_OPENRW)) { + rights |= + SA_RIGHT_FILE_WRITE_ATTRIBUTES | + SA_RIGHT_FILE_APPEND_DATA | + SA_RIGHT_FILE_WRITE_DATA; + } + + if (mode == SMB_AM_OPENEXEC) { + rights |= + SA_RIGHT_FILE_READ_ATTRIBUTES | + SA_RIGHT_FILE_EXECUTE; + } + + return (rights); } static int @@ -1576,34 +1279,43 @@ smb_rights2mode(uint32_t rights) if (rights & (SA_RIGHT_FILE_APPEND_DATA | SA_RIGHT_FILE_DELETE_CHILD | SA_RIGHT_FILE_WRITE_EA | SA_RIGHT_FILE_WRITE_ATTRIBUTES | SA_RIGHT_FILE_WRITE_DATA | STD_RIGHT_WRITE_OWNER_ACCESS | - STD_RIGHT_DELETE_ACCESS | STD_RIGHT_WRITE_DAC_ACCESS | - GENERIC_RIGHT_ALL_ACCESS | GENERIC_RIGHT_WRITE_ACCESS)) + STD_RIGHT_DELETE_ACCESS | STD_RIGHT_WRITE_DAC_ACCESS)) accmode = SMB_AM_OPENWRITE; if (rights & (SA_RIGHT_FILE_READ_DATA | SA_RIGHT_FILE_READ_ATTRIBUTES | - SA_RIGHT_FILE_READ_EA | STD_RIGHT_READ_CONTROL_ACCESS | - GENERIC_RIGHT_ALL_ACCESS | GENERIC_RIGHT_READ_ACCESS)) + SA_RIGHT_FILE_READ_EA | STD_RIGHT_READ_CONTROL_ACCESS)) accmode = (accmode == SMB_AM_OPENEXEC) ? SMB_AM_OPENREAD : SMB_AM_OPENRW; return (accmode); } static int -smbfs_smb_oldopen(struct smbnode *np, int accmode, struct smb_cred *scrp, - int *attrcacheupdated, uint16_t *fidp, const char *name, - int nmlen, int xattr, len_t *sizep, uint32_t *rightsp) +smbfs_smb_oldopen( + struct smbnode *np, + const char *name, + int nmlen, + int xattr, + int accmode, + struct smb_cred *scrp, + uint16_t *fidp, + uint16_t *granted_mode_p, + smbfattr_t *fap) { struct smb_rq rq, *rqp = &rq; struct smb_share *ssp = np->n_mount->smi_share; struct smb_vc *vcp = SSTOVC(ssp); struct mbchain *mbp; struct mdchain *mdp; - struct smbfattr fap; + struct smbfattr fa; uint8_t wc; - uint16_t fid, wattr, grantedmode; + uint16_t wattr; uint32_t longint; int error; + bzero(&fa, sizeof (fa)); + /* + * XXX: move to callers... + * * Use DENYNONE to give unixy semantics of permitting * everything not forbidden by permissions. Ie denial * is up to server with clients/openers needing to use @@ -1611,7 +1323,6 @@ smbfs_smb_oldopen(struct smbnode *np, int accmode, struct smb_cred *scrp, */ accmode |= SMB_SM_DENYNONE; - gethrestime(&fap.fa_reqtime); error = smb_rq_init(rqp, SSTOCP(ssp), SMB_COM_OPEN, scrp); if (error) return (error); @@ -1623,91 +1334,55 @@ smbfs_smb_oldopen(struct smbnode *np, int accmode, struct smb_cred *scrp, smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_uint8(mbp, SMB_DT_ASCII); - do { - error = smbfs_fullpath(mbp, vcp, np, name, &nmlen, - xattr ? ':' : '\\'); - if (error) - break; - smb_rq_bend(rqp); - /* - * Don't want to risk missing a successful - * open response, or we could "leak" FIDs. - */ - rqp->sr_flags |= SMBR_NOINTR_RECV; - error = smb_rq_simple_timed(rqp, smb_timo_open); - if (error) - break; - smb_rq_getreply(rqp, &mdp); - /* - * 8/2002 a DAVE server returned wc of 15 so we ignore that. - * (the actual packet length and data was correct) - */ - if (md_get_uint8(mdp, &wc) != 0 || (wc != 7 && wc != 15)) { - error = EBADRPC; - break; - } - md_get_uint16le(mdp, &fid); - md_get_uint16le(mdp, &wattr); - fap.fa_attr = wattr; - /* - * Be careful using the time returned here, as - * with FAT on NT4SP6, at least, the time returned is low - * 32 bits of 100s of nanoseconds (since 1601) so it rolls - * over about every seven minutes! - */ - md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */ - if (longint) /* avoid bogus zero returns */ - smb_time_server2local(longint, vcp->vc_sopt.sv_tz, - &fap.fa_mtime); - md_get_uint32le(mdp, &longint); - fap.fa_size = longint; - if (sizep) - *sizep = fap.fa_size; - md_get_uint16le(mdp, &grantedmode); - /*LINTED*/ - } while (0); - smb_rq_done(rqp); + + error = smbfs_fullpath(mbp, vcp, np, name, &nmlen, + xattr ? ':' : '\\'); if (error) - return (error); - if (fidp) - *fidp = fid; - if (xattr) - goto uncached; - if (rightsp) - *rightsp = smb_mode2rights(grantedmode); - if (attrcacheupdated) - *attrcacheupdated = 0; + goto done; + smb_rq_bend(rqp); /* - * Update the cached attributes if they are still valid - * in the cache and if nothing has changed. - * Note that this won't ever update if the file size is - * greater than the 32-bits returned by SMB_COM_OPEN. - * For 64-bit file sizes, SMB_COM_NT_CREATE_ANDX must - * be used instead of SMB_COM_OPEN. + * Don't want to risk missing a successful + * open response, or we could "leak" FIDs. */ - if (np->r_vnode == NULL) - goto uncached; - if (smbfs_attr_cachelookup(np->r_vnode, NULL) != 0) - goto uncached; /* the cached attributes are not valid */ - if (fap.fa_size != np->n_size) - goto uncached; /* the size is different */ - if (fap.fa_attr != np->n_dosattr) - goto uncached; /* the attrs are different */ + rqp->sr_flags |= SMBR_NOINTR_RECV; + error = smb_rq_simple_timed(rqp, smb_timo_open); + if (error) + goto done; + smb_rq_getreply(rqp, &mdp); /* - * fap.fa_mtime is in two second increments while np->n_mtime - * may be in one second increments, so comparing the times is - * somewhat sloppy. + * 8/2002 a DAVE server returned wc of 15 so we ignore that. + * (the actual packet length and data was correct) */ - if (fap.fa_mtime.tv_sec != np->n_mtime.tv_sec && - fap.fa_mtime.tv_sec != np->n_mtime.tv_sec - 1 && - fap.fa_mtime.tv_sec != np->n_mtime.tv_sec + 1) - goto uncached; /* the mod time is different */ - - fap.fa_mtime.tv_sec = np->n_mtime.tv_sec; /* keep higher res time */ - smbfs_attr_cacheenter(np->r_vnode, &fap); - if (attrcacheupdated) - *attrcacheupdated = 1; -uncached: + error = md_get_uint8(mdp, &wc); + if (error) + goto done; + if (wc != 7 && wc != 15) { + error = EBADRPC; + goto done; + } + md_get_uint16le(mdp, fidp); + md_get_uint16le(mdp, &wattr); + fa.fa_attr = wattr; + /* + * Be careful using the time returned here, as + * with FAT on NT4SP6, at least, the time returned is low + * 32 bits of 100s of nanoseconds (since 1601) so it rolls + * over about every seven minutes! + */ + md_get_uint32le(mdp, &longint); /* specs: secs since 1970 */ + smb_time_server2local(longint, vcp->vc_sopt.sv_tz, &fa.fa_mtime); + md_get_uint32le(mdp, &longint); + fa.fa_size = longint; + error = md_get_uint16le(mdp, granted_mode_p); + +done: + smb_rq_done(rqp); + if (error) + return (error); + + if (fap) + *fap = fa; /* struct copy */ + return (0); } @@ -1717,8 +1392,7 @@ smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights, struct smb_cred *scrp, { struct smb_share *ssp = np->n_mount->smi_share; struct smb_vc *vcp = SSTOVC(ssp); - enum vtype vt = VREG; - int error; + int accmode, error; /* Shared lock for n_fid use below. */ ASSERT(smbfs_rw_lock_held(&np->r_lkserlock, RW_READER)); @@ -1735,18 +1409,27 @@ smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights, struct smb_cred *scrp, } mutex_exit(&np->r_statelock); - if (!(vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS)) { - int mode = smb_rights2mode(rights); - error = smbfs_smb_oldopen(np, mode, scrp, - NULL, fidp, NULL, 0, 0, NULL, NULL); - } else { - if (SMBTOV(np)) - vt = SMBTOV(np)->v_type; - error = smbfs_smb_ntcreatex(np, rights, scrp, vt, - NULL, fidp, NULL, 0, NTCREATEX_DISP_OPEN, 0, - NULL, NULL); + /* re-open an existing file. */ + if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { + error = smbfs_smb_ntcreatex(np, + NULL, 0, 0, /* name nmlen xattr */ + rights, SMB_EFA_NORMAL, + NTCREATEX_SHARE_ACCESS_ALL, + NTCREATEX_DISP_OPEN, + 0, /* create options */ + scrp, fidp, + NULL, NULL); /* cr_act_p fa_p */ + return (error); } + accmode = smb_rights2mode(rights); + error = smbfs_smb_oldopen(np, + NULL, 0, 0, /* name nmlen xattr */ + accmode, scrp, + fidp, + NULL, /* granted mode p */ + NULL); /* fa p */ + return (error); } @@ -1786,27 +1469,48 @@ smbfs_smb_tmpclose(struct smbnode *np, uint16_t fid, struct smb_cred *scrp) } int -smbfs_smb_open(struct smbnode *np, uint32_t rights, struct smb_cred *scrp, - int *attrcacheupdated, uint16_t *fidp, const char *name, - int nmlen, int xattr, len_t *sizep, uint32_t *rightsp) +smbfs_smb_open( + struct smbnode *np, + const char *name, + int nmlen, + int xattr, + uint32_t rights, + struct smb_cred *scrp, + uint16_t *fidp, + uint32_t *rightsp, + smbfattr_t *fap) { - int error; struct smb_share *ssp = np->n_mount->smi_share; struct smb_vc *vcp = SSTOVC(ssp); - enum vtype vt = VREG; + int accmode, error; + uint16_t grantedmode; + /* open an existing file */ if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { - if (SMBTOV(np)) - vt = SMBTOV(np)->v_type; - error = smbfs_smb_ntcreatex(np, rights, scrp, vt, - attrcacheupdated, fidp, name, nmlen, - NTCREATEX_DISP_OPEN, xattr, sizep, rightsp); - } else { - error = smbfs_smb_oldopen(np, smb_rights2mode(rights), scrp, - attrcacheupdated, fidp, name, nmlen, xattr, sizep, rightsp); + error = smbfs_smb_ntcreatex(np, + name, nmlen, xattr, + rights, SMB_EFA_NORMAL, + NTCREATEX_SHARE_ACCESS_ALL, + NTCREATEX_DISP_OPEN, + 0, /* create options */ + scrp, fidp, + NULL, fap); /* cr_act_p fa_p */ + if (error != 0) + return (error); + *rightsp = rights; + return (0); } - return (error); + accmode = smb_rights2mode(rights); + error = smbfs_smb_oldopen(np, + name, nmlen, xattr, accmode, scrp, + fidp, &grantedmode, fap); + if (error != 0) + return (error); + *rightsp = smb_mode2rights(grantedmode); + (void) smbfs_smb_getfattr(np, fap, scrp); + + return (0); } int @@ -1825,7 +1529,8 @@ smbfs_smb_close(struct smb_share *ssp, uint16_t fid, struct timespec *mtime, smb_rq_wstart(rqp); mb_put_uint16le(mbp, fid); if (mtime) { - smb_time_local2server(mtime, SSTOVC(ssp)->vc_sopt.sv_tz, &time); + int sv_tz = SSTOVC(ssp)->vc_sopt.sv_tz; + smb_time_local2server(mtime, sv_tz, &time); } else time = 0; mb_put_uint32le(mbp, time); @@ -1865,7 +1570,7 @@ smbfs_smb_close(struct smb_share *ssp, uint16_t fid, struct timespec *mtime, static int smbfs_smb_oldcreate(struct smbnode *dnp, const char *name, int nmlen, - struct smb_cred *scrp, uint16_t *fidp, int xattr) + int xattr, struct smb_cred *scrp, uint16_t *fidp) { struct smb_rq rq, *rqp = &rq; struct smb_share *ssp = dnp->n_mount->smi_share; @@ -1893,32 +1598,45 @@ smbfs_smb_oldcreate(struct smbnode *dnp, const char *name, int nmlen, mb_put_uint8(mbp, SMB_DT_ASCII); error = smbfs_fullpath(mbp, SSTOVC(ssp), dnp, name, &nmlen, xattr ? ':' : '\\'); - if (!error) { - smb_rq_bend(rqp); - /* - * Don't want to risk missing a successful - * open response, or we could "leak" FIDs. - */ - rqp->sr_flags |= SMBR_NOINTR_RECV; - error = smb_rq_simple_timed(rqp, smb_timo_open); - if (!error) { - smb_rq_getreply(rqp, &mdp); - md_get_uint8(mdp, &wc); - if (wc == 1) - md_get_uint16le(mdp, fidp); - else - error = EBADRPC; - } + if (error) + goto out; + smb_rq_bend(rqp); + /* + * Don't want to risk missing a successful + * open response, or we could "leak" FIDs. + */ + rqp->sr_flags |= SMBR_NOINTR_RECV; + error = smb_rq_simple_timed(rqp, smb_timo_open); + if (error) + goto out; + + smb_rq_getreply(rqp, &mdp); + md_get_uint8(mdp, &wc); + if (wc != 1) { + error = EBADRPC; + goto out; } + error = md_get_uint16le(mdp, fidp); + +out: smb_rq_done(rqp); return (error); } int -smbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen, - struct smb_cred *scrp, uint16_t *fidp, uint32_t disp, int xattr) +smbfs_smb_create( + struct smbnode *dnp, + const char *name, + int nmlen, + int xattr, + uint32_t disp, + struct smb_cred *scrp, + uint16_t *fidp) { - struct smb_vc *vcp = SSTOVC(dnp->n_mount->smi_share); + struct smb_share *ssp = dnp->n_mount->smi_share; + struct smb_vc *vcp = SSTOVC(ssp); + uint32_t efa, rights; + int error; /* * At present the only access we might need is to WRITE data, @@ -1927,12 +1645,21 @@ smbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen, * and be set upstream. */ if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { - return (smbfs_smb_ntcreatex(dnp, SA_RIGHT_FILE_WRITE_DATA, - scrp, VREG, NULL, fidp, name, nmlen, disp, xattr, - NULL, NULL)); - } else - return (smbfs_smb_oldcreate(dnp, name, nmlen, scrp, fidp, - xattr)); + rights = SA_RIGHT_FILE_WRITE_DATA; + efa = SMB_EFA_NORMAL; + if (!xattr && name && *name == '.') + efa = SMB_EFA_HIDDEN; + error = smbfs_smb_ntcreatex(dnp, + name, nmlen, xattr, rights, efa, + NTCREATEX_SHARE_ACCESS_ALL, + disp, /* != NTCREATEX_DISP_OPEN */ + NTCREATEX_OPTIONS_NON_DIRECTORY_FILE, + scrp, fidp, NULL, NULL); /* cr_act_p fa_p */ + return (error); + } + + error = smbfs_smb_oldcreate(dnp, name, nmlen, xattr, scrp, fidp); + return (error); } int @@ -2031,19 +1758,18 @@ smbfs_smb_move(struct smbnode *src, struct smbnode *tdnp, smb_rq_wend(rqp); smb_rq_bstart(rqp); mb_put_uint8(mbp, SMB_DT_ASCII); - do { - error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, NULL, '\\'); - if (error) - break; - mb_put_uint8(mbp, SMB_DT_ASCII); - error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, &tnmlen, - '\\'); - if (error) - break; - smb_rq_bend(rqp); - error = smb_rq_simple(rqp); - /*LINTED*/ - } while (0); + + error = smbfs_fullpath(mbp, SSTOVC(ssp), src, NULL, NULL, '\\'); + if (error) + goto out; + mb_put_uint8(mbp, SMB_DT_ASCII); + error = smbfs_fullpath(mbp, SSTOVC(ssp), tdnp, tname, &tnmlen, '\\'); + if (error) + goto out; + smb_rq_bend(rqp); + error = smb_rq_simple(rqp); + +out: smb_rq_done(rqp); return (error); } @@ -2075,10 +1801,12 @@ smbfs_smb_oldmkdir(struct smbnode *dnp, const char *name, int len, } int -smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len, +smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int nmlen, struct smb_cred *scrp) { struct smb_share *ssp = dnp->n_mount->smi_share; + struct smb_vc *vcp = SSTOVC(ssp); + uint32_t rights; uint16_t fid; int error; @@ -2087,18 +1815,23 @@ smbfs_smb_mkdir(struct smbnode *dnp, const char *name, int len, * just to be asking for something. The rights==0 case could * easily be broken on some old or unusual servers. */ - if (SSTOVC(ssp)->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { - error = smbfs_smb_ntcreatex(dnp, SA_RIGHT_FILE_READ_DATA, - scrp, VDIR, NULL, &fid, name, len, - NTCREATEX_DISP_CREATE, 0, NULL, NULL); + if (vcp->vc_sopt.sv_caps & SMB_CAP_NT_SMBS) { + rights = SA_RIGHT_FILE_READ_DATA; + error = smbfs_smb_ntcreatex(dnp, + name, nmlen, 0, /* xattr */ + rights, SMB_EFA_DIRECTORY, + NTCREATEX_SHARE_ACCESS_ALL, + NTCREATEX_DISP_CREATE, + NTCREATEX_OPTIONS_DIRECTORY, + scrp, &fid, NULL, NULL); /* cr_act_p fa_p */ if (error) return (error); - error = smbfs_smb_close(ssp, fid, NULL, scrp); - if (error) - SMBERROR("error %d closing fid %d\n", error, fid); + (void) smbfs_smb_close(ssp, fid, NULL, scrp); return (0); - } else - return (smbfs_smb_oldmkdir(dnp, name, len, scrp)); + } + + error = smbfs_smb_oldmkdir(dnp, name, nmlen, scrp); + return (error); } int @@ -2183,21 +1916,25 @@ smbfs_smb_search(struct smbfs_fctx *ctx) } else if (error) return (error); smb_rq_getreply(rqp, &mdp); - md_get_uint8(mdp, &wc); + error = md_get_uint8(mdp, &wc); + if (error) + return (error); if (wc != 1) return (iseof ? ENOENT : EBADRPC); md_get_uint16le(mdp, &ec); + md_get_uint16le(mdp, &bc); + md_get_uint8(mdp, &bt); + error = md_get_uint16le(mdp, &dlen); + if (error) + return (error); if (ec == 0) return (ENOENT); ctx->f_ecnt = ec; - md_get_uint16le(mdp, &bc); if (bc < 3) return (EBADRPC); bc -= 3; - md_get_uint8(mdp, &bt); if (bt != SMB_DT_VARIABLE) return (EBADRPC); - md_get_uint16le(mdp, &dlen); if (dlen != bc || dlen % SMB_DENTRYLEN != 0) return (EBADRPC); return (0); @@ -2249,7 +1986,6 @@ smbfs_smb_findnextLM1(struct smbfs_fctx *ctx, uint16_t limit) error = smbfs_smb_search(ctx); if (error) return (error); - ctx->f_attr.fa_reqtime = ts; } rqp = ctx->f_rq; smb_rq_getreply(rqp, &mdp); @@ -2259,7 +1995,7 @@ smbfs_smb_findnextLM1(struct smbfs_fctx *ctx, uint16_t limit) md_get_uint16le(mdp, &date); md_get_uint32le(mdp, &size); cp = ctx->f_name; - md_get_mem(mdp, cp, sizeof (ctx->f_fname), MB_MSYSTEM); + error = md_get_mem(mdp, cp, sizeof (ctx->f_fname), MB_MSYSTEM); cp[sizeof (ctx->f_fname) - 1] = 0; cp += strlen(cp) - 1; while (*cp == ' ' && cp >= ctx->f_name) @@ -2473,7 +2209,6 @@ smbfs_smb_findnextLM2(struct smbfs_fctx *ctx, uint16_t limit) error = smbfs_smb_trans2find2(ctx); if (error) return (error); - ctx->f_attr.fa_reqtime = ts; ctx->f_otws++; } t2p = ctx->f_t2; @@ -2485,6 +2220,8 @@ smbfs_smb_findnextLM2(struct smbfs_fctx *ctx, uint16_t limit) fxsz = 0; md_get_uint16le(mdp, &date); md_get_uint16le(mdp, &time); /* creation time */ + smb_dos2unixtime(date, time, 0, svtz, + &ctx->f_attr.fa_createtime); md_get_uint16le(mdp, &date); md_get_uint16le(mdp, &time); /* access time */ smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_atime); @@ -2493,7 +2230,8 @@ smbfs_smb_findnextLM2(struct smbfs_fctx *ctx, uint16_t limit) smb_dos2unixtime(date, time, 0, svtz, &ctx->f_attr.fa_mtime); md_get_uint32le(mdp, &size); ctx->f_attr.fa_size = size; - md_get_uint32le(mdp, NULL); /* allocation size */ + md_get_uint32le(mdp, &size); /* allocation size */ + ctx->f_attr.fa_allocsz = size; md_get_uint16le(mdp, &wattr); ctx->f_attr.fa_attr = wattr; error = md_get_uint8(mdp, &tb); @@ -2507,18 +2245,19 @@ smbfs_smb_findnextLM2(struct smbfs_fctx *ctx, uint16_t limit) case SMB_FIND_BOTH_DIRECTORY_INFO: md_get_uint32le(mdp, &next); md_get_uint32le(mdp, &resumekey); /* file index (resume key) */ - md_get_uint64le(mdp, NULL); /* creation time */ + md_get_uint64le(mdp, &llongint); /* creation time */ + smb_time_NT2local(llongint, &ctx->f_attr.fa_createtime); md_get_uint64le(mdp, &llongint); - smb_time_NT2local(llongint, svtz, &ctx->f_attr.fa_atime); + smb_time_NT2local(llongint, &ctx->f_attr.fa_atime); md_get_uint64le(mdp, &llongint); - smb_time_NT2local(llongint, svtz, &ctx->f_attr.fa_mtime); + smb_time_NT2local(llongint, &ctx->f_attr.fa_mtime); md_get_uint64le(mdp, &llongint); - smb_time_NT2local(llongint, svtz, &ctx->f_attr.fa_ctime); + smb_time_NT2local(llongint, &ctx->f_attr.fa_ctime); md_get_uint64le(mdp, &llongint); /* file size */ ctx->f_attr.fa_size = llongint; - md_get_uint64le(mdp, NULL); /* real size (should use) */ - /* freebsd bug: fa_attr endian bug */ - md_get_uint32le(mdp, &dattr); /* extended file attributes */ + md_get_uint64le(mdp, &llongint); /* alloc. size */ + ctx->f_attr.fa_allocsz = llongint; + md_get_uint32le(mdp, &dattr); /* ext. file attributes */ ctx->f_attr.fa_attr = dattr; error = md_get_uint32le(mdp, &size); /* name len */ if (error) @@ -2541,6 +2280,7 @@ smbfs_smb_findnextLM2(struct smbfs_fctx *ctx, uint16_t limit) SMBVDEBUG("unexpected info level %d\n", ctx->f_infolevel); return (EINVAL); } + if (SMB_UNICODE_STRINGS(SSTOVC(ctx->f_ssp))) nmlen = min(size, SMB_MAXFNAMELEN * 2); else @@ -2631,7 +2371,12 @@ smbfs_smb_findcloseLM2(struct smbfs_fctx *ctx) kmem_free(ctx->f_name, ctx->f_namesz); if (ctx->f_t2) smb_t2_done(ctx->f_t2); - if ((ctx->f_flags & SMBFS_RDD_NOCLOSE) == 0) + /* + * If SMBFS_RDD_FINDFIRST is still set, we were opened + * but never saw a findfirst, so we don't have any + * search handle to close. + */ + if ((ctx->f_flags & (SMBFS_RDD_FINDFIRST | SMBFS_RDD_NOCLOSE)) == 0) error = smbfs_smb_findclose2(ctx); return (error); } @@ -2656,8 +2401,7 @@ smbfs_smb_findopen(struct smbnode *dnp, const char *wild, int wlen, goto out; } - if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0 || - (dnp->n_mount->smi_args.flags & SMBFS_MOUNT_NO_LONG)) { + if (SMB_DIALECT(SSTOVC(ctx->f_ssp)) < SMB_DIALECT_LANMAN2_0) { error = smbfs_smb_findopenLM1(ctx, dnp, wild, wlen, attr); } else { error = smbfs_smb_findopenLM2(ctx, dnp, wild, wlen, attr); @@ -2718,8 +2462,7 @@ smbfs_smb_findnext(struct smbfs_fctx *ctx, int limit, struct smb_cred *scrp) * the ..._findnext functions above. */ - ctx->f_attr.fa_ino = smbfs_getino(ctx->f_dnp, ctx->f_name, - ctx->f_nmlen); + ctx->f_inum = smbfs_getino(ctx->f_dnp, ctx->f_name, ctx->f_nmlen); return (0); } @@ -2780,6 +2523,11 @@ smbfs_smb_lookup(struct smbnode *dnp, const char **namep, int *nmlenp, } /* + * XXX: Should use _qpathinfo here instead. + * (if SMB_CAP_NT_SMBS) + */ + + /* * Shared lock for n_fid use (smb_flush). */ intr = dnp->n_mount->smi_flags & SMI_INT; @@ -2802,8 +2550,11 @@ smbfs_smb_lookup(struct smbnode *dnp, const char **namep, int *nmlenp, error = smbfs_smb_findnext(ctx, 1, scrp); if (error == 0) { *fap = ctx->f_attr; - if (name == NULL) - fap->fa_ino = dnp->n_ino; + /* + * Solaris smbfattr doesn't have fa_ino, + * and we don't allow name==NULL in this + * function anymore. + */ if (namep) *namep = (const char *)smbfs_name_alloc( ctx->f_name, ctx->f_nmlen); diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c index 508dcbdede..90549cbbc7 100644 --- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.c @@ -43,13 +43,7 @@ #include <sys/vnode.h> #include <sys/sunddi.h> -#ifdef APPLE -#include <sys/smb_apple.h> -#include <sys/utfconv.h> -#include <sys/smb_iconv.h> -#else /* APPLE */ #include <netsmb/smb_osdep.h> -#endif /* APPLE */ #include <netsmb/smb.h> #include <netsmb/smb_conn.h> @@ -60,203 +54,6 @@ #include <smbfs/smbfs_node.h> #include <smbfs/smbfs_subr.h> -#ifdef APPLE -MALLOC_DEFINE(M_SMBFSDATA, "SMBFS data", "SMBFS private data"); -#endif /* APPLE */ - -/* - * Time & date conversion routines taken from msdosfs. Although leap - * year calculation is bogus, it's sufficient before 2100 :) - */ -/* - * This is the format of the contents of the deTime field in the direntry - * structure. - * We don't use bitfields because we don't know how compilers for - * arbitrary machines will lay them out. - */ -#define DT_2SECONDS_MASK 0x1F /* seconds divided by 2 */ -#define DT_2SECONDS_SHIFT 0 -#define DT_MINUTES_MASK 0x7E0 /* minutes */ -#define DT_MINUTES_SHIFT 5 -#define DT_HOURS_MASK 0xF800 /* hours */ -#define DT_HOURS_SHIFT 11 - -/* - * This is the format of the contents of the deDate field in the direntry - * structure. - */ -#define DD_DAY_MASK 0x1F /* day of month */ -#define DD_DAY_SHIFT 0 -#define DD_MONTH_MASK 0x1E0 /* month */ -#define DD_MONTH_SHIFT 5 -#define DD_YEAR_MASK 0xFE00 /* year - 1980 */ -#define DD_YEAR_SHIFT 9 -/* - * Total number of days that have passed for each month in a regular year. - */ -static ushort_t regyear[] = { - 31, 59, 90, 120, 151, 181, - 212, 243, 273, 304, 334, 365 -}; - -/* - * Total number of days that have passed for each month in a leap year. - */ -static ushort_t leapyear[] = { - 31, 60, 91, 121, 152, 182, - 213, 244, 274, 305, 335, 366 -}; - -/* - * Variables used to remember parts of the last time conversion. Maybe we - * can avoid a full conversion. - */ -static ulong_t lasttime; -static ulong_t lastday; -static ushort_t lastddate; -static ushort_t lastdtime; - -#ifdef APPLE -PRIVSYM int wall_cmos_clock = 0; /* XXX */ -PRIVSYM int adjkerntz = 0; /* XXX */ -#endif /* APPLE */ - -void -smb_time_unix2dos(struct timespec *tsp, int tzoff, u_int16_t *ddp, - u_int16_t *dtp, u_int8_t *dhp) -{ - long t; - ulong_t days, year, month, inc; - ushort_t *months; - - /* - * If the time from the last conversion is the same as now, then - * skip the computations and use the saved result. - */ - smb_time_local2server(tsp, tzoff, &t); - t &= ~1; - if (lasttime != t) { - lasttime = t; - if (t < 0) { - /* - * This is before 1970, so it's before 1980, - * and can't be represented as a DOS time. - * Just represent it as the DOS epoch. - */ - lastdtime = 0; - lastddate = (1 << DD_DAY_SHIFT) - + (1 << DD_MONTH_SHIFT) - + ((1980 - 1980) << DD_YEAR_SHIFT); - } else { - lastdtime = (((t / 2) % 30) << DT_2SECONDS_SHIFT) - + (((t / 60) % 60) << DT_MINUTES_SHIFT) - + (((t / 3600) % 24) << DT_HOURS_SHIFT); - - /* - * If the number of days since 1970 is the same as - * the last time we did the computation then skip - * all this leap year and month stuff. - */ - days = t / (24 * 60 * 60); - if (days != lastday) { - lastday = days; - for (year = 1970; ; year++) { - /* - * XXX - works in 2000, but won't - * work in 2100. - */ - inc = year & 0x03 ? 365 : 366; - if (days < inc) - break; - days -= inc; - } - /* - * XXX - works in 2000, but won't work in 2100. - */ - months = year & 0x03 ? regyear : leapyear; - for (month = 0; days >= months[month]; month++) - ; - if (month > 0) - days -= months[month - 1]; - lastddate = ((days + 1) << DD_DAY_SHIFT) - + ((month + 1) << DD_MONTH_SHIFT); - /* - * Remember DOS's idea of time is relative - * to 1980, but UN*X's is relative to 1970. - * If somehow we get a time before 1980 then - * don't give totally crazy results. - */ - if (year > 1980) - lastddate += (year - 1980) << - DD_YEAR_SHIFT; - } - } - } - if (dtp) - *dtp = lastdtime; - if (dhp) - *dhp = (tsp->tv_sec & 1) * 100 + tsp->tv_nsec / 10000000; - - *ddp = lastddate; -} - -/* - * The number of seconds between Jan 1, 1970 and Jan 1, 1980. In that - * interval there were 8 regular years and 2 leap years. - */ -#define SECONDSTO1980 (((8 * 365) + (2 * 366)) * (24 * 60 * 60)) - -static ushort_t lastdosdate; -static ulong_t lastseconds; - -void -smb_dos2unixtime(uint_t dd, uint_t dt, uint_t dh, int tzoff, - struct timespec *tsp) -{ - ulong_t seconds; - ulong_t month; - ulong_t year; - ulong_t days; - ushort_t *months; - - if (dd == 0) { - tsp->tv_sec = 0; - tsp->tv_nsec = 0; - return; - } - seconds = (((dt & DT_2SECONDS_MASK) >> DT_2SECONDS_SHIFT) << 1) - + ((dt & DT_MINUTES_MASK) >> DT_MINUTES_SHIFT) * 60 - + ((dt & DT_HOURS_MASK) >> DT_HOURS_SHIFT) * 3600 - + dh / 100; - /* - * If the year, month, and day from the last conversion are the - * same then use the saved value. - */ - if (lastdosdate != dd) { - lastdosdate = (ushort_t)dd; - days = 0; - year = (dd & DD_YEAR_MASK) >> DD_YEAR_SHIFT; - days = year * 365; - days += year / 4 + 1; /* add in leap days */ - /* - * XXX - works in 2000, but won't work in 2100. - */ - if ((year & 0x03) == 0) - days--; /* if year is a leap year */ - months = year & 0x03 ? regyear : leapyear; - month = (dd & DD_MONTH_MASK) >> DD_MONTH_SHIFT; - if (month < 1 || month > 12) { - month = 1; - } - if (month > 1) - days += months[month - 2]; - days += ((dd & DD_DAY_MASK) >> DD_DAY_SHIFT) - 1; - lastseconds = (days * 24 * 60 * 60) + SECONDSTO1980; - } - smb_time_server2local(seconds + lastseconds, tzoff, tsp); - tsp->tv_nsec = (dh % 100) * 10000000; -} - /* * In the Darwin code, this function used to compute the full path * by following the chain of n_parent pointers back to the root. @@ -388,7 +185,7 @@ smbfs_fname_tolocal(struct smbfs_fctx *ctx) errout: /* * Conversion failed, but our caller does not - * deal with errors here, so... (hack). + * deal with errors here, so just put a "?". * Don't expect to ever see this. */ (void) strlcpy(ctx->f_name, "?", ctx->f_namesz); diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h index 7c1107378b..78a50077d9 100644 --- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr.h @@ -110,6 +110,7 @@ struct smbfs_fctx { * Return values */ struct smbfattr f_attr; /* current attributes */ + u_longlong_t f_inum; /* current I number */ char *f_name; /* current file name */ int f_nmlen; /* name len */ int f_namesz; /* memory allocated */ @@ -148,7 +149,7 @@ typedef struct smbfs_fctx smbfs_fctx_t; #define f_t2 f_urq.uf_t2 /* - * smb level + * smb level (smbfs_smb.c) */ int smbfs_smb_lock(struct smbnode *np, int op, caddr_t id, offset_t start, uint64_t len, int largelock, @@ -163,25 +164,21 @@ int smbfs_smb_setfsize(struct smbnode *np, uint16_t fid, uint64_t newsize, int smbfs_smb_getfattr(struct smbnode *np, struct smbfattr *fap, struct smb_cred *scrp); -int smbfs_smb_setfattr(struct smbnode *np, uint16_t fid, +int smbfs_smb_setfattr(struct smbnode *np, int fid, uint32_t attr, struct timespec *mtime, struct timespec *atime, struct smb_cred *scrp); -int smbfs_smb_setpattr(struct smbnode *np, - uint32_t attr, struct timespec *mtime, struct timespec *atime, - struct smb_cred *scrp); - -int smbfs_smb_open(struct smbnode *np, uint32_t rights, struct smb_cred *scrp, - int *attrcacheupdated, uint16_t *fidp, const char *name, int nmlen, - int xattr, len_t *sizep, uint32_t *rightsp); +int smbfs_smb_open(struct smbnode *np, const char *name, int nmlen, + int xattr, uint32_t rights, struct smb_cred *scrp, + uint16_t *fidp, uint32_t *rightsp, struct smbfattr *fap); int smbfs_smb_tmpopen(struct smbnode *np, uint32_t rights, struct smb_cred *scrp, uint16_t *fidp); int smbfs_smb_close(struct smb_share *ssp, uint16_t fid, struct timespec *mtime, struct smb_cred *scrp); int smbfs_smb_tmpclose(struct smbnode *ssp, uint16_t fid, struct smb_cred *scrp); -int smbfs_smb_create(struct smbnode *dnp, const char *name, int len, - struct smb_cred *scrp, uint16_t *fidp, uint32_t disp, int xattr); +int smbfs_smb_create(struct smbnode *dnp, const char *name, int nmlen, + int xattr, uint32_t disp, struct smb_cred *scrp, uint16_t *fidp); int smbfs_smb_delete(struct smbnode *np, struct smb_cred *scrp, const char *name, int len, int xattr); int smbfs_smb_rename(struct smbnode *src, struct smbnode *tdnp, @@ -218,9 +215,9 @@ int smbfs_smb_setsec_m(struct smb_share *ssp, uint16_t fid, struct smb_cred *scrp, uint32_t selector, mblk_t **mp); int smbfs_getacl(vnode_t *vp, vsecattr_t *vsecattr, - int *uidp, int *gidp, int flag, cred_t *cr); + uid_t *uidp, gid_t *gidp, int flag, cred_t *cr); int smbfs_setacl(vnode_t *vp, vsecattr_t *vsecattr, - int uid, int gid, int flag, cred_t *cr); + uid_t uid, gid_t gid, int flag, cred_t *cr); int smbfs_getsd(vnode_t *vp, uint32_t sel, mblk_t **mp, cred_t *cr); int smbfs_setsd(vnode_t *vp, uint32_t sel, mblk_t **mp, cred_t *cr); @@ -238,33 +235,62 @@ int smbfs_smb_qstreaminfo(struct smbnode *np, struct smb_cred *scrp, uio_t uio, size_t *sizep); #endif /* NOT_YET */ -void smbfs_fname_tolocal(struct smbfs_fctx *ctx); +/* + * VFS-level init, fini stuff + */ -void smb_time_local2server(struct timespec *tsp, int tzoff, long *seconds); -void smb_time_server2local(ulong_t seconds, int tzoff, struct timespec *tsp); -void smb_time_NT2local(uint64_t nsec, int tzoff, struct timespec *tsp); -void smb_time_local2NT(struct timespec *tsp, int tzoff, uint64_t *nsec); -void smb_time_unix2dos(struct timespec *tsp, int tzoff, uint16_t *ddp, - uint16_t *dtp, uint8_t *dhp); -void smb_dos2unixtime(uint_t dd, uint_t dt, uint_t dh, int tzoff, - struct timespec *tsp); - -/* Stuff borrowed from NFS (and then hacked) */ -vnode_t *smbfs_make_node(vfs_t *vfsp, - const char *dir, int dirlen, - const char *name, int nmlen, - char sep, struct smbfattr *fap); -void smb_addfree(smbnode_t *sp); -void smb_addhash(smbnode_t *sp); -void smb_rmhash(smbnode_t *); +int smbfs_vfsinit(void); +void smbfs_vfsfini(void); int smbfs_subrinit(void); void smbfs_subrfini(void); int smbfs_clntinit(void); void smbfs_clntfini(void); + void smbfs_zonelist_add(smbmntinfo_t *smi); void smbfs_zonelist_remove(smbmntinfo_t *smi); + +int smbfs_check_table(struct vfs *vfsp, struct smbnode *srp); void smbfs_destroy_table(struct vfs *vfsp); +void smbfs_rflush(struct vfs *vfsp, cred_t *cr); + +/* + * Function definitions - those having to do with + * smbfs nodes, vnodes, etc + */ + +void smbfs_attrcache_prune(struct smbnode *np); +void smbfs_attrcache_remove(struct smbnode *np); +void smbfs_attrcache_rm_locked(struct smbnode *np); +#ifndef DEBUG +#define smbfs_attrcache_rm_locked(np) (np)->r_attrtime = gethrtime() +#endif +void smbfs_attr_touchdir(struct smbnode *dnp); +void smbfs_attrcache_fa(vnode_t *vp, struct smbfattr *fap); +void smbfs_cache_check(struct vnode *vp, struct smbfattr *fap); + +void smbfs_addfree(struct smbnode *sp); +void smbfs_rmhash(struct smbnode *); + +/* See avl_create in smbfs_vfsops.c */ +void smbfs_init_hash_avl(avl_tree_t *); + +uint32_t smbfs_gethash(const char *rpath, int prlen); +uint32_t smbfs_getino(struct smbnode *dnp, const char *name, int nmlen); + +extern struct smbfattr smbfs_fattr0; +smbnode_t *smbfs_node_findcreate(smbmntinfo_t *mi, + const char *dir, int dirlen, + const char *name, int nmlen, + char sep, struct smbfattr *fap); + +int smbfs_nget(vnode_t *dvp, const char *name, int nmlen, + struct smbfattr *fap, vnode_t **vpp); + +void smbfs_fname_tolocal(struct smbfs_fctx *ctx); +char *smbfs_name_alloc(const char *name, int nmlen); +void smbfs_name_free(const char *name, int nmlen); + int smbfs_readvnode(vnode_t *, uio_t *, cred_t *, struct vattr *); int smbfs_writevnode(vnode_t *vp, uio_t *uiop, cred_t *cr, int ioflag, int timo); diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr2.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr2.c index a1c65b236f..0e787c0d2c 100644 --- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr2.c +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_subr2.c @@ -27,8 +27,9 @@ */ /* - * Node hash implementation borrowed from NFS. - * See: uts/common/fs/nfs/nfs_subr.c + * Node hash implementation initially borrowed from NFS (nfs_subr.c) + * but then heavily modified. It's no longer an array of hash lists, + * but an AVL tree per mount point. More on this below. */ #include <sys/param.h> @@ -39,14 +40,9 @@ #include <sys/dnlc.h> #include <sys/kmem.h> #include <sys/sunddi.h> +#include <sys/sysmacros.h> -#ifdef APPLE -#include <sys/smb_apple.h> -#include <sys/utfconv.h> -#include <sys/smb_iconv.h> -#else #include <netsmb/smb_osdep.h> -#endif #include <netsmb/smb.h> #include <netsmb/smb_conn.h> @@ -58,62 +54,63 @@ #include <smbfs/smbfs_subr.h> /* - * The hash queues for the access to active and cached smbnodes - * are organized as doubly linked lists. A reader/writer lock - * for each hash bucket is used to control access and to synchronize - * lookups, additions, and deletions from the hash queue. + * The AVL trees (now per-mount) allow finding an smbfs node by its + * full remote path name. It also allows easy traversal of all nodes + * below (path wise) any given node. A reader/writer lock for each + * (per mount) AVL tree is used to control access and to synchronize + * lookups, additions, and deletions from that AVL tree. + * + * Previously, this code use a global array of hash chains, each with + * its own rwlock. A few struct members, functions, and comments may + * still refer to a "hash", and those should all now be considered to + * refer to the per-mount AVL tree that replaced the old hash chains. + * (i.e. member smi_hash_lk, function sn_hashfind, etc.) * * The smbnode freelist is organized as a doubly linked list with * a head pointer. Additions and deletions are synchronized via * a single mutex. * - * In order to add an smbnode to the free list, it must be hashed into - * a hash queue and the exclusive lock to the hash queue be held. - * If an smbnode is not hashed into a hash queue, then it is destroyed + * In order to add an smbnode to the free list, it must be linked into + * the mount's AVL tree and the exclusive lock for the AVL must be held. + * If an smbnode is not linked into the AVL tree, then it is destroyed * because it represents no valuable information that can be reused - * about the file. The exclusive lock to the hash queue must be - * held in order to prevent a lookup in the hash queue from finding - * the smbnode and using it and assuming that the smbnode is not on the - * freelist. The lookup in the hash queue will have the hash queue - * locked, either exclusive or shared. + * about the file. The exclusive lock for the AVL tree must be held + * in order to prevent a lookup in the AVL tree from finding the + * smbnode and using it and assuming that the smbnode is not on the + * freelist. The lookup in the AVL tree will have the AVL tree lock + * held, either exclusive or shared. * * The vnode reference count for each smbnode is not allowed to drop * below 1. This prevents external entities, such as the VM * subsystem, from acquiring references to vnodes already on the * freelist and then trying to place them back on the freelist * when their reference is released. This means that the when an - * smbnode is looked up in the hash queues, then either the smbnode + * smbnode is looked up in the AVL tree, then either the smbnode * is removed from the freelist and that reference is tranfered to * the new reference or the vnode reference count must be incremented * accordingly. The mutex for the freelist must be held in order to * accurately test to see if the smbnode is on the freelist or not. - * The hash queue lock might be held shared and it is possible that + * The AVL tree lock might be held shared and it is possible that * two different threads may race to remove the smbnode from the * freelist. This race can be resolved by holding the mutex for the * freelist. Please note that the mutex for the freelist does not * need to held if the smbnode is not on the freelist. It can not be * placed on the freelist due to the requirement that the thread * putting the smbnode on the freelist must hold the exclusive lock - * to the hash queue and the thread doing the lookup in the hash - * queue is holding either a shared or exclusive lock to the hash - * queue. + * for the AVL tree and the thread doing the lookup in the AVL tree + * is holding either a shared or exclusive lock for the AVL tree. * * The lock ordering is: * - * hash bucket lock -> vnode lock - * hash bucket lock -> freelist lock + * AVL tree lock -> vnode lock + * AVL tree lock -> freelist lock */ -static rhashq_t *smbtable; static kmutex_t smbfreelist_lock; static smbnode_t *smbfreelist = NULL; static ulong_t smbnodenew = 0; long nsmbnode = 0; -static int smbtablesize; -static int smbtablemask; -static int smbhashlen = 4; - static struct kmem_cache *smbnode_cache; /* @@ -125,19 +122,25 @@ kmutex_t smbfs_minor_lock; int smbfs_major; int smbfs_minor; +/* See smbfs_node_findcreate() */ +struct smbfattr smbfs_fattr0; + /* * Local functions. - * Not static, to aid debugging. + * SN for Smb Node */ -void smb_rmfree(smbnode_t *); -void smbinactive(smbnode_t *); -void smb_rmhash_locked(smbnode_t *); -void smb_destroy_node(smbnode_t *); +static void sn_rmfree(smbnode_t *); +static void sn_inactive(smbnode_t *); +static void sn_addhash_locked(smbnode_t *, avl_index_t); +static void sn_rmhash_locked(smbnode_t *); +static void sn_destroy_node(smbnode_t *); void smbfs_kmem_reclaim(void *cdrarg); -smbnode_t *smbhashfind(struct vfs *, const char *, int, rhashq_t *); -static vnode_t *make_smbnode(vfs_t *, char *, int, rhashq_t *, int *); +static smbnode_t * +sn_hashfind(smbmntinfo_t *, const char *, int, avl_index_t *); +static smbnode_t * +make_smbnode(smbmntinfo_t *, const char *, int, int *); /* * Free the resources associated with an smbnode. @@ -145,135 +148,147 @@ static vnode_t *make_smbnode(vfs_t *, char *, int, rhashq_t *, int *); * * NFS: nfs_subr.c:rinactive */ -void -smbinactive(smbnode_t *np) +static void +sn_inactive(smbnode_t *np) { + cred_t *oldcr; + char *orpath; + int orplen; - if (np->n_rpath) { - kmem_free(np->n_rpath, np->n_rplen + 1); - np->n_rpath = NULL; - } + /* + * Flush and invalidate all pages (todo) + * Free any held credentials and caches... + * etc. (See NFS code) + */ + mutex_enter(&np->r_statelock); + + oldcr = np->r_cred; + np->r_cred = NULL; + + orpath = np->n_rpath; + orplen = np->n_rplen; + np->n_rpath = NULL; + np->n_rplen = 0; + + mutex_exit(&np->r_statelock); + + if (oldcr != NULL) + crfree(oldcr); + + if (orpath != NULL) + kmem_free(orpath, orplen + 1); } /* - * Return a vnode for the given CIFS directory and filename. - * If no smbnode exists for this fhandle, create one and put it - * into the hash queues. If the smbnode for this fhandle - * already exists, return it. + * Find and optionally create an smbnode for the passed + * mountinfo, directory, separator, and name. If the + * desired smbnode already exists, return a reference. + * If the file attributes pointer is non-null, the node + * is created if necessary and linked into the AVL tree. + * + * Callers that need a node created but don't have the + * real attributes pass smbfs_fattr0 to force creation. * - * Note: make_smbnode() may upgrade the hash bucket lock to exclusive. + * Note: make_smbnode() may upgrade the "hash" lock to exclusive. * * NFS: nfs_subr.c:makenfsnode */ -vnode_t * -smbfs_make_node( - vfs_t *vfsp, - const char *dir, +smbnode_t * +smbfs_node_findcreate( + smbmntinfo_t *mi, + const char *dirnm, int dirlen, const char *name, int nmlen, char sep, struct smbfattr *fap) { - char *rpath; - int rplen, idx; - uint32_t hash; - rhashq_t *rhtp; + char tmpbuf[256]; + size_t rpalloc; + char *p, *rpath; + int rplen; smbnode_t *np; vnode_t *vp; -#ifdef NOT_YET - vattr_t va; -#endif int newnode; /* - * Build the full path name in allocated memory - * so we have it for lookup, etc. Note the - * special case at the root (dir=="\\", dirlen==1) - * where this does not add a slash separator. - * To do that would make a double slash, which - * has special meaning in CIFS. - * - * ToDo: Would prefer to allocate a remote path - * only when we will create a new node. + * Build the search string, either in tmpbuf or + * in allocated memory if larger than tmpbuf. */ - if (dirlen <= 1 && sep == '\\') - sep = '\0'; /* no slash */ - - /* Compute the length of rpath and allocate. */ rplen = dirlen; - if (sep) + if (sep != '\0') rplen++; - if (name) - rplen += nmlen; - - rpath = kmem_alloc(rplen + 1, KM_SLEEP); - - /* Fill in rpath */ - bcopy(dir, rpath, dirlen); - if (sep) - rpath[dirlen++] = sep; - if (name) - bcopy(name, &rpath[dirlen], nmlen); - rpath[rplen] = 0; - - hash = smbfs_hash(rpath, rplen); - idx = hash & smbtablemask; - rhtp = &smbtable[idx]; - rw_enter(&rhtp->r_lock, RW_READER); - - vp = make_smbnode(vfsp, rpath, rplen, rhtp, &newnode); - np = VTOSMB(vp); - np->n_ino = hash; /* Equivalent to: smbfs_getino() */ + rplen += nmlen; + if (rplen < sizeof (tmpbuf)) { + /* use tmpbuf */ + rpalloc = 0; + rpath = tmpbuf; + } else { + rpalloc = rplen + 1; + rpath = kmem_alloc(rpalloc, KM_SLEEP); + } + p = rpath; + bcopy(dirnm, p, dirlen); + p += dirlen; + if (sep != '\0') + *p++ = sep; + if (name != NULL) { + bcopy(name, p, nmlen); + p += nmlen; + } + ASSERT(p == rpath + rplen); /* - * Note: make_smbnode keeps a reference to rpath in - * new nodes it creates, so only free when we found - * an existing node. + * Find or create a node with this path. */ - if (!newnode) { - kmem_free(rpath, rplen + 1); - rpath = NULL; - } + rw_enter(&mi->smi_hash_lk, RW_READER); + if (fap == NULL) + np = sn_hashfind(mi, rpath, rplen, NULL); + else + np = make_smbnode(mi, rpath, rplen, &newnode); + rw_exit(&mi->smi_hash_lk); + + if (rpalloc) + kmem_free(rpath, rpalloc); if (fap == NULL) { -#ifdef NOT_YET - if (newnode) { - PURGE_ATTRCACHE(vp); - } -#endif - rw_exit(&rhtp->r_lock); - return (vp); + /* + * Caller is "just looking" (no create) + * so np may or may not be NULL here. + * Either way, we're done. + */ + return (np); } - /* Have SMB attributes. */ - vp->v_type = (fap->fa_attr & SMB_FA_DIR) ? VDIR : VREG; - /* XXX: np->n_ino = fap->fa_ino; see above */ - np->r_size = fap->fa_size; - /* XXX: np->r_attr = *fap here instead? */ - np->r_atime = fap->fa_atime; - np->r_ctime = fap->fa_ctime; - np->r_mtime = fap->fa_mtime; + /* + * We should have a node, possibly created. + * Do we have (real) attributes to apply? + */ + ASSERT(np != NULL); + if (fap == &smbfs_fattr0) + return (np); -#ifdef NOT_YET + /* + * Apply the given attributes to this node, + * dealing with any cache impact, etc. + */ + vp = SMBTOV(np); if (!newnode) { - rw_exit(&rhtp->r_lock); - (void) nfs_cache_fattr(vp, attr, &va, t, cr); - } else { - if (attr->na_type < NFNON || attr->na_type > NFSOC) - vp->v_type = VBAD; - else - vp->v_type = n2v_type(attr); - vp->v_rdev = makedevice(attr->rdev.specdata1, - attr->rdev.specdata2); - nfs_attrcache(vp, attr, t); - rw_exit(&rhtp->r_lock); + /* + * Found an existing node. + * Maybe purge caches... + */ + smbfs_cache_check(vp, fap); } -#else - rw_exit(&rhtp->r_lock); -#endif + smbfs_attrcache_fa(vp, fap); - return (vp); + /* + * Note NFS sets vp->v_type here, assuming it + * can never change for the life of a node. + * We allow v_type to change, and set it in + * smbfs_attrcache(). Also: mode, uid, gid + */ + return (np); } /* @@ -285,33 +300,32 @@ smbfs_make_node( * Find or create an smbnode. * NFS: nfs_subr.c:make_rnode */ -static vnode_t * +static smbnode_t * make_smbnode( - vfs_t *vfsp, - char *rpath, + smbmntinfo_t *mi, + const char *rpath, int rplen, - rhashq_t *rhtp, int *newnode) { smbnode_t *np; smbnode_t *tnp; vnode_t *vp; - smbmntinfo_t *mi; + vfs_t *vfsp; + avl_index_t where; + char *new_rpath = NULL; - ASSERT(RW_READ_HELD(&rhtp->r_lock)); - - mi = VFTOSMI(vfsp); + ASSERT(RW_READ_HELD(&mi->smi_hash_lk)); + vfsp = mi->smi_vfsp; start: - np = smbhashfind(vfsp, rpath, rplen, rhtp); + np = sn_hashfind(mi, rpath, rplen, NULL); if (np != NULL) { - vp = SMBTOV(np); *newnode = 0; - return (vp); + return (np); } /* Note: will retake this lock below. */ - rw_exit(&rhtp->r_lock); + rw_exit(&mi->smi_hash_lk); /* * see if we can find something on the freelist @@ -319,33 +333,36 @@ start: mutex_enter(&smbfreelist_lock); if (smbfreelist != NULL && smbnodenew >= nsmbnode) { np = smbfreelist; - smb_rmfree(np); + sn_rmfree(np); mutex_exit(&smbfreelist_lock); vp = SMBTOV(np); if (np->r_flags & RHASHED) { - rw_enter(&np->r_hashq->r_lock, RW_WRITER); + smbmntinfo_t *tmp_mi = np->n_mount; + ASSERT(tmp_mi != NULL); + rw_enter(&tmp_mi->smi_hash_lk, RW_WRITER); mutex_enter(&vp->v_lock); if (vp->v_count > 1) { vp->v_count--; mutex_exit(&vp->v_lock); - rw_exit(&np->r_hashq->r_lock); - rw_enter(&rhtp->r_lock, RW_READER); + rw_exit(&tmp_mi->smi_hash_lk); + /* start over */ + rw_enter(&mi->smi_hash_lk, RW_READER); goto start; } mutex_exit(&vp->v_lock); - smb_rmhash_locked(np); - rw_exit(&np->r_hashq->r_lock); + sn_rmhash_locked(np); + rw_exit(&tmp_mi->smi_hash_lk); } - smbinactive(np); + sn_inactive(np); mutex_enter(&vp->v_lock); if (vp->v_count > 1) { vp->v_count--; mutex_exit(&vp->v_lock); - rw_enter(&rhtp->r_lock, RW_READER); + rw_enter(&mi->smi_hash_lk, RW_READER); goto start; } mutex_exit(&vp->v_lock); @@ -380,6 +397,13 @@ start: vp = new_vp; } + /* + * Allocate and copy the rpath we'll need below. + */ + new_rpath = kmem_alloc(rplen + 1, KM_SLEEP); + bcopy(rpath, new_rpath, rplen); + new_rpath[rplen] = '\0'; + /* Initialize smbnode_t */ bzero(np, sizeof (*np)); @@ -391,11 +415,11 @@ start: np->r_vnode = vp; np->n_mount = mi; - np->r_hashq = rhtp; + np->n_fid = SMB_FID_UNUSED; - np->n_uid = UID_NOBODY; - np->n_gid = GID_NOBODY; - /* XXX: make attributes stale? */ + np->n_uid = mi->smi_uid; + np->n_gid = mi->smi_gid; + /* Leave attributes "stale." */ #if 0 /* XXX dircache */ /* @@ -414,77 +438,94 @@ start: vp->v_type = VNON; /* - * There is a race condition if someone else - * alloc's the smbnode while no locks are held, so we - * check again and recover if found. + * We entered with mi->smi_hash_lk held (reader). + * Retake it now, (as the writer). + * Will return with it held. */ - rw_enter(&rhtp->r_lock, RW_WRITER); - tnp = smbhashfind(vfsp, rpath, rplen, rhtp); + rw_enter(&mi->smi_hash_lk, RW_WRITER); + + /* + * There is a race condition where someone else + * may alloc the smbnode while no locks are held, + * so check again and recover if found. + */ + tnp = sn_hashfind(mi, rpath, rplen, &where); if (tnp != NULL) { - vp = SMBTOV(tnp); + /* + * Lost the race. Put the node we were building + * on the free list and return the one we found. + */ + rw_exit(&mi->smi_hash_lk); + kmem_free(new_rpath, rplen + 1); + smbfs_addfree(np); + rw_enter(&mi->smi_hash_lk, RW_READER); *newnode = 0; - rw_exit(&rhtp->r_lock); - /* The node we were building goes on the free list. */ - smb_addfree(np); - rw_enter(&rhtp->r_lock, RW_READER); - return (vp); + return (tnp); } /* - * Hash search identifies nodes by the full pathname, - * so store that before linking in the hash list. - * Note: caller allocates the rpath, and knows - * about this reference when *newnode is set. + * Hash search identifies nodes by the remote path + * (n_rpath) so fill that in now, before linking + * this node into the node cache (AVL tree). */ - np->n_rpath = rpath; + np->n_rpath = new_rpath; np->n_rplen = rplen; + np->n_ino = smbfs_gethash(new_rpath, rplen); - smb_addhash(np); + sn_addhash_locked(np, where); *newnode = 1; - return (vp); + return (np); } /* - * smb_addfree - * Put a smbnode on the free list. + * smbfs_addfree + * Put an smbnode on the free list, or destroy it immediately + * if it offers no value were it to be reclaimed later. Also + * destroy immediately when we have too many smbnodes, etc. * * Normally called by smbfs_inactive, but also * called in here during cleanup operations. * - * Smbnodes which were allocated above and beyond the normal limit - * are immediately freed. - * * NFS: nfs_subr.c:rp_addfree */ void -smb_addfree(smbnode_t *np) +smbfs_addfree(smbnode_t *np) { vnode_t *vp; struct vfs *vfsp; + smbmntinfo_t *mi; + + ASSERT(np->r_freef == NULL && np->r_freeb == NULL); vp = SMBTOV(np); ASSERT(vp->v_count >= 1); - ASSERT(np->r_freef == NULL && np->r_freeb == NULL); + + vfsp = vp->v_vfsp; + mi = VFTOSMI(vfsp); /* - * If we have too many smbnodes allocated and there are no - * references to this smbnode, or if the smbnode is no longer - * accessible by it does not reside in the hash queues, - * or if an i/o error occurred while writing to the file, - * then just free it instead of putting it on the smbnode - * freelist. + * If there are no more references to this smbnode and: + * we have too many smbnodes allocated, or if the node + * is no longer accessible via the AVL tree (!RHASHED), + * or an i/o error occurred while writing to the file, + * or it's part of an unmounted FS, then try to destroy + * it instead of putting it on the smbnode freelist. */ - vfsp = vp->v_vfsp; - if (((smbnodenew > nsmbnode || !(np->r_flags & RHASHED) || - np->r_error || (vfsp->vfs_flag & VFS_UNMOUNTED)) && - np->r_count == 0)) { + if (np->r_count == 0 && ( + (np->r_flags & RHASHED) == 0 || + (np->r_error != 0) || + (vfsp->vfs_flag & VFS_UNMOUNTED) || + (smbnodenew > nsmbnode))) { + + /* Try to destroy this node. */ + if (np->r_flags & RHASHED) { - rw_enter(&np->r_hashq->r_lock, RW_WRITER); + rw_enter(&mi->smi_hash_lk, RW_WRITER); mutex_enter(&vp->v_lock); if (vp->v_count > 1) { vp->v_count--; mutex_exit(&vp->v_lock); - rw_exit(&np->r_hashq->r_lock); + rw_exit(&mi->smi_hash_lk); return; /* * Will get another call later, @@ -492,23 +533,23 @@ smb_addfree(smbnode_t *np) */ } mutex_exit(&vp->v_lock); - smb_rmhash_locked(np); - rw_exit(&np->r_hashq->r_lock); + sn_rmhash_locked(np); + rw_exit(&mi->smi_hash_lk); } - smbinactive(np); + sn_inactive(np); /* * Recheck the vnode reference count. We need to * make sure that another reference has not been * acquired while we were not holding v_lock. The - * smbnode is not in the smbnode hash queues, so the - * only way for a reference to have been acquired + * smbnode is not in the smbnode "hash" AVL tree, so + * the only way for a reference to have been acquired * is for a VOP_PUTPAGE because the smbnode was marked - * with RDIRTY or for a modified page. This + * with RDIRTY or for a modified page. This vnode * reference may have been acquired before our call - * to smbinactive. The i/o may have been completed, - * thus allowing smbinactive to complete, but the + * to sn_inactive. The i/o may have been completed, + * thus allowing sn_inactive to complete, but the * reference to the vnode may not have been released * yet. In any case, the smbnode can not be destroyed * until the other references to this vnode have been @@ -525,33 +566,31 @@ smb_addfree(smbnode_t *np) } mutex_exit(&vp->v_lock); - smb_destroy_node(np); + sn_destroy_node(np); return; } + /* - * Lock the hash queue and then recheck the reference count + * Lock the AVL tree and then recheck the reference count * to ensure that no other threads have acquired a reference * to indicate that the smbnode should not be placed on the * freelist. If another reference has been acquired, then * just release this one and let the other thread complete * the processing of adding this smbnode to the freelist. */ - rw_enter(&np->r_hashq->r_lock, RW_WRITER); + rw_enter(&mi->smi_hash_lk, RW_WRITER); mutex_enter(&vp->v_lock); if (vp->v_count > 1) { vp->v_count--; mutex_exit(&vp->v_lock); - rw_exit(&np->r_hashq->r_lock); + rw_exit(&mi->smi_hash_lk); return; } mutex_exit(&vp->v_lock); /* - * If there is no cached data or metadata for this file, then - * put the smbnode on the front of the freelist so that it will - * be reused before other smbnodes which may have cached data or - * metadata associated with them. + * Put this node on the free list. */ mutex_enter(&smbfreelist_lock); if (smbfreelist == NULL) { @@ -566,7 +605,7 @@ smb_addfree(smbnode_t *np) } mutex_exit(&smbfreelist_lock); - rw_exit(&np->r_hashq->r_lock); + rw_exit(&mi->smi_hash_lk); } /* @@ -577,8 +616,8 @@ smb_addfree(smbnode_t *np) * * NFS: nfs_subr.c:rp_rmfree */ -void -smb_rmfree(smbnode_t *np) +static void +sn_rmfree(smbnode_t *np) { ASSERT(MUTEX_HELD(&smbfreelist_lock)); @@ -597,23 +636,21 @@ smb_rmfree(smbnode_t *np) } /* - * Put a smbnode in the hash table. + * Put an smbnode in the "hash" AVL tree. * - * The caller must be holding the exclusive hash queue lock. + * The caller must be hold the rwlock as writer. * * NFS: nfs_subr.c:rp_addhash */ -void -smb_addhash(smbnode_t *np) +static void +sn_addhash_locked(smbnode_t *np, avl_index_t where) { + smbmntinfo_t *mi = np->n_mount; - ASSERT(RW_WRITE_HELD(&np->r_hashq->r_lock)); + ASSERT(RW_WRITE_HELD(&mi->smi_hash_lk)); ASSERT(!(np->r_flags & RHASHED)); - np->r_hashf = np->r_hashq->r_hashf; - np->r_hashq->r_hashf = np; - np->r_hashb = (smbnode_t *)np->r_hashq; - np->r_hashf->r_hashb = np; + avl_insert(&mi->smi_hash_avl, np, where); mutex_enter(&np->r_statelock); np->r_flags |= RHASHED; @@ -621,21 +658,21 @@ smb_addhash(smbnode_t *np) } /* - * Remove a smbnode from the hash table. + * Remove an smbnode from the "hash" AVL tree. * - * The caller must be holding the hash queue lock. + * The caller must hold the rwlock as writer. * * NFS: nfs_subr.c:rp_rmhash_locked */ -void -smb_rmhash_locked(smbnode_t *np) +static void +sn_rmhash_locked(smbnode_t *np) { + smbmntinfo_t *mi = np->n_mount; - ASSERT(RW_WRITE_HELD(&np->r_hashq->r_lock)); + ASSERT(RW_WRITE_HELD(&mi->smi_hash_lk)); ASSERT(np->r_flags & RHASHED); - np->r_hashb->r_hashf = np->r_hashf; - np->r_hashf->r_hashb = np->r_hashb; + avl_remove(&mi->smi_hash_avl, np); mutex_enter(&np->r_statelock); np->r_flags &= ~RHASHED; @@ -643,83 +680,177 @@ smb_rmhash_locked(smbnode_t *np) } /* - * Remove a smbnode from the hash table. + * Remove an smbnode from the "hash" AVL tree. * - * The caller must not be holding the hash queue lock. + * The caller must not be holding the rwlock. */ void -smb_rmhash(smbnode_t *np) +smbfs_rmhash(smbnode_t *np) { + smbmntinfo_t *mi = np->n_mount; - rw_enter(&np->r_hashq->r_lock, RW_WRITER); - smb_rmhash_locked(np); - rw_exit(&np->r_hashq->r_lock); + rw_enter(&mi->smi_hash_lk, RW_WRITER); + sn_rmhash_locked(np); + rw_exit(&mi->smi_hash_lk); } /* - * Lookup a smbnode by fhandle. + * Lookup an smbnode by remote pathname * - * The caller must be holding the hash queue lock, either shared or exclusive. - * XXX: make static? + * The caller must be holding the AVL rwlock, either shared or exclusive. * * NFS: nfs_subr.c:rfind */ -smbnode_t * -smbhashfind( - struct vfs *vfsp, +static smbnode_t * +sn_hashfind( + smbmntinfo_t *mi, const char *rpath, int rplen, - rhashq_t *rhtp) + avl_index_t *pwhere) /* optional */ { + smbfs_node_hdr_t nhdr; smbnode_t *np; vnode_t *vp; - ASSERT(RW_LOCK_HELD(&rhtp->r_lock)); + ASSERT(RW_LOCK_HELD(&mi->smi_hash_lk)); - for (np = rhtp->r_hashf; np != (smbnode_t *)rhtp; np = np->r_hashf) { - vp = SMBTOV(np); - if (vp->v_vfsp == vfsp && - np->n_rplen == rplen && - bcmp(np->n_rpath, rpath, rplen) == 0) { - /* - * remove smbnode from free list, if necessary. - */ - if (np->r_freef != NULL) { - mutex_enter(&smbfreelist_lock); - /* - * If the smbnode is on the freelist, - * then remove it and use that reference - * as the new reference. Otherwise, - * need to increment the reference count. - */ - if (np->r_freef != NULL) { - smb_rmfree(np); - mutex_exit(&smbfreelist_lock); - } else { - mutex_exit(&smbfreelist_lock); - VN_HOLD(vp); - } - } else - VN_HOLD(vp); - return (np); + bzero(&nhdr, sizeof (nhdr)); + nhdr.hdr_n_rpath = (char *)rpath; + nhdr.hdr_n_rplen = rplen; + + /* See smbfs_node_cmp below. */ + np = avl_find(&mi->smi_hash_avl, &nhdr, pwhere); + + if (np == NULL) + return (NULL); + + /* + * Found it in the "hash" AVL tree. + * Remove from free list, if necessary. + */ + vp = SMBTOV(np); + if (np->r_freef != NULL) { + mutex_enter(&smbfreelist_lock); + /* + * If the smbnode is on the freelist, + * then remove it and use that reference + * as the new reference. Otherwise, + * need to increment the reference count. + */ + if (np->r_freef != NULL) { + sn_rmfree(np); + mutex_exit(&smbfreelist_lock); + } else { + mutex_exit(&smbfreelist_lock); + VN_HOLD(vp); } + } else + VN_HOLD(vp); + + return (np); +} + +static int +smbfs_node_cmp(const void *va, const void *vb) +{ + const smbfs_node_hdr_t *a = va; + const smbfs_node_hdr_t *b = vb; + int clen, diff; + + /* + * Same semantics as strcmp, but does not + * assume the strings are null terminated. + */ + clen = (a->hdr_n_rplen < b->hdr_n_rplen) ? + a->hdr_n_rplen : b->hdr_n_rplen; + diff = strncmp(a->hdr_n_rpath, b->hdr_n_rpath, clen); + if (diff < 0) + return (-1); + if (diff > 0) + return (1); + /* they match through clen */ + if (b->hdr_n_rplen > clen) + return (-1); + if (a->hdr_n_rplen > clen) + return (1); + return (0); +} + +/* + * Setup the "hash" AVL tree used for our node cache. + * See: smbfs_mount, smbfs_destroy_table. + */ +void +smbfs_init_hash_avl(avl_tree_t *avl) +{ + avl_create(avl, smbfs_node_cmp, sizeof (smbnode_t), + offsetof(smbnode_t, r_avl_node)); +} + +/* + * Invalidate the cached attributes for all nodes "under" the + * passed-in node. Note: the passed-in node is NOT affected by + * this call. This is used both for files under some directory + * after the directory is deleted or renamed, and for extended + * attribute files (named streams) under a plain file after that + * file is renamed or deleted. + * + * Do this by walking the AVL tree starting at the passed in node, + * and continuing while the visited nodes have a path prefix matching + * the entire path of the passed-in node, and a separator just after + * that matching path prefix. Watch out for cases where the AVL tree + * order may not exactly match the order of an FS walk, i.e. + * consider this sequence: + * "foo" (directory) + * "foo bar" (name containing a space) + * "foo/bar" + * The walk needs to skip "foo bar" and keep going until it finds + * something that doesn't match the "foo" name prefix. + */ +void +smbfs_attrcache_prune(smbnode_t *top_np) +{ + smbmntinfo_t *mi; + smbnode_t *np; + char *rpath; + int rplen; + + mi = top_np->n_mount; + rw_enter(&mi->smi_hash_lk, RW_READER); + + np = top_np; + rpath = top_np->n_rpath; + rplen = top_np->n_rplen; + for (;;) { + np = avl_walk(&mi->smi_hash_avl, np, AVL_AFTER); + if (np == NULL) + break; + if (np->n_rplen < rplen) + break; + if (0 != strncmp(np->n_rpath, rpath, rplen)) + break; + if (np->n_rplen > rplen && ( + np->n_rpath[rplen] == ':' || + np->n_rpath[rplen] == '\\')) + smbfs_attrcache_remove(np); } - return (NULL); + + rw_exit(&mi->smi_hash_lk); } #ifdef SMB_VNODE_DEBUG -int smb_check_table_debug = 1; +int smbfs_check_table_debug = 1; #else /* SMB_VNODE_DEBUG */ -int smb_check_table_debug = 0; +int smbfs_check_table_debug = 0; #endif /* SMB_VNODE_DEBUG */ /* * Return 1 if there is a active vnode belonging to this vfs in the - * smbtable cache. + * smbnode cache. * * Several of these checks are done without holding the usual - * locks. This is safe because destroy_smbtable(), smb_addfree(), + * locks. This is safe because destroy_smbtable(), smbfs_addfree(), * etc. will redo the necessary checks before actually destroying * any smbnodes. * @@ -729,117 +860,148 @@ int smb_check_table_debug = 0; * Relatively harmless, so left 'em in. */ int -smb_check_table(struct vfs *vfsp, smbnode_t *rtnp) +smbfs_check_table(struct vfs *vfsp, smbnode_t *rtnp) { + smbmntinfo_t *mi; smbnode_t *np; vnode_t *vp; - int index; int busycnt = 0; - for (index = 0; index < smbtablesize; index++) { - rw_enter(&smbtable[index].r_lock, RW_READER); - for (np = smbtable[index].r_hashf; - np != (smbnode_t *)(&smbtable[index]); - np = np->r_hashf) { - if (np == rtnp) - continue; /* skip the root */ - vp = SMBTOV(np); - if (vp->v_vfsp != vfsp) - continue; /* skip other mount */ - - /* Now the 'busy' checks: */ - /* Not on the free list? */ - if (np->r_freef == NULL) { - SMBVDEBUG("!r_freef: node=0x%p, v_path=%s\n", - (void *)np, vp->v_path); - busycnt++; - } + mi = VFTOSMI(vfsp); + rw_enter(&mi->smi_hash_lk, RW_READER); + for (np = avl_first(&mi->smi_hash_avl); np != NULL; + np = avl_walk(&mi->smi_hash_avl, np, AVL_AFTER)) { - /* Has dirty pages? */ - if (vn_has_cached_data(vp) && - (np->r_flags & RDIRTY)) { - SMBVDEBUG("is dirty: node=0x%p, v_path=%s\n", - (void *)np, vp->v_path); - busycnt++; - } + if (np == rtnp) + continue; /* skip the root */ + vp = SMBTOV(np); - /* Other refs? (not reflected in v_count) */ - if (np->r_count > 0) { - SMBVDEBUG("+r_count: node=0x%p, v_path=%s\n", - (void *)np, vp->v_path); - busycnt++; - } + /* Now the 'busy' checks: */ + /* Not on the free list? */ + if (np->r_freef == NULL) { + SMBVDEBUG("!r_freef: node=0x%p, rpath=%s\n", + (void *)np, np->n_rpath); + busycnt++; + } - if (busycnt && !smb_check_table_debug) - break; + /* Has dirty pages? */ + if (vn_has_cached_data(vp) && + (np->r_flags & RDIRTY)) { + SMBVDEBUG("is dirty: node=0x%p, rpath=%s\n", + (void *)np, np->n_rpath); + busycnt++; + } + /* Other refs? (not reflected in v_count) */ + if (np->r_count > 0) { + SMBVDEBUG("+r_count: node=0x%p, rpath=%s\n", + (void *)np, np->n_rpath); + busycnt++; } - rw_exit(&smbtable[index].r_lock); + + if (busycnt && !smbfs_check_table_debug) + break; + } + rw_exit(&mi->smi_hash_lk); + return (busycnt); } /* - * Destroy inactive vnodes from the hash queues which belong to this + * Destroy inactive vnodes from the AVL tree which belong to this * vfs. It is essential that we destroy all inactive vnodes during a * forced unmount as well as during a normal unmount. * * NFS: nfs_subr.c:destroy_rtable + * + * In here, we're normally destrying all or most of the AVL tree, + * so the natural choice is to use avl_destroy_nodes. However, + * there may be a few busy nodes that should remain in the AVL + * tree when we're done. The solution: use a temporary tree to + * hold the busy nodes until we're done destroying the old tree, + * then copy the temporary tree over the (now emtpy) real tree. */ void smbfs_destroy_table(struct vfs *vfsp) { - int index; + avl_tree_t tmp_avl; + smbmntinfo_t *mi; smbnode_t *np; smbnode_t *rlist; - smbnode_t *r_hashf; - vnode_t *vp; + void *v; + mi = VFTOSMI(vfsp); rlist = NULL; + smbfs_init_hash_avl(&tmp_avl); - for (index = 0; index < smbtablesize; index++) { - rw_enter(&smbtable[index].r_lock, RW_WRITER); - for (np = smbtable[index].r_hashf; - np != (smbnode_t *)(&smbtable[index]); - np = r_hashf) { - /* save the hash pointer before destroying */ - r_hashf = np->r_hashf; - vp = SMBTOV(np); - if (vp->v_vfsp == vfsp) { - mutex_enter(&smbfreelist_lock); - if (np->r_freef != NULL) { - smb_rmfree(np); - mutex_exit(&smbfreelist_lock); - smb_rmhash_locked(np); - np->r_hashf = rlist; - rlist = np; - } else - mutex_exit(&smbfreelist_lock); - } + rw_enter(&mi->smi_hash_lk, RW_WRITER); + v = NULL; + while ((np = avl_destroy_nodes(&mi->smi_hash_avl, &v)) != NULL) { + + mutex_enter(&smbfreelist_lock); + if (np->r_freef == NULL) { + /* + * Busy node (not on the free list). + * Will keep in the final AVL tree. + */ + mutex_exit(&smbfreelist_lock); + avl_add(&tmp_avl, np); + } else { + /* + * It's on the free list. Remove and + * arrange for it to be destroyed. + */ + sn_rmfree(np); + mutex_exit(&smbfreelist_lock); + + /* + * Last part of sn_rmhash_locked(). + * NB: avl_destroy_nodes has already + * removed this from the "hash" AVL. + */ + mutex_enter(&np->r_statelock); + np->r_flags &= ~RHASHED; + mutex_exit(&np->r_statelock); + + /* + * Add to the list of nodes to destroy. + * Borrowing avl_child[0] for this list. + */ + np->r_avl_node.avl_child[0] = + (struct avl_node *)rlist; + rlist = np; } - rw_exit(&smbtable[index].r_lock); } + avl_destroy(&mi->smi_hash_avl); - for (np = rlist; np != NULL; np = rlist) { - rlist = np->r_hashf; - /* - * This call to smb_addfree will end up destroying the - * smbnode, but in a safe way with the appropriate set - * of checks done. - */ - smb_addfree(np); - } + /* + * Replace the (now destroyed) "hash" AVL with the + * temporary AVL, which restores the busy nodes. + */ + mi->smi_hash_avl = tmp_avl; + rw_exit(&mi->smi_hash_lk); + /* + * Now destroy the nodes on our temporary list (rlist). + * This call to smbfs_addfree will end up destroying the + * smbnode, but in a safe way with the appropriate set + * of checks done. + */ + while ((np = rlist) != NULL) { + rlist = (smbnode_t *)np->r_avl_node.avl_child[0]; + smbfs_addfree(np); + } } /* * This routine destroys all the resources associated with the smbnode - * and then the smbnode itself. + * and then the smbnode itself. Note: sn_inactive has been called. * * NFS: nfs_subr.c:destroy_rnode */ -void -smb_destroy_node(smbnode_t *np) +static void +sn_destroy_node(smbnode_t *np) { vnode_t *vp; vfs_t *vfsp; @@ -850,6 +1012,8 @@ smb_destroy_node(smbnode_t *np) ASSERT(vp->v_count == 1); ASSERT(np->r_count == 0); ASSERT(np->r_mapcnt == 0); + ASSERT(np->r_cred == NULL); + ASSERT(np->n_rpath == NULL); ASSERT(!(np->r_flags & RHASHED)); ASSERT(np->r_freef == NULL && np->r_freeb == NULL); atomic_add_long((ulong_t *)&smbnodenew, -1); @@ -859,7 +1023,17 @@ smb_destroy_node(smbnode_t *np) VFS_RELE(vfsp); } -/* rflush? */ +/* + * Flush all vnodes in this (or every) vfs. + * Used by nfs_sync and by nfs_unmount. + */ +/*ARGSUSED*/ +void +smbfs_rflush(struct vfs *vfsp, cred_t *cr) +{ + /* Todo: mmap support. */ +} + /* access cache */ /* client handles */ @@ -867,17 +1041,15 @@ smb_destroy_node(smbnode_t *np) * initialize resources that are used by smbfs_subr.c * this is called from the _init() routine (by the way of smbfs_clntinit()) * - * allocate and initialze smbfs hash table * NFS: nfs_subr.c:nfs_subrinit */ int smbfs_subrinit(void) { - int i; ulong_t nsmbnode_max; /* - * Allocate and initialize the smbnode hash queues + * Allocate and initialize the smbnode cache */ if (nsmbnode <= 0) nsmbnode = ncsize; /* dnlc.h */ @@ -889,14 +1061,6 @@ smbfs_subrinit(void) nsmbnode = nsmbnode_max; } - smbtablesize = 1 << highbit(nsmbnode / smbhashlen); - smbtablemask = smbtablesize - 1; - smbtable = kmem_alloc(smbtablesize * sizeof (*smbtable), KM_SLEEP); - for (i = 0; i < smbtablesize; i++) { - smbtable[i].r_hashf = (smbnode_t *)(&smbtable[i]); - smbtable[i].r_hashb = (smbnode_t *)(&smbtable[i]); - rw_init(&smbtable[i].r_lock, NULL, RW_DEFAULT, NULL); - } smbnode_cache = kmem_cache_create("smbnode_cache", sizeof (smbnode_t), 0, NULL, NULL, smbfs_kmem_reclaim, NULL, NULL, 0); @@ -926,17 +1090,12 @@ smbfs_subrinit(void) void smbfs_subrfini(void) { - int i; /* - * Deallocate the smbnode hash queues + * Destroy the smbnode cache */ kmem_cache_destroy(smbnode_cache); - for (i = 0; i < smbtablesize; i++) - rw_destroy(&smbtable[i].r_lock); - kmem_free(smbtable, smbtablesize * sizeof (*smbtable)); - /* * Destroy the various mutexes and reader/writer locks */ @@ -950,43 +1109,42 @@ smbfs_subrfini(void) * Support functions for smbfs_kmem_reclaim */ -static int +static void smbfs_node_reclaim(void) { - int freed; + smbmntinfo_t *mi; smbnode_t *np; vnode_t *vp; - freed = 0; mutex_enter(&smbfreelist_lock); while ((np = smbfreelist) != NULL) { - smb_rmfree(np); + sn_rmfree(np); mutex_exit(&smbfreelist_lock); if (np->r_flags & RHASHED) { vp = SMBTOV(np); - rw_enter(&np->r_hashq->r_lock, RW_WRITER); + mi = np->n_mount; + rw_enter(&mi->smi_hash_lk, RW_WRITER); mutex_enter(&vp->v_lock); if (vp->v_count > 1) { vp->v_count--; mutex_exit(&vp->v_lock); - rw_exit(&np->r_hashq->r_lock); + rw_exit(&mi->smi_hash_lk); mutex_enter(&smbfreelist_lock); continue; } mutex_exit(&vp->v_lock); - smb_rmhash_locked(np); - rw_exit(&np->r_hashq->r_lock); + sn_rmhash_locked(np); + rw_exit(&mi->smi_hash_lk); } /* - * This call to smb_addfree will end up destroying the + * This call to smbfs_addfree will end up destroying the * smbnode, but in a safe way with the appropriate set * of checks done. */ - smb_addfree(np); + smbfs_addfree(np); mutex_enter(&smbfreelist_lock); } mutex_exit(&smbfreelist_lock); - return (freed); } /* @@ -999,7 +1157,7 @@ smbfs_node_reclaim(void) void smbfs_kmem_reclaim(void *cdrarg) { - (void) smbfs_node_reclaim(); + smbfs_node_reclaim(); } /* nfs failover stuff */ diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c index b616543a92..d33b0ee0a1 100644 --- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c @@ -39,6 +39,7 @@ #include <sys/systm.h> #include <sys/cred.h> +#include <sys/time.h> #include <sys/vfs.h> #include <sys/vnode.h> #include <fs/fs_subr.h> @@ -173,7 +174,7 @@ static void smbfs_freevfs(vfs_t *); int _init(void) { - int status; + int error; /* * Check compiled-in version of "nsmb" @@ -186,13 +187,30 @@ _init(void) smbfs_mountcount = 0; - if ((status = smbfs_clntinit()) != 0) { + /* + * NFS calls these two in _clntinit + * Easier to follow this way. + */ + if ((error = smbfs_subrinit()) != 0) { + cmn_err(CE_WARN, "_init: smbfs_subrinit failed"); + return (error); + } + + if ((error = smbfs_vfsinit()) != 0) { + cmn_err(CE_WARN, "_init: smbfs_vfsinit failed"); + smbfs_subrfini(); + return (error); + } + + if ((error = smbfs_clntinit()) != 0) { cmn_err(CE_WARN, "_init: smbfs_clntinit failed"); - return (status); + smbfs_vfsfini(); + smbfs_subrfini(); + return (error); } - status = mod_install((struct modlinkage *)&modlinkage); - return (status); + error = mod_install((struct modlinkage *)&modlinkage); + return (error); } /* @@ -222,6 +240,10 @@ _fini(void) */ smbfs_clntfini(); + /* NFS calls these two in _clntfini */ + smbfs_vfsfini(); + smbfs_subrfini(); + /* * Free the ops vectors */ @@ -298,10 +320,21 @@ smbfsfini() void smbfs_free_smi(smbmntinfo_t *smi) { - if (smi) { - smbfs_zonelist_remove(smi); - kmem_free(smi, sizeof (smbmntinfo_t)); - } + if (smi == NULL) + return; + + if (smi->smi_zone != NULL) + zone_rele(smi->smi_zone); + + if (smi->smi_share != NULL) + smb_share_rele(smi->smi_share); + + avl_destroy(&smi->smi_hash_avl); + rw_destroy(&smi->smi_hash_lk); + cv_destroy(&smi->smi_statvfs_cv); + mutex_destroy(&smi->smi_lock); + + kmem_free(smi, sizeof (smbmntinfo_t)); } /* @@ -313,7 +346,7 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) { char *data = uap->dataptr; int error; - vnode_t *rtvp = NULL; /* root of this fs */ + smbnode_t *rtnp = NULL; /* root of this fs */ smbmntinfo_t *smi = NULL; dev_t smbfs_dev; int version; @@ -322,6 +355,7 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) zone_t *mntzone = NULL; smb_share_t *ssp = NULL; smb_cred_t scred; + int flags, sec; STRUCT_DECL(smbfs_args, args); /* smbfs mount arguments */ @@ -336,8 +370,6 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) * * uap->datalen might be different from sizeof (args) * in a compatible situation. - * - * XXX - todo: handle mount options string */ STRUCT_INIT(args, get_udatamodel()); bzero(STRUCT_BUF(args), SIZEOF_STRUCT(smbfs_args, DATAMODEL_NATIVE)); @@ -356,6 +388,9 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) return (EINVAL); } + /* + * Deal with re-mount requests. + */ if (uap->flags & MS_REMOUNT) { cmn_err(CE_WARN, "MS_REMOUNT not implemented"); return (ENOTSUP); @@ -386,11 +421,9 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) return (error); } - smb_credinit(&scred, cr); - /* * Use "goto errout" from here on. - * See: ssp, smi, rtvp, mntzone + * See: ssp, smi, rtnp, mntzone */ /* @@ -437,41 +470,93 @@ smbfs_mount(vfs_t *vfsp, vnode_t *mvp, struct mounta *uap, cred_t *cr) } } - /* - * Get root vnode. - */ -proceed: + /* Prevent unload. */ + atomic_inc_32(&smbfs_mountcount); /* * Create a mount record and link it to the vfs struct. + * No more possiblities for errors from here on. + * Tear-down of this stuff is in smbfs_free_smi() + * * Compare with NFS: nfsrootvp() */ - smi = kmem_zalloc(sizeof (smbmntinfo_t), KM_SLEEP); + smi = kmem_zalloc(sizeof (*smi), KM_SLEEP); + + mutex_init(&smi->smi_lock, NULL, MUTEX_DEFAULT, NULL); + cv_init(&smi->smi_statvfs_cv, NULL, CV_DEFAULT, NULL); - smi->smi_share = ssp; - smi->smi_zone = mntzone; + rw_init(&smi->smi_hash_lk, NULL, RW_DEFAULT, NULL); + smbfs_init_hash_avl(&smi->smi_hash_avl); + + smi->smi_share = ssp; + ssp = NULL; + smi->smi_zone = mntzone; + mntzone = NULL; + + /* + * Initialize option defaults + */ smi->smi_flags = SMI_LLOCK; + smi->smi_acregmin = SEC2HR(SMBFS_ACREGMIN); + smi->smi_acregmax = SEC2HR(SMBFS_ACREGMAX); + smi->smi_acdirmin = SEC2HR(SMBFS_ACDIRMIN); + smi->smi_acdirmax = SEC2HR(SMBFS_ACDIRMAX); /* - * Handle mount options. See also XATTR below. - * XXX: forcedirectio, largefiles (later) + * All "generic" mount options have already been + * handled in vfs.c:domount() - see mntopts stuff. + * Query generic options using vfs_optionisset(). */ if (vfs_optionisset(vfsp, MNTOPT_INTR, NULL)) smi->smi_flags |= SMI_INT; /* - * XXX If not root, get uid/gid from the covered vnode. + * Get the mount options that come in as smbfs_args, + * starting with args.flags (SMBFS_MF_xxx) + */ + flags = STRUCT_FGET(args, flags); + smi->smi_uid = STRUCT_FGET(args, uid); + smi->smi_gid = STRUCT_FGET(args, gid); + smi->smi_fmode = STRUCT_FGET(args, file_mode) & 0777; + smi->smi_dmode = STRUCT_FGET(args, dir_mode) & 0777; + + /* + * Hande the SMBFS_MF_xxx flags. */ - smi->smi_args.dir_mode = STRUCT_FGET(args, dir_mode); - smi->smi_args.file_mode = STRUCT_FGET(args, file_mode); - smi->smi_args.uid = STRUCT_FGET(args, uid); - smi->smi_args.gid = STRUCT_FGET(args, gid); + if (flags & SMBFS_MF_NOAC) + smi->smi_flags |= SMI_NOAC; + if (flags & SMBFS_MF_ACREGMIN) { + sec = STRUCT_FGET(args, acregmin); + if (sec < 0 || sec > SMBFS_ACMINMAX) + sec = SMBFS_ACMINMAX; + smi->smi_acregmin = SEC2HR(sec); + } + if (flags & SMBFS_MF_ACREGMAX) { + sec = STRUCT_FGET(args, acregmax); + if (sec < 0 || sec > SMBFS_ACMAXMAX) + sec = SMBFS_ACMAXMAX; + smi->smi_acregmax = SEC2HR(sec); + } + if (flags & SMBFS_MF_ACDIRMIN) { + sec = STRUCT_FGET(args, acdirmin); + if (sec < 0 || sec > SMBFS_ACMINMAX) + sec = SMBFS_ACMINMAX; + smi->smi_acdirmin = SEC2HR(sec); + } + if (flags & SMBFS_MF_ACDIRMAX) { + sec = STRUCT_FGET(args, acdirmax); + if (sec < 0 || sec > SMBFS_ACMAXMAX) + sec = SMBFS_ACMAXMAX; + smi->smi_acdirmax = SEC2HR(sec); + } /* * Get attributes of the remote file system, * i.e. ACL support, named streams, etc. */ - error = smbfs_smb_qfsattr(ssp, &smi->smi_fsa, &scred); + smb_credinit(&scred, cr); + error = smbfs_smb_qfsattr(smi->smi_share, &smi->smi_fsa, &scred); + smb_credrele(&scred); if (error) { SMBVDEBUG("smbfs_smb_qfsattr error %d\n", error); } @@ -503,57 +588,40 @@ proceed: vfsp->vfs_bcount = 0; smi->smi_vfsp = vfsp; - smbfs_zonelist_add(smi); + smbfs_zonelist_add(smi); /* undo in smbfs_freevfs */ /* * Create the root vnode, which we need in unmount - * for the call to smb_check_table(), etc. + * for the call to smbfs_check_table(), etc. + * Release this hold in smbfs_unmount. */ - rtvp = smbfs_make_node(vfsp, "\\", 1, NULL, 0, 0, NULL); - if (!rtvp) { - cmn_err(CE_WARN, "smbfs_mount: make_node failed\n"); - return (ENOENT); - } - rtvp->v_type = VDIR; - rtvp->v_flag |= VROOT; + rtnp = smbfs_node_findcreate(smi, "\\", 1, NULL, 0, 0, + &smbfs_fattr0); + ASSERT(rtnp != NULL); + rtnp->r_vnode->v_type = VDIR; + rtnp->r_vnode->v_flag |= VROOT; + smi->smi_root = rtnp; /* - * Could get attributes here, but that can wait - * until someone does a getattr call. - * * NFS does other stuff here too: * async worker threads * init kstats * * End of code from NFS nfsrootvp() */ - - smb_credrele(&scred); - - smi->smi_root = VTOSMB(rtvp); - - atomic_inc_32(&smbfs_mountcount); - return (0); errout: - - ASSERT(rtvp == NULL); - vfsp->vfs_data = NULL; - if (smi) + if (smi != NULL) smbfs_free_smi(smi); if (mntzone != NULL) zone_rele(mntzone); - if (ssp) + if (ssp != NULL) smb_share_rele(ssp); - smb_credrele(&scred); - - /* args, if we allocated */ - return (error); } @@ -572,16 +640,14 @@ smbfs_unmount(vfs_t *vfsp, int flag, cred_t *cr) return (EPERM); if ((flag & MS_FORCE) == 0) { -#ifdef APPLE smbfs_rflush(vfsp, cr); -#endif /* * If there are any active vnodes on this file system, * (other than the root vnode) then the file system is * busy and can't be umounted. */ - if (smb_check_table(vfsp, smi->smi_root)) + if (smbfs_check_table(vfsp, smi->smi_root)) return (EBUSY); /* @@ -625,7 +691,7 @@ smbfs_unmount(vfs_t *vfsp, int flag, cred_t *cr) /* * Remove all nodes from the node hash tables. - * This (indirectly) calls: smb_addfree, smbinactive, + * This (indirectly) calls: smbfs_addfree, smbinactive, * which will try to flush dirty pages, etc. so * don't destroy the underlying share just yet. * @@ -652,10 +718,8 @@ smbfs_unmount(vfs_t *vfsp, int flag, cred_t *cr) } /* - * Note: the smb_share_rele() - * happens in smbfs_freevfs() + * The rest happens in smbfs_freevfs() */ - return (0); } @@ -801,12 +865,11 @@ smbfs_sync(vfs_t *vfsp, short flag, cred_t *cr) * Cross-zone calls are OK here, since this translates to a * VOP_PUTPAGE(B_ASYNC), which gets picked up by the right zone. */ -#ifdef APPLE if (!(flag & SYNC_ATTR) && mutex_tryenter(&smbfs_syncbusy) != 0) { smbfs_rflush(vfsp, cr); mutex_exit(&smbfs_syncbusy); } -#endif /* APPLE */ + return (0); } @@ -833,7 +896,6 @@ void smbfs_freevfs(vfs_t *vfsp) { smbmntinfo_t *smi; - smb_share_t *ssp; /* free up the resources */ smi = VFTOSMI(vfsp); @@ -845,15 +907,7 @@ smbfs_freevfs(vfs_t *vfsp) */ ASSERT(smi->smi_io_kstats == NULL); - /* - * Drop our reference to the share. - * This usually leads to VC close. - */ - ssp = smi->smi_share; - smi->smi_share = NULL; - smb_share_rele(ssp); - - zone_rele(smi->smi_zone); + smbfs_zonelist_remove(smi); smbfs_free_smi(smi); diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c index a2ba2f9a5e..1ce01a3112 100644 --- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vnops.c @@ -49,7 +49,6 @@ #include <sys/sysmacros.h> #include <sys/kmem.h> #include <sys/cmn_err.h> -#include <sys/dnlc.h> #include <sys/vfs_opreg.h> #include <sys/policy.h> @@ -98,18 +97,17 @@ static const char illegal_chars[] = { /* * Turning this on causes nodes to be created in the cache - * during directory listings. The "fast" claim is debatable, - * and the effects on the cache can be undesirable. + * during directory listings, normally avoiding a second + * OtW attribute fetch just after a readdir. */ +int smbfs_fastlookup = 1; /* local static function defines */ -#ifdef USE_DNLC -static int smbfslookup_dnlc(vnode_t *dvp, char *nm, vnode_t **vpp, - cred_t *cr); -#endif +static int smbfslookup_cache(vnode_t *, char *, int, vnode_t **, + cred_t *); static int smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr, - int dnlc, caller_context_t *); + int cache_ok, caller_context_t *); static int smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr, caller_context_t *); static int smbfssetattr(vnode_t *, struct vattr *, int, cred_t *); @@ -240,9 +238,9 @@ const fs_operation_def_t smbfs_vnodeops_template[] = { static int smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct) { - struct vattr va; smbnode_t *np; vnode_t *vp; + smbfattr_t fa; u_int32_t rights, rightsrcvd; u_int16_t fid, oldfid; int oldgenid; @@ -250,7 +248,6 @@ smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct) smbmntinfo_t *smi; smb_share_t *ssp; cred_t *oldcr; - int attrcacheupdated = 0; int tmperror; int error = 0; @@ -328,14 +325,10 @@ smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct) int upgrade = 0; if ((flag & FWRITE) && - !(np->n_rights & (SA_RIGHT_FILE_WRITE_DATA | - GENERIC_RIGHT_ALL_ACCESS | - GENERIC_RIGHT_WRITE_ACCESS))) + !(np->n_rights & SA_RIGHT_FILE_WRITE_DATA)) upgrade = 1; if ((flag & FREAD) && - !(np->n_rights & (SA_RIGHT_FILE_READ_DATA | - GENERIC_RIGHT_ALL_ACCESS | - GENERIC_RIGHT_READ_ACCESS))) + !(np->n_rights & SA_RIGHT_FILE_READ_DATA)) upgrade = 1; if (!upgrade) { /* @@ -350,20 +343,24 @@ smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct) /* * we always ask for READ_CONTROL so we can always get the * owner/group IDs to satisfy a stat. Ditto attributes. - * XXX: verify that works with "drop boxes" */ rights |= (STD_RIGHT_READ_CONTROL_ACCESS | SA_RIGHT_FILE_READ_ATTRIBUTES); if ((flag & FREAD)) rights |= SA_RIGHT_FILE_READ_DATA; if ((flag & FWRITE)) - rights |= SA_RIGHT_FILE_APPEND_DATA | SA_RIGHT_FILE_WRITE_DATA; - - /* XXX: open gets the current size, but we don't use it. */ - error = smbfs_smb_open(np, rights, &scred, &attrcacheupdated, &fid, - NULL, 0, 0, NULL, &rightsrcvd); + rights |= SA_RIGHT_FILE_WRITE_DATA | + SA_RIGHT_FILE_APPEND_DATA | + SA_RIGHT_FILE_WRITE_ATTRIBUTES; + + bzero(&fa, sizeof (fa)); + error = smbfs_smb_open(np, + NULL, 0, 0, /* name nmlen xattr */ + rights, &scred, + &fid, &rightsrcvd, &fa); if (error) goto out; + smbfs_attrcache_fa(vp, &fa); /* * We have a new FID and access rights. @@ -382,7 +379,7 @@ smbfs_open(vnode_t **vpp, int flag, cred_t *cr, caller_context_t *ct) * Close old wire-open. */ tmperror = smbfs_smb_close(ssp, - oldfid, &np->n_mtime, &scred); + oldfid, NULL, &scred); if (tmperror) SMBVDEBUG("error %d closing %s\n", tmperror, np->n_rpath); @@ -408,25 +405,6 @@ have_fid: if (np->n_ovtype == VNON) np->n_ovtype = vp->v_type; - /* Get attributes (maybe). */ - - /* Darwin (derived) code. */ - - va.va_mask = AT_MTIME; - if (np->n_flag & NMODIFIED) - smbfs_attr_cacheremove(np); - - /* - * Try to get attributes, but don't bail on error. - * We already hold r_lkserlock/reader so note: - * this call will recursively take r_lkserlock. - */ - tmperror = smbfsgetattr(vp, &va, cr); - if (tmperror) - SMBERROR("getattr failed, error=%d", tmperror); - else - np->n_mtime.tv_sec = va.va_mtime.tv_sec; - out: smb_credrele(&scred); smbfs_rw_exit(&np->r_lkserlock); @@ -441,6 +419,7 @@ smbfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr, smbnode_t *np; smbmntinfo_t *smi; smb_share_t *ssp; + cred_t *oldcr; int error = 0; struct smb_cred scred; @@ -492,12 +471,13 @@ smbfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr, cleanshares(vp, pid); } - if (count > 1) - return (0); /* - * OK, do "last close" stuff. + * This (passed in) count is the ref. count from the + * user's file_t before the closef call (fio.c). + * We only care when the reference goes away. */ - + if (count > 1) + return (0); /* * Do the CIFS close. @@ -545,15 +525,24 @@ smbfs_close(vnode_t *vp, int flag, int count, offset_t offset, cred_t *cr, } } if (error) { - SMBERROR("error %d closing %s\n", + SMBVDEBUG("error %d closing %s\n", error, np->n_rpath); } /* Allow next open to use any v_type. */ np->n_ovtype = VNON; + /* + * Other "last close" stuff. + */ + mutex_enter(&np->r_statelock); if (np->n_flag & NATTRCHANGED) - smbfs_attr_cacheremove(np); + smbfs_attrcache_rm_locked(np); + oldcr = np->r_cred; + np->r_cred = NULL; + mutex_exit(&np->r_statelock); + if (oldcr != NULL) + crfree(oldcr); out: smb_credrele(&scred); @@ -685,7 +674,7 @@ smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr, */ if (ioflag & (FAPPEND | FSYNC)) { if (np->n_flag & NMODIFIED) { - smbfs_attr_cacheremove(np); + smbfs_attrcache_remove(np); /* XXX: smbfs_vinvalbuf? */ } } @@ -730,7 +719,7 @@ smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr, /* Timeout: longer for append. */ timo = smb_timo_write; - if (endoff > np->n_size) + if (endoff > np->r_size) timo = smb_timo_append; /* Shared lock for n_fid use in smb_rwuio */ @@ -748,8 +737,8 @@ smbfs_write(vnode_t *vp, struct uio *uiop, int ioflag, cred_t *cr, if (error == 0) { mutex_enter(&np->r_statelock); np->n_flag |= (NFLUSHWIRE | NATTRCHANGED); - if (uiop->uio_loffset > (offset_t)np->n_size) - np->n_size = (len_t)uiop->uio_loffset; + if (uiop->uio_loffset > (offset_t)np->r_size) + np->r_size = (len_t)uiop->uio_loffset; mutex_exit(&np->r_statelock); if (ioflag & (FSYNC|FDSYNC)) { /* Don't error the I/O if this fails. */ @@ -866,62 +855,18 @@ smbfs_getattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr, if (vap->va_mask | AT_SIZE) vap->va_size = np->r_size; if (vap->va_mask | AT_FSID) - vap->va_fsid = np->r_attr.va_fsid; + vap->va_fsid = vp->v_vfsp->vfs_dev; if (vap->va_mask | AT_RDEV) - vap->va_rdev = np->r_attr.va_rdev; + vap->va_rdev = vp->v_rdev; mutex_exit(&np->r_statelock); return (0); } } - return (smbfsgetattr(vp, vap, cr)); } -/* - * Mostly from Darwin smbfs_getattr() - */ -int -smbfsgetattr(vnode_t *vp, struct vattr *vap, cred_t *cr) -{ - int error; - smbnode_t *np; - struct smb_cred scred; - struct smbfattr fattr; - - ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone); - - np = VTOSMB(vp); - - /* - * If we've got cached attributes, we're done, otherwise go - * to the server to get attributes, which will update the cache - * in the process. - * - * This section from Darwin smbfs_getattr, - * but then modified a lot. - */ - error = smbfs_attr_cachelookup(vp, vap); - if (error != ENOENT) - return (error); - - /* Shared lock for (possible) n_fid use. */ - if (smbfs_rw_enter_sig(&np->r_lkserlock, RW_READER, SMBINTR(vp))) - return (EINTR); - smb_credinit(&scred, cr); - - bzero(&fattr, sizeof (fattr)); - error = smbfs_smb_getfattr(np, &fattr, &scred); - - smb_credrele(&scred); - smbfs_rw_exit(&np->r_lkserlock); - - if (!error) { - smbfs_attr_cacheenter(vp, &fattr); - error = smbfs_attr_cachelookup(vp, vap); - } - return (error); -} +/* smbfsgetattr() in smbfs_client.c */ /* * XXX @@ -933,23 +878,29 @@ static int smbfs_setattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr, caller_context_t *ct) { + vfs_t *vfsp; + smbmntinfo_t *smi; int error; uint_t mask; struct vattr oldva; - smbmntinfo_t *smi; - smi = VTOSMI(vp); + vfsp = vp->v_vfsp; + smi = VFTOSMI(vfsp); if (curproc->p_zone != smi->smi_zone) return (EIO); - if (smi->smi_flags & SMI_DEAD || vp->v_vfsp->vfs_flag & VFS_UNMOUNTED) + if (smi->smi_flags & SMI_DEAD || vfsp->vfs_flag & VFS_UNMOUNTED) return (EIO); mask = vap->va_mask; if (mask & AT_NOSET) return (EINVAL); + if (vfsp->vfs_flag & VFS_RDONLY) + return (EROFS); + + bzero(&oldva, sizeof (oldva)); oldva.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID; error = smbfsgetattr(vp, &oldva, cr); if (error) @@ -973,7 +924,6 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr) { int error = 0; smbnode_t *np = VTOSMB(vp); - smbmntinfo_t *smi = VTOSMI(vp); uint_t mask = vap->va_mask; struct timespec *mtime, *atime; struct smb_cred scred; @@ -982,7 +932,7 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr) int have_fid = 0; uint32_t rights = 0; - ASSERT(curproc->p_zone == smi->smi_zone); + ASSERT(curproc->p_zone == VTOSMI(vp)->smi_zone); /* * There are no settable attributes on the XATTR dir, @@ -1016,20 +966,21 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr) */ if (mask & (AT_ATIME | AT_MTIME)) { rights |= - SA_RIGHT_FILE_WRITE_ATTRIBUTES | - GENERIC_RIGHT_ALL_ACCESS | - GENERIC_RIGHT_WRITE_ACCESS; + SA_RIGHT_FILE_WRITE_ATTRIBUTES; } if (mask & AT_SIZE) { rights |= SA_RIGHT_FILE_WRITE_DATA | SA_RIGHT_FILE_APPEND_DATA; - /* - * Only SIZE requires a handle. - * XXX May be more reliable to just - * always get the file handle here. - * The tmpopen checks n_vcgenid. - */ + } + + /* + * Only SIZE really requires a handle, but it's + * simpler and more reliable to set via a handle. + * Some servers like NT4 won't set times by path. + * Also, we're usually setting everything anyway. + */ + if (mask & (AT_SIZE | AT_ATIME | AT_MTIME)) { error = smbfs_smb_tmpopen(np, rights, &scred, &fid); if (error) { SMBVDEBUG("error %d opening %s\n", @@ -1039,7 +990,6 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr) have_fid = 1; } - /* * If the server supports the UNIX extensions, right here is where * we'd support changes to uid, gid, mode, and possibly va_flags. @@ -1089,21 +1039,16 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr) if (mtime || atime) { /* - * If file is opened with write-attributes capability, - * we use handle-based calls. If not, we use path-based ones. + * Always use the handle-based set attr call now. + * Not trying to set DOS attributes here so pass zero. */ - if (have_fid) { - error = smbfs_smb_setfattr(np, fid, - np->n_dosattr, mtime, atime, &scred); - } else { - error = smbfs_smb_setpattr(np, - np->n_dosattr, mtime, atime, &scred); - } + ASSERT(have_fid); + error = smbfs_smb_setfattr(np, fid, + 0, mtime, atime, &scred); if (error) { SMBVDEBUG("set times error %d file %s\n", error, np->n_rpath); } else { - /* XXX: set np->n_mtime, etc? */ modified = 1; } } @@ -1111,20 +1056,16 @@ smbfssetattr(vnode_t *vp, struct vattr *vap, int flags, cred_t *cr) out: if (modified) { /* - * Invalidate attribute cache in case if server doesn't set - * required attributes. - */ - smbfs_attr_cacheremove(np); - /* - * XXX Darwin called _getattr here to - * update the mtime. Should we? + * Invalidate attribute cache in case the server + * doesn't set exactly the attributes we asked. */ + smbfs_attrcache_remove(np); } if (have_fid) { cerror = smbfs_smb_tmpclose(np, fid, &scred); if (cerror) - SMBERROR("error %d closing %s\n", + SMBVDEBUG("error %d closing %s\n", cerror, np->n_rpath); } @@ -1188,10 +1129,9 @@ smbfs_access_rwx(vfs_t *vfsp, int vtype, int mode, cred_t *cr) va.va_mask = AT_TYPE | AT_MODE | AT_UID | AT_GID; va.va_type = vtype; va.va_mode = (vtype == VDIR) ? - smi->smi_args.dir_mode : - smi->smi_args.file_mode; - va.va_uid = smi->smi_args.uid; - va.va_gid = smi->smi_args.gid; + smi->smi_dmode : smi->smi_fmode; + va.va_uid = smi->smi_uid; + va.va_gid = smi->smi_gid; /* * Disallow write attempts on read-only file systems, @@ -1367,7 +1307,7 @@ smbfs_inactive(vnode_t *vp, cred_t *cr, caller_context_t *ct) np->n_dirrefs, fid, np->n_rpath); } - smb_addfree(np); + smbfs_addfree(np); } /* @@ -1408,37 +1348,29 @@ smbfs_lookup(vnode_t *dvp, char *nm, vnode_t **vpp, struct pathname *pnp, if ((vfs->vfs_flag & VFS_XATTR) == 0) return (EINVAL); - /* - * We don't allow recursive attributes. - */ - if (dnp->n_flag & N_XATTR) - return (EINVAL); - error = smbfs_get_xattrdir(dvp, vpp, cr, flags); return (error); } - if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_READER, SMBINTR(dvp))) { - error = EINTR; - goto out; - } + if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_READER, SMBINTR(dvp))) + return (EINTR); error = smbfslookup(dvp, nm, vpp, cr, 1, ct); smbfs_rw_exit(&dnp->r_rwlock); -out: return (error); } /* ARGSUSED */ static int -smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr, int dnlc, - caller_context_t *ct) +smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr, + int cache_ok, caller_context_t *ct) { int error; int supplen; /* supported length */ vnode_t *vp; + smbnode_t *np; smbnode_t *dnp; smbmntinfo_t *smi; /* struct smb_vc *vcp; */ @@ -1471,9 +1403,8 @@ smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr, int dnlc, ASSERT(dnp->r_rwlock.count != 0); /* - * If lookup is for "", just return dvp. Don't need - * to send it over the wire, look it up in the dnlc, - * or perform any access checks. + * If lookup is for "", just return dvp. + * No need to perform any access checks. */ if (nmlen == 0) { VN_HOLD(dvp); @@ -1495,9 +1426,8 @@ smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr, int dnlc, return (error); /* - * If lookup is for ".", just return dvp. Don't need - * to send it over the wire or look it up in the dnlc, - * just need to check access (done above). + * If lookup is for ".", just return dvp. + * Access check was done above. */ if (nmlen == 1 && name[0] == '.') { VN_HOLD(dvp); @@ -1523,21 +1453,8 @@ smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr, int dnlc, if (strpbrk(nm, ill)) return (EINVAL); -#ifdef USE_DNLC - if (dnlc) { - /* - * Lookup this name in the DNLC. If there was a valid entry, - * then return the results of the lookup. - */ - error = smbfslookup_dnlc(dvp, nm, vpp, cr); - if (error || *vpp != NULL) - return (error); - } -#endif /* USE_DNLC */ - /* - * Handle lookup of ".." which is quite tricky, - * because the protocol gives us little help. + * Special handling for lookup of ".." * * We keep full pathnames (as seen on the server) * so we can just trim off the last component to @@ -1570,7 +1487,6 @@ smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr, int dnlc, */ if (dvp->v_flag & V_XATTRDIR) { error = smbfs_xa_parent(dvp, vpp); - /* Intentionally no dnlc_update */ return (error); } @@ -1583,21 +1499,19 @@ smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr, int dnlc, if (dnp->n_rpath[rplen] == '\\') break; } - if (rplen == 0) { + if (rplen <= 0) { /* Found our way to the root. */ vp = SMBTOV(smi->smi_root); VN_HOLD(vp); *vpp = vp; return (0); } - vp = smbfs_make_node(dvp->v_vfsp, - dnp->n_rpath, rplen, - NULL, 0, 0, NULL); - ASSERT(vp); + np = smbfs_node_findcreate(smi, + dnp->n_rpath, rplen, NULL, 0, 0, + &smbfs_fattr0); /* force create */ + ASSERT(np != NULL); + vp = SMBTOV(np); vp->v_type = VDIR; -#ifdef USE_DNLC - dnlc_update(dvp, nm, vp); -#endif /* Success! */ *vpp = vp; @@ -1605,34 +1519,49 @@ smbfslookup(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr, int dnlc, } /* - * Normal lookup of a child node. - * Note we handled "." and ".." above. - * - * First, go over-the-wire to get the - * node type (and attributes). + * Normal lookup of a name under this directory. + * Note we handled "", ".", ".." above. + */ + if (cache_ok) { + /* + * The caller indicated that it's OK to use a + * cached result for this lookup, so try to + * reclaim a node from the smbfs node cache. + */ + error = smbfslookup_cache(dvp, nm, nmlen, &vp, cr); + if (error) + return (error); + if (vp != NULL) { + /* hold taken in lookup_cache */ + *vpp = vp; + return (0); + } + } + + /* + * OK, go over-the-wire to get the attributes, + * then create the node. */ smb_credinit(&scred, cr); /* Note: this can allocate a new "name" */ error = smbfs_smb_lookup(dnp, &name, &nmlen, &fa, &scred); smb_credrele(&scred); -#ifdef USE_DNLC - if (error == ENOENT) - dnlc_enter(dvp, nm, DNLC_NO_VNODE); -#endif + if (error == ENOTDIR) { + /* + * Lookup failed because this directory was + * removed or renamed by another client. + * Remove any cached attributes under it. + */ + smbfs_attrcache_remove(dnp); + smbfs_attrcache_prune(dnp); + } if (error) goto out; - /* - * Find or create the node. - */ error = smbfs_nget(dvp, name, nmlen, &fa, &vp); if (error) goto out; -#ifdef USE_DNLC - dnlc_update(dvp, nm, vp); -#endif - /* Success! */ *vpp = vp; @@ -1644,83 +1573,98 @@ out: return (error); } -#ifdef USE_DNLC +/* + * smbfslookup_cache + * + * Try to reclaim a node from the smbfs node cache. + * Some statistics for DEBUG. + * + * This mechanism lets us avoid many of the five (or more) + * OtW lookup calls per file seen with "ls -l" if we search + * the smbfs node cache for recently inactive(ated) nodes. + */ #ifdef DEBUG -static int smbfs_lookup_dnlc_hits = 0; -static int smbfs_lookup_dnlc_misses = 0; -static int smbfs_lookup_dnlc_neg_hits = 0; -static int smbfs_lookup_dnlc_disappears = 0; -static int smbfs_lookup_dnlc_lookups = 0; -#endif +int smbfs_lookup_cache_calls = 0; +int smbfs_lookup_cache_error = 0; +int smbfs_lookup_cache_miss = 0; +int smbfs_lookup_cache_stale = 0; +int smbfs_lookup_cache_hits = 0; +#endif /* DEBUG */ /* ARGSUSED */ static int -smbfslookup_dnlc(vnode_t *dvp, char *nm, vnode_t **vpp, cred_t *cr) +smbfslookup_cache(vnode_t *dvp, char *nm, int nmlen, + vnode_t **vpp, cred_t *cr) { - int error; - vnode_t *vp; struct vattr va; smbnode_t *dnp; + smbnode_t *np; + vnode_t *vp; + int error; + char sep; dnp = VTOSMB(dvp); + *vpp = NULL; - ASSERT(*nm != '\0'); - ASSERT(curproc->p_zone == VTOSMI(dvp)->smi_zone); +#ifdef DEBUG + smbfs_lookup_cache_calls++; +#endif /* - * Lookup this name in the DNLC. If successful, then validate - * the caches and then recheck the DNLC. The DNLC is rechecked - * just in case this entry got invalidated during the call - * to smbfsgetattr(). - * An assumption is being made that it is safe to say that a - * file exists which may not on the server. Any operations to - * the server will fail with ESTALE. + * First make sure we can get attributes for the + * directory. Cached attributes are OK here. + * If we removed or renamed the directory, this + * will return ENOENT. If someone else removed + * this directory or file, we'll find out when we + * try to open or get attributes. */ - -#ifdef DEBUG - smbfs_lookup_dnlc_lookups++; -#endif - vp = dnlc_lookup(dvp, nm); - if (vp != NULL) { - if (vp == DNLC_NO_VNODE && !vn_is_readonly(dvp)) - smbfs_attr_cacheremove(dnp); - VN_RELE(vp); - error = smbfsgetattr(dvp, &va, cr); - if (error) - return (error); - vp = dnlc_lookup(dvp, nm); - if (vp != NULL) { - /* - * NFS checks VEXEC access here, - * but we've already done that - * in the caller. - */ - if (vp == DNLC_NO_VNODE) { - VN_RELE(vp); + va.va_mask = AT_TYPE | AT_MODE; + error = smbfsgetattr(dvp, &va, cr); + if (error) { #ifdef DEBUG - smbfs_lookup_dnlc_neg_hits++; + smbfs_lookup_cache_error++; #endif - return (ENOENT); - } - *vpp = vp; + return (error); + } + + /* + * Passing NULL smbfattr here so we will + * just look, not create. + */ + sep = SMBFS_DNP_SEP(dnp); + np = smbfs_node_findcreate(dnp->n_mount, + dnp->n_rpath, dnp->n_rplen, + nm, nmlen, sep, NULL); + if (np == NULL) { #ifdef DEBUG - smbfs_lookup_dnlc_hits++; + smbfs_lookup_cache_miss++; #endif - return (0); - } + return (0); + } + + /* + * Found it. Attributes still valid? + */ + vp = SMBTOV(np); + if (np->r_attrtime <= gethrtime()) { + /* stale */ #ifdef DEBUG - smbfs_lookup_dnlc_disappears++; + smbfs_lookup_cache_stale++; #endif + VN_RELE(vp); + return (0); } + + /* + * Success! + * Caller gets hold from smbfs_node_findcreate + */ #ifdef DEBUG - else - smbfs_lookup_dnlc_misses++; + smbfs_lookup_cache_hits++; #endif - *vpp = NULL; - + *vpp = vp; return (0); } -#endif /* USE_DNLC */ /* * XXX @@ -1805,7 +1749,7 @@ smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive, /* * NFS needs to go over the wire, just to be sure whether the - * file exists or not. Using the DNLC can be dangerous in + * file exists or not. Using a cached result is dangerous in * this case when making a decision regarding existence. * * The SMB protocol does NOT really need to go OTW here @@ -1870,9 +1814,6 @@ smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive, if (error) goto out; - /* remove possible negative entry from the dnlc */ - dnlc_remove(dvp, nm); - /* * Now the code derived from Darwin, * but with greater use of NT_CREATE @@ -1894,7 +1835,9 @@ smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive, disp = NTCREATEX_DISP_OPEN_IF; } xattr = (dnp->n_flag & N_XATTR) ? 1 : 0; - error = smbfs_smb_create(dnp, name, nmlen, &scred, &fid, disp, xattr); + error = smbfs_smb_create(dnp, + name, nmlen, xattr, + disp, &scred, &fid); if (error) goto out; @@ -1935,7 +1878,7 @@ smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive, cerror = smbfs_smb_close(smi->smi_share, fid, NULL, &scred); if (cerror) - SMBERROR("error %d closing %s\\%s\n", + SMBVDEBUG("error %d closing %s\\%s\n", cerror, dnp->n_rpath, name); /* @@ -1958,10 +1901,6 @@ smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive, if (error) goto out; -#ifdef USE_DNLC - dnlc_update(dvp, nm, vp); -#endif - /* XXX invalidate pages if we truncated? */ /* Success! */ @@ -1970,9 +1909,9 @@ smbfs_create(vnode_t *dvp, char *nm, struct vattr *va, enum vcexcl exclusive, out: smb_credrele(&scred); + smbfs_rw_exit(&dnp->r_rwlock); if (name != nm) smbfs_name_free(name, nmlen); - smbfs_rw_exit(&dnp->r_rwlock); return (error); } @@ -2005,6 +1944,7 @@ smbfs_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct, dnp = VTOSMB(dvp); if (smbfs_rw_enter_sig(&dnp->r_rwlock, RW_WRITER, SMBINTR(dvp))) return (EINTR); + smb_credinit(&scred, cr); /* * Verify access to the dirctory. @@ -2031,48 +1971,46 @@ smbfs_remove(vnode_t *dvp, char *nm, cred_t *cr, caller_context_t *ct, } /* - * First just remove the entry from the name cache, as it - * is most likely the only entry for this vp. - */ - dnlc_remove(dvp, nm); - - /* - * If the file has a v_count > 1 then there may be more than one - * entry in the name cache due multiple links or an open file, - * but we don't have the real reference count so flush all - * possible entries. - */ - if (vp->v_count > 1) - dnlc_purge_vp(vp); - - /* * Now we have the real reference count on the vnode + * Do we have the file open? */ np = VTOSMB(vp); mutex_enter(&np->r_statelock); - if (vp->v_count > 1) { + if ((vp->v_count > 1) && (np->n_fidrefs > 0)) { /* * NFS does a rename on remove here. * Probably not applicable for SMB. * Like Darwin, just return EBUSY. * - * XXX: Todo - Ask the server to set the + * XXX: Todo - Use Trans2rename, and + * if that fails, ask the server to * set the delete-on-close flag. */ mutex_exit(&np->r_statelock); error = EBUSY; } else { + smbfs_attrcache_rm_locked(np); mutex_exit(&np->r_statelock); - smb_credinit(&scred, cr); error = smbfs_smb_delete(np, &scred, NULL, 0, 0); - smb_credrele(&scred); + /* + * If the file should no longer exist, discard + * any cached attributes under this node. + */ + switch (error) { + case 0: + case ENOENT: + case ENOTDIR: + smbfs_attrcache_prune(np); + break; + } } VN_RELE(vp); out: + smb_credrele(&scred); smbfs_rw_exit(&dnp->r_rwlock); return (error); @@ -2164,6 +2102,7 @@ smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr, return (EINTR); } } + smb_credinit(&scred, cr); /* * No returns after this point (goto out) */ @@ -2238,35 +2177,6 @@ smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr, } /* - * Purge the name cache of all references to this vnode - * so that we can check the reference count to infer - * whether it is active or not. - */ - /* - * First just remove the entry from the name cache, as it - * is most likely the only entry for this vp. - */ - dnlc_remove(ndvp, nnm); - /* - * If the file has a v_count > 1 then there may be more - * than one entry in the name cache due multiple links - * or an open file, but we don't have the real reference - * count so flush all possible entries. - */ - if (nvp->v_count > 1) - dnlc_purge_vp(nvp); - /* - * when renaming directories to be a subdirectory of a - * different parent, the dnlc entry for ".." will no - * longer be valid, so it must be removed - */ - if (ndvp != odvp) { - if (ovp->v_type == VDIR) { - dnlc_remove(ovp, ".."); - } - } - - /* * CIFS gives a SHARING_VIOLATION error when * trying to rename onto an exising object, * so try to remove the target first. @@ -2285,7 +2195,7 @@ smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr, */ nnp = VTOSMB(nvp); mutex_enter(&nnp->r_statelock); - if (nvp->v_count > 2) { + if ((nvp->v_count > 2) && (nnp->n_fidrefs > 0)) { /* * The target file exists, is not the same as * the source file, and is active. Other FS @@ -2297,14 +2207,26 @@ smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr, error = EBUSY; goto out; } - mutex_exit(&nnp->r_statelock); /* * Target file is not active. Try to remove it. */ - smb_credinit(&scred, cr); + smbfs_attrcache_rm_locked(nnp); + mutex_exit(&nnp->r_statelock); + error = smbfs_smb_delete(nnp, &scred, NULL, 0, 0); - smb_credrele(&scred); + + /* + * Similar to smbfs_remove + */ + switch (error) { + case 0: + case ENOENT: + case ENOTDIR: + smbfs_attrcache_prune(nnp); + break; + } + if (error) goto out; /* @@ -2317,14 +2239,17 @@ smbfsrename(vnode_t *odvp, char *onm, vnode_t *ndvp, char *nnm, cred_t *cr, nvp = NULL; } /* nvp */ - dnlc_remove(odvp, onm); - dnlc_remove(ndvp, nnm); - onp = VTOSMB(ovp); - smb_credinit(&scred, cr); + smbfs_attrcache_remove(onp); + error = smbfs_smb_rename(onp, ndnp, nnm, strlen(nnm), &scred); - smb_credrele(&scred); + /* + * If the old name should no longer exist, + * discard any cached attributes under it. + */ + if (error == 0) + smbfs_attrcache_prune(onp); out: if (nvp) { @@ -2335,6 +2260,7 @@ out: if (ovp) VN_RELE(ovp); + smb_credrele(&scred); smbfs_rw_exit(&odnp->r_rwlock); smbfs_rw_exit(&ndnp->r_rwlock); @@ -2393,9 +2319,6 @@ smbfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp, if (error) goto out; - /* remove possible negative entry from the dnlc */ - dnlc_remove(dvp, nm); - error = smbfs_smb_mkdir(dnp, name, nmlen, &scred); if (error) goto out; @@ -2410,10 +2333,6 @@ smbfs_mkdir(vnode_t *dvp, char *nm, struct vattr *va, vnode_t **vpp, if (error) goto out; -#ifdef USE_DNLC - dnlc_update(dvp, nm, vp); -#endif - if (name[0] == '.') if ((hiderr = smbfs_smb_hideit(VTOSMB(vp), NULL, 0, &scred))) SMBVDEBUG("hide failure %d\n", hiderr); @@ -2498,28 +2417,20 @@ smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr, goto out; } - /* - * First just remove the entry from the name cache, as it - * is most likely an entry for this vp. - */ - dnlc_remove(dvp, nm); + smbfs_attrcache_remove(np); + error = smbfs_smb_rmdir(np, &scred); /* - * If there vnode reference count is greater than one, then - * there may be additional references in the DNLC which will - * need to be purged. First, trying removing the entry for - * the parent directory and see if that removes the additional - * reference(s). If that doesn't do it, then use dnlc_purge_vp - * to completely remove any references to the directory which - * might still exist in the DNLC. + * Similar to smbfs_remove */ - if (vp->v_count > 1) { - dnlc_remove(vp, ".."); - if (vp->v_count > 1) - dnlc_purge_vp(vp); + switch (error) { + case 0: + case ENOENT: + case ENOTDIR: + smbfs_attrcache_prune(np); + break; } - error = smbfs_smb_rmdir(np, &scred); if (error) goto out; @@ -2527,7 +2438,7 @@ smbfs_rmdir(vnode_t *dvp, char *nm, vnode_t *cdir, cred_t *cr, dnp->n_flag |= NMODIFIED; mutex_exit(&np->r_statelock); smbfs_attr_touchdir(dnp); - smb_rmhash(np); + smbfs_rmhash(np); out: if (vp) { @@ -2636,15 +2547,6 @@ smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp, if (uio->uio_resid < dbufsiz) return (EINVAL); -#ifdef USE_DNLC - /* - * This dnlc_purge_vp ensures that name cache for this dir will be - * current - it'll only have the items for which the smbfs_nget - * MAKEENTRY happened. - */ - if (smbfs_fastlookup) - dnlc_purge_vp(vp); -#endif SMBVDEBUG("dirname='%s'\n", np->n_rpath); smb_credinit(&scred, cr); dp = kmem_alloc(dbufsiz, KM_SLEEP); @@ -2757,20 +2659,19 @@ smbfs_readvdir(vnode_t *vp, uio_t *uio, cred_t *cr, int *eofp, nmlen = SMB_MAXFNAMELEN; SMBVDEBUG("Truncating name: %s\n", ctx->f_name); } -#ifdef NOT_YET if (smbfs_fastlookup) { + /* See comment at smbfs_fastlookup above. */ if (smbfs_nget(vp, ctx->f_name, nmlen, &ctx->f_attr, &newvp) == 0) VN_RELE(newvp); } -#endif /* NOT_YET */ reclen = DIRENT64_RECLEN(nmlen); bzero(dp, reclen); dp->d_reclen = reclen; bcopy(ctx->f_name, dp->d_name, nmlen); dp->d_name[nmlen] = '\0'; - dp->d_ino = ctx->f_attr.fa_ino; + dp->d_ino = ctx->f_inum; dp->d_off = offset + 1; /* See d_off comment above */ error = uiomove(dp, reclen, UIO_READ, uio); if (error) @@ -3000,9 +2901,10 @@ smbfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr, case _PC_ACL_ENABLED: /* - * Always say "yes" here. Our _getsecattr - * will build a trivial ACL when needed, - * i.e. when server does not have ACLs. + * Always indicate that ACLs are enabled and + * that we support ACE_T format, otherwise + * libsec will ask for ACLENT_T format data + * which we don't support. */ *valp = _ACL_ACE_ENABLED; break; @@ -3019,8 +2921,11 @@ smbfs_pathconf(vnode_t *vp, int cmd, ulong_t *valp, cred_t *cr, return (EINVAL); case _PC_TIMESTAMP_RESOLUTION: - /* nanosecond timestamp resolution */ - *valp = 1L; + /* + * Windows times are tenths of microseconds + * (multiples of 100 nanoseconds). + */ + *valp = 100L; break; default: @@ -3036,7 +2941,9 @@ smbfs_getsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr, { vfs_t *vfsp; smbmntinfo_t *smi; - int error, uid, gid; + uid_t uid; + gid_t gid; + int error; uint_t mask; vfsp = vp->v_vfsp; @@ -3059,12 +2966,9 @@ smbfs_getsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr, if (mask == 0) return (ENOSYS); - /* XXX - access check ACE_READ_ACL? */ - - if (smi->smi_fsattr & FILE_PERSISTENT_ACLS) { + if (smi->smi_flags & SMI_ACL) error = smbfs_getacl(vp, vsa, &uid, &gid, flag, cr); - /* XXX: Save uid/gid somewhere? */ - } else + else error = ENOSYS; if (error == ENOSYS) @@ -3100,21 +3004,20 @@ smbfs_setsecattr(vnode_t *vp, vsecattr_t *vsa, int flag, cred_t *cr, if (mask == 0) return (ENOSYS); - /* - * If and when smbfs_access is extended, we can - * check ACE_WRITE_ACL here instead. (XXX todo) - * For now, in-line parts of smbfs_access, - * i.e. only allow _setacl by the owner, - * and check for read-only FS. - */ if (vfsp->vfs_flag & VFS_RDONLY) return (EROFS); - if (crgetuid(cr) != smi->smi_args.uid) - return (EACCES); - if (smi->smi_fsattr & FILE_PERSISTENT_ACLS) { + /* + * Allow only the mount owner to do this. + * See comments at smbfs_access_rwx. + */ + error = secpolicy_vnode_setdac(cr, smi->smi_uid); + if (error != 0) + return (error); + + if (smi->smi_flags & SMI_ACL) error = smbfs_setacl(vp, vsa, -1, -1, flag, cr); - } else + else error = ENOSYS; return (error); diff --git a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_xattr.c b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_xattr.c index ad68648d12..83c91fecc0 100644 --- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_xattr.c +++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_xattr.c @@ -41,7 +41,6 @@ #include <sys/kmem.h> #include <sys/stat.h> #include <sys/cmn_err.h> -#include <sys/dnlc.h> #include <sys/u8_textprep.h> #include <netsmb/smb_osdep.h> @@ -86,12 +85,20 @@ smbfs_get_xattrdir(vnode_t *pvp, vnode_t **vpp, cred_t *cr, int flags) pnp = VTOSMB(pvp); - xvp = smbfs_make_node(pvp->v_vfsp, - pnp->n_rpath, pnp->n_rplen, - NULL, 0, ':', NULL); - ASSERT(xvp); + /* + * We don't allow recursive extended attributes + * (xattr under xattr dir.) so the "parent" node + * (pnp) must NOT be an XATTR directory or file. + */ + if (pnp->n_flag & N_XATTR) + return (EINVAL); + + xnp = smbfs_node_findcreate(pnp->n_mount, + pnp->n_rpath, pnp->n_rplen, NULL, 0, ':', + &smbfs_fattr0); /* force create */ + ASSERT(xnp != NULL); + xvp = SMBTOV(xnp); /* Note: xvp has a VN_HOLD, which our caller expects. */ - xnp = VTOSMB(xvp); /* If it's a new node, initialize. */ if (xvp->v_type == VNON) { @@ -122,9 +129,11 @@ int smbfs_xa_parent(vnode_t *vp, vnode_t **vpp) { smbnode_t *np = VTOSMB(vp); - vnode_t *pvp; + smbnode_t *pnp; int rplen; + *vpp = NULL; + if ((np->n_flag & N_XATTR) == 0) return (EINVAL); @@ -163,13 +172,12 @@ smbfs_xa_parent(vnode_t *vp, vnode_t **vpp) } } - pvp = smbfs_make_node(vp->v_vfsp, - np->n_rpath, rplen, - NULL, 0, 0, NULL); - ASSERT(pvp); - - /* Note: pvp has a VN_HOLD from _make_node */ - *vpp = pvp; + pnp = smbfs_node_findcreate(np->n_mount, + np->n_rpath, rplen, NULL, 0, 0, + &smbfs_fattr0); /* force create */ + ASSERT(pnp != NULL); + /* Note: have VN_HOLD from smbfs_node_findcreate */ + *vpp = SMBTOV(pnp); return (0); } diff --git a/usr/src/uts/common/netsmb/mchain.h b/usr/src/uts/common/netsmb/mchain.h index bccb9aab7f..c5c8512fd7 100644 --- a/usr/src/uts/common/netsmb/mchain.h +++ b/usr/src/uts/common/netsmb/mchain.h @@ -87,8 +87,24 @@ #endif /* (BYTE_ORDER == LITTLE_ENDIAN) */ +/* + * Additions for Solaris to replace things that came from + * <sys/mbuf.h> in the Darwin code. These are mostly just + * wrappers for streams functions. See: subr_mchain.c + */ + #ifdef _KERNEL +/* + * BSD-style mbuf "shim" for kernel code. Note, this + * does NOT implement BSD mbufs in the kernel. Rather, + * macros and wrapper functions are used so that code + * fomerly using mbuf_t now use STREAMS mblk_t instead. + */ + +#include <sys/stream.h> /* mblk_t */ +typedef mblk_t mbuf_t; + /* BEGIN CSTYLED */ /* * BSD-style mbufs, vs SysV-style mblks: @@ -115,7 +131,42 @@ */ /* END CSTYLED */ -#include <sys/stream.h> /* mblk_t */ +#define mtod(m, t) ((t)((m)->b_rptr)) + +/* length arg for m_copym to "copy all" */ +#define M_COPYALL -1 + +mblk_t *m_copym(mblk_t *, int, int, int); +mblk_t *m_pullup(mblk_t *, int); +mblk_t *m_split(mblk_t *, int, int); +void m_cat(mblk_t *, mblk_t *); +#define m_freem(x) freemsg(x) +mblk_t *m_getblk(int, int); +int m_fixhdr(mblk_t *m); + +#else /* _KERNEL */ + +/* + * BSD-style mbuf work-alike, for user-level. + * See libsmbfs mbuf.c + */ +typedef struct mbuf { + int m_len; + int m_maxlen; + char *m_data; + struct mbuf *m_next; +} mbuf_t; + +#define mtod(m, t) ((t)(m)->m_data) + +int m_get(int, mbuf_t **); +void m_freem(mbuf_t *); + +#endif /* _KERNEL */ + +/* + * BSD-style mbchain/mdchain work-alike + */ /* * Type of copy for mb_{put|get}_mem() @@ -126,6 +177,8 @@ #define MB_MZERO 3 /* bzero(), mb_put_mem only */ #define MB_MCUSTOM 4 /* use an user defined function */ +#ifdef _KERNEL + struct mbchain { mblk_t *mb_top; mblk_t *mb_cur; @@ -136,65 +189,64 @@ typedef struct mbchain mbchain_t; struct mdchain { mblk_t *md_top; /* head of mblk chain */ mblk_t *md_cur; /* current mblk */ - uchar_t *md_pos; /* offset in the current mblk */ + uchar_t *md_pos; /* position in md_cur */ + /* NB: md_pos is same type as mblk_t b_rptr, b_wptr members. */ }; typedef struct mdchain mdchain_t; -int m_fixhdr(mblk_t *m); +mblk_t *mb_detach(mbchain_t *mbp); +int mb_fixhdr(mbchain_t *mbp); +int mb_put_uio(mbchain_t *mbp, uio_t *uiop, size_t size); -int mb_init(struct mbchain *mbp); -void mb_initm(struct mbchain *mbp, mblk_t *m); -void mb_done(struct mbchain *mbp); -mblk_t *mb_detach(struct mbchain *mbp); -int mb_fixhdr(struct mbchain *mbp); -void *mb_reserve(struct mbchain *mbp, int size); - -int mb_put_padbyte(struct mbchain *mbp); -int mb_put_uint8(struct mbchain *mbp, uint8_t x); -int mb_put_uint16be(struct mbchain *mbp, uint16_t x); -int mb_put_uint16le(struct mbchain *mbp, uint16_t x); -int mb_put_uint32be(struct mbchain *mbp, uint32_t x); -int mb_put_uint32le(struct mbchain *mbp, uint32_t x); -int mb_put_uint64be(struct mbchain *mbp, uint64_t x); -int mb_put_uint64le(struct mbchain *mbp, uint64_t x); -int mb_put_mem(struct mbchain *mbp, const void *src, int size, int type); - -int mb_put_mbuf(struct mbchain *mbp, mblk_t *m); -int mb_put_uio(struct mbchain *mbp, uio_t *uiop, size_t size); - -int md_init(struct mdchain *mdp); -void md_initm(struct mdchain *mbp, mblk_t *m); -void md_done(struct mdchain *mdp); -void md_append_record(struct mdchain *mdp, mblk_t *top); -int md_next_record(struct mdchain *mdp); -int md_get_uint8(struct mdchain *mdp, uint8_t *x); -int md_get_uint16le(struct mdchain *mdp, uint16_t *x); -int md_get_uint16be(struct mdchain *mdp, uint16_t *x); -int md_get_uint32be(struct mdchain *mdp, uint32_t *x); -int md_get_uint32le(struct mdchain *mdp, uint32_t *x); -int md_get_uint64be(struct mdchain *mdp, uint64_t *x); -int md_get_uint64le(struct mdchain *mdp, uint64_t *x); -int md_get_mem(struct mdchain *mdp, void *vdst, int size, int type); -int md_get_mbuf(struct mdchain *mdp, int size, mblk_t **m); -int md_get_uio(struct mdchain *mdp, uio_t *uiop, size_t size); +void md_append_record(mdchain_t *mdp, mblk_t *top); +void md_next_record(mdchain_t *mdp); +int md_get_uio(mdchain_t *mdp, uio_t *uiop, size_t size); + +#else /* _KERNEL */ /* - * Additions for Solaris to replace things that came from - * <sys/mbuf.h> in the Darwin code. These are mostly just - * wrappers for streams functions. See: subr_mchain.c + * user-level code uses the same struct for both (MB, MD) */ +typedef struct mbdata { + mbuf_t *mb_top; /* head of mbuf chain */ + mbuf_t *mb_cur; /* current mbuf */ + char *mb_pos; /* position in mb_cur (get) */ + /* NB: mb_pos is same type as mbuf_t m_data member. */ + int mb_count; /* bytes marshalled (put) */ +} mbdata_t; +typedef struct mbdata mbchain_t; +typedef struct mbdata mdchain_t; + +#endif /* _KERNEL */ + +int mb_init(mbchain_t *); +void mb_initm(mbchain_t *, mbuf_t *); +void mb_done(mbchain_t *); +void *mb_reserve(mbchain_t *, int size); + +int mb_put_padbyte(mbchain_t *mbp); +int mb_put_uint8(mbchain_t *, uint8_t); +int mb_put_uint16be(mbchain_t *, uint16_t); +int mb_put_uint16le(mbchain_t *, uint16_t); +int mb_put_uint32be(mbchain_t *, uint32_t); +int mb_put_uint32le(mbchain_t *, uint32_t); +int mb_put_uint64be(mbchain_t *, uint64_t); +int mb_put_uint64le(mbchain_t *, uint64_t); +int mb_put_mem(mbchain_t *, const void *, int, int); +int mb_put_mbuf(mbchain_t *, mbuf_t *); + +int md_init(mdchain_t *mdp); +void md_initm(mdchain_t *mbp, mbuf_t *m); +void md_done(mdchain_t *mdp); + +int md_get_uint8(mdchain_t *, uint8_t *); +int md_get_uint16be(mdchain_t *, uint16_t *); +int md_get_uint16le(mdchain_t *, uint16_t *); +int md_get_uint32be(mdchain_t *, uint32_t *); +int md_get_uint32le(mdchain_t *, uint32_t *); +int md_get_uint64be(mdchain_t *, uint64_t *); +int md_get_uint64le(mdchain_t *, uint64_t *); +int md_get_mem(mdchain_t *, void *, int, int); +int md_get_mbuf(mdchain_t *, int, mbuf_t **); -#define mtod(m, t) ((t)((m)->b_rptr)) - -/* length to m_copym to copy all */ -#define M_COPYALL -1 - -mblk_t *m_copym(mblk_t *, int, int, int); -mblk_t *m_pullup(mblk_t *, int); -mblk_t *m_split(mblk_t *, int, int); -void m_cat(mblk_t *, mblk_t *); -#define m_freem(x) freemsg(x) -mblk_t *m_getblk(int, int); - -#endif /* ifdef _KERNEL */ #endif /* !_MCHAIN_H_ */ diff --git a/usr/src/uts/common/sys/fs/smbfs_mount.h b/usr/src/uts/common/sys/fs/smbfs_mount.h index 6eeb8f909f..2e4981e02b 100644 --- a/usr/src/uts/common/sys/fs/smbfs_mount.h +++ b/usr/src/uts/common/sys/fs/smbfs_mount.h @@ -33,15 +33,13 @@ */ /* - * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _SMBFS_MOUNT_H #define _SMBFS_MOUNT_H -#pragma ident "%Z%%M% %I% %E% SMI" - /* * This file defines the interface used by mount_smbfs. * Some of this came from the Darwin file: @@ -49,43 +47,34 @@ */ #define SMBFS_VERMAJ 1 -#define SMBFS_VERMIN 3200 +#define SMBFS_VERMIN 3300 #define SMBFS_VERSION (SMBFS_VERMAJ*100000 + SMBFS_VERMIN) -#define SMBFS_VER_STR "1.32" +#define SMBFS_VER_STR "1.33" #define SMBFS_VFSNAME "smbfs" -/* Values for flags */ -#define SMBFS_MOUNT_SOFT 0x0001 -#define SMBFS_MOUNT_INTR 0x0002 -#define SMBFS_MOUNT_STRONG 0x0004 -#define SMBFS_MOUNT_HAVE_NLS 0x0008 -#define SMBFS_MOUNT_NO_LONG 0x0010 -#define SMBFS_MOUNT_HOSTNAME 0x020 -#define SMBFS_MOUNT_SEMISOFT 0x200000 /* read soft, modify hard */ -#define SMBFS_MOUNT_NOPRINT 0x400000 /* don't print messages */ - -#define MNT_RDONLY 0x0001 -#define MNT_NODEV 0x0002 -#define MNT_NOEXEC 0x0004 -#define MNT_NOSUID 0x0008 -#define MNT_UNION 0x0010 -#define MNT_DONTBROWSE 0x0020 -#define MNT_AUTOMOUNTED 0x0040 +/* Values for smbfs_args.flags */ +#define SMBFS_MF_SOFT 0x0001 +#define SMBFS_MF_INTR 0x0002 +#define SMBFS_MF_NOAC 0x0004 +#define SMBFS_MF_ACREGMIN 0x0100 /* set min secs for file attr cache */ +#define SMBFS_MF_ACREGMAX 0x0200 /* set max secs for file attr cache */ +#define SMBFS_MF_ACDIRMIN 0x0400 /* set min secs for dir attr cache */ +#define SMBFS_MF_ACDIRMAX 0x0800 /* set max secs for dir attr cache */ /* Layout of the mount control block for an smb file system. */ struct smbfs_args { int version; /* smbfs mount version */ int devfd; /* file descriptor */ - uint_t flags; /* mount options, eg: soft */ - mode_t file_mode; /* octal srwx for files */ - mode_t dir_mode; /* octal srwx for dirs */ - int caseopt; /* convert upper|lower|none */ - caddr_t addr; /* file server address */ - caddr_t hostname; /* server's hostname */ - caddr_t sharename; /* server's sharename */ + uint_t flags; /* SMBFS_MF_ flags */ uid_t uid; /* octal user id */ gid_t gid; /* octal group id */ + mode_t file_mode; /* octal srwx for files */ + mode_t dir_mode; /* octal srwx for dirs */ + int acregmin; /* attr cache file min secs */ + int acregmax; /* attr cache file max secs */ + int acdirmin; /* attr cache dir min secs */ + int acdirmax; /* attr cache dir max secs */ }; #ifdef _SYSCALL32 @@ -94,15 +83,15 @@ struct smbfs_args { struct smbfs_args32 { int32_t version; /* smbfs mount version */ int32_t devfd; /* file descriptor */ - uint_t flags; /* mount options, eg: soft */ - mode_t file_mode; /* octal srwx for files */ - mode_t dir_mode; /* octal srwx for dirs */ - int32_t caseopt; /* convert upper|lower|none */ - caddr32_t addr; /* file server address */ - caddr32_t hostname; /* server's hostname */ - caddr32_t sharename; /* server's sharename */ + uint32_t flags; /* SMBFS_MF_ flags */ uid32_t uid; /* octal user id */ gid32_t gid; /* octal group id */ + mode32_t file_mode; /* octal srwx for files */ + mode32_t dir_mode; /* octal srwx for dirs */ + int32_t acregmin; /* attr cache file min secs */ + int32_t acregmax; /* attr cache file max secs */ + int32_t acdirmin; /* attr cache dir min secs */ + int32_t acdirmax; /* attr cache dir max secs */ }; #endif /* _SYSCALL32 */ diff --git a/usr/src/uts/intel/nsmb/Makefile b/usr/src/uts/intel/nsmb/Makefile index ad20178ce4..dbe89e1b9d 100644 --- a/usr/src/uts/intel/nsmb/Makefile +++ b/usr/src/uts/intel/nsmb/Makefile @@ -68,14 +68,12 @@ CERRWARN += -erroff=E_STATEMENT_NOT_REACHED INC_PATH += -I$(UTSBASE)/common/fs/smbclnt LDFLAGS += -dy -Ncrypto/md4 -Ncrypto/md5 -Nmisc/tlimod -LINTTAGS += -erroff=E_FUNC_RET_ALWAYS_IGNOR2 -LINTTAGS += -erroff=E_FUNC_RET_MAYBE_IGNORED2 # Until CR 4994570 is fixed... LINTTAGS += -erroff=E_BAD_FORMAT_ARG_TYPE2 # The mb_put/md_get functions are intentionally used with and without # return value checks, so filter those out like LGREP.2 does. -LGREP.nsmb = egrep -v ' ignored: (mb_put|md_get)' +LGREP.nsmb = egrep -v ' ignored: (mb_init|mb_put|md_get)' LTAIL += 2>&1 | $(LGREP.2) | $(LGREP.nsmb) || true # @@ -107,7 +105,7 @@ $(OBJECTS) : $(IOC_CHECK_H) $(IOC_CHECK_H): $(OFFSETS_SRC) $(OFFSETS_CREATE) <$(OFFSETS_SRC) >$@.tmp cmp -s ioc_check.ref $@.tmp && \ - mv -f $@.tmp $@ + mv -f $@.tmp $@ # # Include common targets. diff --git a/usr/src/uts/intel/smbfs/Makefile b/usr/src/uts/intel/smbfs/Makefile index 445d40c736..65377ffa1e 100644 --- a/usr/src/uts/intel/smbfs/Makefile +++ b/usr/src/uts/intel/smbfs/Makefile @@ -63,16 +63,15 @@ $(MODSTUBS_O) := AS_CPPFLAGS += -DSMBFS_MODULE CLEANFILES += $(MODSTUBS_O) C99MODE = $(C99_ENABLE) INC_PATH += -I$(UTSBASE)/common/fs/smbclnt +INC_PATH += -I$(COMMONBASE)/smbclnt LDFLAGS += -dy -Ndrv/nsmb -LINTTAGS += -erroff=E_FUNC_RET_ALWAYS_IGNOR2 -LINTTAGS += -erroff=E_FUNC_RET_MAYBE_IGNORED2 # Until CR 4994570 is fixed... LINTTAGS += -erroff=E_BAD_FORMAT_ARG_TYPE2 # The mb_put/md_get functions are intentionally used with and without # return value checks, so filter those out like LGREP.2 does. -LGREP.nsmb = egrep -v ' ignored: (mb_put|md_get)' +LGREP.nsmb = egrep -v ' ignored: (mb_init|mb_put|md_get)' LTAIL += 2>&1 | $(LGREP.2) | $(LGREP.nsmb) || true # diff --git a/usr/src/uts/sparc/nsmb/Makefile b/usr/src/uts/sparc/nsmb/Makefile index 174d0f77bf..79515e3de4 100644 --- a/usr/src/uts/sparc/nsmb/Makefile +++ b/usr/src/uts/sparc/nsmb/Makefile @@ -92,14 +92,12 @@ CERRWARN += -erroff=E_STATEMENT_NOT_REACHED INC_PATH += -I$(UTSBASE)/common/fs/smbclnt LDFLAGS += -dy -Ncrypto/md4 -Ncrypto/md5 -Nmisc/tlimod -LINTTAGS += -erroff=E_FUNC_RET_ALWAYS_IGNOR2 -LINTTAGS += -erroff=E_FUNC_RET_MAYBE_IGNORED2 # Until CR 4994570 is fixed... LINTTAGS += -erroff=E_BAD_FORMAT_ARG_TYPE2 # The mb_put/md_get functions are intentionally used with and without # return value checks, so filter those out like LGREP.2 does. -LGREP.nsmb = egrep -v ' ignored: (mb_put|md_get)' +LGREP.nsmb = egrep -v ' ignored: (mb_init|mb_put|md_get)' LTAIL += 2>&1 | $(LGREP.2) | $(LGREP.nsmb) || true # diff --git a/usr/src/uts/sparc/smbfs/Makefile b/usr/src/uts/sparc/smbfs/Makefile index 3f75aa8c83..26be8f8780 100644 --- a/usr/src/uts/sparc/smbfs/Makefile +++ b/usr/src/uts/sparc/smbfs/Makefile @@ -63,16 +63,15 @@ $(MODSTUBS_O) := AS_CPPFLAGS += -DSMBFS_MODULE CLEANFILES += $(MODSTUBS_O) C99MODE = $(C99_ENABLE) INC_PATH += -I$(UTSBASE)/common/fs/smbclnt +INC_PATH += -I$(COMMONBASE)/smbclnt LDFLAGS += -dy -Ndrv/nsmb -LINTTAGS += -erroff=E_FUNC_RET_ALWAYS_IGNOR2 -LINTTAGS += -erroff=E_FUNC_RET_MAYBE_IGNORED2 # Until CR 4994570 is fixed... LINTTAGS += -erroff=E_BAD_FORMAT_ARG_TYPE2 # The mb_put/md_get functions are intentionally used with and without # return value checks, so filter those out like LGREP.2 does. -LGREP.nsmb = egrep -v ' ignored: (mb_put|md_get)' +LGREP.nsmb = egrep -v ' ignored: (mb_init|mb_put|md_get)' LTAIL += 2>&1 | $(LGREP.2) | $(LGREP.nsmb) || true # |