I have a flash device with 6114 blocks of 1024 bytes data. I have the two following functions to access the flash:
long WriteData (long StartBlock, long Count, void *ptr)
long ReadData (long StartBlock, long Count, void *ptr)
Is there some open source code to simulate a filesystem on top of these two functions?
Thanks!
Related
I would like to create a shared memory mechanism between the kernel and 1 specific process in userspace. This process will spawn threads that will access this shared memory region.
Setting up the region between the userspace and the kernel does not have to be fast, but once it is done, no syscall should be made by the userspace process in order to write/read from the region and the region should be accessible by any kernel thread (not only the kernel part of the userspace process)
Ideally I would like to come up with something like:
Userspace allocates k bytes in its own address space using mmap() or posix_memalign(), where k is typically larger than a page.
Userspace sends the address returned by mmap() to the kernel using a kernel module or a syscall.
Kernel uses this address to map this region to its own address space so that it can see everything that gets written in this region also after the process exits the call. This means that the mapping needs to be done elsewhere in the kernel virtual address space
I have managed to come up with an example with a single page, with a kernel module doing something like:
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/sched/signal.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <asm/errno.h>
#include <linux/pagemap.h>
/*
* Prototypes
*/
static int device_open(struct inode *, struct file *);
static int device_release(struct inode *, struct file *);
static ssize_t device_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos);
static struct file_operations led_ops = {
.owner = THIS_MODULE,
.open = device_open,
.release = device_release,
.write = device_write
};
static char *my_page_address;
static struct page *kernel_page;
static ssize_t device_write(struct file *filp, const char __user *buf, s ize_t count, loff_t * ppos)
{
int res;
unsigned long uaddr;
char addrstr[80];
unsigned long copied = copy_from_user(addrstr, buf, count);
struct task_struct *task = current; // getting global current pointer
if (copied != 0)
{
pr_err("Error);
}
//Convert adress to long
uaddr = simple_strtoul(addrstr, NULL, 0);
uint64_t new_addr = uaddr;
printk(KERN_NOTICE "Module received the user adddress %p", uaddr);
//Locks the current process memory map
down_read(¤t->mm->mmap_sem);
res = get_user_pages(
uaddr,
1, //resquest 1 page
1, //write enable
&kernel_page,
NULL);
if (res == 1) {
pr_err("Storing shared page");
my_page_address = kmap(kernel_page);
}
//Release the lock
up_read(¤t->mm->mmap_sem);
return count;
}
Now, this seems to work for a single page. But several questions come to mind:
Can I extend this mechanism to a larger area than a page? Ideally I would like the kernel to access the memory region the same way the userspace process would do (just by having its own pointer in its own address space)
get_user_pages can take an array of pointers to vmas corresponding to each page as the last argument. If the userspace allocates a large contiguous buffer in its address space, can I use this vma to remap the same contiguous region in kernel space?
From what I have seen from other answers, some people recommend to allocate memory from within the kernel and allow users to mmap to it (For example here). But since the address space of the process is visible in the kernel space while the process is making the call, it should be possible to simply remap the part of the user address space to the kernel address space, right?
EDIT: Not a duplicate of this question. I want to know about a good way of mapping a userspace region to the kernel address space. Not accessing it via copy_from_user()
This question already has answers here:
copy_to_user vs memcpy
(2 answers)
Closed 7 years ago.
Let consider following code. For someone who read Linux Device Driver the context will be clear.
In short,
sbull is a driver which acts a disk device and the sbull_transfer function aims to transfer block of data from/to disk/user_space.
And everything is clear expect one thing.
I don't understand why we can just simply use memcpy function. After all, we copy from user space so why it is possible? Usually, I noticed, that we should use copy_from_user()/copy_to_user().
I don't understand why we needn't to use them. Please explain.
static void sbull_transfer(struct sbull_dev *dev, unsigned long sector,
unsigned long nsect, char *buffer, int write)
{
unsigned long offset = sector*KERNEL_SECTOR_SIZE;
unsigned long nbytes = nsect*KERNEL_SECTOR_SIZE;
if ((offset + nbytes) > dev->size) {
printk (KERN_NOTICE "Beyond-end write (%ld %ld)\n", offset, nbytes);
return;
}
if (write)
memcpy(dev->data + offset, buffer, nbytes);
else
memcpy(buffer, dev->data + offset, nbytes);
}
The sbull driver can implement the actual data transfer with a simple memcpy call because data is already in memory, after all.
Function
static void sbull_request(request_queue_t *q)
{
struct request *req;
while ((req = elv_next_request(q)) != NULL) {
struct sbull_dev *dev = req->rq_disk->private_data;
if (! blk_fs_request(req)) {
printk (KERN_NOTICE "Skip non-fs request\n");
end_request(req, 0);
continue;
}
sbull_transfer(dev, req->sector, req->current_nr_sectors,
req->buffer, rq_data_dir(req));
end_request(req, 1);
}
}
calls elv_next_request before data is passed to sbull_transfer. Request function takes care about copying data to/from user space. The buffer contained in returned request struct is described in book as:
char *buffer;
A pointer to the buffer to or from which the data should
be transferred. This pointer is a kernel virtual address and can be
dereferenced directly by the driver if need be.
I've got some linux drivers I'm trying to port from linux 2.4 to 3.0. During this lengthy span of time, the argument list of ioctl (unlocked_ioctl now) changed a bit:
-static int can_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static long can_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
The code was using the inode to get the minor version and was passing it to some other commands. Now that inode isn't a "free-be" given in the ioctl parameter list, how can I get it?
Is it possible to derive from the file pointer? or should I "save" a global pointer to it when it shows up in the _open() method? I'd rather avoid that if there's a better way.
You can get the inode from struct file * file in the kernel space. here is the brief struct map
file->f_path.d.dentry->d_inode; you can find the definition followed.
for dentry struct in dcache.h
struct dentry {
atomic_t d_count;
unsigned int d_flags; /* protected by d_lock */
spinlock_t d_lock; /* per dentry lock */
int d_mounted;
struct inode *d_inode; /* Where the name belongs to - NULL is
* negative */
/*
* The next three fields are touched by __d_lookup. Place them here
* so they all fit in a cache line.
*/
struct hlist_node d_hash; /* lookup hash list */
for the file structure in fs.h
file {
/*
* fu_list becomes invalid after file_free is called and queued via
* fu_rcuhead for RCU freeing
*/
...
struct path f_path;
#define f_dentry f_path.dentry
#define f_vfsmnt f_path.mnt
const struct file_operations *f_op;
spinlock_t f_lock; /* f_ep_links, f_flags, no IRQ */
#ifdef CONFIG_SMP
oop, just figured it out by poking around the kernel and looking at other drivers (don't know why it didn't occur to me to do that before). In case anyone else is interested you can get the inode from the file pointer passed into the ioctl as such:
long can_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct inode *inode = file->f_path.dentry->d_inode;
If anyone knows why this is a bad idea (I just took it from another driver), or if there's a better/preferred way let me know.
To get total installed RAM I can use popen("sysctl -n hw.memsize", "r"), but is there some library to get this info without running external tools?
sysctl
You can use sysctl (more detail here)
The symbols used in this section are
declared in the file sysctl.h. —
Function:
int sysctl (int *names, int nlen, void *oldval, size_t *oldlenp, void *newval, size_t newlen)
getrusage
getrusage
#include <sys/resource.h>
int getrusage(int who, struct rusage *usage);
struct rusage {
struct timeval ru_utime; /* user time used */
struct timeval ru_stime; /* system time used */
long ru_maxrss; /* maximum resident set size */
long ru_ixrss; /* integral shared memory size */
long ru_idrss; /* integral unshared data size */
long ru_isrss; /* integral unshared stack size */
long ru_minflt; /* page reclaims */
long ru_majflt; /* page faults */
long ru_nswap; /* swaps */
long ru_inblock; /* block input operations */
long ru_oublock; /* block output operations */
long ru_msgsnd; /* messages sent */
long ru_msgrcv; /* messages received */
long ru_nsignals; /* signals received */
long ru_nvcsw; /* voluntary context switches */
long ru_nivcsw; /* involuntary context switches */
};
You can use the api getrusage
int who = RUSAGE_SELF;
struct rusage usage={0,};
int ret=0;
ret = getrusage(who, &usage);
Look up the structure of rusage and pick the values of concern to you.
How can I get exact total space of a drive using C language program running on Linux? I dont want to use shell script. Any suggestions?
statfs/statfs64
#include <sys/vfs.h> /* or <sys/statfs.h> */
int statfs(const char *path, struct statfs *buf);
int fstatfs(int fd, struct statfs *buf);
From the man page:
The function statfs() returns information about a mounted file system.
path is the pathname of any file within the mounted file system.
buf is a pointer to a statfs structure defined approximately as follows:
struct statfs {
long f_type; /* type of file system (see below) */
long f_bsize; /* optimal transfer block size */
long f_blocks; /* total data blocks in file system */
long f_bfree; /* free blocks in fs */
long f_bavail; /* free blocks avail to non-superuser */
long f_files; /* total file nodes in file system */
long f_ffree; /* free file nodes in fs */
fsid_t f_fsid; /* file system id */
long f_namelen; /* maximum length of filenames */
};
You can use it like this:
struct statfs buf;
statfs("/", &buf);