Page MenuHomeFreeBSD

D38052.id115127.diff
No OneTemporary

D38052.id115127.diff

diff --git a/sys/fs/tmpfs/tmpfs.h b/fs/tmpfs/tmpfs.h
--- a/sys/fs/tmpfs/tmpfs.h
+++ b/fs/tmpfs/tmpfs.h
@@ -132,6 +132,20 @@
#define TMPFS_DIRCOOKIE_DUP_MAX \
(TMPFS_DIRCOOKIE_DUP | TMPFS_DIRCOOKIE_MASK)
+/*
+ * Internal representation of a tmpfs extended attribute entry.
+ */
+LIST_HEAD(tmpfs_extattr_list, tmpfs_extattr);
+
+struct tmpfs_extattr {
+ LIST_ENTRY(tmpfs_extattr) ea_extattrs;
+ int ea_namespace; /* attr namespace */
+ char * ea_name; /* attr name */
+ unsigned char ea_namelen; /* attr name length */
+ char * ea_value; /* attr value buffer */
+ ssize_t ea_size; /* attr value size */
+};
+
/*
* Internal representation of a tmpfs file system node.
*
@@ -239,6 +253,9 @@
/* Transient refcounter on this node. */
u_int tn_refcount; /* 0<->1 (m) + (i) */
+ /* Extended attributes of this node. */
+ struct tmpfs_extattr_list tn_extattrs; /* (v) */
+
/* misc data field for different tn_type node */
union {
/* Valid when tn_type == VBLK || tn_type == VCHR. */
@@ -384,6 +401,9 @@
/* Number of nodes currently that are in use. */
ino_t tm_nodes_inuse;
+ /* Memory used by extended attributes */
+ u_long tm_ea_memory_inuse;
+
/* Refcounter on this struct tmpfs_mount. */
uint64_t tm_refcount;
@@ -480,6 +500,8 @@
struct tmpfs_dir_cursor *dc);
struct tmpfs_dirent *tmpfs_dir_next(struct tmpfs_node *dnode,
struct tmpfs_dir_cursor *dc);
+bool tmpfs_pages_check_avail(struct tmpfs_mount *tmp, size_t req_pages);
+void tmpfs_extattr_free(struct tmpfs_extattr* ea);
static __inline void
tmpfs_update(struct vnode *vp)
{
@@ -518,6 +540,13 @@
#define TMPFS_PAGES_MINRESERVED (4 * 1024 * 1024 / PAGE_SIZE)
#endif
+/*
+ * Amount of memory to reserve for extended attributes.
+ */
+#if !defined(TMPFS_EA_MEMORY_RESERVED)
+#define TMPFS_EA_MEMORY_RESERVED (16 * 1024 * 1024)
+#endif
+
size_t tmpfs_mem_avail(void);
size_t tmpfs_pages_used(struct tmpfs_mount *tmp);
int tmpfs_subr_init(void);
diff --git a/sys/fs/tmpfs/tmpfs_subr.c b/fs/tmpfs/tmpfs_subr.c
--- a/sys/fs/tmpfs/tmpfs_subr.c
+++ b/fs/tmpfs/tmpfs_subr.c
@@ -434,7 +434,7 @@
return (meta_pages + tmp->tm_pages_used);
}
-static bool
+bool
tmpfs_pages_check_avail(struct tmpfs_mount *tmp, size_t req_pages)
{
if (tmpfs_mem_avail() < req_pages)
@@ -587,6 +587,7 @@
nnode->tn_mode = mode;
nnode->tn_id = alloc_unr64(&tmp->tm_ino_unr);
nnode->tn_refcount = 1;
+ LIST_INIT(&nnode->tn_extattrs);
/* Type-specific initialization. */
switch (nnode->tn_type) {
@@ -702,6 +703,7 @@
tmpfs_free_node_locked(struct tmpfs_mount *tmp, struct tmpfs_node *node,
bool detach)
{
+ struct tmpfs_extattr *ea;
vm_object_t uobj;
char *symlink;
bool last;
@@ -748,6 +750,11 @@
}
#endif
+ while ((ea = LIST_FIRST(&node->tn_extattrs)) != NULL) {
+ LIST_REMOVE(ea, ea_extattrs);
+ tmpfs_extattr_free(ea);
+ }
+
switch (node->tn_type) {
case VREG:
uobj = node->tn_reg.tn_aobj;
diff --git a/sys/fs/tmpfs/tmpfs_vfsops.c b/fs/tmpfs/tmpfs_vfsops.c
--- a/sys/fs/tmpfs/tmpfs_vfsops.c
+++ b/fs/tmpfs/tmpfs_vfsops.c
@@ -443,6 +443,7 @@
mtx_init(&tmp->tm_allnode_lock, "tmpfs allnode lock", NULL, MTX_DEF);
tmp->tm_nodes_max = nodes_max;
tmp->tm_nodes_inuse = 0;
+ tmp->tm_ea_memory_inuse = 0;
tmp->tm_refcount = 1;
tmp->tm_maxfilesize = maxfilesize > 0 ? maxfilesize : OFF_MAX;
LIST_INIT(&tmp->tm_nodes_used);
@@ -712,11 +713,12 @@
mp->mnt_stat.f_mntonname, tmp);
db_printf(
"\tsize max %ju pages max %lu pages used %lu\n"
- "\tinodes max %ju inodes inuse %ju refcount %ju\n"
+ "\tinodes max %ju inodes inuse %ju ea inuse %ju refcount %ju\n"
"\tmaxfilesize %ju r%c %snamecache %smtime\n",
(uintmax_t)tmp->tm_size_max, tmp->tm_pages_max, tmp->tm_pages_used,
(uintmax_t)tmp->tm_nodes_max, (uintmax_t)tmp->tm_nodes_inuse,
- (uintmax_t)tmp->tm_refcount, (uintmax_t)tmp->tm_maxfilesize,
+ (uintmax_t)tmp->tm_ea_memory_inuse, (uintmax_t)tmp->tm_refcount,
+ (uintmax_t)tmp->tm_maxfilesize,
tmp->tm_ronly ? 'o' : 'w', tmp->tm_nonc ? "no" : "",
tmp->tm_nomtime ? "no" : "");
}
diff --git a/sys/fs/tmpfs/tmpfs_vnops.c b/fs/tmpfs/tmpfs_vnops.c
--- a/sys/fs/tmpfs/tmpfs_vnops.c
+++ b/fs/tmpfs/tmpfs_vnops.c
@@ -41,6 +41,7 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/dirent.h>
+#include <sys/extattr.h>
#include <sys/fcntl.h>
#include <sys/file.h>
#include <sys/filio.h>
@@ -79,6 +80,10 @@
__DEVOLATILE(int *, &tmpfs_rename_restarts), 0,
"Times rename had to restart due to lock contention");
+static long tmpfs_ea_mem_reserved = TMPFS_EA_MEMORY_RESERVED;
+
+MALLOC_DEFINE(M_TMPFSEA, "tmpfs extattr", "tmpfs extattr structure");
+
static int
tmpfs_vn_get_ino_alloc(struct mount *mp, void *arg, int lkflags,
struct vnode **rvp)
@@ -1843,6 +1848,307 @@
return (ENOENT);
}
+void
+tmpfs_extattr_free(struct tmpfs_extattr *ea)
+{
+
+ free(ea->ea_name, M_TMPFSEA);
+ free(ea->ea_value, M_TMPFSEA);
+ free(ea, M_TMPFSEA);
+}
+
+static int
+tmpfs_extattr_valid_attrname(int attrnamespace, const char *attrname)
+{
+
+ if (attrname == NULL)
+ return (0);
+ if (strlen(attrname) == 0)
+ return (0);
+ if (strlen(attrname) > EXTATTR_MAXNAMELEN)
+ return (0);
+ return (1);
+}
+
+static int
+sysctl_ea_mem_reserved(SYSCTL_HANDLER_ARGS)
+{
+ long bytes;
+ int error;
+
+ bytes = *(long *)arg1;
+
+ error = sysctl_handle_long(oidp, &bytes, 0, req);
+ if (error || !req->newptr)
+ return (error);
+
+ if (bytes < 0)
+ return (EINVAL);
+
+ *(long *)arg1 = bytes;
+ return (0);
+}
+
+SYSCTL_PROC(_vfs_tmpfs, OID_AUTO, ea_memory_reserved,
+ CTLTYPE_LONG|CTLFLAG_MPSAFE|CTLFLAG_RW, &tmpfs_ea_mem_reserved, 0,
+ sysctl_ea_mem_reserved, "L",
+ "Extended attributes memory reserved per mount point");
+
+static int
+tmpfs_extattr_update_mem(struct tmpfs_mount *tmp, ssize_t size)
+{
+ int error = 0;
+
+ TMPFS_LOCK(tmp);
+
+ if (size > 0 &&
+ !tmpfs_pages_check_avail(tmp, howmany(size, PAGE_SIZE))) {
+ error = ENOSPC;
+ goto out;
+ }
+
+ if (tmp->tm_ea_memory_inuse + size >
+ atomic_load_long(&tmpfs_ea_mem_reserved))
+ error = ENOSPC;
+ else
+ tmp->tm_ea_memory_inuse += size;
+
+out:
+ TMPFS_UNLOCK(tmp);
+
+ return (error);
+}
+
+static int
+tmpfs_deleteextattr(struct vop_deleteextattr_args *ap)
+{
+ struct vnode *vp = ap->a_vp;
+ struct tmpfs_mount *tmp;
+ struct tmpfs_node *node;
+ struct tmpfs_extattr *ea;
+ unsigned char namelen;
+ ssize_t diff;
+ int error;
+
+ MPASS(VOP_ISLOCKED(vp));
+
+ node = VP_TO_TMPFS_NODE(vp);
+ tmp = VFS_TO_TMPFS(vp->v_mount);
+
+ if (atomic_load_long(&tmpfs_ea_mem_reserved) == 0)
+ return (EOPNOTSUPP);
+
+ if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK)
+ return (EOPNOTSUPP);
+
+ if (!tmpfs_extattr_valid_attrname(ap->a_attrnamespace, ap->a_name))
+ return (EINVAL);
+
+ error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
+ ap->a_cred, ap->a_td, VWRITE);
+ if (error)
+ return (error);
+
+ namelen = strnlen(ap->a_name, EXTATTR_MAXNAMELEN);
+
+ LIST_FOREACH(ea, &node->tn_extattrs, ea_extattrs) {
+ if (ea->ea_namespace == ap->a_attrnamespace &&
+ namelen == ea->ea_namelen &&
+ memcmp(ap->a_name, ea->ea_name, namelen) == 0)
+ break;
+ }
+
+ if (ea != NULL) {
+ LIST_REMOVE(ea, ea_extattrs);
+ diff = -(sizeof(struct tmpfs_extattr) + namelen + ea->ea_size);
+ tmpfs_extattr_update_mem(tmp, diff);
+ tmpfs_extattr_free(ea);
+ return (0);
+ }
+
+ return (ENOATTR);
+}
+
+static int
+tmpfs_getextattr(struct vop_getextattr_args *ap)
+{
+ struct vnode *vp = ap->a_vp;
+ struct tmpfs_node *node;
+ struct tmpfs_extattr *ea;
+ unsigned char namelen;
+ int error;
+
+ MPASS(VOP_ISLOCKED(vp));
+
+ node = VP_TO_TMPFS_NODE(vp);
+
+ if (atomic_load_long(&tmpfs_ea_mem_reserved) == 0)
+ return (EOPNOTSUPP);
+
+ if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK)
+ return (EOPNOTSUPP);
+
+ if (!tmpfs_extattr_valid_attrname(ap->a_attrnamespace, ap->a_name))
+ return (EINVAL);
+
+ error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
+ ap->a_cred, ap->a_td, VREAD);
+ if (error)
+ return (error);
+
+ if (ap->a_size != NULL)
+ *ap->a_size = 0;
+
+ namelen = strnlen(ap->a_name, EXTATTR_MAXNAMELEN);
+
+ LIST_FOREACH(ea, &node->tn_extattrs, ea_extattrs) {
+ if (ea->ea_namespace == ap->a_attrnamespace &&
+ namelen == ea->ea_namelen &&
+ memcmp(ap->a_name, ea->ea_name, namelen) == 0)
+ break;
+ }
+
+ if (ea != NULL) {
+ if (ap->a_size != NULL)
+ *ap->a_size = ea->ea_size;
+
+ if (ap->a_uio != NULL && ea->ea_size != 0)
+ error = uiomove(ea->ea_value, ea->ea_size, ap->a_uio);
+
+ return (error);
+ }
+
+ return (ENOATTR);
+}
+
+static int
+tmpfs_listextattr(struct vop_listextattr_args *ap)
+{
+ struct vnode *vp = ap->a_vp;
+ struct tmpfs_node *node;
+ struct tmpfs_extattr *ea;
+ int error;
+
+ MPASS(VOP_ISLOCKED(vp));
+
+ node = VP_TO_TMPFS_NODE(vp);
+
+ if (atomic_load_long(&tmpfs_ea_mem_reserved) == 0)
+ return (EOPNOTSUPP);
+
+ if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK)
+ return (EOPNOTSUPP);
+
+ error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
+ ap->a_cred, ap->a_td, VREAD);
+ if (error)
+ return (error);
+
+ if (ap->a_size != NULL)
+ *ap->a_size = 0;
+
+ LIST_FOREACH(ea, &node->tn_extattrs, ea_extattrs) {
+ if (ea->ea_namespace != ap->a_attrnamespace)
+ continue;
+
+ if (ap->a_size != NULL)
+ *ap->a_size += ea->ea_namelen + 1;
+
+ if (ap->a_uio != NULL) {
+ error = uiomove(&ea->ea_namelen, 1, ap->a_uio);
+ if (error)
+ break;
+
+ error = uiomove(ea->ea_name, ea->ea_namelen, ap->a_uio);
+ if (error)
+ break;
+ }
+ }
+
+ return (error);
+}
+
+static int
+tmpfs_setextattr(struct vop_setextattr_args *ap)
+{
+ struct vnode *vp = ap->a_vp;
+ struct tmpfs_mount *tmp;
+ struct tmpfs_node *node;
+ struct tmpfs_extattr *ea;
+ struct tmpfs_extattr *new_ea;
+ unsigned char namelen;
+ size_t attr_size;
+ ssize_t diff;
+ int error;
+
+ MPASS(VOP_ISLOCKED(vp));
+
+ node = VP_TO_TMPFS_NODE(vp);
+ tmp = VFS_TO_TMPFS(vp->v_mount);
+ diff = 0;
+
+ if (atomic_load_long(&tmpfs_ea_mem_reserved) == 0)
+ return (EOPNOTSUPP);
+
+ if (ap->a_vp->v_type == VCHR || ap->a_vp->v_type == VBLK)
+ return (EOPNOTSUPP);
+
+ if (!tmpfs_extattr_valid_attrname(ap->a_attrnamespace, ap->a_name))
+ return (EINVAL);
+
+ error = extattr_check_cred(ap->a_vp, ap->a_attrnamespace,
+ ap->a_cred, ap->a_td, VWRITE);
+ if (error)
+ return (error);
+
+ namelen = strnlen(ap->a_name, EXTATTR_MAXNAMELEN);
+ attr_size = ap->a_uio->uio_resid;
+
+ LIST_FOREACH(ea, &node->tn_extattrs, ea_extattrs) {
+ if (ea->ea_namespace == ap->a_attrnamespace &&
+ namelen == ea->ea_namelen &&
+ memcmp(ap->a_name, ea->ea_name, namelen) == 0) {
+ diff -= sizeof(struct tmpfs_extattr) + ea->ea_namelen +
+ ea->ea_size;
+ break;
+ }
+ }
+
+ diff += sizeof(struct tmpfs_extattr) + namelen + attr_size;
+ error = tmpfs_extattr_update_mem(tmp, diff);
+ if (error)
+ return (error);
+
+ new_ea = malloc(sizeof(struct tmpfs_extattr), M_TMPFSEA, M_WAITOK);
+ new_ea->ea_namespace = ap->a_attrnamespace;
+ new_ea->ea_name = malloc(namelen, M_TMPFSEA, M_WAITOK);
+ new_ea->ea_namelen = namelen;
+ memcpy(new_ea->ea_name, ap->a_name, namelen);
+
+ if (attr_size != 0) {
+ new_ea->ea_value = malloc(attr_size, M_TMPFSEA, M_WAITOK);
+ new_ea->ea_size = attr_size;
+ error = uiomove(new_ea->ea_value, attr_size, ap->a_uio);
+ } else {
+ new_ea->ea_value = NULL;
+ new_ea->ea_size = 0;
+ }
+
+ if (error) {
+ tmpfs_extattr_update_mem(tmp, -diff);
+ tmpfs_extattr_free(new_ea);
+ } else {
+ if (ea != NULL) {
+ LIST_REMOVE(ea, ea_extattrs);
+ tmpfs_extattr_free(ea);
+ }
+
+ LIST_INSERT_HEAD(&node->tn_extattrs, new_ea, ea_extattrs);
+ }
+
+ return (error);
+}
+
static off_t
tmpfs_seek_data_locked(vm_object_t obj, off_t noff)
{
@@ -2010,6 +2316,10 @@
.vop_lock1 = vop_lock,
.vop_unlock = vop_unlock,
.vop_islocked = vop_islocked,
+ .vop_deleteextattr = tmpfs_deleteextattr,
+ .vop_getextattr = tmpfs_getextattr,
+ .vop_listextattr = tmpfs_listextattr,
+ .vop_setextattr = tmpfs_setextattr,
.vop_add_writecount = vop_stdadd_writecount_nomsync,
.vop_ioctl = tmpfs_ioctl,
};

File Metadata

Mime Type
text/plain
Expires
Sat, May 16, 8:47 PM (5 h, 4 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33152103
Default Alt Text
D38052.id115127.diff (11 KB)

Event Timeline