diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-19 14:35:30 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-19 14:35:30 -0400 |
commit | ba0234ec35127fe21d373db53cbaf9fe20620cb6 (patch) | |
tree | a2cbef204482512ae9e723f2bf4d22051975ef45 /arch/s390/hypfs/hypfs_vm.c | |
parent | 537b60d17894b7c19a6060feae40299d7109d6e7 (diff) | |
parent | 939e379e9e183ae6291ac7caa4a5e1dfadae4ccc (diff) |
Merge branch 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6
* 'for-linus' of git://git390.marist.edu/pub/scm/linux-2.6: (24 commits)
[S390] drivers/s390/char: Use kmemdup
[S390] drivers/s390/char: Use kstrdup
[S390] debug: enable exception-trace debug facility
[S390] s390_hypfs: Add new attributes
[S390] qdio: remove API wrappers
[S390] qdio: set correct bit in dsci
[S390] qdio: dont convert timestamps to microseconds
[S390] qdio: remove memset hack
[S390] qdio: prevent starvation on PCI devices
[S390] qdio: count number of qdio interrupts
[S390] user space fault: report fault before calling do_exit
[S390] topology: expose core identifier
[S390] dasd: remove uid from devmap
[S390] dasd: add dynamic pav toleration
[S390] vdso: add missing vdso_install target
[S390] vdso: remove redundant check for CONFIG_64BIT
[S390] avoid default_llseek in s390 drivers
[S390] vmcp: disallow modular build
[S390] add breaking event address for user space
[S390] virtualization aware cpu measurement
...
Diffstat (limited to 'arch/s390/hypfs/hypfs_vm.c')
-rw-r--r-- | arch/s390/hypfs/hypfs_vm.c | 87 |
1 files changed, 80 insertions, 7 deletions
diff --git a/arch/s390/hypfs/hypfs_vm.c b/arch/s390/hypfs/hypfs_vm.c index f0b0d31f0b48..ee5ab1a578e7 100644 --- a/arch/s390/hypfs/hypfs_vm.c +++ b/arch/s390/hypfs/hypfs_vm.c | |||
@@ -10,14 +10,18 @@ | |||
10 | #include <linux/string.h> | 10 | #include <linux/string.h> |
11 | #include <linux/vmalloc.h> | 11 | #include <linux/vmalloc.h> |
12 | #include <asm/ebcdic.h> | 12 | #include <asm/ebcdic.h> |
13 | #include <asm/timex.h> | ||
13 | #include "hypfs.h" | 14 | #include "hypfs.h" |
14 | 15 | ||
15 | #define NAME_LEN 8 | 16 | #define NAME_LEN 8 |
17 | #define DBFS_D2FC_HDR_VERSION 0 | ||
16 | 18 | ||
17 | static char local_guest[] = " "; | 19 | static char local_guest[] = " "; |
18 | static char all_guests[] = "* "; | 20 | static char all_guests[] = "* "; |
19 | static char *guest_query; | 21 | static char *guest_query; |
20 | 22 | ||
23 | static struct dentry *dbfs_d2fc_file; | ||
24 | |||
21 | struct diag2fc_data { | 25 | struct diag2fc_data { |
22 | __u32 version; | 26 | __u32 version; |
23 | __u32 flags; | 27 | __u32 flags; |
@@ -76,23 +80,26 @@ static int diag2fc(int size, char* query, void *addr) | |||
76 | return -residual_cnt; | 80 | return -residual_cnt; |
77 | } | 81 | } |
78 | 82 | ||
79 | static struct diag2fc_data *diag2fc_store(char *query, int *count) | 83 | /* |
84 | * Allocate buffer for "query" and store diag 2fc at "offset" | ||
85 | */ | ||
86 | static void *diag2fc_store(char *query, unsigned int *count, int offset) | ||
80 | { | 87 | { |
88 | void *data; | ||
81 | int size; | 89 | int size; |
82 | struct diag2fc_data *data; | ||
83 | 90 | ||
84 | do { | 91 | do { |
85 | size = diag2fc(0, query, NULL); | 92 | size = diag2fc(0, query, NULL); |
86 | if (size < 0) | 93 | if (size < 0) |
87 | return ERR_PTR(-EACCES); | 94 | return ERR_PTR(-EACCES); |
88 | data = vmalloc(size); | 95 | data = vmalloc(size + offset); |
89 | if (!data) | 96 | if (!data) |
90 | return ERR_PTR(-ENOMEM); | 97 | return ERR_PTR(-ENOMEM); |
91 | if (diag2fc(size, query, data) == 0) | 98 | if (diag2fc(size, query, data + offset) == 0) |
92 | break; | 99 | break; |
93 | vfree(data); | 100 | vfree(data); |
94 | } while (1); | 101 | } while (1); |
95 | *count = (size / sizeof(*data)); | 102 | *count = (size / sizeof(struct diag2fc_data)); |
96 | 103 | ||
97 | return data; | 104 | return data; |
98 | } | 105 | } |
@@ -168,9 +175,10 @@ int hypfs_vm_create_files(struct super_block *sb, struct dentry *root) | |||
168 | { | 175 | { |
169 | struct dentry *dir, *file; | 176 | struct dentry *dir, *file; |
170 | struct diag2fc_data *data; | 177 | struct diag2fc_data *data; |
171 | int rc, i, count = 0; | 178 | unsigned int count = 0; |
179 | int rc, i; | ||
172 | 180 | ||
173 | data = diag2fc_store(guest_query, &count); | 181 | data = diag2fc_store(guest_query, &count, 0); |
174 | if (IS_ERR(data)) | 182 | if (IS_ERR(data)) |
175 | return PTR_ERR(data); | 183 | return PTR_ERR(data); |
176 | 184 | ||
@@ -218,8 +226,61 @@ failed: | |||
218 | return rc; | 226 | return rc; |
219 | } | 227 | } |
220 | 228 | ||
229 | struct dbfs_d2fc_hdr { | ||
230 | u64 len; /* Length of d2fc buffer without header */ | ||
231 | u16 version; /* Version of header */ | ||
232 | char tod_ext[16]; /* TOD clock for d2fc */ | ||
233 | u64 count; /* Number of VM guests in d2fc buffer */ | ||
234 | char reserved[30]; | ||
235 | } __attribute__ ((packed)); | ||
236 | |||
237 | struct dbfs_d2fc { | ||
238 | struct dbfs_d2fc_hdr hdr; /* 64 byte header */ | ||
239 | char buf[]; /* d2fc buffer */ | ||
240 | } __attribute__ ((packed)); | ||
241 | |||
242 | static int dbfs_d2fc_open(struct inode *inode, struct file *file) | ||
243 | { | ||
244 | struct dbfs_d2fc *data; | ||
245 | unsigned int count; | ||
246 | |||
247 | data = diag2fc_store(guest_query, &count, sizeof(data->hdr)); | ||
248 | if (IS_ERR(data)) | ||
249 | return PTR_ERR(data); | ||
250 | get_clock_ext(data->hdr.tod_ext); | ||
251 | data->hdr.len = count * sizeof(struct diag2fc_data); | ||
252 | data->hdr.version = DBFS_D2FC_HDR_VERSION; | ||
253 | data->hdr.count = count; | ||
254 | memset(&data->hdr.reserved, 0, sizeof(data->hdr.reserved)); | ||
255 | file->private_data = data; | ||
256 | return nonseekable_open(inode, file); | ||
257 | } | ||
258 | |||
259 | static int dbfs_d2fc_release(struct inode *inode, struct file *file) | ||
260 | { | ||
261 | diag2fc_free(file->private_data); | ||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | static ssize_t dbfs_d2fc_read(struct file *file, char __user *buf, | ||
266 | size_t size, loff_t *ppos) | ||
267 | { | ||
268 | struct dbfs_d2fc *data = file->private_data; | ||
269 | |||
270 | return simple_read_from_buffer(buf, size, ppos, data, data->hdr.len + | ||
271 | sizeof(struct dbfs_d2fc_hdr)); | ||
272 | } | ||
273 | |||
274 | static const struct file_operations dbfs_d2fc_ops = { | ||
275 | .open = dbfs_d2fc_open, | ||
276 | .read = dbfs_d2fc_read, | ||
277 | .release = dbfs_d2fc_release, | ||
278 | }; | ||
279 | |||
221 | int hypfs_vm_init(void) | 280 | int hypfs_vm_init(void) |
222 | { | 281 | { |
282 | if (!MACHINE_IS_VM) | ||
283 | return 0; | ||
223 | if (diag2fc(0, all_guests, NULL) > 0) | 284 | if (diag2fc(0, all_guests, NULL) > 0) |
224 | guest_query = all_guests; | 285 | guest_query = all_guests; |
225 | else if (diag2fc(0, local_guest, NULL) > 0) | 286 | else if (diag2fc(0, local_guest, NULL) > 0) |
@@ -227,5 +288,17 @@ int hypfs_vm_init(void) | |||
227 | else | 288 | else |
228 | return -EACCES; | 289 | return -EACCES; |
229 | 290 | ||
291 | dbfs_d2fc_file = debugfs_create_file("diag_2fc", 0400, hypfs_dbfs_dir, | ||
292 | NULL, &dbfs_d2fc_ops); | ||
293 | if (IS_ERR(dbfs_d2fc_file)) | ||
294 | return PTR_ERR(dbfs_d2fc_file); | ||
295 | |||
230 | return 0; | 296 | return 0; |
231 | } | 297 | } |
298 | |||
299 | void hypfs_vm_exit(void) | ||
300 | { | ||
301 | if (!MACHINE_IS_VM) | ||
302 | return; | ||
303 | debugfs_remove(dbfs_d2fc_file); | ||
304 | } | ||