[04/11] Add system call for setting inode/file write stream ID
diff mbox

Message ID 1457107853-8689-5-git-send-email-axboe@fb.com
State New
Headers show

Commit Message

Jens Axboe March 4, 2016, 4:10 p.m. UTC
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

Patch
diff mbox

diff --git a/fs/read_write.c b/fs/read_write.c
index dadf24e5c95b..6dcae3eb7b0f 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -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;
+}
diff --git a/include/linux/streamid.h b/include/linux/streamid.h
new file mode 100644
index 000000000000..ea1f8e7eb8a5
--- /dev/null
+++ b/include/linux/streamid.h
@@ -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
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index ebd10e624598..7d1540da0bb1 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -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