@@ -18,6 +18,7 @@
#include <linux/compat.h>
#include <linux/mount.h>
#include <linux/fs.h>
+#include <linux/streamid.h>
#include "internal.h"
#include <asm/uaccess.h>
@@ -1668,3 +1669,65 @@ out:
return ret;
}
EXPORT_SYMBOL(vfs_dedupe_file_range);
+
+SYSCALL_DEFINE4(streamid, int, fd, int, cmd,
+ unsigned int, flags, int, streamid)
+{
+ struct inode *inode;
+ ssize_t ret = 0;
+ struct fd f;
+
+ if (cmd != STREAMID_OPEN && cmd != STREAMID_CLOSE &&
+ cmd != STREAMID_GET)
+ return -EINVAL;
+ if (flags & ~(STREAMID_F_INODE | STREAMID_F_FILE))
+ return -EINVAL;
+
+ f = fdget(fd);
+ if (!f.file)
+ return -EBADF;
+
+ inode = file_inode(f.file);
+ if (S_ISFIFO(inode->i_mode)) {
+ ret = -ESPIPE;
+ goto done;
+ }
+
+ if (cmd == STREAMID_OPEN) {
+ if (flags & STREAMID_F_FILE) {
+ if (f.file->f_streamid) {
+ ret = -EBUSY;
+ goto done;
+ }
+ f.file->f_streamid = ret;
+ }
+ if (flags & STREAMID_F_INODE) {
+ spin_lock(&inode->i_lock);
+ if (inode_streamid(inode))
+ ret = -EBUSY;
+ else
+ inode->i_streamid = ret;
+ spin_unlock(&inode->i_lock);
+ }
+ } else if (cmd == STREAMID_CLOSE) {
+ if (f.file->f_streamid == streamid)
+ f.file->f_streamid = 0;
+ if (inode_streamid(inode) == streamid) {
+ spin_lock(&inode->i_lock);
+ inode->i_streamid = 0;
+ spin_unlock(&inode->i_lock);
+ }
+ } else if (cmd == STREAMID_GET) {
+ ret = 0;
+ if (flags & STREAMID_F_FILE)
+ ret = f.file->f_streamid;
+ if (!ret && (flags & STREAMID_F_INODE))
+ ret = inode_streamid(inode);
+ if (!(flags & (STREAMID_F_FILE | STREAMID_F_INODE)))
+ ret = file_streamid(f.file);
+ }
+
+done:
+ fdput(f);
+ return ret;
+}
new file mode 100644
@@ -0,0 +1,13 @@
+#ifndef STREAMID_H
+#define STREAMID_H
+
+enum {
+ STREAMID_OPEN = 1, /* open new stream */
+ STREAMID_CLOSE = 2, /* close stream */
+ STREAMID_GET = 3, /* get file/inode stream ID */
+
+ STREAMID_F_INODE = 1, /* set streamid on the inode */
+ STREAMID_F_FILE = 2, /* set streamid on the file */
+};
+
+#endif
@@ -385,6 +385,7 @@ header-y += soundcard.h
header-y += sound.h
header-y += stat.h
header-y += stddef.h
+header-y += streamid.h
header-y += string.h
header-y += suspend_ioctls.h
header-y += swab.h
Single system call: ssize_t streamid(int fd, int cmd, unsigned int flags, int streamid); where 'fd' is a file descriptor to the file that we want to set the write stream ID on. 'cmd' is one of the following: STREAMID_OPEN Open/allocate a new stream ID STREAMID_CLOSE Close/free a previously allocated stream ID STREAMID_GET Return the currently assigned stream ID 'flags' is a mask of one or more of the following: STREAMID_F_INODE Set stream ID on the inode STREAMID_F_FILE Set stream ID on the file 'streamid' is either 0, which means that streamid() will return the first available stream ID, or it's set to some integer value between 1 and STREAMID_MAX (both inclusive) to ask for a specific stream ID value. streamid() returns the allocated stream ID on succes, or -1 and sets errno appropriately. Possible error values: -EINVAL cmd/flags isn't valid -ESPIPE 'fd' refers to a pipe -EBADF 'fd' isn't valid -EBUSY 'streamid' is already allocated/assigned Signed-off-by: Jens Axboe <axboe@fb.com> --- fs/read_write.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++ include/linux/streamid.h | 13 ++++++++++ include/uapi/linux/Kbuild | 1 + 3 files changed, 77 insertions(+) create mode 100644 include/linux/streamid.h