Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4343d008 authored by David Howells's avatar David Howells
Browse files

afs: Get rid of the afs_writeback record



Get rid of the afs_writeback record that kAFS is using to match keys with
writes made by that key.

Instead, keep a list of keys that have a file open for writing and/or
sync'ing and iterate through those.

Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
parent 215804a9
Loading
Loading
Loading
Loading
+57 −26
Original line number Diff line number Diff line
@@ -23,7 +23,6 @@ static int afs_readpage(struct file *file, struct page *page);
static void afs_invalidatepage(struct page *page, unsigned int offset,
			       unsigned int length);
static int afs_releasepage(struct page *page, gfp_t gfp_flags);
static int afs_launder_page(struct page *page);

static int afs_readpages(struct file *filp, struct address_space *mapping,
			 struct list_head *pages, unsigned nr_pages);
@@ -62,6 +61,50 @@ const struct address_space_operations afs_fs_aops = {
	.writepages	= afs_writepages,
};

/*
 * Discard a pin on a writeback key.
 */
void afs_put_wb_key(struct afs_wb_key *wbk)
{
	if (refcount_dec_and_test(&wbk->usage)) {
		key_put(wbk->key);
		kfree(wbk);
	}
}

/*
 * Cache key for writeback.
 */
int afs_cache_wb_key(struct afs_vnode *vnode, struct afs_file *af)
{
	struct afs_wb_key *wbk, *p;

	wbk = kzalloc(sizeof(struct afs_wb_key), GFP_KERNEL);
	if (!wbk)
		return -ENOMEM;
	refcount_set(&wbk->usage, 2);
	wbk->key = af->key;

	spin_lock(&vnode->wb_lock);
	list_for_each_entry(p, &vnode->wb_keys, vnode_link) {
		if (p->key == wbk->key)
			goto found;
	}

	key_get(wbk->key);
	list_add_tail(&wbk->vnode_link, &vnode->wb_keys);
	spin_unlock(&vnode->wb_lock);
	af->wb = wbk;
	return 0;

found:
	refcount_inc(&p->usage);
	spin_unlock(&vnode->wb_lock);
	af->wb = p;
	kfree(wbk);
	return 0;
}

/*
 * open an AFS file or directory and attach a key to it
 */
@@ -85,12 +128,18 @@ int afs_open(struct inode *inode, struct file *file)
		ret = -ENOMEM;
		goto error_key;
	}
	af->key = key;

	ret = afs_validate(vnode, key);
	if (ret < 0)
		goto error_af;

	af->key = key;
	if (file->f_mode & FMODE_WRITE) {
		ret = afs_cache_wb_key(vnode, af);
		if (ret < 0)
			goto error_af;
	}
	
	file->private_data = af;
	_leave(" = 0");
	return 0;
@@ -115,8 +164,11 @@ int afs_release(struct inode *inode, struct file *file)
	_enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode);

	file->private_data = NULL;
	if (af->wb)
		afs_put_wb_key(af->wb);
	key_put(af->key);
	kfree(af);
	afs_prune_wb_keys(vnode);
	_leave(" = 0");
	return 0;
}
@@ -516,16 +568,6 @@ static int afs_readpages(struct file *file, struct address_space *mapping,
	return ret;
}

/*
 * write back a dirty page
 */
static int afs_launder_page(struct page *page)
{
	_enter("{%lu}", page->index);

	return 0;
}

/*
 * invalidate part or all of a page
 * - release a page and clean up its private data if offset is 0 (indicating
@@ -534,8 +576,6 @@ static int afs_launder_page(struct page *page)
static void afs_invalidatepage(struct page *page, unsigned int offset,
			       unsigned int length)
{
	struct afs_writeback *wb = (struct afs_writeback *) page_private(page);

	_enter("{%lu},%u,%u", page->index, offset, length);

	BUG_ON(!PageLocked(page));
@@ -551,12 +591,7 @@ static void afs_invalidatepage(struct page *page, unsigned int offset,
#endif

		if (PagePrivate(page)) {
			if (wb && !PageWriteback(page)) {
			set_page_private(page, 0);
				afs_put_writeback(wb);
			}

			if (!page_private(page))
			ClearPagePrivate(page);
		}
	}
@@ -570,7 +605,6 @@ static void afs_invalidatepage(struct page *page, unsigned int offset,
 */
