On Mon 29-04-19 12:26:41, Goldwyn Rodrigues wrote:
> From: Goldwyn Rodrigues <rgold...@suse.com>
> 
> We replace the existing entry to the newly allocated one
> in case of CoW. Also, we mark the entry as PAGECACHE_TAG_TOWRITE
> so writeback marks this entry as writeprotected. This
> helps us snapshots so new write pagefaults after snapshots
> trigger a CoW.

I don't understand why do you need to mark the new entry with
PAGECACHE_TAG_TOWRITE. dax_insert_entry() will unmap the entry from all
page tables so what's there left to writeprotect?

>  /*
>   * By this point grab_mapping_entry() has ensured that we have a locked entry
>   * of the appropriate size so we don't have to worry about downgrading PMDs 
> to
> @@ -709,14 +712,17 @@ static int copy_user_dax(struct block_device *bdev, 
> struct dax_device *dax_dev,
>   */
>  static void *dax_insert_entry(struct xa_state *xas,
>               struct address_space *mapping, struct vm_fault *vmf,
> -             void *entry, pfn_t pfn, unsigned long flags, bool dirty)
> +             void *entry, pfn_t pfn, unsigned long flags,
> +             unsigned long insert_flags)
>  {
>       void *new_entry = dax_make_entry(pfn, flags);
> +     bool dirty = insert_flags & DAX_IF_DIRTY;
> +     bool cow = insert_flags & DAX_IF_COW;

Does 'cow' really need to be a separate flag? dax_insert_entry() can just
figure out the right thing to do on its own based on old entry value and
new entry to be inserted...

>  
>       if (dirty)
>               __mark_inode_dirty(mapping->host, I_DIRTY_PAGES);
>  
> -     if (dax_is_zero_entry(entry) && !(flags & DAX_ZERO_PAGE)) {
> +     if (cow || (dax_is_zero_entry(entry) && !(flags & DAX_ZERO_PAGE))) {

E.g. here we need to unmap if old entry is not 'empty' and the pfns differ
(well, the pfns differ check should better be done like I outline below to
make pmd + pte match work correctly).

>               unsigned long index = xas->xa_index;
>               /* we are replacing a zero page with block mapping */
>               if (dax_is_pmd_entry(entry))
> @@ -728,12 +734,12 @@ static void *dax_insert_entry(struct xa_state *xas,
>  
>       xas_reset(xas);
>       xas_lock_irq(xas);
> -     if (dax_entry_size(entry) != dax_entry_size(new_entry)) {
> +     if (cow || (dax_entry_size(entry) != dax_entry_size(new_entry))) {

This needs to be done if entries are different at all...

>               dax_disassociate_entry(entry, mapping, false);
>               dax_associate_entry(new_entry, mapping, vmf->vma, vmf->address);
>       }
>  
> -     if (dax_is_zero_entry(entry) || dax_is_empty_entry(entry)) {
> +     if (cow || dax_is_zero_entry(entry) || dax_is_empty_entry(entry)) {

This is the only place that will be a bit more subtle - you need to check
whether the new entry is not a subset of the old one (i.e., a PTE inside a
PMD) and skip setting in that case. So something like:

        if (xa_to_value(new_entry) | DAX_LOCKED == xa_to_value(entry) ||
            (dax_is_pmd_entry(entry) && dax_is_pte_entry(new_entry) &&
             dax_to_pfn(entry) + (xas->xa_index & PG_PMD_COLOUR) ==
             dax_to_pfn(new_entry))) {
                /* New entry is a subset of the current one? Skip update... */
                xas_load(xas);
        } else {
                do work...
        }


                                                                Honza
-- 
Jan Kara <j...@suse.com>
SUSE Labs, CR
_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm

Reply via email to