Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F145044491
D38052.1777266140.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
12 KB
Referenced Files
None
Subscribers
None
D38052.1777266140.diff
View Options
diff --git a/share/man/man5/tmpfs.5 b/share/man/man5/tmpfs.5
--- a/share/man/man5/tmpfs.5
+++ b/share/man/man5/tmpfs.5
@@ -140,6 +140,9 @@
.It Cm maxfilesize
Specifies the maximum file size in bytes.
Defaults to the maximum possible value.
+.It Cm easize
+Specifies the maximum memory size used by extended attributes in bytes.
+Defaults to 16 megabytes.
.El
.Sh EXAMPLES
Mount a
diff --git a/sys/fs/tmpfs/tmpfs.h b/sys/fs/tmpfs/tmpfs.h
--- a/sys/fs/tmpfs/tmpfs.h
+++ b/sys/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,12 @@
/* Number of nodes currently that are in use. */
ino_t tm_nodes_inuse;
+ /* Memory used by extended attributes */
+ uint64_t tm_ea_memory_inuse;
+
+ /* Maximum memory available for extended attributes */
+ uint64_t tm_ea_memory_max;
+
/* Refcounter on this struct tmpfs_mount. */
uint64_t tm_refcount;
@@ -480,6 +503,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 +543,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/sys/fs/tmpfs/tmpfs_subr.c
--- a/sys/fs/tmpfs/tmpfs_subr.c
+++ b/sys/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/sys/fs/tmpfs/tmpfs_vfsops.c
--- a/sys/fs/tmpfs/tmpfs_vfsops.c
+++ b/sys/fs/tmpfs/tmpfs_vfsops.c
@@ -92,12 +92,12 @@
static int tmpfs_statfs(struct mount *, struct statfs *);
static const char *tmpfs_opts[] = {
- "from", "size", "maxfilesize", "inodes", "uid", "gid", "mode", "export",
- "union", "nonc", "nomtime", NULL
+ "from", "easize", "size", "maxfilesize", "inodes", "uid", "gid", "mode",
+ "export", "union", "nonc", "nomtime", NULL
};
static const char *tmpfs_updateopts[] = {
- "from", "export", "nomtime", "size", NULL
+ "from", "easize", "export", "nomtime", "size", NULL
};
static int
@@ -332,7 +332,7 @@
bool nomtime, nonc;
/* Size counters. */
u_quad_t pages;
- off_t nodes_max, size_max, maxfilesize;
+ off_t nodes_max, size_max, maxfilesize, ea_max_size;
/* Root node attributes. */
uid_t root_uid;
@@ -360,6 +360,9 @@
if (size_max != tmp->tm_size_max)
return (EOPNOTSUPP);
}
+ if (vfs_getopt_size(mp->mnt_optnew, "easize", &ea_max_size) == 0) {
+ tmp->tm_ea_memory_max = ea_max_size;
+ }
if (vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0) &&
!tmp->tm_ronly) {
/* RW -> RO */
@@ -405,6 +408,8 @@
size_max = 0;
if (vfs_getopt_size(mp->mnt_optnew, "maxfilesize", &maxfilesize) != 0)
maxfilesize = 0;
+ if (vfs_getopt_size(mp->mnt_optnew, "easize", &ea_max_size) != 0)
+ ea_max_size = 0;
nonc = vfs_getopt(mp->mnt_optnew, "nonc", NULL, NULL) == 0;
nomtime = vfs_getopt(mp->mnt_optnew, "nomtime", NULL, NULL) == 0;
@@ -443,8 +448,11 @@
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;
+ tmp->tm_ea_memory_max = ea_max_size > 0 ?
+ ea_max_size : TMPFS_EA_MEMORY_RESERVED;
LIST_INIT(&tmp->tm_nodes_used);
tmp->tm_size_max = size_max;
@@ -708,11 +716,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/sys/fs/tmpfs/tmpfs_vnops.c
--- a/sys/fs/tmpfs/tmpfs_vnops.c
+++ b/sys/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,8 @@
__DEVOLATILE(int *, &tmpfs_rename_restarts), 0,
"Times rename had to restart due to lock contention");
+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)
@@ -1855,6 +1858,215 @@
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 bool
+tmpfs_extattr_update_mem(struct tmpfs_mount *tmp, ssize_t size)
+{
+ TMPFS_LOCK(tmp);
+ if (size > 0 &&
+ !tmpfs_pages_check_avail(tmp, howmany(size, PAGE_SIZE))) {
+ TMPFS_UNLOCK(tmp);
+ return (false);
+ }
+ if (tmp->tm_ea_memory_inuse + size > tmp->tm_ea_memory_max) {
+ TMPFS_UNLOCK(tmp);
+ return (false);
+ }
+ tmp->tm_ea_memory_inuse += size;
+ TMPFS_UNLOCK(tmp);
+ return (true);
+}
+
+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;
+ size_t namelen;
+ ssize_t diff;
+ int error;
+
+ node = VP_TO_TMPFS_NODE(vp);
+ tmp = VFS_TO_TMPFS(vp->v_mount);
+ 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, VWRITE);
+ if (error != 0)
+ return (error);
+ if (ap->a_name == NULL || ap->a_name[0] == '\0')
+ return (EINVAL);
+ namelen = strlen(ap->a_name);
+ if (namelen > EXTATTR_MAXNAMELEN)
+ return (EINVAL);
+
+ 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)
+ return (ENOATTR);
+ 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);
+}
+
+static int
+tmpfs_getextattr(struct vop_getextattr_args *ap)
+{
+ struct vnode *vp = ap->a_vp;
+ struct tmpfs_node *node;
+ struct tmpfs_extattr *ea;
+ size_t namelen;
+ int error;
+
+ node = VP_TO_TMPFS_NODE(vp);
+ 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 != 0)
+ return (error);
+ if (ap->a_name == NULL || ap->a_name[0] == '\0')
+ return (EINVAL);
+ namelen = strlen(ap->a_name);
+ if (namelen > EXTATTR_MAXNAMELEN)
+ return (EINVAL);
+
+ 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)
+ return (ENOATTR);
+ 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);
+}
+
+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;
+
+ node = VP_TO_TMPFS_NODE(vp);
+ 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 != 0)
+ 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 != 0)
+ break;
+ error = uiomove(ea->ea_name, ea->ea_namelen, ap->a_uio);
+ if (error != 0)
+ 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;
+ size_t attr_size;
+ size_t namelen;
+ ssize_t diff;
+ int error;
+
+ node = VP_TO_TMPFS_NODE(vp);
+ tmp = VFS_TO_TMPFS(vp->v_mount);
+ attr_size = ap->a_uio->uio_resid;
+ diff = 0;
+ 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, VWRITE);
+ if (error != 0)
+ return (error);
+ if (ap->a_name == NULL || ap->a_name[0] == '\0')
+ return (EINVAL);
+ namelen = strlen(ap->a_name);
+ if (namelen > EXTATTR_MAXNAMELEN)
+ return (EINVAL);
+
+ 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;
+ if (!tmpfs_extattr_update_mem(tmp, diff))
+ return (ENOSPC);
+ 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 != 0) {
+ tmpfs_extattr_update_mem(tmp, -diff);
+ tmpfs_extattr_free(new_ea);
+ return (error);
+ }
+ if (ea != NULL) {
+ LIST_REMOVE(ea, ea_extattrs);
+ tmpfs_extattr_free(ea);
+ }
+ LIST_INSERT_HEAD(&node->tn_extattrs, new_ea, ea_extattrs);
+ return (0);
+}
+
static off_t
tmpfs_seek_data_locked(vm_object_t obj, off_t noff)
{
@@ -2022,6 +2234,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
Details
Attached
Mime Type
text/plain
Expires
Mon, Apr 27, 5:02 AM (12 h, 56 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28436489
Default Alt Text
D38052.1777266140.diff (12 KB)
Attached To
Mode
D38052: [tmpfs]: Add extended attributes
Attached
Detach File
Event Timeline
Log In to Comment