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@xxxxxx> --- 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 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 -- 2.4.1.168.g1ea28e1 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html