static int afs_releasepage(struct page *page, gfp_t gfp_flags)
{
	struct afs_writeback *wb = (struct afs_writeback *) page_private(page);
	struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);

	_enter("{{%x:%u}[%lu],%lx},%x",
@@ -587,10 +621,7 @@ static int afs_releasepage(struct page *page, gfp_t gfp_flags)
#endif

	if (PagePrivate(page)) {
		if (wb) {
		set_page_private(page, 0);
			afs_put_writeback(wb);
		}
		ClearPagePrivate(page);
	}

+11 −13
Original line number Diff line number Diff line
@@ -1119,18 +1119,18 @@ static const struct afs_call_type afs_RXFSStoreData64 = {
 * store a set of pages to a very large file
 */
static int afs_fs_store_data64(struct afs_fs_cursor *fc,
			       struct afs_writeback *wb,
			       struct address_space *mapping,
			       pgoff_t first, pgoff_t last,
			       unsigned offset, unsigned to,
			       loff_t size, loff_t pos, loff_t i_size)
{
	struct afs_vnode *vnode = wb->vnode;
	struct afs_vnode *vnode = fc->vnode;
	struct afs_call *call;
	struct afs_net *net = afs_v2net(vnode);
	__be32 *bp;

	_enter(",%x,{%x:%u},,",
	       key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode);
	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);

	call = afs_alloc_flat_call(net, &afs_RXFSStoreData64,
				   (4 + 6 + 3 * 2) * 4,
@@ -1138,10 +1138,9 @@ static int afs_fs_store_data64(struct afs_fs_cursor *fc,
	if (!call)
		return -ENOMEM;

	call->wb = wb;
	call->key = wb->key;
	call->key = fc->key;
	call->mapping = mapping;
	call->reply[0] = vnode;
	call->mapping = vnode->vfs_inode.i_mapping;
	call->first = first;
	call->last = last;
	call->first_offset = offset;
@@ -1177,18 +1176,18 @@ static int afs_fs_store_data64(struct afs_fs_cursor *fc,
/*
 * store a set of pages
 */
int afs_fs_store_data(struct afs_fs_cursor *fc, struct afs_writeback *wb,
int afs_fs_store_data(struct afs_fs_cursor *fc, struct address_space *mapping,
		      pgoff_t first, pgoff_t last,
		      unsigned offset, unsigned to)
{
	struct afs_vnode *vnode = wb->vnode;
	struct afs_vnode *vnode = fc->vnode;
	struct afs_call *call;
	struct afs_net *net = afs_v2net(vnode);
	loff_t size, pos, i_size;
	__be32 *bp;

	_enter(",%x,{%x:%u},,",
	       key_serial(wb->key), vnode->fid.vid, vnode->fid.vnode);
	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);

	size = (loff_t)to - (loff_t)offset;
	if (first != last)
@@ -1205,7 +1204,7 @@ int afs_fs_store_data(struct afs_fs_cursor *fc, struct afs_writeback *wb,
	       (unsigned long long) i_size);

	if (pos >> 32 || i_size >> 32 || size >> 32 || (pos + size) >> 32)
		return afs_fs_store_data64(fc, wb, first, last, offset, to,
		return afs_fs_store_data64(fc, mapping, first, last, offset, to,
					   size, pos, i_size);

	call = afs_alloc_flat_call(net, &afs_RXFSStoreData,
@@ -1214,10 +1213,9 @@ int afs_fs_store_data(struct afs_fs_cursor *fc, struct afs_writeback *wb,
	if (!call)
		return -ENOMEM;

	call->wb = wb;
	call->key = wb->key;
	call->key = fc->key;
	call->mapping = mapping;
	call->reply[0] = vnode;
	call->mapping = vnode->vfs_inode.i_mapping;
	call->first = first;
	call->last = last;
	call->first_offset = offset;
+7 −4
Original line number Diff line number Diff line
@@ -482,7 +482,12 @@ void afs_evict_inode(struct inode *inode)
		vnode->cb_interest = NULL;
	}

	ASSERT(list_empty(&vnode->writebacks));
	while (!list_empty(&vnode->wb_keys)) {
		struct afs_wb_key *wbk = list_entry(vnode->wb_keys.next,
						    struct afs_wb_key, vnode_link);
		list_del(&wbk->vnode_link);
		afs_put_wb_key(wbk);
	}

#ifdef CONFIG_AFS_FSCACHE
	fscache_relinquish_cookie(vnode->cache, 0);
@@ -514,10 +519,8 @@ int afs_setattr(struct dentry *dentry, struct iattr *attr)
	}

	/* flush any dirty data outstanding on a regular file */
	if (S_ISREG(vnode->vfs_inode.i_mode)) {
	if (S_ISREG(vnode->vfs_inode.i_mode))
		filemap_write_and_wait(vnode->vfs_inode.i_mapping);
		afs_writeback_all(vnode);
	}

	if (attr->ia_valid & ATTR_FILE) {
		key = afs_file_key(attr->ia_file);
+18 −33
Original line number Diff line number Diff line
@@ -89,8 +89,7 @@ struct afs_call {
	struct afs_server	*cm_server;	/* Server affected by incoming CM call */
	struct afs_cb_interest	*cbi;		/* Callback interest for server used */
	void			*request;	/* request data (first part) */
	struct address_space	*mapping;	/* page set */
	struct afs_writeback	*wb;		/* writeback being performed */
	struct address_space	*mapping;	/* Pages being written from */
	void			*buffer;	/* reply receive buffer */
	void			*reply[4];	/* Where to put the reply */
	pgoff_t			first;		/* first page in mapping to deal with */
@@ -138,11 +137,21 @@ struct afs_call_type {
	void (*work)(struct work_struct *work);
};

/*
 * Key available for writeback on a file.
 */
struct afs_wb_key {
	refcount_t		usage;
	struct key		*key;
	struct list_head	vnode_link;	/* Link in vnode->wb_keys */
};

/*
 * AFS open file information record.  Pointed to by file->private_data.
 */
struct afs_file {
	struct key		*key;		/* The key this file was opened with */
	struct afs_wb_key	*wb;		/* Writeback key record for this file */
};

static inline struct key *afs_file_key(struct file *file)
@@ -167,32 +176,6 @@ struct afs_read {
	struct page		*pages[];
};

/*
 * record of an outstanding writeback on a vnode
 */
struct afs_writeback {
	struct list_head	link;		/* link in vnode->writebacks */
	struct work_struct	writer;		/* work item to perform the writeback */
	struct afs_vnode	*vnode;		/* vnode to which this write applies */
	struct key		*key;		/* owner of this write */
	wait_queue_head_t	waitq;		/* completion and ready wait queue */
	pgoff_t			first;		/* first page in batch */
	pgoff_t			point;		/* last page in current store op */
	pgoff_t			last;		/* last page in batch (inclusive) */
	unsigned		offset_first;	/* offset into first page of start of write */
	unsigned		to_last;	/* offset into last page of end of write */
	int			num_conflicts;	/* count of conflicting writes in list */
	int			usage;
	bool			conflicts;	/* T if has dependent conflicts */
	enum {
		AFS_WBACK_SYNCING,		/* synchronisation being performed */
		AFS_WBACK_PENDING,		/* write pending */
		AFS_WBACK_CONFLICTING,		/* conflicting writes posted */
		AFS_WBACK_WRITING,		/* writing back */
		AFS_WBACK_COMPLETE		/* the writeback record has been unlinked */
	} state __attribute__((packed));
};

/*
 * AFS superblock private data
 * - there's one superblock per volume
@@ -460,7 +443,7 @@ struct afs_vnode {
	struct afs_permits	*permit_cache;	/* cache of permits so far obtained */
	struct mutex		io_lock;	/* Lock for serialising I/O on this mutex */
	struct mutex		validate_lock;	/* lock for validating this vnode */
	spinlock_t		writeback_lock;	/* lock for writebacks */
	spinlock_t		wb_lock;	/* lock for wb_keys */
	spinlock_t		lock;		/* waitqueue/flags lock */
	unsigned long		flags;
#define AFS_VNODE_CB_PROMISED	0		/* Set if vnode has a callback promise */
@@ -476,7 +459,7 @@ struct afs_vnode {
#define AFS_VNODE_AUTOCELL	10		/* set if Vnode is an auto mount point */
#define AFS_VNODE_PSEUDODIR	11		/* set if Vnode is a pseudo directory */

	struct list_head	writebacks;	/* alterations in pagecache that need writing */
	struct list_head	wb_keys;	/* List of keys available for writeback */
	struct list_head	pending_locks;	/* locks waiting to be granted */
	struct list_head	granted_locks;	/* locks granted on this file */
	struct delayed_work	lock_work;	/* work to be done in locking */
@@ -648,6 +631,8 @@ extern const struct address_space_operations afs_fs_aops;
extern const struct inode_operations afs_file_inode_operations;
extern const struct file_operations afs_file_operations;

extern int afs_cache_wb_key(struct afs_vnode *, struct afs_file *);
extern void afs_put_wb_key(struct afs_wb_key *);
extern int afs_open(struct inode *, struct file *);
extern int afs_release(struct inode *, struct file *);
extern int afs_fetch_data(struct afs_vnode *, struct key *, struct afs_read *);
@@ -678,7 +663,7 @@ extern int afs_fs_symlink(struct afs_fs_cursor *, const char *, const char *,
			  struct afs_fid *, struct afs_file_status *);
extern int afs_fs_rename(struct afs_fs_cursor *, const char *,
			 struct afs_vnode *, const char *);
extern int afs_fs_store_data(struct afs_fs_cursor *, struct afs_writeback *,
extern int afs_fs_store_data(struct afs_fs_cursor *, struct address_space *,
			     pgoff_t, pgoff_t, unsigned, unsigned);
extern int afs_fs_setattr(struct afs_fs_cursor *, struct iattr *);
extern int afs_fs_get_volume_status(struct afs_fs_cursor *, struct afs_volume_status *);
@@ -889,7 +874,6 @@ extern int afs_check_volume_status(struct afs_volume *, struct key *);
 * write.c
 */
extern int afs_set_page_dirty(struct page *);
extern void afs_put_writeback(struct afs_writeback *);
extern int afs_write_begin(struct file *file, struct address_space *mapping,
			loff_t pos, unsigned len, unsigned flags,
			struct page **pagep, void **fsdata);
@@ -900,9 +884,10 @@ extern int afs_writepage(struct page *, struct writeback_control *);
extern int afs_writepages(struct address_space *, struct writeback_control *);
extern void afs_pages_written_back(struct afs_vnode *, struct afs_call *);
extern ssize_t afs_file_write(struct kiocb *, struct iov_iter *);
extern int afs_writeback_all(struct afs_vnode *);
extern int afs_flush(struct file *, fl_owner_t);
extern int afs_fsync(struct file *, loff_t, loff_t, int);
extern void afs_prune_wb_keys(struct afs_vnode *);
extern int afs_launder_page(struct page *);

/*
 * xattr.c
+2 −2
Original line number Diff line number Diff line
@@ -546,9 +546,9 @@ static void afs_i_init_once(void *_vnode)
	inode_init_once(&vnode->vfs_inode);
	mutex_init(&vnode->io_lock);
	mutex_init(&vnode->validate_lock);
	spin_lock_init(&vnode->writeback_lock);
	spin_lock_init(&vnode->wb_lock);
	spin_lock_init(&vnode->lock);
	INIT_LIST_HEAD(&vnode->writebacks);
	INIT_LIST_HEAD(&vnode->wb_keys);
	INIT_LIST_HEAD(&vnode->pending_locks);
	INIT_LIST_HEAD(&vnode->granted_locks);
	INIT_DELAYED_WORK(&vnode->lock_work, afs_lock_work);
Loading