* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Whamcloud, Inc.
+ * Copyright (c) 2011, 2013, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/mm.h>
-#include <linux/smp_lock.h>
#include <linux/quotaops.h>
#include <linux/highmem.h>
#include <linux/pagemap.h>
#include <lustre_ver.h>
#include "llite_internal.h"
+static int ll_create_it(struct inode *, struct dentry *,
+ int, struct lookup_intent *);
+
/*
* Check if we have something mounted at the named dchild.
* In such a case there would always be dentry present.
ll_read_inode2(inode, md);
if (S_ISREG(inode->i_mode) &&
- ll_i2info(inode)->lli_clob == NULL)
+ ll_i2info(inode)->lli_clob == NULL) {
+ CDEBUG(D_INODE,
+ "%s: apply lsm %p to inode "DFID".\n",
+ ll_get_fsname(sb, NULL, 0), md->lsm,
+ PFID(ll_inode2fid(inode)));
rc = cl_file_inode_init(inode, md);
+ }
if (rc != 0) {
- md->lsm = NULL;
make_bad_inode(inode);
unlock_new_inode(inode);
iput(inode);
static void ll_invalidate_negative_children(struct inode *dir)
{
struct dentry *dentry, *tmp_subdir;
+ struct ll_d_hlist_node *p;
ll_lock_dcache(dir);
- list_for_each_entry(dentry, &dir->i_dentry, d_alias) {
+ ll_d_hlist_for_each_entry(dentry, p, &dir->i_dentry, d_alias) {
spin_lock(&dentry->d_lock);
if (!list_empty(&dentry->d_subdirs)) {
struct dentry *child;
list_for_each_entry_safe(child, tmp_subdir,
&dentry->d_subdirs,
- d_child) {
+ d_u.d_child) {
if (child->d_inode == NULL)
- d_lustre_invalidate(child);
+ d_lustre_invalidate(child, 1);
}
}
spin_unlock(&dentry->d_lock);
switch (flag) {
case LDLM_CB_BLOCKING:
ldlm_lock2handle(lock, &lockh);
- rc = ldlm_cli_cancel(&lockh);
+ rc = ldlm_cli_cancel(&lockh, LCF_ASYNC);
if (rc < 0) {
CDEBUG(D_INODE, "ldlm_cli_cancel: %d\n", rc);
RETURN(rc);
}
break;
case LDLM_CB_CANCELING: {
- struct inode *inode = ll_inode_from_lock(lock);
+ struct inode *inode = ll_inode_from_resource_lock(lock);
struct ll_inode_info *lli;
__u64 bits = lock->l_policy_data.l_inodebits.bits;
struct lu_fid *fid;
ldlm_mode_t mode = lock->l_req_mode;
+ /* Inode is set to lock->l_resource->lr_lvb_inode
+ * for mdc - bug 24555 */
+ LASSERT(lock->l_ast_data == NULL);
+
/* Invalidate all dentries associated with this inode */
if (inode == NULL)
break;
LASSERT(lock->l_flags & LDLM_FL_CANCELING);
- /* For OPEN locks we differentiate between lock modes - CR, CW. PR - bug 22891 */
- if (bits & (MDS_INODELOCK_LOOKUP | MDS_INODELOCK_UPDATE))
+ /* For OPEN locks we differentiate between lock modes
+ * LCK_CR, LCK_CW, LCK_PR - bug 22891 */
+ if (bits & (MDS_INODELOCK_LOOKUP | MDS_INODELOCK_UPDATE |
+ MDS_INODELOCK_LAYOUT | MDS_INODELOCK_PERM))
ll_have_md_lock(inode, &bits, LCK_MINMODE);
if (bits & MDS_INODELOCK_OPEN)
ll_md_real_close(inode, flags);
}
- lli = ll_i2info(inode);
+ lli = ll_i2info(inode);
+ if (bits & MDS_INODELOCK_LAYOUT) {
+ struct cl_object_conf conf = { { 0 } };
+
+ conf.coc_opc = OBJECT_CONF_INVALIDATE;
+ conf.coc_inode = inode;
+ rc = ll_layout_conf(inode, &conf);
+ if (rc)
+ CDEBUG(D_INODE, "invaliding layout %d.\n", rc);
+ }
+
if (bits & MDS_INODELOCK_UPDATE)
lli->lli_flags &= ~LLIF_MDS_SIZE_LOCK;
if (inode->i_sb->s_root &&
inode != inode->i_sb->s_root->d_inode &&
- (bits & MDS_INODELOCK_LOOKUP))
+ (bits & (MDS_INODELOCK_LOOKUP | MDS_INODELOCK_PERM)))
ll_invalidate_aliases(inode);
iput(inode);
break;
static struct dentry *ll_find_alias(struct inode *inode, struct dentry *dentry)
{
struct dentry *alias, *discon_alias, *invalid_alias;
+ struct ll_d_hlist_node *p;
- if (list_empty(&inode->i_dentry))
+ if (ll_d_hlist_empty(&inode->i_dentry))
return NULL;
discon_alias = invalid_alias = NULL;
ll_lock_dcache(inode);
- list_for_each_entry(alias, &inode->i_dentry, d_alias) {
+ ll_d_hlist_for_each_entry(alias, p, &inode->i_dentry, d_alias) {
LASSERT(alias != dentry);
spin_lock(&alias->d_lock);
}
/*
- * Similar to d_splice_alias(), but lustre treats DCACHE_LUSTRE_INVALID alias
+ * Similar to d_splice_alias(), but lustre treats invalid alias
* similar to DCACHE_DISCONNECTED, and tries to use it anyway.
*/
struct dentry *ll_splice_alias(struct inode *inode, struct dentry *de)
return new;
}
}
- __d_lustre_invalidate(de);
ll_dops_init(de, 1, 1);
+ __d_lustre_invalidate(de);
d_add(de, inode);
CDEBUG(D_DENTRY, "Add dentry %p inode %p refc %d flags %#x\n",
de, de->d_inode, d_refcount(de), de->d_flags);
/* NB 1 request reference will be taken away by ll_intent_lock()
* when I return */
+ CDEBUG(D_DENTRY, "it %p it_disposition %x\n", it,
+ it->d.lustre.it_disposition);
if (!it_disposition(it, DISP_LOOKUP_NEG)) {
- rc = ll_prep_inode(&inode, request, (*de)->d_sb);
+ rc = ll_prep_inode(&inode, request, (*de)->d_sb, it);
if (rc)
RETURN(rc);
Also see bug 7198. */
}
- *de = ll_splice_alias(inode, *de);
+ /* Only hash *de if it is unhashed (new dentry).
+ * Atoimc_open may passin hashed dentries for open.
+ */
+ if (d_unhashed(*de))
+ *de = ll_splice_alias(inode, *de);
if (!it_disposition(it, DISP_LOOKUP_NEG)) {
/* we have lookup look - unhide dentry */
if (bits & MDS_INODELOCK_LOOKUP)
d_lustre_revalidate(*de);
- } else {
+ } else if (!it_disposition(it, DISP_OPEN_CREATE)) {
+ /* If file created on server, don't depend on parent UPDATE
+ * lock to unhide it. It is left hidden and next lookup can
+ * find it in ll_splice_alias.
+ */
/* Check that parent has UPDATE lock. */
struct lookup_intent parent_it = {
.it_op = IT_GETATTR,
if (IS_ERR(op_data))
RETURN((void *)op_data);
- it->it_create_mode &= ~cfs_curproc_umask();
+ /* enforce umask if acl disabled or MDS doesn't support umask */
+ if (!IS_POSIXACL(parent) || !exp_connect_umask(ll_i2mdexp(parent)))
+ it->it_create_mode &= ~cfs_curproc_umask();
rc = md_intent_lock(ll_i2mdexp(parent), op_data, NULL, 0, it,
lookup_flags, &req, ll_md_blocking_ast, 0);
return retval;
}
+#ifdef HAVE_IOP_ATOMIC_OPEN
+static struct dentry *ll_lookup_nd(struct inode *parent, struct dentry *dentry,
+ unsigned int flags)
+{
+ struct lookup_intent *itp, it = { .it_op = IT_GETATTR };
+ struct dentry *de;
+
+ CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p),flags=%u\n",
+ dentry->d_name.len, dentry->d_name.name, parent->i_ino,
+ parent->i_generation, parent, flags);
+
+ /* Optimize away (CREATE && !OPEN). Let .create handle the race. */
+ if ((flags & LOOKUP_CREATE ) && !(flags & LOOKUP_OPEN)) {
+ ll_dops_init(dentry, 1, 1);
+ __d_lustre_invalidate(dentry);
+ d_add(dentry, NULL);
+ return NULL;
+ }
+
+ if (flags & (LOOKUP_PARENT|LOOKUP_OPEN|LOOKUP_CREATE))
+ itp = NULL;
+ else
+ itp = ⁢
+ de = ll_lookup_it(parent, dentry, itp, 0);
+
+ if (itp != NULL)
+ ll_intent_release(itp);
+
+ return de;
+}
+
+/*
+ * For cached negative dentry and new dentry, handle lookup/create/open
+ * together.
+ */
+static int ll_atomic_open(struct inode *dir, struct dentry *dentry,
+ struct file *file, unsigned open_flags,
+ umode_t mode, int *opened)
+{
+ struct lookup_intent *it;
+ struct dentry *de;
+ long long lookup_flags = LOOKUP_OPEN;
+ int rc = 0;
+ ENTRY;
+
+ CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p),file %p,"
+ "open_flags %x,mode %x opened %d\n",
+ dentry->d_name.len, dentry->d_name.name, dir->i_ino,
+ dir->i_generation, dir, file, open_flags, mode, *opened);
+
+ OBD_ALLOC(it, sizeof(*it));
+ if (!it)
+ RETURN(-ENOMEM);
+
+ it->it_op = IT_OPEN;
+ if (mode) {
+ it->it_op |= IT_CREAT;
+ lookup_flags |= LOOKUP_CREATE;
+ }
+ it->it_create_mode = (mode & S_IALLUGO) | S_IFREG;
+ it->it_flags = (open_flags & ~O_ACCMODE) | OPEN_FMODE(open_flags);
+
+ /* Dentry added to dcache tree in ll_lookup_it */
+ de = ll_lookup_it(dir, dentry, it, lookup_flags);
+ if (IS_ERR(de))
+ rc = PTR_ERR(de);
+ else if (de != NULL)
+ dentry = de;
+
+ if (!rc) {
+ if (it_disposition(it, DISP_OPEN_CREATE)) {
+ /* Dentry instantiated in ll_create_it. */
+ rc = ll_create_it(dir, dentry, mode, it);
+ if (rc) {
+ /* We dget in ll_splice_alias. */
+ if (de != NULL)
+ dput(de);
+ goto out_release;
+ }
+
+ *opened |= FILE_CREATED;
+ }
+ if (dentry->d_inode && it_disposition(it, DISP_OPEN_OPEN)) {
+ /* Open dentry. */
+ if (S_ISFIFO(dentry->d_inode->i_mode)) {
+ /* We cannot call open here as it would
+ * deadlock.
+ */
+ if (it_disposition(it, DISP_ENQ_OPEN_REF))
+ ptlrpc_req_finished(
+ (struct ptlrpc_request *)
+ it->d.lustre.it_data);
+ rc = finish_no_open(file, de);
+ } else {
+ file->private_data = it;
+ rc = finish_open(file, dentry, NULL, opened);
+ /* We dget in ll_splice_alias. finish_open takes
+ * care of dget for fd open.
+ */
+ if (de != NULL)
+ dput(de);
+ }
+ } else {
+ rc = finish_no_open(file, de);
+ }
+ }
+
+out_release:
+ ll_intent_release(it);
+ OBD_FREE(it, sizeof(*it));
+
+ RETURN(rc);
+}
+
+#else /* !HAVE_IOP_ATOMIC_OPEN */
struct lookup_intent *ll_convert_intent(struct open_intent *oit,
int lookup_flags)
{
- struct lookup_intent *it;
-
- OBD_ALLOC(it, sizeof(*it));
- if (!it)
- return ERR_PTR(-ENOMEM);
-
- if (lookup_flags & LOOKUP_OPEN) {
- it->it_op = IT_OPEN;
- if (lookup_flags & LOOKUP_CREATE)
- it->it_op |= IT_CREAT;
- it->it_create_mode = (oit->create_mode & S_IALLUGO) | S_IFREG;
- it->it_flags = oit->flags;
- } else {
- it->it_op = IT_GETATTR;
- }
+ struct lookup_intent *it;
+
+ OBD_ALLOC(it, sizeof(*it));
+ if (!it)
+ return ERR_PTR(-ENOMEM);
+
+ if (lookup_flags & LOOKUP_OPEN) {
+ it->it_op = IT_OPEN;
+ if (lookup_flags & LOOKUP_CREATE)
+ it->it_op |= IT_CREAT;
+ it->it_create_mode = (oit->create_mode & S_IALLUGO) | S_IFREG;
+ it->it_flags = ll_namei_to_lookup_intent_flag(oit->flags);
+ } else {
+ it->it_op = IT_GETATTR;
+ }
- return it;
+ return it;
}
static struct dentry *ll_lookup_nd(struct inode *parent, struct dentry *dentry,
if (nd && !(nd->flags & (LOOKUP_CONTINUE|LOOKUP_PARENT))) {
struct lookup_intent *it;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
- /* Did we came here from failed revalidate just to propagate
- * its error? */
- if (nd->flags & LOOKUP_OPEN)
- if (IS_ERR(nd->intent.open.file))
- RETURN((struct dentry *)nd->intent.open.file);
-#endif
if (ll_d2d(dentry) && ll_d2d(dentry)->lld_it) {
it = ll_d2d(dentry)->lld_it;
ll_d2d(dentry)->lld_it = NULL;
RETURN(de);
}
+#endif /* HAVE_IOP_ATOMIC_OPEN */
/* We depend on "mode" being set with the proper file type/umask by now */
static struct inode *ll_create_node(struct inode *dir, const char *name,
LASSERT(it_disposition(it, DISP_ENQ_CREATE_REF));
request = it->d.lustre.it_data;
it_clear_disposition(it, DISP_ENQ_CREATE_REF);
- rc = ll_prep_inode(&inode, request, dir->i_sb);
+ rc = ll_prep_inode(&inode, request, dir->i_sb, it);
if (rc)
GOTO(out, inode = ERR_PTR(rc));
- LASSERT(list_empty(&inode->i_dentry));
+ LASSERT(ll_d_hlist_empty(&inode->i_dentry));
/* We asked for a lock on the directory, but were granted a
* lock on the inode. Since we finally have an inode pointer,
* with d_instantiate().
*/
static int ll_create_it(struct inode *dir, struct dentry *dentry, int mode,
- struct lookup_intent *it)
+ struct lookup_intent *it)
{
- struct inode *inode;
- int rc = 0;
- ENTRY;
+ struct inode *inode;
+ int rc = 0;
+ ENTRY;
- CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p),intent=%s\n",
- dentry->d_name.len, dentry->d_name.name, dir->i_ino,
- dir->i_generation, dir, LL_IT2STR(it));
+ CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p),intent=%s\n",
+ dentry->d_name.len, dentry->d_name.name, dir->i_ino,
+ dir->i_generation, dir, LL_IT2STR(it));
- rc = it_open_error(DISP_OPEN_CREATE, it);
- if (rc)
- RETURN(rc);
+ rc = it_open_error(DISP_OPEN_CREATE, it);
+ if (rc)
+ RETURN(rc);
- inode = ll_create_node(dir, dentry->d_name.name, dentry->d_name.len,
- NULL, 0, mode, 0, it);
- if (IS_ERR(inode))
- RETURN(PTR_ERR(inode));
+ inode = ll_create_node(dir, dentry->d_name.name, dentry->d_name.len,
+ NULL, 0, mode, 0, it);
+ if (IS_ERR(inode))
+ RETURN(PTR_ERR(inode));
- d_instantiate(dentry, inode);
- RETURN(0);
+ if (filename_is_volatile(dentry->d_name.name, dentry->d_name.len, NULL))
+ ll_i2info(inode)->lli_volatile = true;
+
+ d_instantiate(dentry, inode);
+ RETURN(0);
}
static void ll_update_times(struct ptlrpc_request *request,
ll_update_times(request, dir);
if (dchild) {
- err = ll_prep_inode(&inode, request, dchild->d_sb);
+ err = ll_prep_inode(&inode, request, dchild->d_sb, NULL);
if (err)
GOTO(err_exit, err);
name->len, name->name, dir->i_ino, dir->i_generation, dir,
mode, rdev);
- mode &= ~cfs_curproc_umask();
+ if (!IS_POSIXACL(dir) || !exp_connect_umask(ll_i2mdexp(dir)))
+ mode &= ~cfs_curproc_umask();
switch (mode & S_IFMT) {
case 0:
RETURN(err);
}
+#ifdef HAVE_IOP_ATOMIC_OPEN
+/*
+ * Plain create. Intent create is handled in atomic_open.
+ */
static int ll_create_nd(struct inode *dir, struct dentry *dentry,
- int mode, struct nameidata *nd)
+ umode_t mode, bool want_excl)
+{
+ int rc;
+
+ CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p),"
+ "flags=%u, excl=%d\n",
+ dentry->d_name.len, dentry->d_name.name, dir->i_ino,
+ dir->i_generation, dir, mode, want_excl);
+
+ rc = ll_mknod_generic(dir, &dentry->d_name, mode, 0, dentry);
+
+ ll_stats_ops_tally(ll_i2sbi(dir), LPROC_LL_CREATE, 1);
+
+ CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s, unhashed %d\n",
+ dentry->d_name.len, dentry->d_name.name, d_unhashed(dentry));
+
+ return rc;
+}
+#else /* !HAVE_IOP_ATOMIC_OPEN */
+static int ll_create_nd(struct inode *dir, struct dentry *dentry,
+ ll_umode_t mode, struct nameidata *nd)
{
struct lookup_intent *it = ll_d2d(dentry)->lld_it;
int rc;
return rc;
}
+#endif /* HAVE_IOP_ATOMIC_OPEN */
static int ll_symlink_generic(struct inode *dir, struct qstr *name,
const char *tgt, struct dentry *dchild)
CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p)\n",
name->len, name->name, dir->i_ino, dir->i_generation, dir);
- mode = (mode & (S_IRWXUGO|S_ISVTX) & ~cfs_curproc_umask()) | S_IFDIR;
+ if (!IS_POSIXACL(dir) || !exp_connect_umask(ll_i2mdexp(dir)))
+ mode &= ~cfs_curproc_umask();
+ mode = (mode & (S_IRWXUGO|S_ISVTX)) | S_IFDIR;
err = ll_new_node(dir, name, NULL, mode, 0, dchild, LUSTRE_OPC_MKDIR);
if (!err)
static void ll_get_child_fid(struct inode * dir, struct qstr *name,
struct lu_fid *fid)
{
- struct dentry *parent, *child;
+ struct dentry *parent, *child;
- parent = list_entry(dir->i_dentry.next, struct dentry, d_alias);
- child = d_lookup(parent, name);
+ parent = ll_d_hlist_entry(dir->i_dentry, struct dentry, d_alias);
+ child = d_lookup(parent, name);
if (child) {
if (child->d_inode)
*fid = *ll_inode2fid(child->d_inode);
RETURN(PTR_ERR(op_data));
ll_get_child_fid(dir, name, &op_data->op_fid3);
+ op_data->op_fid2 = op_data->op_fid3;
rc = md_unlink(ll_i2sbi(dir)->ll_md_exp, op_data, &request);
ll_finish_md_op_data(op_data);
if (rc == 0) {
RETURN(rc);
}
+/**
+ * Remove dir entry
+ **/
+int ll_rmdir_entry(struct inode *dir, char *name, int namelen)
+{
+ struct ptlrpc_request *request = NULL;
+ struct md_op_data *op_data;
+ int rc;
+ ENTRY;
+
+ CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p)\n",
+ namelen, name, dir->i_ino, dir->i_generation, dir);
+
+ op_data = ll_prep_md_op_data(NULL, dir, NULL, name, strlen(name),
+ S_IFDIR, LUSTRE_OPC_ANY, NULL);
+ if (IS_ERR(op_data))
+ RETURN(PTR_ERR(op_data));
+ op_data->op_cli_flags |= CLI_RM_ENTRY;
+ rc = md_unlink(ll_i2sbi(dir)->ll_md_exp, op_data, &request);
+ ll_finish_md_op_data(op_data);
+ if (rc == 0) {
+ ll_update_times(request, dir);
+ ll_stats_ops_tally(ll_i2sbi(dir), LPROC_LL_RMDIR, 1);
+ }
+
+ ptlrpc_req_finished(request);
+ RETURN(rc);
+}
+
int ll_objects_destroy(struct ptlrpc_request *request, struct inode *dir)
{
struct mdt_body *body;
if (oa == NULL)
GOTO(out_free_memmd, rc = -ENOMEM);
- oa->o_id = lsm->lsm_object_id;
- oa->o_seq = lsm->lsm_object_seq;
+ oa->o_oi = lsm->lsm_oi;
oa->o_mode = body->mode & S_IFMT;
oa->o_valid = OBD_MD_FLID | OBD_MD_FLTYPE | OBD_MD_FLGROUP;
GOTO(out_free_memmd, rc);
}
- rc = obd_destroy(NULL, ll_i2dtexp(dir), oa, lsm, &oti,
- ll_i2mdexp(dir), oc);
- capa_put(oc);
- OBDO_FREE(oa);
- if (rc)
- CERROR("obd destroy objid "LPX64" error %d\n",
- lsm->lsm_object_id, rc);
- out_free_memmd:
- obd_free_memmd(ll_i2dtexp(dir), &lsm);
- out:
- return rc;
+ rc = obd_destroy(NULL, ll_i2dtexp(dir), oa, lsm, &oti,
+ ll_i2mdexp(dir), oc);
+ capa_put(oc);
+ if (rc)
+ CERROR("obd destroy objid "DOSTID" error %d\n",
+ POSTID(&lsm->lsm_oi), rc);
+out_free_memmd:
+ obd_free_memmd(ll_i2dtexp(dir), &lsm);
+ OBDO_FREE(oa);
+out:
+ return rc;
}
/* ll_unlink_generic() doesn't update the inode with the new link count.
if (IS_ERR(op_data))
RETURN(PTR_ERR(op_data));
- ll_get_child_fid(dir, name, &op_data->op_fid3);
- rc = md_unlink(ll_i2sbi(dir)->ll_md_exp, op_data, &request);
- ll_finish_md_op_data(op_data);
- if (rc)
- GOTO(out, rc);
+ ll_get_child_fid(dir, name, &op_data->op_fid3);
+ op_data->op_fid2 = op_data->op_fid3;
+ rc = md_unlink(ll_i2sbi(dir)->ll_md_exp, op_data, &request);
+ ll_finish_md_op_data(op_data);
+ if (rc)
+ GOTO(out, rc);
ll_update_times(request, dir);
ll_stats_ops_tally(ll_i2sbi(dir), LPROC_LL_UNLINK, 1);
RETURN(err);
}
-static int ll_mknod(struct inode *dir, struct dentry *dchild, int mode,
- ll_dev_t rdev)
+static int ll_mknod(struct inode *dir, struct dentry *dchild, ll_umode_t mode,
+ dev_t rdev)
{
- return ll_mknod_generic(dir, &dchild->d_name, mode,
- old_encode_dev(rdev), dchild);
+ return ll_mknod_generic(dir, &dchild->d_name, mode,
+ old_encode_dev(rdev), dchild);
}
static int ll_unlink(struct inode * dir, struct dentry *dentry)
{
return ll_unlink_generic(dir, NULL, dentry, &dentry->d_name);
}
-static int ll_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+
+static int ll_mkdir(struct inode *dir, struct dentry *dentry, ll_umode_t mode)
{
return ll_mkdir_generic(dir, &dentry->d_name, mode, dentry);
}
+
static int ll_rmdir(struct inode *dir, struct dentry *dentry)
{
return ll_rmdir_generic(dir, NULL, dentry, &dentry->d_name);
}
+
static int ll_symlink(struct inode *dir, struct dentry *dentry,
const char *oldname)
{
return ll_symlink_generic(dir, &dentry->d_name, oldname, dentry);
}
+
static int ll_link(struct dentry *old_dentry, struct inode *dir,
struct dentry *new_dentry)
{
return ll_link_generic(old_dentry->d_inode, dir, &new_dentry->d_name,
new_dentry);
}
+
static int ll_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry)
{
}
struct inode_operations ll_dir_inode_operations = {
- .mknod = ll_mknod,
- .lookup = ll_lookup_nd,
- .create = ll_create_nd,
- /* We need all these non-raw things for NFSD, to not patch it. */
- .unlink = ll_unlink,
- .mkdir = ll_mkdir,
- .rmdir = ll_rmdir,
- .symlink = ll_symlink,
- .link = ll_link,
- .rename = ll_rename,
- .setattr = ll_setattr,
- .getattr = ll_getattr,
- .permission = ll_inode_permission,
- .setxattr = ll_setxattr,
- .getxattr = ll_getxattr,
- .listxattr = ll_listxattr,
- .removexattr = ll_removexattr,
+ .mknod = ll_mknod,
+#ifdef HAVE_IOP_ATOMIC_OPEN
+ .atomic_open = ll_atomic_open,
+#endif
+ .lookup = ll_lookup_nd,
+ .create = ll_create_nd,
+ /* We need all these non-raw things for NFSD, to not patch it. */
+ .unlink = ll_unlink,
+ .mkdir = ll_mkdir,
+ .rmdir = ll_rmdir,
+ .symlink = ll_symlink,
+ .link = ll_link,
+ .rename = ll_rename,
+ .setattr = ll_setattr,
+ .getattr = ll_getattr,
+ .permission = ll_inode_permission,
+ .setxattr = ll_setxattr,
+ .getxattr = ll_getxattr,
+ .listxattr = ll_listxattr,
+ .removexattr = ll_removexattr,
+#ifdef HAVE_IOP_GET_ACL
+ .get_acl = ll_get_acl,
+#endif
};
struct inode_operations ll_special_inode_operations = {
- .setattr = ll_setattr,
- .getattr = ll_getattr,
- .permission = ll_inode_permission,
- .setxattr = ll_setxattr,
- .getxattr = ll_getxattr,
- .listxattr = ll_listxattr,
- .removexattr = ll_removexattr,
+ .setattr = ll_setattr,
+ .getattr = ll_getattr,
+ .permission = ll_inode_permission,
+ .setxattr = ll_setxattr,
+ .getxattr = ll_getxattr,
+ .listxattr = ll_listxattr,
+ .removexattr = ll_removexattr,
+#ifdef HAVE_IOP_GET_ACL
+ .get_acl = ll_get_acl,
+#endif
};