aboutsummaryrefslogtreecommitdiff
path: root/sys/fs
diff options
context:
space:
mode:
Diffstat (limited to 'sys/fs')
-rw-r--r--sys/fs/deadfs/dead_vnops.c10
-rw-r--r--sys/fs/devfs/devfs_int.h1
-rw-r--r--sys/fs/devfs/devfs_vnops.c17
-rw-r--r--sys/fs/fuse/fuse_device.c7
-rw-r--r--sys/fs/fuse/fuse_ipc.c2
-rw-r--r--sys/fs/fuse/fuse_vnops.c2
-rw-r--r--sys/fs/msdosfs/msdosfs_vnops.c3
-rw-r--r--sys/fs/nfs/nfs_commonsubs.c40
-rw-r--r--sys/fs/nfs/nfsproto.h4
-rw-r--r--sys/fs/nfsclient/nfs_clrpcops.c39
-rw-r--r--sys/fs/nfsclient/nfs_clvfsops.c8
-rw-r--r--sys/fs/nfsclient/nfs_clvnops.c8
-rw-r--r--sys/fs/nfsserver/nfs_nfsdport.c11
-rw-r--r--sys/fs/nfsserver/nfs_nfsdserv.c17
14 files changed, 128 insertions, 41 deletions
diff --git a/sys/fs/deadfs/dead_vnops.c b/sys/fs/deadfs/dead_vnops.c
index 296cf058f8c9..137c86b65058 100644
--- a/sys/fs/deadfs/dead_vnops.c
+++ b/sys/fs/deadfs/dead_vnops.c
@@ -122,18 +122,18 @@ dead_read(struct vop_read_args *ap)
{
/*
- * Return EOF for tty devices, EIO for others
+ * Return EOF for tty devices, ENXIO for others
*/
- if ((ap->a_vp->v_vflag & VV_ISTTY) == 0)
- return (EIO);
- return (0);
+ if (ap->a_vp->v_vflag & VV_ISTTY)
+ return (0);
+ return (ENXIO);
}
int
dead_write(struct vop_write_args *ap)
{
- return (EIO);
+ return (ENXIO);
}
int
diff --git a/sys/fs/devfs/devfs_int.h b/sys/fs/devfs/devfs_int.h
index 916297425b53..9fa75c0e90ad 100644
--- a/sys/fs/devfs/devfs_int.h
+++ b/sys/fs/devfs/devfs_int.h
@@ -67,6 +67,7 @@ struct cdev_priv {
void *cdp_dtr_cb_arg;
LIST_HEAD(, cdev_privdata) cdp_fdpriv;
+ u_int cdp_fdpriv_dtrc;
struct mtx cdp_threadlock;
};
diff --git a/sys/fs/devfs/devfs_vnops.c b/sys/fs/devfs/devfs_vnops.c
index caadf257b8ad..323f1e0fa961 100644
--- a/sys/fs/devfs/devfs_vnops.c
+++ b/sys/fs/devfs/devfs_vnops.c
@@ -200,14 +200,25 @@ devfs_foreach_cdevpriv(struct cdev *dev, int (*cb)(void *data, void *arg),
void
devfs_destroy_cdevpriv(struct cdev_privdata *p)
{
+ struct file *fp;
+ struct cdev_priv *cdp;
mtx_assert(&cdevpriv_mtx, MA_OWNED);
- KASSERT(p->cdpd_fp->f_cdevpriv == p,
- ("devfs_destoy_cdevpriv %p != %p", p->cdpd_fp->f_cdevpriv, p));
- p->cdpd_fp->f_cdevpriv = NULL;
+ fp = p->cdpd_fp;
+ KASSERT(fp->f_cdevpriv == p,
+ ("devfs_destoy_cdevpriv %p != %p", fp->f_cdevpriv, p));
+ cdp = cdev2priv((struct cdev *)fp->f_data);
+ cdp->cdp_fdpriv_dtrc++;
+ fp->f_cdevpriv = NULL;
LIST_REMOVE(p, cdpd_list);
mtx_unlock(&cdevpriv_mtx);
(p->cdpd_dtr)(p->cdpd_data);
+ mtx_lock(&cdevpriv_mtx);
+ MPASS(cdp->cdp_fdpriv_dtrc >= 1);
+ cdp->cdp_fdpriv_dtrc--;
+ if (cdp->cdp_fdpriv_dtrc == 0)
+ wakeup(&cdp->cdp_fdpriv_dtrc);
+ mtx_unlock(&cdevpriv_mtx);
free(p, M_CDEVPDATA);
}
diff --git a/sys/fs/fuse/fuse_device.c b/sys/fs/fuse/fuse_device.c
index 75bc0357571f..cee477865c42 100644
--- a/sys/fs/fuse/fuse_device.c
+++ b/sys/fs/fuse/fuse_device.c
@@ -550,6 +550,13 @@ fuse_device_write(struct cdev *dev, struct uio *uio, int ioflag)
} else if (ohead.unique == 0){
/* unique == 0 means asynchronous notification */
SDT_PROBE1(fusefs, , device, fuse_device_write_notify, &ohead);
+ if (data->mp == NULL) {
+ SDT_PROBE2(fusefs, , device, trace, 1,
+ "asynchronous notification before mount"
+ " or after unmount");
+ return (EXTERROR(ENODEV,
+ "This FUSE session is not mounted"));
+ }
mp = data->mp;
vfs_ref(mp);
err = vfs_busy(mp, 0);
diff --git a/sys/fs/fuse/fuse_ipc.c b/sys/fs/fuse/fuse_ipc.c
index 7f754ab7f1d4..bc36f0070d7d 100644
--- a/sys/fs/fuse/fuse_ipc.c
+++ b/sys/fs/fuse/fuse_ipc.c
@@ -694,7 +694,7 @@ fuse_body_audit(struct fuse_ticket *ftick, size_t blen)
break;
case FUSE_FORGET:
- panic("FUSE: a handler has been intalled for FUSE_FORGET");
+ panic("FUSE: a handler has been installed for FUSE_FORGET");
break;
case FUSE_GETATTR:
diff --git a/sys/fs/fuse/fuse_vnops.c b/sys/fs/fuse/fuse_vnops.c
index 683ee2f7ad56..97aa23bfb0b0 100644
--- a/sys/fs/fuse/fuse_vnops.c
+++ b/sys/fs/fuse/fuse_vnops.c
@@ -2756,7 +2756,7 @@ fuse_vnop_setextattr(struct vop_setextattr_args *ap)
*/
if (fsess_not_impl(mp, FUSE_REMOVEXATTR))
return (EXTERROR(EOPNOTSUPP, "This server does not "
- "implement removing extended attributess"));
+ "implement removing extended attributes"));
else
return (EXTERROR(EINVAL, "DELETEEXTATTR should be used "
"to remove extattrs"));
diff --git a/sys/fs/msdosfs/msdosfs_vnops.c b/sys/fs/msdosfs/msdosfs_vnops.c
index 33e0d94954d7..6dfac1b4ebd2 100644
--- a/sys/fs/msdosfs/msdosfs_vnops.c
+++ b/sys/fs/msdosfs/msdosfs_vnops.c
@@ -1944,6 +1944,9 @@ msdosfs_pathconf(struct vop_pathconf_args *ap)
case _PC_HAS_HIDDENSYSTEM:
*ap->a_retval = 1;
return (0);
+ case _PC_CASE_INSENSITIVE:
+ *ap->a_retval = 1;
+ return (0);
default:
return (vop_stdpathconf(ap));
}
diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c
index ec95716ea485..f580a394a735 100644
--- a/sys/fs/nfs/nfs_commonsubs.c
+++ b/sys/fs/nfs/nfs_commonsubs.c
@@ -194,7 +194,6 @@ struct nfsv4_opflag nfsv4_opflag[NFSV42_NOPS] = {
{ 0, 1, 1, 1, LK_EXCLUSIVE, 1, 1 }, /* Removexattr */
};
-static int ncl_mbuf_mhlen = MHLEN;
struct nfsrv_lughash {
struct mtx mtx;
struct nfsuserhashhead lughead;
@@ -641,6 +640,7 @@ nfscl_fillsattr(struct nfsrv_descript *nd, struct vattr *vap,
if ((flags & NFSSATTR_FULL) && vap->va_size != VNOVAL)
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SIZE);
if ((flags & NFSSATTR_FULL) && vap->va_flags != VNOVAL) {
+ NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ARCHIVE);
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN);
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM);
}
@@ -769,7 +769,7 @@ nfsm_dissct(struct nfsrv_descript *nd, int siz, int how)
nd->nd_dpos += siz;
} else if (nd->nd_md->m_next == NULL) {
return (retp);
- } else if (siz > ncl_mbuf_mhlen) {
+ } else if (siz > MHLEN) {
panic("nfs S too big");
} else {
MGET(mp2, how, MT_DATA);
@@ -1672,9 +1672,17 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp,
attrsum += NFSX_UNSIGNED;
break;
case NFSATTRBIT_ARCHIVE:
- NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
- if (compare && !(*retcmpp))
- *retcmpp = NFSERR_ATTRNOTSUPP;
+ NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
+ if (compare) {
+ if (!(*retcmpp) && ((*tl == newnfs_true &&
+ (nap->na_flags & UF_ARCHIVE) == 0) ||
+ (*tl == newnfs_false &&
+ (nap->na_flags & UF_ARCHIVE) != 0)))
+ *retcmpp = NFSERR_NOTSAME;
+ } else if (nap != NULL) {
+ if (*tl == newnfs_true)
+ nap->na_flags |= UF_ARCHIVE;
+ }
attrsum += NFSX_UNSIGNED;
break;
case NFSATTRBIT_CANSETTIME:
@@ -2804,6 +2812,7 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
if (!has_hiddensystem) {
NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN);
NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM);
+ NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_ARCHIVE);
}
if (clone_blksize == 0)
NFSCLRBIT_ATTRBIT(&attrbits,
@@ -2888,6 +2897,14 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
*tl = txdr_unsigned(NFSV4ACE_SUPTYPES);
retnum += NFSX_UNSIGNED;
break;
+ case NFSATTRBIT_ARCHIVE:
+ NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
+ if ((vap->va_flags & UF_ARCHIVE) != 0)
+ *tl = newnfs_true;
+ else
+ *tl = newnfs_false;
+ retnum += NFSX_UNSIGNED;
+ break;
case NFSATTRBIT_CANSETTIME:
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
if (fsinf.fs_properties & NFSV3FSINFO_CANSETTIME)
@@ -4174,10 +4191,15 @@ nfssvc_idname(struct nfsd_idargs *nidp)
nidp->nid_namelen);
if (error == 0 && nidp->nid_ngroup > 0 &&
(nidp->nid_flag & NFSID_ADDUID) != 0) {
- grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
- M_WAITOK);
- error = copyin(nidp->nid_grps, grps,
- sizeof(gid_t) * nidp->nid_ngroup);
+ grps = NULL;
+ if (nidp->nid_ngroup > NGROUPS_MAX)
+ error = EINVAL;
+ if (error == 0) {
+ grps = malloc(sizeof(gid_t) * nidp->nid_ngroup, M_TEMP,
+ M_WAITOK);
+ error = copyin(nidp->nid_grps, grps,
+ sizeof(gid_t) * nidp->nid_ngroup);
+ }
if (error == 0) {
/*
* Create a credential just like svc_getcred(),
diff --git a/sys/fs/nfs/nfsproto.h b/sys/fs/nfs/nfsproto.h
index d628108bdc1a..13fec8a102a3 100644
--- a/sys/fs/nfs/nfsproto.h
+++ b/sys/fs/nfs/nfsproto.h
@@ -1135,6 +1135,7 @@ struct nfsv3_sattr {
NFSATTRBM_RDATTRERROR | \
NFSATTRBM_ACL | \
NFSATTRBM_ACLSUPPORT | \
+ NFSATTRBM_ARCHIVE | \
NFSATTRBM_CANSETTIME | \
NFSATTRBM_CASEINSENSITIVE | \
NFSATTRBM_CASEPRESERVING | \
@@ -1217,6 +1218,7 @@ struct nfsv3_sattr {
#define NFSATTRBIT_SETABLE0 \
(NFSATTRBM_SIZE | \
NFSATTRBM_HIDDEN | \
+ NFSATTRBM_ARCHIVE | \
NFSATTRBM_ACL)
#define NFSATTRBIT_SETABLE1 \
(NFSATTRBM_MODE | \
@@ -1262,6 +1264,7 @@ struct nfsv3_sattr {
NFSATTRBM_CHANGE | \
NFSATTRBM_SIZE | \
NFSATTRBM_FSID | \
+ NFSATTRBM_ARCHIVE | \
NFSATTRBM_FILEID | \
NFSATTRBM_HIDDEN | \
NFSATTRBM_MAXREAD)
@@ -1298,6 +1301,7 @@ struct nfsv3_sattr {
NFSATTRBM_CHANGE | \
NFSATTRBM_SIZE | \
NFSATTRBM_FSID | \
+ NFSATTRBM_ARCHIVE | \
NFSATTRBM_FILEID | \
NFSATTRBM_HIDDEN | \
NFSATTRBM_MAXREAD)
diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c
index ad9404a18fc8..b61218958550 100644
--- a/sys/fs/nfsclient/nfs_clrpcops.c
+++ b/sys/fs/nfsclient/nfs_clrpcops.c
@@ -2212,7 +2212,7 @@ nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode,
NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED
+ NFSX_VERF);
rlen = fxdr_unsigned(int, *tl++);
- if (rlen == 0) {
+ if (rlen <= 0 || rlen > len) {
error = NFSERR_IO;
goto nfsmout;
} else if (rlen < len) {
@@ -4162,9 +4162,12 @@ nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
NFSATTRBIT_TIMECREATE))
NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMECREATE);
if (!NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
+ NFSATTRBIT_ARCHIVE) ||
+ !NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
NFSATTRBIT_HIDDEN) ||
!NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
NFSATTRBIT_SYSTEM)) {
+ NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_ARCHIVE);
NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN);
NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM);
}
@@ -5281,7 +5284,7 @@ nfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred,
struct nfsrv_descript nfsd;
struct nfsrv_descript *nd = &nfsd;
u_char *cp, *cp2, *fhp;
- int error, cnt, len, setnil;
+ int error, cnt, i, len, setnil;
u_int32_t *opcntp;
nfscl_reqstart(nd, NFSPROC_PUTROOTFH, nmp, NULL, 0, &opcntp, NULL, 0,
@@ -5322,8 +5325,12 @@ nfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred,
if (error)
return (error);
if (nd->nd_repstat == 0) {
- NFSM_DISSECT(tl, u_int32_t *, (3 + 2 * cnt) * NFSX_UNSIGNED);
- tl += (2 + 2 * cnt);
+ NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED);
+ tl += 2;
+ for (i = 0; i < cnt; i++) {
+ NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
+ tl++;
+ }
if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
len > NFSX_FHMAX) {
nd->nd_repstat = NFSERR_BADXDR;
@@ -5596,7 +5603,7 @@ nfsrpc_createsession(struct nfsmount *nmp, struct nfsclsession *sep,
}
*tl++ = txdr_unsigned(4096); /* Max response size cached */
*tl++ = txdr_unsigned(20); /* Max operations */
- *tl++ = txdr_unsigned(64); /* Max slots */
+ *tl++ = txdr_unsigned(NFSV4_SLOTS); /* Max slots */
*tl = 0; /* No rdma ird */
/* Fill in back channel attributes. */
@@ -5665,6 +5672,11 @@ nfsrpc_createsession(struct nfsmount *nmp, struct nfsclsession *sep,
sep->nfsess_maxcache = fxdr_unsigned(int, *tl++);
tl++;
sep->nfsess_foreslots = fxdr_unsigned(uint16_t, *tl++);
+ if (sep->nfsess_foreslots == 0) {
+ error = NFSERR_BADXDR;
+ goto nfsmout;
+ } else if (sep->nfsess_foreslots > NFSV4_SLOTS)
+ sep->nfsess_foreslots = NFSV4_SLOTS;
NFSCL_DEBUG(4, "fore slots=%d\n", (int)sep->nfsess_foreslots);
irdcnt = fxdr_unsigned(int, *tl);
if (irdcnt < 0 || irdcnt > 1) {
@@ -5678,6 +5690,8 @@ nfsrpc_createsession(struct nfsmount *nmp, struct nfsclsession *sep,
NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
tl += 5;
sep->nfsess_backslots = fxdr_unsigned(uint16_t, *tl);
+ if (sep->nfsess_backslots > NFSV4_CBSLOTS)
+ sep->nfsess_backslots = NFSV4_CBSLOTS;
NFSCL_DEBUG(4, "back slots=%d\n", (int)sep->nfsess_backslots);
}
error = nd->nd_repstat;
@@ -5797,7 +5811,8 @@ nfsrpc_getdeviceinfo(struct nfsmount *nmp, uint8_t *deviceid, int layouttype,
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
stripecnt = fxdr_unsigned(int, *tl);
NFSCL_DEBUG(4, "stripecnt=%d\n", stripecnt);
- if (stripecnt < 1 || stripecnt > 4096) {
+ if (stripecnt >= MHLEN / NFSX_UNSIGNED ||
+ stripecnt < 1) {
printf("pNFS File layout devinfo stripecnt %d:"
" out of range\n", stripecnt);
error = NFSERR_BADXDR;
@@ -7246,7 +7261,7 @@ nfsrpc_writeds(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF);
rlen = fxdr_unsigned(int, *tl++);
NFSCL_DEBUG(4, "nfsrpc_writeds: len=%d rlen=%d\n", len, rlen);
- if (rlen == 0) {
+ if (rlen <= 0 || rlen > len) {
error = NFSERR_IO;
goto nfsmout;
} else if (rlen < len) {
@@ -8243,7 +8258,7 @@ nfsrv_parseug(struct nfsrv_descript *nd, int dogrp, uid_t *uidp, gid_t *gidp,
NFSPROC_T *p)
{
uint32_t *tl;
- char *cp, *str, str0[NFSV4_SMALLSTR + 1];
+ char *str, str0[NFSV4_SMALLSTR + 1];
uint32_t len = 0;
int error = 0;
@@ -8266,9 +8281,9 @@ nfsrv_parseug(struct nfsrv_descript *nd, int dogrp, uid_t *uidp, gid_t *gidp,
str = malloc(len + 1, M_TEMP, M_WAITOK);
else
str = str0;
- NFSM_DISSECT(cp, char *, NFSM_RNDUP(len));
- NFSBCOPY(cp, str, len);
- str[len] = '\0';
+ error = nfsrv_mtostr(nd, str, len);
+ if (error != 0)
+ goto nfsmout;
NFSCL_DEBUG(4, "nfsrv_parseug: str=%s\n", str);
if (dogrp != 0)
error = nfsv4_strtogid(nd, str, len, gidp);
@@ -9745,7 +9760,7 @@ nfsm_split(struct mbuf *mp, uint64_t xfer)
pgno++;
} while (pgno < m->m_epg_npgs);
if (pgno == m->m_epg_npgs)
- panic("nfsm_split: eroneous ext_pgs mbuf");
+ panic("nfsm_split: erroneous ext_pgs mbuf");
m2 = mb_alloc_ext_pgs(M_WAITOK, mb_free_mext_pgs, 0);
m2->m_epg_flags |= EPG_FLAG_ANON;
diff --git a/sys/fs/nfsclient/nfs_clvfsops.c b/sys/fs/nfsclient/nfs_clvfsops.c
index 5ea7eab07632..212c88f28930 100644
--- a/sys/fs/nfsclient/nfs_clvfsops.c
+++ b/sys/fs/nfsclient/nfs_clvfsops.c
@@ -927,7 +927,7 @@ nfs_mount(struct mount *mp)
struct vnode *vp;
struct thread *td;
char *hst;
- u_char nfh[NFSX_FHMAX], krbname[100], dirpath[100], srvkrbname[100];
+ u_char nfh[NFSX_FHMAX], krbname[100], *dirpath, srvkrbname[100];
char *cp, *opt, *name, *secname, *tlscertname;
int nametimeo = NFS_DEFAULT_NAMETIMEO;
int negnametimeo = NFS_DEFAULT_NEGNAMETIMEO;
@@ -943,6 +943,7 @@ nfs_mount(struct mount *mp)
newflag = 0;
tlscertname = NULL;
hst = malloc(MNAMELEN, M_TEMP, M_WAITOK);
+ dirpath = malloc(MNAMELEN, M_TEMP, M_WAITOK);
if (vfs_filteropt(mp->mnt_optnew, nfs_opts)) {
error = EINVAL;
goto out;
@@ -1329,7 +1330,7 @@ nfs_mount(struct mount *mp)
goto out;
} else if (nfs_mount_parse_from(mp->mnt_optnew,
&args.hostname, (struct sockaddr_in **)&nam, dirpath,
- sizeof(dirpath), &dirlen) == 0) {
+ MNAMELEN, &dirlen) == 0) {
has_nfs_from_opt = 1;
bcopy(args.hostname, hst, MNAMELEN);
hst[MNAMELEN - 1] = '\0';
@@ -1387,7 +1388,7 @@ nfs_mount(struct mount *mp)
if (has_nfs_from_opt == 0) {
if (vfs_getopt(mp->mnt_optnew,
"dirpath", (void **)&name, NULL) == 0)
- strlcpy(dirpath, name, sizeof (dirpath));
+ strlcpy(dirpath, name, MNAMELEN);
else
dirpath[0] = '\0';
dirlen = strlen(dirpath);
@@ -1472,6 +1473,7 @@ out:
MNT_IUNLOCK(mp);
}
free(hst, M_TEMP);
+ free(dirpath, M_TEMP);
return (error);
}
diff --git a/sys/fs/nfsclient/nfs_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c
index e9ae91e046e7..f80cf30669ca 100644
--- a/sys/fs/nfsclient/nfs_clvnops.c
+++ b/sys/fs/nfsclient/nfs_clvnops.c
@@ -1081,12 +1081,14 @@ nfs_setattr(struct vop_setattr_args *ap)
#endif
/*
- * Only setting of UF_HIDDEN and UF_SYSTEM are supported and
+ * Only setting of UF_ARCHIVE, UF_HIDDEN and UF_SYSTEM are supported and
* only for NFSv4 servers that support them.
*/
nmp = VFSTONFS(vp->v_mount);
if (vap->va_flags != VNOVAL && (!NFSHASNFSV4(nmp) ||
- (vap->va_flags & ~(UF_HIDDEN | UF_SYSTEM)) != 0 ||
+ (vap->va_flags & ~(UF_ARCHIVE | UF_HIDDEN | UF_SYSTEM)) != 0 ||
+ ((vap->va_flags & UF_ARCHIVE) != 0 &&
+ !NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr, NFSATTRBIT_ARCHIVE)) ||
((vap->va_flags & UF_HIDDEN) != 0 &&
!NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr, NFSATTRBIT_HIDDEN)) ||
((vap->va_flags & UF_SYSTEM) != 0 &&
@@ -4835,6 +4837,8 @@ nfs_pathconf(struct vop_pathconf_args *ap)
break;
case _PC_HAS_HIDDENSYSTEM:
if (NFS_ISV4(vp) && NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr,
+ NFSATTRBIT_ARCHIVE) &&
+ NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr,
NFSATTRBIT_HIDDEN) &&
NFSISSET_ATTRBIT(&np->n_vattr.na_suppattr,
NFSATTRBIT_SYSTEM))
diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c
index eb6ba285f8fe..9fe3f4426124 100644
--- a/sys/fs/nfsserver/nfs_nfsdport.c
+++ b/sys/fs/nfsserver/nfs_nfsdport.c
@@ -3193,7 +3193,8 @@ nfsv4_sattr(struct nfsrv_descript *nd, vnode_t vp, struct nfsvattr *nvap,
bitpos = NFSATTRBIT_MAX;
} else {
bitpos = 0;
- if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_HIDDEN) ||
+ if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_ARCHIVE) ||
+ NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_HIDDEN) ||
NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_SYSTEM))
nvap->na_flags = 0;
}
@@ -3226,9 +3227,11 @@ nfsv4_sattr(struct nfsrv_descript *nd, vnode_t vp, struct nfsvattr *nvap,
attrsum += aclsize;
break;
case NFSATTRBIT_ARCHIVE:
- NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
- if (!nd->nd_repstat)
- nd->nd_repstat = NFSERR_ATTRNOTSUPP;
+ NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
+ if (nd->nd_repstat == 0) {
+ if (*tl == newnfs_true)
+ nvap->na_flags |= UF_ARCHIVE;
+ }
attrsum += NFSX_UNSIGNED;
break;
case NFSATTRBIT_HIDDEN:
diff --git a/sys/fs/nfsserver/nfs_nfsdserv.c b/sys/fs/nfsserver/nfs_nfsdserv.c
index 921ea4887af1..67af0cf71175 100644
--- a/sys/fs/nfsserver/nfs_nfsdserv.c
+++ b/sys/fs/nfsserver/nfs_nfsdserv.c
@@ -436,6 +436,7 @@ nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
/* For NFSv4, only va_uid and va_flags is used from nva2. */
NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
+ NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ARCHIVE);
NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_HIDDEN);
NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SYSTEM);
preat_ret = nfsvno_getattr(vp, &nva2, nd, p, 1, &retbits);
@@ -569,8 +570,15 @@ nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
}
}
if (!nd->nd_repstat &&
- (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN) ||
+ (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ARCHIVE) ||
+ NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN) ||
NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM))) {
+ if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ARCHIVE)) {
+ if ((nva.na_flags & UF_ARCHIVE) != 0)
+ oldflags |= UF_ARCHIVE;
+ else
+ oldflags &= ~UF_ARCHIVE;
+ }
if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN)) {
if ((nva.na_flags & UF_HIDDEN) != 0)
oldflags |= UF_HIDDEN;
@@ -588,6 +596,8 @@ nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
exp);
if (!nd->nd_repstat) {
+ if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ARCHIVE))
+ NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ARCHIVE);
if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN))
NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_HIDDEN);
if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM))
@@ -5128,6 +5138,11 @@ nfsrvd_layoutcommit(struct nfsrv_descript *nd, __unused int isdgram,
NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
layouttype = fxdr_unsigned(int, *tl++);
maxcnt = fxdr_unsigned(int, *tl);
+ /* There is no limit in the RFC, so use 1000 as a sanity limit. */
+ if (maxcnt < 0 || maxcnt > 1000) {
+ error = NFSERR_BADXDR;
+ goto nfsmout;
+ }
if (maxcnt > 0) {
layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
error = nfsrv_mtostr(nd, layp, maxcnt);