1/*
2 * Copyright 2013, Axel D��rfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT license.
4 */
5#ifndef _FS_TRIM_SUPPORT_H
6#define _FS_TRIM_SUPPORT_H
7
8
9#include <AutoDeleter.h>
10#include <KernelExport.h>
11#include <SupportDefs.h>
12
13#include <kernel.h>
14#include <syscall_restart.h>
15
16
17static inline status_t
18get_trim_data_from_user(void* buffer, size_t size, MemoryDeleter& deleter,
19	fs_trim_data*& _trimData)
20{
21	if (!is_called_via_syscall() && !IS_USER_ADDRESS(buffer)) {
22		// Called from kernel
23		_trimData = (fs_trim_data*)buffer;
24		return B_OK;
25	}
26
27	// Called from userland
28	if (!IS_USER_ADDRESS(buffer))
29		return B_BAD_ADDRESS;
30
31	uint32 count;
32	if (user_memcpy(&count, buffer, sizeof(count)) != B_OK)
33		return B_BAD_ADDRESS;
34
35	size_t bytes = (count - 1) * sizeof(uint64) * 2 + sizeof(fs_trim_data);
36	if (bytes > size)
37		return B_BAD_VALUE;
38
39	void* trimBuffer = malloc(bytes);
40	if (trimBuffer == NULL)
41		return B_NO_MEMORY;
42
43	if (user_memcpy(trimBuffer, buffer, bytes) != B_OK) {
44		free(trimBuffer);
45		return B_BAD_ADDRESS;
46	}
47
48	// The passed in MemoryDeleter needs to take care of freeing the buffer
49	// later, since we had to allocate it.
50	deleter.SetTo(trimBuffer);
51
52	_trimData = (fs_trim_data*)trimBuffer;
53	return B_OK;
54}
55
56
57static inline status_t
58copy_trim_data_to_user(void* buffer, fs_trim_data* trimData)
59{
60	if (!is_called_via_syscall() && !IS_USER_ADDRESS(buffer))
61		return B_OK;
62
63	if (!IS_USER_ADDRESS(buffer))
64		return B_BAD_ADDRESS;
65
66	// Do not copy any ranges
67	return user_memcpy(buffer, trimData, offsetof(fs_trim_data, ranges));
68}
69
70
71#endif	// _FS_TRIM_SUPPORT_H
72