#endif
/* Local permission check for name_insert before remote ops. */
- rc = mo_permission(env, md_object_next(mo_p), MAY_WRITE);
+ rc = mo_permission(env, md_object_next(mo_p), MAY_WRITE |
+ (S_ISDIR(ma->ma_attr.la_mode) ? MAY_LINK : 0));
if (rc)
RETURN(rc);
#define MDS_OPEN_HAS_EA 010000000000 /* specify object create pattern */
#define MDS_OPEN_HAS_OBJS 020000000000 /* Just set the EA the obj exist */
+/* permission for increase nlink of a file */
+#define MAY_LINK 64
+
enum {
MDS_CHECK_SPLIT = 1 << 0,
MDS_CROSS_REF = 1 << 1
int mdd_link_sanity_check(const struct lu_env *env, struct mdd_object *tgt_obj,
struct mdd_object *src_obj)
{
+ struct lu_attr *la = &mdd_env_info(env)->mti_la;
+ struct mdd_device *m = mdd_obj2mdd_dev(src_obj);
int rc = 0;
ENTRY;
RETURN(rc);
}
- RETURN(rc);
+ rc = mdd_la_get(env, src_obj, la, BYPASS_CAPA);
+ if (rc)
+ RETURN(rc);
+
+ if (la->la_nlink >= m->mdd_dt_conf.ddp_max_nlink)
+ RETURN(-EMLINK);
+ else
+ RETURN(0);
}
const struct dt_rec *__mdd_fid_rec(const struct lu_env *env,
rc = mdd_may_create(env, tgt_pobj, NULL, 1);
}
+ if (!rc && src_is_dir) {
+ struct lu_attr *la = &mdd_env_info(env)->mti_la;
+ struct mdd_device *m = mdd_obj2mdd_dev(tgt_pobj);
+
+ rc = mdd_la_get(env, tgt_pobj, la, BYPASS_CAPA);
+ if (rc)
+ RETURN(rc);
+
+ if (la->la_nlink >= m->mdd_dt_conf.ddp_max_nlink)
+ RETURN(-EMLINK);
+ }
+
RETURN(rc);
}
rc = -ENOTEMPTY;
}
+ if (!rc && src_is_dir && (src_pobj != tgt_pobj)) {
+ struct lu_attr *la = &mdd_env_info(env)->mti_la;
+ struct mdd_device *m = mdd_obj2mdd_dev(tgt_pobj);
+
+ rc = mdd_la_get(env, tgt_pobj, la, BYPASS_CAPA);
+ if (rc)
+ RETURN(rc);
+
+ if (la->la_nlink >= m->mdd_dt_conf.ddp_max_nlink)
+ RETURN(-EMLINK);
+ }
+
RETURN(rc);
}
/* src object can be remote that is why we use only fid and type of object */
return container_of0(lu_object_next(mdd2lu_obj(o)),
struct dt_object, do_lu);
}
+
static inline struct obd_device *mdd2obd_dev(struct mdd_device *mdd)
{
return mdd->mdd_obd_dev;
}
+static inline struct mdd_device *mdd_obj2mdd_dev(struct mdd_object *obj)
+{
+ return mdo2mdd(&obj->mod_obj);
+}
+
static inline const struct lu_fid *mdo2fid(const struct mdd_object *obj)
{
return lu_object_fid(&obj->mod_obj.mo_lu);
int mdd_permission(const struct lu_env *env, struct md_object *obj, int mask)
{
struct mdd_object *mdd_obj = md2mdd_obj(obj);
+ int check_link = mask & MAY_LINK;
int rc;
ENTRY;
+ mask &= ~MAY_LINK;
rc = mdd_permission_internal_locked(env, mdd_obj, NULL, mask);
+ if (!rc && check_link) {
+ struct lu_attr *la = &mdd_env_info(env)->mti_la;
+ struct mdd_device *m = mdo2mdd(obj);
+
+ rc = mdd_la_get(env, mdd_obj, la, BYPASS_CAPA);
+ if (rc)
+ RETURN(rc);
+
+ if (la->la_nlink >= m->mdd_dt_conf.ddp_max_nlink)
+ RETURN(-EMLINK);
+ }
RETURN(rc);
}
} else /* -ENOENT */ {
/* Do permission check for name_insert first */
rc = mo_permission(info->mti_env, mdt_object_child(mtgtdir),
- MAY_WRITE);
+ MAY_WRITE |
+ (S_ISDIR(ma->ma_attr.la_mode) ? MAY_LINK : 0));
if (rc)
GOTO(out_unlock_tgtdir, rc);