Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F156714689
D38052.id115127.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
11 KB
Referenced Files
None
Subscribers
None
D38052.id115127.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D38052: [tmpfs]: Add extended attributes
Attached
Detach File
Event Timeline
Log In to Comment