- patches.apparmor/remove_suid_new_case_in_2.6.22.diff: Merge fix.
[linux-flexiantxendom0-3.2.10.git] / arch / powerpc / platforms / cell / spufs / file.c
index 505266a..45614c7 100644 (file)
@@ -44,9 +44,25 @@ spufs_mem_open(struct inode *inode, struct file *file)
 {
        struct spufs_inode_info *i = SPUFS_I(inode);
        struct spu_context *ctx = i->i_ctx;
+
+       spin_lock(&ctx->mapping_lock);
        file->private_data = ctx;
-       ctx->local_store = inode->i_mapping;
-       smp_wmb();
+       if (!i->i_openers++)
+               ctx->local_store = inode->i_mapping;
+       spin_unlock(&ctx->mapping_lock);
+       return 0;
+}
+
+static int
+spufs_mem_release(struct inode *inode, struct file *file)
+{
+       struct spufs_inode_info *i = SPUFS_I(inode);
+       struct spu_context *ctx = i->i_ctx;
+
+       spin_lock(&ctx->mapping_lock);
+       if (!--i->i_openers)
+               ctx->local_store = NULL;
+       spin_unlock(&ctx->mapping_lock);
        return 0;
 }
 
@@ -102,14 +118,32 @@ spufs_mem_write(struct file *file, const char __user *buffer,
 static unsigned long spufs_mem_mmap_nopfn(struct vm_area_struct *vma,
                                          unsigned long address)
 {
-       struct spu_context *ctx = vma->vm_file->private_data;
-       unsigned long pfn, offset = address - vma->vm_start;
+       struct spu_context *ctx = vma->vm_file->private_data;
+       unsigned long pfn, offset, addr0 = address;
+#ifdef CONFIG_SPU_FS_64K_LS
+       struct spu_state *csa = &ctx->csa;
+       int psize;
 
-       offset += vma->vm_pgoff << PAGE_SHIFT;
+       /* Check what page size we are using */
+       psize = get_slice_psize(vma->vm_mm, address);
 
+       /* Some sanity checking */
+       BUG_ON(csa->use_big_pages != (psize == MMU_PAGE_64K));
+
+       /* Wow, 64K, cool, we need to align the address though */
+       if (csa->use_big_pages) {
+               BUG_ON(vma->vm_start & 0xffff);
+               address &= ~0xfffful;
+       }
+#endif /* CONFIG_SPU_FS_64K_LS */
+
+       offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
        if (offset >= LS_SIZE)
                return NOPFN_SIGBUS;
 
+       pr_debug("spufs_mem_mmap_nopfn address=0x%lx -> 0x%lx, offset=0x%lx\n",
+                addr0, address, offset);
+
        spu_acquire(ctx);
 
        if (ctx->state == SPU_STATE_SAVED) {
@@ -133,9 +167,24 @@ static struct vm_operations_struct spufs_mem_mmap_vmops = {
        .nopfn = spufs_mem_mmap_nopfn,
 };
 
-static int
-spufs_mem_mmap(struct file *file, struct vm_area_struct *vma)
-{
+static int spufs_mem_mmap(struct file *file, struct vm_area_struct *vma)
+{
+#ifdef CONFIG_SPU_FS_64K_LS
+       struct spu_context      *ctx = file->private_data;
+       struct spu_state        *csa = &ctx->csa;
+
+       /* Sanity check VMA alignment */
+       if (csa->use_big_pages) {
+               pr_debug("spufs_mem_mmap 64K, start=0x%lx, end=0x%lx,"
+                        " pgoff=0x%lx\n", vma->vm_start, vma->vm_end,
+                        vma->vm_pgoff);
+               if (vma->vm_start & 0xffff)
+                       return -EINVAL;
+               if (vma->vm_pgoff & 0xf)
+                       return -EINVAL;
+       }
+#endif /* CONFIG_SPU_FS_64K_LS */
+
        if (!(vma->vm_flags & VM_SHARED))
                return -EINVAL;
 
@@ -147,12 +196,34 @@ spufs_mem_mmap(struct file *file, struct vm_area_struct *vma)
        return 0;
 }
 
+#ifdef CONFIG_SPU_FS_64K_LS
+unsigned long spufs_get_unmapped_area(struct file *file, unsigned long addr,
+                                     unsigned long len, unsigned long pgoff,
+                                     unsigned long flags)
+{
+       struct spu_context      *ctx = file->private_data;
+       struct spu_state        *csa = &ctx->csa;
+
+       /* If not using big pages, fallback to normal MM g_u_a */
+       if (!csa->use_big_pages)
+               return current->mm->get_unmapped_area(file, addr, len,
+                                                     pgoff, flags);
+
+       /* Else, try to obtain a 64K pages slice */
+       return slice_get_unmapped_area(addr, len, flags,
+                                      MMU_PAGE_64K, 1, 0);
+}
+#endif /* CONFIG_SPU_FS_64K_LS */
+
 static const struct file_operations spufs_mem_fops = {
-       .open    = spufs_mem_open,
-       .read    = spufs_mem_read,
-       .write   = spufs_mem_write,
-       .llseek  = generic_file_llseek,
-       .mmap    = spufs_mem_mmap,
+       .open                   = spufs_mem_open,
+       .read                   = spufs_mem_read,
+       .write                  = spufs_mem_write,
+       .llseek                 = generic_file_llseek,
+       .mmap                   = spufs_mem_mmap,
+#ifdef CONFIG_SPU_FS_64K_LS
+       .get_unmapped_area      = spufs_get_unmapped_area,
+#endif
 };
 
 static unsigned long spufs_ps_nopfn(struct vm_area_struct *vma,
@@ -238,16 +309,33 @@ static int spufs_cntl_open(struct inode *inode, struct file *file)
        struct spufs_inode_info *i = SPUFS_I(inode);
        struct spu_context *ctx = i->i_ctx;
 
+       spin_lock(&ctx->mapping_lock);
        file->private_data = ctx;
-       ctx->cntl = inode->i_mapping;
-       smp_wmb();
+       if (!i->i_openers++)
+               ctx->cntl = inode->i_mapping;
+       spin_unlock(&ctx->mapping_lock);
        return simple_attr_open(inode, file, spufs_cntl_get,
                                        spufs_cntl_set, "0x%08lx");
 }
 
+static int
+spufs_cntl_release(struct inode *inode, struct file *file)
+{
+       struct spufs_inode_info *i = SPUFS_I(inode);
+       struct spu_context *ctx = i->i_ctx;
+
+       simple_attr_close(inode, file);
+
+       spin_lock(&ctx->mapping_lock);
+       if (!--i->i_openers)
+               ctx->cntl = NULL;
+       spin_unlock(&ctx->mapping_lock);
+       return 0;
+}
+
 static const struct file_operations spufs_cntl_fops = {
        .open = spufs_cntl_open,
-       .release = simple_attr_close,
+       .release = spufs_cntl_release,
        .read = simple_attr_read,
        .write = simple_attr_write,
        .mmap = spufs_cntl_mmap,
@@ -723,12 +811,28 @@ static int spufs_signal1_open(struct inode *inode, struct file *file)
 {
        struct spufs_inode_info *i = SPUFS_I(inode);
        struct spu_context *ctx = i->i_ctx;
+
+       spin_lock(&ctx->mapping_lock);
        file->private_data = ctx;
-       ctx->signal1 = inode->i_mapping;
-       smp_wmb();
+       if (!i->i_openers++)
+               ctx->signal1 = inode->i_mapping;
+       spin_unlock(&ctx->mapping_lock);
        return nonseekable_open(inode, file);
 }
 
+static int
+spufs_signal1_release(struct inode *inode, struct file *file)
+{
+       struct spufs_inode_info *i = SPUFS_I(inode);
+       struct spu_context *ctx = i->i_ctx;
+
+       spin_lock(&ctx->mapping_lock);
+       if (!--i->i_openers)
+               ctx->signal1 = NULL;
+       spin_unlock(&ctx->mapping_lock);
+       return 0;
+}
+
 static ssize_t __spufs_signal1_read(struct spu_context *ctx, char __user *buf,
                        size_t len, loff_t *pos)
 {
@@ -821,6 +925,7 @@ static int spufs_signal1_mmap(struct file *file, struct vm_area_struct *vma)
 
 static const struct file_operations spufs_signal1_fops = {
        .open = spufs_signal1_open,
+       .release = spufs_signal1_release,
        .read = spufs_signal1_read,
        .write = spufs_signal1_write,
        .mmap = spufs_signal1_mmap,
@@ -830,12 +935,28 @@ static int spufs_signal2_open(struct inode *inode, struct file *file)
 {
        struct spufs_inode_info *i = SPUFS_I(inode);
        struct spu_context *ctx = i->i_ctx;
+
+       spin_lock(&ctx->mapping_lock);
        file->private_data = ctx;
-       ctx->signal2 = inode->i_mapping;
-       smp_wmb();
+       if (!i->i_openers++)
+               ctx->signal2 = inode->i_mapping;
+       spin_unlock(&ctx->mapping_lock);
        return nonseekable_open(inode, file);
 }
 
+static int
+spufs_signal2_release(struct inode *inode, struct file *file)
+{
+       struct spufs_inode_info *i = SPUFS_I(inode);
+       struct spu_context *ctx = i->i_ctx;
+
+       spin_lock(&ctx->mapping_lock);
+       if (!--i->i_openers)
+               ctx->signal2 = NULL;
+       spin_unlock(&ctx->mapping_lock);
+       return 0;
+}
+
 static ssize_t __spufs_signal2_read(struct spu_context *ctx, char __user *buf,
                        size_t len, loff_t *pos)
 {
@@ -932,6 +1053,7 @@ static int spufs_signal2_mmap(struct file *file, struct vm_area_struct *vma)
 
 static const struct file_operations spufs_signal2_fops = {
        .open = spufs_signal2_open,
+       .release = spufs_signal2_release,
        .read = spufs_signal2_read,
        .write = spufs_signal2_write,
        .mmap = spufs_signal2_mmap,
@@ -1031,13 +1153,30 @@ static int spufs_mss_open(struct inode *inode, struct file *file)
        struct spu_context *ctx = i->i_ctx;
 
        file->private_data = i->i_ctx;
-       ctx->mss = inode->i_mapping;
-       smp_wmb();
+
+       spin_lock(&ctx->mapping_lock);
+       if (!i->i_openers++)
+               ctx->mss = inode->i_mapping;
+       spin_unlock(&ctx->mapping_lock);
        return nonseekable_open(inode, file);
 }
 
+static int
+spufs_mss_release(struct inode *inode, struct file *file)
+{
+       struct spufs_inode_info *i = SPUFS_I(inode);
+       struct spu_context *ctx = i->i_ctx;
+
+       spin_lock(&ctx->mapping_lock);
+       if (!--i->i_openers)
+               ctx->mss = NULL;
+       spin_unlock(&ctx->mapping_lock);
+       return 0;
+}
+
 static const struct file_operations spufs_mss_fops = {
        .open    = spufs_mss_open,
+       .release = spufs_mss_release,
        .mmap    = spufs_mss_mmap,
 };
 
@@ -1072,14 +1211,30 @@ static int spufs_psmap_open(struct inode *inode, struct file *file)
        struct spufs_inode_info *i = SPUFS_I(inode);
        struct spu_context *ctx = i->i_ctx;
 
+       spin_lock(&ctx->mapping_lock);
        file->private_data = i->i_ctx;
-       ctx->psmap = inode->i_mapping;
-       smp_wmb();
+       if (!i->i_openers++)
+               ctx->psmap = inode->i_mapping;
+       spin_unlock(&ctx->mapping_lock);
        return nonseekable_open(inode, file);
 }
 
+static int
+spufs_psmap_release(struct inode *inode, struct file *file)
+{
+       struct spufs_inode_info *i = SPUFS_I(inode);
+       struct spu_context *ctx = i->i_ctx;
+
+       spin_lock(&ctx->mapping_lock);
+       if (!--i->i_openers)
+               ctx->psmap = NULL;
+       spin_unlock(&ctx->mapping_lock);
+       return 0;
+}
+
 static const struct file_operations spufs_psmap_fops = {
        .open    = spufs_psmap_open,
+       .release = spufs_psmap_release,
        .mmap    = spufs_psmap_mmap,
 };
 
@@ -1126,12 +1281,27 @@ static int spufs_mfc_open(struct inode *inode, struct file *file)
        if (atomic_read(&inode->i_count) != 1)
                return -EBUSY;
 
+       spin_lock(&ctx->mapping_lock);
        file->private_data = ctx;
-       ctx->mfc = inode->i_mapping;
-       smp_wmb();
+       if (!i->i_openers++)
+               ctx->mfc = inode->i_mapping;
+       spin_unlock(&ctx->mapping_lock);
        return nonseekable_open(inode, file);
 }
 
+static int
+spufs_mfc_release(struct inode *inode, struct file *file)
+{
+       struct spufs_inode_info *i = SPUFS_I(inode);
+       struct spu_context *ctx = i->i_ctx;
+
+       spin_lock(&ctx->mapping_lock);
+       if (!--i->i_openers)
+               ctx->mfc = NULL;
+       spin_unlock(&ctx->mapping_lock);
+       return 0;
+}
+
 /* interrupt-level mfc callback function. */
 void spufs_mfc_callback(struct spu *spu)
 {
@@ -1313,7 +1483,10 @@ static ssize_t spufs_mfc_write(struct file *file, const char __user *buffer,
        if (ret)
                goto out;
 
-       spu_acquire_runnable(ctx, 0);
+       ret = spu_acquire_runnable(ctx, 0);
+       if (ret)
+               goto out;
+
        if (file->f_flags & O_NONBLOCK) {
                ret = ctx->ops->send_mfc_command(ctx, &cmd);
        } else {
@@ -1399,6 +1572,7 @@ static int spufs_mfc_fasync(int fd, struct file *file, int on)
 
 static const struct file_operations spufs_mfc_fops = {
        .open    = spufs_mfc_open,
+       .release = spufs_mfc_release,
        .read    = spufs_mfc_read,
        .write   = spufs_mfc_write,
        .poll    = spufs_mfc_poll,