summaryrefslogtreecommitdiff
path: root/linux-core
diff options
context:
space:
mode:
Diffstat (limited to 'linux-core')
-rw-r--r--linux-core/mmfs_drv.c113
-rw-r--r--linux-core/mmfs_drv.h7
2 files changed, 111 insertions, 9 deletions
diff --git a/linux-core/mmfs_drv.c b/linux-core/mmfs_drv.c
index f4b07117..d973592d 100644
--- a/linux-core/mmfs_drv.c
+++ b/linux-core/mmfs_drv.c
@@ -91,12 +91,12 @@ mmfs_handle_delete(struct mmfs_file *mmfs_filp, int handle)
* we may want to use ida for number allocation and a hash table
* for the pointers, anyway.
*/
- spin_lock(&mmfs_filp->delete_lock);
+ spin_lock(&mmfs_filp->table_lock);
/* Check if we currently have a reference on the object */
obj = idr_find(&mmfs_filp->object_idr, handle);
if (obj == NULL) {
- spin_unlock(&mmfs_filp->delete_lock);
+ spin_unlock(&mmfs_filp->table_lock);
return -EINVAL;
}
@@ -104,11 +104,34 @@ mmfs_handle_delete(struct mmfs_file *mmfs_filp, int handle)
idr_remove(&mmfs_filp->object_idr, handle);
mmfs_object_unreference(obj);
- spin_unlock(&mmfs_filp->delete_lock);
+ spin_unlock(&mmfs_filp->table_lock);
return 0;
}
+/** Returns a reference to the object named by the handle. */
+static struct mmfs_object *
+mmfs_object_lookup(struct mmfs_file *mmfs_filp, int handle)
+{
+ struct mmfs_object *obj;
+
+ spin_lock(&mmfs_filp->table_lock);
+
+ /* Check if we currently have a reference on the object */
+ obj = idr_find(&mmfs_filp->object_idr, handle);
+ if (obj == NULL) {
+ spin_unlock(&mmfs_filp->table_lock);
+ return NULL;
+ }
+
+ mmfs_object_reference(obj);
+
+ spin_unlock(&mmfs_filp->table_lock);
+
+ return obj;
+}
+
+
/**
* Allocates a new mmfs object and returns a handle to it.
*/
@@ -164,7 +187,7 @@ mmfs_alloc_ioctl(struct inode *inode, struct file *filp,
}
/**
- * Allocates a new mmfs object and returns a handle to it.
+ * Releases the handle to an mmfs object.
*/
static int
mmfs_unreference_ioctl(struct inode *inode, struct file *filp,
@@ -182,6 +205,84 @@ mmfs_unreference_ioctl(struct inode *inode, struct file *filp,
return ret;
}
+/**
+ * Reads data from the object referenced by handle.
+ *
+ * On error, the contents of *data are undefined.
+ */
+static int
+mmfs_pread_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ struct mmfs_file *mmfs_filp = filp->private_data;
+ struct mmfs_pread_args args;
+ struct mmfs_object *obj;
+ ssize_t read;
+ loff_t offset;
+
+ if (copy_from_user(&args, (void __user *)arg, sizeof(args)))
+ return -EFAULT;
+
+ obj = mmfs_object_lookup(mmfs_filp, args.handle);
+ if (obj == NULL)
+ return -EINVAL;
+
+ offset = args.offset;
+
+ read = obj->filp->f_op->read(obj->filp, (char __user *)args.data,
+ args.size, &offset);
+ if (read != args.size) {
+ mmfs_object_unreference(obj);
+ if (read < 0)
+ return read;
+ else
+ return -EINVAL;
+ }
+
+ mmfs_object_unreference(obj);
+
+ return 0;
+}
+
+/**
+ * Writes data to the object referenced by handle.
+ *
+ * On error, the contents of the buffer that were to be modified are undefined.
+ */
+static int
+mmfs_pwrite_ioctl(struct inode *inode, struct file *filp,
+ unsigned int cmd, unsigned long arg)
+{
+ struct mmfs_file *mmfs_filp = filp->private_data;
+ struct mmfs_pwrite_args args;
+ struct mmfs_object *obj;
+ ssize_t written;
+ loff_t offset;
+
+ if (copy_from_user(&args, (void __user *)arg, sizeof(args)))
+ return -EFAULT;
+
+ obj = mmfs_object_lookup(mmfs_filp, args.handle);
+ if (obj == NULL)
+ return -EINVAL;
+
+ offset = args.offset;
+
+ written = obj->filp->f_op->write(obj->filp, (char __user *)args.data,
+ args.size, &offset);
+ if (written != args.size) {
+ mmfs_object_unreference(obj);
+ if (written < 0)
+ return written;
+ else
+ return -EINVAL;
+ }
+
+ mmfs_object_unreference(obj);
+
+ return 0;
+}
+
static int
mmfs_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
@@ -192,6 +293,10 @@ mmfs_ioctl(struct inode *inode, struct file *filp,
return mmfs_alloc_ioctl(inode, filp, cmd, arg);
case MMFS_IOCTL_UNREFERENCE:
return mmfs_unreference_ioctl(inode, filp, cmd, arg);
+ case MMFS_IOCTL_PREAD:
+ return mmfs_pread_ioctl(inode, filp, cmd, arg);
+ case MMFS_IOCTL_PWRITE:
+ return mmfs_pwrite_ioctl(inode, filp, cmd, arg);
default:
return -EINVAL;
}
diff --git a/linux-core/mmfs_drv.h b/linux-core/mmfs_drv.h
index 1944d2af..53d2f6cb 100644
--- a/linux-core/mmfs_drv.h
+++ b/linux-core/mmfs_drv.h
@@ -54,11 +54,8 @@ struct mmfs_object {
struct mmfs_file {
/** Mapping of object handles to object pointers. */
struct idr object_idr;
- /**
- * Lock for synchronization of access to object->refcount and
- * object_idr. See note in mmfs_unreference_ioctl.
- */
- spinlock_t delete_lock;
+ /** Lock for synchronization of access to object_idr. */
+ spinlock_t table_lock;
};
void mmfs_object_reference(struct mmfs_object *obj);