[POWERPC] spufs: clear mapping pointers after last close
authorChristoph Hellwig <hch@lst.de>
Mon, 23 Apr 2007 19:08:07 +0000 (21:08 +0200)
committerArnd Bergmann <arnd@klappe.arndb.de>
Mon, 23 Apr 2007 19:18:53 +0000 (21:18 +0200)
Make sure the pointers to various mappings are cleared once the last
user stopped using them.  This avoids accessing freed memory when
tearing down the gang directory aswell as optimizing away
pte invalidations if no one uses these.

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Arnd Bergmann <arnd.bergmann@de.ibm.com>
arch/powerpc/platforms/cell/spufs/context.c
arch/powerpc/platforms/cell/spufs/file.c
arch/powerpc/platforms/cell/spufs/inode.c
arch/powerpc/platforms/cell/spufs/spufs.h

index 04ad2e364e977350643d89087b06e2c5c8163478..b3954aba424e2abc5365cd2c65c2b4f3448f9957 100644 (file)
@@ -41,6 +41,7 @@ struct spu_context *alloc_spu_context(struct spu_gang *gang)
                goto out_free;
        }
        spin_lock_init(&ctx->mmio_lock);
+       spin_lock_init(&ctx->mapping_lock);
        kref_init(&ctx->kref);
        mutex_init(&ctx->state_mutex);
        init_MUTEX(&ctx->run_sema);
index 505266a568d4221d9305c9e4ef1b0e99cc3ffc88..deb340e6e0ae618b40fb826c9a58782217ba0397 100644 (file)
@@ -44,8 +44,26 @@ 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;
+       if (!i->i_openers++)
+               ctx->local_store = inode->i_mapping;
+       spin_unlock(&ctx->mapping_lock);
+       smp_wmb();
+       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);
        smp_wmb();
        return 0;
 }
@@ -149,6 +167,7 @@ spufs_mem_mmap(struct file *file, struct vm_area_struct *vma)
 
 static const struct file_operations spufs_mem_fops = {
        .open    = spufs_mem_open,
+       .release = spufs_mem_release,
        .read    = spufs_mem_read,
        .write   = spufs_mem_write,
        .llseek  = generic_file_llseek,
@@ -238,16 +257,35 @@ 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;
+       if (!i->i_openers++)
+               ctx->cntl = inode->i_mapping;
+       spin_unlock(&ctx->mapping_lock);
        smp_wmb();
        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);
+       smp_wmb();
+       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 +761,30 @@ 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;
+       if (!i->i_openers++)
+               ctx->signal1 = inode->i_mapping;
+       spin_unlock(&ctx->mapping_lock);
        smp_wmb();
        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);
+       smp_wmb();
+       return 0;
+}
+
 static ssize_t __spufs_signal1_read(struct spu_context *ctx, char __user *buf,
                        size_t len, loff_t *pos)
 {
@@ -821,6 +877,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 +887,30 @@ 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;
+       if (!i->i_openers++)
+               ctx->signal2 = inode->i_mapping;
+       spin_unlock(&ctx->mapping_lock);
        smp_wmb();
        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);
+       smp_wmb();
+       return 0;
+}
+
 static ssize_t __spufs_signal2_read(struct spu_context *ctx, char __user *buf,
                        size_t len, loff_t *pos)
 {
@@ -932,6 +1007,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 +1107,32 @@ 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;
+
+       spin_lock(&ctx->mapping_lock);
+       if (!i->i_openers++)
+               ctx->mss = inode->i_mapping;
+       spin_unlock(&ctx->mapping_lock);
        smp_wmb();
        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);
+       smp_wmb();
+       return 0;
+}
+
 static const struct file_operations spufs_mss_fops = {
        .open    = spufs_mss_open,
+       .release = spufs_mss_release,
        .mmap    = spufs_mss_mmap,
 };
 
@@ -1072,14 +1167,32 @@ 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;
+       if (!i->i_openers++)
+               ctx->psmap = inode->i_mapping;
+       spin_unlock(&ctx->mapping_lock);
        smp_wmb();
        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);
+       smp_wmb();
+       return 0;
+}
+
 static const struct file_operations spufs_psmap_fops = {
        .open    = spufs_psmap_open,
+       .release = spufs_psmap_release,
        .mmap    = spufs_psmap_mmap,
 };
 
@@ -1126,12 +1239,29 @@ 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;
+       if (!i->i_openers++)
+               ctx->mfc = inode->i_mapping;
+       spin_unlock(&ctx->mapping_lock);
        smp_wmb();
        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);
+       smp_wmb();
+       return 0;
+}
+
 /* interrupt-level mfc callback function. */
 void spufs_mfc_callback(struct spu *spu)
 {
@@ -1399,6 +1529,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,
index e3f4ee97c9132fd7de6ab0bfc867f17059f9a390..423596a6b995166fd12d9ec2020dd72530c5e3c8 100644 (file)
@@ -54,6 +54,7 @@ spufs_alloc_inode(struct super_block *sb)
 
        ei->i_gang = NULL;
        ei->i_ctx = NULL;
+       ei->i_openers = 0;
 
        return &ei->vfs_inode;
 }
index f418378abdff5173292919c246d64e23166f1932..0fb366d9d257c97cd012703ab3f196c5986f7f0e 100644 (file)
@@ -50,11 +50,12 @@ struct spu_context {
        spinlock_t mmio_lock;             /* protects mmio access */
        struct address_space *local_store; /* local store mapping.  */
        struct address_space *mfc;         /* 'mfc' area mappings. */
-       struct address_space *cntl;        /* 'control' area mappings. */
-       struct address_space *signal1;     /* 'signal1' area mappings. */
-       struct address_space *signal2;     /* 'signal2' area mappings. */
-       struct address_space *mss;         /* 'mss' area mappings. */
-       struct address_space *psmap;       /* 'psmap' area mappings. */
+       struct address_space *cntl;        /* 'control' area mappings. */
+       struct address_space *signal1;     /* 'signal1' area mappings. */
+       struct address_space *signal2;     /* 'signal2' area mappings. */
+       struct address_space *mss;         /* 'mss' area mappings. */
+       struct address_space *psmap;       /* 'psmap' area mappings. */
+       spinlock_t mapping_lock;
        u64 object_id;             /* user space pointer for oprofile */
 
        enum { SPU_STATE_RUNNABLE, SPU_STATE_SAVED } state;
@@ -149,6 +150,7 @@ struct spufs_inode_info {
        struct spu_context *i_ctx;
        struct spu_gang *i_gang;
        struct inode vfs_inode;
+       int i_openers;
 };
 #define SPUFS_I(inode) \
        container_of(inode, struct spufs_inode_info, vfs_inode)