From: Josef Bacik <jbacik@redhat.com> Date: Tue, 10 Feb 2009 13:49:35 -0500 Subject: [mm] make new aops kABI friendly Message-id: 1234291777-15344-23-git-send-email-jbacik@redhat.com O-Subject: [PATCH 22/24] [RHEL 5.4] mm: make new aops kABI friendly Bugzilla: 445433 This patch is not a backport of anything from upstream, and is related to bz 445433. This patch introduces struct address_space_operations_ext which is used to hold write_begin and write_end. If an fs supports the new aops they set MS_HAS_NEW_AOPS in sb->s_flags and uses the new struct with write_begin and write_end filled out. Signed-off-by: Josef Bacik <jbacik@redhat.com> diff --git a/drivers/block/loop.c b/drivers/block/loop.c index f61d013..0b481f1 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -770,7 +770,7 @@ static int loop_set_fd(struct loop_device *lo, struct file *lo_file, */ if (!file->f_op->sendfile) goto out_putf; - if (aops->prepare_write || aops->write_begin) + if (aops->prepare_write || IS_NEWAOPS(inode)) lo_flags |= LO_FLAGS_USE_AOPS; if (!(lo_flags & LO_FLAGS_USE_AOPS) && !file->f_op->write) lo_flags |= LO_FLAGS_READ_ONLY; diff --git a/include/linux/fs.h b/include/linux/fs.h index 5f5f524..6a2fa23 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -125,6 +125,7 @@ extern int dir_notify_enable; #define MS_NO_LEASES (1<<21) /* fs does not support leases */ #define MS_HAS_SETLEASE (1<<22) /* fs supports setlease fop */ #define MS_I_VERSION (1<<23) /* Update inode I_version field */ +#define MS_HAS_NEW_AOPS (1<<24) /* fs supports new aops */ #define MS_ACTIVE (1<<30) #define MS_NOUSER (1<<31) @@ -189,6 +190,7 @@ extern int dir_notify_enable; #define IS_PRIVATE(inode) ((inode)->i_flags & S_PRIVATE) #define IS_NO_LEASES(inode) __IS_FLG(inode, MS_NO_LEASES) #define IS_SETLEASE(inode) __IS_FLG(inode, MS_HAS_SETLEASE) +#define IS_NEWAOPS(inode) __IS_FLG(inode, MS_HAS_NEW_AOPS) /* the read-only stuff doesn't really belong here, but any other place is probably as bad and I don't want to create yet another include file. */ @@ -463,13 +465,6 @@ struct address_space_operations { int (*prepare_write)(struct file *, struct page *, unsigned, unsigned); int (*commit_write)(struct file *, struct page *, unsigned, unsigned); - int (*write_begin)(struct file *, struct address_space *mapping, - loff_t pos, unsigned len, unsigned flags, - struct page **pagep, void **fsdata); - int (*write_end)(struct file *, struct address_space *mapping, - loff_t pos, unsigned len, unsigned copied, - struct page *page, void *fsdata); - /* Unfortunately this kludge is needed for FIBMAP. Don't use it */ sector_t (*bmap)(struct address_space *, sector_t); void (*invalidatepage) (struct page *, unsigned long); @@ -483,6 +478,18 @@ struct address_space_operations { struct page *, struct page *); }; +struct address_space_operations_ext { + struct address_space_operations orig_aops; + + /* if MS_HAS_NEW_AOPS is set then these are there */ + int (*write_begin)(struct file *, struct address_space *mapping, + loff_t pos, unsigned len, unsigned flags, + struct page **pagep, void **fsdata); + int (*write_end)(struct file *, struct address_space *mapping, + loff_t pos, unsigned len, unsigned copied, + struct page *page, void *fsdata); +}; + /* * pagecache_write_begin/pagecache_write_end must be used by general code * to write into the pagecache. diff --git a/mm/filemap.c b/mm/filemap.c index 15282de..3c578e2 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -2130,9 +2130,13 @@ int pagecache_write_begin(struct file *file, struct address_space *mapping, struct page **pagep, void **fsdata) { const struct address_space_operations *aops = mapping->a_ops; + struct inode *inode = mapping->host; + + if (IS_NEWAOPS(inode)) { + struct address_space_operations_ext *axops = + (struct address_space_operations_ext *)mapping->a_ops; - if (aops->write_begin) { - return aops->write_begin(file, mapping, pos, len, flags, + return axops->write_begin(file, mapping, pos, len, flags, pagep, fsdata); } else { int ret; @@ -2184,11 +2188,14 @@ int pagecache_write_end(struct file *file, struct address_space *mapping, struct page *page, void *fsdata) { const struct address_space_operations *aops = mapping->a_ops; + struct inode *inode = mapping->host; int ret; - if (aops->write_end) { + if (IS_NEWAOPS(inode)) { + struct address_space_operations_ext *axops = + (struct address_space_operations_ext *)mapping->a_ops; mark_page_accessed(page); - ret = aops->write_end(file, mapping, pos, len, copied, + ret = axops->write_end(file, mapping, pos, len, copied, page, fsdata); } else { unsigned offset = pos & (PAGE_CACHE_SIZE - 1); @@ -2461,7 +2468,8 @@ static ssize_t generic_perform_write(struct file *file, struct iov_iter *i, loff_t pos) { struct address_space *mapping = file->f_mapping; - const struct address_space_operations *a_ops = mapping->a_ops; + const struct address_space_operations_ext *a_ops = + (struct address_space_operations_ext *)mapping->a_ops; long status = 0; ssize_t written = 0; unsigned int flags = 0; @@ -2557,7 +2565,7 @@ generic_file_buffered_write(struct kiocb *iocb, const struct iovec *iov, struct iov_iter i; iov_iter_init(&i, iov, nr_segs, count, written); - if (a_ops->write_begin) + if (IS_NEWAOPS(inode)) status = generic_perform_write(file, &i, pos); else status = generic_perform_write_2copy(file, &i, pos);