From 7bb78fa519cd404758c67811c116744bc755b2cf Mon Sep 17 00:00:00 2001 From: Bobi Jam Date: Wed, 8 Aug 2012 13:23:42 +0800 Subject: [PATCH] LU-1540 osd: add NUL terminator for long symlink Add NUL terminator for long symlink to ldiskfs inode on-disk data. Signed-off-by: Bobi Jam Change-Id: Id7ce7829ec9b4c8eb72cf257df046a5288a5eb7b Reviewed-on: http://review.whamcloud.com/3560 Tested-by: Hudson Tested-by: Maloo Reviewed-by: Andreas Dilger Reviewed-by: Oleg Drokin --- lustre/osd-ldiskfs/osd_internal.h | 2 +- lustre/osd-ldiskfs/osd_io.c | 44 +++++++++++++++++++++----------- lustre/osd-ldiskfs/osd_scrub.c | 2 +- lustre/tests/sanity.sh | 53 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 84 insertions(+), 17 deletions(-) diff --git a/lustre/osd-ldiskfs/osd_internal.h b/lustre/osd-ldiskfs/osd_internal.h index 6617c25..879343c 100644 --- a/lustre/osd-ldiskfs/osd_internal.h +++ b/lustre/osd-ldiskfs/osd_internal.h @@ -809,7 +809,7 @@ static inline void osd_ipd_put(const struct lu_env *env, int osd_ldiskfs_read(struct inode *inode, void *buf, int size, loff_t *offs); int osd_ldiskfs_write_record(struct inode *inode, void *buf, int bufsize, - loff_t *offs, handle_t *handle); + int write_NUL, loff_t *offs, handle_t *handle); static inline struct dentry *osd_child_dentry_by_inode(const struct lu_env *env, diff --git a/lustre/osd-ldiskfs/osd_io.c b/lustre/osd-ldiskfs/osd_io.c index 9adc20f..b7ad5a0 100644 --- a/lustre/osd-ldiskfs/osd_io.c +++ b/lustre/osd-ldiskfs/osd_io.c @@ -970,7 +970,7 @@ static int osd_ldiskfs_writelink(struct inode *inode, char *buffer, int buflen) } int osd_ldiskfs_write_record(struct inode *inode, void *buf, int bufsize, - loff_t *offs, handle_t *handle) + int write_NUL, loff_t *offs, handle_t *handle) { struct buffer_head *bh = NULL; loff_t offset = *offs; @@ -982,6 +982,15 @@ int osd_ldiskfs_write_record(struct inode *inode, void *buf, int bufsize, int boffs; int dirty_inode = 0; + if (write_NUL) { + /* + * long symlink write does not count the NUL terminator in + * bufsize, we write it, and the inode's file size does not + * count the NUL terminator as well. + */ + ((char *)buf)[bufsize] = '\0'; + ++bufsize; + } while (bufsize > 0) { if (bh != NULL) brelse(bh); @@ -1020,6 +1029,8 @@ int osd_ldiskfs_write_record(struct inode *inode, void *buf, int bufsize, if (bh) brelse(bh); + if (write_NUL) + --new_size; /* correct in-core and on-disk sizes */ if (new_size > i_size_read(inode)) { cfs_spin_lock(&inode->i_lock); @@ -1044,12 +1055,13 @@ static ssize_t osd_write(const struct lu_env *env, struct dt_object *dt, struct thandle *handle, struct lustre_capa *capa, int ignore_quota) { - struct inode *inode = osd_dt_obj(dt)->oo_inode; - struct osd_thandle *oh; - ssize_t result; + struct inode *inode = osd_dt_obj(dt)->oo_inode; + struct osd_thandle *oh; + ssize_t result; #ifdef HAVE_QUOTA_SUPPORT - cfs_cap_t save = cfs_curproc_cap_pack(); + cfs_cap_t save = cfs_curproc_cap_pack(); #endif + int is_link; LASSERT(dt_object_exists(dt)); @@ -1069,16 +1081,18 @@ static ssize_t osd_write(const struct lu_env *env, struct dt_object *dt, else cfs_cap_lower(CFS_CAP_SYS_RESOURCE); #endif - /* Write small symlink to inode body as we need to maintain correct - * on-disk symlinks for ldiskfs. - */ - if (S_ISLNK(dt->do_lu.lo_header->loh_attr) && - (buf->lb_len < sizeof(LDISKFS_I(inode)->i_data))) - result = osd_ldiskfs_writelink(inode, buf->lb_buf, buf->lb_len); - else - result = osd_ldiskfs_write_record(inode, buf->lb_buf, - buf->lb_len, pos, - oh->ot_handle); + /* Write small symlink to inode body as we need to maintain correct + * on-disk symlinks for ldiskfs. + * Note: the buf->lb_buf contains a NUL terminator while buf->lb_len + * does not count it in. + */ + is_link = S_ISLNK(dt->do_lu.lo_header->loh_attr); + if (is_link && (buf->lb_len < sizeof(LDISKFS_I(inode)->i_data))) + result = osd_ldiskfs_writelink(inode, buf->lb_buf, buf->lb_len); + else + result = osd_ldiskfs_write_record(inode, buf->lb_buf, + buf->lb_len, is_link, pos, + oh->ot_handle); #ifdef HAVE_QUOTA_SUPPORT cfs_curproc_cap_unpack(save); #endif diff --git a/lustre/osd-ldiskfs/osd_scrub.c b/lustre/osd-ldiskfs/osd_scrub.c index e24e54a..5c9a290 100644 --- a/lustre/osd-ldiskfs/osd_scrub.c +++ b/lustre/osd-ldiskfs/osd_scrub.c @@ -214,7 +214,7 @@ int osd_scrub_file_store(struct osd_scrub *scrub) osd_scrub_file_to_le(&scrub->os_file_disk, &scrub->os_file); rc = osd_ldiskfs_write_record(scrub->os_inode, &scrub->os_file_disk, - len, &pos, jh); + len, 0, &pos, jh); ldiskfs_journal_stop(jh); if (rc != 0) CERROR("%.16s: fail to store scrub file, expected = %d, " diff --git a/lustre/tests/sanity.sh b/lustre/tests/sanity.sh index 1bc10ae..c6f92b8 100644 --- a/lustre/tests/sanity.sh +++ b/lustre/tests/sanity.sh @@ -488,6 +488,59 @@ test_17k() { #bug 22301 } run_test 17k "symlinks: rsync with xattrs enabled =========================" +# LU-1540 +test_17m() { + local short_sym="0123456789" + local WDIR=$DIR/${tdir}m + local mds_index + local devname + local cmd + local i + local rc=0 + + mkdir -p $WDIR + long_sym=$short_sym + # create a long symlink file + for ((i = 0; i < 4; ++i)); do + long_sym=${long_sym}${long_sym} + done + + echo "create 512 short and long symlink files under $WDIR" + for ((i = 0; i < 256; ++i)); do + ln -sf ${long_sym}"a5a5" $WDIR/long-$i + ln -sf ${short_sym}"a5a5" $WDIR/short-$i + done + + echo "erase them" + rm -f $WDIR/* + sync + sleep 2 + + echo "recreate the 512 symlink files with a shorter string" + for ((i = 0; i < 512; ++i)); do + # rewrite the symlink file with a shorter string + ln -sf ${long_sym} $WDIR/long-$i + ln -sf ${short_sym} $WDIR/short-$i + done + + mds_index=$($LFS getstripe -M $WDIR) + mds_index=$((mds_index+1)) + devname=$(mdsdevname $mds_index) + cmd="$E2FSCK -fnvd $devname" + + echo "stop and checking mds${mds_index}: $cmd" + # e2fsck should not return error + stop mds${mds_index} -f + do_facet mds${mds_index} $cmd || rc=$? + + start mds${mds_index} $devname $MDS_MOUNT_OPTS + df $MOUNT > /dev/null 2>&1 + [ $rc -ne 0 ] && error "e2fsck should not report error upon "\ + "short/long symlink MDT: rc=$rc" + return $rc +} +run_test 17m "run e2fsck against MDT which contains short/long symlink" + test_18() { touch $DIR/f ls $DIR || error -- 1.8.3.1