On Thu, 2015-04-16 at 14:16 +0200, Mateusz Guzik wrote:
> Hi,
> 
> Currently obtaining a new file descriptor results in locking fdtable
> twice - once in order to reserve a slot and second time to fill it

...


>  void __fd_install(struct files_struct *files, unsigned int fd,
>               struct file *file)
>  {
> +     unsigned long seq;

        unsigned int seq;

>       struct fdtable *fdt;
> -     spin_lock(&files->file_lock);
> -     fdt = files_fdtable(files);
> -     BUG_ON(fdt->fd[fd] != NULL);
> -     rcu_assign_pointer(fdt->fd[fd], file);
> -     spin_unlock(&files->file_lock);
> +
> +     rcu_read_lock();
> +     do {
> +             seq = read_seqcount_begin(&files->fdt_seqcount);
> +             fdt = files_fdtable_seq(files);
> +             /*
> +              * Entry in the table can already be equal to file if we
> +              * had to restart and copy_fdtable picked up our update.
> +              */
> +             BUG_ON(!(fdt->fd[fd] == NULL || fdt->fd[fd] == file));
> +             rcu_assign_pointer(fdt->fd[fd], file);
> +             smp_mb();
> +     } while (__read_seqcount_retry(&files->fdt_seqcount, seq));
> +     rcu_read_unlock();
>  }
>  

So one problem here is :

As soon as  rcu_assign_pointer(fdt->fd[fd], file) is done, and other cpu
does one expand_fdtable() and releases files->file_lock, another cpu can
close(fd).

Then another cpu can reuse the [fd] now empty slot and install a new
file in it.

Then this cpu will crash here :

BUG_ON(!(fdt->fd[fd] == NULL || fdt->fd[fd] == file));



--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to