#include <linux/fs.h>
+#include <linux/net.h>
#include <linux/stat.h>
#include <linux/sched.h>
#include <linux/dcache.h>
#include <linux/fdtable.h>
+#include <linux/file.h>
#include <linux/version.h>
+#include <linux/in.h>
+#include <linux/in6.h>
+#include <linux/net.h>
#include <writer/swap_msg.h>
#include <master/swap_deps.h>
#include <us_manager/sspt/sspt.h> /* ... check_vma() */
char path[0];
} __packed;
+struct osock {
+ u32 fd;
+ u32 ip;
+ u32 port;
+} __packed;
+
static int pack_ofile(void *data, size_t size, int fd, struct file *file,
loff_t fsize)
{
return sizeof(*ofile) + ret;
}
-static int pack_status_info(void *data, size_t size, struct task_struct *task)
+static int is_file_mode(umode_t mode)
{
- int ret, fd;
- u32 *file_cnt;
- struct files_struct *files;
- const size_t old_size = size;
+ return S_ISREG(mode);
+}
- files = swap_get_files_struct(task);
- if (files == NULL)
- return -EIO;
+static int pack_osock(void *data, size_t size, int fd, struct file *file,
+ loff_t fsize)
+{
+ struct osock *pack_sock;
+ struct socket *sock;
+ struct sockaddr_storage addr;
+ struct sockaddr *saddr = (struct sockaddr *)&addr;
+ struct sockaddr_in *sin = (struct sockaddr_in *)&addr;
+ int ret_size = sizeof(*pack_sock);
+ int addrlen;
+ int err;
+
+ if (size < sizeof(*pack_sock))
+ return -ENOMEM;
- /* pack pid */
- *((u32 *)data) = (u32)task->tgid;
- data += 4;
- size -= 4;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
+ sock = sockfd_lookup(fd, &err);
+#else
+ sock = sock_from_file(file, &err);
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0) */
+ if (!sock)
+ return 0;
+
+ kernel_getsockname(sock, saddr, &addrlen);
+
+ pack_sock = (struct osock *)data;
+ pack_sock->fd = (u32)fd;
+ pack_sock->ip = (u32)0x0;
+ pack_sock->port = 0;
+
+ switch (saddr->sa_family) {
+ case AF_INET:
+ pack_sock->ip = (u32)(sin->sin_addr.s_addr);
+ pack_sock->port = ntohs(sin->sin_port);
+ break;
+ default:
+ pr_info("[USM] ignored unknown address type: %u\n",
+ (unsigned int)saddr->sa_family);
+ ret_size = 0;
+ break;
+ }
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0)
+ sockfd_put(sock);
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3, 6, 0) */
+
+ return ret_size;
+}
+
+static int is_sock_mode(umode_t mode)
+{
+ return S_ISSOCK(mode);
+}
+
+typedef int (*pack_func_t)(void *data, size_t size, int fd, struct file *file,
+ loff_t fsize);
+typedef int (*check_mode_func_t)(umode_t mode);
+
+static int pack_descriptors(void *data, size_t size, pack_func_t pack_func,
+ check_mode_func_t check_mode,
+ struct files_struct *files)
+{
+ int ret, fd;
+ const size_t old_size = size;
+ u32 *desc_cnt;
- /* pack file count */
- file_cnt = (u32 *)data;
- *file_cnt = 0;
+ /* pack descriptor count */
+ desc_cnt = (u32 *)data;
+ *desc_cnt = 0;
data += 4;
size -= 4;
- /* pack file list */
+ /* pack descriptors list */
rcu_read_lock();
for (fd = 0; fd < files_fdtable(files)->max_fds; ++fd) {
struct file *file;
file = fcheck_files(files, fd);
if (file == NULL)
- continue;
+ continue;
inode = file->f_path.dentry->d_inode;
/* check inode and if it is a regular file */
- if (inode == NULL || !S_ISREG(inode->i_mode))
+ if (!inode || !check_mode(inode->i_mode))
continue;
fsize = inode->i_size;
rcu_read_unlock();
- ret = pack_ofile(data, size, fd, file, fsize);
- if (ret < 0)
- goto put_fstruct;
-
- data += ret;
- size -= ret;
- ++(*file_cnt);
+ ret = pack_func(data, size, fd, file, fsize);
+ if (ret < 0) {
+ goto exit;
+ } else if (ret > 0) {
+ /* increment if data packed only */
+ data += ret;
+ size -= ret;
+ ++(*desc_cnt);
+ }
rcu_read_lock();
}
+
rcu_read_unlock();
ret = old_size - size;
+exit:
+ return ret;
+}
+
+static int pack_status_info(void *data, size_t size, struct task_struct *task)
+{
+ int ret;
+ const size_t old_size = size;
+ struct files_struct *files;
+
+ files = swap_get_files_struct(task);
+ if (!files)
+ return -EIO;
+
+ /* pack pid */
+ *((u32 *)data) = (u32)task->tgid;
+ data += 4;
+ size -= 4;
+
+ /* pack file descriptors */
+ ret = pack_descriptors(data, size, pack_ofile, is_file_mode, files);
+ if (ret < 0)
+ goto put_fstruct;
+ data += ret;
+ size -= ret;
+
+ /* pack sock descriptors */
+ ret = pack_descriptors(data, size, pack_osock, is_sock_mode, files);
+ if (ret < 0)
+ goto put_fstruct;
+ data += ret;
+ size -= ret;
+
+ ret = old_size - size;
+
put_fstruct:
swap_put_files_struct(files);
return ret;