-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathfile_operations.c
130 lines (98 loc) · 2.43 KB
/
file_operations.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include "file_operations.h"
#include "message_queue.h"
#include <linux/module.h>
#include <linux/sched.h>
static spinlock_t open_count_guard;
static int open_count __read_mostly = 0;
static int handle_open_file(struct inode* inode, struct file* file)
{
spin_lock_bh(&open_count_guard);
if (open_count == 0)
{
open_count = 1;
spin_unlock_bh(&open_count_guard);
printk(KERN_INFO "File open: /proc/net/%s\n", filename);
return 0;
}
spin_unlock_bh(&open_count_guard);
// File was already opened
#ifdef DEBUG
printk(KERN_DEBUG "Forcing flush of busy file: /proc/net/%s\n", filename);
#endif
mq_signal_waiting();
return -EBUSY;
}
static int handle_close_file(struct inode* inode, struct file* file)
{
spin_lock_bh(&open_count_guard);
printk(KERN_INFO "File close: /proc/net/%s\n", filename);
open_count = 0;
spin_unlock_bh(&open_count_guard);
return 0;
}
static ssize_t handle_read_file(struct file* file, char __user* buf, size_t len, loff_t* ppos)
{
ssize_t count;
struct msg msg;
int err;
if (buf == NULL)
{
return -EINVAL;
}
if (len < sizeof(struct msg))
{
printk(KERN_ERR "User-space buffer is too small\n");
return 0;
}
for (count = 0; count + sizeof(struct msg) <= len; count += sizeof(struct msg))
{
err = mq_dequeue(&msg);
if (err != 0)
{
// Force flush file
return err < 0 ? err : count;
}
if (copy_to_user(buf + count, &msg, sizeof(struct msg)))
{
printk(KERN_ERR "Failed to copy to user-space buffer\n");
return -EFAULT;
}
}
return count;
}
static const struct file_operations fo_file_operations =
{
.owner = THIS_MODULE,
.open = handle_open_file,
.release = handle_close_file,
.read = handle_read_file,
.llseek = noop_llseek,
};
int fo_init(void)
{
spin_lock_init(&open_count_guard);
if (!proc_create(filename, S_IRUSR, init_net.proc_net, &fo_file_operations))
{
printk(KERN_ERR "Failed to create file: /proc/net/%s\n", filename);
return -1;
}
printk(KERN_INFO "Created file: /proc/net/%s\n", filename);
return 0;
}
void fo_destroy(void)
{
// Ensure that nobody can reopen the file while we're closing it
do
{
mq_signal_waiting();
spin_lock_bh(&open_count_guard);
if (open_count == 0)
{
break; // we're not releasing the lock here on purpose
}
spin_unlock_bh(&open_count_guard);
} while (1);
spin_unlock_bh(&open_count_guard);
remove_proc_entry(filename, init_net.proc_net);
printk(KERN_INFO "Removing file: /proc/net/%s\n", filename);
}