@@ -216,7 +216,7 @@ static int handle_create(const char *nodename, umode_t mode, kuid_t uid,
newattrs.ia_gid = gid;
newattrs.ia_valid = ATTR_MODE|ATTR_UID|ATTR_GID;
inode_lock(d_inode(dentry));
- notify_change(dentry, &newattrs, NULL);
+ notify_change(dentry, &newattrs, NULL, NULL);
inode_unlock(d_inode(dentry));
/* mark as kernel-created inode */
@@ -323,9 +323,9 @@ static int handle_remove(const char *nodename, struct device *dev)
newattrs.ia_valid =
ATTR_UID|ATTR_GID|ATTR_MODE;
inode_lock(d_inode(dentry));
- notify_change(dentry, &newattrs, NULL);
+ notify_change(dentry, &newattrs, NULL, NULL);
inode_unlock(d_inode(dentry));
- err = vfs_unlink(d_inode(parent.dentry), dentry, NULL);
+ err = vfs_unlink(d_inode(parent.dentry), dentry, NULL, NULL);
if (!err || err == -ENOENT)
deleted = 1;
}
@@ -185,6 +185,7 @@ EXPORT_SYMBOL(setattr_copy);
* notify_change - modify attributes of a filesytem object
* @dentry: object affected
* @iattr: new attributes
+ * @owner: allow delegations to this owner to remain
* @delegated_inode: returns inode, if the inode is delegated
*
* The caller must hold the i_mutex on the affected object.
@@ -201,7 +202,7 @@ EXPORT_SYMBOL(setattr_copy);
* the file open for write, as there can be no conflicting delegation in
* that case.
*/
-int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **delegated_inode)
+int notify_change(struct dentry * dentry, struct iattr * attr, fl_owner_t owner, struct inode **delegated_inode)
{
struct inode *inode = dentry->d_inode;
umode_t mode = inode->i_mode;
@@ -304,7 +305,7 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
error = security_inode_setattr(dentry, attr);
if (error)
return error;
- error = try_break_deleg(inode, delegated_inode);
+ error = try_break_deleg(inode, owner, delegated_inode);
if (error)
return error;
@@ -1788,7 +1788,7 @@ static int __remove_privs(struct dentry *dentry, int kill)
* Note we call this on write, so notify_change will not
* encounter any conflicting delegations:
*/
- return notify_change(dentry, &newattrs, NULL);
+ return notify_change(dentry, &newattrs, NULL, NULL);
}
/*
@@ -1408,6 +1408,8 @@ static bool leases_conflict(struct file_lock *lease, struct file_lock *breaker)
return false;
if ((breaker->fl_flags & FL_DELEG) && (lease->fl_flags & FL_LEASE))
return false;
+ if (breaker->fl_owner && breaker->fl_owner == lease->fl_owner)
+ return false;
return locks_conflict(breaker, lease);
}
@@ -1429,6 +1431,7 @@ any_leases_conflict(struct inode *inode, struct file_lock *breaker)
/**
* __break_lease - revoke all outstanding leases on file
* @inode: the inode of the file to return
+ * @owner: if non-NULL, ignore leases held by this owner.
* @mode: O_RDONLY: break only write leases; O_WRONLY or O_RDWR:
* break all leases
* @type: FL_LEASE: break leases and delegations; FL_DELEG: break
@@ -1439,7 +1442,7 @@ any_leases_conflict(struct inode *inode, struct file_lock *breaker)
* a call to open() or truncate(). This function can sleep unless you
* specified %O_NONBLOCK to your open().
*/
-int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
+int __break_lease(struct inode *inode, fl_owner_t owner, unsigned int mode, unsigned int type)
{
int error = 0;
struct file_lock_context *ctx;
@@ -1452,6 +1455,7 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
if (IS_ERR(new_fl))
return PTR_ERR(new_fl);
new_fl->fl_flags = type;
+ new_fl->fl_owner = owner;
/* typically we will check that ctx is non-NULL before calling */
ctx = smp_load_acquire(&inode->i_flctx);
@@ -3941,6 +3941,7 @@ SYSCALL_DEFINE1(rmdir, const char __user *, pathname)
* vfs_unlink - unlink a filesystem object
* @dir: parent directory
* @dentry: victim
+ * @owner: allow delegation to this owner to remain.
* @delegated_inode: returns victim inode, if the inode is delegated.
*
* The caller must hold dir->i_mutex.
@@ -3955,7 +3956,7 @@ SYSCALL_DEFINE1(rmdir, const char __user *, pathname)
* be appropriate for callers that expect the underlying filesystem not
* to be NFS exported.
*/
-int vfs_unlink(struct inode *dir, struct dentry *dentry, struct inode **delegated_inode)
+int vfs_unlink(struct inode *dir, struct dentry *dentry, fl_owner_t owner, struct inode **delegated_inode)
{
struct inode *target = dentry->d_inode;
int error = may_delete(dir, dentry, 0);
@@ -3972,7 +3973,7 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry, struct inode **delegate
else {
error = security_inode_unlink(dir, dentry);
if (!error) {
- error = try_break_deleg(target, delegated_inode);
+ error = try_break_deleg(target, owner, delegated_inode);
if (error)
goto out;
error = dir->i_op->unlink(dir, dentry);
@@ -4040,7 +4041,7 @@ static long do_unlinkat(int dfd, const char __user *pathname)
error = security_path_unlink(&path, dentry);
if (error)
goto exit2;
- error = vfs_unlink(path.dentry->d_inode, dentry, &delegated_inode);
+ error = vfs_unlink(path.dentry->d_inode, dentry, NULL, &delegated_inode);
exit2:
dput(dentry);
}
@@ -4049,7 +4050,7 @@ static long do_unlinkat(int dfd, const char __user *pathname)
iput(inode); /* truncate the inode here */
inode = NULL;
if (delegated_inode) {
- error = break_deleg_wait(&delegated_inode);
+ error = break_deleg_wait(NULL, &delegated_inode);
if (!error)
goto retry_deleg;
}
@@ -4152,6 +4153,7 @@ SYSCALL_DEFINE2(symlink, const char __user *, oldname, const char __user *, newn
* @old_dentry: object to be linked
* @dir: new parent
* @new_dentry: where to create the new link
+ * @owner: allow delegation to this owner to remain
* @delegated_inode: returns inode needing a delegation break
*
* The caller must hold dir->i_mutex
@@ -4166,7 +4168,8 @@ SYSCALL_DEFINE2(symlink, const char __user *, oldname, const char __user *, newn
* be appropriate for callers that expect the underlying filesystem not
* to be NFS exported.
*/
-int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry, struct inode **delegated_inode)
+int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry,
+ fl_owner_t owner, struct inode **delegated_inode)
{
struct inode *inode = old_dentry->d_inode;
unsigned max_links = dir->i_sb->s_max_links;
@@ -4210,7 +4213,7 @@ int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_de
else if (max_links && inode->i_nlink >= max_links)
error = -EMLINK;
else {
- error = try_break_deleg(inode, delegated_inode);
+ error = try_break_deleg(inode, owner, delegated_inode);
if (!error)
error = dir->i_op->link(old_dentry, dir, new_dentry);
}
@@ -4280,11 +4283,11 @@ SYSCALL_DEFINE5(linkat, int, olddfd, const char __user *, oldname,
error = security_path_link(old_path.dentry, &new_path, new_dentry);
if (error)
goto out_dput;
- error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry, &delegated_inode);
+ error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry, NULL, &delegated_inode);
out_dput:
done_path_create(&new_path, new_dentry);
if (delegated_inode) {
- error = break_deleg_wait(&delegated_inode);
+ error = break_deleg_wait(NULL, &delegated_inode);
if (!error) {
path_put(&old_path);
goto retry;
@@ -4312,6 +4315,7 @@ SYSCALL_DEFINE2(link, const char __user *, oldname, const char __user *, newname
* @old_dentry: source
* @new_dir: parent of destination
* @new_dentry: destination
+ * @owner: allow delegation to this owner to remain
* @delegated_inode: returns an inode needing a delegation break
* @flags: rename flags
*
@@ -4358,6 +4362,7 @@ SYSCALL_DEFINE2(link, const char __user *, oldname, const char __user *, newname
*/
int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry,
+ fl_owner_t owner,
struct inode **delegated_inode, unsigned int flags)
{
int error;
@@ -4435,12 +4440,12 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (is_dir && !(flags & RENAME_EXCHANGE) && target)
shrink_dcache_parent(new_dentry);
if (!is_dir) {
- error = try_break_deleg(source, delegated_inode);
+ error = try_break_deleg(source, owner, delegated_inode);
if (error)
goto out;
}
if (target && !new_is_dir) {
- error = try_break_deleg(target, delegated_inode);
+ error = try_break_deleg(target, owner, delegated_inode);
if (error)
goto out;
}
@@ -4594,7 +4599,7 @@ SYSCALL_DEFINE5(renameat2, int, olddfd, const char __user *, oldname,
goto exit5;
error = vfs_rename(old_path.dentry->d_inode, old_dentry,
new_path.dentry->d_inode, new_dentry,
- &delegated_inode, flags);
+ NULL, &delegated_inode, flags);
exit5:
dput(new_dentry);
exit4:
@@ -4602,7 +4607,7 @@ SYSCALL_DEFINE5(renameat2, int, olddfd, const char __user *, oldname,
exit3:
unlock_rename(new_path.dentry, old_path.dentry);
if (delegated_inode) {
- error = break_deleg_wait(&delegated_inode);
+ error = break_deleg_wait(NULL, &delegated_inode);
if (!error)
goto retry_deleg;
}
@@ -3654,6 +3654,27 @@ find_file_locked(struct knfsd_fh *fh, unsigned int hashval)
return NULL;
}
+static struct nfs4_file *
+find_deleg_file_by_inode(struct inode *ino)
+{
+ int i;
+ struct nfs4_file *fp;
+
+ if (!ino)
+ return NULL;
+
+ rcu_read_lock();
+ for (i = 0; i < FILE_HASH_SIZE; i++)
+ hlist_for_each_entry_rcu(fp, &file_hashtbl[i], fi_hash)
+ if (fp->fi_deleg_file && file_inode(fp->fi_deleg_file) == ino)
+ if (atomic_inc_not_zero(&fp->fi_ref)) {
+ rcu_read_unlock();
+ return fp;
+ }
+
+ return NULL;
+}
+
struct nfs4_file *
find_file(struct knfsd_fh *fh)
{
@@ -3825,6 +3846,49 @@ nfsd_break_deleg_cb(struct file_lock *fl)
return ret;
}
+static struct nfs4_client *nfsd4_client_from_rqst(struct svc_rqst *rqst)
+{
+ struct nfsd4_compoundres *resp;
+
+ /*
+ * In case it's possible we could be called from NLM or ACL
+ * code?:
+ */
+ if (rqst->rq_prog != NFS_PROGRAM)
+ return NULL;
+ if (rqst->rq_vers != 4)
+ return NULL;
+ resp = rqst->rq_resp;
+ return resp->cstate.clp;
+}
+
+int nfsd_conflicting_leases(struct dentry *dentry, struct svc_rqst *rqstp)
+{
+ struct nfs4_client *cl;
+ struct nfs4_delegation *dl;
+ struct nfs4_file *fi;
+ bool conflict;
+
+ cl = nfsd4_client_from_rqst(rqstp);
+ if (!cl)
+ return 0;
+ fi = find_deleg_file_by_inode(d_inode(dentry));
+ if (!fi)
+ return 0;
+
+ spin_lock(&fi->fi_lock);
+ conflict = false;
+ list_for_each_entry(dl, &fi->fi_delegations, dl_perfile) {
+ if (dl->dl_stid.sc_client != cl) {
+ fi->fi_had_conflict = true;
+ nfsd_break_one_deleg(dl);
+ conflict = true;
+ }
+ }
+ spin_unlock(&fi->fi_lock);
+ return conflict ? -EWOULDBLOCK : 0;
+}
+
static int
nfsd_change_deleg_cb(struct file_lock *onlist, int arg,
struct list_head *dispose)
@@ -4137,6 +4201,8 @@ static bool nfsd4_cb_channel_good(struct nfs4_client *clp)
return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN;
}
+char nfsd_deleg_owner[1];
+
static struct file_lock *nfs4_alloc_init_lease(struct nfs4_file *fp, int flag)
{
struct file_lock *fl;
@@ -4148,7 +4214,7 @@ static struct file_lock *nfs4_alloc_init_lease(struct nfs4_file *fp, int flag)
fl->fl_flags = FL_DELEG;
fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
fl->fl_end = OFFSET_MAX;
- fl->fl_owner = (fl_owner_t)fp;
+ fl->fl_owner = (fl_owner_t)nfsd_deleg_owner;
fl->fl_pid = current->tgid;
return fl;
}
@@ -75,6 +75,9 @@ struct raparm_hbucket {
#define RAPARM_HASH_MASK (RAPARM_HASH_SIZE-1)
static struct raparm_hbucket raparm_hash[RAPARM_HASH_SIZE];
+bool nfsd_conflicting_leases(struct dentry *dentry, struct svc_rqst *rqstp);
+extern char nfsd_deleg_owner[1];
+
/*
* Called from nfsd_lookup and encode_dirent. Check if we have crossed
* a mount point.
@@ -455,7 +458,8 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
.ia_size = iap->ia_size,
};
- host_err = notify_change(dentry, &size_attr, NULL);
+ host_err = nfsd_conflicting_leases(dentry, rqstp);
+ host_err = host_err ?: notify_change(dentry, &size_attr, nfsd_deleg_owner, NULL);
if (host_err)
goto out_unlock;
iap->ia_valid &= ~ATTR_SIZE;
@@ -470,7 +474,8 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
}
iap->ia_valid |= ATTR_CTIME;
- host_err = notify_change(dentry, iap, NULL);
+ host_err = nfsd_conflicting_leases(dentry, rqstp);
+ host_err = host_err ?: notify_change(dentry, iap, nfsd_deleg_owner, NULL);
out_unlock:
fh_unlock(fhp);
@@ -1590,7 +1595,8 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
err = nfserr_noent;
if (d_really_is_negative(dold))
goto out_dput;
- host_err = vfs_link(dold, dirp, dnew, NULL);
+ host_err = nfsd_conflicting_leases(dold, rqstp);
+ host_err = host_err ?: vfs_link(dold, dirp, dnew, nfsd_deleg_owner, NULL);
if (!host_err) {
err = nfserrno(commit_metadata(ffhp));
if (!err)
@@ -1683,7 +1689,9 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
if (ffhp->fh_export->ex_path.dentry != tfhp->fh_export->ex_path.dentry)
goto out_dput_new;
- host_err = vfs_rename(fdir, odentry, tdir, ndentry, NULL, 0);
+ host_err = nfsd_conflicting_leases(odentry, rqstp);
+ host_err |= nfsd_conflicting_leases(ndentry, rqstp);
+ host_err = host_err ?: vfs_rename(fdir, odentry, tdir, ndentry, nfsd_deleg_owner, NULL, 0);
if (!host_err) {
host_err = commit_metadata(tfhp);
if (!host_err)
@@ -1752,9 +1760,10 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
if (!type)
type = d_inode(rdentry)->i_mode & S_IFMT;
- if (type != S_IFDIR)
- host_err = vfs_unlink(dirp, rdentry, NULL);
- else
+ if (type != S_IFDIR) {
+ host_err = nfsd_conflicting_leases(dentry, rqstp);
+ host_err = host_err ?: vfs_unlink(dirp, rdentry, nfsd_deleg_owner, NULL);
+ } else
host_err = vfs_rmdir(dirp, rdentry);
if (!host_err)
host_err = commit_metadata(fhp);
@@ -60,7 +60,7 @@ int do_truncate(struct dentry *dentry, loff_t length, unsigned int time_attrs,
inode_lock(dentry->d_inode);
/* Note any delegations or leases have already been broken: */
- ret = notify_change(dentry, &newattrs, NULL);
+ ret = notify_change(dentry, &newattrs, NULL, NULL);
inode_unlock(dentry->d_inode);
return ret;
}
@@ -529,11 +529,11 @@ static int chmod_common(const struct path *path, umode_t mode)
goto out_unlock;
newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
- error = notify_change(path->dentry, &newattrs, &delegated_inode);
+ error = notify_change(path->dentry, &newattrs, NULL, &delegated_inode);
out_unlock:
inode_unlock(inode);
if (delegated_inode) {
- error = break_deleg_wait(&delegated_inode);
+ error = break_deleg_wait(NULL, &delegated_inode);
if (!error)
goto retry_deleg;
}
@@ -609,10 +609,10 @@ static int chown_common(const struct path *path, uid_t user, gid_t group)
inode_lock(inode);
error = security_path_chown(path, uid, gid);
if (!error)
- error = notify_change(path->dentry, &newattrs, &delegated_inode);
+ error = notify_change(path->dentry, &newattrs, NULL, &delegated_inode);
inode_unlock(inode);
if (delegated_inode) {
- error = break_deleg_wait(&delegated_inode);
+ error = break_deleg_wait(NULL, &delegated_inode);
if (!error)
goto retry_deleg;
}
@@ -87,10 +87,10 @@ static int utimes_common(const struct path *path, struct timespec *times)
}
retry_deleg:
inode_lock(inode);
- error = notify_change(path->dentry, &newattrs, &delegated_inode);
+ error = notify_change(path->dentry, &newattrs, NULL, &delegated_inode);
inode_unlock(inode);
if (delegated_inode) {
- error = break_deleg_wait(&delegated_inode);
+ error = break_deleg_wait(NULL, &delegated_inode);
if (!error)
goto retry_deleg;
}
@@ -1084,7 +1084,7 @@ extern int vfs_test_lock(struct file *, struct file_lock *);
extern int vfs_lock_file(struct file *, unsigned int, struct file_lock *, struct file_lock *);
extern int vfs_cancel_lock(struct file *filp, struct file_lock *fl);
extern int locks_lock_inode_wait(struct inode *inode, struct file_lock *fl);
-extern int __break_lease(struct inode *inode, unsigned int flags, unsigned int type);
+extern int __break_lease(struct inode *inode, fl_owner_t owner, unsigned int flags, unsigned int type);
extern void lease_get_mtime(struct inode *, struct timespec *time);
extern int generic_setlease(struct file *, long, struct file_lock **, void **priv);
extern int vfs_setlease(struct file *, long, struct file_lock **, void **);
@@ -1195,7 +1195,7 @@ static inline int locks_lock_inode_wait(struct inode *inode, struct file_lock *f
return -ENOLCK;
}
-static inline int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
+static inline int __break_lease(struct inode *inode, fl_owner_t owner, unsigned int mode, unsigned int type)
{
return 0;
}
@@ -1573,10 +1573,10 @@ extern int vfs_create(struct inode *, struct dentry *, umode_t, bool);
extern int vfs_mkdir(struct inode *, struct dentry *, umode_t);
extern int vfs_mknod(struct inode *, struct dentry *, umode_t, dev_t);
extern int vfs_symlink(struct inode *, struct dentry *, const char *);
-extern int vfs_link(struct dentry *, struct inode *, struct dentry *, struct inode **);
+extern int vfs_link(struct dentry *, struct inode *, struct dentry *, fl_owner_t, struct inode **);
extern int vfs_rmdir(struct inode *, struct dentry *);
-extern int vfs_unlink(struct inode *, struct dentry *, struct inode **);
-extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *, struct inode **, unsigned int);
+extern int vfs_unlink(struct inode *, struct dentry *, fl_owner_t, struct inode **);
+extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *, fl_owner_t, struct inode **, unsigned int);
extern int vfs_whiteout(struct inode *, struct dentry *);
extern struct dentry *vfs_tmpfile(struct dentry *dentry, umode_t mode,
@@ -2260,11 +2260,11 @@ static inline int break_lease(struct inode *inode, unsigned int mode)
*/
smp_mb();
if (inode->i_flctx && !list_empty_careful(&inode->i_flctx->flc_lease))
- return __break_lease(inode, mode, FL_LEASE);
+ return __break_lease(inode, NULL, mode, FL_LEASE);
return 0;
}
-static inline int break_deleg(struct inode *inode, unsigned int mode)
+static inline int break_deleg(struct inode *inode, fl_owner_t owner, unsigned int mode)
{
/*
* Since this check is lockless, we must ensure that any refcounts
@@ -2274,15 +2274,15 @@ static inline int break_deleg(struct inode *inode, unsigned int mode)
*/
smp_mb();
if (inode->i_flctx && !list_empty_careful(&inode->i_flctx->flc_lease))
- return __break_lease(inode, mode, FL_DELEG);
+ return __break_lease(inode, owner, mode, FL_DELEG);
return 0;
}
-static inline int try_break_deleg(struct inode *inode, struct inode **delegated_inode)
+static inline int try_break_deleg(struct inode *inode, fl_owner_t owner, struct inode **delegated_inode)
{
int ret;
- ret = break_deleg(inode, O_WRONLY|O_NONBLOCK);
+ ret = break_deleg(inode, owner, O_WRONLY|O_NONBLOCK);
if (ret == -EWOULDBLOCK && delegated_inode) {
*delegated_inode = inode;
ihold(inode);
@@ -2290,11 +2290,11 @@ static inline int try_break_deleg(struct inode *inode, struct inode **delegated_
return ret;
}
-static inline int break_deleg_wait(struct inode **delegated_inode)
+static inline int break_deleg_wait(fl_owner_t owner, struct inode **delegated_inode)
{
int ret;
- ret = break_deleg(*delegated_inode, O_WRONLY);
+ ret = break_deleg(*delegated_inode, owner, O_WRONLY);
iput(*delegated_inode);
*delegated_inode = NULL;
return ret;
@@ -2304,7 +2304,7 @@ static inline int break_layout(struct inode *inode, bool wait)
{
smp_mb();
if (inode->i_flctx && !list_empty_careful(&inode->i_flctx->flc_lease))
- return __break_lease(inode,
+ return __break_lease(inode, NULL,
wait ? O_WRONLY : O_WRONLY | O_NONBLOCK,
FL_LAYOUT);
return 0;
@@ -2316,17 +2316,17 @@ static inline int break_lease(struct inode *inode, unsigned int mode)
return 0;
}
-static inline int break_deleg(struct inode *inode, unsigned int mode)
+static inline int break_deleg(struct inode *inode, fl_owner_t owner, unsigned int mode)
{
return 0;
}
-static inline int try_break_deleg(struct inode *inode, struct inode **delegated_inode)
+static inline int try_break_deleg(struct inode *inode, fl_owner_t owner, struct inode **delegated_inode)
{
return 0;
}
-static inline int break_deleg_wait(struct inode **delegated_inode)
+static inline int break_deleg_wait(fl_owner_t owner, struct inode **delegated_inode)
{
BUG();
return 0;
@@ -2643,7 +2643,7 @@ extern void emergency_remount(void);
#ifdef CONFIG_BLOCK
extern sector_t bmap(struct inode *, sector_t);
#endif
-extern int notify_change(struct dentry *, struct iattr *, struct inode **);
+extern int notify_change(struct dentry *, struct iattr *, fl_owner_t, struct inode **);
extern int inode_permission(struct inode *, int);
extern int __inode_permission(struct inode *, int);
extern int generic_permission(struct inode *, int);