On 16-Jul 00:59, KP Singh wrote: > On 15-Jul 14:57, Martin KaFai Lau wrote: > > On Thu, Jul 09, 2020 at 12:12:37PM +0200, KP Singh wrote: > > > From: KP Singh <kpsingh@xxxxxxxxxx> > > > > > > Similar to bpf_local_storage for sockets, add local storage for inodes. > > > The life-cycle of storage is managed with the life-cycle of the inode. > > > i.e. the storage is destroyed along with the owning inode. > > > > > > The BPF LSM allocates an __rcu pointer to the bpf_local_storage in the > > > security blob which are now stackable and can co-exist with other LSMs. > > > > > > Signed-off-by: KP Singh <kpsingh@xxxxxxxxxx> > > > > [ ... ] > > > > > > > +static void *bpf_inode_storage_lookup_elem(struct bpf_map *map, void *key) > > > +{ > > > + struct bpf_local_storage_data *sdata; > > > + struct inode *inode; > > > + int err = -EINVAL; > > > + > > > + if (key) { > > > + inode = *(struct inode **)(key); > > The bpf_inode_storage_lookup_elem() here and the (update|delete)_elem() below > > are called from the userspace syscall. How the userspace may provide this key? > > I realized this when I replied about the _fd_ name in the sk helpers. > I am going to mark them as unsupported for now for inodes. > > We could, probably and separately, use a combination of the device > and inode number as a key from userspace. I actually implemented these as: static int bpf_fd_inode_storage_delete_elem(struct bpf_map *map, void *key) { struct file *f; int fd; fd = *(int *)key; f = fcheck(fd); if (!f) return -EINVAL; return inode_storage_delete(f->f_inode, map); } This keeps it similar to sk_storage and the userspace can just pass an fd. - KP > > - KP > > > > > > + sdata = inode_storage_lookup(inode, map, true); > > > + return sdata ? sdata->data : NULL; > > > + } > > > + > > > + return ERR_PTR(err); > > > +} > > > + > > > +static int bpf_inode_storage_update_elem(struct bpf_map *map, void *key, > > > + void *value, u64 map_flags) > > > +{ > > > + struct bpf_local_storage_data *sdata; > > > + struct inode *inode; > > > + int err = -EINVAL; > > > + > > > + if (key) { > > > + inode = *(struct inode **)(key); > > > + sdata = map->ops->map_local_storage_update(inode, map, value, > > > + map_flags); > > > + return PTR_ERR_OR_ZERO(sdata); > > > + } > > > + return err; > > > +} > > > + > > > +static int inode_storage_delete(struct inode *inode, struct bpf_map *map) > > > +{ > > > + struct bpf_local_storage_data *sdata; > > > + > > > + sdata = inode_storage_lookup(inode, map, false); > > > + if (!sdata) > > > + return -ENOENT; > > > + > > > + bpf_selem_unlink_map_elem(SELEM(sdata)); > > > + > > > + return 0; > > > +} > > > + > > > +static int bpf_inode_storage_delete_elem(struct bpf_map *map, void *key) > > > +{ > > > + struct inode *inode; > > > + int err = -EINVAL; > > > + > > > + if (key) { > > > + inode = *(struct inode **)(key); > > > + err = inode_storage_delete(inode, map); > > > + } > > > + > > > + return err; > > > +} > > > + > > > > [ ... ] > > > > > +static int inode_storage_map_btf_id; > > > +const struct bpf_map_ops inode_storage_map_ops = { > > > + .map_alloc_check = bpf_local_storage_map_alloc_check, > > > + .map_alloc = inode_storage_map_alloc, > > > + .map_free = inode_storage_map_free, > > > + .map_get_next_key = notsupp_get_next_key, > > > + .map_lookup_elem = bpf_inode_storage_lookup_elem, > > > + .map_update_elem = bpf_inode_storage_update_elem, > > > + .map_delete_elem = bpf_inode_storage_delete_elem, > > > + .map_check_btf = bpf_local_storage_map_check_btf, > > > + .map_btf_name = "bpf_local_storage_map", > > > + .map_btf_id = &inode_storage_map_btf_id, > > > + .map_local_storage_alloc = inode_storage_alloc, > > > + .map_selem_alloc = inode_selem_alloc, > > > + .map_local_storage_update = inode_storage_update, > > > + .map_local_storage_unlink = unlink_inode_storage, > > > +}; > > > +